diff --git a/Composer/packages/client/src/pages/notifications/NotificationList.tsx b/Composer/packages/client/src/pages/notifications/NotificationList.tsx
index a50bf2e88a..9aadd3b14e 100644
--- a/Composer/packages/client/src/pages/notifications/NotificationList.tsx
+++ b/Composer/packages/client/src/pages/notifications/NotificationList.tsx
@@ -43,6 +43,7 @@ const columns: IColumn[] = [
return ;
},
},
+
{
key: 'NotificationType',
name: formatMessage('Type'),
@@ -68,6 +69,31 @@ const columns: IColumn[] = [
},
isPadded: true,
},
+ {
+ key: 'NotificationBotName',
+ name: formatMessage('Bot'),
+ className: notification.columnCell,
+ fieldName: 'botName',
+ minWidth: 70,
+ maxWidth: 90,
+ isRowHeader: true,
+ isResizable: true,
+ data: 'string',
+ onRender: (item: INotification) => {
+ return (
+
+ );
+ },
+ isPadded: true,
+ },
{
key: 'NotificationLocation',
name: formatMessage('Location'),
diff --git a/Composer/packages/client/src/pages/notifications/Notifications.tsx b/Composer/packages/client/src/pages/notifications/Notifications.tsx
index 89d0377eed..4057f06db6 100644
--- a/Composer/packages/client/src/pages/notifications/Notifications.tsx
+++ b/Composer/packages/client/src/pages/notifications/Notifications.tsx
@@ -20,13 +20,18 @@ const Notifications: React.FC> = (pro
const { projectId = '' } = props;
const [filter, setFilter] = useState('');
const notifications = useNotifications(projectId, filter);
+ const rootProjectId = projectId;
+
const navigations = {
[NotificationType.LG]: (item: INotification) => {
const { projectId, resourceId, diagnostic, dialogPath } = item;
let uri = `/bot/${projectId}/language-generation/${resourceId}/edit#L=${diagnostic.range?.start.line || 0}`;
//the format of item.id is lgFile#inlineTemplateId
if (dialogPath) {
- uri = convertPathToUrl(projectId, resourceId, dialogPath);
+ uri =
+ rootProjectId === projectId
+ ? convertPathToUrl(projectId, null, resourceId, dialogPath)
+ : convertPathToUrl(rootProjectId, projectId, resourceId, dialogPath);
}
navigateTo(uri);
},
@@ -34,7 +39,10 @@ const Notifications: React.FC> = (pro
const { projectId, resourceId, diagnostic, dialogPath } = item;
let uri = `/bot/${projectId}/language-understanding/${resourceId}/edit#L=${diagnostic.range?.start.line || 0}`;
if (dialogPath) {
- uri = convertPathToUrl(projectId, resourceId, dialogPath);
+ uri =
+ rootProjectId === projectId
+ ? convertPathToUrl(projectId, null, resourceId, dialogPath)
+ : convertPathToUrl(rootProjectId, projectId, resourceId, dialogPath);
}
navigateTo(uri);
},
@@ -46,8 +54,11 @@ const Notifications: React.FC> = (pro
[NotificationType.DIALOG]: (item: INotification) => {
//path is like main.trigers[0].actions[0]
//uri = id?selected=triggers[0]&focused=triggers[0].actions[0]
- const { projectId, id, dialogPath } = item;
- const uri = convertPathToUrl(projectId, id, dialogPath ?? '');
+ const { projectId, id, dialogPath = '' } = item;
+ const uri =
+ rootProjectId === projectId
+ ? convertPathToUrl(projectId, null, id, dialogPath)
+ : convertPathToUrl(rootProjectId, projectId, id, dialogPath);
navigateTo(uri);
},
[NotificationType.SKILL]: (item: INotification) => {
diff --git a/Composer/packages/client/src/pages/notifications/types.ts b/Composer/packages/client/src/pages/notifications/types.ts
index 1253df95c2..fbde0a273b 100644
--- a/Composer/packages/client/src/pages/notifications/types.ts
+++ b/Composer/packages/client/src/pages/notifications/types.ts
@@ -20,6 +20,7 @@ export enum NotificationType {
export interface INotification {
projectId: string;
+ botName: string;
id: string;
severity: string;
type: NotificationType;
@@ -32,6 +33,7 @@ export interface INotification {
export abstract class Notification implements INotification {
projectId: string;
+ botName: string;
id: string;
severity: string;
type = NotificationType.GENERAL;
@@ -40,8 +42,9 @@ export abstract class Notification implements INotification {
diagnostic: Diagnostic;
dialogPath?: string;
resourceId: string;
- constructor(projectId: string, id: string, location: string, diagnostic: Diagnostic) {
+ constructor(projectId: string, botName: string, id: string, location: string, diagnostic: Diagnostic) {
this.projectId = projectId;
+ this.botName = botName;
this.id = id;
this.resourceId = getBaseName(id);
this.severity = DiagnosticSeverity[diagnostic.severity] || '';
@@ -52,16 +55,16 @@ export abstract class Notification implements INotification {
export class ServerNotification extends Notification {
type = NotificationType.GENERAL;
- constructor(projectId: string, id: string, location: string, diagnostic: Diagnostic) {
- super(projectId, id, location, diagnostic);
+ constructor(projectId: string, botName: string, id: string, location: string, diagnostic: Diagnostic) {
+ super(projectId, botName, id, location, diagnostic);
this.message = diagnostic.message;
}
}
export class DialogNotification extends Notification {
type = NotificationType.DIALOG;
- constructor(projectId: string, id: string, location: string, diagnostic: Diagnostic) {
- super(projectId, id, location, diagnostic);
+ constructor(projectId: string, botName: string, id: string, location: string, diagnostic: Diagnostic) {
+ super(projectId, botName, id, location, diagnostic);
this.message = `In ${replaceDialogDiagnosticLabel(diagnostic.path)} ${diagnostic.message}`;
this.dialogPath = diagnostic.path;
}
@@ -69,8 +72,8 @@ export class DialogNotification extends Notification {
export class SkillNotification extends Notification {
type = NotificationType.SKILL;
- constructor(projectId: string, id: string, location: string, diagnostic: Diagnostic) {
- super(projectId, id, location, diagnostic);
+ constructor(projectId: string, botName: string, id: string, location: string, diagnostic: Diagnostic) {
+ super(projectId, botName, id, location, diagnostic);
this.message = `${replaceDialogDiagnosticLabel(diagnostic.path)} ${diagnostic.message}`;
this.dialogPath = diagnostic.path;
}
@@ -78,8 +81,8 @@ export class SkillNotification extends Notification {
export class SettingNotification extends Notification {
type = NotificationType.SETTING;
- constructor(projectId: string, id: string, location: string, diagnostic: Diagnostic) {
- super(projectId, id, location, diagnostic);
+ constructor(projectId: string, botName: string, id: string, location: string, diagnostic: Diagnostic) {
+ super(projectId, botName, id, location, diagnostic);
this.message = `${replaceDialogDiagnosticLabel(diagnostic.path)} ${diagnostic.message}`;
this.dialogPath = diagnostic.path;
}
@@ -89,13 +92,14 @@ export class LgNotification extends Notification {
type = NotificationType.LG;
constructor(
projectId: string,
+ botName: string,
id: string,
location: string,
diagnostic: Diagnostic,
lgFile: LgFile,
dialogs: DialogInfo[]
) {
- super(projectId, id, location, diagnostic);
+ super(projectId, botName, id, location, diagnostic);
this.message = createSingleMessage(diagnostic);
this.dialogPath = this.findDialogPath(lgFile, dialogs, diagnostic);
}
@@ -120,13 +124,14 @@ export class LuNotification extends Notification {
type = NotificationType.LU;
constructor(
projectId: string,
+ botName: string,
id: string,
location: string,
diagnostic: Diagnostic,
luFile: LuFile,
dialogs: DialogInfo[]
) {
- super(projectId, id, location, diagnostic);
+ super(projectId, botName, id, location, diagnostic);
this.dialogPath = this.findDialogPath(luFile, dialogs, diagnostic);
this.message = createSingleMessage(diagnostic);
}
@@ -146,8 +151,8 @@ export class LuNotification extends Notification {
export class QnANotification extends Notification {
type = NotificationType.QNA;
- constructor(projectId: string, id: string, location: string, diagnostic: Diagnostic) {
- super(projectId, id, location, diagnostic);
+ constructor(projectId: string, botName: string, id: string, location: string, diagnostic: Diagnostic) {
+ super(projectId, botName, id, location, diagnostic);
this.dialogPath = '';
this.message = createSingleMessage(diagnostic);
}
diff --git a/Composer/packages/client/src/pages/notifications/useNotifications.tsx b/Composer/packages/client/src/pages/notifications/useNotifications.tsx
index 08997f0e14..365502a4e2 100644
--- a/Composer/packages/client/src/pages/notifications/useNotifications.tsx
+++ b/Composer/packages/client/src/pages/notifications/useNotifications.tsx
@@ -1,116 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-import { BotIndexer } from '@bfc/indexers';
-import { BotAssets } from '@bfc/shared';
-import get from 'lodash/get';
-import { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
-import {
- botDiagnosticsState,
- botProjectFileState,
- crossTrainConfigState,
- dialogSchemasState,
- formDialogSchemasSelectorFamily,
- jsonSchemaFilesState,
- lgFilesState,
- luFilesState,
- qnaFilesState,
- settingsState,
- skillManifestsState,
- validateDialogsSelectorFamily,
-} from '../../recoilModel';
-import { recognizersSelectorFamily } from '../../recoilModel/selectors/recognizers';
+import { messagersSelector } from '../../recoilModel/selectors';
-import { getReferredLuFiles } from './../../utils/luUtil';
-import {
- DialogNotification,
- LgNotification,
- LuNotification,
- Notification,
- QnANotification,
- ServerNotification,
- SettingNotification,
- SkillNotification,
-} from './types';
-
-export default function useNotifications(projectId: string, filter?: string) {
- const dialogs = useRecoilValue(validateDialogsSelectorFamily(projectId));
- const luFiles = useRecoilValue(luFilesState(projectId));
- const lgFiles = useRecoilValue(lgFilesState(projectId));
- const diagnostics = useRecoilValue(botDiagnosticsState(projectId));
- const setting = useRecoilValue(settingsState(projectId));
- const skillManifests = useRecoilValue(skillManifestsState(projectId));
- const dialogSchemas = useRecoilValue(dialogSchemasState(projectId));
- const qnaFiles = useRecoilValue(qnaFilesState(projectId));
- const formDialogSchemas = useRecoilValue(formDialogSchemasSelectorFamily(projectId));
- const botProjectFile = useRecoilValue(botProjectFileState(projectId));
- const jsonSchemaFiles = useRecoilValue(jsonSchemaFilesState(projectId));
- const recognizers = useRecoilValue(recognizersSelectorFamily(projectId));
- const crossTrainConfig = useRecoilValue(crossTrainConfigState(projectId));
- const botAssets: BotAssets = {
- projectId,
- dialogs,
- luFiles,
- qnaFiles,
- lgFiles,
- skillManifests,
- setting,
- dialogSchemas,
- formDialogSchemas,
- botProjectFile,
- jsonSchemaFiles,
- recognizers,
- crossTrainConfig,
- };
-
- const memoized = useMemo(() => {
- const notifications: Notification[] = [];
- diagnostics.forEach((d) => {
- notifications.push(new ServerNotification(projectId, '', d.source, d));
- });
- const skillDiagnostics = BotIndexer.checkSkillSetting(botAssets);
- skillDiagnostics.forEach((item) => {
- if (item.source.endsWith('.json')) {
- notifications.push(new SkillNotification(projectId, item.source, item.source, item));
- } else {
- notifications.push(new DialogNotification(projectId, item.source, item.source, item));
- }
- });
- const luisLocaleDiagnostics = BotIndexer.checkLUISLocales(botAssets);
-
- luisLocaleDiagnostics.forEach((item) => {
- notifications.push(new SettingNotification(projectId, item.source, item.source, item));
- });
-
- dialogs.forEach((dialog) => {
- dialog.diagnostics.forEach((diagnostic) => {
- const location = `${dialog.id}.dialog`;
- notifications.push(new DialogNotification(projectId, dialog.id, location, diagnostic));
- });
- });
- getReferredLuFiles(luFiles, dialogs).forEach((lufile) => {
- lufile.diagnostics.forEach((diagnostic) => {
- const location = `${lufile.id}.lu`;
- notifications.push(new LuNotification(projectId, lufile.id, location, diagnostic, lufile, dialogs));
- });
- });
- lgFiles.forEach((lgFile) => {
- lgFile.diagnostics.forEach((diagnostic) => {
- const location = `${lgFile.id}.lg`;
- notifications.push(new LgNotification(projectId, lgFile.id, location, diagnostic, lgFile, dialogs));
- });
- });
- qnaFiles.forEach((qnaFile) => {
- get(qnaFile, 'diagnostics', []).forEach((diagnostic) => {
- const location = `${qnaFile.id}.qna`;
- notifications.push(new QnANotification(projectId, qnaFile.id, location, diagnostic));
- });
- });
- return notifications;
- }, [botAssets, diagnostics]);
-
- const notifications: Notification[] = filter ? memoized.filter((x) => x.severity === filter) : memoized;
- return notifications;
+export default function useNotifications(_projectId: string, filter?: string) {
+ const messagers = useRecoilValue(messagersSelector);
+ return filter ? messagers.filter((x) => x.severity === filter) : messagers;
}
diff --git a/Composer/packages/client/src/recoilModel/selectors/index.ts b/Composer/packages/client/src/recoilModel/selectors/index.ts
index 062b4fdbe0..37b4503a74 100644
--- a/Composer/packages/client/src/recoilModel/selectors/index.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/index.ts
@@ -8,3 +8,4 @@ export * from './validatedDialogs';
export * from './dialogs';
export * from './dialogImports';
export * from './projectTemplates';
+export * from './messagers';
diff --git a/Composer/packages/client/src/recoilModel/selectors/messagers.ts b/Composer/packages/client/src/recoilModel/selectors/messagers.ts
new file mode 100644
index 0000000000..5b689542d6
--- /dev/null
+++ b/Composer/packages/client/src/recoilModel/selectors/messagers.ts
@@ -0,0 +1,124 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+import { selector } from 'recoil';
+import { BotIndexer } from '@bfc/indexers';
+import { BotAssets } from '@bfc/shared';
+
+import {
+ botDiagnosticsState,
+ botProjectFileState,
+ botProjectSpaceSelector,
+ crossTrainConfigState,
+ dialogSchemasState,
+ formDialogSchemasSelectorFamily,
+ jsonSchemaFilesState,
+ lgFilesState,
+ luFilesState,
+ qnaFilesState,
+ settingsState,
+ skillManifestsState,
+ validateDialogsSelectorFamily,
+} from '../../recoilModel';
+import { recognizersSelectorFamily } from '../../recoilModel/selectors/recognizers';
+import {
+ DialogNotification,
+ LgNotification,
+ LuNotification,
+ Notification,
+ QnANotification,
+ ServerNotification,
+ SettingNotification,
+ SkillNotification,
+} from '../../pages/notifications/types';
+
+import { getReferredLuFiles } from './../../utils/luUtil';
+
+export const messagersSelector = selector({
+ key: 'messagersSelector',
+ get: ({ get }) => {
+ const botProjectSpace = get(botProjectSpaceSelector);
+ const allMessage: Notification[] = [];
+
+ console.log(botProjectSpace);
+ for (const project of botProjectSpace) {
+ const { projectId, name } = project;
+ const dialogs = get(validateDialogsSelectorFamily(projectId));
+ const luFiles = get(luFilesState(projectId));
+ const lgFiles = get(lgFilesState(projectId));
+ const diagnostics = get(botDiagnosticsState(projectId));
+ const setting = get(settingsState(projectId));
+ const skillManifests = get(skillManifestsState(projectId));
+ const dialogSchemas = get(dialogSchemasState(projectId));
+ const qnaFiles = get(qnaFilesState(projectId));
+ const formDialogSchemas = get(formDialogSchemasSelectorFamily(projectId));
+ const botProjectFile = get(botProjectFileState(projectId));
+ const jsonSchemaFiles = get(jsonSchemaFilesState(projectId));
+ const recognizers = get(recognizersSelectorFamily(projectId));
+ const crossTrainConfig = get(crossTrainConfigState(projectId));
+ const botAssets: BotAssets = {
+ projectId,
+ dialogs,
+ luFiles,
+ qnaFiles,
+ lgFiles,
+ skillManifests,
+ setting,
+ dialogSchemas,
+ formDialogSchemas,
+ botProjectFile,
+ jsonSchemaFiles,
+ recognizers,
+ crossTrainConfig,
+ };
+
+ const notifications: Notification[] = [];
+ diagnostics.forEach((d) => {
+ notifications.push(new ServerNotification(projectId, name, '', d.source, d));
+ });
+ const skillDiagnostics = BotIndexer.checkSkillSetting(botAssets);
+ skillDiagnostics.forEach((item) => {
+ if (item.source.endsWith('.json')) {
+ notifications.push(new SkillNotification(projectId, name, item.source, item.source, item));
+ } else {
+ notifications.push(new DialogNotification(projectId, name, item.source, item.source, item));
+ }
+ });
+ const luisLocaleDiagnostics = BotIndexer.checkLUISLocales(botAssets);
+
+ luisLocaleDiagnostics.forEach((item) => {
+ notifications.push(new SettingNotification(projectId, name, item.source, item.source, item));
+ });
+
+ dialogs.forEach((dialog) => {
+ dialog.diagnostics.forEach((diagnostic) => {
+ const location = `${dialog.id}.dialog`;
+ notifications.push(new DialogNotification(projectId, name, dialog.id, location, diagnostic));
+ });
+ });
+ getReferredLuFiles(luFiles, dialogs).forEach((lufile) => {
+ lufile.diagnostics.forEach((diagnostic) => {
+ const location = `${lufile.id}.lu`;
+ notifications.push(new LuNotification(projectId, name, lufile.id, location, diagnostic, lufile, dialogs));
+ });
+ });
+ lgFiles.forEach((lgFile) => {
+ lgFile.diagnostics.forEach((diagnostic) => {
+ const location = `${lgFile.id}.lg`;
+ notifications.push(new LgNotification(projectId, name, lgFile.id, location, diagnostic, lgFile, dialogs));
+ });
+ });
+ qnaFiles.forEach((qnaFile) => {
+ qnaFile.diagnostics.forEach((diagnostic) => {
+ const location = `${qnaFile.id}.qna`;
+ notifications.push(new QnANotification(projectId, name, qnaFile.id, location, diagnostic));
+ });
+ });
+ allMessage.push(...notifications);
+ }
+
+ return allMessage;
+ },
+});