Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -187,34 +187,47 @@ describe('generateDispatchModels', () => {
const dialogs: any = [{ id: 'test', content: { recognizer: 'test.lu' } }];
const selectedTriggers = [];
const luFiles = [];
const result = generateDispatchModels(schema, dialogs, selectedTriggers, luFiles);
const qnaFiles = [];
const result = generateDispatchModels(schema, dialogs, selectedTriggers, luFiles, qnaFiles);
expect(result).toEqual({});
});

it("should return empty object if the schema doesn't include dispatchModels", () => {
const schema = { properties: {} };
const dialogs: any = [{ id: 'test', content: { recognizer: 'test.lu' } }];
const dialogs: any = [{ id: 'test', content: { recognizer: 'test.lu.qna' } }];
const selectedTriggers = [{ $kind: SDKKinds.OnIntent, intent: 'testIntent' }];
const luFiles: any = [{ id: 'test.en-us' }, { id: 'test.fr-FR' }];
const result = generateDispatchModels(schema, dialogs, selectedTriggers, luFiles);
const luFiles: any = [
{ id: 'test.en-us', empty: false },
{ id: 'test.fr-FR', empty: false },
];
const qnaFiles = [];
const result = generateDispatchModels(schema, dialogs, selectedTriggers, luFiles, qnaFiles);
expect(result).toEqual({});
});

it('should return empty object if the recognizer type is not luis', () => {
const schema = { properties: {} };
const dialogs: any = [{ id: 'test', content: {} }];
const selectedTriggers = [{ $kind: SDKKinds.OnIntent, intent: 'testIntent' }];
const luFiles: any = [{ id: 'test.en-us' }, { id: 'test.fr-FR' }];
const result = generateDispatchModels(schema, dialogs, selectedTriggers, luFiles);
const luFiles: any = [
{ id: 'test.en-us', empty: false },
{ id: 'test.fr-FR', empty: false },
];
const qnaFiles = [];
const result = generateDispatchModels(schema, dialogs, selectedTriggers, luFiles, qnaFiles);
expect(result).toEqual({});
});

