diff --git a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx index 2a706a50fa..1e26365b92 100644 --- a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx +++ b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx @@ -26,7 +26,7 @@ import { triggerNotSupported } from '../../utils/dialogValidator'; import { useFeatureFlag } from '../../utils/hooks'; import { LoadingSpinner } from '../LoadingSpinner'; import TelemetryClient from '../../telemetry/TelemetryClient'; -import { dialog } from '../ErrorPopup/styles'; +import { getBaseName } from '../../utils/fileUtil'; import { TreeItem } from './treeItem'; import { ExpandableNode } from './ExpandableNode'; @@ -500,6 +500,35 @@ export const ProjectTree: React.FC = ({ : renderTriggerList(dialog.triggers, dialog, projectId, dialogLink, 1); }; + // flatten lg imports url is same to dialog, to match correct link need render it as dialog + const renderLgImportAsDialog = (item: LanguageFileImport, projectId: string): React.ReactNode => { + const link: TreeLink = { + projectId: rootProjectId, + skillId: projectId === rootProjectId ? undefined : projectId, + dialogId: getBaseName(item.id), + displayName: item.displayName ?? item.id, + diagnostics: [], + isRoot: false, + isRemote: false, + }; + + return ( + + ); + }; + const renderLgImport = (item: LanguageFileImport, projectId: string, dialogId: string): React.ReactNode => { const link: TreeLink = { projectId: rootProjectId, @@ -537,6 +566,34 @@ export const ProjectTree: React.FC = ({ }); }; + const renderLuImportAsDialog = (item: LanguageFileImport, projectId: string): React.ReactNode => { + const link: TreeLink = { + projectId: rootProjectId, + skillId: projectId === rootProjectId ? undefined : projectId, + dialogId: getBaseName(item.id), + displayName: item.displayName ?? item.id, + diagnostics: [], + isRoot: false, + isRemote: false, + }; + + return ( + + ); + }; + const renderLuImport = (item: LanguageFileImport, projectId: string, dialogId: string): React.ReactNode => { const link: TreeLink = { projectId: rootProjectId, @@ -588,10 +645,10 @@ export const ProjectTree: React.FC = ({ const commonLink = options.showCommonLinks ? [renderCommonDialogHeader(projectId, 1)] : []; const importedLgLinks = options.showLgImports - ? lgImportsList.map((file) => renderLgImport(file, projectId, dialog.id)) + ? lgImportsList.map((file) => renderLgImportAsDialog(file, projectId)) : []; const importedLuLinks = options.showLuImports - ? luImportsList.map((file) => renderLuImport(file, projectId, dialog.id)) + ? luImportsList.map((file) => renderLuImportAsDialog(file, projectId)) : []; return [ diff --git a/Composer/packages/client/src/pages/language-generation/LGPage.tsx b/Composer/packages/client/src/pages/language-generation/LGPage.tsx index 94e4a06870..d83b975832 100644 --- a/Composer/packages/client/src/pages/language-generation/LGPage.tsx +++ b/Composer/packages/client/src/pages/language-generation/LGPage.tsx @@ -12,7 +12,7 @@ import { useRecoilValue } from 'recoil'; import { LoadingSpinner } from '../../components/LoadingSpinner'; import { navigateTo } from '../../utils/navigation'; import { Page } from '../../components/Page'; -import { dialogIdsState } from '../../recoilModel'; +import { lgFilesSelectorFamily, localeState } from '../../recoilModel'; import TelemetryClient from '../../telemetry/TelemetryClient'; import TableView from './table-view'; @@ -25,19 +25,24 @@ const LGPage: React.FC> = (props) => { const { dialogId = '', projectId = '', skillId, lgFileId = '' } = props; - const dialogs = useRecoilValue(dialogIdsState(skillId ?? projectId)); + const actualProjectId = skillId ?? projectId; + const locale = useRecoilValue(localeState(actualProjectId)); + const lgFiles = useRecoilValue(lgFilesSelectorFamily(skillId ?? projectId)); const path = props.location?.pathname ?? ''; const edit = /\/edit(\/)?$/.test(path); const baseURL = skillId == null ? `/bot/${projectId}/` : `/bot/${projectId}/skill/${skillId}/`; + const activeFile = lgFileId + ? lgFiles.find(({ id }) => id === lgFileId || id === `${lgFileId}.${locale}`) + : lgFiles.find(({ id }) => id === dialogId || id === `${dialogId}.${locale}`); + useEffect(() => { - const activeDialog = dialogs.find((id) => id === dialogId); - if (!activeDialog && dialogs.length && dialogId !== 'common' && !lgFileId) { + if (!activeFile && lgFiles.length) { navigateTo(`${baseURL}language-generation/common`); } - }, [dialogId, dialogs, projectId, lgFileId]); + }, [dialogId, lgFiles, projectId, lgFileId]); const onToggleEditMode = useCallback( (_e) => { @@ -77,8 +82,22 @@ const LGPage: React.FC }> - - + + diff --git a/Composer/packages/client/src/pages/language-generation/code-editor.tsx b/Composer/packages/client/src/pages/language-generation/code-editor.tsx index dbfd6709ed..f226009d4e 100644 --- a/Composer/packages/client/src/pages/language-generation/code-editor.tsx +++ b/Composer/packages/client/src/pages/language-generation/code-editor.tsx @@ -29,10 +29,11 @@ interface CodeEditorProps extends RouteComponentProps<{}> { projectId: string; skillId?: string; lgFileId?: string; + file?: LgFile; } const CodeEditor: React.FC = (props) => { - const { dialogId, projectId, skillId, lgFileId } = props; + const { dialogId, projectId, skillId, lgFileId, file } = props; const actualProjectId = skillId ?? projectId; const userSettings = useRecoilValue(userSettingsState); @@ -49,10 +50,6 @@ const CodeEditor: React.FC = (props) => { setLocale, } = useRecoilValue(dispatcherState); - const file: LgFile | undefined = lgFileId - ? lgFiles.find(({ id }) => id === lgFileId) - : lgFiles.find(({ id }) => id === dialogId || id === `${dialogId}.${locale}`); - const defaultLangFile = lgFileId ? lgFiles.find(({ id }) => id === lgFileId) : lgFiles.find(({ id }) => id === `${dialogId}.${defaultLanguage}`); diff --git a/Composer/packages/client/src/pages/language-generation/table-view.tsx b/Composer/packages/client/src/pages/language-generation/table-view.tsx index 9ed2b4e732..2b98abeae3 100644 --- a/Composer/packages/client/src/pages/language-generation/table-view.tsx +++ b/Composer/packages/client/src/pages/language-generation/table-view.tsx @@ -18,6 +18,7 @@ import { RouteComponentProps } from '@reach/router'; import { LgTemplate } from '@bfc/shared'; import { useRecoilValue } from 'recoil'; import { lgUtil } from '@bfc/indexers'; +import { LgFile } from '@botframework-composer/types/src'; import { EditableField } from '../../components/EditableField'; import { navigateTo } from '../../utils/navigation'; @@ -32,10 +33,11 @@ interface TableViewProps extends RouteComponentProps<{ dialogId: string; skillId skillId?: string; dialogId?: string; lgFileId?: string; + file?: LgFile; } const TableView: React.FC = (props) => { - const { dialogId, projectId, skillId, lgFileId } = props; + const { dialogId, projectId, skillId, lgFileId, file } = props; const actualProjectId = skillId ?? projectId; @@ -49,10 +51,6 @@ const TableView: React.FC = (props) => { const { languages, defaultLanguage } = settings; - const file = lgFileId - ? lgFiles.find(({ id }) => id === lgFileId) - : lgFiles.find(({ id }) => id === dialogId || id === `${dialogId}.${locale}`); - const defaultLangFile = lgFileId ? lgFiles.find(({ id }) => id === lgFileId) : lgFiles.find(({ id }) => id === `${dialogId}.${defaultLanguage}`); diff --git a/Composer/packages/client/src/pages/language-understanding/LUPage.tsx b/Composer/packages/client/src/pages/language-understanding/LUPage.tsx index 5aa4f25dd2..64a2d3df50 100644 --- a/Composer/packages/client/src/pages/language-understanding/LUPage.tsx +++ b/Composer/packages/client/src/pages/language-understanding/LUPage.tsx @@ -11,7 +11,7 @@ import { useRecoilValue } from 'recoil'; import { navigateTo, buildURL } from '../../utils/navigation'; import { LoadingSpinner } from '../../components/LoadingSpinner'; import { Page } from '../../components/Page'; -import { dialogIdsState } from '../../recoilModel'; +import { localeState, luFilesState } from '../../recoilModel'; import TableView from './table-view'; @@ -24,18 +24,23 @@ const LUPage: React.FC> = (props) => { const { dialogId = '', projectId = '', skillId, luFileId = '' } = props; - const dialogs = useRecoilValue(dialogIdsState(skillId ?? projectId)); + const actualProjectId = skillId ?? projectId; + const locale = useRecoilValue(localeState(actualProjectId)); + const luFiles = useRecoilValue(luFilesState(actualProjectId)); const path = props.location?.pathname ?? ''; const edit = /\/edit(\/)?$/.test(path); const isRoot = dialogId === 'all'; + const activeFile = luFileId + ? luFiles.find(({ id }) => id === luFileId || id === `${luFileId}.${locale}`) + : luFiles.find(({ id }) => id === dialogId || id === `${dialogId}.${locale}`); + useEffect(() => { - const activeDialog = dialogs.find((id) => id === dialogId); - if (!activeDialog && dialogId !== 'all' && dialogs.length && !luFileId) { + if (!activeFile && luFiles.length) { navigateTo(buildURL('language-understanding', { projectId, skillId })); } - }, [dialogId, dialogs, projectId, luFileId]); + }, [dialogId, luFiles, projectId, luFileId]); const onToggleEditMode = useCallback(() => { let url = buildURL('language-understanding', { projectId, skillId, dialogId }); @@ -73,8 +78,22 @@ const LUPage: React.FC }> - - + + diff --git a/Composer/packages/client/src/pages/language-understanding/code-editor.tsx b/Composer/packages/client/src/pages/language-understanding/code-editor.tsx index a056e8c01e..3f0cbd86c7 100644 --- a/Composer/packages/client/src/pages/language-understanding/code-editor.tsx +++ b/Composer/packages/client/src/pages/language-understanding/code-editor.tsx @@ -11,6 +11,7 @@ import { RouteComponentProps } from '@reach/router'; import querystring from 'query-string'; import { CodeEditorSettings } from '@bfc/shared'; import { useRecoilValue } from 'recoil'; +import { LuFile } from '@bfc/shared'; import { luFilesState, localeState, settingsState } from '../../recoilModel/atoms'; import { userSettingsState, dispatcherState } from '../../recoilModel'; @@ -24,6 +25,7 @@ interface CodeEditorProps extends RouteComponentProps<{}> { projectId: string; skillId?: string; luFileId?: string; + file?: LuFile; } const CodeEditor: React.FC = (props) => { @@ -34,7 +36,7 @@ const CodeEditor: React.FC = (props) => { updateUserSettings, setLocale, } = useRecoilValue(dispatcherState); - const { dialogId, projectId, skillId, luFileId } = props; + const { dialogId, projectId, skillId, luFileId, file } = props; const actualProjectId = skillId ?? projectId; const luFiles = useRecoilValue(luFilesState(actualProjectId)); @@ -43,10 +45,6 @@ const CodeEditor: React.FC = (props) => { const { languages, defaultLanguage } = settings; - const file = luFileId - ? luFiles.find(({ id }) => id === luFileId) - : luFiles.find(({ id }) => id === dialogId || id === `${dialogId}.${locale}`); - const defaultLangFile = luFileId ? luFiles.find(({ id }) => id === luFileId) : luFiles.find(({ id }) => id === `${dialogId}.${defaultLanguage}`); diff --git a/Composer/packages/client/src/pages/language-understanding/table-view.tsx b/Composer/packages/client/src/pages/language-understanding/table-view.tsx index 95a222d373..e79ebec04a 100644 --- a/Composer/packages/client/src/pages/language-understanding/table-view.tsx +++ b/Composer/packages/client/src/pages/language-understanding/table-view.tsx @@ -32,6 +32,7 @@ interface TableViewProps extends RouteComponentProps<{ dialogId: string; skillId skillId?: string; dialogId?: string; luFileId?: string; + file?: LuFile; } interface Intent { @@ -44,7 +45,7 @@ interface Intent { } const TableView: React.FC = (props) => { - const { dialogId, projectId, skillId, luFileId } = props; + const { dialogId, projectId, skillId, luFileId, file } = props; const actualProjectId = skillId ?? projectId; const baseURL = skillId == null ? `/bot/${projectId}/` : `/bot/${projectId}/skill/${skillId}/`; @@ -60,10 +61,6 @@ const TableView: React.FC = (props) => { const activeDialog = dialogs.find(({ id }) => id === dialogId); - const file = luFileId - ? luFiles.find(({ id }) => id === luFileId) - : luFiles.find(({ id }) => id === dialogId || id === `${dialogId}.${locale}`); - const defaultLangFile = luFileId ? luFiles.find(({ id }) => id === luFileId) : luFiles.find(({ id }) => id === `${dialogId}.${defaultLanguage}`); @@ -107,7 +104,7 @@ const TableView: React.FC = (props) => { return result.concat(items); }, []); - if (luFileId && file) { + if (file) { const luIntents: Intent[] = []; get(file, 'intents', []).forEach(({ Name: name, Body: phrases }) => { const state = getIntentState(file); @@ -127,7 +124,7 @@ const TableView: React.FC = (props) => { } else { setIntents(allIntents); } - }, [luFiles, activeDialog, actualProjectId, luFileId]); + }, [luFiles, activeDialog, actualProjectId, luFileId, file]); const handleIntentUpdate = useCallback( (fileId: string, intentName: string, intent: LuIntentSection) => { diff --git a/Composer/packages/client/src/utils/navigation.ts b/Composer/packages/client/src/utils/navigation.ts index a2da1037df..764938c358 100644 --- a/Composer/packages/client/src/utils/navigation.ts +++ b/Composer/packages/client/src/utils/navigation.ts @@ -121,11 +121,11 @@ export function buildURL(pageMode: PageMode, link: Partial) { const baseURL = skillId == null ? `/bot/${projectId}/` : `/bot/${projectId}/skill/${skillId}/`; if (pageMode === 'language-generation' && lgFileId) { - return `${baseURL}${pageMode}/${dialogId ?? 'all'}/item/${lgFileId}`; + return dialogId ? `${baseURL}${pageMode}/${dialogId}/item/${lgFileId}` : `${baseURL}${pageMode}/${lgFileId}`; } if (pageMode === 'language-understanding' && luFileId) { - return `${baseURL}${pageMode}/${dialogId ?? 'all'}/item/${luFileId}`; + return dialogId ? `${baseURL}${pageMode}/${dialogId}/item/${luFileId}` : `${baseURL}${pageMode}/${luFileId}`; } return `${baseURL}${pageMode}/${dialogId ?? 'all'}`;