From 188ee86233028036fd4632a0220dc43c0593fef1 Mon Sep 17 00:00:00 2001 From: Soroush Date: Fri, 23 Oct 2020 15:11:22 -0700 Subject: [PATCH] Edit schema menu item (#4506) Co-authored-by: Soroush Co-authored-by: Geoff Cox (Microsoft) --- .../components/ProjectTree/ProjectTree.tsx | 27 ++++++++-- .../recoilModel/dispatchers/formDialogs.ts | 5 ++ .../src/recoilModel/selectors/project.ts | 49 ++++++++++--------- 3 files changed, 55 insertions(+), 26 deletions(-) diff --git a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx index 6c03f50ad8..379b7fbfec 100644 --- a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx +++ b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx @@ -130,7 +130,7 @@ export const ProjectTree: React.FC = ({ onDeleteTrigger, onSelect, }) => { - const { onboardingAddCoachMarkRef, selectTo, navTo } = useRecoilValue(dispatcherState); + const { onboardingAddCoachMarkRef, selectTo, navTo, navigateToFormDialogSchema } = useRecoilValue(dispatcherState); const [filter, setFilter] = useState(''); const [selectedLink, setSelectedLink] = useState(); @@ -167,6 +167,13 @@ export const ProjectTree: React.FC = ({ return process.env.COMPOSER_ENABLE_FORMS && dialog.content?.schema !== undefined; }; + const formDialogSchemaExists = (projectId: string, dialog: DialogInfo) => { + return ( + dialogIsFormDialog(dialog) && + !!botProjectSpace?.find((s) => s.projectId === projectId)?.formDialogSchemas.find((fd) => fd.id === dialog.id) + ); + }; + const botHasWarnings = (bot: BotInProject) => { return bot.dialogs.some(dialogHasWarnings); }; @@ -238,10 +245,14 @@ export const ProjectTree: React.FC = ({ displayName: dialog.displayName, isRoot: dialog.isRoot, projectId: currentProjectId, - skillId: null, + skillId, errorContent, warningContent, }; + + const isFormDialog = dialogIsFormDialog(dialog); + const showEditSchema = formDialogSchemaExists(skillId, dialog); + return ( = ({ = ({ onDeleteDialog(link.dialogName ?? ''); }, }, + ...(showEditSchema + ? [ + { + label: formatMessage('Edit schema'), + icon: 'Edit', + onClick: (link) => + navigateToFormDialogSchema({ projectId: link.skillId, schemaId: link.dialogName }), + }, + ] + : []), ]} onSelect={handleOnSelect} /> diff --git a/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts b/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts index 3b1257c9bd..7ef47347d8 100644 --- a/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts +++ b/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts @@ -91,6 +91,10 @@ export const formDialogsDispatcher = () => { navigate(`/bot/${projectId}/dialogs/${schemaId}`); }; + const navigateToFormDialogSchema = ({ projectId, schemaId }) => { + navigate(`/bot/${projectId}/forms/${schemaId}`); + }; + return { createFormDialogSchema, updateFormDialogSchema, @@ -98,5 +102,6 @@ export const formDialogsDispatcher = () => { removeFormDialogSchema, generateFormDialog, navigateToGeneratedDialog, + navigateToFormDialogSchema, }; }; diff --git a/Composer/packages/client/src/recoilModel/selectors/project.ts b/Composer/packages/client/src/recoilModel/selectors/project.ts index e35cde28e2..a0faea636f 100644 --- a/Composer/packages/client/src/recoilModel/selectors/project.ts +++ b/Composer/packages/client/src/recoilModel/selectors/project.ts @@ -1,22 +1,23 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import { selector, selectorFamily } from 'recoil'; -import isEmpty from 'lodash/isEmpty'; import { FormDialogSchema, JsonSchemaFile } from '@bfc/shared'; +import isEmpty from 'lodash/isEmpty'; +import { selector, selectorFamily } from 'recoil'; import { - botErrorState, botDisplayNameState, + botErrorState, + botNameIdentifierState, botProjectFileState, botProjectIdsState, - projectMetaDataState, - botNameIdentifierState, formDialogSchemaIdsState, formDialogSchemaState, jsonSchemaFilesState, + projectMetaDataState, } from '../atoms'; import { dialogsSelectorFamily } from '../selectors'; + // Actions export const botsForFilePersistenceSelector = selector({ key: 'botsForFilePersistenceSelector', @@ -30,18 +31,36 @@ export const botsForFilePersistenceSelector = selector({ }, }); -// TODO: This selector would be modfied and leveraged by the project tree +export const formDialogSchemasSelectorFamily = selectorFamily({ + key: 'formDialogSchemasSelector', + get: (projectId: string) => ({ get }) => { + const formDialogSchemaIds = get(formDialogSchemaIdsState(projectId)); + return formDialogSchemaIds.map((schemaId) => get(formDialogSchemaState({ projectId, schemaId }))); + }, +}); + +// Given a form dialog schema, indicates if the dialog exist for it (aka is generated) +export const formDialogSchemaDialogExistsSelector = selectorFamily({ + key: 'formDialogSchemasSelector', + get: ({ projectId, schemaId }) => ({ get }) => { + const dialogs = get(dialogsSelectorFamily(projectId)); + return !!dialogs.find((d) => d.id === schemaId); + }, +}); + +// TODO: This selector would be modified and leveraged by the project tree export const botProjectSpaceSelector = selector({ key: 'botProjectSpaceSelector', get: ({ get }) => { const botProjects = get(botProjectIdsState); const result = botProjects.map((projectId: string) => { const dialogs = get(dialogsSelectorFamily(projectId)); + const formDialogSchemas = get(formDialogSchemasSelectorFamily(projectId)); const metaData = get(projectMetaDataState(projectId)); const botError = get(botErrorState(projectId)); const name = get(botDisplayNameState(projectId)); const botNameId = get(botNameIdentifierState(projectId)); - return { dialogs, projectId, name, ...metaData, error: botError, botNameId }; + return { dialogs, formDialogSchemas, projectId, name, ...metaData, error: botError, botNameId }; }); return result; }, @@ -61,22 +80,6 @@ export const rootBotProjectIdSelector = selector({ }, }); -export const formDialogSchemasSelectorFamily = selectorFamily({ - key: 'formDialogSchemasSelector', - get: (projectId: string) => ({ get }) => { - const formDialogSchemaIds = get(formDialogSchemaIdsState(projectId)); - return formDialogSchemaIds.map((schemaId) => get(formDialogSchemaState({ projectId, schemaId }))); - }, -}); - -export const formDialogSchemaDialogExistsSelector = selectorFamily({ - key: 'formDialogSchemasSelector', - get: ({ projectId, schemaId }: { projectId: string; schemaId: string }) => ({ get }) => { - const dialogs = get(dialogsSelectorFamily(projectId)); - return !!dialogs.find((d) => d.id === schemaId); - }, -}); - export const jsonSchemaFilesByProjectIdSelector = selector({ key: 'jsonSchemaFilesByProjectIdSelector', get: ({ get }) => {