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

fix: Update attachment template format to support PVA #7564

Merged
merged 10 commits into from
May 4, 2021
1 change: 0 additions & 1 deletion Composer/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
node_modules
tdurnford marked this conversation as resolved.
Show resolved Hide resolved
lib
dist
7 changes: 3 additions & 4 deletions Composer/packages/client/src/shell/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { LgMetaData, LgTemplateRef, LgType } from '@bfc/shared';
import { LgMetaData, LgTemplateRef, LgType, extractTemplateNameFromExpression } from '@bfc/shared';
import { LgTemplate, MicrosoftIDialog, ShellApi } from '@botframework-composer/types';

type SerializableLg = {
Expand Down Expand Up @@ -44,9 +44,8 @@ export const serializeLgTemplate = (
? (lgTemplate.properties[responseType] as string[])
: ([lgTemplate.properties[responseType]] as string[]);
for (const subTemplateItem of subTemplateItems) {
const matched = subTemplateItem.trim().match(exprRegex);
if (matched && matched.length > 1) {
const subTemplateId = matched[1];
const subTemplateId = extractTemplateNameFromExpression(subTemplateItem.trim());
tdurnford marked this conversation as resolved.
Show resolved Hide resolved
if (subTemplateId) {
const subTemplate = lgTemplates.find((x) => x.name === subTemplateId);
if (subTemplate) {
if (!serializableLg.relatedLgTemplateBodies) {
Expand Down
8 changes: 2 additions & 6 deletions Composer/packages/lib/code-editor/src/lg/ModalityPivot.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { CodeEditorSettings, LgTemplate, TelemetryClient } from '@bfc/shared';
import { CodeEditorSettings, LgTemplate, TelemetryClient, extractTemplateNameFromExpression } from '@bfc/shared';
import { FluentTheme, FontSizes } from '@uifabric/fluent-theme';
import formatMessage from 'format-message';
import { IconButton } from 'office-ui-fabric-react/lib/Button';
Expand All @@ -20,11 +20,7 @@ import mergeWith from 'lodash/mergeWith';

import { LGOption } from '../utils';
import { ItemWithTooltip } from '../components/ItemWithTooltip';
import {
extractTemplateNameFromExpression,
getTemplateId,
structuredResponseToString,
} from '../utils/structuredResponse';
import { getTemplateId, structuredResponseToString } from '../utils/structuredResponse';

import { AttachmentModalityEditor } from './modalityEditors/AttachmentModalityEditor';
import { SpeechModalityEditor } from './modalityEditors/SpeechModalityEditor';
Expand Down
4 changes: 2 additions & 2 deletions Composer/packages/lib/code-editor/src/lg/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type LgCardTemplateType = typeof lgCardAttachmentTemplates[number];
export const cardTemplates: Record<LgCardTemplateType, string> = {
adaptive: `> To learn more Adaptive Cards format, read the documentation at
> https://docs.microsoft.com/en-us/adaptive-cards/getting-started/bots
- \`\`\`\${json({
- \${{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2",
"type": "AdaptiveCard",
Expand All @@ -34,7 +34,7 @@ export const cardTemplates: Record<LgCardTemplateType, string> = {
"isSubtle": false
}
]
})}\`\`\``,
}}`,
hero: `[HeroCard
title =
subtitle =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
import formatMessage from 'format-message';
import React from 'react';
import { IDropdownOption, DropdownMenuItemType } from 'office-ui-fabric-react/lib/Dropdown';
import { CodeEditorSettings } from '@bfc/shared';
import { CodeEditorSettings, extractTemplateNameFromExpression } from '@bfc/shared';

import {
AttachmentsStructuredResponseItem,
AttachmentLayoutStructuredResponseItem,
CommonModalityEditorProps,
} from '../types';
import { extractTemplateNameFromExpression } from '../../utils/structuredResponse';

import { ModalityEditorContainer } from './ModalityEditorContainer';
import { AttachmentArrayEditor } from './AttachmentArrayEditor';
Expand Down Expand Up @@ -46,7 +45,11 @@ const AttachmentModalityEditor = React.memo(
(newItems: string[]) => {
setItems(newItems);
onUpdateResponseTemplate({
Attachments: { kind: 'Attachments', value: newItems.map((item) => `\${${item}()}`), valueType: 'direct' },
Attachments: {
kind: 'Attachments',
value: newItems.map((item) => `\${json(${item}())}`),
valueType: 'direct',
},
});
},
[setItems, onUpdateResponseTemplate]
Expand Down
12 changes: 2 additions & 10 deletions Composer/packages/lib/code-editor/src/utils/structuredResponse.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/* eslint-disable security/detect-unsafe-regex */
tdurnford marked this conversation as resolved.
Show resolved Hide resolved

import { LgTemplate } from '@bfc/shared';
import { LgTemplate, extractTemplateNameFromExpression } from '@bfc/shared';

import { activityTemplateType } from '../lg/constants';
import {
Expand All @@ -20,7 +21,6 @@ import {
} from '../lg/types';

const subTemplateNameRegex = /\${(.*)}/;
const templateNameExtractRegex = /\${(.*)(\(.*\))\s*}/;
const defaultIndent = ' ';

const getStructuredResponseHelper = (value: unknown, kind: 'Text' | 'Speak' | 'Attachments') => {
Expand Down Expand Up @@ -113,14 +113,6 @@ export const getStructuredResponseFromTemplate = (lgTemplate?: LgTemplate): Part
return Object.keys(structuredResponse).length ? structuredResponse : undefined;
};

/**
* Extracts template name from an LG expression
* ${templateName(params)} => templateName
* @param expression Expression to extract template name from.
*/
export const extractTemplateNameFromExpression = (expression: string): string | undefined =>
expression.match(templateNameExtractRegex)?.[1]?.trim();

export const structuredResponseToString = (structuredResponse: PartialStructuredResponse): string => {
const keys = Object.keys(structuredResponse);

Expand Down
7 changes: 6 additions & 1 deletion Composer/packages/lib/shared/src/lgUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,9 @@ export { default as LgTemplateRef } from './models/LgTemplateRef';
export { default as LgType } from './models/LgType';
export { extractLgTemplateRefs } from './parsers/parseLgTemplateRef';
export { LgNamePattern } from './parsers/lgPatterns';
export { TemplateBodyItem, parseTemplateBody, templateBodyItemsToString } from './stringBuilders/lgStringUtils';
export {
TemplateBodyItem,
parseTemplateBody,
templateBodyItemsToString,
extractTemplateNameFromExpression,
} from './stringBuilders/lgStringUtils';
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,17 @@ export const templateBodyItemsToString = (items: TemplateBodyItem[]) =>
}
})
.join('\n');

tdurnford marked this conversation as resolved.
Show resolved Hide resolved
const templateNameExtractRegex = /\${(?<templateName>.*)(\(.*\))\s*}/;
const jsonTemplateNameExtractRegex = /\${json\((?<templateName>.*)(\(.*\))\s*}/;

/**
* Extracts template name from an LG expression
* ${templateName(params)} => templateName
* ${json(templateName(params))} => templateName
* @param expression Expression to extract template name from.
*/
export const extractTemplateNameFromExpression = (expression: string): string | undefined =>
expression.startsWith('${json(')
? expression.match(jsonTemplateNameExtractRegex)?.groups?.templateName?.trim()
: expression.match(templateNameExtractRegex)?.groups?.templateName?.trim();
16 changes: 6 additions & 10 deletions Composer/packages/ui-plugins/lg/src/LgWidget/useLgTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { LgTemplateRef, parseTemplateBody } from '@bfc/shared';
import { LgTemplateRef, parseTemplateBody, extractTemplateNameFromExpression } from '@bfc/shared';
import { LgTemplate, useShellApi } from '@bfc/extension-client';

import { locateLgTemplatePosition } from '../locateLgTemplatePosition';

const exprRegex = /^\${(.*)\(\)}$/;

const getAttachmentDisplayText = (template: LgTemplate) => {
const cardType = template.properties?.$type as string;
const title = (template.properties?.title as string) ?? '';
Expand All @@ -31,10 +29,9 @@ const getLgTemplateTextData = (
if (responseType === 'Text' || responseType === 'Speak') {
const subTemplateItem = template.properties[responseType];
if (subTemplateItem && typeof subTemplateItem === 'string') {
const matched = subTemplateItem.trim().match(exprRegex);
const subTemplateId = extractTemplateNameFromExpression(subTemplateItem.trim());
//If it's a template
if (matched && matched.length > 1) {
const subTemplateId = matched[1];
if (subTemplateId) {
const subTemplate = templates.find((x) => x.name === subTemplateId);
// If found template and it matches auto-generated names
if (subTemplate) {
Expand All @@ -57,10 +54,9 @@ const getLgTemplateTextData = (
: [template.properties[responseType]]) as string[];
const subTemplateItem = subTemplateItems[0];
if (subTemplateItem && typeof subTemplateItem === 'string') {
const matched = subTemplateItem.trim().match(exprRegex);
//If it's a template
if (matched && matched.length > 1) {
const subTemplateId = matched[1];
const subTemplateId = extractTemplateNameFromExpression(subTemplateItem.trim());
// If it's a template
if (subTemplateId) {
const subTemplate = templates.find((x) => x.name === subTemplateId);
if (subTemplate) {
acc[responseType] = {
Expand Down