diff --git a/Composer/packages/client/src/pages/knowledge-base/QnAPage.tsx b/Composer/packages/client/src/pages/knowledge-base/QnAPage.tsx index d54b371cd3..6494ac5ae6 100644 --- a/Composer/packages/client/src/pages/knowledge-base/QnAPage.tsx +++ b/Composer/packages/client/src/pages/knowledge-base/QnAPage.tsx @@ -21,17 +21,18 @@ import TableView from './table-view'; const CodeEditor = React.lazy(() => import('./code-editor')); -interface QnAPageProps extends RouteComponentProps<{}> { - projectId?: string; - dialogId?: string; -} +const QnAPage: React.FC> = (props) => { + const { dialogId = '', projectId = '', skillId } = props; -const QnAPage: React.FC = (props) => { - const { dialogId = '', projectId = '' } = props; + const baseURL = skillId == null ? `/bot/${projectId}/` : `/bot/${projectId}/skill/${skillId}/`; const actions = useRecoilValue(dispatcherState); - const dialogs = useRecoilValue(dialogsSelectorFamily(projectId)); - const qnaFiles = useRecoilValue(qnaFilesState(projectId)); + const dialogs = useRecoilValue(dialogsSelectorFamily(skillId ?? projectId)); + const qnaFiles = useRecoilValue(qnaFilesState(skillId ?? projectId)); //To do: support other languages const locale = 'en-us'; //const locale = useRecoilValue(localeState); @@ -47,7 +48,7 @@ const QnAPage: React.FC = (props) => { id: dialog.id, name: dialog.displayName, ariaLabel: formatMessage('qna file'), - url: `/bot/${projectId}/knowledge-base/${dialog.id}`, + url: `${baseURL}knowledge-base/${dialog.id}`, menuIconProps: { iconName: 'Add', }, @@ -81,7 +82,7 @@ const QnAPage: React.FC = (props) => { id: 'all', name: 'All', ariaLabel: formatMessage('all qna files'), - url: `/bot/${projectId}/knowledge-base/all`, + url: `${baseURL}knowledge-base/all`, }); return newDialogLinks; }, [dialogs]); @@ -90,13 +91,13 @@ const QnAPage: React.FC = (props) => { setCreateOnDialogId(''); const activeDialog = dialogs.find(({ id }) => id === dialogId); if (!activeDialog && dialogs.length && dialogId !== 'all') { - navigateTo(`/bot/${projectId}/knowledge-base/${dialogId}`); + navigateTo(`${baseURL}knowledge-base/${dialogId}`); } }, [dialogId, dialogs, projectId]); const onToggleEditMode = useCallback( (_e) => { - let url = `/bot/${projectId}/knowledge-base/${dialogId}`; + let url = `${baseURL}knowledge-base/${dialogId}`; if (!edit) url += `/edit`; navigateTo(url); }, diff --git a/Composer/packages/client/src/pages/language-generation/LGPage.tsx b/Composer/packages/client/src/pages/language-generation/LGPage.tsx index fa55cb201c..adb275f743 100644 --- a/Composer/packages/client/src/pages/language-generation/LGPage.tsx +++ b/Composer/packages/client/src/pages/language-generation/LGPage.tsx @@ -18,22 +18,23 @@ import { validateDialogsSelectorFamily } from '../../recoilModel'; import TableView from './table-view'; const CodeEditor = React.lazy(() => import('./code-editor')); -interface LGPageProps { +const LGPage: React.FC> = (props: RouteComponentProps) => { - const { dialogId = '', projectId = '' } = props; - const dialogs = useRecoilValue(validateDialogsSelectorFamily(projectId)); + skillId: string; +}>> = (props) => { + const { dialogId = '', projectId = '', skillId } = props; + const dialogs = useRecoilValue(validateDialogsSelectorFamily(skillId ?? projectId ?? '')); const path = props.location?.pathname ?? ''; const edit = /\/edit(\/)?$/.test(path); + const baseURL = skillId == null ? `/bot/${projectId}/` : `/bot/${projectId}/skill/${skillId}/`; + const navLinks: INavTreeItem[] = useMemo(() => { const newDialogLinks: INavTreeItem[] = dialogs.map((dialog) => { - let url = `/bot/${projectId}/language-generation/${dialog.id}`; + let url = `${baseURL}language-generation/${dialog.id}`; if (edit) { url += `/edit`; } @@ -50,7 +51,7 @@ const LGPage: React.FC> = (props: RouteComponen const mainDialog = newDialogLinks.splice(mainDialogIndex, 1)[0]; newDialogLinks.splice(0, 0, mainDialog); } - let commonUrl = `/bot/${projectId}/language-generation/common`; + let commonUrl = `${baseURL}language-generation/common`; if (edit) { commonUrl += '/edit'; } @@ -67,13 +68,13 @@ const LGPage: React.FC> = (props: RouteComponen useEffect(() => { const activeDialog = dialogs.find(({ id }) => id === dialogId); if (!activeDialog && dialogs.length && dialogId !== 'common') { - navigateTo(`/bot/${projectId}/language-generation/common`); + navigateTo(`${baseURL}language-generation/common`); } }, [dialogId, dialogs, projectId]); const onToggleEditMode = useCallback( (_e) => { - let url = `/bot/${projectId}/language-generation/${dialogId}`; + let url = `${baseURL}language-generation/${dialogId}`; if (!edit) url += `/edit`; navigateTo(url); }, diff --git a/Composer/packages/client/src/pages/language-understanding/LUPage.tsx b/Composer/packages/client/src/pages/language-understanding/LUPage.tsx index 70e4fc433b..024a3e80b7 100644 --- a/Composer/packages/client/src/pages/language-understanding/LUPage.tsx +++ b/Composer/packages/client/src/pages/language-understanding/LUPage.tsx @@ -18,19 +18,21 @@ import TableView from './table-view'; const CodeEditor = React.lazy(() => import('./code-editor')); const LUPage: React.FC> = (props) => { - const { dialogId = '', projectId = '' } = props; - const dialogs = useRecoilValue(validateDialogsSelectorFamily(projectId)); + const { dialogId = '', projectId = '', skillId } = props; + const dialogs = useRecoilValue(validateDialogsSelectorFamily(skillId ?? projectId ?? '')); const path = props.location?.pathname ?? ''; const edit = /\/edit(\/)?$/.test(path); const isRoot = dialogId === 'all'; + const baseURL = skillId == null ? `/bot/${projectId}/` : `/bot/${projectId}/skill/${skillId}/`; const navLinks: INavTreeItem[] = useMemo(() => { const newDialogLinks: INavTreeItem[] = dialogs.map((dialog) => { - let url = `/bot/${projectId}/language-understanding/${dialog.id}`; + let url = `${baseURL}language-understanding/${dialog.id}`; if (edit) { url += `/edit`; } @@ -51,7 +53,7 @@ const LUPage: React.FC { const activeDialog = dialogs.find(({ id }) => id === dialogId); if (!activeDialog && dialogId !== 'all' && dialogs.length) { - navigateTo(`/bot/${projectId}/language-understanding/all`); + navigateTo(`${baseURL}language-understanding/all`); } }, [dialogId, dialogs, projectId]); const onToggleEditMode = useCallback( (_e) => { - let url = `/bot/${projectId}/language-understanding/${dialogId}`; + let url = `${baseURL}language-understanding/${dialogId}`; if (!edit) url += `/edit`; navigateTo(url); }, diff --git a/Composer/packages/client/src/utils/hooks.ts b/Composer/packages/client/src/utils/hooks.ts index 662bad635b..c7cd7c6168 100644 --- a/Composer/packages/client/src/utils/hooks.ts +++ b/Composer/packages/client/src/utils/hooks.ts @@ -44,13 +44,14 @@ export const useFeatureFlag = (featureFlagKey: FeatureFlagKey): boolean => { export const useLinks = () => { const projectId = useRecoilValue(currentProjectIdState); + const rootProjectId = useRecoilValue(rootBotProjectIdSelector); const designPageLocation = useRecoilValue(designPageLocationState(projectId)); const pluginPages = useRecoilValue(pluginPagesSelector); const openedDialogId = designPageLocation.dialogId || 'Main'; const showFormDialog = useFeatureFlag('FORM_DIALOG'); const pageLinks = useMemo(() => { - return topLinks(projectId, openedDialogId, pluginPages, showFormDialog); + return topLinks(projectId, openedDialogId, pluginPages, showFormDialog, rootProjectId); }, [projectId, openedDialogId, pluginPages, showFormDialog]); return { topLinks: pageLinks, bottomLinks }; diff --git a/Composer/packages/client/src/utils/pageLinks.ts b/Composer/packages/client/src/utils/pageLinks.ts index e152bef987..ced601d7c8 100644 --- a/Composer/packages/client/src/utils/pageLinks.ts +++ b/Composer/packages/client/src/utils/pageLinks.ts @@ -9,9 +9,14 @@ export const topLinks = ( projectId: string, openedDialogId: string, pluginPages: ExtensionPageConfig[], - showFormDialog: boolean + showFormDialog: boolean, + rootProjectId: string | undefined ) => { const botLoaded = !!projectId; + const linkBase = + projectId === rootProjectId || rootProjectId == null + ? `/bot/${projectId}/` + : `/bot/${rootProjectId}/skill/${projectId}/`; let links = [ { to: '/home', @@ -21,28 +26,28 @@ export const topLinks = ( disabled: false, }, { - to: `/bot/${projectId}/dialogs/${openedDialogId}`, + to: linkBase + `dialogs/${openedDialogId}`, iconName: 'SplitObject', labelName: formatMessage('Design'), exact: false, disabled: !botLoaded, }, { - to: `/bot/${projectId}/language-generation`, + to: linkBase + `language-generation/${openedDialogId}`, iconName: 'Robot', labelName: formatMessage('Bot Responses'), exact: false, disabled: !botLoaded, }, { - to: `/bot/${projectId}/language-understanding`, + to: linkBase + `language-understanding/${openedDialogId}`, iconName: 'People', labelName: formatMessage('User Input'), exact: false, disabled: !botLoaded, }, { - to: `/bot/${projectId}/knowledge-base`, + to: linkBase + `knowledge-base/${openedDialogId}`, iconName: 'QnAIcon', labelName: formatMessage('QnA'), exact: true, diff --git a/Composer/packages/server/src/__mocks__/samplebots/bot1/settings/appsettings.json b/Composer/packages/server/src/__mocks__/samplebots/bot1/settings/appsettings.json index e468dd1746..640496cb60 100644 --- a/Composer/packages/server/src/__mocks__/samplebots/bot1/settings/appsettings.json +++ b/Composer/packages/server/src/__mocks__/samplebots/bot1/settings/appsettings.json @@ -24,5 +24,11 @@ "languages": [ "en-us" ], - "MicrosoftAppPassword": "" + "MicrosoftAppPassword": "", + "skillConfiguration": { + "isSkill": false, + "allowedCallers": [ + "*" + ] + } } \ No newline at end of file