Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Added form dialog generation controller #4037

Merged
merged 9 commits into from
Sep 10, 2020
1 change: 1 addition & 0 deletions Composer/packages/lib/shared/src/types/indexers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export enum FileExtensions {
Lg = '.lg',
Qna = '.qna',
Setting = 'appsettings.json',
FormDialogSchema = '.form-dialog',
}

export interface FileInfo {
Expand Down
3 changes: 2 additions & 1 deletion Composer/packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"@bfc/plugin-loader": "*",
"@bfc/shared": "*",
"@microsoft/bf-dispatcher": "^4.10.0-preview.141651",
"@microsoft/bf-generate-library": "^4.10.0-daily.20200827.161452",
"@microsoft/bf-lu": "^4.10.0-dev.20200808.5a7c973",
"archiver": "^3.0.0",
"axios": "^0.19.2",
Expand Down Expand Up @@ -99,4 +100,4 @@
"resolutions": {
"bl": "^2.2.1"
}
}
}
57 changes: 57 additions & 0 deletions Composer/packages/server/src/controllers/formDialog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { Request, Response } from 'express';
import { PluginLoader } from '@bfc/plugin-loader';
import { schemas, expandPropertyDefinition } from '@microsoft/bf-generate-library';

import { BotProjectService } from '../services/project';

const expandJsonSchemaProperty = async (req: Request, res: Response) => {
const { propertyName, schema } = req.body;
const result = await expandPropertyDefinition(propertyName, schema);

if (result !== undefined) {
res.status(200).json(result);
} else {
res.status(404).json({
message: 'Failed to get form dialog schema/property.',
});
}
};

const getTemplateSchemas = async (req: Request, res: Response) => {
const result = await schemas();

if (result !== undefined) {
res.status(200).json(result);
} else {
res.status(404).json({
message: 'Failed to retrieve form dialog template schemas.',
});
}
};

const generate = async (req: Request, res: Response) => {
const projectId = req.params.projectId;
const user = await PluginLoader.getUserFromRequest(req);

const currentProject = await BotProjectService.getProjectById(projectId, user);
if (currentProject !== undefined) {
const { name } = req.body;

await currentProject.generateDialog(name);
const updatedProject = await BotProjectService.getProjectById(projectId, user);
res.status(200).json({ id: projectId, ...updatedProject.getProject() });
} else {
res.status(404).json({
message: `Could not generate form dialog. Project ${projectId} not found.`,
});
}
};

export const FormDialogController = {
getTemplateSchemas,
generate,
expandJsonSchemaProperty,
};
53 changes: 52 additions & 1 deletion Composer/packages/server/src/models/bot/botProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import fs from 'fs';

import axios from 'axios';
import { autofixReferInDialog } from '@bfc/indexers';
import { getNewDesigner, FileInfo, Skill, Diagnostic, IBotProject, DialogSetting } from '@bfc/shared';
import { getNewDesigner, FileInfo, Skill, Diagnostic, IBotProject, DialogSetting, FileExtensions } from '@bfc/shared';
import { UserIdentity, pluginLoader } from '@bfc/plugin-loader';
import { FeedbackType, generate } from '@microsoft/bf-generate-library';

import { Path } from '../../utility/path';
import { copyDir } from '../../utility/storage';
Expand Down Expand Up @@ -488,6 +489,56 @@ export class BotProject implements IBotProject {
return qnaEndpointKey;
};

