From b32e27ecf4527a18b72a6d9889b50e0033db2e2b Mon Sep 17 00:00:00 2001 From: Ben Brown Date: Fri, 23 Apr 2021 09:31:05 -0500 Subject: [PATCH 01/13] fix: expose provisionComposer script in easily downloadable way (#7180) * add an adminHandoff folder and new instructions * rename folder * add easily downloadable scripts * direct download link for scripts * direct download link for scripts * correct numbers on steps --- Provisioning/README.md | 149 ++++++++++++++++++++++++++++++ Provisioning/provisionScripts.zip | Bin 0 -> 17489 bytes 2 files changed, 149 insertions(+) create mode 100644 Provisioning/README.md create mode 100644 Provisioning/provisionScripts.zip diff --git a/Provisioning/README.md b/Provisioning/README.md new file mode 100644 index 0000000000..f1d7c5a996 --- /dev/null +++ b/Provisioning/README.md @@ -0,0 +1,149 @@ +# How to manually provision Azure resources for your Composer project + +This article covers script-based instructions to manually provision resources for use with Composer. +This is an alternative to using the in-app provisioning tool. + +## Prerequisites + +- A subscription to [Microsoft Azure](https://azure.microsoft.com/free/). +- [A basic bot built using Composer](https://aka.ms/composer-create-first-bot). +- Latest version of the [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli). +- [Node.js](https://nodejs.org/). Use version 12.13.0 or later. +- PowerShell version 6.0 and later. + +## Provision Azure resources + +Follow these instructions to manually provision Azure resources: + +1. Download and unzip the [provisioning helper scripts.](provisionScripts.zip) +2. Open a new Command Prompt and navigate to the newly created folder. For example: + + ```cmd + cd provisionScripts/ + ``` + +3. Run the following command to install the dependencies: + + ```cmd + npm install + ``` + +4. Run the following command to provision new Azure resources. + + - **_Azure Web App_**: + + ```cmd + node provisionComposer.js --subscriptionId= --name= --appPassword= --environment= + ``` + + - **_Azure Functions_**: + + ```cmd + node provisionComposer.js --subscriptionId= --name= --appPassword= --environment= --customArmTemplate=DeploymentTemplates/function-template-with-preexisting-rg.json + ``` + + | Property | Description | + | --------------------------- | --------------------------------------------------------------------------------------- | + | Your Azure Subscription ID | Find it in your Azure resource in the **Subscription ID** field. | + | Name of your resource group | The name you give to the resource group you are creating. | + | App password | At least 16 characters with at least one number, one letter, and one special character. | + | Name for environment | The name you give to the publish environment. | + + Once completed, the provision scripts will create the following resources in the Azure portal: + + | Resource | Required/Optional | + | --------------------------------------------- | ----------------- | + | App Service plan | Required | + | App Service | Required | + | Application Registration | Required | + | Azure Cosmos DB | Optional | + | Application Insights | Optional | + | Azure Blob Storage | Optional | + | LUIS authoring resource (Cognitive Services) | Optional | + | LUIS prediction resource (Cognitive Services) | Optional | + | QnA Maker resources (Cognitive Services) | Optional | + + > [!TIP] + > Read the [parameters list](#provision-scripts-parameters-list) to customize the provision scripts and create the Azure resources you want. + + 1. You will be asked to login to the Azure portal in your browser. + + 2. If you see the error message "InsufficientQuota", add a param '--createLuisAuthoringResource false' and run the script again. + + - **_Azure Web App_**: + + ```cmd + node provisionComposer.js --subscriptionId= --name=--appPassword= --environment= --createLuisAuthoringResource false + ``` + + - **_Azure Functions_**: + + ```cmd + node provisionComposer.js --subscriptionId= --name= --appPassword= --environment= --createLuisAuthoringResource false --customArmTemplate=DeploymentTemplates/function-template-with-preexisting-rg.json + ``` + + > [!NOTE] + > If you use `--createLuisAuthoringResource false` in this step, you should manually add the LUIS authoring key to the publish configuration. The default region is `westus`. To provision to other regions, you should add `--location region`. + +5. As the Azure resources are being provisioned, you will see a spinning activity indicator for a few minutes. + + Once completed, you will see the generated JSON appears in the command line like the following. The JSON output is the publishing profile, which will be used in step 6. + + ```json + { + "accessToken": "", + "name": "", + "environment": "", + "hostname": "", + "luisResource": "", + "settings": { + "applicationInsights": { + "InstrumentationKey": "" + }, + "cosmosDb": { + "cosmosDBEndpoint": "", + "authKey": "", + "databaseId": "botstate-db", + "collectionId": "botstate-collection", + "containerId": "botstate-container" + }, + "blobStorage": { + "connectionString": "", + "container": "transcripts" + }, + "luis": { + "endpointKey": "", + "authoringKey": "", + "region": "westus" + }, + "qna": { + "endpoint": "", + "subscriptionKey": "" + }, + "MicrosoftAppId": "", + "MicrosoftAppPassword": "" + } + } + ``` + +6. From the "Publish" tab of Composer, choose to import an existing publishing profile. Paste the JSON from step 5 into Composer and save the profile. + +### Provision scripts parameters list + +You don't need to create a complete list of the Azure resources as covered in **step 3** of the [provision Azure resources](#provision-azure-resources) section. The following is a table of the parameters you can use to customize the provision scripts so that you only provision the resources needed. + +| Parameter | Required/Optional | Default value | Description | +| --------------------------- | ----------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| subscriptionId | Required | N/A | Your Azure subscription ID. | +| name | Required | N/A | The name of your resource group | +| appPassword | Required | N/A | The password to create the resource. It must be at least 16 characters long, contain at least 1 upper or lower case alphabetical character, and contain at least 1 special character | +| environment | Optional | dev | N/A | +| location | Optional | `westus` | Your Azure resource group region | +| tenantId | Optional | default tenantId | ID of your tenant if required. | +| customArmTemplate | Optional | `/DeploymentTemplates/template-with-preexisting-rg.json` | For Azure Functions or your own template for a custom deployment. | +| createLuisResource | Optional | `true` | The LUIS prediction resource to create. Region is default to `westus` and cannot be changed. | +| createLuisAuthoringResource | Optional | true | The LUIS authoring resource to create. Region is default to `westus` and cannot be changed. | +| createQnAResource | Optional | `true` | The QnA resource to create. | +| createCosmosDb | Optional | `true` | The CosmosDb resource to create. | +| createStorage | Optional | `true` | The BlobStorage resource to create. | +| createAppInsights | Optional | `true` | The AppInsights resource to create. | diff --git a/Provisioning/provisionScripts.zip b/Provisioning/provisionScripts.zip new file mode 100644 index 0000000000000000000000000000000000000000..52d586a2f55e7d45e12c16726b0b3dd731201dda GIT binary patch literal 17489 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 Date: Fri, 23 Apr 2021 08:04:27 -0700 Subject: [PATCH 02/13] fix: use correct worker script in electron development (#7274) Co-authored-by: Soroush Co-authored-by: Andy Brown --- Composer/packages/server-workers/src/server-worker.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Composer/packages/server-workers/src/server-worker.ts b/Composer/packages/server-workers/src/server-worker.ts index c74f5dab35..b7feb3acf3 100644 --- a/Composer/packages/server-workers/src/server-worker.ts +++ b/Composer/packages/server-workers/src/server-worker.ts @@ -10,6 +10,8 @@ import type { DialogMergeArgs } from './workers/dialogMerge.worker'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const isElectron: boolean = process.versions && (process.versions as any).electron; +export const isProduction = process.env.NODE_ENV === 'production'; + export type WorkerName = 'dialogMerge' | 'templateInstallation'; export class ServerWorker { @@ -67,7 +69,7 @@ export class ServerWorker { } private static getWorkerPath(workerName: WorkerName) { - if (isElectron) { + if (isElectron && isProduction) { return path.join( // eslint-disable-next-line @typescript-eslint/no-explicit-any (process as any).resourcesPath, From 24f65b17fac45b986cbd99d9900f8e4996485ddf Mon Sep 17 00:00:00 2001 From: Ben Yackley <61990921+beyackle@users.noreply.github.com> Date: Fri, 23 Apr 2021 08:05:07 -0700 Subject: [PATCH 03/13] fix: use router-based links to project manager (#7271) * use router-based links to project manager * fix unit test * Update AdapterSettings.test.tsx Co-authored-by: Andy Brown Co-authored-by: Soroush Co-authored-by: TJ Durnford --- .../pages/botProjectsSettings/AdapterSettings.test.tsx | 2 +- .../src/pages/botProject/adapters/AdapterSection.tsx | 10 ++++------ .../botProject/adapters/ExternalAdapterSettings.tsx | 9 ++++----- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/AdapterSettings.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/AdapterSettings.test.tsx index 5d9ee98620..e91d6792c9 100644 --- a/Composer/packages/client/__tests__/pages/botProjectsSettings/AdapterSettings.test.tsx +++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/AdapterSettings.test.tsx @@ -87,7 +87,7 @@ describe('ExternalAdapterSettings', () => { const link = getByText(/from package manager/); - expect(link.attributes.getNamedItem('href')?.value).toEqual('plugin/package-manager/package-manager'); + expect(link.attributes.getNamedItem('href')?.value).toContain('plugin/package-manager/package-manager'); }); it('brings up the modal', () => { diff --git a/Composer/packages/client/src/pages/botProject/adapters/AdapterSection.tsx b/Composer/packages/client/src/pages/botProject/adapters/AdapterSection.tsx index b2845ee773..4002f7fabf 100644 --- a/Composer/packages/client/src/pages/botProject/adapters/AdapterSection.tsx +++ b/Composer/packages/client/src/pages/botProject/adapters/AdapterSection.tsx @@ -6,9 +6,9 @@ import { useEffect, useRef } from 'react'; import formatMessage from 'format-message'; import { Stack } from 'office-ui-fabric-react/lib/Stack'; import { Link } from 'office-ui-fabric-react/lib/Link'; +import { Link as RouterLink } from '@reach/router'; import { title, subtitle, subtext } from '../styles'; -import { navigateTo } from '../../../utils/navigation'; import ExternalAdapterSettings from './ExternalAdapterSettings'; import ABSChannels from './ABSChannels'; @@ -54,14 +54,12 @@ const AdapterSection = ({ projectId, scrollToSectionId }: Props) => { 'Find and install more external services to your bot project in package manager. For further guidance, see documentation for adding external connections.', { a: ({ children }) => ( - { - navigateTo(`/bot/${projectId}/plugin/package-manager/package-manager`); - }} + to={`/bot/${projectId}/plugin/package-manager/package-manager`} > {children} - + ), a2: ({ children }) => ( { const schemas = useRecoilValue(schemasState(projectId)); const currentSettings = useRecoilValue(settingsState(projectId)); const { setSettings } = useRecoilValue(dispatcherState); - const packageManagerLink = useRouterCache('plugin/package-manager/package-manager'); const adapters: AdapterRecord[] = currentSettings.runtimeSettings?.adapters ?? []; @@ -130,11 +129,11 @@ const ExternalAdapterSettings = (props: Props) => {
{externalServices(adapterSchemas)}
- {formatMessage.rich('Add from package manager.', { + {formatMessage.rich('Add from package manager', { a: ({ children }) => ( - + {children} - + ), })}
From 03e41629246ebafe39d87de34c8972ca30ff82d2 Mon Sep 17 00:00:00 2001 From: taicchoumsft <61705609+taicchoumsft@users.noreply.github.com> Date: Fri, 23 Apr 2021 08:49:33 -0700 Subject: [PATCH 04/13] Fix for settings being overriden (#7294) Co-authored-by: Andy Brown --- Composer/packages/server/src/models/bot/builder.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Composer/packages/server/src/models/bot/builder.ts b/Composer/packages/server/src/models/bot/builder.ts index 6d3efbd5ca..9dbe9d4cb4 100644 --- a/Composer/packages/server/src/models/bot/builder.ts +++ b/Composer/packages/server/src/models/bot/builder.ts @@ -207,7 +207,10 @@ export class Builder { TelemetryService.endEvent('OrchestratorBuildCompleted', 'OrchestratorBuilder'); this.orchestratorSettings.orchestrator.models[modelData.lang] = modelPath; - this.orchestratorSettings.orchestrator.snapshots = snapshotData; + this.orchestratorSettings.orchestrator.snapshots = { + ...this.orchestratorSettings.orchestrator.snapshots, + ...snapshotData, + }; } } From bb55a539834d244db5530939d76fb662780526f3 Mon Sep 17 00:00:00 2001 From: TJ Durnford Date: Fri, 23 Apr 2021 11:49:57 -0600 Subject: [PATCH 05/13] fix: Change carousal to carousel in LG Editor (#7318) * fix: Change carousal to carousel in LG Editor * l10n --- .../lg/modalityEditors/AttachmentModalityEditor.tsx | 4 ++-- Composer/packages/server/src/locales/en-US.json | 11 ++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Composer/packages/lib/code-editor/src/lg/modalityEditors/AttachmentModalityEditor.tsx b/Composer/packages/lib/code-editor/src/lg/modalityEditors/AttachmentModalityEditor.tsx index 2d4548c11c..2da8010773 100644 --- a/Composer/packages/lib/code-editor/src/lg/modalityEditors/AttachmentModalityEditor.tsx +++ b/Composer/packages/lib/code-editor/src/lg/modalityEditors/AttachmentModalityEditor.tsx @@ -69,8 +69,8 @@ const AttachmentModalityEditor = React.memo( selected: attachmentLayout === 'list', }, { - key: 'carousal', - text: formatMessage('Carousal'), + key: 'carousel', + text: formatMessage('Carousel'), selected: attachmentLayout === 'carousel', }, ], diff --git a/Composer/packages/server/src/locales/en-US.json b/Composer/packages/server/src/locales/en-US.json index f2315d0642..6b96acd29a 100644 --- a/Composer/packages/server/src/locales/en-US.json +++ b/Composer/packages/server/src/locales/en-US.json @@ -20,8 +20,8 @@ "ErrorInfo_part3": { "message": "Try navigating to another node in the visual editor." }, - "a_add_from_package_manager_a_4515cfc2": { - "message": "Add from package manager." + "a_add_from_package_manager_a_9eee7630": { + "message": "Add from package manager" }, "a_dialog_file_must_have_a_name_123ff67d": { "message": "a dialog file must have a name" @@ -590,8 +590,8 @@ "cannot_upload_file_conversation_not_found_8a983504": { "message": "Cannot upload file. Conversation not found." }, - "carousal_c65edfcd": { - "message": "Carousal" + "carousel_a2321ac9": { + "message": "Carousel" }, "change_recognizer_3145b93d": { "message": "Change Recognizer" @@ -2363,9 +2363,6 @@ "minimum_f31b05ab": { "message": "Minimum" }, - "miss_dispatch_modal_cf2d278e": { - "message": "Miss dispatch modal" - }, "missing_definition_for_defname_33f2b594": { "message": "Missing definition for { defName }" }, From b2b74cb101ce9e17960159ff917add925c81b41d Mon Sep 17 00:00:00 2001 From: Tony Anziano Date: Fri, 23 Apr 2021 11:27:26 -0700 Subject: [PATCH 06/13] Moved Web Chat log item keys outside of component (#7319) --- .../TabExtensions/WebChatLog/WebChatActivityLogItem.tsx | 5 ++--- .../TabExtensions/WebChatLog/WebChatLogContent.tsx | 6 +++--- .../TabExtensions/WebChatLog/WebChatNetworkLogItem.tsx | 5 ++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatActivityLogItem.tsx b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatActivityLogItem.tsx index 95b679ef2d..c528a90562 100644 --- a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatActivityLogItem.tsx +++ b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatActivityLogItem.tsx @@ -25,14 +25,13 @@ const renderActivityArrow = (activity) => { }; type WebChatActivityLogItemProps = { - index: number; item: ConversationActivityTrafficItem; isSelected?: boolean; onClickTraffic: (data: WebChatInspectionData) => void; }; export const WebChatActivityLogItem: React.FC = (props) => { - const { index, item, isSelected = false, onClickTraffic } = props; + const { item, isSelected = false, onClickTraffic } = props; const { appLocale } = useRecoilValue(userSettingsState); const onClick = useCallback(() => { @@ -40,7 +39,7 @@ export const WebChatActivityLogItem: React.FC = (pr }, [item, onClickTraffic]); return ( - + {renderTimeStamp(item.timestamp, appLocale)} {renderActivityArrow(item.activity)} {item.activity.type || 'unknown'} diff --git a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatLogContent.tsx b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatLogContent.tsx index 78c514cd09..4f2a6c7dbd 100644 --- a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatLogContent.tsx +++ b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatLogContent.tsx @@ -134,7 +134,7 @@ export const WebChatLogContent: React.FC = ({ isActive case 'activity': return ( = ({ isActive case 'network': return ( = ({ isActive case 'networkError': return ( void; }; export const WebChatNetworkLogItem: React.FC = (props) => { - const { index, item, isSelected = false, onClickTraffic } = props; + const { item, isSelected = false, onClickTraffic } = props; const { appLocale } = useRecoilValue(userSettingsState); const onClickRequest = useCallback(() => { onClickTraffic({ item, mode: 'request' }); @@ -49,7 +48,7 @@ export const WebChatNetworkLogItem: React.FC = (prop ) : null; return ( -
+
{renderTimeStamp(item.timestamp, appLocale)} From 1d4b434e2a68b8ddfe5f90d1eb7a7bcd561490b7 Mon Sep 17 00:00:00 2001 From: leileizhang Date: Sat, 24 Apr 2021 02:56:31 +0800 Subject: [PATCH 07/13] fix: Data loss when cutting / copying & pasting response (#7296) Co-authored-by: Dong Lei Co-authored-by: Soroush --- Composer/packages/client/src/shell/lgApi.ts | 15 +++++++-------- Composer/packages/client/src/shell/luApi.ts | 14 +++++++------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Composer/packages/client/src/shell/lgApi.ts b/Composer/packages/client/src/shell/lgApi.ts index 2b4d32da82..23d6aec7a9 100644 --- a/Composer/packages/client/src/shell/lgApi.ts +++ b/Composer/packages/client/src/shell/lgApi.ts @@ -10,7 +10,7 @@ import formatMessage from 'format-message'; import { useResolvers } from '../hooks/useResolver'; import { Dispatcher } from '../recoilModel/dispatchers'; -import { dispatcherState, focusPathState } from './../recoilModel'; +import { designPageLocationState, dispatcherState } from './../recoilModel'; const fileNotFound = (id: string) => formatMessage('LG file {id} not found', { id }); const TEMPLATE_ERROR = formatMessage('templateName is missing or empty'); @@ -31,13 +31,13 @@ const memoizedDebounce = (func, wait, options = {}) => { }; function createLgApi( - state: { focusPath: string; projectId: string }, + state: { dialogId: string; projectId: string }, actions: Dispatcher, lgFileResolver: (id: string) => LgFile | undefined ): LgContextApi { const getLgTemplates = (id) => { if (id === undefined) throw new Error('must have a file id'); - const focusedDialogId = state.focusPath.split('#').shift() || id; + const focusedDialogId = state.dialogId || id; const file = lgFileResolver(focusedDialogId); if (!file) throw new Error(fileNotFound(id)); return file.templates; @@ -148,15 +148,14 @@ function createLgApi( } export function useLgApi(projectId: string) { - const focusPath = useRecoilValue(focusPathState(projectId)); + const { dialogId } = useRecoilValue(designPageLocationState(projectId)); const actions: Dispatcher = useRecoilValue(dispatcherState); const { lgFileResolver } = useResolvers(projectId); - const [api, setApi] = useState(createLgApi({ focusPath, projectId }, actions, lgFileResolver)); + const [api, setApi] = useState(createLgApi({ dialogId, projectId }, actions, lgFileResolver)); useEffect(() => { - const newApi = createLgApi({ focusPath, projectId }, actions, lgFileResolver); + const newApi = createLgApi({ dialogId, projectId }, actions, lgFileResolver); setApi(newApi); - return () => { Object.keys(newApi).forEach((apiName) => { if (typeof newApi[apiName].flush === 'function') { @@ -164,7 +163,7 @@ export function useLgApi(projectId: string) { } }); }; - }, [projectId, focusPath]); + }, [projectId, dialogId]); return api; } diff --git a/Composer/packages/client/src/shell/luApi.ts b/Composer/packages/client/src/shell/luApi.ts index d6ed5ed1a6..5599b025ec 100644 --- a/Composer/packages/client/src/shell/luApi.ts +++ b/Composer/packages/client/src/shell/luApi.ts @@ -8,14 +8,14 @@ import formatMessage from 'format-message'; import debounce from 'lodash/debounce'; import { useResolvers } from '../hooks/useResolver'; -import { dispatcherState, focusPathState } from '../recoilModel'; +import { designPageLocationState, dispatcherState } from '../recoilModel'; import { Dispatcher } from '../recoilModel/dispatchers'; const fileNotFound = (id: string) => formatMessage(`LU file {id} not found`, { id }); const INTENT_ERROR = formatMessage('intentName is missing or empty'); function createLuApi( - state: { focusPath: string; projectId: string }, + state: { dialogId: string; projectId: string }, dispatchers: Dispatcher, luFileResolver: (id: string) => LuFile | undefined ): LuContextApi { @@ -65,7 +65,7 @@ function createLuApi( const getLuIntents = (id: string): LuIntentSection[] => { if (id === undefined) throw new Error('must have a file id'); - const focusedDialogId = state.focusPath.split('#').shift() || id; + const focusedDialogId = state.dialogId || id; const file = luFileResolver(focusedDialogId); if (!file) throw new Error(fileNotFound(id)); return file.intents; @@ -90,13 +90,13 @@ function createLuApi( } export function useLuApi(projectId: string) { - const focusPath = useRecoilValue(focusPathState(projectId)); + const { dialogId } = useRecoilValue(designPageLocationState(projectId)); const dispatchers = useRecoilValue(dispatcherState); const { luFileResolver } = useResolvers(projectId); - const [api, setApi] = useState(createLuApi({ focusPath, projectId }, dispatchers, luFileResolver)); + const [api, setApi] = useState(createLuApi({ dialogId, projectId }, dispatchers, luFileResolver)); useEffect(() => { - const newApi = createLuApi({ focusPath, projectId }, dispatchers, luFileResolver); + const newApi = createLuApi({ dialogId, projectId }, dispatchers, luFileResolver); setApi(newApi); return () => { @@ -106,7 +106,7 @@ export function useLuApi(projectId: string) { } }); }; - }, [projectId, focusPath]); + }, [projectId, dialogId]); return api; } From 669db58d80466125ff203b27265980fc979f66f4 Mon Sep 17 00:00:00 2001 From: Zhixiang Zhan Date: Sat, 24 Apr 2021 03:42:51 +0800 Subject: [PATCH 08/13] fix: export bot include v2 project structure files (#7248) * export bot include new structure files * include js runtime type bot files * clean up Co-authored-by: Chris Whitten --- .../src/models/storage/localDiskStorage.ts | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/Composer/packages/server/src/models/storage/localDiskStorage.ts b/Composer/packages/server/src/models/storage/localDiskStorage.ts index bbac978713..79880acbf1 100644 --- a/Composer/packages/server/src/models/storage/localDiskStorage.ts +++ b/Composer/packages/server/src/models/storage/localDiskStorage.ts @@ -162,22 +162,38 @@ export class LocalDiskStorage implements IFileStorage { async zip(source: string, exclusions, cb): Promise { const defaultDirectories = [ + '/Controllers/', '/dialogs/', - '/language-understanding/', - '/language-generation/', - '/settings/', - '/generated/', + '/form-dialogs/', '/knowledge-base/', + '/language-generation/', + '/language-understanding/', + '/media/', + '/Properties/', '/recognizers/', - '/form-dialogs/', + '/schemas/', '/scripts/', + '/settings/', + '/wwwroot/', + '/generated/', ]; const directoriesToInclude = defaultDirectories.filter((elem) => { return exclusions?.directories == undefined || exclusions?.directories?.indexOf(elem) == -1; }); - const defaultFiles = [`*${FileExtensions.BotProject}`, `*${FileExtensions.Dialog}`, 'README.md', '.gitignore']; + const defaultFiles = [ + `*${FileExtensions.BotProject}`, + `*${FileExtensions.Dialog}`, + `*.csproj`, + `*.cs`, + `*.js`, + `*.json`, + `Nuget.config`, + 'web.config', + 'README.md', + '.gitignore', + ]; const filesToInclude = defaultFiles.filter((elem) => { return exclusions?.files == undefined || exclusions?.files?.indexOf(elem) == -1; From 6e872ca3eff3642bfd4624b68fc26fcd12a6a0da Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Fri, 23 Apr 2021 12:54:08 -0700 Subject: [PATCH 09/13] fix: refactor way we get COMPOSER_VERSION (#7326) Co-authored-by: Chris Whitten --- Composer/packages/client/config/env.js | 12 ++++++++++-- .../packages/client/src/pages/about/About.tsx | 2 +- Composer/packages/electron-server/src/main.ts | 1 + .../packages/electron-server/src/preload.js | 4 +--- Composer/packages/server/src/constants.ts | 2 -- .../packages/server/src/models/bot/builder.ts | 3 +-- Composer/packages/server/src/server.ts | 2 ++ .../packages/server/src/utility/getVersion.ts | 17 +++++++++++++++++ 8 files changed, 33 insertions(+), 10 deletions(-) create mode 100644 Composer/packages/server/src/utility/getVersion.ts diff --git a/Composer/packages/client/config/env.js b/Composer/packages/client/config/env.js index 0a93828633..5cedb12698 100644 --- a/Composer/packages/client/config/env.js +++ b/Composer/packages/client/config/env.js @@ -1,6 +1,6 @@ 'use strict'; -const fs = require('fs'); +const fs = require('fs-extra'); const path = require('path'); const { execSync } = require('child_process'); @@ -49,6 +49,14 @@ function getGitSha() { } } +function getComposerVersion() { + try { + return fs.readJSONSync(path.join(__dirname, '../../electron-server/package.json')).version; + } catch { + return 'unknown'; + } +} + // We support resolving modules according to `NODE_PATH`. // This lets you use absolute paths in imports inside large monorepos: // https://github.com/facebook/create-react-app/issues/253. @@ -88,7 +96,7 @@ function getClientEnvironment(publicUrl) { PUBLIC_URL: publicUrl, GIT_SHA: getGitSha().toString().replace('\n', ''), SDK_PACKAGE_VERSION: '4.12.2', // TODO: change this when Composer supports custom schema/custom runtime - COMPOSER_VERSION: '1.4.0', + COMPOSER_VERSION: getComposerVersion(), LOCAL_PUBLISH_PATH: process.env.LOCAL_PUBLISH_PATH || path.resolve(process.cwd(), '../../../extensions/localPublish/hostedBots'), WEBLOGIN_CLIENTID: process.env.WEBLOGIN_CLIENTID, diff --git a/Composer/packages/client/src/pages/about/About.tsx b/Composer/packages/client/src/pages/about/About.tsx index f121a823eb..1db2782875 100644 --- a/Composer/packages/client/src/pages/about/About.tsx +++ b/Composer/packages/client/src/pages/about/About.tsx @@ -33,7 +33,7 @@ export const About: React.FC = () => {
{formatMessage(`Release: `) + (isElectron() - ? (window as any).appVersion + ? process.env.COMPOSER_VERSION : `${process.env.COMPOSER_VERSION}-${process.env.GIT_SHA}` || 'Unknown')}
diff --git a/Composer/packages/electron-server/src/main.ts b/Composer/packages/electron-server/src/main.ts index 18d1a83663..0699300fb7 100644 --- a/Composer/packages/electron-server/src/main.ts +++ b/Composer/packages/electron-server/src/main.ts @@ -141,6 +141,7 @@ function initializeAppUpdater(settings: AppUpdaterSettings) { } async function loadServer() { + process.env.COMPOSER_VERSION = app.getVersion(); if (!isDevelopment) { // only change paths if packaged electron app const unpackedDir = getUnpackedAsarPath(); diff --git a/Composer/packages/electron-server/src/preload.js b/Composer/packages/electron-server/src/preload.js index f1ea8ec4f5..ff5c0bc7bb 100644 --- a/Composer/packages/electron-server/src/preload.js +++ b/Composer/packages/electron-server/src/preload.js @@ -1,11 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -const { app, ipcRenderer } = require('electron'); // eslint-disable-line +const { ipcRenderer } = require('electron'); // eslint-disable-line // expose ipcRenderer to the browser window.ipcRenderer = ipcRenderer; -// get the app version to hand into the client -window.appVersion = app.getVersion(); // flag to distinguish electron client from web app client window.__IS_ELECTRON__ = true; diff --git a/Composer/packages/server/src/constants.ts b/Composer/packages/server/src/constants.ts index 2f440237d5..cffe786283 100644 --- a/Composer/packages/server/src/constants.ts +++ b/Composer/packages/server/src/constants.ts @@ -18,5 +18,3 @@ export enum ClaimNames { export const APPINSIGHTS_INSTRUMENTATIONKEY = process.env.APPINSIGHTS_INSTRUMENTATIONKEY; export const piiProperties = []; - -export const COMPOSER_VERSION = '1.4.0'; diff --git a/Composer/packages/server/src/models/bot/builder.ts b/Composer/packages/server/src/models/bot/builder.ts index 9dbe9d4cb4..b9d0ecf316 100644 --- a/Composer/packages/server/src/models/bot/builder.ts +++ b/Composer/packages/server/src/models/bot/builder.ts @@ -17,7 +17,6 @@ import { IFileStorage } from '../storage/interface'; import log from '../../logger'; import { setEnvDefault } from '../../utility/setEnvDefault'; import { useElectronContext } from '../../utility/electronContext'; -import { COMPOSER_VERSION } from '../../constants'; import { TelemetryService } from '../../services/telemetry'; import { IOrchestratorNLRList, IOrchestratorProgress, IOrchestratorSettings } from './interface'; @@ -52,7 +51,7 @@ export type DownSamplingConfig = { const getUserAgent = () => { const platform = useElectronContext() ? 'desktop' : 'web'; - return `microsoft.bot.composer/${COMPOSER_VERSION} ${platform}`; + return `microsoft.bot.composer/${process.env.COMPOSER_VERSION} ${platform}`; }; export class Builder { diff --git a/Composer/packages/server/src/server.ts b/Composer/packages/server/src/server.ts index 1be9c3f9b6..b91782dae9 100644 --- a/Composer/packages/server/src/server.ts +++ b/Composer/packages/server/src/server.ts @@ -35,11 +35,13 @@ import { mountConversationsRoutes } from './directline/mountConversationRoutes'; import { mountDirectLineRoutes } from './directline/mountDirectlineRoutes'; import { mountAttachmentRoutes } from './directline/mountAttachmentRoutes'; import { cleanHostedBots } from './utility/cleanHostedBots'; +import { getVersion } from './utility/getVersion'; // eslint-disable-next-line @typescript-eslint/no-var-requires const session = require('express-session'); export async function start(electronContext?: ElectronContext): Promise { + setEnvDefault('COMPOSER_VERSION', getVersion()); if (electronContext) { setElectronContext(electronContext); } diff --git a/Composer/packages/server/src/utility/getVersion.ts b/Composer/packages/server/src/utility/getVersion.ts new file mode 100644 index 0000000000..32ea970c94 --- /dev/null +++ b/Composer/packages/server/src/utility/getVersion.ts @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import path from 'path'; + +import fs from 'fs-extra'; + +const isProduction = process.env.NODE_ENV === 'production'; + +export function getVersion(): string { + try { + const version = fs.readJSONSync(path.join(__dirname, '../../../electron-server/package.json')).version; + return isProduction ? version : `${version}-DEV`; + } catch { + return 'unknown'; + } +} From 81c7c3f827ae1378c320c18d4dc65e242fa84ef1 Mon Sep 17 00:00:00 2001 From: Soroush Date: Fri, 23 Apr 2021 13:35:01 -0700 Subject: [PATCH 10/13] fixes 6799 (#7320) Co-authored-by: Soroush --- Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx b/Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx index cd7b796bd5..10e3a6cb8b 100644 --- a/Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx +++ b/Composer/packages/lib/code-editor/src/lu/LuLabelingMenu.tsx @@ -4,6 +4,7 @@ import { LuEntity, LuFile } from '@botframework-composer/types'; import formatMessage from 'format-message'; import { ContextualMenu, DirectionalHint, IContextualMenuItem } from 'office-ui-fabric-react/lib/ContextualMenu'; +import { ZIndexes } from 'office-ui-fabric-react/lib/Styling'; import React, { useCallback, useEffect, useState } from 'react'; import { isSelectionWithinBrackets } from '../utils/luUtils'; @@ -11,6 +12,9 @@ import { isSelectionWithinBrackets } from '../utils/luUtils'; import { useLabelingMenuProps } from './hooks/useLabelingMenuItems'; import { useMonacoSelectedTextDom } from './hooks/useMonacoSelectedTextDom'; +// This makes sure that this Fabric context menu appears under any Fabric layers in Composer +const calloutProps = { layerProps: { styles: { root: { zIndex: ZIndexes.Layer - 1 } } } }; + type Props = { editor: any; luFile?: LuFile; @@ -92,6 +96,7 @@ export const LuLabelingMenu = ({ editor, luFile, onMenuToggled, onInsertEntity } return menuTargetElm && !noEntities ? (
- { onNext(); }} /> + diff --git a/extensions/azurePublish/src/components/ResourceGroupPicker.tsx b/extensions/azurePublish/src/components/ResourceGroupPicker.tsx index 85a6ab616a..00a8105b17 100644 --- a/extensions/azurePublish/src/components/ResourceGroupPicker.tsx +++ b/extensions/azurePublish/src/components/ResourceGroupPicker.tsx @@ -7,29 +7,13 @@ import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown'; import { Icon } from 'office-ui-fabric-react/lib/Icon'; import { Stack } from 'office-ui-fabric-react/lib/Stack'; import { TextField } from 'office-ui-fabric-react/lib/TextField'; -import { FluentTheme } from '@uifabric/fluent-theme'; -import { TooltipHost } from 'office-ui-fabric-react/lib/Tooltip'; import { useDebounce } from './useDebounce'; const stackStyles = { root: { marginBottom: '6px' } }; -const dropdownStyles = { root: { marginBottom: '6px' }, dropdown: { width: '75%' } }; +const dropdownStyles = { root: { marginBottom: '6px' }, dropdown: { width: '300px' } }; const itemIconStyles = { marginRight: '8px' }; -const newNameTextFileStyles = { root: { marginTop: '10px', width: '75%' } }; - -const getInfoIconStyle = (required) => { - return { - root: { - selectors: { - '&::before': { - content: required ? " '*'" : '', - color: FluentTheme.palette.red, - paddingRight: 3, - }, - }, - }, - }; -}; +const newNameTextFileStyles = { root: { marginTop: '10px', width: '300px' } }; const CREATE_NEW_KEY = 'CREATE_NEW'; @@ -70,31 +54,6 @@ type Props = { onChange: (choice: ResourceGroupItemChoice) => void; }; -const onRenderLabel = (props) => { - return ( -
-
- {` ${props.label} `} -
- - - -
- ); -}; - export const ResourceGroupPicker = ({ disabled, resourceGroupNames, @@ -170,12 +129,7 @@ export const ResourceGroupPicker = ({ return ( {isNew && ( { setNewName(val || ''); }} - onRenderLabel={onRenderLabel} /> )} diff --git a/extensions/azurePublish/src/components/azureProvisionDialog.tsx b/extensions/azurePublish/src/components/azureProvisionDialog.tsx index 72c4e259c7..ca3a7d8a28 100644 --- a/extensions/azurePublish/src/components/azureProvisionDialog.tsx +++ b/extensions/azurePublish/src/components/azureProvisionDialog.tsx @@ -34,10 +34,15 @@ import { SelectionMode, Stack, Text, + FontWeights, + FontSizes, + Label, + IStackTokens, + IStackItemStyles, + Link, } from 'office-ui-fabric-react'; import { MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/MessageBar'; import { JsonEditor } from '@bfc/code-editor'; -import { SharedColors } from '@uifabric/fluent-theme'; import { ResourceGroup } from '@azure/arm-resources/esm/models'; import sortBy from 'lodash/sortBy'; @@ -75,27 +80,46 @@ const AddResourcesSectionName = styled(Text)` font-size: ${FluentTheme.fonts.mediumPlus.fontSize}; `; -const labelTooltipStyles = { +const ConfigureResourcesSectionName = styled(Text)` + font-size: ${FluentTheme.fonts.mediumPlus.fontSize}; + font-weight: ${FontWeights.semibold}; + margin-bottom: 4px; +`; + +const ConfigureResourcesSectionDescription = styled(Text)` + font-size: ${FluentTheme.fonts.medium.fontSize}; + line-height: ${FontSizes.size14}; + margin-bottom: 20px; +`; + +const configureResourcePropertyStackTokens: IStackTokens = { childrenGap: 5 }; + +const configureResourcePropertyLabelStackStyles: IStackItemStyles = { root: { - userSelect: 'none', + width: '200px', }, }; -const iconStyle = (required) => { - return { - root: { - selectors: { - '&::before': { - content: required ? " '*'" : '', - color: SharedColors.red10, - paddingRight: 3, - }, - }, - }, - }; +const ConfigureResourcesPropertyLabel = styled(Label)` + font-size: ${FluentTheme.fonts.medium.fontSize}; + font-weight: ${FontWeights.regular}; +`; + +const configureResourceDropdownStyles = { root: { paddingBottom: '4px', width: '300px' } }; + +const configureResourceTextFieldStyles = { root: { paddingBottom: '4px', width: '300px' } }; + +const configureResourcesIconStyle = { + root: { + color: NeutralColors.gray160, + userSelect: 'none', + }, }; -const resourceFieldStyles = { root: { paddingBottom: '4px', width: '75%' } }; +const LearnMoreLink = styled(Link)` + user-select: none; + font-size: 14px; +`; const PageTypes = { ChooseAction: 'chooseAction', @@ -141,36 +165,10 @@ const DialogTitle = { }, CONFIG_RESOURCES: { title: formatMessage('Configure resources'), - subText: formatMessage('How you would like to provision your Azure resources to publish your bot?'), + subText: '', }, }; -const onRenderLabel = (props) => { - return ( -
-
- {' '} - {props.label}{' '} -
- - - -
- ); -}; - const getResourceRegion = (item: ResourcesItem): string => { const { key, region } = item; switch (key) { @@ -295,6 +293,7 @@ export const AzureProvisionDialog: React.FC = () => { } = usePublishApi(); const telemetryClient: TelemetryClient = useTelemetryClient(); + // eslint-disable-next-line no-console console.log('TELEMETRY CLIENT', telemetryClient); const { setItem, getItem, clearAll } = useLocalStorage(); @@ -787,6 +786,14 @@ export const AzureProvisionDialog: React.FC = () => {
); + const renderPropertyInfoIcon = (tooltip: string) => { + return ( + + + + ); + }; + const PageFormConfig = ( { style={{ height: 'calc(100vh - 65px)' }} >
- ({ key: t.tenantId, text: t.displayName }))} - selectedKey={formData.tenantId} - styles={resourceFieldStyles} - onChange={(_e, o) => { - updateFormData('tenantId', o.key as string); - }} - onRenderLabel={onRenderLabel} - /> - { - updateFormData('subscriptionId', o.key as string); - }} - onRenderLabel={onRenderLabel} - /> - { - setIsNewResourceGroup(choice.isNew); - updateFormData('resourceGroup', choice.name); - setErrorResourceGroupName(choice.errorMessage); - }} - /> - - - { - updateFormData('luisLocation', o.key as string); - }} - /> + + {formatMessage('Azure details')} + + {formatMessage('Select your Azure directory and subscription, enter resource group name.')} + + + + + {formatMessage('Azure Directory')} + + {renderPropertyInfoIcon( + formatMessage( + 'Azure Active Directory is Microsoft’s cloud-based identity and access management service.' + ) + )} + + ({ key: t.tenantId, text: t.displayName }))} + selectedKey={formData.tenantId} + styles={configureResourceDropdownStyles} + onChange={(_e, o) => { + updateFormData('tenantId', o.key as string); + }} + /> + + + + + {formatMessage('Subscription')} + + {renderPropertyInfoIcon(formatMessage('The subscription that will be billed for the resources.'))} + + { + updateFormData('subscriptionId', o.key as string); + }} + /> + + + + + {formatMessage('Resource group')} + + {renderPropertyInfoIcon( + formatMessage( + 'A custom resource group name that you choose or create. Resource groups allow you to group Azure resources for access and management.' + ) + )} + + { + setIsNewResourceGroup(choice.isNew); + updateFormData('resourceGroup', choice.name); + setErrorResourceGroupName(choice.errorMessage); + }} + /> + + {formatMessage('Resource details')} + + {formatMessage('Enter resource name and select region. This will be applied to the new resources.')} + + + + {formatMessage('Name')} + {renderPropertyInfoIcon(formatMessage('A unique name for your resources.'))} + + + + + + {formatMessage('Region')} + {renderPropertyInfoIcon(formatMessage('The region where your resources and bot will be used.'))} + + + + + + + + {formatMessage('LUIS region')} + + {renderPropertyInfoIcon(formatMessage('The region associated with your Language understanding model.'))} + + + {formatMessage('Learn More')} + + + { + updateFormData('luisLocation', o.key as string); + }} + /> + +
); @@ -1037,7 +1094,7 @@ export const AzureProvisionDialog: React.FC = () => { { onNext(formData.hostname); }} @@ -1058,6 +1115,13 @@ export const AzureProvisionDialog: React.FC = () => { onClick={onSave} /> )} + { + closeDialog(); + }} + />
); @@ -1143,7 +1207,7 @@ export const AzureProvisionDialog: React.FC = () => { { const selectedResources = formData.requiredResources.concat(formData.enabledResources); onSubmit({ @@ -1158,6 +1222,13 @@ export const AzureProvisionDialog: React.FC = () => { }); }} /> + { + closeDialog(); + }} + /> ); @@ -1226,7 +1297,15 @@ export const AzureProvisionDialog: React.FC = () => { closeDialog(); }} /> -
+
{page === PageTypes.ChooseAction && PageChooseAction} {page === PageTypes.ConfigProvision && PageFormConfig} From 99a74b9a5686d30759a331fadb25a0d301c89852 Mon Sep 17 00:00:00 2001 From: Chris Whitten Date: Fri, 23 Apr 2021 15:39:27 -0700 Subject: [PATCH 12/13] Updated link location to SDK release, adds link to documenation on the About page (#7339) Co-authored-by: Soroush --- Composer/packages/client/config/env.js | 2 +- Composer/packages/client/src/pages/about/About.tsx | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Composer/packages/client/config/env.js b/Composer/packages/client/config/env.js index 5cedb12698..d2fbdabd8b 100644 --- a/Composer/packages/client/config/env.js +++ b/Composer/packages/client/config/env.js @@ -95,7 +95,7 @@ function getClientEnvironment(publicUrl) { // images into the `src` and `import` them in code to get their paths. PUBLIC_URL: publicUrl, GIT_SHA: getGitSha().toString().replace('\n', ''), - SDK_PACKAGE_VERSION: '4.12.2', // TODO: change this when Composer supports custom schema/custom runtime + SDK_PACKAGE_VERSION: '4.12.0', // TODO: change this when Composer supports custom schema/custom runtime COMPOSER_VERSION: getComposerVersion(), LOCAL_PUBLISH_PATH: process.env.LOCAL_PUBLISH_PATH || path.resolve(process.cwd(), '../../../extensions/localPublish/hostedBots'), diff --git a/Composer/packages/client/src/pages/about/About.tsx b/Composer/packages/client/src/pages/about/About.tsx index 1db2782875..38355c4b4c 100644 --- a/Composer/packages/client/src/pages/about/About.tsx +++ b/Composer/packages/client/src/pages/about/About.tsx @@ -41,7 +41,7 @@ export const About: React.FC = () => {
{formatMessage(`SDK runtime packages`)}
@@ -51,13 +51,18 @@ export const About: React.FC = () => {
+
+ + {formatMessage(`Documentation`)} + +
- {formatMessage(`Getting Help`)} + {formatMessage(`Report a bug or request a feature`)}
From 1de395f4e39b7ed62fa709c6f177ce60d4afe9cc Mon Sep 17 00:00:00 2001 From: Chris Whitten Date: Sun, 25 Apr 2021 07:49:26 -0700 Subject: [PATCH 13/13] Bumps to 2.0.0 (#7350) --- Composer/packages/electron-server/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Composer/packages/electron-server/package.json b/Composer/packages/electron-server/package.json index a5857668ec..b718146017 100644 --- a/Composer/packages/electron-server/package.json +++ b/Composer/packages/electron-server/package.json @@ -2,7 +2,7 @@ "name": "@bfc/electron-server", "license": "MIT", "author": "Microsoft Corporation", - "version": "1.4.0", + "version": "2.0.0", "description": "Electron wrapper around Composer that launches Composer as a desktop application.", "main": "./build/main.js", "engines": {