Skip to content

Commit

Permalink
feat: Added form dialog generation controller (microsoft#4037)
Browse files Browse the repository at this point in the history
* Added form dialog generation controller

* Improved project not found error message.

* PR fixes

* Added generate comments
  • Loading branch information
GeoffCoxMSFT committed Sep 10, 2020
1 parent d79dc3a commit 9865336
Show file tree
Hide file tree
Showing 7 changed files with 342 additions and 14 deletions.
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}`);
};

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

0 comments on commit 9865336

Please sign in to comment.