public async generateDialog(name: string) {
const defaultLocale = this.settings?.defaultLanguage || defaultLanguage;
const relativePath = defaultFilePath(this.name, defaultLocale, `${name}${FileExtensions.FormDialogSchema}`);
const schemaPath = Path.resolve(this.dir, relativePath);

const dialogPath = defaultFilePath(this.name, defaultLocale, `${name}${FileExtensions.Dialog}`);
const outDir = Path.dirname(Path.resolve(this.dir, dialogPath));

const feedback = (type: FeedbackType, message: string): void => {
// eslint-disable-next-line no-console
console.log(`${type} - ${message}`);
};

GeoffCoxMSFT marked this conversation as resolved.
Show resolved Hide resolved
const generateParams = {
schemaPath,
prefix: name,
outDir,
metaSchema: undefined,
allLocales: undefined,
templateDirs: [],
force: false,
merge: true,
singleton: true,
feedback,
};

// schema path = path to the JSON schema file defining the form data
// prefix - the dialog name to prefix on generated assets
// outDir - the directory where the dialog assets will be saved
// metaSchema - deprecated
// allLocales - the additional locales for which to generate assets
// templateDirs - paths to directories containing customized templates
// force - if assets are overwritten causing any user customizations to be lost
// merge - if generated assets should be merged with any user customized assets
// singleton - if the generated assets should be merged into a single dialog
// feeback - a callback for status and progress and generation happens
await generate(
generateParams.schemaPath,
generateParams.prefix,
generateParams.outDir,
generateParams.metaSchema,
generateParams.allLocales,
generateParams.templateDirs,
generateParams.force,
generateParams.merge,
generateParams.singleton,
generateParams.feedback
);
}

private async removeLocalRuntimeData(projectId) {
const method = 'localpublish';
if (pluginLoader.extensions.publish[method]?.methods?.stopBot) {
Expand Down
9 changes: 8 additions & 1 deletion Composer/packages/server/src/models/bot/botStructure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const BotStructureTemplate = {
qna: 'dialogs/${DIALOGNAME}/knowledge-base/en-us/${DIALOGNAME}.en-us.qna',
dialogSchema: 'dialogs/${DIALOGNAME}/${DIALOGNAME}.dialog.schema',
},
formDialogs: 'form-dialogs/${FORMDIALOGNAME}',
skillManifests: 'manifests/${MANIFESTFILENAME}',
};

Expand Down Expand Up @@ -52,13 +53,19 @@ export const defaultFilePath = (botName: string, defaultLocale: string, filename
const LOCALE = locale;

// 1. Even appsettings.json hit FileExtensions.Manifest, but it never use this do created.
// 2. When exprot bot as a skill, name is `EchoBot-4-2-1-preview-1-manifest.json`
// 2. When export bot as a skill, name is `EchoBot-4-2-1-preview-1-manifest.json`
if (fileType === FileExtensions.Manifest) {
return templateInterpolate(BotStructureTemplate.skillManifests, {
MANIFESTFILENAME: filename,
});
}

if (fileType === FileExtensions.FormDialogSchema) {
return templateInterpolate(BotStructureTemplate.formDialogs, {
FORMDIALOGNAME: filename,
});
}

// common.lg
if (fileId === CommonFileId && fileType === FileExtensions.Lg) {
return templateInterpolate(BotStructureTemplate.common.lg, {
Expand Down
6 changes: 6 additions & 0 deletions Composer/packages/server/src/router/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { StorageController } from '../controllers/storage';
import { PublishController } from '../controllers/publisher';
import { AssetController } from '../controllers/asset';
import { EjectController } from '../controllers/eject';
import { FormDialogController } from '../controllers/formDialog';
import * as PluginsController from '../controllers/plugins';

import { UtilitiesController } from './../controllers/utilities';
Expand All @@ -31,6 +32,11 @@ router.post('/projects/:projectId/qnaSettings/set', ProjectController.setQnASett
router.post('/projects/:projectId/project/saveAs', ProjectController.saveProjectAs);
router.get('/projects/:projectId/export', ProjectController.exportProject);

// form dialog generation apis
router.post('/formDialogs/expandJsonSchemaProperty', FormDialogController.expandJsonSchemaProperty);
router.get('/formDialogs/templateSchemas', FormDialogController.getTemplateSchemas);
router.post('/formDialogs/:projectId/generate', FormDialogController.generate);

// update the boilerplate content
router.get('/projects/:projectId/boilerplateVersion', ProjectController.checkBoilerplateVersion);
router.post('/projects/:projectId/updateBoilerplate', ProjectController.updateBoilerplate);
Expand Down
Loading