From f0ebe562c6d8d7334b62b078f2cc4f52fbed8e4a Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Wed, 20 Nov 2019 14:22:24 -0800 Subject: [PATCH 01/45] docs: update coveralls badge (#1621) * update coveralls badge * try using coveralls github action * use master branch for status badges * remove old coveralls step --- .github/workflows/main.yml | 18 +++++------------- Composer/README.md | 4 ++-- README.md | 6 +++--- 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c32f34e045..8bcfa37e0c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,19 +42,11 @@ jobs: - name: yarn test:coverage run: yarn test:coverage working-directory: Composer - # secrets are not exposed to PRs opened by forks, so just skip this step if it is not defined - - name: Publish coverage results - run: | - if [[ -z $COVERALLS_REPO_TOKEN ]]; then - echo "Coveralls token not found. Skipping." - else - cat coverage/lcov.info | ./node_modules/.bin/coveralls - fi - working-directory: Composer - env: - COVERALLS_SERVICE_NAME: "Github Actions" - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} - COVERALLS_GIT_BRANCH: ${{ github.ref }} + - name: Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: ./Composer/coverage/lcov.info botproject: name: BotProject diff --git a/Composer/README.md b/Composer/README.md index 50a7c25158..91f9e36dda 100644 --- a/Composer/README.md +++ b/Composer/README.md @@ -1,5 +1,5 @@ -[![Build Status](https://github.com/microsoft/BotFramework-Composer/workflows/Composer%20CI/badge.svg?branch=stable)](https://github.com/microsoft/BotFramework-Composer/actions?query=branch%3Astable) -[![Coverage Status](https://coveralls.io/repos/github/microsoft/BotFramework-Composer/badge.svg?branch=stable)](https://coveralls.io/github/microsoft/BotFramework-Composer?branch=stable) +[![Build Status](https://github.com/microsoft/BotFramework-Composer/workflows/Composer%20CI/badge.svg?branch=master)](https://github.com/microsoft/BotFramework-Composer/actions?query=branch%3Amaster) +[![Coverage Status](https://coveralls.io/repos/github/microsoft/BotFramework-Composer/badge.svg?branch=master)](https://coveralls.io/github/microsoft/BotFramework-Composer?branch=master) [![Total alerts](https://img.shields.io/lgtm/alerts/g/microsoft/BotFramework-Composer.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/microsoft/BotFramework-Composer/alerts/) # Composer diff --git a/README.md b/README.md index 4269ac16a4..8a6983b404 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ # Microsoft Bot Framework Composer [PREVIEW] -[![Build Status](https://github.com/microsoft/BotFramework-Composer/workflows/Composer%20CI/badge.svg?branch=stable)](https://github.com/microsoft/BotFramework-Composer/actions?query=branch%3Astable) -[![Coverage Status](https://coveralls.io/repos/github/microsoft/BotFramework-Composer/badge.svg?branch=stable)](https://coveralls.io/github/microsoft/BotFramework-Composer?branch=stable) +[![Build Status](https://github.com/microsoft/BotFramework-Composer/workflows/Composer%20CI/badge.svg?branch=master)](https://github.com/microsoft/BotFramework-Composer/actions?query=branch%3Amaster) +[![Coverage Status](https://coveralls.io/repos/github/microsoft/BotFramework-Composer/badge.svg?branch=master)](https://coveralls.io/github/microsoft/BotFramework-Composer?branch=master) [![Total alerts](https://img.shields.io/lgtm/alerts/g/microsoft/BotFramework-Composer.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/microsoft/BotFramework-Composer/alerts/) ## Overview @@ -73,7 +73,7 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio ### Issues and feature requests -Please file issues and feature requests [here](https://github.com/microsoft/BotFramework-Composer/issues/issues). +Please file issues and feature requests [here](https://github.com/microsoft/BotFramework-Composer/issues/issues). Also, see current [known issues](https://github.com/microsoft/BotFramework-Composer/labels/known%20issue) for high impact bugs you may experience. From 29b4232ce258761b4638e9c8235dbdfc6cef672c Mon Sep 17 00:00:00 2001 From: Lu Han <32191031+luhan2017@users.noreply.github.com> Date: Thu, 21 Nov 2019 23:56:51 +0800 Subject: [PATCH 02/45] fix: Fix interruption sample (#1624) * Fix interruption sample 1. add a thredhold in GetStarted intent to avoid over trigger. 2. fix malformed schema, extra comma 3. fix value expression. 4. fix turn.value -> this.value 5. fix allowInterrutions: notRecognized->true * Update common.lg * Update common.lg --- .../GetProfile/GetProfile.dialog | 30 +++++++++---------- .../ComposerDialogs/Main/Main.dialog | 3 +- .../ComposerDialogs/common/common.lg | 6 ++++ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/GetProfile/GetProfile.dialog b/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/GetProfile/GetProfile.dialog index 6cbf0cb754..4f8703b538 100644 --- a/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/GetProfile/GetProfile.dialog +++ b/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/GetProfile/GetProfile.dialog @@ -20,18 +20,18 @@ "name": "Prompt for text", "id": "362298" }, - "allowInterruptions": "true", "prompt": "What is your name? \\n \\[Suggestions=Why? | No name | Cancel | Reset profile\\]", - "invalidPrompt": "Sorry, '{turn.value}' does not work. I'm looking for 2-150 characters. What is your name? \\n \\[Suggestions=Why? | No name | Cancel | Reset profile\\]", + "invalidPrompt": "[bfdinvalidPrompt-362298]", "maxTurnCount": 3, "validations": [ - "length(turn.value) <= 150", - "length(turn.value) > 2" + "length(this.value) <= 150", + "length(this.value) > 2" ], - "value": "concat(toUpper(substring(@userName, 0, 1)), substring(@userName, 1))", "property": "user.profile.name", "defaultValue": "'Human'", + "value": "@userName", "alwaysPrompt": false, + "allowInterruptions": "true", "outputFormat": "trim" }, { @@ -40,21 +40,21 @@ "name": "Prompt for a number", "id": "005947" }, - "property": "user.profile.age", "prompt": "Hello {user.profile.name}, how old are you? \\n \\[Suggestions=Why? | Reset profile | Cancel | No age\\]", - "invalidPrompt": "Sorry, {turn.value} does not work. I'm looking for a value between 1-150. What is your age? \\n \\[Suggestions=Why? | Reset profile | Cancel | No age\\]", + "unrecognizedPrompt": "Hello {user.profile.name}, how old are you? \\n \\[Suggestions=Why? | Reset profile | Cancel | No age\\]", + "invalidPrompt": "[bfdinvalidPrompt-005947]", "maxTurnCount": 3, "validations": [ - "int(turn.value) >= 1", - "int(turn.value) <= 150" + "int(this.value) >= 1", + "int(this.value) <= 150" ], - "value": "@userAge", + "property": "user.profile.age", "defaultValue": "30", + "value": "@userAge", "alwaysPrompt": false, - "allowInterruptions": "notRecognized", + "allowInterruptions": "true", "outputFormat": "float", - "defaultLocale": "en-us", - "unrecognizedPrompt": "Hello {user.profile.name}, how old are you? \\n \\[Suggestions=Why? | Reset profile | Cancel | No age\\]" + "defaultLocale": "en-us" }, { "$type": "Microsoft.SendActivity", @@ -169,5 +169,5 @@ "intent": "GetProfileInputs" } ], - "$schema": "https://raw.githubusercontent.com/microsoft/BotFramework-Composer/stable/Composer/packages/server/schemas/sdk.schema", -} \ No newline at end of file + "$schema": "https://raw.githubusercontent.com/microsoft/BotFramework-Composer/stable/Composer/packages/server/schemas/sdk.schema" +} diff --git a/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/Main/Main.dialog b/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/Main/Main.dialog index 96e2cc07f9..e67eb8e819 100644 --- a/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/Main/Main.dialog +++ b/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/Main/Main.dialog @@ -33,6 +33,7 @@ "name": "GetStarted", "id": "629539" }, + "condition": "turn.recognized.score > 0.7", "actions": [ { "$type": "Microsoft.BeginDialog", @@ -172,4 +173,4 @@ } ], "$schema": "https://raw.githubusercontent.com/microsoft/BotFramework-Composer/stable/Composer/packages/server/schemas/sdk.schema" -} \ No newline at end of file +} diff --git a/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/common/common.lg b/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/common/common.lg index e29c5887ce..a0e2394507 100644 --- a/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/common/common.lg +++ b/Composer/packages/server/assets/projects/InterruptionSample/ComposerDialogs/common/common.lg @@ -51,3 +51,9 @@ Here's what I know about you - # bfdactivity-032735 - I've reset your profile. \n \[Suggestions=Get started] + +# bfdinvalidPrompt-362298 +- Sorry, '{this.value}' does not work. I'm looking for 2-150 characters. What is your name? \n \[Suggestions=Why? | No name | Cancel | Reset profile\] + +# bfdinvalidPrompt-005947 +- Sorry, {this.value} does not work. I'm looking for a value between 1-150. What is your age? \n \[Suggestions=Why? | Reset profile | Cancel | No age\] From 2f96b5210cb9a86f20fe3ebdc07e01c054f733a3 Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Thu, 21 Nov 2019 13:58:46 -0800 Subject: [PATCH 03/45] refactor: convert cypress tests to typescript (#1630) * remove eslint typechecking rules causes too many issues with vscode for now * consolidate tsconfig * set up cypress for typescript * remove unused files * only need to lint ts and tsx * use base tsconifg * fix lint errors and TS errors * set up integration tests for typescript * remove old js files * configure eslint for cypress * convert support files to typescript * fix create bot command * remove waits * update create bot spec * restore before each cleanup task * convert home page spec to typescript * convert LeftNavBar spec to typescript * convert LGPage spec to typescript * convert LuisDeploy spec to typescript * convert LUPage spec to typescript * convert NewDialog spec to typescript * convert NotificationPage spec to typescript * convert Onboarding spec to typescript * convert RemoveDialog spec to typescript * remove commented waits * convert SaveAs spec to typescript * remove switch condition spec too unstable * convert ToDo spec to typescript * convert VisualDesigner spec to typescript * remove unused cypress commands --- Composer/.eslintrc.js | 1 - Composer/cypress.json | 1 + Composer/cypress/.eslintrc.js | 3 + .../cypress/integration/Breadcrumb.spec.js | 75 --- .../cypress/integration/Breadcrumb.spec.ts | 66 ++ .../cypress/integration/CreateNewBot.spec.js | 44 -- .../cypress/integration/CreateNewBot.spec.ts | 35 + Composer/cypress/integration/HomePage.spec.ts | 22 + .../{LGPage.spec.js => LGPage.spec.ts} | 17 +- .../{LUPage.spec.js => LUPage.spec.ts} | 20 +- .../cypress/integration/LeftNavBar.spec.js | 18 - .../cypress/integration/LeftNavBar.spec.ts | 20 + ...{LuisDeploy.spec.js => LuisDeploy.spec.ts} | 33 +- .../cypress/integration/NewDialog.spec.js | 18 - .../cypress/integration/NewDialog.spec.ts | 18 + .../integration/NotificationPage.spec.js | 25 - .../integration/NotificationPage.spec.ts | 25 + .../cypress/integration/Onboarding.spec.js | 51 -- .../cypress/integration/Onboarding.spec.ts | 44 ++ ...oveDialog.spec.js => RemoveDialog.spec.ts} | 17 +- Composer/cypress/integration/SaveAs.spec.js | 22 - Composer/cypress/integration/SaveAs.spec.ts | 21 + .../integration/SwitchCondition.spec.js | 164 ----- Composer/cypress/integration/ToDoBot.spec.js | 62 -- Composer/cypress/integration/ToDoBot.spec.ts | 58 ++ .../integration/VisualDesigner.spec.js | 28 - .../integration/VisualDesigner.spec.ts | 26 + Composer/cypress/integration/homePage.spec.js | 19 - .../cypress/plugins/cy-ts-preprocessor.js | 31 + Composer/cypress/plugins/index.js | 23 +- Composer/cypress/support/commands.d.ts | 30 + Composer/cypress/support/commands.js | 107 --- Composer/cypress/support/commands.ts | 26 + Composer/cypress/support/index.js | 29 - Composer/cypress/support/index.ts | 14 + Composer/cypress/tsconfig.json | 10 + Composer/package.json | 5 +- Composer/packages/client/src/ShellApi.ts | 13 +- .../ProjectTree/TriggerCreationModal.tsx | 4 - .../src/extension-container/EditorMap.ts | 2 +- .../ExtensionContainer.tsx | 50 +- .../pages/language-generation/code-editor.tsx | 10 +- .../client/src/store/action/setting.ts | 2 +- .../src/store/middlewares/undo/history.ts | 5 - Composer/packages/client/tsconfig.json | 15 +- .../obiformeditor/demo/src/index.tsx | 4 - .../extensions/obiformeditor/package.json | 2 +- .../obiformeditor/src/Form/utils.ts | 8 +- .../obiformeditor/src/FormEditor.tsx | 2 +- .../extensions/obiformeditor/tsconfig.json | 16 +- .../extensions/visual-designer/.eslintignore | 2 - .../extensions/visual-designer/.travis.yml | 16 - .../components/lib/EdgeComponents.test.tsx | 3 + .../extensions/visual-designer/package.json | 2 +- .../components/lib/Collapse/CollapseStyles.ts | 3 + .../src/components/lib/Collapse/index.tsx | 7 +- .../src/components/lib/DragScroll.tsx | 3 + .../src/components/lib/EdgeComponents.tsx | 3 + .../src/components/lib/KeyboardZone.tsx | 3 + .../src/components/lib/OffsetContainer.tsx | 3 + .../src/components/lib/Panel.tsx | 5 +- .../visual-designer/src/editors/ObiEditor.tsx | 2 +- .../extensions/visual-designer/src/index.tsx | 31 +- .../src/store/NodeRendererContext.ts | 30 +- .../visual-designer/src/utils/hooks.ts | 2 +- .../extensions/visual-designer/tsconfig.json | 19 +- .../packages/lib/code-editor/package.json | 2 +- .../lib/code-editor/src/BaseEditor.tsx | 9 +- .../lib/code-editor/src/RichEditor.tsx | 2 +- .../packages/lib/code-editor/tsconfig.json | 18 +- Composer/packages/lib/indexers/package.json | 2 +- Composer/packages/lib/indexers/tsconfig.json | 18 +- .../packages/lib/shared/src/types/shell.ts | 16 +- Composer/packages/lib/shared/tsconfig.json | 19 +- Composer/packages/server/src/server.ts | 2 +- Composer/packages/server/tsconfig.json | 21 +- Composer/tsconfig.base.json | 20 + Composer/yarn.lock | 629 +++++++++++++++++- 78 files changed, 1259 insertions(+), 994 deletions(-) create mode 100644 Composer/cypress/.eslintrc.js delete mode 100644 Composer/cypress/integration/Breadcrumb.spec.js create mode 100644 Composer/cypress/integration/Breadcrumb.spec.ts delete mode 100644 Composer/cypress/integration/CreateNewBot.spec.js create mode 100644 Composer/cypress/integration/CreateNewBot.spec.ts create mode 100644 Composer/cypress/integration/HomePage.spec.ts rename Composer/cypress/integration/{LGPage.spec.js => LGPage.spec.ts} (64%) rename Composer/cypress/integration/{LUPage.spec.js => LUPage.spec.ts} (63%) delete mode 100644 Composer/cypress/integration/LeftNavBar.spec.js create mode 100644 Composer/cypress/integration/LeftNavBar.spec.ts rename Composer/cypress/integration/{LuisDeploy.spec.js => LuisDeploy.spec.ts} (57%) delete mode 100644 Composer/cypress/integration/NewDialog.spec.js create mode 100644 Composer/cypress/integration/NewDialog.spec.ts delete mode 100644 Composer/cypress/integration/NotificationPage.spec.js create mode 100644 Composer/cypress/integration/NotificationPage.spec.ts delete mode 100644 Composer/cypress/integration/Onboarding.spec.js create mode 100644 Composer/cypress/integration/Onboarding.spec.ts rename Composer/cypress/integration/{RemoveDialog.spec.js => RemoveDialog.spec.ts} (52%) delete mode 100644 Composer/cypress/integration/SaveAs.spec.js create mode 100644 Composer/cypress/integration/SaveAs.spec.ts delete mode 100644 Composer/cypress/integration/SwitchCondition.spec.js delete mode 100644 Composer/cypress/integration/ToDoBot.spec.js create mode 100644 Composer/cypress/integration/ToDoBot.spec.ts delete mode 100644 Composer/cypress/integration/VisualDesigner.spec.js create mode 100644 Composer/cypress/integration/VisualDesigner.spec.ts delete mode 100644 Composer/cypress/integration/homePage.spec.js create mode 100644 Composer/cypress/plugins/cy-ts-preprocessor.js create mode 100644 Composer/cypress/support/commands.d.ts delete mode 100644 Composer/cypress/support/commands.js create mode 100644 Composer/cypress/support/commands.ts delete mode 100644 Composer/cypress/support/index.js create mode 100644 Composer/cypress/support/index.ts create mode 100644 Composer/cypress/tsconfig.json delete mode 100644 Composer/packages/extensions/visual-designer/.eslintignore delete mode 100644 Composer/packages/extensions/visual-designer/.travis.yml create mode 100644 Composer/tsconfig.base.json diff --git a/Composer/.eslintrc.js b/Composer/.eslintrc.js index 678fddde71..ed316fe804 100644 --- a/Composer/.eslintrc.js +++ b/Composer/.eslintrc.js @@ -3,7 +3,6 @@ module.exports = { 'eslint:recommended', 'plugin:prettier/recommended', 'plugin:@typescript-eslint/recommended', - 'plugin:@typescript-eslint/recommended-requiring-type-checking', 'plugin:@typescript-eslint/eslint-recommended', 'prettier/@typescript-eslint', 'plugin:@bfc/bfcomposer/recommended', diff --git a/Composer/cypress.json b/Composer/cypress.json index 2146eadef4..a1ba87574c 100644 --- a/Composer/cypress.json +++ b/Composer/cypress.json @@ -4,6 +4,7 @@ "**/examples/*", "*.hot-update.js" ], + "supportFile": "cypress/support/index.ts", "video": false, "videoUploadOnPasses": false, "viewportWidth": 1600, diff --git a/Composer/cypress/.eslintrc.js b/Composer/cypress/.eslintrc.js new file mode 100644 index 0000000000..89d2a80a8c --- /dev/null +++ b/Composer/cypress/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['../.eslintrc.js', 'plugin:cypress/recommended'], +}; diff --git a/Composer/cypress/integration/Breadcrumb.spec.js b/Composer/cypress/integration/Breadcrumb.spec.js deleted file mode 100644 index 3a00e21e28..0000000000 --- a/Composer/cypress/integration/Breadcrumb.spec.js +++ /dev/null @@ -1,75 +0,0 @@ -/// - -context('breadcrumb', () => { - - beforeEach(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - cy.createBot('TodoSample'); - cy.wait(100); - - // Return to Main.dialog - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.wait(1000); - cy.getByText('__TestTodoSample.Main').click(); - cy.wait(1000); - }); - }); - - it('can show dialog name in breadcrumb', () => { - // Should path = main dialog at first render - cy.getByTestId('Breadcrumb') - .invoke('text') - .should('contain', '__TestTodoSample.Main'); - - // Click on AddToDo dialog - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('AddToDo').click(); - }); - cy.getByTestId('Breadcrumb') - .invoke('text') - .should('contain', 'AddToDo'); - cy.wait(1000); - // Return to Main.dialog - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('__TestTodoSample.Main').click(); - cy.wait(100); - }); - - cy.getByTestId('Breadcrumb') - .invoke('text') - .should('contain', '__TestTodoSample'); - }); - - it('can show event name in breadcrumb', () => { - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('AddToDo').click(); - cy.wait(100); - cy.getByText('Dialog started (BeginDialog)').click(); - cy.wait(100); - }); - - cy.getByTestId('Breadcrumb') - .invoke('text') - .should('match', /AddToDo.*Dialog started (BeginDialog)*/); - }); - - it('can show action name in breadcrumb', () => { - cy.wait(100); - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('Greeting (ConversationUpdate)').click(); - cy.wait(500); - }); - - // Click on an action - cy.withinEditor('VisualEditor', () => { - cy.getByTestId('RuleEditor').within(() => { - cy.getByText('Send a response').click(); - cy.wait(500); - }); - }); - - cy.getByTestId('Breadcrumb') - .invoke('text') - .should('match', /__TestTodoSample.Main.*Greeting \(ConversationUpdate\).*Send a response/); - }); -}); diff --git a/Composer/cypress/integration/Breadcrumb.spec.ts b/Composer/cypress/integration/Breadcrumb.spec.ts new file mode 100644 index 0000000000..8c647ee409 --- /dev/null +++ b/Composer/cypress/integration/Breadcrumb.spec.ts @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('breadcrumb', () => { + beforeEach(() => { + cy.visit(Cypress.env('COMPOSER_URL')); + cy.createBot('TodoSample'); + + // Return to Main.dialog + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('__TestTodoSample.Main').click(); + }); + }); + + function hasBreadcrumbItems(cy: Cypress.cy, items: (string | RegExp)[]) { + cy.findByTestId('Breadcrumb') + .get('li') + .should($li => { + items.forEach((item, idx) => { + expect($li.eq(idx)).to.contain(item); + }); + }); + } + + it('can show dialog name in breadcrumb', () => { + // Should path = main dialog at first render + hasBreadcrumbItems(cy, ['__TestTodoSample.Main']); + + // Click on AddToDo dialog + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('AddToDo').click(); + }); + hasBreadcrumbItems(cy, ['AddToDo']); + + // Return to Main.dialog + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('__TestTodoSample.Main').click(); + }); + + hasBreadcrumbItems(cy, ['__TestTodoSample']); + }); + + it('can show event name in breadcrumb', () => { + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('AddToDo').click(); + cy.findByText('Dialog started (BeginDialog)').click(); + }); + + hasBreadcrumbItems(cy, ['AddToDo', 'Dialog started (BeginDialog)']); + }); + + it('can show action name in breadcrumb', () => { + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('Greeting (ConversationUpdate)').click(); + }); + + // Click on an action + cy.withinEditor('VisualEditor', () => { + cy.findByTestId('RuleEditor').within(() => { + cy.findByText('Send a response').click(); + }); + }); + + hasBreadcrumbItems(cy, ['__TestTodoSample.Main', 'Greeting (ConversationUpdate)', 'Send a response']); + }); +}); diff --git a/Composer/cypress/integration/CreateNewBot.spec.js b/Composer/cypress/integration/CreateNewBot.spec.js deleted file mode 100644 index dff154be2a..0000000000 --- a/Composer/cypress/integration/CreateNewBot.spec.js +++ /dev/null @@ -1,44 +0,0 @@ -/// - -context('Creating a new bot', () => { - beforeEach(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - cy.wait(1000); - cy.get('[data-testid="LeftNav-CommandBarButtonHome"]').click(); - cy.wait(5000); - cy.get('[data-testid="homePage-ToolBar-New"]').within(() => { - cy.getByText('New').click(); - }); - cy.wait(5000); - }); - - it('can create a new bot', () => { - cy.get('input[data-testid="Create from scratch"]').click(); - cy.wait(100); - cy.get('button[data-testid="NextStepButton"]').click(); - cy.wait(100); - cy.get('input[data-testid="NewDialogName"]').type('__TestNewProject'); - cy.get('input[data-testid="NewDialogName"]').type('{enter}'); - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('__TestNewProject.Main').should('exist'); - }); - }); - - it('can create a bot from the ToDo template', () => { - cy.get('input[data-testid="Create from template"]').click({ force: true }); - cy.wait(100); - cy.get('[data-testid="TodoSample"]').click(); - cy.wait(100); - cy.get('button[data-testid="NextStepButton"]').click(); - cy.wait(100); - cy.get('input[data-testid="NewDialogName"]').type('__TestNewProject'); - cy.get('input[data-testid="NewDialogName"]').type('{enter}'); - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('__TestNewProject.Main').should('exist'); - cy.getByText('AddToDo').should('exist'); - cy.getByText('ClearToDos').should('exist'); - cy.getByText('DeleteToDo').should('exist'); - cy.getByText('ShowToDos').should('exist'); - }); - }); -}); diff --git a/Composer/cypress/integration/CreateNewBot.spec.ts b/Composer/cypress/integration/CreateNewBot.spec.ts new file mode 100644 index 0000000000..a02d28cc9a --- /dev/null +++ b/Composer/cypress/integration/CreateNewBot.spec.ts @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('Creating a new bot', () => { + beforeEach(() => { + cy.visit(Cypress.env('COMPOSER_URL')); + cy.findByTestId('LeftNav-CommandBarButtonHome').click(); + cy.findByTestId('homePage-ToolBar-New').within(() => { + cy.findByText('New').click(); + }); + }); + + it('can create a new bot', () => { + cy.findByTestId('Create from scratch').click(); + cy.findByTestId('NextStepButton').click(); + cy.findByTestId('NewDialogName').type('{selectall}__TestNewProject{enter}'); + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('__TestNewProject.Main').should('exist'); + }); + }); + + it('can create a bot from the ToDo template', () => { + cy.findByTestId('Create from template').click(); + cy.findByTestId('TodoSample').click(); + cy.findByTestId('NextStepButton').click(); + cy.findByTestId('NewDialogName').type('{selectall}__TestNewProject{enter}'); + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('__TestNewProject.Main').should('exist'); + cy.findByText('AddToDo').should('exist'); + cy.findByText('ClearToDos').should('exist'); + cy.findByText('DeleteToDo').should('exist'); + cy.findByText('ShowToDos').should('exist'); + }); + }); +}); diff --git a/Composer/cypress/integration/HomePage.spec.ts b/Composer/cypress/integration/HomePage.spec.ts new file mode 100644 index 0000000000..cdd82aa5aa --- /dev/null +++ b/Composer/cypress/integration/HomePage.spec.ts @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('Home Page ', () => { + beforeEach(() => { + cy.visit(Cypress.env('COMPOSER_URL')); + }); + + it('can open buttons in home page', () => { + cy.findByTestId('LeftNav-CommandBarButtonHome').click(); + cy.findByTestId('homePage-ToolBar-New').click(); + cy.findByText('Create from scratch?').should('exist'); + cy.findByText('Cancel').should('exist'); + cy.findByText('Cancel').click(); + cy.findByTestId('homePage-ToolBar-Open').click(); + cy.findByText('Select a Bot').should('exist'); + cy.findByText('Cancel').should('exist'); + cy.findByText('Cancel').click(); + cy.findByTestId('homePage-body-New').click(); + cy.findByText('Create from scratch?').should('exist'); + }); +}); diff --git a/Composer/cypress/integration/LGPage.spec.js b/Composer/cypress/integration/LGPage.spec.ts similarity index 64% rename from Composer/cypress/integration/LGPage.spec.js rename to Composer/cypress/integration/LGPage.spec.ts index cf9d281e7b..a10f2c7c82 100644 --- a/Composer/cypress/integration/LGPage.spec.js +++ b/Composer/cypress/integration/LGPage.spec.ts @@ -1,13 +1,14 @@ -/// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. -context('check language generation page', () => { +context('LG Page', () => { beforeEach(() => { cy.visit(Cypress.env('COMPOSER_URL')); cy.createBot('TodoSample'); }); it('can open language generation page', () => { - cy.get('[data-testid="LeftNav-CommandBarButtonBot Responses"]').click(); + cy.findByTestId('LeftNav-CommandBarButtonBot Responses').click(); // left nav tree cy.contains('TodoSample.Main'); cy.contains('All'); @@ -15,17 +16,21 @@ context('check language generation page', () => { cy.get('.toggleEditMode button').as('switchButton'); // by default is table view - cy.get('[data-testid="LGEditor"] [data-testid="table-view"]').should('exist'); + cy.findByTestId('LGEditor') + .findByTestId('table-view') + .should('exist'); // goto edit-mode cy.get('@switchButton').click(); - cy.get('[data-testid="LGEditor"] .monaco-editor').should('exist'); + cy.findByTestId('LGEditor') + .get('.monaco-editor') + .should('exist'); // back to table view cy.get('@switchButton').click(); // nav to Main dialog cy.get('.dialogNavTree a[title="__TestTodoSample.Main"]').click(); - cy.wait(300); + // cy.wait(300); // dialog filter, edit mode button is disabled. cy.get('@switchButton').should('be.disabled'); diff --git a/Composer/cypress/integration/LUPage.spec.js b/Composer/cypress/integration/LUPage.spec.ts similarity index 63% rename from Composer/cypress/integration/LUPage.spec.js rename to Composer/cypress/integration/LUPage.spec.ts index c10e15bc76..4f762924b1 100644 --- a/Composer/cypress/integration/LUPage.spec.js +++ b/Composer/cypress/integration/LUPage.spec.ts @@ -1,13 +1,14 @@ -/// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. -context('check language understanding page', () => { +context('LU Page', () => { before(() => { cy.visit(Cypress.env('COMPOSER_URL')); cy.createBot('ToDoBotWithLuisSample'); }); it('can open language understanding page', () => { - cy.get('[data-testid="LeftNav-CommandBarButtonUser Input"]').click(); + cy.findByTestId('LeftNav-CommandBarButtonUser Input').click(); // left nav tree cy.contains('ToDoBotWithLuisSample.Main'); @@ -19,18 +20,23 @@ context('check language understanding page', () => { cy.get('@switchButton').should('be.disabled'); // by default is table view - cy.get('[data-testid="LUEditor"] [data-testid="table-view"]').should('exist'); + cy.findByTestId('LUEditor') + .findByTestId('table-view') + .should('exist'); // nav to ToDoBotWithLuisSample.main dialog cy.get('.dialogNavTree button[title="__TestToDoBotWithLuisSample.Main"]').click({ multiple: true }); - cy.wait(300); // goto edit-mode cy.get('@switchButton').click(); - cy.get('[data-testid="LUEditor"] .monaco-editor').should('exist'); + cy.findByTestId('LUEditor') + .get('.monaco-editor') + .should('exist'); // back to all table view cy.get('.dialogNavTree button[title="All"]').click(); - cy.get('[data-testid="LUEditor"] [data-testid="table-view"]').should('exist'); + cy.findByTestId('LUEditor') + .findByTestId('table-view') + .should('exist'); }); }); diff --git a/Composer/cypress/integration/LeftNavBar.spec.js b/Composer/cypress/integration/LeftNavBar.spec.js deleted file mode 100644 index 130c66ead2..0000000000 --- a/Composer/cypress/integration/LeftNavBar.spec.js +++ /dev/null @@ -1,18 +0,0 @@ -/// -context('check Nav Expandion ', () => { - beforeEach(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - cy.createBot('TodoSample'); - }); - - it('can expand left Nav Bar', () => { - cy.get('[data-testid="LeftNavButton"]').click(); - cy.get('[data-testid="LeftNav-CommandBarButtonDesign Flow"]').should('exist'); - cy.get('[data-testid="LeftNav-CommandBarButtonBot Responses"]').click(); - cy.url().should('include', 'language-generation'); - cy.get('[data-testid="LeftNav-CommandBarButtonUser Input"]').click(); - cy.url().should('include', 'language-understanding'); - cy.get('[data-testid="LeftNav-CommandBarButtonSettings"]').click(); - cy.url().should('include', 'setting'); - }); -}); diff --git a/Composer/cypress/integration/LeftNavBar.spec.ts b/Composer/cypress/integration/LeftNavBar.spec.ts new file mode 100644 index 0000000000..780189025d --- /dev/null +++ b/Composer/cypress/integration/LeftNavBar.spec.ts @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('Left Nav Bar', () => { + beforeEach(() => { + cy.visit(Cypress.env('COMPOSER_URL')); + cy.createBot('TodoSample'); + }); + + it('can expand left Nav Bar', () => { + cy.findByTestId('LeftNavButton').click(); + cy.findByTestId('LeftNav-CommandBarButtonDesign Flow').should('exist'); + cy.findByTestId('LeftNav-CommandBarButtonBot Responses').click(); + cy.url().should('include', 'language-generation'); + cy.findByTestId('LeftNav-CommandBarButtonUser Input').click(); + cy.url().should('include', 'language-understanding'); + cy.findByTestId('LeftNav-CommandBarButtonSettings').click(); + cy.url().should('include', 'setting'); + }); +}); diff --git a/Composer/cypress/integration/LuisDeploy.spec.js b/Composer/cypress/integration/LuisDeploy.spec.ts similarity index 57% rename from Composer/cypress/integration/LuisDeploy.spec.js rename to Composer/cypress/integration/LuisDeploy.spec.ts index d6c3172d06..3283bf6cd6 100644 --- a/Composer/cypress/integration/LuisDeploy.spec.js +++ b/Composer/cypress/integration/LuisDeploy.spec.ts @@ -1,4 +1,5 @@ -/// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. context('Luis Deploy', () => { beforeEach(() => { @@ -11,7 +12,7 @@ context('Luis Deploy', () => { }); it('can deploy luis success', () => { - cy.get('[data-testid="LeftNav-CommandBarButtonUser Input"]').click(); + cy.findByTestId('LeftNav-CommandBarButtonUser Input').click(); cy.route({ method: 'POST', @@ -19,24 +20,22 @@ context('Luis Deploy', () => { status: 200, response: 'fixture:luPublish/success', }); - cy.getByText('Start Bot').click(); - cy.wait(5000); + cy.findByText('Start Bot').click(); + // clear its settings before - cy.get('[data-testid="ProjectNameInput"]') + cy.findByTestId('ProjectNameInput') .clear() .type('MyProject'); - cy.get('[data-testid="EnvironmentInput"]') + cy.findByTestId('EnvironmentInput') .clear() .type('composer'); - cy.get('[data-testid="AuthoringKeyInput"]') + cy.findByTestId('AuthoringKeyInput') .clear() .type('0d4991873f334685a9686d1b48e0ff48'); // wait for the debounce interval of sync settings - cy.wait(1000); - cy.getByText('OK').click(); - cy.wait(1000); - cy.getByText('Restart Bot').should('exist'); - cy.getByText('Test in Emulator').should('exist'); + cy.findByText('OK').click(); + cy.findByText('Restart Bot').should('exist'); + cy.findByText('Test in Emulator').should('exist'); cy.route({ method: 'POST', @@ -44,11 +43,9 @@ context('Luis Deploy', () => { status: 400, response: 'fixture:luPublish/error', }); - cy.getByText('Restart Bot').click(); - cy.wait(1000); - cy.getByText('Try again').click(); - cy.wait(1000); - cy.get('[data-testid="AuthoringKeyInput"]').type('no-id'); - cy.getByText('OK').click(); + cy.findByText('Restart Bot').click(); + cy.findByText('Try again').click(); + cy.findByTestId('AuthoringKeyInput').type('no-id'); + cy.findByText('OK').click(); }); }); diff --git a/Composer/cypress/integration/NewDialog.spec.js b/Composer/cypress/integration/NewDialog.spec.js deleted file mode 100644 index dedb0be001..0000000000 --- a/Composer/cypress/integration/NewDialog.spec.js +++ /dev/null @@ -1,18 +0,0 @@ -/// - -context('Creating a new Dialog', () => { - beforeEach(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - cy.copyBot('TodoSample', 'ToDoBotCopy'); - cy.get('[data-testid="LeftNav-CommandBarButtonDesign Flow"]').click(); - }); - - it('can create a new dialog from project tree', () => { - cy.getByText('New Dialog ..').click(); - cy.get('input[data-testid="NewDialogName"]').type('__TestNewDialog2'); - cy.get('input[data-testid="NewDialogName"]').type('{enter}'); - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('__TestNewDialog2').should('exist'); - }); - }); -}); diff --git a/Composer/cypress/integration/NewDialog.spec.ts b/Composer/cypress/integration/NewDialog.spec.ts new file mode 100644 index 0000000000..23c379ddfd --- /dev/null +++ b/Composer/cypress/integration/NewDialog.spec.ts @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('Creating a new Dialog', () => { + beforeEach(() => { + cy.visit(Cypress.env('COMPOSER_URL')); + cy.createBot('TodoSample'); + cy.findByTestId('LeftNav-CommandBarButtonDesign Flow').click(); + }); + + it('can create a new dialog from project tree', () => { + cy.findByText('New Dialog ..').click(); + cy.findByTestId('NewDialogName').type('{selectall}__TestNewDialog2{enter}'); + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('__TestNewDialog2').should('exist'); + }); + }); +}); diff --git a/Composer/cypress/integration/NotificationPage.spec.js b/Composer/cypress/integration/NotificationPage.spec.js deleted file mode 100644 index 0618ed70ba..0000000000 --- a/Composer/cypress/integration/NotificationPage.spec.js +++ /dev/null @@ -1,25 +0,0 @@ -/// - -context('check notifications page', () => { - beforeEach(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - cy.createBot('TodoSample'); - }); - - it('can show lg syntax error ', () => { - cy.visitPage("Bot Responses"); - // left nav tree - cy.contains('TodoSample.Main'); - cy.contains('All'); - - cy.get('.toggleEditMode button').click(); - cy.get('textarea').type('test lg syntax error'); - - cy.visitPage("Notifications"); - - cy.get('[data-testid="notifications-table-view"]').within(() => { - cy.getByText('common.lg').should('exist'); - }); - - }); -}); diff --git a/Composer/cypress/integration/NotificationPage.spec.ts b/Composer/cypress/integration/NotificationPage.spec.ts new file mode 100644 index 0000000000..7a3d9fe657 --- /dev/null +++ b/Composer/cypress/integration/NotificationPage.spec.ts @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('Notification Page', () => { + beforeEach(() => { + cy.visit(Cypress.env('COMPOSER_URL')); + cy.createBot('TodoSample'); + }); + + it('can show lg syntax error ', () => { + cy.visitPage('Bot Responses'); + // left nav tree + cy.contains('TodoSample.Main'); + cy.contains('All'); + + cy.get('.toggleEditMode button').click(); + cy.get('textarea').type('test lg syntax error'); + + cy.visitPage('Notifications'); + + cy.get('[data-testid="notifications-table-view"]').within(() => { + cy.findByText('common.lg').should('exist'); + }); + }); +}); diff --git a/Composer/cypress/integration/Onboarding.spec.js b/Composer/cypress/integration/Onboarding.spec.js deleted file mode 100644 index 595cb0be40..0000000000 --- a/Composer/cypress/integration/Onboarding.spec.js +++ /dev/null @@ -1,51 +0,0 @@ -/// - -context('onboarding', () => { - beforeEach(() => { - cy.visit(`${Cypress.env('COMPOSER_URL')}/home`, { enableOnboarding: true }); - cy.wait(1000); - cy.get('[data-testid="homePage-ToolBar-New"]').within(() => { - cy.getByText('New').click(); - }); - cy.wait(5000); - - cy.get('input[data-testid="Create from template"]').click({ force: true }); - cy.wait(100); - cy.get('[data-testid="TodoSample"]').click(); - cy.wait(100); - cy.get('button[data-testid="NextStepButton"]').click(); - cy.wait(100); - cy.get('input[data-testid="NewDialogName"]').type('__TestOnboarding'); - cy.get('input[data-testid="NewDialogName"]').type('{enter}'); - cy.wait(2000); - - //enable onboarding setting - cy.visitPage("Settings"); - cy.wait(2000); - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.get('[title="Onboarding"]').click(); - }); - cy.get('button[data-testid="onboardingToggle"]').click(); - cy.visitPage("Design Flow"); - }); - - it('walk through product tour teaching bubbles', () => { - cy.getByTestId('onboardingNextSet', { force: true }).click(); - cy.getByTestId('onboardingNext', { force: true }).click(); - cy.getByTestId('onboardingNext', { force: true }).click(); - cy.getByTestId('onboardingNext', { force: true }).click(); - cy.getByTestId('onboardingNext', { force: true }).click(); - cy.getByTestId('onboardingNext', { force: true }).click(); - - cy.getByTestId('onboardingNextSet', { force: true }).click(); - cy.getByTestId('onboardingNext', { force: true }).click(); - - cy.getByTestId('onboardingNextSet', { force: true }).click(); - cy.getByTestId('onboardingNext', { force: true }).click(); - - cy.getByTestId('onboardingNextSet', { force: true }).click(); - cy.getByTestId('onboardingNext', { force: true }).click(); - - cy.getByTestId('onboardingDone', { force: true }).click(); - }); -}); diff --git a/Composer/cypress/integration/Onboarding.spec.ts b/Composer/cypress/integration/Onboarding.spec.ts new file mode 100644 index 0000000000..e6f714fb16 --- /dev/null +++ b/Composer/cypress/integration/Onboarding.spec.ts @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('Onboarding', () => { + beforeEach(() => { + window.localStorage.setItem('composer:OnboardingState', JSON.stringify({ complete: false })); + + cy.visit(`${Cypress.env('COMPOSER_URL')}/home`); + cy.findByTestId('homePage-ToolBar-New').within(() => { + cy.findByText('New').click(); + }); + + cy.findByTestId('Create from template').click({ force: true }); + cy.findByTestId('TodoSample').click(); + cy.findByTestId('NextStepButton').click(); + cy.findByTestId('NewDialogName').type('{selectall}__TestOnboarding{enter}'); + + //enable onboarding setting + cy.visitPage('Settings'); + cy.findByText('Onboarding').click(); + cy.findByTestId('onboardingToggle').click(); + cy.visitPage('Design Flow'); + }); + + it('walk through product tour teaching bubbles', () => { + cy.findByTestId('onboardingNextSet').click(); + cy.findByTestId('onboardingNext').click(); + cy.findByTestId('onboardingNext').click(); + cy.findByTestId('onboardingNext').click(); + cy.findByTestId('onboardingNext').click(); + cy.findByTestId('onboardingNext').click(); + + cy.findByTestId('onboardingNextSet').click(); + cy.findByTestId('onboardingNext').click(); + + cy.findByTestId('onboardingNextSet').click(); + cy.findByTestId('onboardingNext').click(); + + cy.findByTestId('onboardingNextSet').click(); + cy.findByTestId('onboardingNext').click(); + + cy.findByTestId('onboardingDone').click(); + }); +}); diff --git a/Composer/cypress/integration/RemoveDialog.spec.js b/Composer/cypress/integration/RemoveDialog.spec.ts similarity index 52% rename from Composer/cypress/integration/RemoveDialog.spec.js rename to Composer/cypress/integration/RemoveDialog.spec.ts index 16f8faa26a..cbe924757e 100644 --- a/Composer/cypress/integration/RemoveDialog.spec.js +++ b/Composer/cypress/integration/RemoveDialog.spec.ts @@ -1,26 +1,27 @@ -/// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. context('RemoveDialog', () => { beforeEach(() => { cy.visit(Cypress.env('COMPOSER_URL')); - cy.copyBot('ToDoBotWithLuisSample', 'ToDoBotWithLuisSampleSpec'); + cy.createBot('ToDoBotWithLuisSample'); }); it('can remove dialog', () => { - cy.getByTestId('ProjectTree').within(() => { - cy.getByTestId('DialogTreeItemtriggers[4]').within(() => { - cy.getByTestId('dialogMoreButton') + cy.findByTestId('ProjectTree').within(() => { + cy.findByTestId('DialogTreeItemtriggers[4]').within(() => { + cy.findByTestId('dialogMoreButton') .first() .invoke('attr', 'style', 'visibility: visible') .click(); - }); }); + }); cy.get('.ms-ContextualMenu-linkContent > .ms-ContextualMenu-itemText').within(() => { - cy.getByText('Delete').click(); + cy.findByText('Delete').click(); }); - cy.getByTestId('ProjectTree').within(() => { + cy.findByTestId('ProjectTree').within(() => { cy.get('[title="AddItem"]').should('not.exist'); }); }); diff --git a/Composer/cypress/integration/SaveAs.spec.js b/Composer/cypress/integration/SaveAs.spec.js deleted file mode 100644 index bd71d8a748..0000000000 --- a/Composer/cypress/integration/SaveAs.spec.js +++ /dev/null @@ -1,22 +0,0 @@ -/// - -context('Saving As', () => { - beforeEach(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - }); - - it('can create a new bot from an existing bot', () => { - cy.createBot('ToDoBotWithLuisSample'); - cy.get('[data-testid="LeftNav-CommandBarButtonHome"]').click(); - cy.getByText('Save as').click(); - - cy.get('input[data-testid="NewDialogName"]').type('__TestSaveAs'); - cy.get('input[data-testid="NewDialogName"]').type('{enter}'); - cy.wait(1000); - - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('__TestSaveAs.Main').should('exist'); - cy.getByText('ViewCollection').should('exist'); - }); - }); -}); diff --git a/Composer/cypress/integration/SaveAs.spec.ts b/Composer/cypress/integration/SaveAs.spec.ts new file mode 100644 index 0000000000..300776f0db --- /dev/null +++ b/Composer/cypress/integration/SaveAs.spec.ts @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('Saving As', () => { + beforeEach(() => { + cy.visit(Cypress.env('COMPOSER_URL')); + cy.createBot('ToDoBotWithLuisSample'); + }); + + it('can create a new bot from an existing bot', () => { + cy.findByTestId('LeftNav-CommandBarButtonHome').click(); + cy.findByText('Save as').click(); + + cy.findByTestId('NewDialogName').type('{selectall}__TestSaveAs{enter}'); + + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('__TestSaveAs.Main').should('exist'); + cy.findByText('ViewCollection').should('exist'); + }); + }); +}); diff --git a/Composer/cypress/integration/SwitchCondition.spec.js b/Composer/cypress/integration/SwitchCondition.spec.js deleted file mode 100644 index 8a98afc186..0000000000 --- a/Composer/cypress/integration/SwitchCondition.spec.js +++ /dev/null @@ -1,164 +0,0 @@ -/// - -// this test is too unstable right now -// re-enable when stablized -context.skip('SwitchCondition', () => { - beforeEach(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - cy.startFromTemplate('EmptyBot', 'SwitchConditionSpec'); - }); - - //will remove skip after add trigger is ok - it('can manage cases', () => { - cy.addEventHandler('Handle Unknown Intent'); - - cy.withinEditor('VisualEditor', () => { - cy.getByText(/OnUnknownIntent/).click({ force: true }); - cy.wait(100); - cy.getByText(/UnknownIntent/).click({ force: true }); - cy.wait(100); - cy.getByTestId('StepGroupAdd').click({ force: true }); - cy.getByText('Flow').click({ force: true }); - cy.getByText('Branch: Switch').click({ force: true }); - cy.getByTestId('SwitchConditionDiamond').click({ force: true }); - }); - - // Add case and add/delete/edit steps - cy.withinEditor('FormEditor', () => { - // Edit condition - cy.getByLabelText('Condition').type('user.age >= 21'); - - // Add new case - cy.getByText('Add New Case').click({ force: true }); - cy.getByLabelText('Value') - .type('Case1') - .type('{enter}'); - - // Add some steps - - // Send activity - // Use { force: true } can disable error checking like dom not visible or width and height '0 * 0' pixels. - // So if a button is in a popup window, using { force: true } to button click can make the tests more stable. - cy.getByText('Add New Action for Case1').click({ force: true }); - cy.getByText('Send Messages').click({ force: true }); - cy.getByText('Send an Activity').click({ force: true }); - cy.wait(300); - }); - cy.withinEditor('VisualEditor', () => { - cy.getByText('Branch: Switch').click({ force: true }); - }); - cy.withinEditor('FormEditor', () => { - // Edit array - cy.getByText('Add New Action for Case1').click({ force: true }); - cy.getByText('Memory manipulation').click({ force: true }); - cy.getByText('Edit an Array Property').click({ force: true }); - cy.wait(300); - }); - cy.withinEditor('VisualEditor', () => { - cy.getByText('Branch: Switch').click({ force: true }); - }); - cy.withinEditor('FormEditor', () => { - // Log step - cy.getByText('Add New Action for Case1').click({ force: true }); - cy.getByText('Debugging').click({ force: true }); - cy.getByText('Log to console').click({ force: true }); - cy.wait(300); - }); - cy.withinEditor('VisualEditor', () => { - cy.getByText('Branch: Switch').click({ force: true }); - }); - cy.withinEditor('FormEditor', () => { - cy.get('[data-automationid="DetailsRow"]') - .as('steps') - .should('have.length', 3); - - // re-order steps - const btn0 = cy - .get('@steps') - .eq(0) - .find('button') - .click({ force: true }); - btn0.invoke('attr', 'aria-owns').then(menuId => { - cy.get(`#${menuId}`) - .getByText('Move Down') - .click({ force: true }); - cy.wait(100); - }); - - const btn2 = cy - .get('@steps') - .eq(2) - .find('button') - .click({ force: true }); - btn2.invoke('attr', 'aria-owns').then(menuId => { - cy.get(`#${menuId}`) - .getByText('Move Up') - .click({ force: true }); - cy.wait(100); - }); - - // assert that the steps are in correct order - cy.get('@steps') - .get('[data-automationid="DetailsRowCell"][data-automation-key="name"]') - .eq(0) - .should('contain.text', 'Edit an Array Property'); - cy.get('@steps') - .get('[data-automationid="DetailsRowCell"][data-automation-key="name"]') - .eq(1) - .should('contain.text', 'Log to console'); - cy.get('@steps') - .get('[data-automationid="DetailsRowCell"][data-automation-key="name"]') - .eq(2) - .should('contain.text', 'Send an Activity'); - - // Add another new case - cy.getByText('Add New Case').click({ force: true }); - cy.wait(100); - cy.getByLabelText('Value') - .type('Case2') - .type('{enter}'); - - cy.wait(100); - - // move first case - let btn = cy - .get('.CasesFieldConditionsMenu') - .first() - .find('button'); - btn.click({ force: true }); - btn.invoke('attr', 'aria-owns').then(menuId => { - cy.get(`#${menuId}`) - .getByText('Move Down') - .click({ force: true }); - cy.wait(100); - }); - - cy.get('[role="separator"]') - .filter(':not(:contains(Branch: Switch))') - .should('have.length', 3) - .eq(1) - .should('have.text', 'Branch: Case1'); - - cy.wait(100); - - // remove case1 - btn = cy - .get('.CasesFieldConditionsMenu') - .first() - .find('button'); - btn.click({ force: true }); - btn.invoke('attr', 'aria-owns').then(menuId => { - cy.get(`#${menuId}`) - .getByText('Remove') - .click({ force: true }); - cy.wait(100); - }); - - cy.get('[role="separator"]') - .filter(':not(:contains(Branch: Switch))') - .should('have.length', 2) - .eq(1) - .should('have.text', 'Default'); - }); - }); -}); diff --git a/Composer/cypress/integration/ToDoBot.spec.js b/Composer/cypress/integration/ToDoBot.spec.js deleted file mode 100644 index 13d349d89d..0000000000 --- a/Composer/cypress/integration/ToDoBot.spec.js +++ /dev/null @@ -1,62 +0,0 @@ -/// - -context('ToDo Bot', () => { - beforeEach(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - cy.createBot('TodoSample'); - }); - - it('can open the main dialog', () => { - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('__TestTodoSample.Main').click(); - cy.wait(100); - }); - cy.withinEditor('FormEditor', () => { - cy.getByDisplayValue('__TestTodoSample').should('exist'); - }); - }); - - it('can open the AddToDo dialog', () => { - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('AddToDo').click(); - cy.wait(100); - }); - - cy.withinEditor('FormEditor', () => { - cy.getByDisplayValue('AddToDo').should('exist'); - }); - }); - - it('can open the ClearToDos dialog', () => { - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('ClearToDos').click(); - cy.wait(100); - }); - - cy.withinEditor('FormEditor', () => { - cy.getByDisplayValue('ClearToDos').should('exist'); - }); - }); - - it('can open the DeleteToDo dialog', () => { - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('DeleteToDo').click(); - cy.wait(100); - }); - - cy.withinEditor('FormEditor', () => { - cy.getByDisplayValue('DeleteToDo').should('exist'); - }); - }); - - it('can open the ShowToDos dialog', () => { - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('ShowToDos').click(); - cy.wait(100); - }); - - cy.withinEditor('FormEditor', () => { - cy.getByDisplayValue('ShowToDos').should('exist'); - }); - }); -}); diff --git a/Composer/cypress/integration/ToDoBot.spec.ts b/Composer/cypress/integration/ToDoBot.spec.ts new file mode 100644 index 0000000000..6af6943b15 --- /dev/null +++ b/Composer/cypress/integration/ToDoBot.spec.ts @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('ToDo Bot', () => { + beforeEach(() => { + cy.visit(Cypress.env('COMPOSER_URL')); + cy.createBot('TodoSample'); + }); + + it('can open the main dialog', () => { + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('__TestTodoSample.Main').click(); + }); + cy.withinEditor('FormEditor', () => { + cy.findByDisplayValue('__TestTodoSample').should('exist'); + }); + }); + + it('can open the AddToDo dialog', () => { + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('AddToDo').click(); + }); + + cy.withinEditor('FormEditor', () => { + cy.findByDisplayValue('AddToDo').should('exist'); + }); + }); + + it('can open the ClearToDos dialog', () => { + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('ClearToDos').click(); + }); + + cy.withinEditor('FormEditor', () => { + cy.findByDisplayValue('ClearToDos').should('exist'); + }); + }); + + it('can open the DeleteToDo dialog', () => { + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('DeleteToDo').click(); + }); + + cy.withinEditor('FormEditor', () => { + cy.findByDisplayValue('DeleteToDo').should('exist'); + }); + }); + + it('can open the ShowToDos dialog', () => { + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('ShowToDos').click(); + }); + + cy.withinEditor('FormEditor', () => { + cy.findByDisplayValue('ShowToDos').should('exist'); + }); + }); +}); diff --git a/Composer/cypress/integration/VisualDesigner.spec.js b/Composer/cypress/integration/VisualDesigner.spec.js deleted file mode 100644 index 06f2e5a759..0000000000 --- a/Composer/cypress/integration/VisualDesigner.spec.js +++ /dev/null @@ -1,28 +0,0 @@ -/// - -context('Visual Designer', () => { - before(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - cy.createBot('TodoSample'); - cy.wait(100); - }); - - beforeEach(() => { - // Return to Main.dialog - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('__TestTodoSample.Main').click(); - cy.wait(100); - }); - }); - - it('can find Visual Designer default trigger in container', () => { - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText('Greeting (ConversationUpdate)').click(); - cy.wait(500); - }); - - cy.withinEditor('VisualEditor', () => { - cy.getByText('Trigger').should('exist'); - }); - }); -}); diff --git a/Composer/cypress/integration/VisualDesigner.spec.ts b/Composer/cypress/integration/VisualDesigner.spec.ts new file mode 100644 index 0000000000..7ecdabfaa2 --- /dev/null +++ b/Composer/cypress/integration/VisualDesigner.spec.ts @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +context('Visual Designer', () => { + before(() => { + cy.visit(Cypress.env('COMPOSER_URL')); + cy.createBot('TodoSample'); + }); + + beforeEach(() => { + // Return to Main.dialog + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('__TestTodoSample.Main').click(); + }); + }); + + it('can find Visual Designer default trigger in container', () => { + cy.findByTestId('ProjectTree').within(() => { + cy.findByText('Greeting (ConversationUpdate)').click(); + }); + + cy.withinEditor('VisualEditor', () => { + cy.findByText('Trigger').should('exist'); + }); + }); +}); diff --git a/Composer/cypress/integration/homePage.spec.js b/Composer/cypress/integration/homePage.spec.js deleted file mode 100644 index 15fddc136b..0000000000 --- a/Composer/cypress/integration/homePage.spec.js +++ /dev/null @@ -1,19 +0,0 @@ -/// -context('check Nav Expandion ', () => { - beforeEach(() => { - cy.visit(Cypress.env('COMPOSER_URL')); - }); - it('can open buttons in home page', () => { - cy.get('[data-testid="LeftNav-CommandBarButtonHome"]').click(); - cy.get('[data-testid="homePage-ToolBar-New"]').click(); - cy.getByText('Create from scratch?').should('exist'); - cy.getByText('Cancel').should('exist'); - cy.getByText('Cancel').click(); - cy.get('[data-testid="homePage-ToolBar-Open"]').click(); - cy.getByText('Select a Bot').should('exist'); - cy.getByText('Cancel').should('exist'); - cy.getByText('Cancel').click(); - cy.get('[data-testid="homePage-body-New"]').click(); - cy.getByText('Create from scratch?').should('exist'); - }); -}); diff --git a/Composer/cypress/plugins/cy-ts-preprocessor.js b/Composer/cypress/plugins/cy-ts-preprocessor.js new file mode 100644 index 0000000000..149b4a8052 --- /dev/null +++ b/Composer/cypress/plugins/cy-ts-preprocessor.js @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/* eslint-disable @typescript-eslint/no-var-requires */ + +const wp = require('@cypress/webpack-preprocessor'); + +const webpackOptions = { + resolve: { + extensions: ['.ts', '.js'], + }, + module: { + rules: [ + { + test: /\.ts$/, + exclude: [/node_modules/], + use: [ + { + loader: 'ts-loader', + }, + ], + }, + ], + }, +}; + +const options = { + webpackOptions, +}; + +module.exports = wp(options); diff --git a/Composer/cypress/plugins/index.js b/Composer/cypress/plugins/index.js index fd170fba69..e107f2de30 100644 --- a/Composer/cypress/plugins/index.js +++ b/Composer/cypress/plugins/index.js @@ -1,17 +1,10 @@ -// *********************************************************** -// This example plugins/index.js can be used to load plugins -// -// You can change the location of this file or turn off loading -// the plugins file with the 'pluginsFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/plugins-guide -// *********************************************************** +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. -// This function is called when a project is opened or re-opened (e.g. due to -// the project's config changing) +/* eslint-disable @typescript-eslint/no-var-requires */ -module.exports = (on, config) => { - // `on` is used to hook into various events Cypress emits - // `config` is the resolved Cypress config -} +const cypressTypeScriptPreprocessor = require('./cy-ts-preprocessor'); + +module.exports = on => { + on('file:preprocessor', cypressTypeScriptPreprocessor); +}; diff --git a/Composer/cypress/support/commands.d.ts b/Composer/cypress/support/commands.d.ts new file mode 100644 index 0000000000..d9e9e141b4 --- /dev/null +++ b/Composer/cypress/support/commands.d.ts @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/// + +declare namespace Cypress { + interface Chainable { + /** + * Creates a bot based on template id. + * If botName not provided, names the bot __Test${botId}, + * otherwise, __Test&{botName}. + * @example cy.createBot('TodoSample', 'NewBotName') + */ + createBot(botId: string, botName?: string): void; + + /** + * Visits a page from the left nav bar using the page's testid + * @example visitPage('Bot Responses'); + */ + visitPage(page: string): void; + + /** + * Invokes callback inside editor context + * @example cy.withinEditor('VisualEditor', () => { + * cy.findByText('SomeText'); + * }); + */ + withinEditor(editor: string, cb: (currentSubject: JQuery) => void): void; + } +} diff --git a/Composer/cypress/support/commands.js b/Composer/cypress/support/commands.js deleted file mode 100644 index a82d72318c..0000000000 --- a/Composer/cypress/support/commands.js +++ /dev/null @@ -1,107 +0,0 @@ -// *********************************************** This example commands.js -// shows you how to create various custom commands and overwrite existing -// commands. -// -// For more comprehensive examples of custom commands please read more here: -// https://on.cypress.io/custom-commands -// *********************************************** -// -// -// -- This is a parent command -- Cypress.Commands.add("login", (email, -// password) => { ... }) -// -// -// -- This is a child command -- Cypress.Commands.add("drag", { prevSubject: -// 'element'}, (subject, options) => { ... }) -// -// -// -- This is a dual command -- Cypress.Commands.add("dismiss", { prevSubject: -// 'optional'}, (subject, options) => { ... }) -// -// - -Cypress.Commands.overwrite("visit", (originalFn, url, { enableOnboarding } = {}) => { - if (!enableOnboarding) { - cy.window().then(window => window.localStorage.setItem('composer:OnboardingState', JSON.stringify({ complete: true }))); - } - originalFn(url); - }); - -import 'cypress-testing-library/add-commands'; - -Cypress.Commands.add('createBot', botName => { - cy.get('[data-testid="LeftNav-CommandBarButtonHome"]').click(); - cy.wait(500); - cy.get('[data-testid="homePage-ToolBar-New"]').within(() => { - cy.getByText('New').click(); - }); - cy.wait(500); - cy.get('input[data-testid="Create from template"]').click({ force: true }); - cy.wait(100); - cy.get(`[data-testid=${botName}]`).click(); - cy.wait(100); - cy.get('button[data-testid="NextStepButton"]').click(); - cy.wait(100); - cy.get('input[data-testid="NewDialogName"]').type(`__Test${botName}`); - cy.get('input[data-testid="NewDialogName"]').type('{enter}'); -}); - -Cypress.Commands.add('openBot', botName => { - cy.get('[data-testid="LeftNav-CommandBarButtonHome"]').click(); - cy.get('[data-testid="homePage-ToolBar-Open"]').within(() => { - cy.getByText('Open').click(); - }); - cy.get('[data-testid="SelectLocation"]').within(() => { - cy.get(`[aria-label="${botName}"]`).click({ force: true }); - cy.wait(500); - }); - cy.wait(500); -}); - -Cypress.Commands.add('withinEditor', (editorName, cb) => { - cy.get(`iframe[name="${editorName}"]`).then(editor => { - cy.wrap(editor.contents().find('body')).within(cb); - }); -}); - -Cypress.Commands.add('openDialog', dialogName => { - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText(dialogName).click(); - cy.wait(500); - }); -}); - -Cypress.Commands.add('startFromTemplate', (template, name) => { - cy.get('[data-testid="LeftNav-CommandBarButtonHome"]').click(); - cy.getByTestId(`TemplateCopy-${template}`).click(); - cy.get('input[data-testid="NewDialogName"]').type(`__Test${name}`); - cy.get('input[data-testid="NewDialogName"]').type('{enter}'); - cy.wait(1000); -}); - -Cypress.Commands.add('copyBot', (bot, name) => { - cy.createBot(bot); - cy.get('[data-testid="LeftNav-CommandBarButtonHome"]').click(); - cy.getByText('Save as').click(); - - cy.get('input[data-testid="NewDialogName"]').type(`__Test${name}`); - cy.get('input[data-testid="NewDialogName"]').type('{enter}'); - cy.wait(1000); -}); - -Cypress.Commands.add('addEventHandler', handler => { - cy.get('[data-testid="ProjectTree"]').within(() => { - cy.getByText(/New Trigger ../).click(); - }); - cy.get(`[data-testid="triggerTypeDropDown"]`).click(); - cy.getByText(handler).click(); - if (handler === 'Dialog trigger') { - cy.get(`[data-testid="eventTypeDropDown"]`).click(); - cy.getByText('consultDialog').click(); - } - cy.get(`[data-testid="triggerFormSubmit"]`).click(); -}); - -Cypress.Commands.add('visitPage', (page) => { - cy.get(`[data-testid="LeftNav-CommandBarButton${page}"]`).click(); -}); diff --git a/Composer/cypress/support/commands.ts b/Composer/cypress/support/commands.ts new file mode 100644 index 0000000000..de5939e41f --- /dev/null +++ b/Composer/cypress/support/commands.ts @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import '@testing-library/cypress/add-commands'; + +Cypress.Commands.add('createBot', (bobotId: string, botName?: string) => { + cy.findByTestId('LeftNav-CommandBarButtonHome').click(); + cy.findByTestId('homePage-ToolBar-New').within(() => { + cy.findByText('New').click(); + }); + cy.findByTestId('Create from template').click({ force: true }); + cy.findByTestId(`${bobotId}`).click(); + cy.findByTestId('NextStepButton').click(); + cy.findByTestId('NewDialogName').type(`{selectall}__Test${botName || bobotId}{enter}`); + cy.wait(1000); +}); + +Cypress.Commands.add('withinEditor', (editorName, cb) => { + cy.get(`iframe[name="${editorName}"]`).then(editor => { + cy.wrap(editor.contents().find('body') as JQuery).within(cb); + }); +}); + +Cypress.Commands.add('visitPage', page => { + cy.findByTestId(`LeftNav-CommandBarButton${page}`).click(); +}); diff --git a/Composer/cypress/support/index.js b/Composer/cypress/support/index.js deleted file mode 100644 index 5c76e07023..0000000000 --- a/Composer/cypress/support/index.js +++ /dev/null @@ -1,29 +0,0 @@ -// *********************************************************** -// This example support/index.js is processed and -// loaded automatically before your test files. -// -// This is a great place to put global configuration and -// behavior that modifies Cypress. -// -// You can change the location of this file or turn off -// automatically serving support files with the -// 'supportFile' configuration option. -// -// You can read more here: -// https://on.cypress.io/configuration -// *********************************************************** - -// Import commands.js using ES2015 syntax: -import './commands'; - -// Alternatively you can use CommonJS syntax: -// require('./commands') - -beforeEach(() => { - cy.exec('yarn test:integration:clean'); -}); - -after(() => { - cy.wait(500); - cy.exec('yarn test:integration:clean'); -}); diff --git a/Composer/cypress/support/index.ts b/Composer/cypress/support/index.ts new file mode 100644 index 0000000000..0bbb874401 --- /dev/null +++ b/Composer/cypress/support/index.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import './commands'; + +beforeEach(() => { + cy.exec('yarn test:integration:clean'); + window.localStorage.setItem('composer:OnboardingState', JSON.stringify({ complete: true })); +}); + +after(() => { + cy.wait(500); + cy.exec('yarn test:integration:clean'); +}); diff --git a/Composer/cypress/tsconfig.json b/Composer/cypress/tsconfig.json new file mode 100644 index 0000000000..6a00ad6e70 --- /dev/null +++ b/Composer/cypress/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "strict": true, + "baseUrl": "../node_modules", + "target": "es5", + "lib": ["es5", "dom"], + "types": ["cypress", "@types/testing-library__cypress", "./support/commands"] + }, + "include": ["**/*.ts"] +} diff --git a/Composer/package.json b/Composer/package.json index 4901453bb5..d269fc9fbe 100644 --- a/Composer/package.json +++ b/Composer/package.json @@ -59,7 +59,9 @@ "@babel/preset-react": "^7.0.0", "@babel/preset-typescript": "^7.3.3", "@bfc/eslint-plugin-bfcomposer": "*", + "@cypress/webpack-preprocessor": "^4.1.1", "@emotion/babel-preset-css-prop": "^10.0.17", + "@testing-library/cypress": "^5.0.2", "@typescript-eslint/eslint-plugin": "2.6.0", "@typescript-eslint/parser": "2.6.0", "babel-jest": "24.0.0", @@ -67,9 +69,9 @@ "coveralls": "^3.0.7", "cypress": "^3.6.1", "cypress-plugin-tab": "^1.0.1", - "cypress-testing-library": "^3.0.1", "eslint": "^5.15.1", "eslint-config-prettier": "^4.1.0", + "eslint-plugin-cypress": "^2.7.0", "eslint-plugin-emotion": "^10.0.14", "eslint-plugin-format-message": "^6.2.3", "eslint-plugin-import": "^2.16.0", @@ -92,6 +94,7 @@ "prettier": "^1.15.3", "react-testing-library": "^6.0.2", "rimraf": "^2.6.3", + "ts-loader": "^6.2.1", "typescript": "3.6.4", "wsrun": "^3.6.4" }, diff --git a/Composer/packages/client/src/ShellApi.ts b/Composer/packages/client/src/ShellApi.ts index fcdfc80b54..391946b4ad 100644 --- a/Composer/packages/client/src/ShellApi.ts +++ b/Composer/packages/client/src/ShellApi.ts @@ -13,7 +13,7 @@ import ApiClient from './messenger/ApiClient'; import { getDialogData, setDialogData, sanitizeDialogData } from './utils'; import { isAbsHosted } from './utils/envUtil'; import { OpenAlertModal, DialogStyle } from './components/Modal'; -import { getFocusPath, navigateTo } from './utils/navigation'; +import { getFocusPath } from './utils/navigation'; // this is the api interface provided by shell to extensions this is the single // place handles all incoming request from extensions, VisualDesigner or @@ -42,16 +42,6 @@ const FileTargetTypes = { LG: 'lg', }; -const shellNavigator = (shellPage: string, opts: { id?: string } = {}) => { - switch (shellPage) { - case 'lu': - navigateTo(`/language-understanding/${opts.id}`); - return; - default: - return; - } -}; - export const ShellApi: React.FC = () => { const { state, actions } = useContext(StoreContext); @@ -332,7 +322,6 @@ export const ShellApi: React.FC = () => { apiClient.registerApi('onFocusSteps', focusSteps); apiClient.registerApi('onSelect', onSelect); apiClient.registerApi('onCopy', onCopy); - apiClient.registerApi('shellNavigate', ({ shellPage, opts }) => shellNavigator(shellPage, opts)); apiClient.registerApi('isExpression', ({ expression }) => isExpression(expression)); apiClient.registerApi('createDialog', () => { return new Promise(resolve => { diff --git a/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx b/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx index e052d54eba..6a6988b3cc 100644 --- a/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx +++ b/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx @@ -31,10 +31,6 @@ import { StoreContext } from '../../store'; import { styles, dropdownStyles, dialogWindow } from './styles'; -const isValidName = name => { - const nameRegex = /^[a-zA-Z0-9-_.]+$/; - return nameRegex.test(name); -}; const validateForm = (data: TriggerFormData): TriggerFormDataErrors => { const errors: TriggerFormDataErrors = {}; const { $type, specifiedType } = data; diff --git a/Composer/packages/client/src/extension-container/EditorMap.ts b/Composer/packages/client/src/extension-container/EditorMap.ts index 819c5fa2e0..325ff50a72 100644 --- a/Composer/packages/client/src/extension-container/EditorMap.ts +++ b/Composer/packages/client/src/extension-container/EditorMap.ts @@ -5,7 +5,7 @@ import FormEditor from '@bfc/extensions/obiformeditor'; import VisualDesigner from '@bfc/extensions/visual-designer'; -const getEditor = (): VisualDesigner | typeof FormEditor | null => { +const getEditor = (): typeof VisualDesigner | typeof FormEditor | null => { // i'm now more towarding pick editor based on name, not data // because we want shell to totally control file read/save // which means each editor cann't be differiante by data diff --git a/Composer/packages/client/src/extension-container/ExtensionContainer.tsx b/Composer/packages/client/src/extension-container/ExtensionContainer.tsx index 7ac8814c49..8603f6b565 100644 --- a/Composer/packages/client/src/extension-container/ExtensionContainer.tsx +++ b/Composer/packages/client/src/extension-container/ExtensionContainer.tsx @@ -3,7 +3,7 @@ import React, { useState, useEffect } from 'react'; import { initializeIcons } from '@uifabric/icons'; -import { LuFile, ShellData } from '@bfc/shared'; +import { ShellData, ShellApi } from '@bfc/shared'; import ApiClient from '../messenger/ApiClient'; @@ -29,8 +29,8 @@ const apiClient = new ApiClient(); const subEditorCallbacks = {}; -const shellApi = { - getState: (): Promise => { +const shellApi: ShellApi = { + getState: () => { return apiClient.apiCall('getState', {}); }, @@ -38,71 +38,59 @@ const shellApi = { return apiClient.apiCall('saveData', { newData, updatePath }); }, - navTo: (path: string, rest) => { + navTo: (path, rest) => { return apiClient.apiCall('navTo', { path, rest }); }, - navDown: (subPath: string) => { - return apiClient.apiCall('navDown', { subPath: subPath }); - }, - - focusTo: (subPath: string) => { - return apiClient.apiCall('focusTo', { subPath: subPath }); - }, - - onFocusEvent: (subPath: string) => { + onFocusEvent: subPath => { return apiClient.apiCall('onFocusEvent', { subPath }); }, - onFocusSteps: (subPaths: string[], fragment?: string) => { + onFocusSteps: (subPaths, fragment) => { return apiClient.apiCall('onFocusSteps', { subPaths, fragment }); }, - onSelect: (ids: string[]) => { + onSelect: ids => { return apiClient.apiCall('onSelect', ids); }, - onCopy: (actions: any[]) => { + onCopy: actions => { return apiClient.apiCall('onCopy', actions); }, - shellNavigate: (shellPage, opts = {}) => { - return apiClient.apiCall('shellNavigate', { shellPage, opts }); - }, - - createLuFile: (id: string) => { + createLuFile: id => { return apiClient.apiCall('createLuFile', { id }); }, - updateLuFile: (luFile: LuFile) => { + updateLuFile: luFile => { return apiClient.apiCall('updateLuFile', luFile); }, - updateLgFile: (id: string, content: string) => { + updateLgFile: (id, content) => { return apiClient.apiCall('updateLgFile', { id, content }); }, - getLgTemplates: (id: string) => { + getLgTemplates: id => { return apiClient.apiCall('getLgTemplates', { id }); }, - createLgTemplate: (id: string, template: string, position?: number) => { + createLgTemplate: (id, template, position) => { return apiClient.apiCall('createLgTemplate', { id, template, position }); }, - removeLgTemplate: (id: string, templateName: string) => { + removeLgTemplate: (id, templateName) => { return apiClient.apiCall('removeLgTemplate', { id, templateName }); }, - removeLgTemplates: (id: string, templateNames: string[]) => { + removeLgTemplates: (id, templateNames) => { return apiClient.apiCall('removeLgTemplates', { id, templateNames }); }, - copyLgTemplate: (id: string, fromTemplateName: string, toTemplateName: string) => { + copyLgTemplate: (id, fromTemplateName, toTemplateName) => { return apiClient.apiCall('copyLgTemplate', { id, fromTemplateName, toTemplateName }); }, - updateLgTemplate: (id: string, templateName: string, template: string) => { + updateLgTemplate: (id, templateName, template) => { return apiClient.apiCall('updateLgTemplate', { id, templateName, @@ -114,7 +102,7 @@ const shellApi = { return apiClient.apiCall('createDialog'); }, - validateExpression: (expression: string) => { + validateExpression: expression => { return apiClient.apiCall('isExpression', { expression }); }, @@ -126,7 +114,7 @@ const shellApi = { return apiClient.apiCall('redo'); }, - addCoachMarkRef: (target: any) => { + addCoachMarkRef: target => { return apiClient.apiCall('addCoachMarkPosition', target); }, }; diff --git a/Composer/packages/client/src/pages/language-generation/code-editor.tsx b/Composer/packages/client/src/pages/language-generation/code-editor.tsx index 075e01b43d..247e26a2a7 100644 --- a/Composer/packages/client/src/pages/language-generation/code-editor.tsx +++ b/Composer/packages/client/src/pages/language-generation/code-editor.tsx @@ -7,17 +7,17 @@ import { LgEditor } from '@bfc/code-editor'; import get from 'lodash/get'; import debounce from 'lodash/debounce'; import isEmpty from 'lodash/isEmpty'; -import { CodeRange } from '@bfc/shared'; +import { CodeRange, LgFile } from '@bfc/shared'; import * as lgUtil from '../../utils/lgUtil'; interface CodeEditorProps { - file: object; + file: LgFile; onChange: (value: string) => void; - codeRange: Partial; + codeRange?: Partial | null; } -export default function CodeEditor(props) { +export default function CodeEditor(props: CodeEditorProps) { const { file, codeRange } = props; const onChange = debounce(props.onChange, 500); const [diagnostics, setDiagnostics] = useState(get(file, 'diagnostics', [])); @@ -53,7 +53,7 @@ export default function CodeEditor(props) { lineDecorationsWidth: undefined, lineNumbersMinChars: false, }} - codeRange={codeRange} + codeRange={codeRange || -1} errorMsg={errorMsg} value={content} onChange={_onChange} diff --git a/Composer/packages/client/src/store/action/setting.ts b/Composer/packages/client/src/store/action/setting.ts index e4d17f681e..8dd79ac515 100644 --- a/Composer/packages/client/src/store/action/setting.ts +++ b/Composer/packages/client/src/store/action/setting.ts @@ -50,7 +50,7 @@ export const setDialogSettingsSlot = async ({ dispatch }, editing: boolean, slot const url = `/projects/opened/settings${suffix}${query}`; try { - const response = await httpClient.get(`/projects/opened/settings${suffix}`); + const response = await httpClient.get(url); const settings = response.data; dispatch({ type: ActionTypes.GET_ENV_SETTING, diff --git a/Composer/packages/client/src/store/middlewares/undo/history.ts b/Composer/packages/client/src/store/middlewares/undo/history.ts index e2024dc17a..2f698078f9 100644 --- a/Composer/packages/client/src/store/middlewares/undo/history.ts +++ b/Composer/packages/client/src/store/middlewares/undo/history.ts @@ -16,7 +16,6 @@ class UndoHistory { private stacks: { [key: string]: UndoStack } = {}; private history: History[] = []; private pointer = -1; - private _limit = 5; public createStack(undo: ActionCreator, redo: ActionCreator) { const stack = new UndoStack(undo, redo); @@ -64,10 +63,6 @@ class UndoHistory { }); } - public set limit(limit: number) { - this._limit = limit; - } - canUndo = () => this.pointer > -1; canRedo = () => this.pointer < this.history.length - 1; } diff --git a/Composer/packages/client/tsconfig.json b/Composer/packages/client/tsconfig.json index 46407dba78..42032f429e 100644 --- a/Composer/packages/client/tsconfig.json +++ b/Composer/packages/client/tsconfig.json @@ -1,18 +1,9 @@ { + "extends": "../../tsconfig.base.json", "compilerOptions": { - "noImplicitAny": false, + "allowJs": true, + "declaration": false, "module": "esnext", - "target": "es5", - "jsx": "react", - "sourceMap": true, - "moduleResolution": "node", - "esModuleInterop": true, - "strict": true, - "resolveJsonModule": true, - "allowJs": true }, "include": ["./src/**/*", "./__tests__/**/*"], - "exclude": [ - "node_modules" - ], } diff --git a/Composer/packages/extensions/obiformeditor/demo/src/index.tsx b/Composer/packages/extensions/obiformeditor/demo/src/index.tsx index 0b5257ce8c..8dee3657fe 100644 --- a/Composer/packages/extensions/obiformeditor/demo/src/index.tsx +++ b/Composer/packages/extensions/obiformeditor/demo/src/index.tsx @@ -148,12 +148,8 @@ function getDefaultMemory() { const mockShellApi = [ 'getState', 'getData', - 'getDialogs', 'saveData', 'navTo', - 'navDown', - 'focusTo', - 'shellNavigate', 'updateLuFile', 'updateLgFile', 'createLuFile', diff --git a/Composer/packages/extensions/obiformeditor/package.json b/Composer/packages/extensions/obiformeditor/package.json index 83afabd09b..419e102656 100644 --- a/Composer/packages/extensions/obiformeditor/package.json +++ b/Composer/packages/extensions/obiformeditor/package.json @@ -18,7 +18,7 @@ "prepublishOnly": "npm run build", "start": "webpack-dev-server --config demo/webpack.config.demo.js", "test": "jest", - "lint": "eslint --quiet --ext .js,.jsx,.ts,.tsx ./src ./__tests__", + "lint": "eslint --quiet --ext .ts,.tsx ./src ./__tests__", "lint:fix": "yarn lint --fix", "lint:typecheck": "tsc --noEmit", "watch": "yarn build:ts --watch" diff --git a/Composer/packages/extensions/obiformeditor/src/Form/utils.ts b/Composer/packages/extensions/obiformeditor/src/Form/utils.ts index 0eb0d6677d..334fd2e522 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/utils.ts +++ b/Composer/packages/extensions/obiformeditor/src/Form/utils.ts @@ -114,7 +114,9 @@ export function insertAt(arr: T[], item: T, idx: number): T[] { return newArr; } -function getOptions(memory: FormMemory, scope: MemoryScope): IDropdownOption[] { +function getOptions(memory: FormMemory | undefined, scope: MemoryScope): IDropdownOption[] { + if (!memory || !memory[scope]) return []; + const options: IDropdownOption[] = []; for (const key in memory[scope]) { options.push({ key: `${scope}.${key}`, text: `${memory[scope][key]}` }); @@ -122,7 +124,7 @@ function getOptions(memory: FormMemory, scope: MemoryScope): IDropdownOption[] { return options; } -function buildScope(memory: FormMemory, scope: MemoryScope): IDropdownOption[] { +function buildScope(memory: FormMemory | undefined, scope: MemoryScope): IDropdownOption[] { if (!memory || !memory[scope]) return []; const options = getOptions(memory, scope); @@ -136,7 +138,7 @@ function buildScope(memory: FormMemory, scope: MemoryScope): IDropdownOption[] { ]; } -export function getMemoryOptions(memory: FormMemory): IDropdownOption[] { +export function getMemoryOptions(memory?: FormMemory): IDropdownOption[] { return [ ...buildScope(memory, MemoryScope.user), ...buildScope(memory, MemoryScope.conversation), diff --git a/Composer/packages/extensions/obiformeditor/src/FormEditor.tsx b/Composer/packages/extensions/obiformeditor/src/FormEditor.tsx index 789788cedb..30c1a2642b 100644 --- a/Composer/packages/extensions/obiformeditor/src/FormEditor.tsx +++ b/Composer/packages/extensions/obiformeditor/src/FormEditor.tsx @@ -19,7 +19,7 @@ const getType = (data: FormData): string | undefined => { }; export interface FormEditorProps extends ShellData { - memory: FormMemory; + memory?: FormMemory; onBlur?: () => void; onChange: (newData: object, updatePath?: string) => void; shellApi: ShellApi; diff --git a/Composer/packages/extensions/obiformeditor/tsconfig.json b/Composer/packages/extensions/obiformeditor/tsconfig.json index d6f621d54c..8eab2df086 100644 --- a/Composer/packages/extensions/obiformeditor/tsconfig.json +++ b/Composer/packages/extensions/obiformeditor/tsconfig.json @@ -1,20 +1,8 @@ { + "extends": "../../../tsconfig.base.json", "compilerOptions": { "outDir": "./lib/", - "noImplicitAny": false, "module": "esnext", - "target": "es5", - "jsx": "react", - "sourceMap": true, - "moduleResolution": "node", - "esModuleInterop": true, - "strict": true, - "resolveJsonModule": true, - "noUnusedLocals": true, - "allowJs": false }, - "include": ["./src/**/*", "./__tests__/**/*"], - "exclude": [ - "node_modules" - ], + "include": ["./src/**/*", "./__tests__/**/*"] } diff --git a/Composer/packages/extensions/visual-designer/.eslintignore b/Composer/packages/extensions/visual-designer/.eslintignore deleted file mode 100644 index c18ed016a7..0000000000 --- a/Composer/packages/extensions/visual-designer/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -lib/ \ No newline at end of file diff --git a/Composer/packages/extensions/visual-designer/.travis.yml b/Composer/packages/extensions/visual-designer/.travis.yml deleted file mode 100644 index 06e30d936d..0000000000 --- a/Composer/packages/extensions/visual-designer/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -sudo: false - -language: node_js -node_js: - - 8 - -before_install: - - npm install codecov.io coveralls - -after_success: - - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js - - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js - -branches: - only: - - master diff --git a/Composer/packages/extensions/visual-designer/__tests__/components/lib/EdgeComponents.test.tsx b/Composer/packages/extensions/visual-designer/__tests__/components/lib/EdgeComponents.test.tsx index 37981d1570..b17af1b688 100644 --- a/Composer/packages/extensions/visual-designer/__tests__/components/lib/EdgeComponents.test.tsx +++ b/Composer/packages/extensions/visual-designer/__tests__/components/lib/EdgeComponents.test.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + import React from 'react'; import { render } from 'react-testing-library'; diff --git a/Composer/packages/extensions/visual-designer/package.json b/Composer/packages/extensions/visual-designer/package.json index 157a576892..5fbdf33761 100644 --- a/Composer/packages/extensions/visual-designer/package.json +++ b/Composer/packages/extensions/visual-designer/package.json @@ -17,7 +17,7 @@ "prepublishOnly": "npm run build", "start": "webpack-dev-server --config demo/webpack.config.demo.js --port 3002", "test": "jest --no-cache", - "lint": "eslint --quiet --ext .js,.jsx,.ts,.tsx ./src ./__tests__", + "lint": "eslint --quiet --ext .ts,.tsx ./src ./__tests__", "lint:fix": "yarn lint --fix" }, "dependencies": { diff --git a/Composer/packages/extensions/visual-designer/src/components/lib/Collapse/CollapseStyles.ts b/Composer/packages/extensions/visual-designer/src/components/lib/Collapse/CollapseStyles.ts index 0ce784cd7f..6a1cfc1de0 100644 --- a/Composer/packages/extensions/visual-designer/src/components/lib/Collapse/CollapseStyles.ts +++ b/Composer/packages/extensions/visual-designer/src/components/lib/Collapse/CollapseStyles.ts @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + import { css } from '@emotion/core'; export const collapseContainer = css` diff --git a/Composer/packages/extensions/visual-designer/src/components/lib/Collapse/index.tsx b/Composer/packages/extensions/visual-designer/src/components/lib/Collapse/index.tsx index bdf5ff0d86..e15f07be03 100644 --- a/Composer/packages/extensions/visual-designer/src/components/lib/Collapse/index.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/lib/Collapse/index.tsx @@ -1,7 +1,10 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + /** @jsx jsx */ -import { jsx, css } from '@emotion/core'; +import { jsx } from '@emotion/core'; import { useState } from 'react'; -import { IconButton } from 'office-ui-fabric-react'; +import { IconButton } from 'office-ui-fabric-react/lib/Button'; import { collapseContainer, diff --git a/Composer/packages/extensions/visual-designer/src/components/lib/DragScroll.tsx b/Composer/packages/extensions/visual-designer/src/components/lib/DragScroll.tsx index d25dc77ab2..793310e320 100644 --- a/Composer/packages/extensions/visual-designer/src/components/lib/DragScroll.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/lib/DragScroll.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + /** @jsx jsx */ import { jsx } from '@emotion/core'; import { useRef } from 'react'; diff --git a/Composer/packages/extensions/visual-designer/src/components/lib/EdgeComponents.tsx b/Composer/packages/extensions/visual-designer/src/components/lib/EdgeComponents.tsx index 934c3ce60d..d6dc2431bc 100644 --- a/Composer/packages/extensions/visual-designer/src/components/lib/EdgeComponents.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/lib/EdgeComponents.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + /** @jsx jsx */ import { jsx } from '@emotion/core'; import { Fragment } from 'react'; diff --git a/Composer/packages/extensions/visual-designer/src/components/lib/KeyboardZone.tsx b/Composer/packages/extensions/visual-designer/src/components/lib/KeyboardZone.tsx index a567728cb6..eef1a4e25a 100644 --- a/Composer/packages/extensions/visual-designer/src/components/lib/KeyboardZone.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/lib/KeyboardZone.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + /** @jsx jsx */ import { jsx } from '@emotion/core'; import { FC } from 'react'; diff --git a/Composer/packages/extensions/visual-designer/src/components/lib/OffsetContainer.tsx b/Composer/packages/extensions/visual-designer/src/components/lib/OffsetContainer.tsx index 6854f97deb..fd06d825b0 100644 --- a/Composer/packages/extensions/visual-designer/src/components/lib/OffsetContainer.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/lib/OffsetContainer.tsx @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + /** @jsx jsx */ import { jsx } from '@emotion/core'; // eslint-disable-next-line no-unused-vars diff --git a/Composer/packages/extensions/visual-designer/src/components/lib/Panel.tsx b/Composer/packages/extensions/visual-designer/src/components/lib/Panel.tsx index 5b4f8a3001..1709584a14 100644 --- a/Composer/packages/extensions/visual-designer/src/components/lib/Panel.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/lib/Panel.tsx @@ -1,7 +1,10 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + /** @jsx jsx */ import { jsx } from '@emotion/core'; import { useState, useLayoutEffect } from 'react'; -import { IconButton } from 'office-ui-fabric-react'; +import { IconButton } from 'office-ui-fabric-react/lib/Button'; import { PanelSize } from '../../constants/ElementSizes'; diff --git a/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx b/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx index d5dad318a0..e71ab326cf 100644 --- a/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx +++ b/Composer/packages/extensions/visual-designer/src/editors/ObiEditor.tsx @@ -267,7 +267,7 @@ export const ObiEditor: FC = ({ } break; case KeyboardPrimaryTypes.Cursor: { - const currentSelectedId = selectionContext.selectedIds[0] || focusedId; + const currentSelectedId = selectionContext.selectedIds[0] || focusedId || ''; const { selected, focused, tab } = moveCursor(selectableElements, currentSelectedId, command); setSelectionContext({ getNodeIndex: selectionContext.getNodeIndex, diff --git a/Composer/packages/extensions/visual-designer/src/index.tsx b/Composer/packages/extensions/visual-designer/src/index.tsx index 4b1a47ba44..c54693165d 100644 --- a/Composer/packages/extensions/visual-designer/src/index.tsx +++ b/Composer/packages/extensions/visual-designer/src/index.tsx @@ -7,6 +7,7 @@ import createCache from '@emotion/cache'; import React, { useRef } from 'react'; import isEqual from 'lodash/isEqual'; import formatMessage from 'format-message'; +import { ShellData, ShellApi } from '@bfc/shared'; import { ObiEditor } from './editors/ObiEditor'; import { NodeRendererContext } from './store/NodeRendererContext'; @@ -88,7 +89,7 @@ const VisualDesigner: React.FC = ({ focusedEvent={focusedEvent} onFocusEvent={onFocusEvent} onClipboardChange={onCopy} - onOpen={(x, rest) => navTo(x, rest)} + onOpen={x => navTo(x)} onChange={x => saveData(x)} onSelect={onSelect} undo={undo} @@ -102,32 +103,24 @@ const VisualDesigner: React.FC = ({ ); }; -interface VisualDesignerProps { - data: object; - dialogId: string; - focusedEvent: string; - focusedActions: string[]; - focusedSteps: string[]; - focusedTab: string; - clipboardActions: any[]; - shellApi: any; - hosted: boolean; - currentDialog: { id: string; displayName: string; isRoot: boolean }; +interface VisualDesignerProps extends ShellData { + onChange: (newData: object, updatePath?: string) => void; + shellApi: ShellApi; } VisualDesigner.defaultProps = { dialogId: '', focusedEvent: '', focusedSteps: [], - data: {}, - shellApi: { + data: { $type: '' }, + shellApi: ({ navTo: () => {}, - onFocusEvent: (_eventId: string) => {}, - onFocusSteps: (_stepIds: string[], _fragment?: string) => {}, - onSelect: (_ids: string[]) => {}, + onFocusEvent: () => {}, + onFocusSteps: () => {}, + onSelect: () => {}, saveData: () => {}, - addCoachMarkRef: (_: any) => {}, - }, + addCoachMarkRef: () => {}, + } as unknown) as ShellApi, }; export default VisualDesigner; diff --git a/Composer/packages/extensions/visual-designer/src/store/NodeRendererContext.ts b/Composer/packages/extensions/visual-designer/src/store/NodeRendererContext.ts index 535ed58533..36aa1abd0f 100644 --- a/Composer/packages/extensions/visual-designer/src/store/NodeRendererContext.ts +++ b/Composer/packages/extensions/visual-designer/src/store/NodeRendererContext.ts @@ -2,20 +2,30 @@ // Licensed under the MIT License. import React from 'react'; +import { ShellApi } from '@bfc/shared'; -interface LgTemplate { - Name: string; - Body: string; +type ShellApiFuncs = + | 'getLgTemplates' + | 'copyLgTemplate' + | 'removeLgTemplate' + | 'removeLgTemplates' + | 'updateLgTemplate'; + +interface NodeRendererContextValue extends Pick { + focusedId?: string; + focusedEvent?: string; + focusedTab?: string; + clipboardActions: any[]; } -export const NodeRendererContext = React.createContext({ +export const NodeRendererContext = React.createContext({ focusedId: '', focusedEvent: '', focusedTab: '', - clipboardActions: [] as any[], - getLgTemplates: (_id: string, _templateName: string) => Promise.resolve([] as LgTemplate[]), - copyLgTemplate: (_id: string, _fromTemplateName: string, _toTemplateName: string) => Promise.resolve(''), - removeLgTemplate: (_id: string, _templateName: string) => Promise.resolve(), - removeLgTemplates: (_id: string, _templateNames: string[]) => Promise.resolve(), - updateLgTemplate: (_id: string, _templateName: string, _template: string) => Promise.resolve('' as string), + clipboardActions: [], + getLgTemplates: () => Promise.resolve([]), + copyLgTemplate: () => Promise.resolve(''), + removeLgTemplate: () => Promise.resolve(), + removeLgTemplates: () => Promise.resolve(), + updateLgTemplate: () => Promise.resolve(), }); diff --git a/Composer/packages/extensions/visual-designer/src/utils/hooks.ts b/Composer/packages/extensions/visual-designer/src/utils/hooks.ts index 8e1a401c49..eddd11f52d 100644 --- a/Composer/packages/extensions/visual-designer/src/utils/hooks.ts +++ b/Composer/packages/extensions/visual-designer/src/utils/hooks.ts @@ -37,7 +37,7 @@ export const useLgTemplate = (str?: string, dialogId?: string) => { setTemplateText(str || ''); } - const templates = getLgTemplates ? await getLgTemplates('common', `${templateId}`) : []; + const templates = getLgTemplates ? await getLgTemplates('common') : []; const [template] = templates.filter(template => { return template.Name === templateId; }); diff --git a/Composer/packages/extensions/visual-designer/tsconfig.json b/Composer/packages/extensions/visual-designer/tsconfig.json index 294df87cb6..8eab2df086 100644 --- a/Composer/packages/extensions/visual-designer/tsconfig.json +++ b/Composer/packages/extensions/visual-designer/tsconfig.json @@ -1,23 +1,8 @@ { + "extends": "../../../tsconfig.base.json", "compilerOptions": { "outDir": "./lib/", - "noImplicitAny": false, "module": "esnext", - "target": "es5", - "jsx": "react", - "sourceMap": true, - "moduleResolution": "node", - "esModuleInterop": true, - "strict": true, - "resolveJsonModule": true, - "allowJs": false }, - "include": [ - "./src/**/*", - "./__tests__/**/*" - ], - "exclude": [ - "node_modules", - "lib" - ], + "include": ["./src/**/*", "./__tests__/**/*"] } diff --git a/Composer/packages/lib/code-editor/package.json b/Composer/packages/lib/code-editor/package.json index e01574348a..31db849c38 100644 --- a/Composer/packages/lib/code-editor/package.json +++ b/Composer/packages/lib/code-editor/package.json @@ -14,7 +14,7 @@ "prepublishOnly": "npm run build", "start": "webpack-dev-server --config demo/webpack.config.demo.js", "test": "jest", - "lint": "eslint --quiet --ext .js,.jsx,.ts,.tsx ./src", + "lint": "eslint --quiet --ext .ts,.tsx ./src", "lint:fix": "yarn lint --fix", "lint:typecheck": "tsc --noEmit", "watch": "yarn build:ts --watch" diff --git a/Composer/packages/lib/code-editor/src/BaseEditor.tsx b/Composer/packages/lib/code-editor/src/BaseEditor.tsx index 8013661b26..7d5cb02801 100644 --- a/Composer/packages/lib/code-editor/src/BaseEditor.tsx +++ b/Composer/packages/lib/code-editor/src/BaseEditor.tsx @@ -32,7 +32,7 @@ export interface BaseEditorProps extends Omit { onChange: (newValue: string) => void; placeholder?: string; value?: string; - codeRange?: ICodeRange | -1; + codeRange?: Partial | -1; } export function BaseEditor(props: BaseEditorProps) { @@ -42,8 +42,6 @@ export function BaseEditor(props: BaseEditorProps) { options.folding = false; } const containerRef = useRef(null); - // editor.setHiddenAreas is an internal api, not included in , so here mark it - const [editor, setEditor] = useState(null); const [rect, setRect] = useState({ height: 0, width: 0 }); const updateRect = throttle(() => { @@ -93,10 +91,10 @@ export function BaseEditor(props: BaseEditorProps) { const hiddenRanges = [ { startLineNumber: 1, - endLineNumber: codeRange.startLineNumber - 1, + endLineNumber: (codeRange.startLineNumber || 1) - 1, }, { - startLineNumber: codeRange.endLineNumber + 1, + startLineNumber: (codeRange.endLineNumber || 1) + 1, endLineNumber: lineCount, }, ]; @@ -117,7 +115,6 @@ export function BaseEditor(props: BaseEditorProps) { if (typeof props.editorDidMount === 'function') { props.editorDidMount(editor, monaco); } - setEditor(editor); updateEditorCodeRangeUI(editor); }; diff --git a/Composer/packages/lib/code-editor/src/RichEditor.tsx b/Composer/packages/lib/code-editor/src/RichEditor.tsx index b532812248..a882ff41f4 100644 --- a/Composer/packages/lib/code-editor/src/RichEditor.tsx +++ b/Composer/packages/lib/code-editor/src/RichEditor.tsx @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import React, { Fragment, useMemo, useState } from 'react'; +import React, { Fragment, useState } from 'react'; import { SharedColors, NeutralColors } from '@uifabric/fluent-theme'; import formatMessage from 'format-message'; diff --git a/Composer/packages/lib/code-editor/tsconfig.json b/Composer/packages/lib/code-editor/tsconfig.json index 24ff942876..bdcff025b4 100644 --- a/Composer/packages/lib/code-editor/tsconfig.json +++ b/Composer/packages/lib/code-editor/tsconfig.json @@ -1,19 +1,7 @@ { + "extends": "../../../tsconfig.base.json", "compilerOptions": { - "outDir": "./lib/", - "noImplicitAny": false, - "module": "es6", - "target": "es5", - "jsx": "react", - "sourceMap": true, - "declaration": true, - "moduleResolution": "node", - "esModuleInterop": true, - "strict": true, - "resolveJsonModule": true + "outDir": "lib" }, - "include": ["./src/**/*", "./__tests__/**/*"], - "exclude": [ - "node_modules" - ], + "include": ["./src/**/*", "./__tests__/**/*"] } diff --git a/Composer/packages/lib/indexers/package.json b/Composer/packages/lib/indexers/package.json index aede41bb43..c6bacc6cf0 100644 --- a/Composer/packages/lib/indexers/package.json +++ b/Composer/packages/lib/indexers/package.json @@ -13,7 +13,7 @@ "prepublishOnly": "npm run build", "start": "webpack-dev-server --config demo/webpack.config.demo.js", "test": "jest", - "lint": "eslint --quiet --ext .js,.jsx,.ts,.tsx ./src", + "lint": "eslint --quiet --ext .ts,.tsx ./src", "lint:fix": "yarn lint --fix", "lint:typecheck": "tsc --noEmit", "watch": "yarn build:ts --watch" diff --git a/Composer/packages/lib/indexers/tsconfig.json b/Composer/packages/lib/indexers/tsconfig.json index 8dc920c722..bdcff025b4 100644 --- a/Composer/packages/lib/indexers/tsconfig.json +++ b/Composer/packages/lib/indexers/tsconfig.json @@ -1,19 +1,7 @@ { + "extends": "../../../tsconfig.base.json", "compilerOptions": { - "outDir": "./lib/", - "noImplicitAny": false, - "module": "commonjs", - "target": "es6", - "sourceMap": true, - "declaration": true, - "moduleResolution": "node", - "esModuleInterop": true, - "strict": true, - "noUnusedLocals": true, - "resolveJsonModule": true + "outDir": "lib" }, - "include": ["./src/**/*", "./__tests__/**/*"], - "exclude": [ - "node_modules" - ], + "include": ["./src/**/*", "./__tests__/**/*"] } diff --git a/Composer/packages/lib/shared/src/types/shell.ts b/Composer/packages/lib/shared/src/types/shell.ts index a694b24622..10087b4165 100644 --- a/Composer/packages/lib/shared/src/types/shell.ts +++ b/Composer/packages/lib/shared/src/types/shell.ts @@ -117,19 +117,25 @@ export interface ShellData { export interface ShellApi { getState: () => Promise; - getDialogs: () => Promise; - saveData: (newData: T, updatePath: string) => Promise; - navTo: (path: string) => Promise; + saveData: (newData: T, updatePath?: string) => Promise; + navTo: (path: string, rest?: any) => Promise; onFocusSteps: (stepIds: string[], focusedTab?: string) => Promise; onFocusEvent: (eventId: string) => Promise; + onSelect: (ids: string[]) => Promise; createLuFile: (id: string) => Promise; - updateLuFile: (id: string, content: string) => Promise; + updateLuFile: (luFile: { id: string; content: string }) => Promise; updateLgFile: (id: string, content: string) => Promise; getLgTemplates: (id: string) => Promise; copyLgTemplate: (id: string, fromTemplateName: string, toTemplateName?: string) => Promise; - createLgTemplate: (id: string, template: LgTemplate, position: number) => Promise; + createLgTemplate: (id: string, template: Partial, position: number) => Promise; updateLgTemplate: (id: string, templateName: string, templateStr: string) => Promise; removeLgTemplate: (id: string, templateName: string) => Promise; + removeLgTemplates: (id: string, templateNames: string[]) => Promise; createDialog: () => Promise; validateExpression: (expression?: string) => Promise; + // TODO: fix these types + addCoachMarkRef: any; + onCopy: any; + undo: any; + redo: any; } diff --git a/Composer/packages/lib/shared/tsconfig.json b/Composer/packages/lib/shared/tsconfig.json index 9b9f5d74ef..bdcff025b4 100644 --- a/Composer/packages/lib/shared/tsconfig.json +++ b/Composer/packages/lib/shared/tsconfig.json @@ -1,20 +1,7 @@ { + "extends": "../../../tsconfig.base.json", "compilerOptions": { - "outDir": "./lib/", - "noImplicitAny": false, - "module": "commonjs", - "target": "es5", - "jsx": "react", - "sourceMap": true, - "declaration": true, - "moduleResolution": "node", - "esModuleInterop": true, - "strict": true, - "noUnusedLocals": true, - "resolveJsonModule": true + "outDir": "lib" }, - "include": ["./src/**/*", "./__tests__/**/*"], - "exclude": [ - "node_modules" - ], + "include": ["./src/**/*", "./__tests__/**/*"] } diff --git a/Composer/packages/server/src/server.ts b/Composer/packages/server/src/server.ts index 58d74569c9..0114f67a97 100644 --- a/Composer/packages/server/src/server.ts +++ b/Composer/packages/server/src/server.ts @@ -56,7 +56,7 @@ app.all('*', function(req: Request, res: Response, next: NextFunction) { next(); }); -app.use(`${BASEURL}/`, express.static(path.join(__dirname, './public'))); +app.use(`${BASEURL}/`, express.static(path.join(__dirname, './public'), { immutable: true, maxAge: 31536000 })); app.use(morgan('dev')); app.use(bodyParser.json({ limit: '50mb' })); diff --git a/Composer/packages/server/tsconfig.json b/Composer/packages/server/tsconfig.json index 6b25f32993..b105534557 100644 --- a/Composer/packages/server/tsconfig.json +++ b/Composer/packages/server/tsconfig.json @@ -1,23 +1,10 @@ { - /* Options used for linting (tests included) */ + "extends": "../../tsconfig.base.json", "compilerOptions": { + "declaration": false, "outDir": "./build/", - "noImplicitAny": false, - "module": "commonjs", - "target": "es6", "sourceMap": true, - "declaration": true, - "moduleResolution": "node", - "esModuleInterop": true, - "strict": true, - "noUnusedLocals": true, - "resolveJsonModule": true + "target": "es6" }, - "exclude": [ - "node_modules", - ], - "include": [ - "src/**/*.ts", - "__tests__/**/*.test.ts" - ] + "include": ["src/**/*.ts", "__tests__/**/*.test.ts"] } diff --git a/Composer/tsconfig.base.json b/Composer/tsconfig.base.json new file mode 100644 index 0000000000..41801b32e2 --- /dev/null +++ b/Composer/tsconfig.base.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "allowJs": false, + "declaration": true, + "esModuleInterop": true, + "jsx": "react", + "module": "commonjs", + "moduleResolution": "node", + "noImplicitAny": false, + "noUnusedLocals": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "target": "es5" + }, + "exclude": [ + "node_modules" + ], +} diff --git a/Composer/yarn.lock b/Composer/yarn.lock index 92871f5d82..fc01994dec 100644 --- a/Composer/yarn.lock +++ b/Composer/yarn.lock @@ -54,6 +54,13 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/code-frame@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" + integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== + dependencies: + "@babel/highlight" "^7.0.0" + "@babel/core@7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.2.2.tgz#07adba6dde27bb5ad8d8672f15fde3e08184a687" @@ -94,6 +101,26 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.0.1": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.2.tgz#ea5b99693bcfc058116f42fa1dd54da412b29d91" + integrity sha512-eeD7VEZKfhK1KUXGiyPFettgF3m513f8FoBSWiQ1xTvl1RAopLs42Wp9+Ze911I6H0N9lNqJMDgoZT7gHsipeQ== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.2" + "@babel/helpers" "^7.7.0" + "@babel/parser" "^7.7.2" + "@babel/template" "^7.7.0" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.7.2" + convert-source-map "^1.7.0" + debug "^4.1.0" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/core@^7.1.0", "@babel/core@^7.1.6", "@babel/core@^7.3.4": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.4.0.tgz#248fd6874b7d755010bfe61f557461d4f446d9e9" @@ -156,6 +183,16 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.7.2": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.2.tgz#2f4852d04131a5e17ea4f6645488b5da66ebf3af" + integrity sha512-WthSArvAjYLz4TcbKOi88me+KmDJdKSlfwwN8CnUYn9jBkzhq0ZEPuBfkAWIvjJ3AdEV1Cf/+eSQTnp3IDJKlQ== + dependencies: + "@babel/types" "^7.7.2" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" @@ -163,6 +200,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-annotate-as-pure@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.0.tgz#efc54032d43891fe267679e63f6860aa7dbf4a5e" + integrity sha512-k50CQxMlYTYo+GGyUGFwpxKVtxVJi9yh61sXZji3zYHccK9RYliZGSTOgci85T+r+0VFN2nWbGM04PIqwfrpMg== + dependencies: + "@babel/types" "^7.7.0" + "@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f" @@ -221,6 +265,14 @@ "@babel/helper-replace-supers" "^7.4.4" "@babel/helper-split-export-declaration" "^7.4.4" +"@babel/helper-create-regexp-features-plugin@^7.7.0": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.7.2.tgz#6f20443778c8fce2af2ff4206284afc0ced65db6" + integrity sha512-pAil/ZixjTlrzNpjx+l/C/wJk002Wo7XbbZ8oujH/AoJ3Juv0iN/UTcPUHXKMFLqsfS0Hy6Aow8M31brUYBlQQ== + dependencies: + "@babel/helper-regex" "^7.4.4" + regexpu-core "^4.6.0" + "@babel/helper-define-map@^7.1.0", "@babel/helper-define-map@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.0.tgz#cbfd8c1b2f12708e262c26f600cd16ed6a3bc6c9" @@ -239,6 +291,15 @@ "@babel/types" "^7.4.4" lodash "^4.17.11" +"@babel/helper-define-map@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.7.0.tgz#60b0e9fd60def9de5054c38afde8c8ee409c7529" + integrity sha512-kPKWPb0dMpZi+ov1hJiwse9dWweZsz3V9rP4KdytnX1E7z3cTNmFGglwklzFPuqIcHLIY3bgKSs4vkwXXdflQA== + dependencies: + "@babel/helper-function-name" "^7.7.0" + "@babel/types" "^7.7.0" + lodash "^4.17.13" + "@babel/helper-explode-assignable-expression@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6" @@ -256,6 +317,15 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-function-name@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.0.tgz#44a5ad151cfff8ed2599c91682dda2ec2c8430a3" + integrity sha512-tDsJgMUAP00Ugv8O2aGEua5I2apkaQO7lBGUq1ocwN3G23JE5Dcq0uh3GvFTChPa4b40AWiAsLvCZOA2rdnQ7Q== + dependencies: + "@babel/helper-get-function-arity" "^7.7.0" + "@babel/template" "^7.7.0" + "@babel/types" "^7.7.0" + "@babel/helper-get-function-arity@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" @@ -263,6 +333,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-get-function-arity@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.0.tgz#c604886bc97287a1d1398092bc666bc3d7d7aa2d" + integrity sha512-tLdojOTz4vWcEnHWHCuPN5P85JLZWbm5Fx5ZsMEMPhF3Uoe3O7awrbM2nQ04bDOUToH/2tH/ezKEOR8zEYzqyw== + dependencies: + "@babel/types" "^7.7.0" + "@babel/helper-hoist-variables@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.0.tgz#25b621399ae229869329730a62015bbeb0a6fbd6" @@ -277,6 +354,13 @@ dependencies: "@babel/types" "^7.4.4" +"@babel/helper-hoist-variables@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.0.tgz#b4552e4cfe5577d7de7b183e193e84e4ec538c81" + integrity sha512-LUe/92NqsDAkJjjCEWkNe+/PcpnisvnqdlRe19FahVapa4jndeuJ+FBiTX1rcAKWKcJGE+C3Q3tuEuxkSmCEiQ== + dependencies: + "@babel/types" "^7.7.0" + "@babel/helper-member-expression-to-functions@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f" @@ -284,6 +368,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-member-expression-to-functions@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.7.0.tgz#472b93003a57071f95a541ea6c2b098398bcad8a" + integrity sha512-QaCZLO2RtBcmvO/ekOLp8p7R5X2JriKRizeDpm5ChATAFWrrYDcDxPuCIBXKyBjY+i1vYSdcUTMIb8psfxHDPA== + dependencies: + "@babel/types" "^7.7.0" + "@babel/helper-module-imports@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d" @@ -291,6 +382,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-module-imports@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.7.0.tgz#99c095889466e5f7b6d66d98dffc58baaf42654d" + integrity sha512-Dv3hLKIC1jyfTkClvyEkYP2OlkzNvWs5+Q8WgPbxM5LMeorons7iPP91JM+DU7tRbhqA1ZeooPaMFvQrn23RHw== + dependencies: + "@babel/types" "^7.7.0" + "@babel/helper-module-transforms@^7.1.0": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.2.2.tgz#ab2f8e8d231409f8370c883d20c335190284b963" @@ -315,6 +413,18 @@ "@babel/types" "^7.4.4" lodash "^4.17.11" +"@babel/helper-module-transforms@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.7.0.tgz#154a69f0c5b8fd4d39e49750ff7ac4faa3f36786" + integrity sha512-rXEefBuheUYQyX4WjV19tuknrJFwyKw0HgzRwbkyTbB+Dshlq7eqkWbyjzToLrMZk/5wKVKdWFluiAsVkHXvuQ== + dependencies: + "@babel/helper-module-imports" "^7.7.0" + "@babel/helper-simple-access" "^7.7.0" + "@babel/helper-split-export-declaration" "^7.7.0" + "@babel/template" "^7.7.0" + "@babel/types" "^7.7.0" + lodash "^4.17.13" + "@babel/helper-optimise-call-expression@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5" @@ -322,6 +432,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-optimise-call-expression@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.7.0.tgz#4f66a216116a66164135dc618c5d8b7a959f9365" + integrity sha512-48TeqmbazjNU/65niiiJIJRc5JozB8acui1OS7bSd6PgxfuovWsvjfWSzlgx+gPFdVveNzUdpdIg5l56Pl5jqg== + dependencies: + "@babel/types" "^7.7.0" + "@babel/helper-plugin-utils@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250" @@ -352,6 +469,17 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-remap-async-to-generator@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.0.tgz#4d69ec653e8bff5bce62f5d33fc1508f223c75a7" + integrity sha512-pHx7RN8X0UNHPB/fnuDnRXVZ316ZigkO8y8D835JlZ2SSdFKb6yH9MIYRU4fy/KPe5sPHDFOPvf8QLdbAGGiyw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.7.0" + "@babel/helper-wrap-function" "^7.7.0" + "@babel/template" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + "@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.0.tgz#4f56adb6aedcd449d2da9399c2dcf0545463b64c" @@ -372,6 +500,16 @@ "@babel/traverse" "^7.4.4" "@babel/types" "^7.4.4" +"@babel/helper-replace-supers@^7.5.5", "@babel/helper-replace-supers@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.7.0.tgz#d5365c8667fe7cbd13b8ddddceb9bd7f2b387512" + integrity sha512-5ALYEul5V8xNdxEeWvRsBzLMxQksT7MaStpxjJf9KsnLxpAKBtfw5NeMKZJSYDa0lKdOcy0g+JT/f5mPSulUgg== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.7.0" + "@babel/helper-optimise-call-expression" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + "@babel/helper-simple-access@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c" @@ -380,6 +518,14 @@ "@babel/template" "^7.1.0" "@babel/types" "^7.0.0" +"@babel/helper-simple-access@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.7.0.tgz#97a8b6c52105d76031b86237dc1852b44837243d" + integrity sha512-AJ7IZD7Eem3zZRuj5JtzFAptBw7pMlS3y8Qv09vaBWoFsle0d1kAn5Wq6Q9MyBXITPOKnxwkZKoAm4bopmv26g== + dependencies: + "@babel/template" "^7.7.0" + "@babel/types" "^7.7.0" + "@babel/helper-split-export-declaration@^7.0.0", "@babel/helper-split-export-declaration@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.0.tgz#571bfd52701f492920d63b7f735030e9a3e10b55" @@ -394,6 +540,13 @@ dependencies: "@babel/types" "^7.4.4" +"@babel/helper-split-export-declaration@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.0.tgz#1365e74ea6c614deeb56ebffabd71006a0eb2300" + integrity sha512-HgYSI8rH08neWlAH3CcdkFg9qX9YsZysZI5GD8LjhQib/mM0jGOZOVkoUiiV2Hu978fRtjtsGsW6w0pKHUWtqA== + dependencies: + "@babel/types" "^7.7.0" + "@babel/helper-wrap-function@^7.1.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" @@ -404,6 +557,16 @@ "@babel/traverse" "^7.1.0" "@babel/types" "^7.2.0" +"@babel/helper-wrap-function@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.0.tgz#15af3d3e98f8417a60554acbb6c14e75e0b33b74" + integrity sha512-sd4QjeMgQqzshSjecZjOp8uKfUtnpmCyQhKQrVJBBgeHAB/0FPi33h3AbVlVp07qQtMD4QgYSzaMI7VwncNK/w== + dependencies: + "@babel/helper-function-name" "^7.7.0" + "@babel/template" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + "@babel/helpers@^7.2.0", "@babel/helpers@^7.4.0": version "7.4.2" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.4.2.tgz#3bdfa46a552ca77ef5a0f8551be5f0845ae989be" @@ -422,6 +585,15 @@ "@babel/traverse" "^7.4.4" "@babel/types" "^7.4.4" +"@babel/helpers@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.7.0.tgz#359bb5ac3b4726f7c1fde0ec75f64b3f4275d60b" + integrity sha512-VnNwL4YOhbejHb7x/b5F39Zdg5vIQpUUNzJwx0ww1EcVRt41bbGRZWhAURrfY32T5zTT3qwNOQFWpn+P0i0a2g== + dependencies: + "@babel/template" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" @@ -441,6 +613,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.5.tgz#04af8d5d5a2b044a2a1bffacc1e5e6673544e872" integrity sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew== +"@babel/parser@^7.7.0", "@babel/parser@^7.7.2": + version "7.7.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.3.tgz#5fad457c2529de476a248f75b0f090b3060af043" + integrity sha512-bqv+iCo9i+uLVbI0ILzKkvMorqxouI+GbV13ivcARXn9NNEabi2IEz912IgNpT/60BNXac5dgcfjb94NjsF33A== + "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" @@ -450,6 +627,15 @@ "@babel/helper-remap-async-to-generator" "^7.1.0" "@babel/plugin-syntax-async-generators" "^7.2.0" +"@babel/plugin-proposal-async-generator-functions@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.0.tgz#83ef2d6044496b4c15d8b4904e2219e6dccc6971" + integrity sha512-ot/EZVvf3mXtZq0Pd0+tSOfGWMizqmOohXmNZg6LNFjHOV+wOPv7BvVYh8oPR8LhpIP3ye8nNooKL50YRWxpYA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.7.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-proposal-class-properties@7.3.0": version "7.3.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.3.0.tgz#272636bc0fa19a0bc46e601ec78136a173ea36cd" @@ -483,6 +669,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-decorators" "^7.2.0" +"@babel/plugin-proposal-dynamic-import@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.7.0.tgz#dc02a8bad8d653fb59daf085516fa416edd2aa7f" + integrity sha512-7poL3Xi+QFPC7sGAzEIbXUyYzGJwbc2+gSD0AkiC5k52kH2cqHdqxm5hNFfLW3cRSTcx9bN0Fl7/6zWcLLnKAQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/plugin-proposal-json-strings@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317" @@ -515,6 +709,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-syntax-object-rest-spread" "^7.2.0" +"@babel/plugin-proposal-object-rest-spread@^7.6.2": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.6.2.tgz#8ffccc8f3a6545e9f78988b6bf4fe881b88e8096" + integrity sha512-LDBXlmADCsMZV1Y9OQwMc0MyGZ8Ta/zlD9N67BfQT8uYwkRswiu2hU6nJKrjrt/58aH/vqfQlR/9yId/7A2gWw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-proposal-optional-catch-binding@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5" @@ -541,6 +743,14 @@ "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" +"@babel/plugin-proposal-unicode-property-regex@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.7.0.tgz#549fe1717a1bd0a2a7e63163841cb37e78179d5d" + integrity sha512-mk34H+hp7kRBWJOOAR0ZMGCydgKMD4iN9TpDRp3IIcbunltxEY89XSimc6WbtSLCDrwcdy/EEw7h5CFCzxTchw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-async-generators@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f" @@ -555,7 +765,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-dynamic-import@7.2.0": +"@babel/plugin-syntax-dynamic-import@7.2.0", "@babel/plugin-syntax-dynamic-import@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612" integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w== @@ -597,6 +807,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-top-level-await@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.7.0.tgz#f5699549f50bbe8d12b1843a4e82f0a37bb65f4d" + integrity sha512-hi8FUNiFIY1fnUI2n1ViB1DR0R4QeK4iHcTlW6aJkrPoTdb8Rf1EMQ6GT3f67DDkYyWgew9DFoOZ6gOoEsdzTA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-typescript@^7.2.0": version "7.3.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz#a7cc3f66119a9f7ebe2de5383cce193473d65991" @@ -629,6 +846,15 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-remap-async-to-generator" "^7.1.0" +"@babel/plugin-transform-async-to-generator@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.7.0.tgz#e2b84f11952cf5913fe3438b7d2585042772f492" + integrity sha512-vLI2EFLVvRBL3d8roAMqtVY0Bm9C1QzLkdS57hiKrjUBSqsQYrBsMCeOg/0KK7B0eK9V71J5mWcha9yyoI2tZw== + dependencies: + "@babel/helper-module-imports" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-remap-async-to-generator" "^7.7.0" + "@babel/plugin-transform-block-scoped-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190" @@ -652,6 +878,14 @@ "@babel/helper-plugin-utils" "^7.0.0" lodash "^4.17.11" +"@babel/plugin-transform-block-scoping@^7.6.3": + version "7.6.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.6.3.tgz#6e854e51fbbaa84351b15d4ddafe342f3a5d542a" + integrity sha512-7hvrg75dubcO3ZI2rjYTzUrEuh1E9IyDEhhB6qfcooxhDA33xx2MasuLVgdxzcP6R/lipAC6n9ub9maNW6RKdw== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + lodash "^4.17.13" + "@babel/plugin-transform-classes@7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.2.2.tgz#6c90542f210ee975aa2aa8c8b5af7fa73a126953" @@ -694,6 +928,20 @@ "@babel/helper-split-export-declaration" "^7.4.4" globals "^11.1.0" +"@babel/plugin-transform-classes@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.7.0.tgz#b411ecc1b8822d24b81e5d184f24149136eddd4a" + integrity sha512-/b3cKIZwGeUesZheU9jNYcwrEA7f/Bo4IdPmvp7oHgvks2majB5BoT5byAql44fiNQYOPzhk2w8DbgfuafkMoA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.7.0" + "@babel/helper-define-map" "^7.7.0" + "@babel/helper-function-name" "^7.7.0" + "@babel/helper-optimise-call-expression" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.7.0" + "@babel/helper-split-export-declaration" "^7.7.0" + globals "^11.1.0" + "@babel/plugin-transform-computed-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da" @@ -722,6 +970,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-destructuring@^7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.6.0.tgz#44bbe08b57f4480094d57d9ffbcd96d309075ba6" + integrity sha512-2bGIS5P1v4+sWTCnKNDZDxbGvEqi0ijeqM/YqHtVGrvG2y0ySgnEEhXErvE9dA0bnIzY9bIzdFK0jFA46ASIIQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-dotall-regex@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.2.0.tgz#f0aabb93d120a8ac61e925ea0ba440812dbe0e49" @@ -740,6 +995,14 @@ "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" +"@babel/plugin-transform-dotall-regex@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.7.0.tgz#c5c9ecacab3a5e0c11db6981610f0c32fd698b3b" + integrity sha512-3QQlF7hSBnSuM1hQ0pS3pmAbWLax/uGNCbPBND9y+oJ4Y776jsyujG2k0Sn2Aj2a0QwVOiOFL5QVPA7spjvzSA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-duplicate-keys@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz#d952c4930f312a4dbfff18f0b2914e60c35530b3" @@ -747,6 +1010,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-duplicate-keys@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853" + integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-exponentiation-operator@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008" @@ -793,6 +1063,14 @@ "@babel/helper-function-name" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-function-name@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.7.0.tgz#0fa786f1eef52e3b7d4fc02e54b2129de8a04c2a" + integrity sha512-P5HKu0d9+CzZxP5jcrWdpe7ZlFDe24bmqP6a6X8BHEBl/eizAsY8K6LX8LASZL0Jxdjm5eEfzp+FIrxCm/p8bA== + dependencies: + "@babel/helper-function-name" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-literals@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1" @@ -815,6 +1093,15 @@ "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-modules-amd@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91" + integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg== + dependencies: + "@babel/helper-module-transforms" "^7.1.0" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + "@babel/plugin-transform-modules-commonjs@^7.2.0", "@babel/plugin-transform-modules-commonjs@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.0.tgz#3b8ec61714d3b75d20c5ccfa157f2c2e087fd4ca" @@ -833,6 +1120,16 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-simple-access" "^7.1.0" +"@babel/plugin-transform-modules-commonjs@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.0.tgz#3e5ffb4fd8c947feede69cbe24c9554ab4113fe3" + integrity sha512-KEMyWNNWnjOom8vR/1+d+Ocz/mILZG/eyHHO06OuBQ2aNhxT62fr4y6fGOplRx+CxCSp3IFwesL8WdINfY/3kg== + dependencies: + "@babel/helper-module-transforms" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-simple-access" "^7.7.0" + babel-plugin-dynamic-import-node "^2.3.0" + "@babel/plugin-transform-modules-systemjs@^7.2.0", "@babel/plugin-transform-modules-systemjs@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.0.tgz#c2495e55528135797bc816f5d50f851698c586a1" @@ -849,6 +1146,15 @@ "@babel/helper-hoist-variables" "^7.4.4" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-modules-systemjs@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.7.0.tgz#9baf471213af9761c1617bb12fd278e629041417" + integrity sha512-ZAuFgYjJzDNv77AjXRqzQGlQl4HdUM6j296ee4fwKVZfhDR9LAGxfvXjBkb06gNETPnN0sLqRm9Gxg4wZH6dXg== + dependencies: + "@babel/helper-hoist-variables" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + babel-plugin-dynamic-import-node "^2.3.0" + "@babel/plugin-transform-modules-umd@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae" @@ -857,6 +1163,14 @@ "@babel/helper-module-transforms" "^7.1.0" "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-modules-umd@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.7.0.tgz#d62c7da16670908e1d8c68ca0b5d4c0097b69966" + integrity sha512-u7eBA03zmUswQ9LQ7Qw0/ieC1pcAkbp5OQatbWUzY1PaBccvuJXUkYzoN1g7cqp7dbTu6Dp9bXyalBvD04AANA== + dependencies: + "@babel/helper-module-transforms" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-named-capturing-groups-regex@^7.3.0", "@babel/plugin-transform-named-capturing-groups-regex@^7.4.2": version "7.4.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.2.tgz#800391136d6cbcc80728dbdba3c1c6e46f86c12e" @@ -871,6 +1185,13 @@ dependencies: regexp-tree "^0.1.6" +"@babel/plugin-transform-named-capturing-groups-regex@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.7.0.tgz#358e6fd869b9a4d8f5cbc79e4ed4fc340e60dcaf" + integrity sha512-+SicSJoKouPctL+j1pqktRVCgy+xAch1hWWTMy13j0IflnyNjaoskj+DwRQFimHbLqO3sq2oN2CXMvXq3Bgapg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.0" + "@babel/plugin-transform-new-target@^7.0.0", "@babel/plugin-transform-new-target@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.0.tgz#67658a1d944edb53c8d4fa3004473a0dd7838150" @@ -893,6 +1214,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/helper-replace-supers" "^7.1.0" +"@babel/plugin-transform-object-super@^7.5.5": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.5.5.tgz#c70021df834073c65eb613b8679cc4a381d1a9f9" + integrity sha512-un1zJQAhSosGFBduPgN/YFNvWVpRuHKU7IHBglLoLZsGmruJPOo6pbInneflUdmq7YvSVqhpPs5zdBvLnteltQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/helper-replace-supers" "^7.5.5" + "@babel/plugin-transform-parameters@^7.2.0", "@babel/plugin-transform-parameters@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.0.tgz#a1309426fac4eecd2a9439a4c8c35124a11a48a9" @@ -972,6 +1301,13 @@ dependencies: regenerator-transform "^0.14.0" +"@babel/plugin-transform-regenerator@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.0.tgz#f1b20b535e7716b622c99e989259d7dd942dd9cc" + integrity sha512-AXmvnC+0wuj/cFkkS/HFHIojxH3ffSXE+ttulrqWjZZRaUOonfJc60e1wSNT4rV8tIunvu/R3wCp71/tLAa9xg== + dependencies: + regenerator-transform "^0.14.0" + "@babel/plugin-transform-reserved-words@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634" @@ -1023,6 +1359,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-spread@^7.6.2": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.6.2.tgz#fc77cf798b24b10c46e1b51b1b88c2bf661bb8dd" + integrity sha512-DpSvPFryKdK1x+EDJYCy28nmAaIMdxmhot62jAXF/o99iA33Zj2Lmcp3vDmz+MUh0LNYVPvfj5iC3feb3/+PFg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-sticky-regex@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1" @@ -1080,6 +1423,14 @@ "@babel/helper-regex" "^7.4.4" regexpu-core "^4.5.4" +"@babel/plugin-transform-unicode-regex@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.0.tgz#743d9bcc44080e3cc7d49259a066efa30f9187a3" + integrity sha512-RrThb0gdrNwFAqEAAx9OWgtx6ICK69x7i9tCnMdVrxQwSDp/Abu9DXFU5Hh16VP33Rmxh04+NGW28NsIkFvFKA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/preset-env@7.3.0": version "7.3.0" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.3.0.tgz#9777a1f61f99fb6cc8bda969541ecc122924317b" @@ -1178,6 +1529,63 @@ js-levenshtein "^1.1.3" semver "^5.3.0" +"@babel/preset-env@^7.0.0": + version "7.7.1" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.7.1.tgz#04a2ff53552c5885cf1083e291c8dd5490f744bb" + integrity sha512-/93SWhi3PxcVTDpSqC+Dp4YxUu3qZ4m7I76k0w73wYfn7bGVuRIO4QUz95aJksbS+AD1/mT1Ie7rbkT0wSplaA== + dependencies: + "@babel/helper-module-imports" "^7.7.0" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-async-generator-functions" "^7.7.0" + "@babel/plugin-proposal-dynamic-import" "^7.7.0" + "@babel/plugin-proposal-json-strings" "^7.2.0" + "@babel/plugin-proposal-object-rest-spread" "^7.6.2" + "@babel/plugin-proposal-optional-catch-binding" "^7.2.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.7.0" + "@babel/plugin-syntax-async-generators" "^7.2.0" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/plugin-syntax-json-strings" "^7.2.0" + "@babel/plugin-syntax-object-rest-spread" "^7.2.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.2.0" + "@babel/plugin-syntax-top-level-await" "^7.7.0" + "@babel/plugin-transform-arrow-functions" "^7.2.0" + "@babel/plugin-transform-async-to-generator" "^7.7.0" + "@babel/plugin-transform-block-scoped-functions" "^7.2.0" + "@babel/plugin-transform-block-scoping" "^7.6.3" + "@babel/plugin-transform-classes" "^7.7.0" + "@babel/plugin-transform-computed-properties" "^7.2.0" + "@babel/plugin-transform-destructuring" "^7.6.0" + "@babel/plugin-transform-dotall-regex" "^7.7.0" + "@babel/plugin-transform-duplicate-keys" "^7.5.0" + "@babel/plugin-transform-exponentiation-operator" "^7.2.0" + "@babel/plugin-transform-for-of" "^7.4.4" + "@babel/plugin-transform-function-name" "^7.7.0" + "@babel/plugin-transform-literals" "^7.2.0" + "@babel/plugin-transform-member-expression-literals" "^7.2.0" + "@babel/plugin-transform-modules-amd" "^7.5.0" + "@babel/plugin-transform-modules-commonjs" "^7.7.0" + "@babel/plugin-transform-modules-systemjs" "^7.7.0" + "@babel/plugin-transform-modules-umd" "^7.7.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.7.0" + "@babel/plugin-transform-new-target" "^7.4.4" + "@babel/plugin-transform-object-super" "^7.5.5" + "@babel/plugin-transform-parameters" "^7.4.4" + "@babel/plugin-transform-property-literals" "^7.2.0" + "@babel/plugin-transform-regenerator" "^7.7.0" + "@babel/plugin-transform-reserved-words" "^7.2.0" + "@babel/plugin-transform-shorthand-properties" "^7.2.0" + "@babel/plugin-transform-spread" "^7.6.2" + "@babel/plugin-transform-sticky-regex" "^7.2.0" + "@babel/plugin-transform-template-literals" "^7.4.4" + "@babel/plugin-transform-typeof-symbol" "^7.2.0" + "@babel/plugin-transform-unicode-regex" "^7.7.0" + "@babel/types" "^7.7.1" + browserslist "^4.6.0" + core-js-compat "^3.1.1" + invariant "^2.2.2" + js-levenshtein "^1.1.3" + semver "^5.5.0" + "@babel/preset-env@^7.1.6": version "7.4.2" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.4.2.tgz#2f5ba1de2daefa9dcca653848f96c7ce2e406676" @@ -1331,7 +1739,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/runtime@^7.0.0": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.6.2": version "7.7.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.2.tgz#111a78002a5c25fc8e3361bedc9529c696b85a6a" integrity sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw== @@ -1384,6 +1792,15 @@ "@babel/parser" "^7.4.4" "@babel/types" "^7.4.4" +"@babel/template@^7.7.0": + version "7.7.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.0.tgz#4fadc1b8e734d97f56de39c77de76f2562e597d0" + integrity sha512-OKcwSYOW1mhWbnTBgQY5lvg1Fxg+VyfQGjcBduZFljfc044J5iDlnDSfhQ867O17XHiSCxYHUxHg2b7ryitbUQ== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/types" "^7.7.0" + "@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.2.2", "@babel/traverse@^7.3.4", "@babel/traverse@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.0.tgz#14006967dd1d2b3494cdd650c686db9daf0ddada" @@ -1414,6 +1831,21 @@ globals "^11.1.0" lodash "^4.17.11" +"@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.2.tgz#ef0a65e07a2f3c550967366b3d9b62a2dcbeae09" + integrity sha512-TM01cXib2+rgIZrGJOLaHV/iZUAxf4A0dt5auY6KNZ+cm6aschuJGqKJM3ROTt3raPUdIDk9siAufIFEleRwtw== + dependencies: + "@babel/code-frame" "^7.5.5" + "@babel/generator" "^7.7.2" + "@babel/helper-function-name" "^7.7.0" + "@babel/helper-split-export-declaration" "^7.7.0" + "@babel/parser" "^7.7.2" + "@babel/types" "^7.7.2" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + "@babel/types@^7.0.0", "@babel/types@^7.1.6", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.4", "@babel/types@^7.4.0": version "7.4.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.0.tgz#670724f77d24cce6cc7d8cf64599d511d164894c" @@ -1432,6 +1864,15 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" +"@babel/types@^7.7.0", "@babel/types@^7.7.1", "@babel/types@^7.7.2": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.2.tgz#550b82e5571dcd174af576e23f0adba7ffc683f7" + integrity sha512-YTf6PXoh3+eZgRCBzzP25Bugd2ngmpQVrk7kXX0i5N9BO7TFBtIgZYs7WtxtOGs8e6A4ZI7ECkbBCEHeXocvOA== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@bfcomposer/monaco-editor-webpack-plugin@^1.7.2": version "1.7.2" resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/@bfcomposer/monaco-editor-webpack-plugin/-/@bfcomposer/monaco-editor-webpack-plugin-1.7.2.tgz#f00ac5cec496dc3d44713d9142956b3336033eab" @@ -1487,6 +1928,18 @@ date-fns "^1.27.2" figures "^1.7.0" +"@cypress/webpack-preprocessor@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-4.1.1.tgz#3c0b5b8de6eaac605dac3b1f1c3f5916c1c6eaea" + integrity sha512-SfzDqOvWBSlfGRm8ak/XHUXAnndwHU2qJIRr1LIC7j2UqWcZoJ+286CuNloJbkwfyEAO6tQggLd4E/WHUAcKZQ== + dependencies: + bluebird "3.7.1" + debug "4.1.1" + optionalDependencies: + "@babel/core" "^7.0.1" + "@babel/preset-env" "^7.0.0" + babel-loader "^8.0.2" + "@cypress/xvfb@1.2.4": version "1.2.4" resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.2.4.tgz#2daf42e8275b39f4aa53c14214e557bd14e7748a" @@ -1889,6 +2342,15 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^12.0.9" +"@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^13.0.0" + "@microsoft/load-themed-styles@^1.7.13": version "1.9.5" resolved "https://registry.yarnpkg.com/@microsoft/load-themed-styles/-/load-themed-styles-1.9.5.tgz#b9f063bafa568e356b4d99a5b522d0bab60bda85" @@ -2057,6 +2519,27 @@ dependencies: defer-to-connect "^1.0.1" +"@testing-library/cypress@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@testing-library/cypress/-/cypress-5.0.2.tgz#68746fc9db11dabcc4bf883e25b64316f637be71" + integrity sha512-AmvBLE+isA/vpdBTXpJ5tu+UYMDgqNW015RVa0nBPJHrv5UXNlmDZyu8tpkxGTFhcf+iFSA2pHuK1jUCQ8PnXQ== + dependencies: + "@babel/runtime" "^7.5.5" + "@testing-library/dom" "^6.0.0" + "@types/testing-library__cypress" "^5.0.0" + +"@testing-library/dom@^6.0.0": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-6.10.1.tgz#da5bf5065d3f9e484aef4cc495f4e1a5bea6df2e" + integrity sha512-5BPKxaO+zSJDUbVZBRNf9KrmDkm/EcjjaHSg3F9+031VZyPACKXlwLBjVzZxheunT9m72DoIq7WvyE457/Xweg== + dependencies: + "@babel/runtime" "^7.6.2" + "@sheerun/mutationobserver-shim" "^0.3.2" + "@types/testing-library__dom" "^6.0.0" + aria-query "3.0.0" + pretty-format "^24.9.0" + wait-for-expect "^3.0.0" + "@types/anymatch@*": version "1.3.1" resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" @@ -2433,6 +2916,21 @@ dependencies: "@types/estree" "*" +"@types/testing-library__cypress@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/testing-library__cypress/-/testing-library__cypress-5.0.1.tgz#d05a264eb5d5a45659699a4e0309a7cebe57b344" + integrity sha512-z2JKxVTh3PDeLbATRofwDUImEwuytsBeu8Si6YLzxwc2HK4xGIDs50HFlwYD9MPlclGDQRm0QL7ynnaIjRtCGg== + dependencies: + "@types/testing-library__dom" "*" + cypress "^3.5.0" + +"@types/testing-library__dom@*", "@types/testing-library__dom@^6.0.0": + version "6.10.0" + resolved "https://registry.yarnpkg.com/@types/testing-library__dom/-/testing-library__dom-6.10.0.tgz#590d76e3875a7c536dc744eb530cbf51b6483404" + integrity sha512-mL/GMlyQxiZplbUuFNwA0vAI3k3uJNSf6slr5AVve9TXmfLfyefNT0uHHnxwdYuPMxYD5gI/+dgAvc/5opW9JQ== + dependencies: + pretty-format "^24.3.0" + "@types/tunnel@0.0.0": version "0.0.0" resolved "https://registry.yarnpkg.com/@types/tunnel/-/tunnel-0.0.0.tgz#c2a42943ee63c90652a5557b8c4e56cda77f944e" @@ -2490,11 +2988,23 @@ "@types/webpack-sources" "*" source-map "^0.6.0" +"@types/yargs-parser@*": + version "13.1.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.1.0.tgz#c563aa192f39350a1d18da36c5a8da382bbd8228" + integrity sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg== + "@types/yargs@^12.0.2", "@types/yargs@^12.0.9": version "12.0.10" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.10.tgz#17a8ec65cd8e88f51b418ceb271af18d3137df67" integrity sha512-WsVzTPshvCSbHThUduGGxbmnwcpkgSctHGHTqzWyFg4lYAuV5qXlyFPOsP3OWqCINfmg/8VXP+zJaa4OxEsBQQ== +"@types/yargs@^13.0.0": + version "13.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.3.tgz#76482af3981d4412d65371a318f992d33464a380" + integrity sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@2.6.0": version "2.6.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.6.0.tgz#e82ed43fc4527b21bfe35c20a2d6e4ed49fc7957" @@ -3087,7 +3597,7 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -aria-query@^3.0.0: +aria-query@3.0.0, aria-query@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= @@ -3405,6 +3915,16 @@ babel-loader@8.0.5: mkdirp "^0.5.1" util.promisify "^1.0.0" +babel-loader@^8.0.2: + version "8.0.6" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb" + integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw== + dependencies: + find-cache-dir "^2.0.0" + loader-utils "^1.0.2" + mkdirp "^0.5.1" + pify "^4.0.1" + babel-plugin-dynamic-import-node@2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.2.0.tgz#c0adfb07d95f4a4495e9aaac6ec386c4d7c2524e" @@ -3412,6 +3932,13 @@ babel-plugin-dynamic-import-node@2.2.0: dependencies: object.assign "^4.1.0" +babel-plugin-dynamic-import-node@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f" + integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ== + dependencies: + object.assign "^4.1.0" + babel-plugin-emotion@^10.0.14: version "10.0.16" resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.16.tgz#cb306798058b102a634ca80e69b012caa345bb09" @@ -3653,6 +4180,11 @@ bluebird@3.5.0: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" integrity sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw= +bluebird@3.7.1, bluebird@^3.5.5: + version "3.7.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" + integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== + bluebird@^3.5.0: version "3.5.5" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" @@ -3663,11 +4195,6 @@ bluebird@^3.5.1, bluebird@^3.5.3: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" integrity sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== -bluebird@^3.5.5: - version "3.7.1" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.1.tgz#df70e302b471d7473489acf26a93d63b53f874de" - integrity sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg== - bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" @@ -4794,7 +5321,7 @@ convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0: dependencies: safe-buffer "~5.1.1" -convert-source-map@^1.6.0: +convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== @@ -5374,15 +5901,7 @@ cypress-plugin-tab@^1.0.1: dependencies: ally.js "^1.4.1" -cypress-testing-library@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/cypress-testing-library/-/cypress-testing-library-3.0.1.tgz#cd5f4ce4423cbb20cafdb869b435b35d01d11b66" - integrity sha512-vpGRbcYS229KP/FOASKQuT717GxpO9mG7rnFz2dOe7sz7JPnIHIP5M3KoPvoLfAN1TictFFv05jndyJi2OLa3A== - dependencies: - "@babel/runtime" "^7.4.3" - dom-testing-library "^4.0.0" - -cypress@^3.6.1: +cypress@^3.5.0, cypress@^3.6.1: version "3.6.1" resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.6.1.tgz#4420957923879f60b7a5146ccbf81841a149b653" integrity sha512-6n0oqENdz/oQ7EJ6IgESNb2M7Bo/70qX9jSJsAziJTC3kICfEMmJUlrAnP9bn+ut24MlXQST5nRXhUP5nRIx6A== @@ -5979,7 +6498,7 @@ debug@3.2.6, debug@^3.1.0, debug@^3.1.1, debug@^3.2.5, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: +debug@4.1.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -6293,16 +6812,6 @@ dom-testing-library@^3.19.0: pretty-format "^24.5.0" wait-for-expect "^1.1.0" -dom-testing-library@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/dom-testing-library/-/dom-testing-library-4.0.1.tgz#f21ef42aea0bd635969b4227a487e4704dbea735" - integrity sha512-Yr0yWlpI2QdTDEgPEk0TEekwP4VyZlJpl9E7nKP2FCKni44cb1jzjsy9KX6hBDsNA7EVlPpq9DHzO2eoEaqDZg== - dependencies: - "@babel/runtime" "^7.4.3" - "@sheerun/mutationobserver-shim" "^0.3.2" - pretty-format "^24.7.0" - wait-for-expect "^1.1.1" - domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" @@ -6589,6 +7098,13 @@ eslint-module-utils@^2.4.0: debug "^2.6.8" pkg-dir "^2.0.0" +eslint-plugin-cypress@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-cypress/-/eslint-plugin-cypress-2.7.0.tgz#117f14ce63698e4c4f3afea3d7e27025c8d504f0" + integrity sha512-52Lq5ePCD/8jc536e1RqtLfj33BAy1s7BlYgCjbG39J5kqUitcTlRY5i3NRoeAyPHueDwETsq0eASF44ugLosQ== + dependencies: + globals "^11.12.0" + eslint-plugin-emotion@^10.0.14: version "10.0.14" resolved "https://registry.yarnpkg.com/eslint-plugin-emotion/-/eslint-plugin-emotion-10.0.14.tgz#c643ff2f34f85ae77a65b2056915e939cf7e8129" @@ -7776,6 +8292,11 @@ globals@^11.1.0, globals@^11.7.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.11.0.tgz#dcf93757fa2de5486fbeed7118538adf789e9c2e" integrity sha512-WHq43gS+6ufNOEqlrDBxVEbb8ntfXrfAUU2ZOpCxrBdGKW3gyv8mCxAfIBD0DroPKGrJ2eSsXsLtY9MPntsyTw== +globals@^11.12.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + globby@*, globby@^9.1.0: version "9.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-9.1.0.tgz#e90f4d5134109e6d855abdd31bdb1b085428592e" @@ -10238,7 +10759,7 @@ lodash.uniq@^4.5.0: resolved "https://botbuilder.myget.org/F/botbuilder-declarative/npm/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@4.17.15, lodash@^4.17.14, lodash@^4.17.15: +lodash@4.17.15, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -12741,6 +13262,16 @@ pretty-format@^24.0.0, pretty-format@^24.7.0: ansi-styles "^3.2.0" react-is "^16.8.4" +pretty-format@^24.3.0, pretty-format@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== + dependencies: + "@jest/types" "^24.9.0" + ansi-regex "^4.0.0" + ansi-styles "^3.2.0" + react-is "^16.8.4" + pretty-format@^24.5.0: version "24.5.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.5.0.tgz#cc69a0281a62cd7242633fc135d6930cd889822d" @@ -13299,6 +13830,13 @@ regenerate-unicode-properties@^8.0.2: dependencies: regenerate "^1.4.0" +regenerate-unicode-properties@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" + integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA== + dependencies: + regenerate "^1.4.0" + regenerate@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" @@ -13368,6 +13906,18 @@ regexpu-core@^4.1.3, regexpu-core@^4.5.4: unicode-match-property-ecmascript "^1.0.4" unicode-match-property-value-ecmascript "^1.1.0" +regexpu-core@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.6.0.tgz#2037c18b327cfce8a6fea2a4ec441f2432afb8b6" + integrity sha512-YlVaefl8P5BnFYOITTNzDvan1ulLOiXJzCNZxduTIosN17b87h3bvG9yHMoHaRuo88H4mQ06Aodj5VtYGGGiTg== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.1.0" + regjsgen "^0.5.0" + regjsparser "^0.6.0" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.1.0" + registry-auth-token@^3.0.1, registry-auth-token@^3.3.2, registry-auth-token@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" @@ -15016,6 +15566,17 @@ ts-loader@^6.0.3: micromatch "^4.0.0" semver "^6.0.0" +ts-loader@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.1.tgz#67939d5772e8a8c6bdaf6277ca023a4812da02ef" + integrity sha512-Dd9FekWuABGgjE1g0TlQJ+4dFUfYGbYcs52/HQObE0ZmUNjQlmLAS7xXsSzy23AMaMwipsx5sNHvoEpT2CZq1g== + dependencies: + chalk "^2.3.0" + enhanced-resolve "^4.0.0" + loader-utils "^1.0.2" + micromatch "^4.0.0" + semver "^6.0.0" + ts-node@^8.4.1: version "8.4.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.4.1.tgz#270b0dba16e8723c9fa4f9b4775d3810fd994b4f" @@ -15520,10 +16081,10 @@ wait-for-expect@^1.1.0: resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-1.1.0.tgz#6607375c3f79d32add35cd2c87ce13f351a3d453" integrity sha512-vQDokqxyMyknfX3luCDn16bSaRcOyH6gGuUXMIbxBLeTo6nWuEWYqMTT9a+44FmW8c2m6TRWBdNvBBjA1hwEKg== -wait-for-expect@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-1.1.1.tgz#9cd10e07d52810af9e0aaf509872e38f3c3d81ae" - integrity sha512-vd9JOqqEcBbCDhARWhW85ecjaEcfBLuXgVBqatfS3iw6oU4kzAcs+sCNjF+TC9YHPImCW7ypsuQc+htscIAQCw== +wait-for-expect@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/wait-for-expect/-/wait-for-expect-3.0.1.tgz#ec204a76b0038f17711e575720aaf28505ac7185" + integrity sha512-3Ha7lu+zshEG/CeHdcpmQsZnnZpPj/UsG3DuKO8FskjuDbkx3jE3845H+CuwZjA2YWYDfKMU2KhnCaXMLd3wVw== walker@~1.0.5: version "1.0.7" From 7e84f05a8295fc0f5ee204558337a20d1bf2e150 Mon Sep 17 00:00:00 2001 From: xieofxie Date: Fri, 22 Nov 2019 16:20:52 +0800 Subject: [PATCH 04/45] add directlinespeech support (#1637) --- BotProject/CSharp/Controllers/BotController.cs | 1 + BotProject/CSharp/Startup.cs | 1 + BotProject/Templates/CSharp/Controllers/BotController.cs | 1 + BotProject/Templates/CSharp/Startup.cs | 1 + 4 files changed, 4 insertions(+) diff --git a/BotProject/CSharp/Controllers/BotController.cs b/BotProject/CSharp/Controllers/BotController.cs index 0b570a99f1..dc1ad5c782 100644 --- a/BotProject/CSharp/Controllers/BotController.cs +++ b/BotProject/CSharp/Controllers/BotController.cs @@ -27,6 +27,7 @@ public BotController(BotManager botManager) } [HttpPost] + [HttpGet] public async Task PostAsync() { // Delegate the processing of the HTTP POST to the adapter. diff --git a/BotProject/CSharp/Startup.cs b/BotProject/CSharp/Startup.cs index aeb49fc25e..12358ce19d 100644 --- a/BotProject/CSharp/Startup.cs +++ b/BotProject/CSharp/Startup.cs @@ -54,6 +54,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) app.UseDefaultFiles(); app.UseStaticFiles(); + app.UseWebSockets(); //app.UseHttpsRedirection(); app.UseMvc(); diff --git a/BotProject/Templates/CSharp/Controllers/BotController.cs b/BotProject/Templates/CSharp/Controllers/BotController.cs index b1b38d5804..5085705abb 100644 --- a/BotProject/Templates/CSharp/Controllers/BotController.cs +++ b/BotProject/Templates/CSharp/Controllers/BotController.cs @@ -30,6 +30,7 @@ public BotController(IBotFrameworkHttpAdapter adapter, IBot bot) } [HttpPost] + [HttpGet] public async Task PostAsync() { // Delegate the processing of the HTTP POST to the adapter. diff --git a/BotProject/Templates/CSharp/Startup.cs b/BotProject/Templates/CSharp/Startup.cs index 172c9aa6f5..5b0d85f24f 100644 --- a/BotProject/Templates/CSharp/Startup.cs +++ b/BotProject/Templates/CSharp/Startup.cs @@ -131,6 +131,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env) app.UseDefaultFiles(); app.UseStaticFiles(); + app.UseWebSockets(); //app.UseHttpsRedirection(); app.UseMvc(); From 4be03bf64c6cd647286d8423535c63cccb5ea47b Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Fri, 22 Nov 2019 13:27:18 -0800 Subject: [PATCH 05/45] ci: include better information in validate-pr action errors (#1634) * add release to valid pr types * add more info to error messages --- .github/actions/conventional-pr/src/utils.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/actions/conventional-pr/src/utils.ts b/.github/actions/conventional-pr/src/utils.ts index fbcbc1f77b..5e76cc4f11 100644 --- a/.github/actions/conventional-pr/src/utils.ts +++ b/.github/actions/conventional-pr/src/utils.ts @@ -14,6 +14,7 @@ const validTypes = [ 'ci', 'chore', 'revert', + 'release', ]; const typeList = validTypes.map(t => ` - ${t}`).join('\n'); @@ -28,22 +29,25 @@ export function validateTitle(title: string): ValidationResult { const hastype = validTypes.some(t => title.startsWith(`${t}: `)); if (!hastype) { - core.info( - `[Title] Missing type in title. Choose from the following:\n${typeList}` + errors.push( + `[Title] Must start with type (ex. 'feat: ').\nThe valid types are:\n${typeList}` ); - errors.push("[Title] Must start with type. i.e. 'feat: '"); } return errors; } const refMatch = /(refs?|close(d|s)?|fix(ed|es)?) \#\d+/i; +const helpLink = + 'https://help.github.com/en/github/managing-your-work-on-github/closing-issues-using-keywords'; export function validateBody(body: string): ValidationResult { let errors: ValidationResult = []; if (!refMatch.test(body)) { - errors.push('[Body] Must reference an issue.'); + errors.push( + `[Body] Must reference an issue (ex. 'fixes #1234').\nSee ${helpLink} for more details.` + ); } return errors; From 190447108d95d1726709bf3cc34a33439929072f Mon Sep 17 00:00:00 2001 From: Pooja Nagpal Date: Fri, 22 Nov 2019 14:29:52 -0800 Subject: [PATCH 06/45] test: allow running composer in hosted mode for tests (#1356) --- .../packages/server/src/models/connector/selfHostConnector.ts | 2 +- Composer/packages/server/src/settings/env.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Composer/packages/server/src/models/connector/selfHostConnector.ts b/Composer/packages/server/src/models/connector/selfHostConnector.ts index a370fcbb57..49af93880c 100644 --- a/Composer/packages/server/src/models/connector/selfHostConnector.ts +++ b/Composer/packages/server/src/models/connector/selfHostConnector.ts @@ -48,7 +48,7 @@ export class SelfHostBotConnector implements IBotConnector { public connect = async (env: BotEnvironments, hostName: string) => { this.status = BotStatus.Connected; const prefix = env === 'production' ? '' : 'integration/'; - const root = hostName ? `https://${hostName}` : absHostRoot; + const root = hostName && hostName !== `localhost` ? `https://${hostName}` : absHostRoot; return Promise.resolve(`${root}/api/${prefix}messages`); }; diff --git a/Composer/packages/server/src/settings/env.ts b/Composer/packages/server/src/settings/env.ts index 05ebdfa285..0fe13fe621 100644 --- a/Composer/packages/server/src/settings/env.ts +++ b/Composer/packages/server/src/settings/env.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -export const absHosted = !!process.env.PUBLIC_URL; +export const absHosted = process.env.COMPOSER_AUTH_PROVIDER === 'abs-h'; export const absHostRoot = process.env.WEBSITE_HOSTNAME ? `https://${process.env.WEBSITE_HOSTNAME}` : 'http://localhost:3978'; From 9e70664aeb350f45ef117590ef28747e608bfc96 Mon Sep 17 00:00:00 2001 From: Long Alan Date: Mon, 25 Nov 2019 13:34:03 +0800 Subject: [PATCH 07/45] fix: support horizontal scrolling in visual eidtor (#1607) * update fabric package * remove extra spacing * remove extra spacing --- .../extensions/obiformeditor/package.json | 2 +- .../extensions/visual-designer/package.json | 2 +- Composer/packages/lib/shared/package.json | 2 +- Composer/yarn.lock | 56 +++++++++++++++++++ 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/Composer/packages/extensions/obiformeditor/package.json b/Composer/packages/extensions/obiformeditor/package.json index 419e102656..9366a3c15e 100644 --- a/Composer/packages/extensions/obiformeditor/package.json +++ b/Composer/packages/extensions/obiformeditor/package.json @@ -34,7 +34,7 @@ "format-message": "^6.2.1", "lodash": "^4.17.15", "nanoid": "^2.0.1", - "office-ui-fabric-react": "7.37.1", + "office-ui-fabric-react": "7.62.0", "react-error-boundary": "^1.2.5" }, "peerDependencies": { diff --git a/Composer/packages/extensions/visual-designer/package.json b/Composer/packages/extensions/visual-designer/package.json index 5fbdf33761..c39739966f 100644 --- a/Composer/packages/extensions/visual-designer/package.json +++ b/Composer/packages/extensions/visual-designer/package.json @@ -31,7 +31,7 @@ "dagre-d3": "^0.6.3", "format-message": "^6.2.1", "lodash": "^4.17.15", - "office-ui-fabric-react": "7.37.1", + "office-ui-fabric-react": "7.62.0", "prop-types": "^15.7.2", "source-map-loader": "^0.2.4" }, diff --git a/Composer/packages/lib/shared/package.json b/Composer/packages/lib/shared/package.json index 6cabe2c1d3..bb5cff12ed 100644 --- a/Composer/packages/lib/shared/package.json +++ b/Composer/packages/lib/shared/package.json @@ -36,7 +36,7 @@ "copyfiles": "^2.1.0", "jest": "24.0.0", "jest-dom": "^3.1.3", - "office-ui-fabric-react": "7.37.1", + "office-ui-fabric-react": "7.62.0", "react": "16.9.0", "react-dom": "16.9.0", "react-testing-library": "^6.0.2", diff --git a/Composer/yarn.lock b/Composer/yarn.lock index fc01994dec..dad6e50189 100644 --- a/Composer/yarn.lock +++ b/Composer/yarn.lock @@ -3075,6 +3075,17 @@ "@uifabric/utilities" "^7.0.9" tslib "^1.7.1" +"@uifabric/foundation@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@uifabric/foundation/-/foundation-7.5.0.tgz#d36f15ef59edeaa8219f2b7d34f74c6d756f6622" + integrity sha512-eymMyV3e+MFCkcfC1AFIAzVP/h6/QvDcYb1l6K3IaG1QG47ZwijJJXseEvNDjimfUiJhez9H7cSsRZPIIJ5MaQ== + dependencies: + "@uifabric/merge-styles" "^7.8.0" + "@uifabric/set-version" "^7.0.2" + "@uifabric/styling" "^7.7.2" + "@uifabric/utilities" "^7.5.0" + tslib "^1.7.1" + "@uifabric/icons@^7.2.1": version "7.2.1" resolved "https://registry.yarnpkg.com/@uifabric/icons/-/icons-7.2.1.tgz#b41f52c3c8443d66c2947f3a0368a8e45f469f9f" @@ -3109,6 +3120,14 @@ "@uifabric/set-version" "^7.0.2" tslib "^1.7.1" +"@uifabric/merge-styles@^7.8.0", "@uifabric/merge-styles@^7.8.1": + version "7.8.1" + resolved "https://registry.yarnpkg.com/@uifabric/merge-styles/-/merge-styles-7.8.1.tgz#b3973eb6942bf5fd1653fb8c2ae349343bacd30d" + integrity sha512-DJBXNsYfrYQ3wCjOE197JqXTkqwfPlGJhQkhYMBwO76ovKBQyJxT8m6NL8og5F9blnIBdCJPrvRUz/21/WlUGg== + dependencies: + "@uifabric/set-version" "^7.0.2" + tslib "^1.7.1" + "@uifabric/react-hooks@^7.0.1": version "7.0.1" resolved "https://registry.yarnpkg.com/@uifabric/react-hooks/-/react-hooks-7.0.1.tgz#aa0e9f17e13def6763de7671bd82210261222591" @@ -3147,6 +3166,17 @@ "@uifabric/utilities" "^7.0.9" tslib "^1.7.1" +"@uifabric/styling@^7.7.2", "@uifabric/styling@^7.7.3": + version "7.7.3" + resolved "https://registry.yarnpkg.com/@uifabric/styling/-/styling-7.7.3.tgz#593dd308dbf4425c1baa9678a553c8494d884448" + integrity sha512-peAAXEfqIXHD1a4GnAA5hs4rv/jgevN2EwJKdlmGv0ecK9kaXl/sgEQEcniV0iBlJffy2OnWRdi8YlZygUxFmA== + dependencies: + "@microsoft/load-themed-styles" "^1.7.13" + "@uifabric/merge-styles" "^7.8.1" + "@uifabric/set-version" "^7.0.2" + "@uifabric/utilities" "^7.5.0" + tslib "^1.7.1" + "@uifabric/utilities@^7.0.10", "@uifabric/utilities@^7.0.9": version "7.0.10" resolved "https://registry.yarnpkg.com/@uifabric/utilities/-/utilities-7.0.10.tgz#cadbc6689c417ec01afc029a2894027bd80215dc" @@ -3167,6 +3197,16 @@ prop-types "^15.5.10" tslib "^1.7.1" +"@uifabric/utilities@^7.5.0", "@uifabric/utilities@^7.6.0": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@uifabric/utilities/-/utilities-7.6.0.tgz#e0a7be2969792f7ef15907744e72bdebbf5ff024" + integrity sha512-umIN2M4Ue1FjqmRv2JVvzXljA/eG5QwoyNi8u2BVfJKXSi2qZ82ey3btV4lCdL2kUo25oXRM1qvaK7416Stdrg== + dependencies: + "@uifabric/merge-styles" "^7.8.1" + "@uifabric/set-version" "^7.0.2" + prop-types "^15.5.10" + tslib "^1.7.1" + "@uifabric/variants@^7.0.5": version "7.0.5" resolved "https://registry.yarnpkg.com/@uifabric/variants/-/variants-7.0.5.tgz#67a5301a8c36bcb2e46c7d86929d58184e37cc2d" @@ -11928,6 +11968,22 @@ office-ui-fabric-react@7.37.1: prop-types "^15.5.10" tslib "^1.7.1" +office-ui-fabric-react@7.62.0: + version "7.62.0" + resolved "https://registry.yarnpkg.com/office-ui-fabric-react/-/office-ui-fabric-react-7.62.0.tgz#3260eaf43d5bfbdefc53fc9ade0470dc51b37412" + integrity sha512-d3UoiBIAdjQeVgxOXCTg97cS8RfasXg5xXgbZBYPv8xv7HxsZ1zabsVqXMl+5TA/vX7rb9hSn6JMscaVWwWaUA== + dependencies: + "@microsoft/load-themed-styles" "^1.7.13" + "@uifabric/foundation" "^7.5.0" + "@uifabric/icons" "^7.3.0" + "@uifabric/merge-styles" "^7.8.1" + "@uifabric/react-hooks" "^7.0.1" + "@uifabric/set-version" "^7.0.2" + "@uifabric/styling" "^7.7.3" + "@uifabric/utilities" "^7.6.0" + prop-types "^15.5.10" + tslib "^1.7.1" + office-ui-fabric-react@^7.29.2: version "7.35.0" resolved "https://registry.yarnpkg.com/office-ui-fabric-react/-/office-ui-fabric-react-7.35.0.tgz#7132cf94bffcf9a9da310bff0e48f63717ae00d9" From fefa1bb0d5fc232534c8df10411ba6821b8fae21 Mon Sep 17 00:00:00 2001 From: Chris Whitten Date: Mon, 25 Nov 2019 08:26:47 -0800 Subject: [PATCH 08/45] chore: bump browserslist (#1645) --- Composer/yarn.lock | 95 +++++++++++----------------------------------- 1 file changed, 22 insertions(+), 73 deletions(-) diff --git a/Composer/yarn.lock b/Composer/yarn.lock index dad6e50189..22d9b50e65 100644 --- a/Composer/yarn.lock +++ b/Composer/yarn.lock @@ -4465,41 +4465,14 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.1.tgz#42e828954b6b29a7a53e352277be429478a69062" - integrity sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A== +browserslist@^4.6.4: + version "4.7.3" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.3.tgz#02341f162b6bcc1e1028e30624815d4924442dc3" + integrity sha512-jWvmhqYpx+9EZm/FxcZSbUZyDEvDTLDi3nSAKbzEkyWvtI0mNSmUosey+5awDW1RUlrgXbQb5A6qY1xQH9U6MQ== dependencies: - caniuse-lite "^1.0.30000929" - electron-to-chromium "^1.3.103" - node-releases "^1.1.3" - -browserslist@^4.0.0, browserslist@^4.3.4, browserslist@^4.3.5, browserslist@^4.4.2, browserslist@^4.5.1: - version "4.5.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.5.2.tgz#36ad281f040af684555a23c780f5c2081c752df0" - integrity sha512-zmJVLiKLrzko0iszd/V4SsjTaomFeoVzQGYYOYgRgsbh7WNh95RgDB0CmBdFWYs/3MyFSt69NypjL/h3iaddKQ== - dependencies: - caniuse-lite "^1.0.30000951" - electron-to-chromium "^1.3.116" - node-releases "^1.1.11" - -browserslist@^4.5.4: - version "4.5.5" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.5.5.tgz#fe1a352330d2490d5735574c149a85bc18ef9b82" - integrity sha512-0QFO1r/2c792Ohkit5XI8Cm8pDtZxgNl2H6HU4mHrpYz7314pEYcsAVVatM0l/YmxPnEzh9VygXouj4gkFUTKA== - dependencies: - caniuse-lite "^1.0.30000960" - electron-to-chromium "^1.3.124" - node-releases "^1.1.14" - -browserslist@^4.6.0: - version "4.6.1" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.1.tgz#ee5059b1aec18cbec9d055d6cb5e24ae50343a9b" - integrity sha512-1MC18ooMPRG2UuVFJTHFIAkk6mpByJfxCrnUyvSlu/hyQSFHMrlhM02SzNuCV+quTP4CKmqtOMAIjrifrpBJXQ== - dependencies: - caniuse-lite "^1.0.30000971" - electron-to-chromium "^1.3.137" - node-releases "^1.1.21" + caniuse-lite "^1.0.30001010" + electron-to-chromium "^1.3.306" + node-releases "^1.1.40" bs-logger@0.x: version "0.2.6" @@ -4775,20 +4748,20 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000918, caniuse-lite@^1.0.30000929, caniuse-lite@^1.0.30000947, caniuse-lite@^1.0.30000951: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000918, caniuse-lite@^1.0.30000947: version "1.0.30000951" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000951.tgz#c7c2fd4d71080284c8677dd410368df8d83688fe" integrity sha512-eRhP+nQ6YUkIcNQ6hnvdhMkdc7n3zadog0KXNRxAZTT2kHjUb1yGn71OrPhSn8MOvlX97g5CR97kGVj8fMsXWg== -caniuse-lite@^1.0.30000957, caniuse-lite@^1.0.30000960: +caniuse-lite@^1.0.30000957: version "1.0.30000960" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000960.tgz#ec48297037e5607f582f246ae7b12bee66a78999" integrity sha512-7nK5qs17icQaX6V3/RYrJkOsZyRNnroA4+ZwxaKJzIKy+crIy0Mz5CBlLySd2SNV+4nbUZeqeNfiaEieUBu3aA== -caniuse-lite@^1.0.30000971: - version "1.0.30000974" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000974.tgz#b7afe14ee004e97ce6dc73e3f878290a12928ad8" - integrity sha512-xc3rkNS/Zc3CmpMKuczWEdY2sZgx09BkAxfvkxlAEBTqcMHeL8QnPqhKse+5sRTi3nrw2pJwToD2WvKn1Uhvww== +caniuse-lite@^1.0.30001010: + version "1.0.30001011" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001011.tgz#0d6c4549c78c4a800bb043a83ca0cbe0aee6c6e1" + integrity sha512-h+Eqyn/YA6o6ZTqpS86PyRmNWOs1r54EBDcd2NTwwfsXQ8re1B38SnB+p2RKF8OUsyEIjeDU8XGec1RGO/wYCg== capture-exit@^2.0.0: version "2.0.0" @@ -6959,20 +6932,10 @@ ejs@^2.7.1: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.1.tgz#5b5ab57f718b79d4aca9254457afecd36fa80228" integrity sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ== -electron-to-chromium@^1.3.103, electron-to-chromium@^1.3.116: - version "1.3.118" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.118.tgz#5c82b0445a40934e6cae9c2f40bfaaa986ea44a3" - integrity sha512-/1FpHvmKmKo2Z6CCza2HfkrKvKhU7Rq4nvyX1FOherdTrdTufhVrJbCrcrIqgqUCI+BG6JC2rlY4z5QA1G0NOw== - -electron-to-chromium@^1.3.124: - version "1.3.124" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.124.tgz#861fc0148748a11b3e5ccebdf8b795ff513fa11f" - integrity sha512-glecGr/kFdfeXUHOHAWvGcXrxNU+1wSO/t5B23tT1dtlvYB26GY8aHzZSWD7HqhqC800Lr+w/hQul6C5AF542w== - -electron-to-chromium@^1.3.137: - version "1.3.148" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.148.tgz#5796c0d9eb0358d397163413b90bf376c5d8bf08" - integrity sha512-nuCOlXNlGMQmdzihIPGm2K3Yf3H1hke/1rK381i02pH8wNliJU9hVNnOi/xjmxt+mjABd/BzufP5nPHWKshLWA== +electron-to-chromium@^1.3.306: + version "1.3.312" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.312.tgz#6ef8700096e4a726b9cd7285523561629fa70e12" + integrity sha512-/Nk6Hvwt+RfS9X3oA4IXpWqpcnS7cdWsTMP4AmrP8hPpxtZbHemvTEYzjAKghk28aS9zIV8NwGHNt8H+6OmJug== elegant-spinner@^1.0.1: version "1.0.1" @@ -11681,26 +11644,12 @@ node-pre-gyp@^0.12.0: semver "^5.3.0" tar "^4" -node-releases@^1.1.11, node-releases@^1.1.3: - version "1.1.11" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.11.tgz#9a0841a4b0d92b7d5141ed179e764f42ad22724a" - integrity sha512-8v1j5KfP+s5WOTa1spNUAOfreajQPN12JXbRR0oDE+YrJBQCXBnNqUDj27EKpPLOoSiU3tKi3xGPB+JaOdUEQQ== +node-releases@^1.1.40: + version "1.1.41" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.41.tgz#57674a82a37f812d18e3b26118aefaf53a00afed" + integrity sha512-+IctMa7wIs8Cfsa8iYzeaLTFwv5Y4r5jZud+4AnfymzeEXKBCavFX0KBgzVaPVqf0ywa6PrO8/b+bPqdwjGBSg== dependencies: - semver "^5.3.0" - -node-releases@^1.1.14: - version "1.1.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.14.tgz#f1f41c83cac82caebd6739e6313d56b3b09c9189" - integrity sha512-d58EpVZRhQE60kWiWUaaPlK9dyC4zg3ZoMcHcky2d4hDksyQj0rUozwInOl0C66mBsqo01Tuns8AvxnL5S7PKg== - dependencies: - semver "^5.3.0" - -node-releases@^1.1.21: - version "1.1.23" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.23.tgz#de7409f72de044a2fa59c097f436ba89c39997f0" - integrity sha512-uq1iL79YjfYC0WXoHbC/z28q/9pOl8kSHaXdWmAAc8No+bDwqkZbzIJz55g/MUsPgSGm9LZ7QSUbzTcH5tz47w== - dependencies: - semver "^5.3.0" + semver "^6.3.0" nodemon@^1.18.11: version "1.18.11" From 1f9bd354d8bf8f820f6b3b3e0cfd963f6fb5b922 Mon Sep 17 00:00:00 2001 From: Chris Whitten Date: Mon, 25 Nov 2019 08:48:56 -0800 Subject: [PATCH 09/45] chore: reduce form width to 400px (#1648) --- Composer/packages/client/src/pages/design/styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Composer/packages/client/src/pages/design/styles.js b/Composer/packages/client/src/pages/design/styles.js index 52a58396da..d957313784 100644 --- a/Composer/packages/client/src/pages/design/styles.js +++ b/Composer/packages/client/src/pages/design/styles.js @@ -78,7 +78,7 @@ export const visualEditor = css` `; export const formEditor = css` - max-width: 600px; + max-width: 400px; flex: 1; border: 0px; transition: width 0.2s ease-in-out; From 49b49977a6145253afd25b150ccd17791cd3385f Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Mon, 25 Nov 2019 10:40:17 -0800 Subject: [PATCH 10/45] add browserslist to dependencies (#1656) --- Composer/packages/client/package.json | 1 + Composer/yarn.lock | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Composer/packages/client/package.json b/Composer/packages/client/package.json index 7f0d60486d..3a540e1976 100644 --- a/Composer/packages/client/package.json +++ b/Composer/packages/client/package.json @@ -67,6 +67,7 @@ "babel-plugin-named-asset-import": "^0.3.1", "babel-preset-react-app": "^7.0.1", "bfj": "6.1.1", + "browserslist": "^4.7.3", "case-sensitive-paths-webpack-plugin": "2.2.0", "css-loader": "3.2.0", "dotenv": "6.0.0", diff --git a/Composer/yarn.lock b/Composer/yarn.lock index 22d9b50e65..c1d16c38ed 100644 --- a/Composer/yarn.lock +++ b/Composer/yarn.lock @@ -4465,7 +4465,16 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.6.4: +browserslist@4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.4.1.tgz#42e828954b6b29a7a53e352277be429478a69062" + integrity sha512-pEBxEXg7JwaakBXjATYw/D1YZh4QUSCX/Mnd/wnqSRPPSi1U39iDhDoKGoBUcraKdxDlrYqJxSI5nNvD+dWP2A== + dependencies: + caniuse-lite "^1.0.30000929" + electron-to-chromium "^1.3.103" + node-releases "^1.1.3" + +browserslist@^4.0.0, browserslist@^4.3.4, browserslist@^4.3.5, browserslist@^4.4.2, browserslist@^4.5.1, browserslist@^4.5.4, browserslist@^4.6.0, browserslist@^4.7.3: version "4.7.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.3.tgz#02341f162b6bcc1e1028e30624815d4924442dc3" integrity sha512-jWvmhqYpx+9EZm/FxcZSbUZyDEvDTLDi3nSAKbzEkyWvtI0mNSmUosey+5awDW1RUlrgXbQb5A6qY1xQH9U6MQ== @@ -4753,6 +4762,11 @@ caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000918, caniuse-lite@^1.0.30000947: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000951.tgz#c7c2fd4d71080284c8677dd410368df8d83688fe" integrity sha512-eRhP+nQ6YUkIcNQ6hnvdhMkdc7n3zadog0KXNRxAZTT2kHjUb1yGn71OrPhSn8MOvlX97g5CR97kGVj8fMsXWg== +caniuse-lite@^1.0.30000929: + version "1.0.30001012" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz#653ec635e815b9e0fb801890923b0c2079eb34ec" + integrity sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg== + caniuse-lite@^1.0.30000957: version "1.0.30000960" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000960.tgz#ec48297037e5607f582f246ae7b12bee66a78999" @@ -6932,6 +6946,11 @@ ejs@^2.7.1: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.1.tgz#5b5ab57f718b79d4aca9254457afecd36fa80228" integrity sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ== +electron-to-chromium@^1.3.103: + version "1.3.314" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.314.tgz#c186a499ed2c9057bce9eb8dca294d6d5450facc" + integrity sha512-IKDR/xCxKFhPts7h+VaSXS02Z1mznP3fli1BbXWXeN89i2gCzKraU8qLpEid8YzKcmZdZD3Mly3cn5/lY9xsBQ== + electron-to-chromium@^1.3.306: version "1.3.312" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.312.tgz#6ef8700096e4a726b9cd7285523561629fa70e12" @@ -11644,7 +11663,7 @@ node-pre-gyp@^0.12.0: semver "^5.3.0" tar "^4" -node-releases@^1.1.40: +node-releases@^1.1.3, node-releases@^1.1.40: version "1.1.41" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.41.tgz#57674a82a37f812d18e3b26118aefaf53a00afed" integrity sha512-+IctMa7wIs8Cfsa8iYzeaLTFwv5Y4r5jZud+4AnfymzeEXKBCavFX0KBgzVaPVqf0ywa6PrO8/b+bPqdwjGBSg== From b2faf6a543f5eb4c15b0189098fa1e5e1673aab8 Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Mon, 25 Nov 2019 11:29:44 -0800 Subject: [PATCH 11/45] ci: do not fail CI if coveralls step fails (#1655) * ci: do not fail CI if coveralls step fails * revert yarn.lock changes --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8bcfa37e0c..15d9d221b0 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -44,6 +44,7 @@ jobs: working-directory: Composer - name: Coveralls uses: coverallsapp/github-action@master + continue-on-error: true with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: ./Composer/coverage/lcov.info From 01d70e4757d8dbe3115a2c6430e38ff6e2227d46 Mon Sep 17 00:00:00 2001 From: Long Alan Date: Tue, 26 Nov 2019 04:18:23 +0800 Subject: [PATCH 12/45] fix: dialog name incorrect when creating new dialog in form editor (#1605) * fix #1144 * fix flicker when jumping into the new dialog * do not render dialog when hidden * invoke onCreateDialogComplete callback async * delay navigation by 500ms after creating dialog from form * convert dialog wrapper and new dialog modal to typescript * set up tests to allow for `@app` path mapping * add test for dialog wrapper --- .../components/DialogWrapper/index.test.tsx | 20 +++++++++++++++++++ Composer/packages/client/jest.config.js | 2 ++ .../DialogWrapper/{index.js => index.tsx} | 19 ++++++++++++++---- .../DialogWrapper/{styles.js => styles.ts} | 4 +++- .../client/src/pages/design/index.tsx | 2 +- ...w-dialog-modal.js => new-dialog-modal.tsx} | 13 ++++++++++-- .../client/src/store/action/dialog.ts | 3 +-- Composer/packages/client/tsconfig.json | 4 ++++ .../src/Form/widgets/DialogSelectWidget.tsx | 2 +- 9 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 Composer/packages/client/__tests__/components/DialogWrapper/index.test.tsx rename Composer/packages/client/src/components/DialogWrapper/{index.js => index.tsx} (60%) rename Composer/packages/client/src/components/DialogWrapper/{styles.js => styles.ts} (67%) rename Composer/packages/client/src/pages/design/{new-dialog-modal.js => new-dialog-modal.tsx} (65%) diff --git a/Composer/packages/client/__tests__/components/DialogWrapper/index.test.tsx b/Composer/packages/client/__tests__/components/DialogWrapper/index.test.tsx new file mode 100644 index 0000000000..5c2f3a13bb --- /dev/null +++ b/Composer/packages/client/__tests__/components/DialogWrapper/index.test.tsx @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import React from 'react'; +import { render } from 'react-testing-library'; +import { DialogWrapper } from '@app/components/DialogWrapper'; + +describe('', () => { + const props = { + isOpen: true, + title: 'My Dialog', + subText: 'Create new dialog', + onDismiss: jest.fn(), + }; + + it('renders null when not open', () => { + const { container } = render(); + expect(container.hasChildNodes()).toBeFalsy(); + }); +}); diff --git a/Composer/packages/client/jest.config.js b/Composer/packages/client/jest.config.js index e89860abc6..7b7eb814eb 100644 --- a/Composer/packages/client/jest.config.js +++ b/Composer/packages/client/jest.config.js @@ -14,6 +14,8 @@ module.exports = { // use commonjs modules for test so they do not need to be compiled 'office-ui-fabric-react/lib/(.*)$': 'office-ui-fabric-react/lib-commonjs/$1', '@uifabric/fluent-theme/lib/(.*)$': '@uifabric/fluent-theme/lib-commonjs/$1', + + '^@app/(.*)$': '/src/$1', }, testPathIgnorePatterns: ['/node_modules/', '/jestMocks/', '/testUtils/'], // Some node modules are packaged and distributed in a non-transpiled form diff --git a/Composer/packages/client/src/components/DialogWrapper/index.js b/Composer/packages/client/src/components/DialogWrapper/index.tsx similarity index 60% rename from Composer/packages/client/src/components/DialogWrapper/index.js rename to Composer/packages/client/src/components/DialogWrapper/index.tsx index ea6839d508..d0ba28e344 100644 --- a/Composer/packages/client/src/components/DialogWrapper/index.js +++ b/Composer/packages/client/src/components/DialogWrapper/index.tsx @@ -2,15 +2,26 @@ // Licensed under the MIT License. import React from 'react'; -import { Dialog, DialogType } from 'office-ui-fabric-react/lib/Dialog'; +import { Dialog, DialogType, IDialogProps } from 'office-ui-fabric-react/lib/Dialog'; import { styles } from './styles'; -export function DialogWrapper(props) { +interface DialogWrapperProps extends Pick { + isOpen: boolean; + title: string; + subText: string; +} + +export const DialogWrapper: React.FC = props => { const { isOpen, onDismiss, title, subText, children } = props; + + if (!isOpen) { + return null; + } + return ( ); -} +}; + +export default NewDialogModal; diff --git a/Composer/packages/client/src/store/action/dialog.ts b/Composer/packages/client/src/store/action/dialog.ts index b0e0b5a6fa..9809e26c9d 100644 --- a/Composer/packages/client/src/store/action/dialog.ts +++ b/Composer/packages/client/src/store/action/dialog.ts @@ -59,7 +59,7 @@ export const createDialogBase: ActionCreator = async (store, { id, content }) => const response = await httpClient.post(`/projects/opened/dialogs`, { id, content }); const onCreateDialogComplete = store.getState().onCreateDialogComplete; if (typeof onCreateDialogComplete === 'function') { - onCreateDialogComplete(id); + setTimeout(() => onCreateDialogComplete(id)); } store.dispatch({ type: ActionTypes.CREATE_DIALOG_SUCCESS, @@ -67,7 +67,6 @@ export const createDialogBase: ActionCreator = async (store, { id, content }) => response, }, }); - navTo(store, id); } catch (err) { setError(store, { message: err.response && err.response.data.message ? err.response.data.message : err, diff --git a/Composer/packages/client/tsconfig.json b/Composer/packages/client/tsconfig.json index 42032f429e..9cfb8edcfe 100644 --- a/Composer/packages/client/tsconfig.json +++ b/Composer/packages/client/tsconfig.json @@ -4,6 +4,10 @@ "allowJs": true, "declaration": false, "module": "esnext", + "baseUrl": ".", + "paths": { + "@app/*": ["src/*"] + } }, "include": ["./src/**/*", "./__tests__/**/*"], } diff --git a/Composer/packages/extensions/obiformeditor/src/Form/widgets/DialogSelectWidget.tsx b/Composer/packages/extensions/obiformeditor/src/Form/widgets/DialogSelectWidget.tsx index a9a36453bb..a625c6148d 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/widgets/DialogSelectWidget.tsx +++ b/Composer/packages/extensions/obiformeditor/src/Form/widgets/DialogSelectWidget.tsx @@ -51,7 +51,7 @@ export const DialogSelectWidget: React.FC = props => { formContext.shellApi.createDialog().then(newDialog => { if (newDialog) { onChange(newDialog); - setComboboxTitle(newDialog); + setTimeout(() => formContext.shellApi.navTo(newDialog), 500); } else { setComboboxTitle(null); } From 32ce9096fac98f4efafbe482f1ccbd0d40ee60e3 Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Mon, 25 Nov 2019 16:20:52 -0800 Subject: [PATCH 13/45] ci: run cypress in single job for now (#1658) * run cypress in single job for now * remove cli flags * do not fail build if cypress artifacts are not present --- Composer/scripts/e2e.sh | 2 +- azure-pipelines.yml | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Composer/scripts/e2e.sh b/Composer/scripts/e2e.sh index 2b9ccc2c27..148fac5b2e 100755 --- a/Composer/scripts/e2e.sh +++ b/Composer/scripts/e2e.sh @@ -5,7 +5,7 @@ set -e yarn start & SERVER_PID=$! -npx cypress run --browser chrome --record --parallel --ci-build-id $BUILD_BUILDNUMBER --group "Azure CI" +npx cypress run --browser chrome cleanup function cleanup { diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 25b9d4f8cc..5cbf7b7cae 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,8 +13,9 @@ variables: jobs: - job: e2e displayName: End-to-End Tests - strategy: - parallel: 4 + # re-enable once we upgrade our subscription to cypress + # strategy: + # parallel: 4 pool: vmImage: ubuntu-latest @@ -46,7 +47,15 @@ jobs: workingDirectory: Composer continueOnError: true env: - CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) + # CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) CYPRESS_VIDEO: true - CYPRESS_VIDEO_UPLOAD_ON_PASSES: true + # CYPRESS_VIDEO_UPLOAD_ON_PASSES: true + CYPRESS_SCREENSHOTS_FOLDER: $(Build.ArtifactStagingDirectory)/cypress/screenshots + CYPRESS_VIDEOS_FOLDER: $(Build.ArtifactStagingDirectory)/cypress/videos TERM: xterm + - task: PublishPipelineArtifact@1 + condition: in(variables['Agent.JobStatus'], 'SucceededWithIssues', 'Failed') + continueOnError: true + inputs: + targetPath: $(Build.ArtifactStagingDirectory)/cypress + artifactName: e2e From 6c8b9cf34b879dfd1973e27dac73d17d59eb6a2f Mon Sep 17 00:00:00 2001 From: liweitian Date: Wed, 27 Nov 2019 03:22:29 +0800 Subject: [PATCH 14/45] feat: support default path environment variable (#1652) * save tmp code * save tmp code * save current path in data.json * initialize default path according to OS * use default path if current path does not work * fix bug about updating last accessed path * create default folder * handle comments * handle comments * fix lint error * fix test case * fix test case * merge data.json and data.template.json and support defautlpath environment variable * resolve default path * use warped path utility * remove console.log * fix bug * fix bug when user set default path as D: rather than D:/ * add debug logger * add COMPOSER_BOTS_FOLDER to env settings * resolve default path in settings * log all settings in debug mode * use default path from settings * move setting default bots folder to settings * run migrations on start up * use TestBots directory for e2e tests * create COMPOSER_BOTS_FOLDER if it doesn't exist * use debug log when creating new bots * fix bugs * fix issue accessing defaultFolder from development settings add interface for settings to catch this at compile time --- Composer/.gitignore | 2 + Composer/package.json | 2 +- .../LocationBrowser/LocationSelectContent.tsx | 10 ++-- .../client/src/store/action/storage.ts | 4 ++ .../server/__tests__/services/project.test.ts | 1 + .../server/__tests__/services/storage.test.ts | 1 + .../server/src/controllers/project.ts | 8 +-- .../server/src/controllers/storage.ts | 6 +++ Composer/packages/server/src/logger.ts | 6 +++ Composer/packages/server/src/router/api.ts | 1 + .../packages/server/src/services/storage.ts | 30 ++++++++++- Composer/packages/server/src/settings/env.ts | 7 +++ .../packages/server/src/settings/index.ts | 19 +++++-- .../server/src/settings/settings.json | 12 ----- .../packages/server/src/settings/settings.ts | 21 ++++++++ .../server/src/store/data.template.ts | 5 +- .../packages/server/src/store/migrations.ts | 54 +++++++++++++++++++ Composer/packages/server/src/store/store.ts | 27 ++++++---- .../packages/server/src/utility/storage.ts | 6 +-- azure-pipelines.yml | 1 + 20 files changed, 177 insertions(+), 46 deletions(-) create mode 100644 Composer/packages/server/src/logger.ts delete mode 100644 Composer/packages/server/src/settings/settings.json create mode 100644 Composer/packages/server/src/settings/settings.ts create mode 100644 Composer/packages/server/src/store/migrations.ts diff --git a/Composer/.gitignore b/Composer/.gitignore index 51892b75d0..1603d74bba 100644 --- a/Composer/.gitignore +++ b/Composer/.gitignore @@ -4,3 +4,5 @@ junit.xml cypress/screenshots cypress/results cypress/videos + +TestBots/ diff --git a/Composer/package.json b/Composer/package.json index d269fc9fbe..ac6795cb0c 100644 --- a/Composer/package.json +++ b/Composer/package.json @@ -31,7 +31,7 @@ "test:coverage": "yarn test --coverage --no-cache --reporters=default", "test:integration": "cypress run --browser chrome", "test:integration:open": "cypress open", - "test:integration:clean": "rimraf ../MyBots/__Test* packages/server/data.json", + "test:integration:clean": "rimraf TestBots/*", "lint": "wsrun --exclude-missing --collect-logs --report lint", "lint:fix": "wsrun --exclude-missing --collect-logs --report lint:fix", "typecheck": "concurrently --kill-others-on-fail \"npm:typecheck:*\"", diff --git a/Composer/packages/client/src/CreationFlow/LocationBrowser/LocationSelectContent.tsx b/Composer/packages/client/src/CreationFlow/LocationBrowser/LocationSelectContent.tsx index a172cc6a5f..b8dad48093 100644 --- a/Composer/packages/client/src/CreationFlow/LocationBrowser/LocationSelectContent.tsx +++ b/Composer/packages/client/src/CreationFlow/LocationBrowser/LocationSelectContent.tsx @@ -7,14 +7,10 @@ import path from 'path'; import { jsx } from '@emotion/core'; import { Fragment, useEffect, useState, useContext, useRef } from 'react'; -import storage from '../../utils/storage'; - import { FileSelector } from './FileSelector'; import { StoreContext } from './../../store'; import { FileTypes } from './../../constants'; -const NEW_BOT_LOCATION_KEY = 'newBotLocation'; - export function LocationSelectContent(props) { const { state, actions } = useContext(StoreContext); const { storages, focusedStorageFolder, storageFileLoadingStatus } = state; @@ -22,7 +18,7 @@ export function LocationSelectContent(props) { const { fetchFolderItemsByPath } = actions; const currentStorageIndex = useRef(0); - const [currentPath, setCurrentPath] = useState(storage.get(NEW_BOT_LOCATION_KEY, '')); + const [currentPath, setCurrentPath] = useState(''); const currentStorageId = storages[currentStorageIndex.current] ? storages[currentStorageIndex.current].id : 'default'; useEffect(() => { @@ -39,6 +35,7 @@ export function LocationSelectContent(props) { // const formatedPath = path.normalize(newPath.replace(/\\/g, '/')); const formatedPath = path.normalize(newPath); await fetchFolderItemsByPath(storageId, formatedPath); + await actions.updateCurrentPath(formatedPath); setCurrentPath(formatedPath); } }; @@ -48,7 +45,7 @@ export function LocationSelectContent(props) { let path = currentPath; let id = ''; if (storages[index]) { - path = path || storages[index].path; + path = storages[index].path; id = storages[index].id; } updateCurrentPath(path, id); @@ -58,7 +55,6 @@ export function LocationSelectContent(props) { if (onChange) { onChange(currentPath); } - storage.set(NEW_BOT_LOCATION_KEY, currentPath); }, [currentPath]); const onSelectionChanged = item => { diff --git a/Composer/packages/client/src/store/action/storage.ts b/Composer/packages/client/src/store/action/storage.ts index 8cbb1f0cbc..13ef23ca4c 100644 --- a/Composer/packages/client/src/store/action/storage.ts +++ b/Composer/packages/client/src/store/action/storage.ts @@ -93,3 +93,7 @@ export const fetchFolderItemsByPath: ActionCreator = async ({ dispatch }, id, pa }); } }; + +export const updateCurrentPath: ActionCreator = async ({ dispatch }, path) => { + await httpClient.put(`/storages/currentPath`, { path: path }); +}; diff --git a/Composer/packages/server/__tests__/services/project.test.ts b/Composer/packages/server/__tests__/services/project.test.ts index cbca239796..1e89ca3385 100644 --- a/Composer/packages/server/__tests__/services/project.test.ts +++ b/Composer/packages/server/__tests__/services/project.test.ts @@ -16,6 +16,7 @@ jest.mock('../../src/store/store', () => { name: 'This PC', type: 'LocalDisk', path: '.', + defaultPath: '.', }, ], recentBotProjects: [] as any[], diff --git a/Composer/packages/server/__tests__/services/storage.test.ts b/Composer/packages/server/__tests__/services/storage.test.ts index 1e507c1157..b93b445482 100644 --- a/Composer/packages/server/__tests__/services/storage.test.ts +++ b/Composer/packages/server/__tests__/services/storage.test.ts @@ -24,6 +24,7 @@ jest.mock('../../src/store/store', () => { name: 'This PC', type: 'LocalDisk', path: '.', + defaultPath: '.', }, ]; return { diff --git a/Composer/packages/server/src/controllers/project.ts b/Composer/packages/server/src/controllers/project.ts index 4cc95230ca..7753fbdc84 100644 --- a/Composer/packages/server/src/controllers/project.ts +++ b/Composer/packages/server/src/controllers/project.ts @@ -9,7 +9,7 @@ import { BotProjectService } from '../services/project'; import AssectService from '../services/asset'; import { LocationRef } from '../models/bot/interface'; import StorageService from '../services/storage'; -import settings from '../settings/settings.json'; +import settings from '../settings'; import { Path } from './../utility/path'; @@ -21,7 +21,7 @@ async function createProject(req: Request, res: Response) { } // default the path to the default folder. - let path = settings.development.defaultFolder; + let path = settings.botsFolder; // however, if path is specified as part of post body, use that one. // this allows developer to specify a custom home for their bot. if (location) { @@ -116,7 +116,7 @@ async function saveProjectAs(req: Request, res: Response) { const locationRef: LocationRef = { storageId, - path: Path.resolve(settings.development.defaultFolder, name), + path: Path.resolve(settings.botsFolder, name), }; try { @@ -352,7 +352,7 @@ async function publishLuis(req: Request, res: Response) { async function getAllProjects(req: Request, res: Response) { const storageId = 'default'; - const folderPath = Path.resolve(settings.development.defaultFolder); + const folderPath = Path.resolve(settings.botsFolder); try { res.status(200).json(await StorageService.getBlob(storageId, folderPath)); } catch (e) { diff --git a/Composer/packages/server/src/controllers/storage.ts b/Composer/packages/server/src/controllers/storage.ts index 33f1ee4515..a5249252ed 100644 --- a/Composer/packages/server/src/controllers/storage.ts +++ b/Composer/packages/server/src/controllers/storage.ts @@ -15,6 +15,11 @@ function createStorageConnection(req: Request, res: Response) { res.status(200).json(StorageService.getStorageConnections()); } +function updateCurrentPath(req: Request, res: Response) { + StorageService.updateCurrentPath(req.body.path); + res.status(200).json('success'); +} + async function getBlob(req: Request, res: Response) { const storageId = req.params.storageId; const reqpath = decodeURI(req.params.path); @@ -34,4 +39,5 @@ export const StorageController = { getStorageConnections, createStorageConnection, getBlob, + updateCurrentPath, }; diff --git a/Composer/packages/server/src/logger.ts b/Composer/packages/server/src/logger.ts new file mode 100644 index 0000000000..124db0d707 --- /dev/null +++ b/Composer/packages/server/src/logger.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import debug from 'debug'; + +export default debug('composer'); diff --git a/Composer/packages/server/src/router/api.ts b/Composer/packages/server/src/router/api.ts index ac359258c3..4a829acc1a 100644 --- a/Composer/packages/server/src/router/api.ts +++ b/Composer/packages/server/src/router/api.ts @@ -32,6 +32,7 @@ router.post('/projects/opened/project/saveAs', ProjectController.saveProjectAs); router.get('/projects/recent', ProjectController.getRecentProjects); // storages +router.put('/storages/currentPath', StorageController.updateCurrentPath); router.get('/storages', StorageController.getStorageConnections); router.post('/storages', StorageController.createStorageConnection); router.get('/storages/:storageId/blobs/:path(*)', StorageController.getBlob); diff --git a/Composer/packages/server/src/services/storage.ts b/Composer/packages/server/src/services/storage.ts index 29c84cf788..d38ee66fab 100644 --- a/Composer/packages/server/src/services/storage.ts +++ b/Composer/packages/server/src/services/storage.ts @@ -18,6 +18,7 @@ class StorageService { constructor() { this.storageConnections = Store.get(this.STORE_KEY); + this.ensureDefaultBotFoldersExist(); } public getStorageClient = (storageId: string): IFileStorage => { @@ -39,11 +40,18 @@ class StorageService { }; public getStorageConnections = (): StorageConnection[] => { - return this.storageConnections.map(s => { + const connections = this.storageConnections.map(s => { const temp = Object.assign({}, s); - temp.path = Path.resolve(s.path); // resolve path if path is relative, and change it to unix pattern + // if the last accessed path exist + if (fs.existsSync(s.path)) { + temp.path = Path.resolve(s.path); // resolve path if path is relative, and change it to unix pattern + } else { + temp.path = Path.resolve(s.defaultPath); + } return temp; }); + this.ensureDefaultBotFoldersExist(); + return connections; }; public checkBlob = async (storageId: string, filePath: string): Promise => { @@ -85,6 +93,17 @@ class StorageService { } }; + public updateCurrentPath = (path: string) => { + this.storageConnections[0].path = path; + Store.set(this.STORE_KEY, this.storageConnections); + }; + + private ensureDefaultBotFoldersExist = () => { + this.storageConnections.forEach(s => { + this.createFolderRecurively(s.defaultPath); + }); + }; + private isBotFolder = (path: string) => { // locate Main.dialog const mainPath = Path.join(path, 'ComposerDialogs/Main', 'Main.dialog'); @@ -119,6 +138,13 @@ class StorageService { const result = await Promise.all(children); return result.filter(item => !!item); }; + + private createFolderRecurively = (path: string) => { + if (!fs.existsSync(path)) { + this.createFolderRecurively(Path.dirname(path)); + fs.mkdirSync(path); + } + }; } const service = new StorageService(); diff --git a/Composer/packages/server/src/settings/env.ts b/Composer/packages/server/src/settings/env.ts index 0fe13fe621..fb7b623929 100644 --- a/Composer/packages/server/src/settings/env.ts +++ b/Composer/packages/server/src/settings/env.ts @@ -5,3 +5,10 @@ export const absHosted = process.env.COMPOSER_AUTH_PROVIDER === 'abs-h'; export const absHostRoot = process.env.WEBSITE_HOSTNAME ? `https://${process.env.WEBSITE_HOSTNAME}` : 'http://localhost:3978'; + +let folder = process.env.COMPOSER_BOTS_FOLDER; +if (folder && folder.endsWith(':')) { + folder = folder + '/'; +} + +export const botsFolder = folder; diff --git a/Composer/packages/server/src/settings/index.ts b/Composer/packages/server/src/settings/index.ts index 9d6f9151b4..2b5db176c4 100644 --- a/Composer/packages/server/src/settings/index.ts +++ b/Composer/packages/server/src/settings/index.ts @@ -3,17 +3,28 @@ import merge from 'lodash/merge'; -import settings from './settings.json'; +import log from '../logger'; + +import settings from './settings'; // overall the guidance in settings.json is to list every item in "development" // section with a default value, and override the value for different environment // in later sections +interface Settings { + botAdminEndpoint: string; + botEndpoint: string; + assetsLibray: string; + runtimeFolder: string; + botsFolder: string; +} + const defaultSettings = settings.development; const environment = process.env.NODE_ENV || 'development'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const environmentSettings = (settings as any)[environment]; +const environmentSettings = settings[environment]; + +const finalSettings = merge(defaultSettings, environmentSettings); -const finalSettings = merge(defaultSettings, environmentSettings); +log('App Settings: %O', finalSettings); export default finalSettings; diff --git a/Composer/packages/server/src/settings/settings.json b/Composer/packages/server/src/settings/settings.json deleted file mode 100644 index 3c40395d5e..0000000000 --- a/Composer/packages/server/src/settings/settings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "development": { - "botAdminEndpoint": "http://localhost:3979", - "botEndpoint": "http://localhost:3979", - "assetsLibray": "./assets", - "runtimeFolder": "../../../BotProject/Templates", - "defaultFolder": "../../../MyBots" - }, - "container": { - "botAdminEndpoint": "http://botruntime:80" - } -} \ No newline at end of file diff --git a/Composer/packages/server/src/settings/settings.ts b/Composer/packages/server/src/settings/settings.ts new file mode 100644 index 0000000000..618f8b110b --- /dev/null +++ b/Composer/packages/server/src/settings/settings.ts @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import os from 'os'; + +import { Path } from '../utility/path'; + +import { botsFolder } from './env'; + +export default { + development: { + botAdminEndpoint: 'http://localhost:3979', + botEndpoint: 'http://localhost:3979', + assetsLibray: Path.resolve('./assets'), + runtimeFolder: Path.resolve('../../../BotProject/Templates'), + botsFolder: botsFolder || Path.join(os.homedir(), 'Documents', 'Composer'), + }, + container: { + botAdminEndpoint: 'http://botruntime:80', + }, +}; diff --git a/Composer/packages/server/src/store/data.template.ts b/Composer/packages/server/src/store/data.template.ts index 9bd5830cdc..4b5a090d31 100644 --- a/Composer/packages/server/src/store/data.template.ts +++ b/Composer/packages/server/src/store/data.template.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import path from 'path'; +import settings from '../settings'; export default { storageConnections: [ @@ -9,7 +9,8 @@ export default { id: 'default', name: 'This PC', type: 'LocalDisk', - path: path.resolve(__dirname, '../../../../../MyBots'), + path: '', // this is used as last accessed path, if it is invalid, use defaultPath + defaultPath: settings.botsFolder, }, ], recentBotProjects: [], diff --git a/Composer/packages/server/src/store/migrations.ts b/Composer/packages/server/src/store/migrations.ts new file mode 100644 index 0000000000..286148eeb6 --- /dev/null +++ b/Composer/packages/server/src/store/migrations.ts @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import get from 'lodash/get'; +import set from 'lodash/set'; + +import log from '../logger'; +import settings from '../settings'; + +interface Migration { + /** + * Migration label. Will be printed to the console in debug. + * @example 'Update Designer to Composer' + */ + name: string; + /** + * Use to check if a condition exists that requires migration. + * @example data => data.name === 'Designer'; + */ + condition: (data: any) => boolean; + /** + * Data transform to run if condition is met. + * @example data => ({ ...data, name: 'Composer' }); + */ + run: (data: any) => any; +} + +const migrations: Migration[] = [ + { + name: 'Add defaultPath', + condition: data => get(data, 'storageConnections.0.defaultPath') !== settings.botsFolder, + run: data => set(data, 'storageConnections[0].defaultPath', settings.botsFolder), + }, +]; + +export function runMigrations(initialData: any): any { + const migrationsToRun: Migration[] = migrations.filter(m => m.condition(initialData)); + if (migrationsToRun.length > 0) { + log('migration: running migrations...'); + + const data = migrationsToRun.reduce((data, m, i) => { + log('migration: %s (%d / %d)', m.name, i + 1, migrationsToRun.length); + return m.run(data); + }, initialData); + + log('migration: done!'); + + return data; + } + + return initialData; +} diff --git a/Composer/packages/server/src/store/store.ts b/Composer/packages/server/src/store/store.ts index d1eb6c55eb..b8af7d62ec 100644 --- a/Composer/packages/server/src/store/store.ts +++ b/Composer/packages/server/src/store/store.ts @@ -4,25 +4,32 @@ import fs from 'fs'; import path from 'path'; +import log from '../logger'; + import localInitData from './data.template'; import abhInitData from './abh-template.json'; - +import { runMigrations } from './migrations'; const isHostedInAzure = !!process.env.WEBSITE_NODE_DEFAULT_VERSION; const dataStorePath = isHostedInAzure && process.env.HOME ? path.resolve(process.env.HOME, './site/data.json') : path.resolve(__dirname, '../../data.json'); -const initData = isHostedInAzure ? abhInitData : localInitData; +let initData = isHostedInAzure ? abhInitData : localInitData; -// create data.json if not exits -if (!fs.existsSync(dataStorePath)) { - fs.writeFileSync(dataStorePath, JSON.stringify(initData, null, 2) + '\n'); - if (isHostedInAzure) { - // for some very odd reason on Azure webapp, fs.readFileSync after writeFileSync doesn't - // always find the file, add one more io to kick the virtual file system - fs.appendFileSync(dataStorePath, ' '); - } +if (fs.existsSync(dataStorePath)) { + const userData = JSON.parse(fs.readFileSync(dataStorePath, 'utf-8')); + initData = runMigrations(userData); +} else { + log('Database not found. Seeding data.json with: %O', initData); +} + +fs.writeFileSync(dataStorePath, JSON.stringify(initData, null, 2) + '\n'); + +if (isHostedInAzure) { + // for some very odd reason on Azure webapp, fs.readFileSync after writeFileSync doesn't + // always find the file, add one more io to kick the virtual file system + fs.appendFileSync(dataStorePath, ' '); } interface KVStore { diff --git a/Composer/packages/server/src/utility/storage.ts b/Composer/packages/server/src/utility/storage.ts index 55eac7a864..853a6882cc 100644 --- a/Composer/packages/server/src/utility/storage.ts +++ b/Composer/packages/server/src/utility/storage.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +import log from '../logger'; import { IFileStorage } from '../models/storage/interface'; /** @@ -24,10 +25,7 @@ export async function copyDir(srcDir: string, srcStorage: IFileStorage, dstDir: const srcPath = `${srcDir}/${path}`; const dstPath = `${dstDir}/${path}`; - if (process.env.NODE_ENV !== 'test') { - // eslint-disable-next-line no-console - console.log(`copying ${srcPath} to ${dstPath}`); - } + log('copying %s to %s', srcPath, dstPath); if ((await srcStorage.stat(srcPath)).isFile) { // copy files diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5cbf7b7cae..0d9e256363 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -53,6 +53,7 @@ jobs: CYPRESS_SCREENSHOTS_FOLDER: $(Build.ArtifactStagingDirectory)/cypress/screenshots CYPRESS_VIDEOS_FOLDER: $(Build.ArtifactStagingDirectory)/cypress/videos TERM: xterm + COMPOSER_BOTS_FOLDER: $(Pipeline.Workspace)/Composer/TestBots - task: PublishPipelineArtifact@1 condition: in(variables['Agent.JobStatus'], 'SucceededWithIssues', 'Failed') continueOnError: true From 3609b4e550adfd0e0433be038722afc480568f86 Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Tue, 26 Nov 2019 13:49:18 -0800 Subject: [PATCH 15/45] chore: enforce node >=12 (#1665) * make node 12 a prereq * enforce node >=12 --- Composer/README.md | 2 +- Composer/package.json | 3 +++ Composer/packages/client/package.json | 3 +++ Composer/packages/extensions/obiformeditor/package.json | 3 +++ Composer/packages/extensions/package.json | 3 +++ Composer/packages/extensions/visual-designer/package.json | 3 +++ Composer/packages/lib/code-editor/package.json | 3 +++ Composer/packages/lib/eslint-plugin-bfcomposer/package.json | 3 +++ Composer/packages/lib/indexers/package.json | 3 +++ Composer/packages/lib/package.json | 3 +++ Composer/packages/lib/shared/package.json | 3 +++ Composer/packages/server/package.json | 3 +++ 12 files changed, 34 insertions(+), 1 deletion(-) diff --git a/Composer/README.md b/Composer/README.md index 91f9e36dda..c4395a8faa 100644 --- a/Composer/README.md +++ b/Composer/README.md @@ -8,7 +8,7 @@ The web app that can edit bots in OBI format, and can use Bot Launcher to run bo ### Instructions Prerequisite: -* node > 10.0 +* node > 12 * yarn // npm install -g yarn To build for hosting as site extension diff --git a/Composer/package.json b/Composer/package.json index ac6795cb0c..742387b7b8 100644 --- a/Composer/package.json +++ b/Composer/package.json @@ -4,6 +4,9 @@ "resolutions": { "@types/react": "16.9.0" }, + "engines": { + "node": ">=12" + }, "workspaces": [ "packages/client", "packages/server", diff --git a/Composer/packages/client/package.json b/Composer/packages/client/package.json index 3a540e1976..3a44f7febe 100644 --- a/Composer/packages/client/package.json +++ b/Composer/packages/client/package.json @@ -2,6 +2,9 @@ "name": "@bfc/client", "version": "0.1.0", "private": true, + "engines": { + "node": ">=12" + }, "scripts": { "start": "node scripts/start.js", "build": "node scripts/build.js", diff --git a/Composer/packages/extensions/obiformeditor/package.json b/Composer/packages/extensions/obiformeditor/package.json index 9366a3c15e..153a8d5a54 100644 --- a/Composer/packages/extensions/obiformeditor/package.json +++ b/Composer/packages/extensions/obiformeditor/package.json @@ -2,6 +2,9 @@ "name": "@bfc/obiformeditor", "version": "1.0.0", "description": "obieditortest React component", + "engines": { + "node": ">=12" + }, "main": "lib/index.js", "module": "es/index.js", "files": [ diff --git a/Composer/packages/extensions/package.json b/Composer/packages/extensions/package.json index 605efc971a..3049abd6eb 100644 --- a/Composer/packages/extensions/package.json +++ b/Composer/packages/extensions/package.json @@ -3,6 +3,9 @@ "version": "1.0.0", "description": "", "main": "index.js", + "engines": { + "node": ">=12" + }, "scripts": { "build:visual-designer": "cd visual-designer && yarn build", "build:obiformeditor": "cd obiformeditor && yarn build", diff --git a/Composer/packages/extensions/visual-designer/package.json b/Composer/packages/extensions/visual-designer/package.json index c39739966f..10909e14cc 100644 --- a/Composer/packages/extensions/visual-designer/package.json +++ b/Composer/packages/extensions/visual-designer/package.json @@ -3,6 +3,9 @@ "version": "1.0.0", "description": "visual-designer React component", "main": "lib/index.js", + "engines": { + "node": ">=12" + }, "files": [ "css", "es", diff --git a/Composer/packages/lib/code-editor/package.json b/Composer/packages/lib/code-editor/package.json index 31db849c38..9013709386 100644 --- a/Composer/packages/lib/code-editor/package.json +++ b/Composer/packages/lib/code-editor/package.json @@ -3,6 +3,9 @@ "version": "0.0.0", "description": "Code editor component that is shared in composer packages", "main": "lib/index.js", + "engines": { + "node": ">=12" + }, "repository": "https://github.com/microsoft/BotFramework-Composer", "license": "MIT", "private": true, diff --git a/Composer/packages/lib/eslint-plugin-bfcomposer/package.json b/Composer/packages/lib/eslint-plugin-bfcomposer/package.json index 6af516e91a..51206fed5b 100644 --- a/Composer/packages/lib/eslint-plugin-bfcomposer/package.json +++ b/Composer/packages/lib/eslint-plugin-bfcomposer/package.json @@ -2,6 +2,9 @@ "name": "@bfc/eslint-plugin-bfcomposer", "version": "1.0.0", "main": "src/index.js", + "engines": { + "node": ">=12" + }, "devDependencies": { "lodash": "^4.17.15" } diff --git a/Composer/packages/lib/indexers/package.json b/Composer/packages/lib/indexers/package.json index c6bacc6cf0..497ecdb788 100644 --- a/Composer/packages/lib/indexers/package.json +++ b/Composer/packages/lib/indexers/package.json @@ -3,6 +3,9 @@ "version": "0.0.0", "description": "", "main": "lib/index.js", + "engines": { + "node": ">=12" + }, "repository": "https://github.com/microsoft/BotFramework-Composer", "license": "MIT", "scripts": { diff --git a/Composer/packages/lib/package.json b/Composer/packages/lib/package.json index 8a903bc33b..6e6604e56c 100644 --- a/Composer/packages/lib/package.json +++ b/Composer/packages/lib/package.json @@ -3,6 +3,9 @@ "version": "1.0.0", "description": "", "main": "index.js", + "engines": { + "node": ">=12" + }, "scripts": { "build:code-editor": "cd code-editor && yarn build", "build:shared": "cd shared && yarn build", diff --git a/Composer/packages/lib/shared/package.json b/Composer/packages/lib/shared/package.json index bb5cff12ed..73e55bf6e9 100644 --- a/Composer/packages/lib/shared/package.json +++ b/Composer/packages/lib/shared/package.json @@ -5,6 +5,9 @@ "main": "lib/index.js", "repository": "https://github.com/microsoft/BotFramework-Composer", "license": "MIT", + "engines": { + "node": ">=12" + }, "scripts": { "build": "yarn clean && yarn build:css && yarn build:ts", "build:ts": "tsc --build tsconfig.build.json", diff --git a/Composer/packages/server/package.json b/Composer/packages/server/package.json index 9eb7ba7a42..3ec2c1ce72 100644 --- a/Composer/packages/server/package.json +++ b/Composer/packages/server/package.json @@ -3,6 +3,9 @@ "version": "1.0.0", "description": "", "main": "index.js", + "engines": { + "node": ">=12" + }, "scripts": { "analyze": "source-map-explorer 'build/public/static/js/*.js'", "build": "tsc -p tsconfig.build.json", From f492bef632f29eaa950a6e9e96edfa4ebeed7659 Mon Sep 17 00:00:00 2001 From: Andy Brown Date: Tue, 26 Nov 2019 14:48:12 -0800 Subject: [PATCH 16/45] ci: correctly clean up server process after e2e tests (#1666) * use TERM signal to kill server on exit using KILL does not actually kill all child processes of `yarn start` * fail build on e2e failure --- Composer/scripts/e2e.sh | 4 +++- azure-pipelines.yml | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Composer/scripts/e2e.sh b/Composer/scripts/e2e.sh index 148fac5b2e..3846b0fedf 100755 --- a/Composer/scripts/e2e.sh +++ b/Composer/scripts/e2e.sh @@ -6,12 +6,14 @@ yarn start & SERVER_PID=$! npx cypress run --browser chrome +EXIT_CODE=$? cleanup function cleanup { - kill -9 $SERVER_PID + kill $SERVER_PID } # kill server process trap cleanup EXIT +exit $EXIT_CODE diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0d9e256363..f0b2fa4364 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -45,7 +45,6 @@ jobs: - script: ./scripts/e2e.sh displayName: Run E2E Tests workingDirectory: Composer - continueOnError: true env: # CYPRESS_RECORD_KEY: $(CYPRESS_RECORD_KEY) CYPRESS_VIDEO: true @@ -55,7 +54,7 @@ jobs: TERM: xterm COMPOSER_BOTS_FOLDER: $(Pipeline.Workspace)/Composer/TestBots - task: PublishPipelineArtifact@1 - condition: in(variables['Agent.JobStatus'], 'SucceededWithIssues', 'Failed') + condition: failed() continueOnError: true inputs: targetPath: $(Build.ArtifactStagingDirectory)/cypress From 70e13ef18838cd4dda6602fbf7dad4abba1433c2 Mon Sep 17 00:00:00 2001 From: zeye <2295905420@qq.com> Date: Fri, 29 Nov 2019 11:41:51 +0800 Subject: [PATCH 17/45] feat: Trigger Node (#1529) * new trigger * add `subtitle` in ConceptLabels to override some title * refine new css of Trigger * fix an unsafe prop visit * fix eslint import path * move styles to 'triggerStyles.ts' * use lodash.get in Trigger.tsx * add subtitle in form editor (#1662) * Final changes * Remove unnecessary guard * enable debug when running tests * fix ci: BreadCrumb * fix ci: CreateNewBot * revert BreadCrumb * delete data.json before each e2e test * More labeling * Fix e2e test * fix visual designer spec * use findAllBy for breadcrumb spec sometimes more than one breadcrumb is found. this will use the last one found * use debug logger * pipe server output to log file and print after tests are run * fix up e2e script * run headless * pipe server logs to file * only invoke cleanup function once * fix visual designer spec again * display server logs * add more debug logging * always print e2e logs * Base leileizh's e2e fixes * update the node env --- .../cypress/integration/Breadcrumb.spec.ts | 13 +-- .../cypress/integration/CreateNewBot.spec.ts | 4 +- .../integration/NotificationPage.spec.ts | 1 + .../integration/VisualDesigner.spec.ts | 9 +- Composer/cypress/support/commands.ts | 6 ++ Composer/package.json | 2 +- .../ProjectTree/TriggerCreationModal.tsx | 2 +- .../packages/client/src/utils/dialogUtil.ts | 12 ++- .../src/Form/fields/RootField.tsx | 5 ++ .../obiformeditor/src/Form/fields/styles.css | 10 ++- .../src/components/nodes/Trigger.tsx | 64 ++++++------- .../src/components/nodes/triggerStyles.ts | 43 +++++++++ Composer/packages/lib/shared/src/labelMap.ts | 38 ++++++-- Composer/packages/lib/shared/src/viewUtils.ts | 8 +- .../packages/server/schemas/editor.schema | 63 +++++++++---- .../server/src/controllers/project.ts | 4 + .../server/src/models/asset/assetManager.ts | 2 + Composer/packages/server/src/server.ts | 3 +- .../packages/server/src/services/project.ts | 3 +- Composer/packages/server/src/store/store.ts | 1 + Composer/scripts/e2e.sh | 13 ++- azure-pipelines.yml | 11 ++- docs/concept-dialog.md | 89 +++++++++++-------- docs/concept-events-and-triggers.md | 2 +- 24 files changed, 280 insertions(+), 128 deletions(-) create mode 100644 Composer/packages/extensions/visual-designer/src/components/nodes/triggerStyles.ts diff --git a/Composer/cypress/integration/Breadcrumb.spec.ts b/Composer/cypress/integration/Breadcrumb.spec.ts index 8c647ee409..63adecd879 100644 --- a/Composer/cypress/integration/Breadcrumb.spec.ts +++ b/Composer/cypress/integration/Breadcrumb.spec.ts @@ -13,7 +13,8 @@ context('breadcrumb', () => { }); function hasBreadcrumbItems(cy: Cypress.cy, items: (string | RegExp)[]) { - cy.findByTestId('Breadcrumb') + cy.get('[data-testid="Breadcrumb"]') + .last() .get('li') .should($li => { items.forEach((item, idx) => { @@ -37,21 +38,21 @@ context('breadcrumb', () => { cy.findByText('__TestTodoSample.Main').click(); }); - hasBreadcrumbItems(cy, ['__TestTodoSample']); + hasBreadcrumbItems(cy, ['__TestTodoSample.Main']); }); it('can show event name in breadcrumb', () => { cy.findByTestId('ProjectTree').within(() => { cy.findByText('AddToDo').click(); - cy.findByText('Dialog started (BeginDialog)').click(); + cy.findByText('Dialog started').click(); }); - hasBreadcrumbItems(cy, ['AddToDo', 'Dialog started (BeginDialog)']); + hasBreadcrumbItems(cy, ['AddToDo', 'Dialog started']); }); it('can show action name in breadcrumb', () => { cy.findByTestId('ProjectTree').within(() => { - cy.findByText('Greeting (ConversationUpdate)').click(); + cy.findByText('Greeting').click(); }); // Click on an action @@ -61,6 +62,6 @@ context('breadcrumb', () => { }); }); - hasBreadcrumbItems(cy, ['__TestTodoSample.Main', 'Greeting (ConversationUpdate)', 'Send a response']); + hasBreadcrumbItems(cy, ['__TestTodoSample.Main', 'Greeting', 'Send a response']); }); }); diff --git a/Composer/cypress/integration/CreateNewBot.spec.ts b/Composer/cypress/integration/CreateNewBot.spec.ts index a02d28cc9a..4841f3cde7 100644 --- a/Composer/cypress/integration/CreateNewBot.spec.ts +++ b/Composer/cypress/integration/CreateNewBot.spec.ts @@ -23,9 +23,9 @@ context('Creating a new bot', () => { cy.findByTestId('Create from template').click(); cy.findByTestId('TodoSample').click(); cy.findByTestId('NextStepButton').click(); - cy.findByTestId('NewDialogName').type('{selectall}__TestNewProject{enter}'); + cy.findByTestId('NewDialogName').type('{selectall}__TestNewProject2{enter}'); cy.findByTestId('ProjectTree').within(() => { - cy.findByText('__TestNewProject.Main').should('exist'); + cy.findByText('__TestNewProject2.Main').should('exist'); cy.findByText('AddToDo').should('exist'); cy.findByText('ClearToDos').should('exist'); cy.findByText('DeleteToDo').should('exist'); diff --git a/Composer/cypress/integration/NotificationPage.spec.ts b/Composer/cypress/integration/NotificationPage.spec.ts index 7a3d9fe657..0f98c58149 100644 --- a/Composer/cypress/integration/NotificationPage.spec.ts +++ b/Composer/cypress/integration/NotificationPage.spec.ts @@ -5,6 +5,7 @@ context('Notification Page', () => { beforeEach(() => { cy.visit(Cypress.env('COMPOSER_URL')); cy.createBot('TodoSample'); + cy.visitPage('Notifications'); }); it('can show lg syntax error ', () => { diff --git a/Composer/cypress/integration/VisualDesigner.spec.ts b/Composer/cypress/integration/VisualDesigner.spec.ts index 7ecdabfaa2..eb6ee33041 100644 --- a/Composer/cypress/integration/VisualDesigner.spec.ts +++ b/Composer/cypress/integration/VisualDesigner.spec.ts @@ -2,12 +2,9 @@ // Licensed under the MIT License. context('Visual Designer', () => { - before(() => { + beforeEach(() => { cy.visit(Cypress.env('COMPOSER_URL')); cy.createBot('TodoSample'); - }); - - beforeEach(() => { // Return to Main.dialog cy.findByTestId('ProjectTree').within(() => { cy.findByText('__TestTodoSample.Main').click(); @@ -16,11 +13,11 @@ context('Visual Designer', () => { it('can find Visual Designer default trigger in container', () => { cy.findByTestId('ProjectTree').within(() => { - cy.findByText('Greeting (ConversationUpdate)').click(); + cy.findByText('Greeting').click(); }); cy.withinEditor('VisualEditor', () => { - cy.findByText('Trigger').should('exist'); + cy.findByText('ConversationUpdate activity').should('exist'); }); }); }); diff --git a/Composer/cypress/support/commands.ts b/Composer/cypress/support/commands.ts index de5939e41f..60b0e246d9 100644 --- a/Composer/cypress/support/commands.ts +++ b/Composer/cypress/support/commands.ts @@ -23,4 +23,10 @@ Cypress.Commands.add('withinEditor', (editorName, cb) => { Cypress.Commands.add('visitPage', page => { cy.findByTestId(`LeftNav-CommandBarButton${page}`).click(); + cy.wait(3000); +}); + +Cypress.on('uncaught:exception', (err, runnable) => { + console.log('uncaught exception', err); + return false; }); diff --git a/Composer/package.json b/Composer/package.json index 742387b7b8..21b3b3df5e 100644 --- a/Composer/package.json +++ b/Composer/package.json @@ -34,7 +34,7 @@ "test:coverage": "yarn test --coverage --no-cache --reporters=default", "test:integration": "cypress run --browser chrome", "test:integration:open": "cypress open", - "test:integration:clean": "rimraf TestBots/*", + "test:integration:clean": "rimraf ../MyBots/__Test*", "lint": "wsrun --exclude-missing --collect-logs --report lint", "lint:fix": "wsrun --exclude-missing --collect-logs --report lint:fix", "typecheck": "concurrently --kill-others-on-fail \"npm:typecheck:*\"", diff --git a/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx b/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx index 6a6988b3cc..71c9075202 100644 --- a/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx +++ b/Composer/packages/client/src/components/ProjectTree/TriggerCreationModal.tsx @@ -180,7 +180,7 @@ export const TriggerCreationModal: React.FC = props = )} {showIntentDropDown && ( = props => { return designerName || dialogName || sdkOverrides.title || title || schema.title || startCase(name); }; + const getSubTitle = (): string => { + return sdkOverrides.subtitle || sdkOverrides.title || formData.$type; + }; + const getDescription = (): string => { return sdkOverrides.description || description || schema.description || ''; }; @@ -65,6 +69,7 @@ export const RootField: React.FC = props => { styleOverrides={{ field: { fontWeight: FontWeights.semibold } }} fontSize={FontSizes.size20} /> +

{getSubTitle()}

{sdkOverrides.description !== false && (description || schema.description) && (

{getDescription()} diff --git a/Composer/packages/extensions/obiformeditor/src/Form/fields/styles.css b/Composer/packages/extensions/obiformeditor/src/Form/fields/styles.css index a73d8e3d8c..67b5509d34 100644 --- a/Composer/packages/extensions/obiformeditor/src/Form/fields/styles.css +++ b/Composer/packages/extensions/obiformeditor/src/Form/fields/styles.css @@ -13,7 +13,15 @@ .RootFieldTitle { border-bottom: 1px solid #c8c6c4; padding: 0 18px; - margin-bottom: 16px; + margin-bottom: 0px; +} +.RootFieldSubtitle { + height: 15px; + line-height: 15px; + font-size: 12px; + font-weight: 600; + color: #4F4F4F; + margin: -7px 0 7px; } .RootFieldDescription { margin-top: 0; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/Trigger.tsx b/Composer/packages/extensions/visual-designer/src/components/nodes/Trigger.tsx index 4827126ce7..82435f8dbd 100644 --- a/Composer/packages/extensions/visual-designer/src/components/nodes/Trigger.tsx +++ b/Composer/packages/extensions/visual-designer/src/components/nodes/Trigger.tsx @@ -5,42 +5,44 @@ import { ConceptLabels } from '@bfc/shared'; import { jsx } from '@emotion/core'; +import { Icon } from 'office-ui-fabric-react/lib/Icon'; +import get from 'lodash/get'; -import { ElementIcon } from '../../utils/obiPropertyResolver'; -import { TriggerSize } from '../../constants/ElementSizes'; - -import { FormCard } from './templates/FormCard'; +import { + triggerContainerStyle, + triggerContentStyle, + titleStyle, + subtitleStyle, + triggerIconStyle, +} from './triggerStyles'; function getLabel(data: any): string { - if (data.intent) { - return data.intent; - } - const labelOverrides = ConceptLabels[data.$type]; - - if (labelOverrides.title) { - return labelOverrides.title; + if (labelOverrides) { + return labelOverrides.subtitle || labelOverrides.title; } - return data.$type; } -export const Trigger = ({ data, onClick = () => {} }): JSX.Element => ( -

- -
-); +function getName(data: any): string { + return ( + data.intent || get(data, '$designer.name', ConceptLabels[data.$type] ? ConceptLabels[data.$type].title : data.$type) + ); +} + +export const Trigger = ({ data, onClick = () => {} }): JSX.Element => { + const name = getName(data); + const label = getLabel(data); + + return ( +
+
+
+ + {name} +
+
{label}
+
+
+ ); +}; diff --git a/Composer/packages/extensions/visual-designer/src/components/nodes/triggerStyles.ts b/Composer/packages/extensions/visual-designer/src/components/nodes/triggerStyles.ts new file mode 100644 index 0000000000..fb85ba5f65 --- /dev/null +++ b/Composer/packages/extensions/visual-designer/src/components/nodes/triggerStyles.ts @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License + +import { TriggerSize } from '../../constants/ElementSizes'; + +export const triggerContainerStyle: any = { + ...TriggerSize, + display: 'flex', + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'flex-end', + paddingBottom: '5px', + boxSizing: 'border-box', +}; + +export const triggerContentStyle: any = { + wordBreak: 'break-all', + display: 'flex', + flexDirection: 'column', + alignItems: 'center', +}; + +export const titleStyle: any = { + whiteSpace: 'nowrap', + color: '#333333', + fontFamily: 'Segoe UI', + fontSize: '18px', + lineHeight: '24px', + fontWeight: 600, +}; + +export const subtitleStyle: any = { + whiteSpace: 'nowrap', + color: '#4f4f4f', + fontFamily: 'Segoe UI', + fontSize: '12px', + lineHeight: '14px', +}; + +export const triggerIconStyle = { + lineHeight: '24px', + marginRight: '5px', +}; diff --git a/Composer/packages/lib/shared/src/labelMap.ts b/Composer/packages/lib/shared/src/labelMap.ts index 889fccdd8f..dec4ca588d 100644 --- a/Composer/packages/lib/shared/src/labelMap.ts +++ b/Composer/packages/lib/shared/src/labelMap.ts @@ -11,6 +11,7 @@ formatMessage.setup({ interface LabelOverride { title?: string | false; + subtitle?: string | false; description?: string | false; } @@ -118,66 +119,85 @@ export const ConceptLabels: { [key in ConceptLabelKey]?: LabelOverride } = { title: formatMessage('OAuth login'), }, [SDKTypes.OnActivity]: { - title: formatMessage('Activity trigger'), + title: formatMessage('Activities'), + subtitle: formatMessage('Activity recieved'), }, [SDKTypes.OnBeginDialog]: { - title: formatMessage('Dialog started (BeginDialog)'), + title: formatMessage('Dialog started'), + subtitle: formatMessage('Begin dialog event'), }, [SDKTypes.OnCancelDialog]: { - title: formatMessage('Dialog cancelled (CancelDialog)'), + title: formatMessage('Dialog cancelled'), + subtitle: formatMessage('Cancel dialog event'), }, [SDKTypes.OnCondition]: { title: formatMessage('Handle a Condition'), }, [SDKTypes.OnConversationUpdateActivity]: { - title: formatMessage('Greeting (ConversationUpdate)'), + title: formatMessage('Greeting'), + subtitle: formatMessage('ConversationUpdate activity'), description: 'Handle the events fired when a user begins a new conversation with the bot. Learn more', }, [SDKTypes.OnCustomEvent]: { - title: formatMessage('Custom trigger'), + title: formatMessage('Custom event'), + subtitle: formatMessage('Custom event'), }, [SDKTypes.OnDialogEvent]: { - title: formatMessage('Dialog trigger'), + title: formatMessage('Dialog events'), + subtitle: formatMessage('Dialog events'), }, [SDKTypes.OnEndOfConversationActivity]: { title: formatMessage('Conversation ended'), + subtitle: formatMessage('EndOfConversation activity'), }, [SDKTypes.OnError]: { title: formatMessage('Error occurred'), + subtitle: formatMessage('Error event'), }, [SDKTypes.OnEventActivity]: { title: formatMessage('Event received'), + subtitle: formatMessage('Event activity'), }, [SDKTypes.OnHandoffActivity]: { title: formatMessage('Handover to human'), + subtitle: formatMessage('Handoff activity'), }, [SDKTypes.OnIntent]: { - title: formatMessage('Intent'), + title: formatMessage('Intent recognized'), + subtitle: formatMessage('Intent recognized'), }, [SDKTypes.OnInvokeActivity]: { title: formatMessage('Conversation invoked'), + subtitle: formatMessage('Invoke activity'), }, [SDKTypes.OnMessageActivity]: { - title: formatMessage('Message activity trigger'), + title: formatMessage('Message events'), + subtitle: formatMessage('Message recieved activity'), }, [SDKTypes.OnMessageDeleteActivity]: { title: formatMessage('Message deleted'), + subtitle: formatMessage('Message deleted activity'), }, [SDKTypes.OnMessageReactionActivity]: { title: formatMessage('Message reaction'), + subtitle: formatMessage('Message reaction activity'), }, [SDKTypes.OnMessageUpdateActivity]: { title: formatMessage('Message updated'), + subtitle: formatMessage('Message updated activity'), }, [SDKTypes.OnRepromptDialog]: { title: formatMessage('Re-prompt for input'), + subtitle: formatMessage('Reprompt dialog event'), }, [SDKTypes.OnTypingActivity]: { title: formatMessage('User is typing'), + subtitle: formatMessage('Typing activity'), }, [SDKTypes.OnUnknownIntent]: { - title: formatMessage('Unrecognized intent'), + title: formatMessage('Unknown intent'), + subtitle: formatMessage('Unknown intent recognized'), }, [SDKTypes.QnAMakerDialog]: { title: formatMessage('Connect to QnA Knowledgebase'), diff --git a/Composer/packages/lib/shared/src/viewUtils.ts b/Composer/packages/lib/shared/src/viewUtils.ts index 332383dc6c..5a59ce4c15 100644 --- a/Composer/packages/lib/shared/src/viewUtils.ts +++ b/Composer/packages/lib/shared/src/viewUtils.ts @@ -110,6 +110,7 @@ export const dialogGroups: DialogGroupsMap = { [DialogGroup.ADVANCED_EVENTS]: { label: 'Advanced Events', types: [ + SDKTypes.OnActivity, SDKTypes.OnConversationUpdateActivity, SDKTypes.OnEndOfConversationActivity, SDKTypes.OnEventActivity, @@ -120,7 +121,12 @@ export const dialogGroups: DialogGroupsMap = { }, [DialogGroup.MESSAGE_EVENTS]: { label: 'Message events', - types: [SDKTypes.OnMessageDeleteActivity, SDKTypes.OnMessageReactionActivity, SDKTypes.OnMessageUpdateActivity], + types: [ + SDKTypes.OnMessageActivity, + SDKTypes.OnMessageDeleteActivity, + SDKTypes.OnMessageReactionActivity, + SDKTypes.OnMessageUpdateActivity, + ], }, [DialogGroup.RECOGNIZER]: { label: 'Recognizers', diff --git a/Composer/packages/server/schemas/editor.schema b/Composer/packages/server/schemas/editor.schema index c4fc174b0e..b6bb740327 100644 --- a/Composer/packages/server/schemas/editor.schema +++ b/Composer/packages/server/schemas/editor.schema @@ -29,6 +29,10 @@ "helpLink": "https://aka.ms/bfc-understanding-dialogs", "helpLinkText": "Learn more" }, + "Microsoft.OnCancelDialog": { + "title": "Dialog cancelled", + "subtitle": "Cancel dialog event" + }, "Microsoft.CancelAllDialogs": { "title": "Cancel All Dialogs", "helpLink": "https://aka.ms/bfc-understanding-dialogs", @@ -144,58 +148,83 @@ "helpLink": "https://aka.ms/bfc-using-oauth" }, "Microsoft.OnActivity": { - "title": "Activity trigger" + "title": "Activities", + "subtitle": "Activity recieved" }, "Microsoft.OnBeginDialog": { - "title": "Dialog started (BeginDialog)" + "title": "Dialog started", + "subtitle": "Begin dialog event" }, "Microsoft.OnConversationUpdateActivity": { - "title": "Greeting (ConversationUpdate)", + "title": "Greeting", + "subtitle": "ConversationUpdate activity", "description": "Handle the events fired when a user begins a new conversation with the bot.", "helpLink": "https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-conversations?view=azure-bot-service-4.0#conversation-lifetime", "helpLinkText": "Learn more" }, "Microsoft.OnDialogEvent": { - "title": "Dialog event" + "title": "Dialog events", + "subtitle": "Dialog event" }, "Microsoft.OnEndOfConversationActivity": { - "title": "Conversation ended" + "title": "Conversation ended", + "subtitle": "EndOfConversation activity" }, "Microsoft.OnCondition": { - "title": "Handle an condition" + "title": "Handle a condition", + "subtitle": "Condition" }, "Microsoft.OnCustomEvent": { - "title": "Handle an Event" + "title": "Handle an Event", + "subtitle": "Custom event" }, "Microsoft.OnEventActivity": { - "title": "Event received" + "title": "Event received", + "subtitle": "Event activity" + }, + "Microsoft.OnError": { + "title": "Error occurred", + "subtitle": "Error event" }, "Microsoft.OnHandoffActivity": { - "title": "Handover to human" + "title": "Handover to human", + "subtitle": "Handoff activity" }, "Microsoft.OnIntent": { - "title": "Intent" + "title": "Intent recognized", + "subtitle": "Intent recognized" }, "Microsoft.OnInvokeActivity": { - "title": "Conversation invoked" + "title": "Conversation invoked", + "subtitle": "Invoke activity" }, "Microsoft.OnMessageActivity": { - "title": "Message received" + "title": "Message events", + "subtitle": "Message recieved activity" }, "Microsoft.OnMessageDeleteActivity": { - "title": "Message deleted" + "title": "Message deleted", + "subtitle": "Message deleted activity" }, "Microsoft.OnMessageReactionActivity": { - "title": "Message reaction" + "title": "Message reaction", + "subtitle": "Message reaction activity" }, "Microsoft.OnMessageUpdateActivity": { - "title": "Message updated" + "title": "Message updated", + "subtitle": "Message updated activity" }, "Microsoft.OnTypingActivity": { - "title": "User is typing" + "title": "User is typing", + "subtitle": "Typing activity" + }, + "Microsoft.OnRepromptDialog": { + "title": "Re-prompt for input", + "subtitle": "Reprompt dialog event" }, "Microsoft.OnUnknownIntent": { - "title": "Unrecognized intent" + "title": "Unknown intent", + "subtitle": "Unknown intent recognized" }, "Microsoft.QnAMakerDialog": { "title": "QnAMakerDialog", diff --git a/Composer/packages/server/src/controllers/project.ts b/Composer/packages/server/src/controllers/project.ts index 7753fbdc84..9a5b391a86 100644 --- a/Composer/packages/server/src/controllers/project.ts +++ b/Composer/packages/server/src/controllers/project.ts @@ -5,6 +5,7 @@ import * as fs from 'fs'; import { Request, Response } from 'express'; +import log from '../logger'; import { BotProjectService } from '../services/project'; import AssectService from '../services/asset'; import { LocationRef } from '../models/bot/interface'; @@ -37,6 +38,8 @@ async function createProject(req: Request, res: Response) { path: Path.resolve(path, name), }; + log('Attempting to create project at %s', path); + try { const newProjRef = await AssectService.manager.copyProjectTemplateTo(templateId, locationRef); await BotProjectService.openProject(newProjRef); @@ -45,6 +48,7 @@ async function createProject(req: Request, res: Response) { await currentProject.updateBotInfo(name, description); await currentProject.index(); const project = currentProject.getIndexes(); + log('Project created successfully.'); res.status(200).json({ ...project, }); diff --git a/Composer/packages/server/src/models/asset/assetManager.ts b/Composer/packages/server/src/models/asset/assetManager.ts index 4ecedd844d..440b5b4ace 100644 --- a/Composer/packages/server/src/models/asset/assetManager.ts +++ b/Composer/packages/server/src/models/asset/assetManager.ts @@ -4,6 +4,7 @@ import find from 'lodash/find'; import { ProjectTemplate } from '@bfc/shared'; +import log from '../../logger'; import { LocalDiskStorage } from '../storage/localDiskStorage'; import { LocationRef } from '../bot/interface'; import { Path } from '../../utility/path'; @@ -171,6 +172,7 @@ export class AssetManager { const dstStorage = StorageService.getStorageClient(ref.storageId); const dstDir = Path.resolve(ref.path); if (await dstStorage.exists(dstDir)) { + log('Failed copying template to %s', dstDir); throw new Error('already have this folder, please give another name'); } diff --git a/Composer/packages/server/src/server.ts b/Composer/packages/server/src/server.ts index 0114f67a97..e332b38c4d 100644 --- a/Composer/packages/server/src/server.ts +++ b/Composer/packages/server/src/server.ts @@ -13,6 +13,7 @@ import compression from 'compression'; import { getAuthProvider } from './router/auth'; import { apiRouter } from './router/api'; import { BASEURL } from './constants'; +import log from './logger'; const app: Express = express(); app.set('view engine', 'ejs'); @@ -81,7 +82,7 @@ app.use(`${BASEURL}/api`, authorize, apiRouter); app.use(function(err: Error, req: Request, res: Response, _next: NextFunction) { if (err) { - console.log(err); + log(err); res.status(500).json({ message: err.message }); } }); diff --git a/Composer/packages/server/src/services/project.ts b/Composer/packages/server/src/services/project.ts index ef966bba08..8bbbba378e 100644 --- a/Composer/packages/server/src/services/project.ts +++ b/Composer/packages/server/src/services/project.ts @@ -7,6 +7,7 @@ import find from 'lodash/find'; import { BotProject } from '../models/bot/botProject'; import { LocationRef } from '../models/bot/interface'; import { Store } from '../store/store'; +import log from '../logger'; import StorageService from './storage'; import { Path } from './../utility/path'; @@ -44,7 +45,7 @@ export class BotProjectService { dateModified = await StorageService.getBlobDateModified(project.storageId, project.path); dateModifiedDict.push({ dateModified, path: project.path }); } catch (err) { - console.error(err); + log(err); } }); await Promise.all(promises); diff --git a/Composer/packages/server/src/store/store.ts b/Composer/packages/server/src/store/store.ts index b8af7d62ec..ef071fafa1 100644 --- a/Composer/packages/server/src/store/store.ts +++ b/Composer/packages/server/src/store/store.ts @@ -67,6 +67,7 @@ class JsonStore implements KVStore { private ensureStore() { if (!fs.existsSync(this.filePath)) { + log('data.json not found. Re-initializing with initial data.'); this.initializeStore(); } } diff --git a/Composer/scripts/e2e.sh b/Composer/scripts/e2e.sh index 3846b0fedf..6eda9118be 100755 --- a/Composer/scripts/e2e.sh +++ b/Composer/scripts/e2e.sh @@ -1,17 +1,14 @@ #!/usr/bin/env bash -set -e +function cleanup { + kill $SERVER_PID +} -yarn start & +yarn start >> e2e.log 2>&1 & SERVER_PID=$! -npx cypress run --browser chrome +npx cypress run EXIT_CODE=$? -cleanup - -function cleanup { - kill $SERVER_PID -} # kill server process trap cleanup EXIT diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f0b2fa4364..96892f72f6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -5,7 +5,7 @@ pr: autoCancel: true branches: include: - - '*' + - "*" variables: YARN_CACHE_FOLDER: $(Pipeline.Workspace)/.yarn @@ -52,10 +52,17 @@ jobs: CYPRESS_SCREENSHOTS_FOLDER: $(Build.ArtifactStagingDirectory)/cypress/screenshots CYPRESS_VIDEOS_FOLDER: $(Build.ArtifactStagingDirectory)/cypress/videos TERM: xterm - COMPOSER_BOTS_FOLDER: $(Pipeline.Workspace)/Composer/TestBots + COMPOSER_BOTS_FOLDER: $(System.DefaultWorkingDirectory)/MyBots + DEBUG: composer - task: PublishPipelineArtifact@1 + displayName: Publish Cypress Artifacts condition: failed() continueOnError: true inputs: targetPath: $(Build.ArtifactStagingDirectory)/cypress artifactName: e2e + - script: cat e2e.log + displayName: Server Logs + condition: always() + continueOnError: true + workingDirectory: Composer diff --git a/docs/concept-dialog.md b/docs/concept-dialog.md index 7ea074c3d8..2bfdd048b6 100644 --- a/docs/concept-dialog.md +++ b/docs/concept-dialog.md @@ -1,102 +1,113 @@ -# Dialogs +# Dialogs + Modern conversational software is comprised of many components, including programming code, custom business logic, cloud APIs, training data for language processing systems and perhaps most importantly, the actual content used in conversations with the bot's end users. With Composer, all of these pieces are integrated with one another into a single interface for constructing blocks of bot functionality called **Dialogs**. ([SDK Docs: Bot Framework Dialogs](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-dialog?view=azure-bot-service-4.0)) -Each dialog represents a piece of the bot's functionality. They contain instructions for how the bot will react to input. Simple bots will have a few dialogs. Complex bots may have dozens or hundreds of individual dialogs. +Each dialog represents a piece of the bot's functionality. They contain instructions for how the bot will react to input. Simple bots will have a few dialogs. Complex bots may have dozens or hundreds of individual dialogs. In Composer, dialogs are functional components offered in a visual interface and do not require you to write code. The dialog system supports building a pluggable and extensible model that integrates building blocks of bot functionality. Dialogs help users focus on conversation modeling rather than the mechanics of dialog management. -## Types of dialogs -There are two types of dialogs in Composer: main dialog and child dialog. Below is a screenshot of a main dialog named `MyBot.Main` and two child dialogs named `Weather` and `Greeting`. +## Types of dialogs + +There are two types of dialogs in Composer: main dialog and child dialog. Below is a screenshot of a main dialog named `MyBot.Main` and two child dialogs named `Weather` and `Greeting`. ![main_child_dialog](./media/dialog/main_child_dialog.png) -You create a dialog in Composer to manage a conversation objective. Main dialog is initialized by default when you create a new bot and it has a **.Main** file extension. Each bot has one main dialog and can have multiple child dialogs or no child dialogs. Read the [Add a dialog](./tutorial/bot-tutorial-add-dialog.md) section to create a dialog in Composer. +You create a dialog in Composer to manage a conversation objective. Main dialog is initialized by default when you create a new bot and it has a **.Main** file extension. Each bot has one main dialog and can have multiple child dialogs or no child dialogs. Read the [Add a dialog](./tutorial/bot-tutorial-add-dialog.md) section to create a dialog in Composer. -At runtime, the main dialog is called into action and becomes the active dialog, triggering event handlers with pre-defined actions. As the conversation flows, a child dialog can be called by a main dialog, and vice versa. Different child dialogs can be called with each other as well. +At runtime, the main dialog is called into action and becomes the active dialog, triggering event handlers with pre-defined actions. As the conversation flows, a child dialog can be called by a main dialog, and vice versa. Different child dialogs can be called with each other as well. -## Anatomy of a dialog -The following diagram shows the anatomy of a dialog in Composer. Note that dialogs in Composer are based on [Adaptive dialogs](https://github.com/Microsoft/BotBuilder-Samples/tree/master/experimental/adaptive-dialog#readme). +## Anatomy of a dialog + +The following diagram shows the anatomy of a dialog in Composer. Note that dialogs in Composer are based on [Adaptive dialogs](https://github.com/Microsoft/BotBuilder-Samples/tree/master/experimental/adaptive-dialog#readme). ![adaptive-dialog-anatomy](./media/dialog/adaptive-dialog-anatomy.png) ### Recognizer -When a dialog is called into action its **recognizer** will start to process the message and try to extract the primary **intent** and any **entity values** the message includes. After processing the message, both the **intent** and **entity values** are passed onto the dialog's triggers. Composer currently supports two recognizers: the LUIS recognizer (default) and the Regular Expression recognizer. You can choose only one recognizer per dialog, and a dialog can have no recognizer choosing the `None` type. Below is a screenshot of recognizers supported in Composer. + +When a dialog is called into action its **recognizer** will start to process the message and try to extract the primary **intent** and any **entity values** the message includes. After processing the message, both the **intent** and **entity values** are passed onto the dialog's triggers. Composer currently supports two recognizers: the LUIS recognizer (default) and the Regular Expression recognizer. You can choose only one recognizer per dialog, and a dialog can have no recognizer choosing the `None` type. Below is a screenshot of recognizers supported in Composer. ![recognizer](./media/dialog/recognizer.png) **Recognizers** provide the functionality of understanding and extracting meaningful pieces of information from a user's input. All recognizers emit events when the recognizer picks up an **intent** (or extracts **entities**) from a given user utterance. A **recognizer** of a dialog is not always called into play when a dialog is called. It depends on how you design the dialog system. ### Trigger -The functionality of a dialog is contained within triggers - rules that tell the bot how to process incoming messages. They are also used to define a wide variety of bot behaviors, from performing the main fulfillment of the user's request, to handling [interruptions](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-handle-user-interrupt?view=azure-bot-service-4.0&tabs=csharp) like requests for help, to handling custom, developer-defined events originating from the app itself. Below is a screenshot of the trigger menu in Composer. + +The functionality of a dialog is contained within triggers - rules that tell the bot how to process incoming messages. They are also used to define a wide variety of bot behaviors, from performing the main fulfillment of the user's request, to handling [interruptions](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-howto-handle-user-interrupt?view=azure-bot-service-4.0&tabs=csharp) like requests for help, to handling custom, developer-defined events originating from the app itself. Below is a screenshot of the trigger menu in Composer. ![trigger_menu](./media/dialog/trigger_menu.gif) -### Action -Triggers contain a series of actions that the bot will undertake to fulfill a user's request. Actions are things like sending messages, making calculations, and performing computational tasks on behalf of the user. The path the bot follows through a dialog can branch and loop. The bot can ask questions, validate input, manipulate and store values in memory, and make decisions. Below is a screenshot of the action menu in Composer. Click the **+** sign below the trigger you can mouse over the action menu. +### Action + +Triggers contain a series of actions that the bot will undertake to fulfill a user's request. Actions are things like sending messages, making calculations, and performing computational tasks on behalf of the user. The path the bot follows through a dialog can branch and loop. The bot can ask questions, validate input, manipulate and store values in memory, and make decisions. Below is a screenshot of the action menu in Composer. Click the **+** sign below the trigger you can mouse over the action menu. ![action_menu](./media/dialog/action_menu.gif) ### Language generator -As the bot takes actions and sends messages, the **language generator** is called into play. This allows messages sent by the bot to be composed from variables and templates. Language generators can be used to create reusable components, variable messages, macros, and dynamic messages that are grammatically correct. + +As the bot takes actions and sends messages, the **language generator** is called into play. This allows messages sent by the bot to be composed from variables and templates. Language generators can be used to create reusable components, variable messages, macros, and dynamic messages that are grammatically correct. -## Create a dialog + +## Create a dialog + When you create a bot in Composer you also create its main dialog by default. Follow the steps to create a bot project and its main dialog: -1. On the left side of the Composer home screen, click **+ New** from the upper left corner (or the big **+ ** sign under "Bot Framework Composer" in the middle part of the home screen). +1. On the left side of the Composer home screen, click **+ New** from the upper left corner (or the big **+ ** sign under "Bot Framework Composer" in the middle part of the home screen). -![create_new_bot](./media/dialog/create_new_bot.png) +![create_new_bot](./media/dialog/create_new_bot.png) -2. After you see the pop-up window, select **Create from scratch** and click **Submit**. +2. After you see the pop-up window, select **Create from scratch** and click **Submit**. -3. In the pop-up window give a name for your bot and optionally fill in a brief description and click **Next**. Leave the **Location** field as is at this time. +3. In the pop-up window give a name for your bot and optionally fill in a brief description and click **Next**. Leave the **Location** field as is at this time. ![new_bot](./media/dialog/new_bot.png) -When your bot is created successfully you will see a **.Main** dialog in the dialog navigation pane. Congratulations! You have created your first bot and its main dialog using Composer. Below is a screenshot of a bot named `Greeting` and its main dialog named `Greeting.Main`: +When your bot is created successfully you will see a **.Main** dialog in the dialog navigation pane. Congratulations! You have created your first bot and its main dialog using Composer. Below is a screenshot of a bot named `Greeting` and its main dialog named `Greeting.Main`: ![main_dialog](./media/dialog/main_dialog.png) > [!NOTE] -> After you create a bot a **ConversationUpdate** trigger will be created by default as well. It is a trigger to handle activities such as sending a welcome message. For details please read [events and triggers](concept-events-and-triggers.md). +> After you create a bot a **ConversationUpdate** trigger will be created by default as well. It is a trigger to handle activities such as sending a welcome message. For details please read [events and triggers](concept-events-and-triggers.md). -## Add a dialog -After you create a bot you are also creating its main dialog by default. The main dialog is like the brain of our bot, controlling and managing the dialog system. Sometimes we find it useful to create a child dialog that contains a chunk of functionality so that our dialog system is organized and easily managed. Let's walk through a very simple example to show how to create a child dialog and wire it up to the main dialog. +## Add a dialog -1. Create a child dialog. Click **New Dialog** on the navigation pane. On the pop-up window give a name for the new dialog and optionally fill in the description and then click **Next**. +After you create a bot you are also creating its main dialog by default. The main dialog is like the brain of our bot, controlling and managing the dialog system. Sometimes we find it useful to create a child dialog that contains a chunk of functionality so that our dialog system is organized and easily managed. Let's walk through a very simple example to show how to create a child dialog and wire it up to the main dialog. + +1. Create a child dialog. Click **New Dialog** on the navigation pane. On the pop-up window give a name for the new dialog and optionally fill in the description and then click **Next**. ![weather_dialog](./media/dialog/weather_dialog.png) -After that, you will see an empty dialog you created on the navigation pane. When creating a child dialog you also create a **Dialog started (BeginDialog)** trigger by default. The new dialog named `Weather` may look like this: +After that, you will see an empty dialog you created on the navigation pane. When creating a child dialog you also create a **Dialog started (Begin dialog event)** trigger by default. The new dialog named `Weather` may look like this: ![new_weather_dialog](./media/dialog/new_weather_dialog.png) -2. Define an action in the **BeginDialog** trigger. Click the `+` sign under **Dialog started (BeginDialog)** in the new dialog and select **Send a response**. In the Language Generation editor put a sentence: "The weather dialog is calle with success!" +2. Define an action in the **BeginDialog** trigger. Click the `+` sign under **Dialog started (Begin dialog event)** in the new dialog and select **Send a response**. In the Language Generation editor put a sentence: "The weather dialog is calle with success!" ![send_response](./media/dialog/send_response.gif) -3. Wire up the new dialog. Click the main dialog in navigation pane and select **ConversationUpdate**. In the authoring canvas, click the **+** sign under **ConversationUpdate** and select **Dialog management** and then **Begin a new dialog** which is a dialog action that begins another dialog. When that dialog is completed, it will return to the caller. +3. Wire up the new dialog. Click the main dialog in navigation pane and select **ConversationUpdate**. In the authoring canvas, click the **+** sign under **ConversationUpdate** and select **Dialog management** and then **Begin a new dialog** which is a dialog action that begins another dialog. When that dialog is completed, it will return to the caller. ![begin_dialog_action](./media/dialog/begin_dialog_action.png) -Now in the properties panel on the right side select the dialog you want to wire up from the drop-down menu. Let's select `Weather` dialog and then you will see the name of the new dialog appear in the **Begin a new dialog** action node. +Now in the properties panel on the right side select the dialog you want to wire up from the drop-down menu. Let's select `Weather` dialog and then you will see the name of the new dialog appear in the **Begin a new dialog** action node. ![wire_up_dialog](./media/dialog/wire_up_dialog.gif) -When the bot runs, the pattern of this simple design is as follows: +When the bot runs, the pattern of this simple design is as follows: - The main dialog `Greeting.Main` is called at bot runtime. -- The **ConversationUpdate** trigger in the main dialog is activated and begins to execute the **Begin a new dialog** action which begins `Weather` dialog. -- When `Weather` dialog becomes active, the **BeginDialog** trigger in the child dialog is fired and send the response "The weather dialog is called with success!" to users. - -You can test the result by clicking **Start** on the upper right corner and then click **Test in Emulator**. You should be able to see the following result in the emulator: +- The **ConversationUpdate** trigger in the main dialog is activated and begins to execute the **Begin a new dialog** action which begins `Weather` dialog. +- When `Weather` dialog becomes active, the **BeginDialog** trigger in the child dialog is fired and send the response "The weather dialog is called with success!" to users. + +You can test the result by clicking **Start** on the upper right corner and then click **Test in Emulator**. You should be able to see the following result in the emulator: ![test_emulator](./media/dialog/test_emulator.png) -## Dialog actions -A bot will have a few dialogs or hundreds of individual dialogs and traditionally it's difficult to manage the dialog system and the conversation with user. In the previous "Add a dialog" section, we cover how to create a child dialog and wire it up to the dialog system using **Begin a new dialog** action. In fact, Composer provides more dialog actions to make it easier to manage the dialog system. You can access the different dialog actions by clicking the **+** node under a trigger and then select **Dialog management**. +## Dialog actions -Below is a list of the dialog actions provided in Composer: +A bot will have a few dialogs or hundreds of individual dialogs and traditionally it's difficult to manage the dialog system and the conversation with user. In the previous "Add a dialog" section, we cover how to create a child dialog and wire it up to the dialog system using **Begin a new dialog** action. In fact, Composer provides more dialog actions to make it easier to manage the dialog system. You can access the different dialog actions by clicking the **+** node under a trigger and then select **Dialog management**. + +Below is a list of the dialog actions provided in Composer: | Dialog Action | Description | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------- | @@ -107,12 +118,14 @@ Below is a list of the dialog actions provided in Composer: | Repeat this Dialog | An action that repeats the current dialog with the same dialog. | | Replace this Dialog | An action that replaces the current dialog with the target dialog. | -With these dialog actions, we can easily build a pluggable and extensible dialog system without worrying about the mechanics of dialog management. +With these dialog actions, we can easily build a pluggable and extensible dialog system without worrying about the mechanics of dialog management. + +## Further reading -## Further reading [Dialogs library](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-dialog?view=azure-bot-service-4.0) [Adaptive dialogs](https://github.com/Microsoft/BotBuilder-Samples/tree/master/experimental/adaptive-dialog#readme) -## Next +## Next + [Events and triggers](./concept-events-and-triggers.md) diff --git a/docs/concept-events-and-triggers.md b/docs/concept-events-and-triggers.md index cb68ebacf0..b0bf02578d 100644 --- a/docs/concept-events-and-triggers.md +++ b/docs/concept-events-and-triggers.md @@ -9,7 +9,7 @@ On the navigation pane, click **New Trigger** and you will see the trigger menu There are different types of triggers. They all work in a similar manner, and in some cases, can be interchanged. This section will cover the different types of triggers and when should we use them. Read more to learn how to [define triggers](howto-defining-triggers.md). ### Dialog trigger -The base type of triggers are dialog triggers. Almost all events start as dialog events which are related to the "lifecycle" of the dialog. Currently there are four different dialog triggers in Composer: **Dialog started (BeginDialog)**, **Dialog cancelled (CancelDialog)**, **Error occurred** and **Re-prompt for input**. Most dialogs will include a trigger configured to respond to the `BeginDialog` event, which fires when the dialog begins and allows the bot to respond immediately. +The base type of triggers are dialog triggers. Almost all events start as dialog events which are related to the "lifecycle" of the dialog. Currently there are four different dialog triggers in Composer: **Dialog started (Begin dialog event)**, **Dialog cancelled (CancelDialog)**, **Error occurred** and **Re-prompt for input**. Most dialogs will include a trigger configured to respond to the `BeginDialog` event, which fires when the dialog begins and allows the bot to respond immediately. Use dialog triggers when you want to: - Take actions immediately when the dialog starts, even before the recognizer is called From ae7fa1dd4f2ba13899cf388a283fefc985504f4f Mon Sep 17 00:00:00 2001 From: Zhixiang Zhan Date: Sat, 30 Nov 2019 01:18:55 +0800 Subject: [PATCH 18/45] feat: LG LSP in Composer (#1504) * Add LSP of LG * change folder name * change folder location * seperate server and client demo * add completion and hover for builtin-functions * change file names * change dependency * refactor the package * update demo readme * make some refine * remove npm lock file * add demos to workspace and run test in 1 command * remove declaration files * change tsc outDir to dist, simplify test command * add syntax highlight in demo and new API * change naming of the project and move the demo * remove package.json in demo * change the content in readme * fix lg-lsp package publish problem * fix build command and redundent d.ts files * integrate LG LSP server to composer server * change api in demo * change the order of commands in build:prod * delete redundent files generated from build * change lg-lsp-server api to attachLSPServer * remove gitignore in lg-lsp-server demo * remove attachLSPServer in server * stash * freeze vscode-languageserver-protocol@3.15.0-next.8 * stash code-editor lsp demo * update * build react sample demo * version 17 * launch lsp server * connect server * calc offset * concat full content * clean demo * update * do not build lglsp editor * update demo * update before build * clean build * inline mode * build * lsp working demo in composer * renaming * eslint and build fix * add utils * monaco editor core component * wrap up editor component * seperate client and server * update wrap * attach language server to composer server * token rules and suggestion context awareness * complete demo * inline template editor in form * inline in all-up view * refactor * check file * update * remove monaco-webpack-plugin * import diectly instead of call register * create language server url * add package * allow suggestion in plaintext state * update integrity hash * exist check * add back monaco-webpack-plugin * add mixed demo * code refactor * merge folder * add dependency * resolve alias in jest * fix type * resolve typing * clean up * clean up * Update Composer/package.json Co-Authored-By: Andy Brown * Update Composer/packages/tools/language-servers/language-generation/src/utils.ts Co-Authored-By: Andy Brown * Update Composer/packages/tools/language-servers/package.json Co-Authored-By: Andy Brown * refactor lsp server * refactor lsp client * resolve eslint * move static syntax setting to code editor * clean up * clean * use latest @types/vscode replace vscode * only path map actual vscode module not including the `$` will make jest replace all modules with *vscode* * disable lint errors * resolve code review warning * clean up * pass less data * fix type * clean up, typo, refine and naming * clean up * extends base * hide source name * add test * eslint resolve * close connection when document close * update * add time stamp for every new connection * pass parameters to inline editor * match lsp server port with env server port * rename /lgServer to /lg-language-server * refactor code * compatible LG Parser, prevent crash * do not close shared connection * send initial diagnostics with delay * update demo * refactor error handling * refine, review * error handling * ignore non-exist references at check template body * update tokenizer * close websocket when editor unmount * all editors use a shared unique ws connection * fix structure lg in inline mode and comment token * fix lint * update structure name token * fix fence_block miss recognize template name * remove plaintext in allowState for LG completion * control initial diagnostics send * fix regExp in getWordAtPosition * optimize data passing * update test * eslint fix * update test --- .vscode/launch.json | 41 +- Composer/jest.config.js | 1 + Composer/package.json | 10 +- .../packages/client/config/webpack.config.js | 6 +- Composer/packages/client/jest.config.js | 2 + .../pages/language-generation/code-editor.tsx | 106 ++- .../src/pages/language-generation/index.tsx | 43 +- Composer/packages/client/src/utils/lgUtil.ts | 12 +- .../obiformeditor/demo/webpack.config.demo.js | 3 + .../extensions/obiformeditor/jest.config.js | 1 + .../extensions/obiformeditor/package.json | 1 + .../src/Form/widgets/LgEditorWidget.tsx | 124 +-- .../lib/code-editor/demo/.eslintrc.js | 7 + .../packages/lib/code-editor/demo/index.html | 36 +- .../lib/code-editor/demo/src/index.tsx | 11 +- .../lib/code-editor/demo/src/inlineEditor.tsx | 49 ++ .../lib/code-editor/demo/src/jsonEditor.tsx | 43 ++ .../lib/code-editor/demo/src/lgEditor.tsx | 89 +++ .../lib/code-editor/demo/src/lgJsonEditor.tsx | 124 +++ .../lib/code-editor/demo/src/luEditor.tsx | 229 ++++++ .../lib/code-editor/demo/src/multiEditors.tsx | 53 ++ .../demo/src/{App.tsx => richEditor.tsx} | 9 +- .../code-editor/demo/webpack.config.demo.js | 16 +- .../packages/lib/code-editor/package.json | 17 +- .../lib/code-editor/src/BaseEditor.tsx | 56 +- .../lib/code-editor/src/JsonEditor.tsx | 1 - .../packages/lib/code-editor/src/LgEditor.tsx | 98 ++- .../lib/code-editor/src/RichEditor.tsx | 7 +- .../lib/code-editor/src/languages/index.ts | 4 + .../lib/code-editor/src/languages/lg.ts | 110 +++ .../lib/code-editor/src/utils/common.ts | 27 + .../lib/code-editor/src/utils/index.ts | 1 + .../lib/code-editor/src/utils/lspUtil.ts | 61 ++ .../lib/code-editor/tsconfig.build.json | 6 +- .../packages/lib/code-editor/tsconfig.json | 8 +- Composer/packages/server/package.json | 6 +- Composer/packages/server/src/server.ts | 31 +- .../packages/server/src/utility/attachLSP.ts | 31 + .../language-generation/.eslintrc.js | 7 + .../language-generation/.gitignore | 3 + .../language-generation/README.md | 21 + .../language-generation/__tests__/app.test.ts | 149 ++++ .../__tests__/helpers/server.ts | 77 ++ .../__tests__/mocks/greeting.lg | 8 + .../__tests__/mocks/initialize-params.json | 238 ++++++ .../language-generation/demo/.eslintrc.js | 7 + .../language-generation/demo/src/attach.ts | 31 + .../language-generation/demo/src/server.ts | 44 ++ .../language-generation/demo/tsconfig.json | 10 + .../language-generation/jest.config.js | 15 + .../language-generation/package.json | 32 + .../language-generation/src/LGServer.ts | 362 +++++++++ .../src/builtinFunctionsMap.ts | 720 ++++++++++++++++++ .../language-generation/src/index.ts | 4 + .../language-generation/src/utils.ts | 126 +++ .../language-generation/tsconfig.build.json | 7 + .../language-generation/tsconfig.json | 10 + .../tools/language-servers/package.json | 12 + Composer/packages/tools/package.json | 12 + Composer/yarn.lock | 495 ++++++++---- 60 files changed, 3474 insertions(+), 396 deletions(-) create mode 100644 Composer/packages/lib/code-editor/demo/.eslintrc.js create mode 100644 Composer/packages/lib/code-editor/demo/src/inlineEditor.tsx create mode 100644 Composer/packages/lib/code-editor/demo/src/jsonEditor.tsx create mode 100644 Composer/packages/lib/code-editor/demo/src/lgEditor.tsx create mode 100644 Composer/packages/lib/code-editor/demo/src/lgJsonEditor.tsx create mode 100644 Composer/packages/lib/code-editor/demo/src/luEditor.tsx create mode 100644 Composer/packages/lib/code-editor/demo/src/multiEditors.tsx rename Composer/packages/lib/code-editor/demo/src/{App.tsx => richEditor.tsx} (91%) create mode 100644 Composer/packages/lib/code-editor/src/languages/index.ts create mode 100644 Composer/packages/lib/code-editor/src/languages/lg.ts create mode 100644 Composer/packages/lib/code-editor/src/utils/common.ts create mode 100644 Composer/packages/lib/code-editor/src/utils/lspUtil.ts create mode 100644 Composer/packages/server/src/utility/attachLSP.ts create mode 100644 Composer/packages/tools/language-servers/language-generation/.eslintrc.js create mode 100644 Composer/packages/tools/language-servers/language-generation/.gitignore create mode 100644 Composer/packages/tools/language-servers/language-generation/README.md create mode 100644 Composer/packages/tools/language-servers/language-generation/__tests__/app.test.ts create mode 100644 Composer/packages/tools/language-servers/language-generation/__tests__/helpers/server.ts create mode 100644 Composer/packages/tools/language-servers/language-generation/__tests__/mocks/greeting.lg create mode 100644 Composer/packages/tools/language-servers/language-generation/__tests__/mocks/initialize-params.json create mode 100644 Composer/packages/tools/language-servers/language-generation/demo/.eslintrc.js create mode 100644 Composer/packages/tools/language-servers/language-generation/demo/src/attach.ts create mode 100644 Composer/packages/tools/language-servers/language-generation/demo/src/server.ts create mode 100644 Composer/packages/tools/language-servers/language-generation/demo/tsconfig.json create mode 100644 Composer/packages/tools/language-servers/language-generation/jest.config.js create mode 100644 Composer/packages/tools/language-servers/language-generation/package.json create mode 100644 Composer/packages/tools/language-servers/language-generation/src/LGServer.ts create mode 100644 Composer/packages/tools/language-servers/language-generation/src/builtinFunctionsMap.ts create mode 100644 Composer/packages/tools/language-servers/language-generation/src/index.ts create mode 100644 Composer/packages/tools/language-servers/language-generation/src/utils.ts create mode 100644 Composer/packages/tools/language-servers/language-generation/tsconfig.build.json create mode 100644 Composer/packages/tools/language-servers/language-generation/tsconfig.json create mode 100644 Composer/packages/tools/language-servers/package.json create mode 100644 Composer/packages/tools/package.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 2506014c71..669e566005 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,14 +1,41 @@ { "version": "0.2.0", "configurations": [ + { + "type": "chrome", + "request": "attach", + "name": "Attach to Chrome", + "port": 9222, + "webRoot": "${workspaceFolder}" + }, + { + "name": "LSP Server", + "type": "node", + "request": "launch", + "args": [ + "${workspaceFolder}/Composer/packages/tools/language-servers/language-generation/demo/src/server.ts" + ], + "runtimeArgs": [ + "--nolazy", + "-r", + "${workspaceFolder}/Composer/node_modules/ts-node/register" + ], + "sourceMaps": true, + "cwd": "${workspaceFolder}/Composer/packages/tools/language-servers/language-generation/demo/src", + "protocol": "inspector", + }, { "type": "node", "request": "launch", "name": "Server: Launch", - "args": ["./build/server.js"], + "args": [ + "./build/server.js" + ], "preLaunchTask": "server: build", "restart": true, - "outFiles": ["./build/*"], + "outFiles": [ + "./build/*" + ], "envFile": "${workspaceFolder}/Composer/packages/server/.env", "outputCapture": "std", "cwd": "${workspaceFolder}/Composer/packages/server" @@ -20,8 +47,14 @@ "name": "Jest Debug", "program": "${workspaceRoot}/Composer/node_modules/jest/bin/jest", "stopOnEntry": false, - "args": ["--runInBand", "--env=jsdom", "--config=jest.config.js"], - "runtimeArgs": ["--inspect-brk"], + "args": [ + "--runInBand", + "--env=jsdom", + "--config=jest.config.js" + ], + "runtimeArgs": [ + "--inspect-brk" + ], "cwd": "${workspaceRoot}/Composer/packages/server", "sourceMaps": true, "console": "integratedTerminal" diff --git a/Composer/jest.config.js b/Composer/jest.config.js index 32b10b6b50..da2165fe69 100644 --- a/Composer/jest.config.js +++ b/Composer/jest.config.js @@ -41,5 +41,6 @@ module.exports = { '/packages/extensions/visual-designer', '/packages/lib/code-editor', '/packages/lib/shared', + '/packages/tools/language-servers/language-generation', ], }; diff --git a/Composer/package.json b/Composer/package.json index 21b3b3df5e..52a879a14e 100644 --- a/Composer/package.json +++ b/Composer/package.json @@ -13,16 +13,20 @@ "packages/extensions", "packages/extensions/*", "packages/lib", - "packages/lib/*" + "packages/lib/*", + "packages/tools", + "packages/tools/language-servers", + "packages/tools/language-servers/*" ], "scripts": { "build": "node scripts/begin.js && yarn build:prod", - "build:prod": "yarn build:lib && yarn build:extensions && yarn build:server && yarn build:client", - "build:dev": "yarn build:lib && yarn build:extensions", + "build:prod": "yarn build:dev && yarn build:server && yarn build:client", + "build:dev": "yarn build:tools && yarn build:lib && yarn build:extensions", "build:lib": "yarn workspace @bfc/libs build:all", "build:extensions": "yarn workspace @bfc/extensions build:all", "build:server": "yarn workspace @bfc/server build", "build:client": "yarn workspace @bfc/client build", + "build:tools": "yarn workspace @bfc/tools build:all", "start": "cross-env NODE_ENV=production PORT=3000 yarn start:server", "startall": "concurrently --kill-others-on-fail \"npm:runtime\" \"npm:start\"", "start:dev": "concurrently \"npm:start:client\" \"npm:start:server:dev\"", diff --git a/Composer/packages/client/config/webpack.config.js b/Composer/packages/client/config/webpack.config.js index 0a98e430f2..f56da750fe 100644 --- a/Composer/packages/client/config/webpack.config.js +++ b/Composer/packages/client/config/webpack.config.js @@ -228,6 +228,10 @@ module.exports = function(webpackEnv) { // `web` extension prefixes have been added for better support // for React Native Web. extensions: paths.moduleFileExtensions.map(ext => `.${ext}`), + alias: { + // Support lsp code editor + vscode: require.resolve('monaco-languageclient/lib/vscode-compatibility'), + }, plugins: [ // Adds support for installing with Plug'n'Play, leading to faster installs and adding // guards against forgotten dependencies and such. @@ -402,7 +406,7 @@ module.exports = function(webpackEnv) { plugins: [ new MonacoWebpackPlugin({ // available options are documented at https://github.com/Microsoft/monaco-editor-webpack-plugin#options - languages: ['markdown', 'botbuilderlg', 'json'], + languages: ['markdown', 'json'], }), // Generates an `index.html` file with the