1
0
mirror of https://github.com/mattermost/focalboard.git synced 2024-12-24 13:43:12 +02:00

move template id handling to plugin

This commit is contained in:
Pablo Andrés Vélez Vidal 2023-01-25 22:06:20 +01:00
parent 66c255e2cd
commit 3b88cefcff
7 changed files with 73 additions and 51 deletions

View File

@ -45,7 +45,8 @@ const manifestStr = `
"type": "bool",
"help_text": "This allows board editors to share boards that can be accessed by anyone with the link.",
"placeholder": "",
"default": false
"default": false,
"hosting": ""
}
]
}

View File

@ -23,16 +23,16 @@ describe('components/createBoardFromTemplate', () => {
it('renders the Create Boards from template component and match snapshot', async () => {
const store = mockStateStore([], state)
let container: Element | DocumentFragment | null = null
const setSelectedTemplate = jest.fn
const toggleAddBoardCheckbox = jest.fn
const setCanCreate = jest.fn
const setAction = jest.fn
const newBoardInfoIcon = (<i className="icon-information-outline" />)
await act(async () => {
const result = render(wrapIntl(
<ReduxProvider store={store}>
<CreateBoardFromTemplate
setSelectedTemplate={setSelectedTemplate}
toggleAddBoardCheck={toggleAddBoardCheckbox}
setAction={setAction}
setCanCreate={setCanCreate}
newBoardInfoIcon={newBoardInfoIcon}
/>
</ReduxProvider>
@ -45,16 +45,16 @@ describe('components/createBoardFromTemplate', () => {
it('clicking checkbox toggles the templates selector', async () => {
const store = mockStateStore([], state)
const setSelectedTemplate = jest.fn
const toggleAddBoardCheckbox = jest.fn
const setCanCreate = jest.fn
const setAction = jest.fn
const newBoardInfoIcon = (<i className="icon-information-outline" />)
await act(async () => {
render(wrapIntl(
<ReduxProvider store={store}>
<CreateBoardFromTemplate
setSelectedTemplate={setSelectedTemplate}
toggleAddBoardCheck={toggleAddBoardCheckbox}
setAction={setAction}
setCanCreate={setCanCreate}
newBoardInfoIcon={newBoardInfoIcon}
/>
</ReduxProvider>
@ -74,7 +74,7 @@ describe('components/createBoardFromTemplate', () => {
await act(async () => {
await userEvent.click(checkbox)
const templatesSelector = screen.queryByText('Select a template')
expect(templatesSelector).not.toBeInTheDocument()
expect(templatesSelector).toBeNull()
})
})

View File

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useState} from 'react'
import React, {useCallback, useEffect, useRef, useState} from 'react'
import {createIntl, createIntlCache, IntlProvider} from 'react-intl'
@ -18,10 +18,11 @@ import {mutator} from '../../../../webapp/src/mutator'
import {useGetAllTemplates} from '../../../../webapp/src/hooks/useGetAllTemplates'
import './createBoardFromTemplate.scss'
import {Board} from '../../../../webapp/src/blocks/board'
type Props = {
setSelectedTemplate: (templateId: string) => void;
toggleAddBoardCheck: (addBoard: boolean) => void;
setCanCreate: (canCreate: boolean) => void;
setAction: (fn: () => (channelId: string, teamId: string) => Promise<Board | undefined>) => void;
newBoardInfoIcon: React.ReactNode;
}
@ -41,23 +42,6 @@ const intl = createIntl({
messages: getMessages(getCurrentLanguage())
}, cache)
export const createBoardFromTemplateAction = async (templateId: string, teamId: string, channelId: string) => {
const ACTION_DESCRIPTION = 'board created from channel'
const asTemplate = false
let boardsAndBlocks = undefined
if (templateId === EMPTY_BOARD) {
boardsAndBlocks = await mutator.addEmptyBoard(teamId, intl)
} else {
boardsAndBlocks = await mutator.duplicateBoard(templateId, ACTION_DESCRIPTION, asTemplate, undefined, undefined, teamId)
}
const board = boardsAndBlocks.boards[0]
await mutator.updateBoard({...board, channelId: channelId}, board, 'linked channel')
return board
}
const {ValueContainer, Placeholder} = components
const CreateBoardFromTemplate = (props: Props) => {
@ -65,14 +49,49 @@ const CreateBoardFromTemplate = (props: Props) => {
const [addBoard, setAddBoard] = useState(false)
const allTemplates = useGetAllTemplates()
const [selectedBoardTemplateId, setSelectedBoardTemplateId] = useState<string>('')
const addBoardRef = useRef(false)
addBoardRef.current = addBoard
const templateIdRef = useRef('')
templateIdRef.current = selectedBoardTemplateId
const showNewBoardTemplateSelector = async () => {
setAddBoard((prev: boolean) => {
props.toggleAddBoardCheck(!prev)
return !prev
})
setAddBoard((prev: boolean) => !prev)
}
// CreateBoardFromTemplate
const addBoardToChannel = async (channelId: string, teamId: string) => {
if (!addBoardRef.current || !templateIdRef.current) {
return
}
const ACTION_DESCRIPTION = 'board created from channel'
const LINKED_CHANNEL = 'linked channel'
const asTemplate = false
let boardsAndBlocks = undefined
if (selectedBoardTemplateId === EMPTY_BOARD) {
boardsAndBlocks = await mutator.addEmptyBoard(teamId, intl)
} else {
boardsAndBlocks = await mutator.duplicateBoard(templateIdRef.current as string, ACTION_DESCRIPTION, asTemplate, undefined, undefined, teamId)
}
const board = boardsAndBlocks.boards[0]
await mutator.updateBoard({...board, channelId: channelId}, board, LINKED_CHANNEL)
return board
}
useEffect(() => {
props.setAction(() => addBoardToChannel)
}, [])
useEffect(() => {
props.setCanCreate(!addBoard || (addBoard && selectedBoardTemplateId !== ''))
}, [addBoard, selectedBoardTemplateId])
const getSubstringWithCompleteWords = (str: string, len: number) => {
if (str?.length <= len) {
return str
@ -128,7 +147,7 @@ const CreateBoardFromTemplate = (props: Props) => {
)
}
const loadOptions = async (value = '') => {
const loadOptions = useCallback(async (value = '') => {
let templates = allTemplates.map((template) => {
return {
id: template.id,
@ -151,7 +170,13 @@ const CreateBoardFromTemplate = (props: Props) => {
templates = templates.filter(template => template.title.toLowerCase().includes(value.toLowerCase()))
}
return templates
}
}, [allTemplates])
const onChange = useCallback((item: SingleValue<ReactSelectItem>) => {
if (item) {
setSelectedBoardTemplateId(item.id)
}
}, [setSelectedBoardTemplateId])
const selectorStyles = {
menu: (baseStyles: CSSObject): CSSObject => ({
@ -205,11 +230,7 @@ const CreateBoardFromTemplate = (props: Props) => {
<Select
classNamePrefix={'CreateBoardFromTemplate--templates-selector'}
placeholder={formatMessage({id: 'new_channel_modal.create_board.select_template_placeholder', defaultMessage: 'Select a template'})}
onChange={(item: SingleValue<ReactSelectItem>) => {
if (item) {
props.setSelectedTemplate(item.id)
}
}}
onChange={onChange}
components={{IndicatorSeparator: () => null, ValueContainer: CustomValueContainer}}
loadOptions={loadOptions}
getOptionValue={(v) => v.id}

View File

@ -139,7 +139,7 @@ const RHSChannelBoards = () => {
<div className='rhs-boards-header'>
<span className='linked-boards'>
<FormattedMessage
id='rhs-boards.linked-boards'
id='rhs-boards.linked-boards2'
defaultMessage='Linked boards'
/>
</span>

View File

@ -39,6 +39,7 @@ import '../../../webapp/src/styles/main.scss'
import '../../../webapp/src/styles/labels.scss'
import octoClient from '../../../webapp/src/octoClient'
import {Constants} from '../../../webapp/src/constants'
import {Board} from '../../../webapp/src/blocks/board'
import appBarIcon from '../../../webapp/static/app-bar-icon.png'
@ -66,7 +67,7 @@ import {PluginRegistry} from './types/mattermost-webapp'
import './plugin.scss'
import CloudUpgradeNudge from "./components/cloudUpgradeNudge/cloudUpgradeNudge"
import CreateBoardFromTemplate, {createBoardFromTemplateAction} from './components/createBoardFromTemplate'
import CreateBoardFromTemplate from './components/createBoardFromTemplate'
function getSubpath(siteURL: string): string {
const url = new URL(siteURL)
@ -339,18 +340,18 @@ export default class Plugin {
if (this.registry.registerActionAfterChannelCreation) {
this.registry.registerActionAfterChannelCreation((props: {
setSelectedTemplate: (templateId: string) => void,
toggleAddBoardCheck: (addBoard: boolean) => void,
setCanCreate: (canCreate: boolean) => void,
setAction: (fn: () => (channelId: string, teamId: string) => Promise<Board | undefined>) => void,
newBoardInfoIcon: React.ReactNode,
}) => (
<ReduxProvider store={store}>
<CreateBoardFromTemplate
setSelectedTemplate={props.setSelectedTemplate}
toggleAddBoardCheck={props.toggleAddBoardCheck}
setCanCreate={props.setCanCreate}
setAction={props.setAction}
newBoardInfoIcon={props.newBoardInfoIcon}
/>
</ReduxProvider>
), createBoardFromTemplateAction)
))
}
this.registry.registerPostWillRenderEmbedComponent(

View File

@ -20,7 +20,7 @@ export interface PluginRegistry {
registerInsightsHandler(handler: (timeRange: string, page: number, perPage: number, teamId: string, insightType: string) => void)
registerSiteStatisticsHandler(handler: () => void)
registerActionAfterChannelCreation(component: React.Element, action: any)
registerActionAfterChannelCreation(component: React.Element)
// Add more if needed from https://developers.mattermost.com/extend/plugins/webapp/reference
}

View File

@ -25,7 +25,6 @@ export const useGetAllTemplates = () => {
const unsortedTemplates = useAppSelector(getTemplates)
const templates = useMemo(() => Object.values(unsortedTemplates).sort((a: Board, b: Board) => a.createAt - b.createAt), [unsortedTemplates])
const allTemplates = globalTemplates.concat(templates)
return allTemplates
return useMemo(() => globalTemplates.concat(templates), [globalTemplates])
}