it('should return dispatch models', () => {
const schema = { properties: { dispatchModels: {} } };
const dialogs: any = [{ id: 'test', content: { recognizer: 'test.lu' }, isRoot: true }];
const dialogs: any = [{ id: 'test', content: { recognizer: 'test.lu.qna' }, isRoot: true }];
const selectedTriggers = [{ $kind: SDKKinds.OnIntent, intent: 'testIntent' }];
const luFiles: any = [{ id: 'test.en-us' }, { id: 'test.fr-FR' }];
const result = generateDispatchModels(schema, dialogs, selectedTriggers, luFiles);
const luFiles: any = [
{ id: 'test.en-us', empty: false },
{ id: 'test.fr-FR', empty: false },
];
const qnaFiles: any = [{ id: 'test.es-es', empty: false }];
const result = generateDispatchModels(schema, dialogs, selectedTriggers, luFiles, qnaFiles);
expect(result).toEqual(
expect.objectContaining({
dispatchModels: {
Expand All @@ -223,15 +236,23 @@ describe('generateDispatchModels', () => {
{
name: 'test',
contentType: 'application/lu',
url: `<test.en-us url>`,
url: `<test.en-us.lu url>`,
description: '<description>',
},
],
'fr-FR': [
{
name: 'test',
contentType: 'application/lu',
url: `<test.fr-FR url>`,
url: `<test.fr-FR.lu url>`,
description: '<description>',
},
],
'es-es': [
{
name: 'test',
contentType: 'application/qna',
url: `<test.es-es.qna url>`,
description: '<description>',
},
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.

import get from 'lodash/get';
import { DialogInfo, DialogSchemaFile, ITrigger, SDKKinds, SkillManifest, LuFile } from '@bfc/shared';
import { DialogInfo, DialogSchemaFile, ITrigger, SDKKinds, SkillManifest, LuFile, QnAFile } from '@bfc/shared';
import { JSONSchema7 } from '@bfc/extension-client';

import { Activities, Activity, activityHandlerMap, ActivityTypes, DispatchModels } from './constants';
Expand All @@ -17,6 +17,7 @@ export const generateSkillManifest = (
dialogs: DialogInfo[],
dialogSchemas: DialogSchemaFile[],
luFiles: LuFile[],
qnaFiles: QnAFile[],
selectedTriggers: ITrigger[],
selectedDialogs: Partial<DialogInfo>[]
) => {
Expand All @@ -41,7 +42,7 @@ export const generateSkillManifest = (
}, []);

const activities = generateActivities(dialogSchemas, triggers, resolvedDialogs);
const dispatchModels = generateDispatchModels(schema, dialogs, triggers, luFiles);
const dispatchModels = generateDispatchModels(schema, dialogs, triggers, luFiles, qnaFiles);
const definitions = getDefinitions(dialogSchemas, resolvedDialogs);

return {
Expand Down Expand Up @@ -104,7 +105,8 @@ export const generateDispatchModels = (
schema: JSONSchema7,
dialogs: DialogInfo[],
selectedTriggers: any[],
luFiles: LuFile[]
luFiles: LuFile[],
qnaFiles: QnAFile[]
): { dispatchModels?: DispatchModels } => {
const intents = selectedTriggers.filter(({ $kind }) => $kind === SDKKinds.OnIntent).map(({ intent }) => intent);
const { id: rootId } = dialogs.find((dialog) => dialog?.isRoot) || {};
Expand All @@ -114,16 +116,46 @@ export const generateDispatchModels = (
return luId === rootId;
});

if (!intents.length || !schema.properties?.dispatchModels) {
const rootQnAFiles = qnaFiles.filter(({ id: qnaFileId }) => {
const [qnaId] = qnaFileId.split('.');
return qnaId === rootId;
});

if (!schema.properties?.dispatchModels) {
return {};
}

const languages = rootLuFiles.reduce((acc, { id }) => {
const luLanguages = intents.length
? rootLuFiles.reduce((acc, { empty, id }) => {
const [name, locale] = id.split('.');
const { content = {} } = dialogs.find(({ id }) => id === name) || {};
const { recognizer = '' } = content;

if (!recognizer.includes('.lu') || empty) {
return acc;
}

return {
...acc,
[locale]: [
...(acc[locale] ?? []),
{
name,
contentType: 'application/lu',
url: `<${id}.lu url>`,
description: '<description>',
},
],
};
}, {})
: {};

const languages = rootQnAFiles.reduce((acc, { empty, id }) => {
const [name, locale] = id.split('.');
const { content = {} } = dialogs.find(({ id }) => id === name) || {};
const { recognizer = '' } = content;

if (!''.endsWith.call(recognizer, '.lu')) {
if (!recognizer.includes('.qna') || empty) {
return acc;
}

Expand All @@ -133,19 +165,21 @@ export const generateDispatchModels = (
...(acc[locale] ?? []),
{
name,
contentType: 'application/lu',
url: `<${id} url>`,
contentType: 'application/qna',
url: `<${id}.qna url>`,
description: '<description>',
},
],
};
}, {});
}, luLanguages);

const dispatchModels = {
...(Object.keys(languages).length ? { languages } : {}),
...(intents.length ? { intents } : {}),
};

return {
dispatchModels: {
...(Object.keys(languages).length ? { languages } : {}),
...(intents.length ? { intents } : {}),
},
...(Object.keys(dispatchModels).length ? { dispatchModels } : {}),
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
dispatcherState,
luFilesState,
skillManifestsState,
qnaFilesState,
} from '../../../recoilModel';

import { editorSteps, ManifestEditorSteps, order } from './constants';
Expand All @@ -34,6 +35,7 @@ const ExportSkillModal: React.FC<ExportSkillModalProps> = ({ onSubmit, onDismiss
const dialogs = useRecoilValue(dialogsState);
const dialogSchemas = useRecoilValue(dialogSchemasState);
const luFiles = useRecoilValue(luFilesState);
const qnaFiles = useRecoilValue(qnaFilesState);
const skillManifests = useRecoilValue(skillManifestsState);
const { updateSkillManifest } = useRecoilValue(dispatcherState);

Expand All @@ -59,6 +61,7 @@ const ExportSkillModal: React.FC<ExportSkillModalProps> = ({ onSubmit, onDismiss
dialogs,
dialogSchemas,
luFiles,
qnaFiles,
selectedTriggers,
selectedDialogs
);
Expand Down