Skip to content

Commit

Permalink
Cherrypicked template tracking logic (#3302)
Browse files Browse the repository at this point in the history
* cherrypicked base impl

* removed debug log
  • Loading branch information
harshilsharma63 authored Jun 30, 2022
1 parent 2a34ed5 commit 53c11e6
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 4 deletions.
2 changes: 1 addition & 1 deletion server/app/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

const (
defaultTemplateVersion = 3
defaultTemplateVersion = 4
)

//go:embed templates.boardarchive
Expand Down
23 changes: 23 additions & 0 deletions server/services/store/sqlstore/blocks.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package sqlstore

import (
//nolint:gosec
"crypto/md5"
"database/sql"
"encoding/json"
"errors"
"fmt"

"github.com/mattermost/focalboard/server/utils"
Expand Down Expand Up @@ -31,6 +34,8 @@ type BlockNotFoundErr struct {
blockID string
}

var ErrInvalidIsTemplateProperty = errors.New("invalid isTemplate property value")

func (be BlockNotFoundErr) Error() string {
return fmt.Sprintf("block not found (block id: %s", be.blockID)
}
Expand Down Expand Up @@ -362,6 +367,24 @@ func (s *SQLStore) insertBlock(db sq.BaseRunner, c store.Container, block *model
return RootIDNilError{}
}

// Generate tracking IDs for in-built templates
if block.Type == model.TypeBoard {
isTemplate := false
if isTemplateStr, ok := block.Fields["isTemplate"]; ok {
var ok bool
isTemplate, ok = isTemplateStr.(bool)
if !ok {
return fmt.Errorf("blockID: %s %w", block.ID, ErrInvalidIsTemplateProperty)
}
}

if isTemplate && c.WorkspaceID == "0" {
//nolint:gosec
// we don't need cryptographically secure hash, so MD5 is fine
block.Fields["trackingTemplateId"] = fmt.Sprintf("%x", md5.Sum([]byte(block.Title)))
}
}

fieldsJSON, err := json.Marshal(block.Fields)
if err != nil {
return err
Expand Down
9 changes: 8 additions & 1 deletion webapp/src/blocks/board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type BoardFields = {
isTemplate?: boolean
cardProperties: IPropertyTemplate[]
columnCalculations: Record<string, string>
trackingTemplateId?: string
}

type Board = Block & {
Expand Down Expand Up @@ -59,7 +60,7 @@ function createBoard(block?: Block): Board {
})
}

return {
const board = {
...createBlock(block),
type: 'board',
fields: {
Expand All @@ -71,7 +72,13 @@ function createBoard(block?: Block): Board {
columnCalculations: block?.fields.columnCalculations || [],
cardProperties,
},
} as Board

if (block?.fields.trackingTemplateId) {
board.fields.trackingTemplateId = block?.fields.trackingTemplateId
}

return board
}

type BoardGroup = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {Utils} from '../../utils'
import {UserWorkspace} from '../../user'
import {mockDOM, mockStateStore, wrapDNDIntl} from '../../testUtils'

import TelemetryClient from '../../telemetry/telemetryClient'

import BoardTemplateSelector from './boardTemplateSelector'

jest.mock('react-router-dom', () => {
Expand All @@ -37,6 +39,9 @@ jest.mock('../../octoClient', () => {
jest.mock('../../utils')
jest.mock('../../mutator')

jest.mock('../../telemetry/telemetryClient')
const mockedTelemetry = mocked(TelemetryClient, true)

describe('components/boardTemplateSelector/boardTemplateSelector', () => {
const mockedUtils = mocked(Utils, true)
const mockedMutator = mocked(Mutator, true)
Expand Down Expand Up @@ -107,6 +112,7 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => {
dateDisplayPropertyId: 'global-id-5',
isTemplate: true,
templateVer: 2,
trackingTemplateId: 'template_id_global',
},
}],
},
Expand Down Expand Up @@ -282,6 +288,7 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => {
})
await waitFor(() => expect(mockedMutator.addBoardFromTemplate).toBeCalledTimes(1))
await waitFor(() => expect(mockedMutator.addBoardFromTemplate).toBeCalledWith(expect.anything(), expect.anything(), expect.anything(), expect.anything(), true))
await waitFor(() => expect(mockedTelemetry.trackEvent).toBeCalledWith('boards', 'createBoardViaTemplate', {boardTemplateId: 'template_id_global'}))
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ const BoardTemplateSelector = (props: Props) => {
}

const handleUseTemplate = async () => {
if (activeTemplate.workspaceId === '0') {
TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.CreateBoardViaTemplate, {boardTemplateId: activeTemplate.fields.trackingTemplateId as string})
}

await mutator.addBoardFromTemplate(intl, showBoard, () => showBoard(currentBoard.id), activeTemplate.id, activeTemplate.workspaceId === '0')
if (activeTemplate.title === OnboardingBoardTitle) {
resetTour()
Expand Down
2 changes: 0 additions & 2 deletions webapp/src/mutator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -863,8 +863,6 @@ class Mutator {
): Promise<[Block[], string]> {
const asTemplate = false
const actionDescription = intl.formatMessage({id: 'Mutator.new-board-from-template', defaultMessage: 'new board from template'})

TelemetryClient.trackEvent(TelemetryCategory, TelemetryActions.CreateBoardViaTemplate, {boardTemplateId})
if (global) {
return mutator.duplicateFromRootBoard(boardTemplateId, actionDescription, asTemplate, afterRedo, beforeUndo)
}
Expand Down

0 comments on commit 53c11e6

Please sign in to comment.