diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 58b082894f..367822f379 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -24,7 +24,7 @@ jobs:
- name: Set Node Version
uses: actions/setup-node@v1
with:
- node-version: 14.15.5
+ node-version: 14.21.3
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
diff --git a/.gitignore b/.gitignore
index 68d4ecb9f5..4e5fd505bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -326,6 +326,7 @@ logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
+**/.swc
# Runtime data
pids
diff --git a/Composer/.eslintrc.js b/Composer/.eslintrc.js
index 2ae34a5390..6b2198f440 100644
--- a/Composer/.eslintrc.js
+++ b/Composer/.eslintrc.js
@@ -7,9 +7,8 @@ module.exports = {
'plugin:prettier/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/eslint-recommended',
- 'prettier/@typescript-eslint',
'plugin:@bfc/bfcomposer/recommended',
- 'plugin:security/recommended',
+ 'plugin:security/recommended-legacy',
],
plugins: ['import', 'notice', 'security', 'lodash', 'security'],
env: {
@@ -17,6 +16,13 @@ module.exports = {
es6: true,
node: true,
},
+ parserOptions: {
+ ecmaVersion: 6,
+ sourceType: 'module',
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
rules: {
'notice/notice': [
'error',
@@ -27,11 +33,11 @@ module.exports = {
],
// typescript
- '@typescript-eslint/ban-ts-ignore': 'warn',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/interface-name-prefix': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-unnecessary-type-assertion': 'off',
+ '@typescript-eslint/no-var-requires': 0,
'@typescript-eslint/no-use-before-define': 'warn',
'@typescript-eslint/prefer-optional-chain': 'error',
diff --git a/Composer/.eslintrc.react.js b/Composer/.eslintrc.react.js
index 4928044fa0..72f4a1ac8b 100644
--- a/Composer/.eslintrc.react.js
+++ b/Composer/.eslintrc.react.js
@@ -2,7 +2,7 @@
// Licensed under the MIT License.
module.exports = {
- extends: ['./.eslintrc.js', 'plugin:react/recommended', 'plugin:security/recommended'],
+ extends: ['./.eslintrc.js', 'plugin:react/recommended', 'plugin:security/recommended-legacy'],
plugins: ['react-hooks', 'format-message', '@emotion', 'jsx-a11y', 'security'],
settings: {
react: {
@@ -31,7 +31,7 @@ module.exports = {
'react/no-danger': 'error',
'react/no-deprecated': 'warn',
'react/prop-types': 'warn',
- 'react/no-unknown-property': 'error',
+ 'react/no-unknown-property': ['error', { 'ignore': ['css'] }],
'react/jsx-boolean-value': ['error', 'never'],
'react/jsx-filename-extension': ['error', { extensions: ['.jsx', '.tsx'] }],
// https://github.com/yannickcr/eslint-plugin-react/blob/HEAD/docs/rules/jsx-sort-props.md
diff --git a/Composer/.glf.json b/Composer/.glf.json
new file mode 100644
index 0000000000..a0813c4641
--- /dev/null
+++ b/Composer/.glf.json
@@ -0,0 +1,17 @@
+{
+ "inputs": ["./package.json"],
+ "output": "../ThirdPartyNotices.txt",
+ "overwrite": true,
+ "eol": "lf",
+ "no-spinner": true,
+ "replace": {
+ "@bcoe/v8-coverage@0.2.3": "./node_modules/@bcoe/v8-coverage/LICENSE.txt",
+ "through@2.3.8": "./node_modules/through/./LICENSE.MIT",
+ "rc@1.2.8": "./node_modules/rc/LICENSE.MIT",
+ "microsoft-cognitiveservices-speech-sdk@1.17.0": "./node_modules/microsoft-cognitiveservices-speech-sdk/LICENSE",
+ "doctrine@3.0.0": "./node_modules/doctrine/LICENSE",
+ "sax@0.5.8": "./node_modules/sax/LICENSE",
+ "atob@2.1.2": "./node_modules/atob/LICENSE",
+ "JSONStream@1.3.5": "./node_modules/JSONStream/LICENSE.MIT"
+ }
+}
\ No newline at end of file
diff --git a/Composer/package.json b/Composer/package.json
index 3311d9d67d..b19890c454 100644
--- a/Composer/package.json
+++ b/Composer/package.json
@@ -140,46 +140,46 @@
]
},
"devDependencies": {
- "@babel/cli": "7.18.6",
- "@babel/core": "7.18.6",
+ "@babel/cli": "7.23.9",
+ "@babel/core": "7.24.0",
"@babel/plugin-proposal-class-properties": "7.18.6",
- "@babel/plugin-transform-runtime": "7.18.6",
- "@babel/preset-env": "7.18.6",
- "@babel/preset-react": "7.18.6",
- "@babel/preset-typescript": "7.18.6",
+ "@babel/plugin-transform-runtime": "7.24.0",
+ "@babel/preset-env": "7.24.0",
+ "@babel/preset-react": "7.23.3",
+ "@babel/preset-typescript": "7.23.3",
"@bfc/eslint-plugin-bfcomposer": "workspace:*",
- "@emotion/babel-preset-css-prop": "11.2.0",
- "@emotion/eslint-plugin": "11.7.0",
- "@typescript-eslint/eslint-plugin": "2.34.0",
- "@typescript-eslint/parser": "2.34.0",
- "concurrently": "7.2.2",
+ "@emotion/babel-preset-css-prop": "11.11.0",
+ "@emotion/eslint-plugin": "11.11.0",
+ "@typescript-eslint/eslint-plugin": "5.62.0",
+ "@typescript-eslint/parser": "5.62.0",
+ "concurrently": "8.2.2",
"coveralls": "3.1.1",
"cross-env": "7.0.3",
- "eslint": "7.0.0",
- "eslint-config-prettier": "6.11.0",
+ "eslint": "8.57.0",
+ "eslint-config-prettier": "9.1.0",
"eslint-formatter-github-actions": "1.1.0",
"eslint-plugin-format-message": "6.2.4",
- "eslint-plugin-import": "2.26.0",
- "eslint-plugin-jsx-a11y": "6.6.0",
+ "eslint-plugin-import": "2.29.1",
+ "eslint-plugin-jsx-a11y": "6.8.0",
"eslint-plugin-lodash": "7.4.0",
"eslint-plugin-notice": "0.9.10",
- "eslint-plugin-prettier": "3.1.3",
- "eslint-plugin-react": "7.30.1",
+ "eslint-plugin-prettier": "5.1.3",
+ "eslint-plugin-react": "7.34.0",
"eslint-plugin-react-hooks": "4.6.0",
- "eslint-plugin-security": "1.5.0",
+ "eslint-plugin-security": "2.1.1",
"format-message": "6.2.4",
"format-message-cli": "6.2.4",
- "get-port": "6.1.2",
- "husky": "8.0.1",
+ "get-port": "7.0.0",
+ "husky": "9.0.11",
"jest": "27.4.7",
"jest-cli": "27.4.7",
- "lint-staged": "13.0.3",
- "prettier": "2.0.5",
+ "lint-staged": "15.2.2",
+ "prettier": "3.2.5",
"rimraf": "3.0.2",
- "ts-loader": "9.3.1",
- "tslib": "2.4.0",
- "typescript": "3.9.2",
- "wait-on": "6.0.1",
+ "ts-loader": "9.5.1",
+ "tslib": "2.6.2",
+ "typescript": "5.4.2",
+ "wait-on": "7.2.0",
"wsrun": "5.2.4"
}
}
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/AdaptiveFlowEditor.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/AdaptiveFlowEditor.test.tsx
index 3c411dfb34..30378cb39f 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/AdaptiveFlowEditor.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/AdaptiveFlowEditor.test.tsx
@@ -20,7 +20,7 @@ describe(' ', () => {
}}
>
-
+ ,
);
expect(visualDesigner).toBeTruthy();
});
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/components/KeyboardZone.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/components/KeyboardZone.test.tsx
index d636746431..8fc46e7404 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/components/KeyboardZone.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/components/KeyboardZone.test.tsx
@@ -19,7 +19,7 @@ describe('KeyboardZone', () => {
const zone = render(
undefined}>
children
-
+ ,
);
expect(zone).toBeTruthy();
expect(zone.getByTestId('zone-child')).toBeTruthy();
@@ -30,7 +30,7 @@ describe('KeyboardZone', () => {
const zone = render(
children
-
+ ,
).getByTestId('keyboard-zone');
fireEvent.focus(zone);
@@ -40,7 +40,7 @@ describe('KeyboardZone', () => {
key: 'C',
code: 'C',
ctrlKey: true,
- })
+ }),
);
expect(mockOnCommand).toHaveBeenCalled();
});
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/contexts/NodeRendererContext.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/contexts/NodeRendererContext.test.tsx
index 2ea28b9329..c8296e0f74 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/contexts/NodeRendererContext.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/contexts/NodeRendererContext.test.tsx
@@ -9,9 +9,8 @@ import { NodeRendererContext } from '../../../src/adaptive-flow-editor/contexts/
describe('NodeRendererContext', () => {
const CtxtConsumer = () => {
- const { focusedId, focusedEvent, focusedTab, clipboardActions, dialogFactory, customSchemas } = useContext(
- NodeRendererContext
- );
+ const { focusedId, focusedEvent, focusedTab, clipboardActions, dialogFactory, customSchemas } =
+ useContext(NodeRendererContext);
return (
@@ -37,7 +36,7 @@ describe('NodeRendererContext', () => {
}}
>
-
+ ,
);
expect(ele.getByTestId('focusedId-value').textContent).toEqual('id1');
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/contexts/SelectionContext.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/contexts/SelectionContext.test.tsx
index 6385eb3b5a..ff60c35f51 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/contexts/SelectionContext.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/contexts/SelectionContext.test.tsx
@@ -8,9 +8,8 @@ import { SelectionContext } from '../../../src/adaptive-flow-editor/contexts/Sel
describe('SelectionContext', () => {
const ContextConsumer = () => {
- const { getNodeIndex, getSelectableIds, selectedIds, setSelectedIds, selectableElements } = useContext(
- SelectionContext
- );
+ const { getNodeIndex, getSelectableIds, selectedIds, setSelectedIds, selectableElements } =
+ useContext(SelectionContext);
return (
{getNodeIndex('')}
@@ -33,7 +32,7 @@ describe('SelectionContext', () => {
}}
>
-
+ ,
);
expect(ele.getByTestId('getNodeIndex-result').textContent).toEqual('1');
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/hooks/useEditorEventApi.test.ts b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/hooks/useEditorEventApi.test.ts
index d198f87c69..c00d6e4e5e 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/hooks/useEditorEventApi.test.ts
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/hooks/useEditorEventApi.test.ts
@@ -18,8 +18,8 @@ describe('useEditorEventApi', () => {
nodeContext: { ...defaultRendererContextValue, focusedId: 'a' },
selectionContext: { ...defaultSelectionContextValue, selectedIds: ['a'] },
},
- ShellApiStub
- )
+ ShellApiStub,
+ ),
).result.current;
it('returns necessary apis.', () => {
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/EdgeMenu.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/EdgeMenu.test.tsx
index eff9b4d7e5..1acf332519 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/EdgeMenu.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/EdgeMenu.test.tsx
@@ -31,7 +31,7 @@ describe('createActionMenu()', () => {
label: 'Begin skill',
submenu: [SDKKinds.BeginSkill],
},
- }
+ },
);
const sdkBeginSkill = menuItems.find((item) => item.key === SDKKinds.BeginSkill);
@@ -61,7 +61,7 @@ describe('createActionMenu()', () => {
{ isSelfHosted: false, enablePaste: false },
[],
{},
- []
+ [],
);
expect(menuItemsWithoutCustomActions.findIndex((x) => x.key === 'Custom Actions')).toEqual(-1);
@@ -74,7 +74,7 @@ describe('createActionMenu()', () => {
{ isSelfHosted: false, enablePaste: false },
[],
{},
- customActions
+ customActions,
);
expect(withCustomActions.findIndex((x) => x.key === 'Custom Actions')).toEqual(withCustomActions.length - 1);
expect(withCustomActions[withCustomActions.length - 1].subMenuProps?.items.length).toEqual(3); // 2 action labels + 1 sep line
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/ElementWrapper.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/ElementWrapper.test.tsx
index 3452ef2e3f..f7e3c14b12 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/ElementWrapper.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/ElementWrapper.test.tsx
@@ -11,7 +11,7 @@ describe('
', () => {
const ele = render(
Content
-
+ ,
);
expect(ele).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/NodeWrapper.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/NodeWrapper.test.tsx
index a48fb8e335..f2be009c6e 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/NodeWrapper.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/renderers/NodeWrapper.test.tsx
@@ -20,7 +20,7 @@ describe('
', () => {
}}
>
-
+ ,
);
expect(ele.getByTestId('ActionNodeWrapper')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/stubs/ShellApiStub.ts b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/stubs/ShellApiStub.ts
index eae8379d3d..76fd1b2ad8 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/stubs/ShellApiStub.ts
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/stubs/ShellApiStub.ts
@@ -3,7 +3,7 @@
import { ShellApi } from '@bfc/shared';
-const fn = () => ({} as any);
+const fn = () => ({}) as any;
const fnList = () => [] as any[];
const fnPromise = () => Promise.resolve({} as any);
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/utils/cursorTracker/index.test.ts b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/utils/cursorTracker/index.test.ts
index 6e83131758..ea6c3d4df1 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/utils/cursorTracker/index.test.ts
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-editor/utils/cursorTracker/index.test.ts
@@ -23,8 +23,8 @@ describe('moveCursor', () => {
} as any,
],
'test',
- KeyboardCommandTypes.Cursor.MoveNext
- )
+ KeyboardCommandTypes.Cursor.MoveNext,
+ ),
).toEqual({ focused: 'test-focused', selected: 'test', tab: '' });
});
@@ -39,8 +39,8 @@ describe('moveCursor', () => {
} as any,
],
'test',
- KeyboardCommandTypes.Cursor.MoveLeft
- )
+ KeyboardCommandTypes.Cursor.MoveLeft,
+ ),
).toEqual({ focused: 'test-focused', selected: 'test', tab: '' });
});
});
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/adaptive/AdaptiveDialog.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/adaptive/AdaptiveDialog.test.tsx
index c588d5329e..bb558733bf 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/adaptive/AdaptiveDialog.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/adaptive/AdaptiveDialog.test.tsx
@@ -40,7 +40,7 @@ describe(' ', () => {
uischema={uischema}
widgets={widgets}
onEvent={() => null}
- />
+ />,
);
expect(renderResult.getAllByText('hello')).toHaveLength(1);
});
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/adaptive/AdaptiveTrigger.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/adaptive/AdaptiveTrigger.test.tsx
index 95d0abf1c4..0aa86e9e0a 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/adaptive/AdaptiveTrigger.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/adaptive/AdaptiveTrigger.test.tsx
@@ -32,7 +32,7 @@ describe(' ', () => {
const renderResult = render(
null} />
-
+ ,
);
expect(renderResult.getAllByText('hello')).toHaveLength(1);
});
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/ElementMeasurer.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/ElementMeasurer.test.tsx
index 422a8ec856..dbe06ad61d 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/ElementMeasurer.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/ElementMeasurer.test.tsx
@@ -11,7 +11,7 @@ describe(' ', () => {
const ele = render(
null}>
-
+ ,
);
expect(ele.getByTestId('measurer-content')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/OffsetContainer.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/OffsetContainer.test.tsx
index 7768c425c7..669e21c748 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/OffsetContainer.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/OffsetContainer.test.tsx
@@ -11,7 +11,7 @@ describe(' ', () => {
const offsetContainer = render(
<>>
-
+ ,
);
expect(offsetContainer).toBeTruthy();
@@ -22,7 +22,7 @@ describe(' ', () => {
const offsetContainer = render(
-
+ ,
);
expect(offsetContainer.getByTestId('offset-content')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/SVGContainer.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/SVGContainer.test.tsx
index b8326b5c6d..88bbb2987e 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/SVGContainer.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/components/SVGContainer.test.tsx
@@ -11,7 +11,7 @@ describe(' ', () => {
const svgContainer = render(
<>>
-
+ ,
);
expect(svgContainer).toBeTruthy();
@@ -22,7 +22,7 @@ describe(' ', () => {
const svgContainer = render(
-
+ ,
);
expect(svgContainer.getByTestId('svg-content')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/layouters/calculateNodeBoundary.test.ts b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/layouters/calculateNodeBoundary.test.ts
index d352d50559..7e0e19fa8a 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/layouters/calculateNodeBoundary.test.ts
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/layouters/calculateNodeBoundary.test.ts
@@ -60,7 +60,7 @@ describe('calculateIfElseBoundary', () => {
expect(bdWithBothBranch.height - bdWithNoBranch.height).toEqual(ifBoundary.height);
expect(bdWithBothBranch.height).toBeGreaterThan(
- conditionBoundary.height + choiceBoundary.height + Math.max(ifBoundary.height, elseBoundary.height)
+ conditionBoundary.height + choiceBoundary.height + Math.max(ifBoundary.height, elseBoundary.height),
);
expect(bdWithBothBranch.width).toBeGreaterThan(ifBoundary.width + elseBoundary.width);
});
@@ -107,7 +107,7 @@ describe('calculateForeachBoundary', () => {
axisY: 0,
};
expect(calculateForeachBoundary(foreachBoundary, stepsBoundary, loopBeginBoundary, loopEndBoundary)).toEqual(
- returnBoundary
+ returnBoundary,
);
});
});
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/layouters/measureJsonBoundary.test.ts b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/layouters/measureJsonBoundary.test.ts
index 1857263683..d3f265d44f 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/layouters/measureJsonBoundary.test.ts
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/layouters/measureJsonBoundary.test.ts
@@ -24,16 +24,16 @@ describe('measureJsonBoundary', () => {
});
it('should return boundary whose size is determined by the json.$kind', () => {
expect(measureJsonBoundary({ $kind: AdaptiveKinds.ChoiceDiamond })).toEqual(
- new Boundary(DiamondSize.width, DiamondSize.height)
+ new Boundary(DiamondSize.width, DiamondSize.height),
);
expect(measureJsonBoundary({ $kind: AdaptiveKinds.ConditionNode })).toEqual(
- new Boundary(InitNodeSize.width, InitNodeSize.height)
+ new Boundary(InitNodeSize.width, InitNodeSize.height),
);
expect(measureJsonBoundary({ $kind: AdaptiveKinds.LoopIndicator })).toEqual(
- new Boundary(LoopIconSize.width, LoopIconSize.height)
+ new Boundary(LoopIconSize.width, LoopIconSize.height),
);
expect(measureJsonBoundary({ $kind: AdaptiveKinds.LogAction })).toEqual(
- new Boundary(StandardNodeWidth, HeaderHeight)
+ new Boundary(StandardNodeWidth, HeaderHeight),
);
});
it("should return boundary whose size is determined by the data's choices when json.$kind is choiceInput", () => {
@@ -49,11 +49,11 @@ describe('measureJsonBoundary', () => {
expect(measureJsonBoundary(data1)).toEqual(
new Boundary(
InitNodeSize.width,
- InitNodeSize.height + ChoiceInputSize.height + ChoiceInputMarginTop + ChoiceInputMarginBottom
- )
+ InitNodeSize.height + ChoiceInputSize.height + ChoiceInputMarginTop + ChoiceInputMarginBottom,
+ ),
);
expect(measureJsonBoundary(data2)).toEqual(
- new Boundary(InitNodeSize.width, InitNodeSize.height + 4 * (ChoiceInputSize.height + ChoiceInputMarginTop))
+ new Boundary(InitNodeSize.width, InitNodeSize.height + 4 * (ChoiceInputSize.height + ChoiceInputMarginTop)),
);
});
});
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/transformers/transformStepGroup.test.ts b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/transformers/transformStepGroup.test.ts
index 1fb1c4d87d..83ae774c22 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/transformers/transformStepGroup.test.ts
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/transformers/transformStepGroup.test.ts
@@ -15,7 +15,7 @@ test('should transform string as BeginDialog', () => {
$kind: AdaptiveKinds.StepGroup,
children: ['CalleeDialog'],
},
- ''
+ '',
);
expect(result[0].json).toEqual({
$kind: AdaptiveKinds.BeginDialog,
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/EdgeUtil.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/EdgeUtil.test.tsx
index b25f6f0d6a..e35ad8cbc3 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/EdgeUtil.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/EdgeUtil.test.tsx
@@ -22,7 +22,7 @@ describe('drawSVGEdge', () => {
it('should render an arrowhead when "directed" option set to true', async () => {
const { container } = render(
- {drawSVGEdge('test', 10, 10, EdgeDirection.Right, 100, { directed: true })}
+ {drawSVGEdge('test', 10, 10, EdgeDirection.Right, 100, { directed: true })} ,
);
const lines = await container.querySelectorAll('line');
expect(lines.length).toEqual(1);
@@ -33,7 +33,7 @@ describe('drawSVGEdge', () => {
it('should render label text when "label" is set', async () => {
const { container } = render(
- {drawSVGEdge('test', 10, 10, EdgeDirection.Right, 100, { label: 'hello' })}
+ {drawSVGEdge('test', 10, 10, EdgeDirection.Right, 100, { label: 'hello' })} ,
);
const labels = await container.querySelectorAll('text');
expect(labels.length).toEqual(1);
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/widgetExpressionEvaluator.test.ts b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/widgetExpressionEvaluator.test.ts
index 1205b69ec7..c4ae50f344 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/widgetExpressionEvaluator.test.ts
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/widgetExpressionEvaluator.test.ts
@@ -64,7 +64,7 @@ describe('evaluateWidgetProp()', () => {
expect(evaluate('=concat(a.x, " and ", a.y)', { a: { X: 'X', Y: 'Y' } })).toEqual('X and Y');
expect(evaluate('=concat(a.x, " and ", a.y)', { a: { x: 1 } })).toEqual('1 and ');
expect(evaluate('=concat(string(a.x), " and ", string(a.y))', { a: { x: { val: 1 }, y: [1] } })).toEqual(
- '{"val":1} and [1]'
+ '{"val":1} and [1]',
);
});
@@ -73,10 +73,10 @@ describe('evaluateWidgetProp()', () => {
expect(
evaluate('=concat("Each value in ", coalesce(action.itemsProperty, "?"))', {
action: { itemsProperty: 'user.names' },
- })
+ }),
).toEqual('Each value in user.names');
expect(evaluate('=concat("Each value in ", coalesce(action.itemsProperty, "?"))', { action: {} })).toEqual(
- 'Each value in ?'
+ 'Each value in ?',
);
});
@@ -89,7 +89,7 @@ describe('evaluateWidgetProp()', () => {
{ property: 'b', value: '2' },
],
},
- })
+ }),
).toEqual(['a : 1', 'b : 2']);
});
});
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/widgetRenderer.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/widgetRenderer.test.tsx
index f2a653e0ab..589b963be6 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/widgetRenderer.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/utils/widgetRenderer.test.tsx
@@ -24,7 +24,7 @@ describe('renderUIWidget', () => {
const ele = renderWidget(
schema,
{ TestWidget },
- { id: '', data: { $kind: 'Kind' }, onEvent: () => null, onResize: () => null }
+ { id: '', data: { $kind: 'Kind' }, onEvent: () => null, onResize: () => null },
);
expect(ele.getByTestId('test-widget')).toBeTruthy();
expect(ele.getAllByText('test')).toHaveLength(1);
@@ -39,7 +39,7 @@ describe('renderUIWidget', () => {
const ele = renderWidget(
schema,
{ TestWidget },
- { id: '', data: { $kind: 'Kind', value: 'testValue' } as any, onEvent: () => null, onResize: () => null }
+ { id: '', data: { $kind: 'Kind', value: 'testValue' } as any, onEvent: () => null, onResize: () => null },
);
expect(ele.getByTestId('test-widget')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/ActionCard.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/ActionCard.test.tsx
index 1162aa58a9..fafaa25bf4 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/ActionCard.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/ActionCard.test.tsx
@@ -10,7 +10,7 @@ import { AdaptiveKinds } from '../../../src/adaptive-flow-renderer/constants/Ada
describe('ActionCard', () => {
it('can be rendered.', () => {
const card = render(
- null} />
+ null} />,
);
expect(card).toBeTruthy();
});
@@ -25,7 +25,7 @@ describe('ActionCard', () => {
header={Header }
id="test"
onEvent={() => null}
- />
+ />,
);
expect(card.getByTestId('test-header')).toBeTruthy();
expect(card.getByTestId('test-body')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/DialogRef.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/DialogRef.test.tsx
index fa6a90262d..38ebf1bd70 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/DialogRef.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/DialogRef.test.tsx
@@ -10,14 +10,14 @@ import { AdaptiveKinds } from '../../../src/adaptive-flow-renderer/constants/Ada
describe('DialogRef', () => {
it('can be rendered.', () => {
const dialogRef = render(
- null} />
+ null} />,
);
expect(dialogRef).toBeTruthy();
});
it('can ref string dialog value correctly.', () => {
const dialogRef = render(
- null} />
+ null} />,
);
expect(dialogRef.queryAllByText('test-dialog')).toHaveLength(1);
});
@@ -29,7 +29,7 @@ describe('DialogRef', () => {
dialog={{ $ref: 'test-dialog-obj' }}
id="test"
onEvent={() => null}
- />
+ />,
);
expect(dialogRef.queryAllByText('test-dialog-obj')).toHaveLength(1);
});
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/ForeachWidget.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/ForeachWidget.test.tsx
index 79880d665b..b362e77981 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/ForeachWidget.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/ForeachWidget.test.tsx
@@ -15,7 +15,7 @@ describe('ForeachWidget', () => {
id="test"
loop={Loop Head }
onEvent={() => null}
- />
+ />,
);
expect(foreachNode).toBeTruthy();
expect(foreachNode.getByTestId('test-loop')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/IfConditionWidget.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/IfConditionWidget.test.tsx
index 618405aa52..4c8daa9730 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/IfConditionWidget.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/IfConditionWidget.test.tsx
@@ -15,7 +15,7 @@ describe('IfConditionWidget', () => {
id="test"
judgement={Condition Judgement }
onEvent={() => null}
- />
+ />,
);
expect(ifCondition).toBeTruthy();
expect(ifCondition.getByTestId('test-judgement')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/PromptWidget.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/PromptWidget.test.tsx
index a8b03a7500..a46118d4f7 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/PromptWidget.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/PromptWidget.test.tsx
@@ -16,7 +16,7 @@ describe('PromptWidget', () => {
id="test"
userInput={UserInput }
onEvent={() => null}
- />
+ />,
);
expect(promptNode).toBeTruthy();
expect(promptNode.getByTestId('test-botAsks')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/SwitchConditionWidget.test.tsx b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/SwitchConditionWidget.test.tsx
index 18a4aabde1..d5a384c660 100644
--- a/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/SwitchConditionWidget.test.tsx
+++ b/Composer/packages/adaptive-flow/__tests__/adaptive-flow-renderer/widgets/SwitchConditionWidget.test.tsx
@@ -15,7 +15,7 @@ describe('SwitchConditionWidget', () => {
id="test"
judgement={Condition Judgement }
onEvent={() => null}
- />
+ />,
);
expect(switchCondition).toBeTruthy();
expect(switchCondition.getByTestId('test-judgement')).toBeTruthy();
diff --git a/Composer/packages/adaptive-flow/package.json b/Composer/packages/adaptive-flow/package.json
index 52048ee8e6..ca6fbfa1d5 100644
--- a/Composer/packages/adaptive-flow/package.json
+++ b/Composer/packages/adaptive-flow/package.json
@@ -15,7 +15,7 @@
"scripts": {
"build": "yarn clean && yarn build:ts",
"build:ts": "tsc --build tsconfig.build.json",
- "clean": "rimraf lib demo/dist",
+ "clean": "rimraf lib demo/dist .swc",
"prepublishOnly": "npm run build",
"start": "webpack-dev-server --config demo/webpack.config.demo.js --port 3002",
"test": "jest --no-cache",
@@ -39,7 +39,7 @@
"prop-types": "^15.7.2",
"react-measure": "^2.3.0",
"source-map-loader": "^0.2.4",
- "tslib": "2.4.0"
+ "tslib": "2.6.2"
},
"peerDependencies": {
"format-message": "^6.2.3",
@@ -53,7 +53,7 @@
"json-loader": "^0.5.7",
"react": "16.13.1",
"react-dom": "16.13.1",
- "ts-loader": "9.3.1",
+ "ts-loader": "9.5.1",
"tsconfig-paths-webpack-plugin": "^3.2.0"
},
"author": "",
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/AdaptiveFlowEditor.tsx b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/AdaptiveFlowEditor.tsx
index 0bba6145db..cef0b337d9 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/AdaptiveFlowEditor.tsx
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/AdaptiveFlowEditor.tsx
@@ -37,7 +37,7 @@ formatMessage.setup({
const emotionCache = createCache({
key: 'adaptive-form-cache',
- // @ts-expect-error
+ // @ts-expect-error: nounce defined during server rendering the page
nonce: window.__nonce__,
});
@@ -96,10 +96,10 @@ const VisualDesigner: React.FC = ({ onFocus, onBlur, schema
const focusedId = Array.isArray(focusedActions) && focusedActions[0] ? focusedActions[0] : '';
// Compute schema diff
- const customActionSchema = useMemo(() => getCustomSchema(schemas?.default, schemas?.sdk?.content).actions, [
- schemas?.sdk?.content,
- schemas?.default,
- ]);
+ const customActionSchema = useMemo(
+ () => getCustomSchema(schemas?.default, schemas?.sdk?.content).actions,
+ [schemas?.sdk?.content, schemas?.default],
+ );
const nodeContext: NodeRendererContextValue = {
focusedId,
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/hooks/useDialogEditApi.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/hooks/useDialogEditApi.ts
index 4b2b038804..f1ac1a70ed 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/hooks/useDialogEditApi.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/hooks/useDialogEditApi.ts
@@ -21,7 +21,7 @@ export function useDialogEditApi(shellApi: ShellApi) {
dialogData: MicrosoftIDialog,
targetArrayPath: string,
targetArrayPosition: number,
- actionsToInsert: MicrosoftIDialog[]
+ actionsToInsert: MicrosoftIDialog[],
): Promise {
const newNodes = await constructActions(dialogId, actionsToInsert);
return insertNodes(dialogData, targetArrayPath, targetArrayPosition, newNodes) as MicrosoftIDialog;
@@ -32,7 +32,7 @@ export function useDialogEditApi(shellApi: ShellApi) {
dialogData: MicrosoftIDialog,
targetArrayPath: string,
targetArrayPosition: number,
- actionToInsert: MicrosoftIDialog
+ actionToInsert: MicrosoftIDialog,
): Promise {
return insertActions(dialogId, dialogData, targetArrayPath, targetArrayPosition, [actionToInsert]);
}
@@ -41,7 +41,7 @@ export function useDialogEditApi(shellApi: ShellApi) {
dialogId: string,
dialogData: MicrosoftIDialog,
targetId: string,
- actionsToInsert: MicrosoftIDialog[]
+ actionsToInsert: MicrosoftIDialog[],
): Promise {
const newNodes = await constructActions(dialogId, actionsToInsert);
return appendNodesAfter(dialogData, targetId, newNodes) as MicrosoftIDialog;
@@ -50,7 +50,7 @@ export function useDialogEditApi(shellApi: ShellApi) {
function deleteSelectedAction(
dialogId: string,
dialogData: MicrosoftIDialog,
- actionId: string
+ actionId: string,
): Promise {
return deleteNode(dialogData, actionId, (node) => deleteAction(dialogId, node));
}
@@ -58,7 +58,7 @@ export function useDialogEditApi(shellApi: ShellApi) {
function deleteSelectedActions(
dialogId: string,
dialogData: MicrosoftIDialog,
- actionIds: string[]
+ actionIds: string[],
): Promise {
return deleteNodes(dialogData, actionIds, (nodes) => deleteActions(dialogId, nodes));
}
@@ -66,7 +66,7 @@ export function useDialogEditApi(shellApi: ShellApi) {
function disableSelectedActions(
dialogId: string,
dialogData: MicrosoftIDialog,
- actionIds: string[]
+ actionIds: string[],
): MicrosoftIDialog {
return disableNodes(dialogData, actionIds);
}
@@ -74,14 +74,14 @@ export function useDialogEditApi(shellApi: ShellApi) {
function enableSelectedActions(
dialogId: string,
dialogData: MicrosoftIDialog,
- actionIds: string[]
+ actionIds: string[],
): MicrosoftIDialog {
return enableNodes(dialogData, actionIds);
}
async function copySelectedActions(
dialogId: string,
dialogData: MicrosoftIDialog,
- actionIds: string[]
+ actionIds: string[],
): Promise {
const actions = queryNodes(dialogData, actionIds);
return copyActions(dialogId, actions);
@@ -90,7 +90,7 @@ export function useDialogEditApi(shellApi: ShellApi) {
async function cutSelectedActions(
dialogId: string,
dialogData: MicrosoftIDialog,
- actionIds: string[]
+ actionIds: string[],
): Promise<{ dialog: MicrosoftIDialog; cutActions: MicrosoftIDialog[] }> {
const cutActions = await copySelectedActions(dialogId, dialogData, actionIds);
const newDialog = await deleteSelectedActions(dialogId, dialogData, actionIds);
@@ -100,7 +100,7 @@ export function useDialogEditApi(shellApi: ShellApi) {
function updateRecognizer(
dialogId: string,
dialogData: MicrosoftIDialog,
- recognizer: MicrosoftIRecognizer | string
+ recognizer: MicrosoftIRecognizer | string,
): MicrosoftIDialog {
dialogData.recognizer = recognizer;
return dialogData;
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/hooks/useEditorEventApi.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/hooks/useEditorEventApi.ts
index 2556c5d338..fea4996ad8 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/hooks/useEditorEventApi.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/hooks/useEditorEventApi.ts
@@ -26,7 +26,7 @@ export const useEditorEventApi = (
nodeContext: NodeRendererContextValue;
selectionContext: SelectionContextData;
},
- shellApi: ShellApi
+ shellApi: ShellApi,
) => {
const { actionsContainLuIntent, getDialog, saveDialog, createDialog } = shellApi;
const {
@@ -167,7 +167,7 @@ export const useEditorEventApi = (
onChange(value, undefined, async () => {
await onFocusSteps([]);
announce(ScreenReaderMessage.ActionDeleted);
- })
+ }),
);
};
break;
@@ -264,7 +264,7 @@ export const useEditorEventApi = (
newDialogData,
`${'triggers'}[0].${'actions'}`,
0,
- actionsToBeMoved
+ actionsToBeMoved,
);
if (actionsContainLuIntent(actionsToBeMoved)) {
// auto assign recognizer type to lu
@@ -285,7 +285,7 @@ export const useEditorEventApi = (
deleteResult,
placeholderPosition.arrayPath,
placeholderPosition.arrayIndex,
- placeholderAction
+ placeholderAction,
);
onChange(insertResult, undefined, async () => {
await onFocusSteps([]);
@@ -301,7 +301,7 @@ export const useEditorEventApi = (
onChange(value, undefined, async () => {
await onFocusSteps([]);
announce(ScreenReaderMessage.ActionsDeleted);
- })
+ }),
);
};
break;
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/EdgeMenu/EdgeMenu.tsx b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/EdgeMenu/EdgeMenu.tsx
index f58c0d06e5..e3764c8f36 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/EdgeMenu/EdgeMenu.tsx
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/EdgeMenu/EdgeMenu.tsx
@@ -45,8 +45,8 @@ export const EdgeMenu: React.FC = ({ id, onClick }) => {
boxShadow += menuSelected
? `,0 0 0 2px ${ObiColors.AzureBlue}`
: nodeSelected
- ? `, 0 0 0 2px ${ObiColors.Black}`
- : '';
+ ? `, 0 0 0 2px ${ObiColors.Black}`
+ : '';
const handleMenuShow = (menuSelected) => {
setMenuSelected(menuSelected);
@@ -65,7 +65,7 @@ export const EdgeMenu: React.FC = ({ id, onClick }) => {
forceDisabledActions,
menuSchema,
// Custom Action 'oneOf' arrays from schema file
- customSchemas.map((x) => x.oneOf).filter((oneOf) => Array.isArray(oneOf) && oneOf.length) as DefinitionSummary[][]
+ customSchemas.map((x) => x.oneOf).filter((oneOf) => Array.isArray(oneOf) && oneOf.length) as DefinitionSummary[][],
);
const moreLabel = formatMessage('Add');
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/EdgeMenu/createSchemaMenu.tsx b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/EdgeMenu/createSchemaMenu.tsx
index 90e1f9dcae..8f5f981318 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/EdgeMenu/createSchemaMenu.tsx
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/EdgeMenu/createSchemaMenu.tsx
@@ -40,7 +40,7 @@ const createBaseActionMenu = (
menuSchema: MenuUISchema,
onClick: ActionMenuItemClickHandler,
forceDisabledActions: DisabledMenuActions[],
- filter?: ActionKindFilter
+ filter?: ActionKindFilter,
): IContextualMenuItem[] => {
const menuTree: MenuTree = Object.entries(menuSchema).reduce((result, [$kind, options]) => {
if (filter && !filter($kind as SDKKinds)) return result;
@@ -97,7 +97,7 @@ const get$kindFrom$ref = ($ref: string): SDKKinds => {
const createCustomActionSubMenu = (
customizedActionGroups: DefinitionSummary[][],
onClick: ActionMenuItemClickHandler,
- filter?: ($kind: SDKKinds) => boolean
+ filter?: ($kind: SDKKinds) => boolean,
): IContextualMenuItem[] => {
if (!Array.isArray(customizedActionGroups) || customizedActionGroups.length === 0) {
return [];
@@ -112,7 +112,7 @@ const createCustomActionSubMenu = (
key: get$kindFrom$ref($ref),
name: title,
onClick: (e, itemData) => onClick(itemData),
- } as IContextualMenuItem)
+ }) as IContextualMenuItem,
);
if (filter) {
return items.filter(({ key }) => filter(key as SDKKinds));
@@ -135,7 +135,7 @@ const createCustomActionSubMenu = (
const createPasteButtonItem = (
menuItemCount: number,
disabled: boolean,
- onClick: ActionMenuItemClickHandler
+ onClick: ActionMenuItemClickHandler,
): IContextualMenuItem => {
return {
key: 'Paste',
@@ -190,7 +190,7 @@ const createSubMenu = (
label: string,
onClick: ActionMenuItemClickHandler,
subItems: IContextualMenuItem[],
- forceDisabledActions: DisabledMenuActions[]
+ forceDisabledActions: DisabledMenuActions[],
): IContextualMenuItem => {
const subMenuItems = subItems.map((subMenuItem: IContextualMenuItem) => {
let additionalProps: Partial = {};
@@ -234,7 +234,7 @@ export const createActionMenu = (
options: ActionMenuOptions,
forceDisabledActions: DisabledMenuActions[],
menuSchema?: MenuUISchema,
- customActionGroups?: DefinitionSummary[][]
+ customActionGroups?: DefinitionSummary[][],
) => {
const resultItems: IContextualMenuItem[] = [];
const menuOptions = menuSchema || {};
@@ -244,7 +244,7 @@ export const createActionMenu = (
menuOptions,
onClick,
forceDisabledActions,
- options.isSelfHosted ? ($kind: SDKKinds) => $kind !== SDKKinds.LogAction : undefined
+ options.isSelfHosted ? ($kind: SDKKinds) => $kind !== SDKKinds.LogAction : undefined,
);
resultItems.push(...baseMenuItems);
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/NodeWrapper.tsx b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/NodeWrapper.tsx
index f175f3de0f..37eb0ed121 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/NodeWrapper.tsx
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/renderers/NodeWrapper.tsx
@@ -27,7 +27,9 @@ const nodeBorderSelectedStyle = css`
// BotAsks, UserAnswers and InvalidPromptBrick nodes selected style
const nodeBorderDoubleSelectedStyle = css`
- box-shadow: 0px 0px 0px 2px #0078d4, 0px 0px 0px 6px rgba(0, 120, 212, 0.3);
+ box-shadow:
+ 0px 0px 0px 2px #0078d4,
+ 0px 0px 0px 6px rgba(0, 120, 212, 0.3);
`;
/**
@@ -91,7 +93,7 @@ export const ActionNodeWrapper = ({ id, tab, data, onEvent, hideComment, childre
(action) => {
nodeFocused && addCoachMarkRef({ action });
},
- [nodeFocused]
+ [nodeFocused],
);
useEffect(() => {
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/calculateRangeSelection.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/calculateRangeSelection.ts
index dbbea65467..6e93c1fda7 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/calculateRangeSelection.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/calculateRangeSelection.ts
@@ -4,7 +4,7 @@
export const calculateRangeSelection = (
focusedId: string,
clickedId: string,
- orderedSelectableIds: string[]
+ orderedSelectableIds: string[],
): string[] => {
const range = [focusedId, clickedId].map((id) => orderedSelectableIds.findIndex((x) => x === id));
const [fromIndex, toIndex] = range.sort();
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/arrowMove.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/arrowMove.ts
index 64edb49f25..fd1be52ec3 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/arrowMove.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/arrowMove.ts
@@ -9,7 +9,7 @@ import { SelectorElement, Direction } from './type';
export function handleArrowkeyMove(
currentElement: SelectorElement,
selectableElements: SelectorElement[],
- command: string
+ command: string,
) {
let element: SelectorElement = currentElement;
let direction: Direction;
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/calculate/calculateBySchema.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/calculate/calculateBySchema.ts
index e4b8176fb8..7e4cbbe73a 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/calculate/calculateBySchema.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/calculate/calculateBySchema.ts
@@ -38,7 +38,7 @@ function transformDefaultBranch(path) {
export function filterPromptElementsBySchema(
currentElement: SelectorElement,
elements: SelectorElement[],
- direction: Direction
+ direction: Direction,
): SelectorElement[] {
let candidateElements: SelectorElement[] = elements;
@@ -46,7 +46,7 @@ export function filterPromptElementsBySchema(
case Direction.Up:
if (currentElement.tab === PromptTab.OTHER || currentElement.tab === PromptTab.USER_INPUT) {
candidateElements = elements.filter(
- (ele) => ele.selectedId === `${currentElement.focusedId}${PromptTab.BOT_ASKS}`
+ (ele) => ele.selectedId === `${currentElement.focusedId}${PromptTab.BOT_ASKS}`,
);
}
break;
@@ -65,7 +65,7 @@ export function filterPromptElementsBySchema(
candidateElements = elements.filter((ele) => ele.tab !== PromptTab.OTHER);
} else if (currentElement.tab === PromptTab.BOT_ASKS || currentElement.tab === PromptTab.USER_INPUT) {
candidateElements = elements.filter(
- (ele) => ele.selectedId === `${currentElement.focusedId}${PromptTab.OTHER}`
+ (ele) => ele.selectedId === `${currentElement.focusedId}${PromptTab.OTHER}`,
);
}
break;
@@ -120,7 +120,7 @@ function handlePrevMoveFilter(currentElement: SelectorElement, elements: Selecto
function handleSwitchCasePrevMoveFilter(
currentElement: SelectorElement,
- elements: SelectorElement[]
+ elements: SelectorElement[],
): SelectorElement[] {
const currentElementSelectors = parseSelector(transformDefaultBranch(currentElement.selectedId)) as string[];
let swicthPosition = -1;
@@ -182,7 +182,7 @@ function handleSwitchCaseNextMoveFilter(currentElement: SelectorElement, element
export function filterElementBySchema(
currentElement: SelectorElement,
elements: SelectorElement[],
- direction: Direction
+ direction: Direction,
) {
const currentElementSelectors = parseSelector(transformDefaultBranch(currentElement.selectedId)) as string[];
let candidateElements = elements;
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/calculate/calculateByVector.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/calculate/calculateByVector.ts
index 5e3e9076b3..a330e4528e 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/calculate/calculateByVector.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/calculate/calculateByVector.ts
@@ -23,7 +23,7 @@ function transformDirectionToVectorAttrs(direction: Direction): Record
- results.push(elements.find((element) => vector.selectedId === element.selectedId) as SelectorElement)
+ results.push(elements.find((element) => vector.selectedId === element.selectedId) as SelectorElement),
);
return results;
}
@@ -32,7 +32,7 @@ function calculateElementVector(
currentElement: SelectorElement,
elements: SelectorElement[],
boundRectKey: BoundRect,
- assistAxle: Axle
+ assistAxle: Axle,
): ElementVector[] {
const currentElementBounds = currentElement.bounds;
const elementVectors: ElementVector[] = [];
@@ -48,7 +48,7 @@ function calculateElementVector(
distance = currentElementBounds[boundRectKey] - bounds[boundRectKey];
}
assistDistance = Math.abs(
- currentElementBounds.left + currentElementBounds.width / 2 - (bounds.left + bounds.width / 2)
+ currentElementBounds.left + currentElementBounds.width / 2 - (bounds.left + bounds.width / 2),
);
} else {
if (boundRectKey === BoundRect.Left) {
@@ -63,7 +63,7 @@ function calculateElementVector(
(bounds[boundRectKey] - bounds.width / 2);
}
assistDistance = Math.abs(
- currentElementBounds.top + currentElementBounds.height / 2 - (bounds.top + bounds.height / 2)
+ currentElementBounds.top + currentElementBounds.height / 2 - (bounds.top + bounds.height / 2),
);
}
elementVectors.push({
@@ -78,7 +78,7 @@ function calculateElementVector(
export function sortElementsByVector(
currentElement: SelectorElement,
elements: SelectorElement[],
- direction: Direction
+ direction: Direction,
): SelectorElement[] {
const { assistAxle, boundRectKey } = transformDirectionToVectorAttrs(direction);
const elementVectors = calculateElementVector(currentElement, elements, boundRectKey, assistAxle);
@@ -90,7 +90,7 @@ export function sortElementsByVector(
export function filterElementsByVector(
currentElement: SelectorElement,
elements: SelectorElement[],
- direction: Direction
+ direction: Direction,
): SelectorElement[] {
const { assistAxle, boundRectKey } = transformDirectionToVectorAttrs(direction);
const elementVectors = calculateElementVector(currentElement, elements, boundRectKey, assistAxle);
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/index.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/index.ts
index 82e6e296cb..ac0e93a2c7 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/index.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/index.ts
@@ -11,7 +11,7 @@ import { handleTabMove } from './tabMove';
export function moveCursor(
selectableElements: SelectorElement[],
id: string,
- command: string
+ command: string,
): { [key: string]: string | undefined } {
const currentElement = selectableElements.find((element) => element.selectedId === id || element.focusedId === id);
if (!currentElement) return { selected: id, focused: undefined };
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/locateElement.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/locateElement.ts
index edbb880d8f..8039a09547 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/locateElement.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/locateElement.ts
@@ -16,7 +16,7 @@ export function locateNearestElement(
currentElement: SelectorElement,
elements: SelectorElement[],
direction: Direction,
- filterAttrs?: string[]
+ filterAttrs?: string[],
): SelectorElement {
// Get elements that meet the filter criteria
let elementArr = elements.filter((element) => !filterAttrs || filterAttrs?.find((key) => !!element[key]));
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/tabMove.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/tabMove.ts
index a76c503699..aa8d573859 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/tabMove.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/cursorTracker/tabMove.ts
@@ -39,13 +39,13 @@ export function handleTabMove(currentElement: SelectorElement, selectableElement
(el) =>
!selectableChildren.includes(el) &&
el.bounds.top > currentElement.bounds.top - 10 &&
- el.bounds.top < currentElement.bounds.top + 10
+ el.bounds.top < currentElement.bounds.top + 10,
);
const nextSibling = locateNearestElement(
currentElement,
selectableSiblings,
command === KeyboardCommandTypes.Cursor.MoveNext ? Direction.Right : Direction.Left,
- ['isNode', 'isEdgeMenu']
+ ['isNode', 'isEdgeMenu'],
);
const findElementWithSuffix = (suffix) => {
return selectableElements.find((element) => element.selectedId === `${selectableParent?.selectedId}${suffix}`);
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/getCustomSchema.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/getCustomSchema.ts
index e88810fef8..b84cbae1a8 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/getCustomSchema.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-editor/utils/getCustomSchema.ts
@@ -30,7 +30,7 @@ const pickSchema = (picked$kinds: SDKKinds[], sourceSchema: SourceSchema): JSONS
{
oneOf: [],
definitions: {},
- } as JSONSchema7
+ } as JSONSchema7,
);
// Sort `oneOf` list alphabetically
@@ -81,6 +81,6 @@ export const getCustomSchema = (baseSchema?: JSONSchema7, ejectedSchema?: JSONSc
triggers: pickSchema(triggerKinds, ejectedDefinitions as SourceSchema),
recognizers: pickSchema(recognizerKinds, ejectedDefinitions as SourceSchema),
},
- (v) => v !== undefined
+ (v) => v !== undefined,
);
};
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/adaptive/AdaptiveTrigger.tsx b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/adaptive/AdaptiveTrigger.tsx
index c2b5e730e9..012cdb2ddb 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/adaptive/AdaptiveTrigger.tsx
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/adaptive/AdaptiveTrigger.tsx
@@ -86,7 +86,7 @@ export const AdaptiveTrigger: React.FC = ({ triggerId, tri
0,
HeadSize.width - HeadSize.axisX,
TailSize.width - TailSize.axisX,
- contentBoundary.width - contentBoundary.axisX
+ contentBoundary.width - contentBoundary.axisX,
);
const editorHeight = HeadSize.height + TailSize.height + contentBoundary.height;
@@ -125,7 +125,7 @@ export const AdaptiveTrigger: React.FC = ({ triggerId, tri
contentBoundary.height + HeadSize.height,
EdgeDirection.Down,
ElementInterval.y / 2,
- { directed: true }
+ { directed: true },
)}
= MapWithEnumKey;
export function useSmartLayout(
nodeMap: GraphNodeMap,
layouter: (nodeMap: GraphNodeMap) => GraphLayout,
- onResize: (boundary: Boundary) => void
+ onResize: (boundary: Boundary) => void,
): {
layout: GraphLayout;
updateNodeBoundary: (nodeName: T, boundary: Boundary) => void;
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/baseInputLayouter.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/baseInputLayouter.ts
index cc1362420d..5e3cd28aa2 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/baseInputLayouter.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/baseInputLayouter.ts
@@ -18,7 +18,7 @@ import { calculateBaseInputBoundary } from './calculateNodeBoundary';
export function baseInputLayouter(
botAsksNode: GraphNode,
userAnswersNode: GraphNode,
- invalidPromptNode: GraphNode
+ invalidPromptNode: GraphNode,
): GraphLayout {
const boundary = calculateBaseInputBoundary(botAsksNode.boundary, userAnswersNode.boundary);
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/calculateNodeBoundary.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/calculateNodeBoundary.ts
index 33ff65fa7b..72343d5177 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/calculateNodeBoundary.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/calculateNodeBoundary.ts
@@ -18,7 +18,7 @@ import { calculateBranchNodesIntervalX } from './sharedLayouterUtils';
export function calculateSequenceBoundary(
boundaries: Boundary[],
widthHeadEdge = true,
- widthTailEdge = true
+ widthTailEdge = true,
): Boundary {
const box = new Boundary();
if (!Array.isArray(boundaries) || boundaries.length === 0) {
@@ -40,7 +40,7 @@ export function calculateForeachBoundary(
foreachBoundary: Boundary | null,
stepsBoundary: Boundary | null,
loopBeginBoundary: Boundary,
- loopEndBoundary: Boundary
+ loopEndBoundary: Boundary,
): Boundary {
const box = new Boundary();
@@ -64,7 +64,7 @@ export function calculateIfElseBoundary(
conditionBoundary: Boundary | null,
choiceBoundary: Boundary | null,
ifBoundary: Boundary,
- elseBoundary: Boundary
+ elseBoundary: Boundary,
): Boundary {
if (!conditionBoundary || !choiceBoundary) return new Boundary();
@@ -76,7 +76,7 @@ export function calculateIfElseBoundary(
export function calculateSwitchCaseBoundary(
conditionBoundary: Boundary | null,
choiceBoundary: Boundary | null,
- branchBoundaries: Boundary[] = []
+ branchBoundaries: Boundary[] = [],
): Boundary {
if (!conditionBoundary || !choiceBoundary) return new Boundary();
@@ -86,7 +86,7 @@ export function calculateSwitchCaseBoundary(
function measureBranchingContainerBoundary(
conditionBoundary: Boundary | null,
choiceBoundary: Boundary | null,
- branchBoundaries: Boundary[] = []
+ branchBoundaries: Boundary[] = [],
): Boundary {
if (!conditionBoundary || !choiceBoundary) return new Boundary();
@@ -113,7 +113,7 @@ function measureBranchingContainerBoundary(
Math.max(
conditionBoundary.width - conditionBoundary.axisX,
choiceBoundary.width - choiceBoundary.axisX,
- branchGroupBoundary.width - branchGroupBoundary.axisX
+ branchGroupBoundary.width - branchGroupBoundary.axisX,
) +
BranchingNodeMarginRight;
@@ -132,7 +132,7 @@ export function calculateBaseInputBoundary(botAsksBoundary: Boundary, userAnswer
boundary.axisX +
Math.max(
botAsksBoundary.width - botAsksBoundary.axisX,
- userAnswersBoundary.width - userAnswersBoundary.axisX + IconBrickSize.width + LoopEdgeMarginLeft + BoxMargin
+ userAnswersBoundary.width - userAnswersBoundary.axisX + IconBrickSize.width + LoopEdgeMarginLeft + BoxMargin,
);
boundary.height = botAsksBoundary.height + ElementInterval.y + userAnswersBoundary.height + ElementInterval.y / 2;
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/foreachLayouter.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/foreachLayouter.ts
index 2f4bdf7183..5fdf889c0b 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/foreachLayouter.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/foreachLayouter.ts
@@ -14,7 +14,7 @@ export const foreachLayouter = (
foreachNode: GraphNode | null,
stepsNode: GraphNode | null,
loopBeginNode: GraphNode,
- loopEndNode: GraphNode
+ loopEndNode: GraphNode,
): GraphLayout => {
if (!foreachNode || !stepsNode) return new GraphLayout();
@@ -22,7 +22,7 @@ export const foreachLayouter = (
foreachNode.boundary,
stepsNode.boundary,
loopBeginNode.boundary,
- loopEndNode.boundary
+ loopEndNode.boundary,
);
foreachNode.offset = {
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/ifelseLayouter.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/ifelseLayouter.ts
index 9beca94902..098e307439 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/ifelseLayouter.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/ifelseLayouter.ts
@@ -14,7 +14,7 @@ export function ifElseLayouter(
conditionNode: GraphNode | null,
choiceNode: GraphNode | null,
ifNode: GraphNode,
- elseNode: GraphNode
+ elseNode: GraphNode,
): GraphLayout {
if (!conditionNode || !choiceNode) return new GraphLayout();
@@ -22,7 +22,7 @@ export function ifElseLayouter(
conditionNode.boundary,
choiceNode.boundary,
ifNode.boundary,
- elseNode.boundary
+ elseNode.boundary,
);
const leftNode = ifNode || new GraphNode();
@@ -141,7 +141,7 @@ export function ifElseLayouter(
x: containerBoundary.axisX,
y: containerBoundary.height,
length: rightNode.offset.x + rightNode.boundary.axisX - containerBoundary.axisX,
- }
+ },
);
} else {
edgeList.push(
@@ -165,7 +165,7 @@ export function ifElseLayouter(
x: containerBoundary.axisX,
y: containerBoundary.height,
length: containerBoundary.width - containerBoundary.axisX,
- }
+ },
);
}
@@ -185,7 +185,7 @@ export function ifElseLayouter(
x: containerBoundary.axisX,
y: leftNode.offset.y + leftNode.boundary.height,
length: containerBoundary.height - (leftNode.offset.y + leftNode.boundary.height),
- }
+ },
);
} else {
edgeList.push({
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/measureJsonBoundary.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/measureJsonBoundary.ts
index c99ea91f2d..9f31d4cb92 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/measureJsonBoundary.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/measureJsonBoundary.ts
@@ -62,7 +62,7 @@ function measureSwitchConditionBoundary(json): Boundary {
return calculateSwitchCaseBoundary(
measureJsonBoundary(condition.json),
measureJsonBoundary(choice.json),
- branches.map((x) => measureJsonBoundary(x.json))
+ branches.map((x) => measureJsonBoundary(x.json)),
);
}
@@ -87,7 +87,7 @@ export function measurePropertyAssignmentBoundary(data): Boundary {
? data.assignments.length * (PropertyAssignmentSize.height + AssignmentMarginTop)
: 4 * (PropertyAssignmentSize.height + AssignmentMarginTop)) + AssignmentMarginBottom
: 0),
- InitNodeSize.height
+ InitNodeSize.height,
);
return new Boundary(width, height);
}
@@ -99,7 +99,7 @@ function measureBaseInputBoundary(data): Boundary {
export function measureJsonBoundary(json): Boundary {
let boundary = new Boundary();
- if (!json || !json.$kind) return boundary;
+ if (!json?.$kind) return boundary;
const cachedBoundary = designerCache.loadBounary(json);
if (cachedBoundary) {
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/sequentialLayouter.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/sequentialLayouter.ts
index b2a43aebf3..59d752d495 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/sequentialLayouter.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/sequentialLayouter.ts
@@ -19,7 +19,7 @@ export function sequentialLayouter(nodes: GraphNode[], withHeadEdge = true, with
const box = calculateSequenceBoundary(
nodes.map((x) => x.boundary),
withHeadEdge,
- withTrailingEdge
+ withTrailingEdge,
);
nodes.reduce((offsetY, node) => {
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/sharedLayouterUtils.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/sharedLayouterUtils.ts
index dc385c5e0c..608be99324 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/sharedLayouterUtils.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/sharedLayouterUtils.ts
@@ -14,7 +14,7 @@ export const calculateBranchNodesIntervalX = (leftNodeBound: Boundary, rightNode
return Math.max(
BranchIntervalX,
- BranchAxisXIntervalMin - getRightWidth(leftNodeBound) - getLeftWidth(rightNodeBound)
+ BranchAxisXIntervalMin - getRightWidth(leftNodeBound) - getLeftWidth(rightNodeBound),
);
};
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/switchCaseLayouter.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/switchCaseLayouter.ts
index ff0d26f110..7b80e2e691 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/switchCaseLayouter.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/layouters/switchCaseLayouter.ts
@@ -18,7 +18,7 @@ import { calculateBranchNodesIntervalX } from './sharedLayouterUtils';
export function switchCaseLayouter(
conditionNode: GraphNode | null,
choiceNode: GraphNode,
- branchNodes: GraphNode[] = []
+ branchNodes: GraphNode[] = [],
): GraphLayout {
if (!conditionNode) {
return new GraphLayout();
@@ -27,7 +27,7 @@ export function switchCaseLayouter(
const containerBoundary = calculateSwitchCaseBoundary(
conditionNode.boundary,
choiceNode.boundary,
- branchNodes.map((x) => x.boundary)
+ branchNodes.map((x) => x.boundary),
);
/** Calulate nodes position */
@@ -80,7 +80,7 @@ export function switchCaseLayouter(
x: x.offset.x + x.boundary.axisX,
y: x.offset.y + x.boundary.height,
length: BottomelinePositionY - x.offset.y - x.boundary.height,
- }
+ },
);
});
@@ -102,7 +102,7 @@ export function switchCaseLayouter(
x: containerBoundary.axisX,
y: BottomelinePositionY,
length: baseLineLength,
- }
+ },
);
}
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformBaseInput.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformBaseInput.ts
index 959704700d..b912cdaa6b 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformBaseInput.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformBaseInput.ts
@@ -6,7 +6,7 @@ import { IndexedNode } from '../models/IndexedNode';
export function transformBaseInput(
input: any,
- jsonpath: string
+ jsonpath: string,
): { botAsks: IndexedNode; userAnswers: IndexedNode; invalidPrompt: IndexedNode } {
return {
botAsks: new IndexedNode(jsonpath, {
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformForeach.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformForeach.ts
index dfc43c6319..8e24eb8314 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformForeach.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformForeach.ts
@@ -11,7 +11,7 @@ const StepsKey = AdaptiveFieldNames.Actions;
export function transformForeach(
input: any,
- jsonpath: string
+ jsonpath: string,
): { foreachDetail: IndexedNode; stepGroup: IndexedNode; loopBegin: IndexedNode; loopEnd: IndexedNode } | null {
if (!input || typeof input !== 'object') return null;
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformIfCondition.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformIfCondition.ts
index 173b56495a..08fb953e47 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformIfCondition.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformIfCondition.ts
@@ -12,7 +12,7 @@ const ElseBranchKey = AdaptiveFieldNames.ElseActions;
export function transformIfCondtion(
input,
- jsonpath: string
+ jsonpath: string,
): { condition: IndexedNode; choice: IndexedNode; ifGroup: IndexedNode; elseGroup: IndexedNode } | null {
if (!input || typeof input !== 'object') return null;
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformSwitchCondition.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformSwitchCondition.ts
index b3a93b551b..abd6991fc8 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformSwitchCondition.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/transformers/transformSwitchCondition.ts
@@ -14,7 +14,7 @@ const DefaultBranchKey = AdaptiveFieldNames.DefaultCase;
export function transformSwitchCondition(
input,
- jsonpath: string
+ jsonpath: string,
): { condition: IndexedNode; choice: IndexedNode; branches: IndexedNode[] } | null {
if (!input || typeof input !== 'object') return null;
@@ -39,7 +39,7 @@ export function transformSwitchCondition(
$kind: AdaptiveKinds.StepGroup,
label: DefaultBranchKey,
children: defaultSteps,
- })
+ }),
);
if (!cases || !Array.isArray(cases)) return result;
@@ -52,7 +52,7 @@ export function transformSwitchCondition(
label: value,
children: actions || [],
});
- })
+ }),
);
inheritParentProperties(input, [result.condition, result.choice, ...result.branches]);
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/DesignerCache.ts b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/DesignerCache.ts
index e905f602ed..5ec43013da 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/DesignerCache.ts
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/DesignerCache.ts
@@ -30,7 +30,6 @@ export class DesignerCache {
}
if (this.cacheSize >= this.MAX_CACHE_SIZE) {
- delete this.boundaryCache;
this.boundaryCache = {};
this.cacheSize = 0;
}
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/EdgeUtil.tsx b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/EdgeUtil.tsx
index fde733599a..7073fb5dd5 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/EdgeUtil.tsx
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/EdgeUtil.tsx
@@ -78,7 +78,7 @@ export const drawSVGEdge = (
y: number,
direction: EdgeDirection,
length: number,
- options?: EdgeOptions
+ options?: EdgeOptions,
): JSX.Element[] => {
if (length <= 0) return [];
diff --git a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/widgetRenderer.tsx b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/widgetRenderer.tsx
index 78d9dcd3fb..54bba511fb 100644
--- a/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/widgetRenderer.tsx
+++ b/Composer/packages/adaptive-flow/src/adaptive-flow-renderer/utils/visual/widgetRenderer.tsx
@@ -15,7 +15,7 @@ export interface UIWidgetContext extends WidgetContainerProps {
export const renderUIWidget = (
widgetSchema: FlowWidget,
widgetMap: FlowEditorWidgetMap,
- context: UIWidgetContext
+ context: UIWidgetContext,
): JSX.Element => {
const parseWidgetSchema = (widgetSchema: FlowWidget) => {
const { widget, ...props } = widgetSchema;
diff --git a/Composer/packages/adaptive-form/package.json b/Composer/packages/adaptive-form/package.json
index aa27598f61..884c06d811 100644
--- a/Composer/packages/adaptive-form/package.json
+++ b/Composer/packages/adaptive-form/package.json
@@ -11,7 +11,7 @@
"start": "tsc --watch --preserveWatchOutput",
"build": "yarn clean && yarn build:ts",
"build:ts": "tsc --build ./tsconfig.build.json",
- "clean": "rimraf lib demo/dist",
+ "clean": "rimraf lib demo/dist .swc",
"lint": "eslint --quiet src",
"lint:fix": "yarn lint --fix",
"prepare": "yarn build"
@@ -40,6 +40,6 @@
"@emotion/react": "^11.1.3",
"lodash": "^4.17.19",
"react-error-boundary": "^1.2.5",
- "tslib": "2.4.0"
+ "tslib": "2.6.2"
}
}
diff --git a/Composer/packages/adaptive-form/src/components/Comment.tsx b/Composer/packages/adaptive-form/src/components/Comment.tsx
index 79d83a9df2..38c5734c46 100644
--- a/Composer/packages/adaptive-form/src/components/Comment.tsx
+++ b/Composer/packages/adaptive-form/src/components/Comment.tsx
@@ -59,7 +59,7 @@ const Comment: React.FC = ({ comment, onChange }) => {
(_e, val?: string) => {
onChange(val);
},
- [onChange]
+ [onChange],
);
const handleBlur = useCallback(() => {
diff --git a/Composer/packages/adaptive-form/src/components/FormRow.tsx b/Composer/packages/adaptive-form/src/components/FormRow.tsx
index 1c25c42beb..4f88c97d96 100644
--- a/Composer/packages/adaptive-form/src/components/FormRow.tsx
+++ b/Composer/packages/adaptive-form/src/components/FormRow.tsx
@@ -16,19 +16,8 @@ export interface FormRowProps extends Omit {
}
export function getRowProps(rowProps: FormRowProps, field: string): FieldProps {
- const {
- id,
- schema,
- definitions,
- value,
- uiOptions,
- className,
- label,
- rawErrors,
- onBlur,
- onFocus,
- onChange,
- } = rowProps;
+ const { id, schema, definitions, value, uiOptions, className, label, rawErrors, onBlur, onFocus, onChange } =
+ rowProps;
const { required = [] } = schema;
const fieldSchema = resolvePropSchema(schema, field, definitions);
diff --git a/Composer/packages/adaptive-form/src/components/FormTitle.tsx b/Composer/packages/adaptive-form/src/components/FormTitle.tsx
index 66dd10db63..d5da5ff94b 100644
--- a/Composer/packages/adaptive-form/src/components/FormTitle.tsx
+++ b/Composer/packages/adaptive-form/src/components/FormTitle.tsx
@@ -77,11 +77,11 @@ const FormTitle: React.FC = (props) => {
data?.intent,
normalizedIntentName,
shell.current.data,
- shell.current.api
+ shell.current.api,
));
}
}, 400),
- []
+ [],
);
const handleTitleChange = (newTitle?: string): void => {
diff --git a/Composer/packages/adaptive-form/src/components/__tests__/Comment.test.tsx b/Composer/packages/adaptive-form/src/components/__tests__/Comment.test.tsx
index 603e0a7aa5..332bf7fbb3 100644
--- a/Composer/packages/adaptive-form/src/components/__tests__/Comment.test.tsx
+++ b/Composer/packages/adaptive-form/src/components/__tests__/Comment.test.tsx
@@ -26,7 +26,7 @@ describe(' ', () => {
it('can edit an existing comment', async () => {
const comment = faker.lorem.paragraph();
const { findByLabelText, findByPlaceholderText, findByText, queryByTestId } = render(
-
+ ,
);
expect(queryByTestId('CommentCard')).toBeVisible();
@@ -56,7 +56,7 @@ describe(' ', () => {
it('can delete a comment', async () => {
const comment = faker.lorem.paragraph();
const { findByLabelText, findByPlaceholderText, queryByTestId, findByRole } = render(
-
+ ,
);
expect(queryByTestId('CommentCard')).toBeInTheDocument();
diff --git a/Composer/packages/adaptive-form/src/components/__tests__/FieldLabel.test.tsx b/Composer/packages/adaptive-form/src/components/__tests__/FieldLabel.test.tsx
index d4eb08a242..8e597be377 100644
--- a/Composer/packages/adaptive-form/src/components/__tests__/FieldLabel.test.tsx
+++ b/Composer/packages/adaptive-form/src/components/__tests__/FieldLabel.test.tsx
@@ -20,7 +20,7 @@ describe(' ', () => {
it('renders a description tooltip', async () => {
const { findByTestId } = render(
-
+ ,
);
expect(await findByTestId('FieldLabelHelpIcon')).toBeInTheDocument();
diff --git a/Composer/packages/adaptive-form/src/components/__tests__/FormRow.test.tsx b/Composer/packages/adaptive-form/src/components/__tests__/FormRow.test.tsx
index 7e3b0871f2..07027a7c8b 100644
--- a/Composer/packages/adaptive-form/src/components/__tests__/FormRow.test.tsx
+++ b/Composer/packages/adaptive-form/src/components/__tests__/FormRow.test.tsx
@@ -63,7 +63,7 @@ describe('getRowProps', () => {
it('gets the correct rawErrors', () => {
expect(getRowProps({ ...field, rawErrors: { single: 'single errors' } }, 'single').rawErrors).toEqual(
- 'single errors'
+ 'single errors',
);
});
diff --git a/Composer/packages/adaptive-form/src/components/expressions/ExpressionFieldToolbar.tsx b/Composer/packages/adaptive-form/src/components/expressions/ExpressionFieldToolbar.tsx
index c9cd13644d..fefc2b845e 100644
--- a/Composer/packages/adaptive-form/src/components/expressions/ExpressionFieldToolbar.tsx
+++ b/Composer/packages/adaptive-form/src/components/expressions/ExpressionFieldToolbar.tsx
@@ -88,7 +88,7 @@ export const ExpressionFieldToolbar = (props: Props) => {
target?.focus();
},
- [target, value, onChange]
+ [target, value, onChange],
);
return target ? (
void,
onLayerMounted: () => void,
- maxHeight?: number
+ maxHeight?: number,
): IContextualMenuItem[] => {
const menuItems: IContextualMenuItem[] =
expressionGroupings?.map((grouping: ExpressionGroupingType) => {
diff --git a/Composer/packages/adaptive-form/src/components/fields/ArrayField.tsx b/Composer/packages/adaptive-form/src/components/fields/ArrayField.tsx
index 5857948d66..69d62d222a 100644
--- a/Composer/packages/adaptive-form/src/components/fields/ArrayField.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/ArrayField.tsx
@@ -35,7 +35,7 @@ const ArrayField: React.FC> = (props) => {
addItem(undefined);
}, [addItem]);
- if (!itemSchema || itemSchema === true) {
+ if (!itemSchema || (itemSchema as unknown) === true) {
return ;
}
diff --git a/Composer/packages/adaptive-form/src/components/fields/EditableField.tsx b/Composer/packages/adaptive-form/src/components/fields/EditableField.tsx
index 0f49795d90..99e3ae5928 100644
--- a/Composer/packages/adaptive-form/src/components/fields/EditableField.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/EditableField.tsx
@@ -77,7 +77,7 @@ const EditableField: React.FC = (props) => {
},
},
},
- styles
+ styles,
) as Partial
}
value={localValue}
diff --git a/Composer/packages/adaptive-form/src/components/fields/IntellisenseFields.tsx b/Composer/packages/adaptive-form/src/components/fields/IntellisenseFields.tsx
index 0bd58e4a33..15ba82651b 100644
--- a/Composer/packages/adaptive-form/src/components/fields/IntellisenseFields.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/IntellisenseFields.tsx
@@ -85,7 +85,7 @@ export const IntellisenseExpressionField: React.FC> = (props)
setToolbarTargetElm(event.target as HTMLInputElement | HTMLTextAreaElement);
}
},
- []
+ [],
);
const onClearTarget = React.useCallback(() => {
diff --git a/Composer/packages/adaptive-form/src/components/fields/IntentField.tsx b/Composer/packages/adaptive-form/src/components/fields/IntentField.tsx
index 3ecff7431d..8d47ef68a6 100644
--- a/Composer/packages/adaptive-form/src/components/fields/IntentField.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/IntentField.tsx
@@ -28,7 +28,7 @@ const IntentField: React.FC = (props) => {
let helpLink = uiOptions.helpLink;
if (isLuisRecognizer(currentDialog)) {
description = formatMessage(
- 'Trigger phrases are inputs from users that will be used to train your LUIS model. This follows .lu file format.'
+ 'Trigger phrases are inputs from users that will be used to train your LUIS model. This follows .lu file format.',
);
helpLink = luisEntityHelpUrl;
}
diff --git a/Composer/packages/adaptive-form/src/components/fields/OneOfField/OneOfField.tsx b/Composer/packages/adaptive-form/src/components/fields/OneOfField/OneOfField.tsx
index 5da27df125..5af98bef90 100644
--- a/Composer/packages/adaptive-form/src/components/fields/OneOfField/OneOfField.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/OneOfField/OneOfField.tsx
@@ -43,9 +43,10 @@ const styles = {
},
nestedDropdown: {
root: {
- ':hover .ms-Dropdown-title, :active .ms-Dropdown-title, :hover .ms-Dropdown-caretDown, :active .ms-Dropdown-caretDown': {
- color: FluentTheme.palette.themeDarker,
- },
+ ':hover .ms-Dropdown-title, :active .ms-Dropdown-title, :hover .ms-Dropdown-caretDown, :active .ms-Dropdown-caretDown':
+ {
+ color: FluentTheme.palette.themeDarker,
+ },
':focus-within .ms-Dropdown-title, :focus-within .ms-Dropdown-caretDown': {
color: FluentTheme.palette.accent,
},
@@ -88,7 +89,7 @@ const OneOfField: React.FC = (props) => {
const { options, isNested } = useMemo(() => getOptions(schema, definitions), [schema, definitions]);
const initialSelectedOption = useMemo(
() => getSelectedOption(value, options) || ({ key: '', data: { schema: undefined } } as IDropdownOption),
- []
+ [],
);
const [
diff --git a/Composer/packages/adaptive-form/src/components/fields/OneOfField/utils.ts b/Composer/packages/adaptive-form/src/components/fields/OneOfField/utils.ts
index 5e8b669e70..5a219d71ef 100644
--- a/Composer/packages/adaptive-form/src/components/fields/OneOfField/utils.ts
+++ b/Composer/packages/adaptive-form/src/components/fields/OneOfField/utils.ts
@@ -39,7 +39,7 @@ const sortOptionsByTypeWeights = ({ key: type1 }, { key: type2 }): number => {
export function getOptions(
schema: JSONSchema7,
- definitions?: SchemaDefinitions
+ definitions?: SchemaDefinitions,
): { options: IDropdownOption[]; isNested: boolean } {
const { type, oneOf, additionalProperties } = schema;
diff --git a/Composer/packages/adaptive-form/src/components/fields/OpenObjectField/OpenObjectField.tsx b/Composer/packages/adaptive-form/src/components/fields/OpenObjectField/OpenObjectField.tsx
index 924addbb78..e673a8a4c7 100644
--- a/Composer/packages/adaptive-form/src/components/fields/OpenObjectField/OpenObjectField.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/OpenObjectField/OpenObjectField.tsx
@@ -12,9 +12,11 @@ import { AddButton } from '../../AddButton';
import { ObjectItem } from './ObjectItem';
-const OpenObjectField: React.FC> = (props) => {
+const OpenObjectField: React.FC<
+ FieldProps<{
+ [key: string]: unknown;
+ }>
+> = (props) => {
const {
definitions,
description,
diff --git a/Composer/packages/adaptive-form/src/components/fields/OpenObjectField/__tests__/OpenObjectField.test.tsx b/Composer/packages/adaptive-form/src/components/fields/OpenObjectField/__tests__/OpenObjectField.test.tsx
index 59f4200e2e..bb795c3126 100644
--- a/Composer/packages/adaptive-form/src/components/fields/OpenObjectField/__tests__/OpenObjectField.test.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/OpenObjectField/__tests__/OpenObjectField.test.tsx
@@ -46,7 +46,7 @@ describe(' ', () => {
expect(onChange).toHaveBeenCalledWith(
expect.objectContaining({
foo: 'new foo value',
- })
+ }),
);
const fooName = getByDisplayValue('foo');
@@ -56,7 +56,7 @@ describe(' ', () => {
expect(onChange).toHaveBeenCalledWith(
expect.objectContaining({
newFoo: 'new foo value',
- })
+ }),
);
const fooActions = getByTestId('ObjectItemActions');
@@ -66,7 +66,7 @@ describe(' ', () => {
expect(onChange).toHaveBeenCalledWith(
expect.not.objectContaining({
foo: 'foo value',
- })
+ }),
);
});
diff --git a/Composer/packages/adaptive-form/src/components/fields/RecognizerField/RecognizerField.tsx b/Composer/packages/adaptive-form/src/components/fields/RecognizerField/RecognizerField.tsx
index 39dab2943b..4c0ac4973f 100644
--- a/Composer/packages/adaptive-form/src/components/fields/RecognizerField/RecognizerField.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/RecognizerField/RecognizerField.tsx
@@ -45,9 +45,10 @@ export const RecognizerField: React.FC> = (prop
useMigrationEffect(value, onChange);
const { recognizers: recognizerConfigs, currentRecognizer } = useRecognizerConfig();
- const detailsListItems = useMemo(() => getDetailsListItems(recognizerConfigs, shellData, shellApi), [
- recognizerConfigs,
- ]);
+ const detailsListItems = useMemo(
+ () => getDetailsListItems(recognizerConfigs, shellData, shellApi),
+ [recognizerConfigs],
+ );
const RecognizerEditor = currentRecognizer?.recognizerEditor;
const widget = RecognizerEditor ? : null;
diff --git a/Composer/packages/adaptive-form/src/components/fields/RecognizerField/useMigrationEffect.ts b/Composer/packages/adaptive-form/src/components/fields/RecognizerField/useMigrationEffect.ts
index e17a19e57c..15f080ed56 100644
--- a/Composer/packages/adaptive-form/src/components/fields/RecognizerField/useMigrationEffect.ts
+++ b/Composer/packages/adaptive-form/src/components/fields/RecognizerField/useMigrationEffect.ts
@@ -7,7 +7,7 @@ import { MicrosoftIRecognizer } from '@bfc/shared';
export const useMigrationEffect = (
recognizer: MicrosoftIRecognizer | undefined,
- onChangeRecognizer: ChangeHandler
+ onChangeRecognizer: ChangeHandler,
) => {
const { qnaFiles, luFiles, currentDialog, locale } = useShellApi();
diff --git a/Composer/packages/adaptive-form/src/components/fields/__tests__/ArrayFieldItem.test.tsx b/Composer/packages/adaptive-form/src/components/fields/__tests__/ArrayFieldItem.test.tsx
index f74349981f..d2d7ec3a45 100644
--- a/Composer/packages/adaptive-form/src/components/fields/__tests__/ArrayFieldItem.test.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/__tests__/ArrayFieldItem.test.tsx
@@ -20,7 +20,7 @@ function renderSubject(overrides = {}) {
onRemove: jest.fn(),
},
fieldProps(),
- overrides
+ overrides,
);
return render( );
diff --git a/Composer/packages/adaptive-form/src/components/fields/__tests__/RegexIntentField.test.tsx b/Composer/packages/adaptive-form/src/components/fields/__tests__/RegexIntentField.test.tsx
index 7a8751b850..ef74139901 100644
--- a/Composer/packages/adaptive-form/src/components/fields/__tests__/RegexIntentField.test.tsx
+++ b/Composer/packages/adaptive-form/src/components/fields/__tests__/RegexIntentField.test.tsx
@@ -27,8 +27,8 @@ function renderSubject(overrides = {}, shellOverrides = {}) {
},
focusedSteps: [],
},
- shellOverrides
- )
+ shellOverrides,
+ ),
);
const props = assign({}, fieldProps(), overrides);
@@ -55,7 +55,7 @@ describe(' ', () => {
const updateRegExIntent = jest.fn();
const { getByDisplayValue } = renderSubject(
{ value: 'FirstIntent' },
- { shellApi: { updateRegExIntent }, currentDialog: { id: 'current-dialog-id', content: dialog } }
+ { shellApi: { updateRegExIntent }, currentDialog: { id: 'current-dialog-id', content: dialog } },
);
const input = getByDisplayValue('first-pattern');
@@ -68,7 +68,7 @@ describe(' ', () => {
it('still renders if no intents found', () => {
const { container } = renderSubject(
{ value: 'FirstIntent' },
- { currentDialog: { id: 'current-dialog-id', content: {} } }
+ { currentDialog: { id: 'current-dialog-id', content: {} } },
);
expect(container).not.toBeEmptyDOMElement();
diff --git a/Composer/packages/adaptive-form/src/components/fields/styles.ts b/Composer/packages/adaptive-form/src/components/fields/styles.ts
index 8d7841b1e9..3c3fe9b977 100644
--- a/Composer/packages/adaptive-form/src/components/fields/styles.ts
+++ b/Composer/packages/adaptive-form/src/components/fields/styles.ts
@@ -18,7 +18,7 @@ export const arrayItem = {
contaInerFocus: mergeStyles(
getFocusStyle(getTheme(), {
inset: -3,
- })
+ }),
),
field: css`
diff --git a/Composer/packages/adaptive-form/src/utils/__tests__/getFieldSets.test.ts b/Composer/packages/adaptive-form/src/utils/__tests__/getFieldSets.test.ts
index b7c1b25c7f..b9d2517dc7 100644
--- a/Composer/packages/adaptive-form/src/utils/__tests__/getFieldSets.test.ts
+++ b/Composer/packages/adaptive-form/src/utils/__tests__/getFieldSets.test.ts
@@ -234,7 +234,7 @@ describe('getFieldsets', () => {
};
expect(() => getFieldsets(schema, uiOptions, {})).toThrow(
- 'fields must be either all strings or all fieldset objects'
+ 'fields must be either all strings or all fieldset objects',
);
});
diff --git a/Composer/packages/adaptive-form/src/utils/__tests__/getOrderedProperties.test.ts b/Composer/packages/adaptive-form/src/utils/__tests__/getOrderedProperties.test.ts
index 8c4d4d950f..df242fe10a 100644
--- a/Composer/packages/adaptive-form/src/utils/__tests__/getOrderedProperties.test.ts
+++ b/Composer/packages/adaptive-form/src/utils/__tests__/getOrderedProperties.test.ts
@@ -36,9 +36,9 @@ describe('getOrderedProperties', () => {
const order = ['one', 'three', ['four', 'five'], 'six', 'seven'];
const expectedResult = ['one', 'three', ['four', 'five'], 'six', 'seven', 'two'];
- // @ts-expect-error
+ // @ts-expect-error: test
expect(getOrderedProperties(schema, { order, hidden: ['two'] }, data)).toEqual(expectedResult);
- // @ts-expect-error
+ // @ts-expect-error: test
expect(getOrderedProperties(schema, { order, hidden: () => ['two'] }, data)).toEqual(expectedResult);
});
@@ -46,9 +46,9 @@ describe('getOrderedProperties', () => {
const expectedResult = ['three', 'one', 'four', ['five', 'six'], 'seven', 'two'];
const order = ['three', '*', ['five', 'six'], ['seven'], 'two'];
- // @ts-expect-error
+ // @ts-expect-error: test
expect(getOrderedProperties(schema, { order }, data)).toEqual(expectedResult);
- // @ts-expect-error
+ // @ts-expect-error: test
expect(getOrderedProperties(schema, { order: () => order }, data)).toEqual(expectedResult);
});
@@ -59,13 +59,13 @@ describe('getOrderedProperties', () => {
it('does not throw an exception for no wildcard if all fields are ordered', () => {
const order = ['three', 'one', 'four', ['five', 'six'], ['seven'], 'two'];
- // @ts-expect-error
+ // @ts-expect-error: test
expect(() => getOrderedProperties(schema, { order }, data)).not.toThrow();
});
it('does not include wildcard in ordered fields if all fields are present', () => {
const order = ['three', 'one', 'four', '*', ['five', 'six'], ['seven'], 'two'];
- // @ts-expect-error
+ // @ts-expect-error: test
expect(getOrderedProperties(schema, { order }, data)).not.toContain('*');
});
@@ -75,7 +75,7 @@ describe('getOrderedProperties', () => {
it('throws an exception if there are multiple wildcards in order option', () => {
expect(() => getOrderedProperties(schema, { order: ['three', '*', 'two', '*'] }, data)).toThrow(
- 'multiple wildcards'
+ 'multiple wildcards',
);
});
});
diff --git a/Composer/packages/adaptive-form/src/utils/__tests__/getSchemaWithAdditionalFields.test.ts b/Composer/packages/adaptive-form/src/utils/__tests__/getSchemaWithAdditionalFields.test.ts
index 0b19b6260e..91acf24968 100644
--- a/Composer/packages/adaptive-form/src/utils/__tests__/getSchemaWithAdditionalFields.test.ts
+++ b/Composer/packages/adaptive-form/src/utils/__tests__/getSchemaWithAdditionalFields.test.ts
@@ -35,7 +35,7 @@ describe('getSchemaWithAdditionalFields', () => {
properties: expect.objectContaining({
additionalField: {},
}),
- })
+ }),
);
});
});
diff --git a/Composer/packages/adaptive-form/src/utils/__tests__/getUIOptions.test.ts b/Composer/packages/adaptive-form/src/utils/__tests__/getUIOptions.test.ts
index 69a8c488cc..6e45fccdd7 100644
--- a/Composer/packages/adaptive-form/src/utils/__tests__/getUIOptions.test.ts
+++ b/Composer/packages/adaptive-form/src/utils/__tests__/getUIOptions.test.ts
@@ -7,7 +7,7 @@ import { getUIOptions } from '../getUIOptions';
describe('getUIOptions', () => {
it('returns empty object when type schema not found', () => {
- // @ts-ignore - Intentionally passing in an invalid value
+ // @ts-expect-error - Intentionally passing in an invalid value
expect(getUIOptions('SomeDialog')).toEqual({});
});
diff --git a/Composer/packages/adaptive-form/src/utils/__tests__/resolveFieldWidget.test.ts b/Composer/packages/adaptive-form/src/utils/__tests__/resolveFieldWidget.test.ts
index 5831634c25..8166d1a9c9 100644
--- a/Composer/packages/adaptive-form/src/utils/__tests__/resolveFieldWidget.test.ts
+++ b/Composer/packages/adaptive-form/src/utils/__tests__/resolveFieldWidget.test.ts
@@ -17,7 +17,7 @@ describe('resolveFieldWidget', () => {
type: 'string' as const,
};
- // @ts-ignore
+ // @ts-expect-error test
const { field: ReturnedField } = resolveFieldWidget({ schema, uiOptions });
expect(ReturnedField).toEqual(TestField);
});
diff --git a/Composer/packages/adaptive-form/src/utils/__tests__/resolvePropSchema.test.ts b/Composer/packages/adaptive-form/src/utils/__tests__/resolvePropSchema.test.ts
index 202d8c4ade..77879bd9d1 100644
--- a/Composer/packages/adaptive-form/src/utils/__tests__/resolvePropSchema.test.ts
+++ b/Composer/packages/adaptive-form/src/utils/__tests__/resolvePropSchema.test.ts
@@ -37,7 +37,7 @@ describe('resolvePropSchema', () => {
},
};
- // @ts-ignore
+ // @ts-expect-error test
const resolved = resolvePropSchema(schema, 'foo', definitions);
expect(resolveRef).toBeCalledWith(schema.properties.foo, definitions);
diff --git a/Composer/packages/adaptive-form/src/utils/__tests__/resolveRef.test.ts b/Composer/packages/adaptive-form/src/utils/__tests__/resolveRef.test.ts
index 889b1ecfb5..4d7ca8bb1e 100644
--- a/Composer/packages/adaptive-form/src/utils/__tests__/resolveRef.test.ts
+++ b/Composer/packages/adaptive-form/src/utils/__tests__/resolveRef.test.ts
@@ -6,7 +6,7 @@ import { resolveRef } from '../resolveRef';
describe('resolveRef', () => {
it('returns the schema if no $ref is defined', () => {
const schema = { type: 'string' };
- // @ts-expect-error
+ // @ts-expect-error: test
expect(resolveRef(schema)).toEqual({ type: 'string' });
});
diff --git a/Composer/packages/adaptive-form/src/utils/__tests__/uiOptionsHelpers.test.ts b/Composer/packages/adaptive-form/src/utils/__tests__/uiOptionsHelpers.test.ts
index b4eceda30e..c2668047eb 100644
--- a/Composer/packages/adaptive-form/src/utils/__tests__/uiOptionsHelpers.test.ts
+++ b/Composer/packages/adaptive-form/src/utils/__tests__/uiOptionsHelpers.test.ts
@@ -87,13 +87,13 @@ describe('getUiPlaceholder', () => {
it('falls back to prop placeholder or schema examples', () => {
expect(getUiPlaceholder(props)).toEqual('prop placeholder');
expect(getUiPlaceholder({ ...props, placeholder: undefined, schema: { examples: ['one', 'two'] } })).toEqual(
- 'ex. one, two'
+ 'ex. one, two',
);
});
it('correctly display examples for non string types', () => {
expect(
- getUiPlaceholder({ ...props, placeholder: undefined, schema: { examples: [true, 5, { arg1: 'test' }] } })
+ getUiPlaceholder({ ...props, placeholder: undefined, schema: { examples: [true, 5, { arg1: 'test' }] } }),
).toEqual('ex. true, 5, {"arg1":"test"}');
});
});
diff --git a/Composer/packages/adaptive-form/src/utils/arrayUtils.ts b/Composer/packages/adaptive-form/src/utils/arrayUtils.ts
index d7f2401224..db584de070 100644
--- a/Composer/packages/adaptive-form/src/utils/arrayUtils.ts
+++ b/Composer/packages/adaptive-form/src/utils/arrayUtils.ts
@@ -39,7 +39,7 @@ export const isItemValueEmpty = (value?: any) =>
export const getArrayItemProps = (
items: ArrayItem[],
index: number,
- onChange: ArrayChangeHandler
+ onChange: ArrayChangeHandler,
) => {
const onItemChange = (newValue: ItemType) => {
const updated = items.map((item, i) => {
@@ -78,7 +78,7 @@ export const getArrayItemProps = (
export function useArrayItems(
items: ItemType[] | undefined,
- onChange: ChangeHandler
+ onChange: ChangeHandler,
): ArrayItemState {
const [cache, setCache] = useState(generateArrayItems(items));
diff --git a/Composer/packages/adaptive-form/src/utils/getFieldsets.ts b/Composer/packages/adaptive-form/src/utils/getFieldsets.ts
index a363ea0f6a..3954c941c8 100644
--- a/Composer/packages/adaptive-form/src/utils/getFieldsets.ts
+++ b/Composer/packages/adaptive-form/src/utils/getFieldsets.ts
@@ -31,7 +31,7 @@ export const getFieldsets = (baseSchema: JSONSchema7, baseUiOptions: UIOptions,
if (
!baseFieldsets.every(
({ fields = ['*'] }) =>
- fields.every((field) => typeof field === 'string') || fields.every((field) => typeof field === 'object')
+ fields.every((field) => typeof field === 'string') || fields.every((field) => typeof field === 'object'),
)
) {
throw new Error(formatMessage('fields must be either all strings or all fieldset objects'));
diff --git a/Composer/packages/adaptive-form/src/utils/getOrderedProperties.ts b/Composer/packages/adaptive-form/src/utils/getOrderedProperties.ts
index 9f330ae78f..2a6e514db6 100644
--- a/Composer/packages/adaptive-form/src/utils/getOrderedProperties.ts
+++ b/Composer/packages/adaptive-form/src/utils/getOrderedProperties.ts
@@ -12,7 +12,7 @@ export function getOrderedProperties(
schema: JSONSchema7,
baseUiOptions: UIOptions,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
- data: any
+ data: any,
): OrderConfig {
const uiOptions = cloneDeep(baseUiOptions);
const { order = ['*'] } = uiOptions;
@@ -52,7 +52,7 @@ export function getOrderedProperties(
}, [] as OrderConfig);
const allProperties = Object.keys(schema.properties ?? {}).filter(
- (p) => !p.startsWith('$') && !hiddenFieldSet.has(p)
+ (p) => !p.startsWith('$') && !hiddenFieldSet.has(p),
);
const restIdx = orderedFields.indexOf('*');
@@ -71,7 +71,7 @@ export function getOrderedProperties(
title: schema.title,
errorMsg,
options: JSON.stringify(uiOptions, null, 2),
- })
+ }),
);
}
}
diff --git a/Composer/packages/adaptive-form/src/utils/objectUtils.ts b/Composer/packages/adaptive-form/src/utils/objectUtils.ts
index 68d2cee085..eeee6cc9b3 100644
--- a/Composer/packages/adaptive-form/src/utils/objectUtils.ts
+++ b/Composer/packages/adaptive-form/src/utils/objectUtils.ts
@@ -35,7 +35,7 @@ const createObjectItem = (propertyName = '', propertyValue?
export const getPropertyItemProps = (
items: ObjectItem[],
index: number,
- onChange: any
+ onChange: any,
) => {
const handlePropertyNameChange = (propertyName: string) => {
const updated = items.map((item, idx) => (idx === index ? { ...item, propertyName } : item));
@@ -60,7 +60,7 @@ export const getPropertyItemProps = (
export function useObjectItems(
items: ItemType,
- onChange: ChangeHandler>
+ onChange: ChangeHandler>,
): ObjectItemState {
const [cache, setCache] = useState(generateObjectEntries(items));
diff --git a/Composer/packages/adaptive-form/src/utils/resolvePropSchema.ts b/Composer/packages/adaptive-form/src/utils/resolvePropSchema.ts
index 7bc605f5d6..a47a76cab7 100644
--- a/Composer/packages/adaptive-form/src/utils/resolvePropSchema.ts
+++ b/Composer/packages/adaptive-form/src/utils/resolvePropSchema.ts
@@ -7,7 +7,7 @@ import { resolveRef } from './resolveRef';
export function resolvePropSchema(
schema: JSONSchema7,
path: string,
- definitions: SchemaDefinitions = {}
+ definitions: SchemaDefinitions = {},
): JSONSchema7 | undefined {
const propSchema = schema.properties?.[path];
diff --git a/Composer/packages/client/__tests__/components/Adapters/ABSChannels.test.tsx b/Composer/packages/client/__tests__/components/Adapters/ABSChannels.test.tsx
index a6d5419223..7146f45886 100644
--- a/Composer/packages/client/__tests__/components/Adapters/ABSChannels.test.tsx
+++ b/Composer/packages/client/__tests__/components/Adapters/ABSChannels.test.tsx
@@ -153,11 +153,9 @@ describe(' ', () => {
expect(await component.findByText('MS Teams')).toBeTruthy();
expect(await component.findByText('Web Chat')).toBeTruthy();
expect(await component.findByText('Speech')).toBeTruthy();
- expect(
- httpClient.get
- ).toBeCalledWith(
+ expect(httpClient.get).toBeCalledWith(
`https://management.azure.com/subscriptions/${mockSubscriptionId}/resourceGroups/${mockResourceGroup}/providers/Microsoft.BotService/botServices/${mockBotName}/channels/MsTeamsChannel?api-version=2020-06-02`,
- { headers: { Authorization: `Bearer ${mockTokenValue}` } }
+ { headers: { Authorization: `Bearer ${mockTokenValue}` } },
);
});
@@ -185,21 +183,17 @@ describe(' ', () => {
await act(async () => {
await fireEvent.click(teamsToggle);
});
- expect(
- httpClient.delete
- ).toBeCalledWith(
+ expect(httpClient.delete).toBeCalledWith(
`https://management.azure.com/subscriptions/${mockSubscriptionId}/resourceGroups/${mockResourceGroup}/providers/Microsoft.BotService/botServices/${mockBotName}/channels/MsTeamsChannel?api-version=2020-06-02`,
- { headers: { Authorization: `Bearer ${mockTokenValue}` } }
+ { headers: { Authorization: `Bearer ${mockTokenValue}` } },
);
await act(async () => {
await fireEvent.click(teamsToggle);
});
- expect(
- httpClient.put
- ).toBeCalledWith(
+ expect(httpClient.put).toBeCalledWith(
`https://management.azure.com/subscriptions/${mockSubscriptionId}/resourceGroups/${mockResourceGroup}/providers/Microsoft.BotService/botServices/${mockBotName}/channels/MsTeamsChannel?api-version=2020-06-02`,
mockData,
- { headers: { Authorization: `Bearer ${mockTokenValue}` } }
+ { headers: { Authorization: `Bearer ${mockTokenValue}` } },
);
});
@@ -228,21 +222,17 @@ describe(' ', () => {
await act(async () => {
await fireEvent.click(webChatToggle);
});
- expect(
- httpClient.delete
- ).toBeCalledWith(
+ expect(httpClient.delete).toBeCalledWith(
`https://management.azure.com/subscriptions/${mockSubscriptionId}/resourceGroups/${mockResourceGroup}/providers/Microsoft.BotService/botServices/${mockBotName}/channels/${CHANNELS.WEBCHAT}?api-version=2020-06-02`,
- { headers: { Authorization: `Bearer ${mockTokenValue}` } }
+ { headers: { Authorization: `Bearer ${mockTokenValue}` } },
);
await act(async () => {
await fireEvent.click(webChatToggle);
});
- expect(
- httpClient.put
- ).toBeCalledWith(
+ expect(httpClient.put).toBeCalledWith(
`https://management.azure.com/subscriptions/${mockSubscriptionId}/resourceGroups/${mockResourceGroup}/providers/Microsoft.BotService/botServices/${mockBotName}/channels/${CHANNELS.WEBCHAT}?api-version=2020-06-02`,
mockData,
- { headers: { Authorization: `Bearer ${mockTokenValue}` } }
+ { headers: { Authorization: `Bearer ${mockTokenValue}` } },
);
});
@@ -252,11 +242,9 @@ describe(' ', () => {
await act(async () => {
await fireEvent.click(speechToggle);
});
- expect(
- httpClient.delete
- ).toBeCalledWith(
+ expect(httpClient.delete).toBeCalledWith(
`https://management.azure.com/subscriptions/${mockSubscriptionId}/resourceGroups/${mockResourceGroup}/providers/Microsoft.BotService/botServices/${mockBotName}/channels/${CHANNELS.SPEECH}?api-version=2020-06-02`,
- { headers: { Authorization: `Bearer ${mockTokenValue}` } }
+ { headers: { Authorization: `Bearer ${mockTokenValue}` } },
);
});
diff --git a/Composer/packages/client/__tests__/components/Adapters/TeamsManifestGenerator.test.tsx b/Composer/packages/client/__tests__/components/Adapters/TeamsManifestGenerator.test.tsx
index 00bf8ac49a..86da93d2c7 100644
--- a/Composer/packages/client/__tests__/components/Adapters/TeamsManifestGenerator.test.tsx
+++ b/Composer/packages/client/__tests__/components/Adapters/TeamsManifestGenerator.test.tsx
@@ -17,7 +17,7 @@ describe(' ', () => {
botDisplayName={mockDisplayName}
hidden={false}
onDismiss={jest.fn()}
- />
+ />,
);
}
diff --git a/Composer/packages/client/__tests__/components/BotRuntimeController/emulatorOpenButton.test.tsx b/Composer/packages/client/__tests__/components/BotRuntimeController/emulatorOpenButton.test.tsx
index 1c5c54ed31..053d1feddb 100644
--- a/Composer/packages/client/__tests__/components/BotRuntimeController/emulatorOpenButton.test.tsx
+++ b/Composer/packages/client/__tests__/components/BotRuntimeController/emulatorOpenButton.test.tsx
@@ -35,11 +35,13 @@ jest.mock('@fluentui/react/lib/Tooltip', () => ({
const projectId = '123.abc';
-const initialState = ({ currentStatus = BotStatus.connected } = {}) => ({ set }) => {
- set(botStatusState(projectId), currentStatus);
- set(botEndpointsState, { [projectId]: 'http://open-in-emulator/api/messages' });
- set(settingsState(projectId), {});
-};
+const initialState =
+ ({ currentStatus = BotStatus.connected } = {}) =>
+ ({ set }) => {
+ set(botStatusState(projectId), currentStatus);
+ set(botEndpointsState, { [projectId]: 'http://open-in-emulator/api/messages' });
+ set(settingsState(projectId), {});
+ };
describe(' ', () => {
it('should show the button to open emulator', async () => {
@@ -56,7 +58,7 @@ describe(' ', () => {
it('should not show the button if the status is not `BotStatus.connected`', () => {
const { container } = renderWithRecoil(
,
- initialState({ currentStatus: BotStatus.pending })
+ initialState({ currentStatus: BotStatus.pending }),
);
expect(container).not.toHaveTextContent('Test in Emulator');
});
diff --git a/Composer/packages/client/__tests__/components/BotRuntimeController/publish-luis-modal.test.tsx b/Composer/packages/client/__tests__/components/BotRuntimeController/publish-luis-modal.test.tsx
index 59c3a09f79..87d3891ddb 100644
--- a/Composer/packages/client/__tests__/components/BotRuntimeController/publish-luis-modal.test.tsx
+++ b/Composer/packages/client/__tests__/components/BotRuntimeController/publish-luis-modal.test.tsx
@@ -53,7 +53,7 @@ describe(' ', () => {
onDismiss={onDismiss}
onPublish={onPublish}
/>,
- recoilInitState
+ recoilInitState,
);
expect(getByText('What is the name of your bot?')).not.toBeNull();
diff --git a/Composer/packages/client/__tests__/components/CreationFlow/CreateOptions/index.test.tsx b/Composer/packages/client/__tests__/components/CreationFlow/CreateOptions/index.test.tsx
index f13c8166fd..d3cc15fc4c 100644
--- a/Composer/packages/client/__tests__/components/CreationFlow/CreateOptions/index.test.tsx
+++ b/Composer/packages/client/__tests__/components/CreationFlow/CreateOptions/index.test.tsx
@@ -42,7 +42,7 @@ describe(' ', () => {
onJumpToOpenModal={handleJumpToOpenModal}
onNext={handleCreateNextMock}
onUpdateLocalTemplatePath={onUpdateLocalTemplatePathMock}
- />
+ />,
);
};
diff --git a/Composer/packages/client/__tests__/components/CreationFlow/DefineConversation/index.test.tsx b/Composer/packages/client/__tests__/components/CreationFlow/DefineConversation/index.test.tsx
index 4cede5894d..1905568ccf 100644
--- a/Composer/packages/client/__tests__/components/CreationFlow/DefineConversation/index.test.tsx
+++ b/Composer/packages/client/__tests__/components/CreationFlow/DefineConversation/index.test.tsx
@@ -47,7 +47,7 @@ describe(' ', () => {
({ set }) => {
set(focusedStorageFolderState, {} as StorageFolder);
set(storagesState, [{ id: 'default' }]);
- }
+ },
);
}
diff --git a/Composer/packages/client/__tests__/components/CreationFlow/LocationBrowser/FileSelector.test.tsx b/Composer/packages/client/__tests__/components/CreationFlow/LocationBrowser/FileSelector.test.tsx
index 109531f1a9..c5a2b605ee 100644
--- a/Composer/packages/client/__tests__/components/CreationFlow/LocationBrowser/FileSelector.test.tsx
+++ b/Composer/packages/client/__tests__/components/CreationFlow/LocationBrowser/FileSelector.test.tsx
@@ -43,7 +43,7 @@ describe(' ', () => {
updateFolder={updateFolder}
onCurrentPathUpdate={onCurrentPathUpdate}
onFileChosen={onFileChosen}
- />
+ />,
);
}
@@ -99,7 +99,7 @@ describe(' ', () => {
//locally this should be 'C:\\test-folder\\Desktop', but online it should be 'C:/test-folder/Desktop'
expect(
createFolder.mock.calls[0][0] === 'C:/test-folder/Desktop' ||
- createFolder.mock.calls[0][0] === 'C:\\test-folder\\Desktop'
+ createFolder.mock.calls[0][0] === 'C:\\test-folder\\Desktop',
).toBeTruthy();
expect(createFolder.mock.calls[0][1]).toBe('newFolder');
});
diff --git a/Composer/packages/client/__tests__/components/CreationFlow/LocationBrowser/LocationSelectContent.test.tsx b/Composer/packages/client/__tests__/components/CreationFlow/LocationBrowser/LocationSelectContent.test.tsx
index 18c331a160..f08b1405a4 100644
--- a/Composer/packages/client/__tests__/components/CreationFlow/LocationBrowser/LocationSelectContent.test.tsx
+++ b/Composer/packages/client/__tests__/components/CreationFlow/LocationBrowser/LocationSelectContent.test.tsx
@@ -59,7 +59,7 @@ describe(' ', () => {
onCurrentPathUpdate={onCurrentPathUpdateMock}
onOpen={onOpenMock}
/>,
- recoilInitState
+ recoilInitState,
);
}
diff --git a/Composer/packages/client/__tests__/components/CreationFlow/index.test.tsx b/Composer/packages/client/__tests__/components/CreationFlow/index.test.tsx
index 033baf540a..f390ceeaea 100644
--- a/Composer/packages/client/__tests__/components/CreationFlow/index.test.tsx
+++ b/Composer/packages/client/__tests__/components/CreationFlow/index.test.tsx
@@ -86,7 +86,7 @@ describe(' ', () => {
} = renderWithRouter(
-
+ ,
);
act(() => {
diff --git a/Composer/packages/client/__tests__/components/ImportModal/ImportModal.test.tsx b/Composer/packages/client/__tests__/components/ImportModal/ImportModal.test.tsx
index 18be17c36e..c9ea40137b 100644
--- a/Composer/packages/client/__tests__/components/ImportModal/ImportModal.test.tsx
+++ b/Composer/packages/client/__tests__/components/ImportModal/ImportModal.test.tsx
@@ -21,7 +21,7 @@ describe(' ', () => {
const { findByTestId } = render(
-
+ ,
);
// connecting state
diff --git a/Composer/packages/client/__tests__/components/ManageLuis/ManageLuis.test.tsx b/Composer/packages/client/__tests__/components/ManageLuis/ManageLuis.test.tsx
index 82ad2d85de..337e1eae7b 100644
--- a/Composer/packages/client/__tests__/components/ManageLuis/ManageLuis.test.tsx
+++ b/Composer/packages/client/__tests__/components/ManageLuis/ManageLuis.test.tsx
@@ -85,7 +85,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// confirm the text of the UI contains the dynamic values
@@ -105,7 +105,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
const cancelButton = await findByText('Cancel');
@@ -126,7 +126,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -143,7 +143,7 @@ describe(' ', () => {
expect(baseElement).toHaveTextContent(`Select ${serviceName} resources`);
expect(baseElement).toHaveTextContent(
- `Choose the subscription where your existing ${serviceName} resource is located.`
+ `Choose the subscription where your existing ${serviceName} resource is located.`,
);
// ensure that since a subscription hasn't been selected
@@ -207,7 +207,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -319,7 +319,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -335,7 +335,7 @@ describe(' ', () => {
});
expect(baseElement).toHaveTextContent(
- `I am creating a conversational experience using Microsoft Bot Framework project.`
+ `I am creating a conversational experience using Microsoft Bot Framework project.`,
);
});
});
diff --git a/Composer/packages/client/__tests__/components/ManageQNA/ManageQNA.test.tsx b/Composer/packages/client/__tests__/components/ManageQNA/ManageQNA.test.tsx
index d36777c32e..dc2443f2f1 100644
--- a/Composer/packages/client/__tests__/components/ManageQNA/ManageQNA.test.tsx
+++ b/Composer/packages/client/__tests__/components/ManageQNA/ManageQNA.test.tsx
@@ -118,7 +118,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// confirm the text of the UI contains the dynamic values
@@ -138,7 +138,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
const cancelButton = await findByText('Cancel');
@@ -159,7 +159,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -176,7 +176,7 @@ describe(' ', () => {
expect(baseElement).toHaveTextContent(`Select ${serviceName} resources`);
expect(baseElement).toHaveTextContent(
- `Choose the subscription where your existing ${serviceName} resource is located.`
+ `Choose the subscription where your existing ${serviceName} resource is located.`,
);
// ensure that since a subscription hasn't been selected
@@ -240,7 +240,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -373,7 +373,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -389,7 +389,7 @@ describe(' ', () => {
});
expect(baseElement).toHaveTextContent(
- `I am creating a conversational experience using Microsoft Bot Framework project.`
+ `I am creating a conversational experience using Microsoft Bot Framework project.`,
);
});
});
diff --git a/Composer/packages/client/__tests__/components/ManageService/ManageService.test.tsx b/Composer/packages/client/__tests__/components/ManageService/ManageService.test.tsx
index 54f5ac1ee3..f81e2873c6 100644
--- a/Composer/packages/client/__tests__/components/ManageService/ManageService.test.tsx
+++ b/Composer/packages/client/__tests__/components/ManageService/ManageService.test.tsx
@@ -98,7 +98,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// confirm the text of the UI contains the dynamic values
@@ -130,7 +130,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
const cancelButton = await findByText('Cancel');
@@ -159,7 +159,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -176,7 +176,7 @@ describe(' ', () => {
expect(baseElement).toHaveTextContent(`Select ${serviceName} resources`);
expect(baseElement).toHaveTextContent(
- `Choose the subscription where your existing ${serviceName} resource is located.`
+ `Choose the subscription where your existing ${serviceName} resource is located.`,
);
// ensure that since a subscription hasn't been selected
@@ -251,7 +251,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -345,7 +345,7 @@ describe(' ', () => {
'mockedGroup',
'mockedResource',
'westus',
- expect.anything()
+ expect.anything(),
);
// ensure that the final callback was called
@@ -377,7 +377,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -499,7 +499,7 @@ describe(' ', () => {
'mockedGroup',
'mockedResource',
'westus',
- 'mockedTier'
+ 'mockedTier',
);
// ensure that the final callback was called
@@ -530,7 +530,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -648,7 +648,7 @@ describe(' ', () => {
'mockedGroup',
'mockedResource',
'westus',
- 'mockedTier'
+ 'mockedTier',
);
// ensure that the final callback was called
@@ -679,7 +679,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -697,7 +697,7 @@ describe(' ', () => {
});
expect(baseElement).toHaveTextContent(
- `I am creating a conversational experience using Microsoft Bot Framework project.`
+ `I am creating a conversational experience using Microsoft Bot Framework project.`,
);
expect(baseElement).toHaveTextContent(handoffInstructions);
});
diff --git a/Composer/packages/client/__tests__/components/ManageSpeech/ManageSpeech.test.tsx b/Composer/packages/client/__tests__/components/ManageSpeech/ManageSpeech.test.tsx
index fd36133a25..09c50ac5ff 100644
--- a/Composer/packages/client/__tests__/components/ManageSpeech/ManageSpeech.test.tsx
+++ b/Composer/packages/client/__tests__/components/ManageSpeech/ManageSpeech.test.tsx
@@ -85,7 +85,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// confirm the text of the UI contains the dynamic values
@@ -105,7 +105,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
const cancelButton = await findByText('Cancel');
@@ -126,7 +126,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -143,7 +143,7 @@ describe(' ', () => {
expect(baseElement).toHaveTextContent(`Select ${serviceName} resources`);
expect(baseElement).toHaveTextContent(
- `Choose the subscription where your existing ${serviceName} resource is located.`
+ `Choose the subscription where your existing ${serviceName} resource is located.`,
);
// ensure that since a subscription hasn't been selected
@@ -207,7 +207,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -320,7 +320,7 @@ describe(' ', () => {
onGetKey={onGetKey}
onNext={onNext}
onToggleVisibility={onToggleVisibility}
- />
+ />,
);
// test the default option (choose existing)
@@ -336,7 +336,7 @@ describe(' ', () => {
});
expect(baseElement).toHaveTextContent(
- `I am creating a conversational experience using Microsoft Bot Framework project.`
+ `I am creating a conversational experience using Microsoft Bot Framework project.`,
);
});
});
diff --git a/Composer/packages/client/__tests__/components/MultiLanguage/MultiLanguage.test.tsx b/Composer/packages/client/__tests__/components/MultiLanguage/MultiLanguage.test.tsx
index 02dd0e9fc5..3a82f6c45d 100644
--- a/Composer/packages/client/__tests__/components/MultiLanguage/MultiLanguage.test.tsx
+++ b/Composer/packages/client/__tests__/components/MultiLanguage/MultiLanguage.test.tsx
@@ -30,7 +30,7 @@ describe(' ', () => {
locale={locale}
onDismiss={onDismiss}
onSubmit={onSubmit}
- />
+ />,
);
const engCheckBox = getByText('English (United States) - Original');
@@ -58,7 +58,7 @@ describe(' ', () => {
locale={locale}
onDismiss={onDismiss}
onSubmit={onSubmit}
- />
+ />,
);
const checkBox = getByText('Chinese (Simplified, China) - Current');
diff --git a/Composer/packages/client/__tests__/components/TriggerCreationModal/triggerCreationModal.test.tsx b/Composer/packages/client/__tests__/components/TriggerCreationModal/triggerCreationModal.test.tsx
index de2e1894ab..a0c9b15b31 100644
--- a/Composer/packages/client/__tests__/components/TriggerCreationModal/triggerCreationModal.test.tsx
+++ b/Composer/packages/client/__tests__/components/TriggerCreationModal/triggerCreationModal.test.tsx
@@ -41,7 +41,7 @@ describe(' ', () => {
onDismiss={onDismissMock}
onSubmit={onSubmitMock}
/>
-
+ ,
);
}
diff --git a/Composer/packages/client/__tests__/components/createDialogModal.test.tsx b/Composer/packages/client/__tests__/components/createDialogModal.test.tsx
index c2c5fef159..f269d78a21 100644
--- a/Composer/packages/client/__tests__/components/createDialogModal.test.tsx
+++ b/Composer/packages/client/__tests__/components/createDialogModal.test.tsx
@@ -18,7 +18,7 @@ describe(' ', () => {
,
({ set }) => {
set(showCreateDialogModalState, true);
- }
+ },
);
}
diff --git a/Composer/packages/client/__tests__/components/design.test.tsx b/Composer/packages/client/__tests__/components/design.test.tsx
index 58084c5a69..79977555ad 100644
--- a/Composer/packages/client/__tests__/components/design.test.tsx
+++ b/Composer/packages/client/__tests__/components/design.test.tsx
@@ -47,7 +47,7 @@ describe(' ', () => {
onDialogDeleteTrigger={handleDeleteTrigger}
onSelect={handleSelect}
/>,
- initRecoilState
+ initRecoilState,
);
const node = await findByTestId('EchoBot-1_Greeting');
fireEvent.click(node);
@@ -61,7 +61,7 @@ describe(' ', () => {
});
const handleSubmit = jest.fn(() => {});
const { getByText } = renderWithRecoil(
-
+ ,
);
const cancelButton = getByText('Cancel');
fireEvent.click(cancelButton);
@@ -81,7 +81,7 @@ describe(' ', () => {
projectId={projectId}
onDismiss={handleDismiss}
onSubmit={handleSubmit}
- />
+ />,
);
const cancelButton = getByText('Cancel');
fireEvent.click(cancelButton);
diff --git a/Composer/packages/client/__tests__/components/errorBoundary.test.tsx b/Composer/packages/client/__tests__/components/errorBoundary.test.tsx
index c0d97a0de0..fd995dc653 100644
--- a/Composer/packages/client/__tests__/components/errorBoundary.test.tsx
+++ b/Composer/packages/client/__tests__/components/errorBoundary.test.tsx
@@ -36,7 +36,7 @@ describe(' ', () => {
setApplicationLevelError={setApplicationErrorStub}
>
test
-
+ ,
);
expect(container).toHaveTextContent('test');
});
@@ -52,7 +52,7 @@ describe(' ', () => {
will not crash
-
+
,
);
expect(container).toHaveTextContent('will not crash');
@@ -65,8 +65,8 @@ describe(' ', () => {
- )
+ ,
+ ),
).toThrow();
});
});
diff --git a/Composer/packages/client/__tests__/components/getStarted.test.tsx b/Composer/packages/client/__tests__/components/getStarted.test.tsx
index c76459ad11..10bdc42e99 100644
--- a/Composer/packages/client/__tests__/components/getStarted.test.tsx
+++ b/Composer/packages/client/__tests__/components/getStarted.test.tsx
@@ -161,7 +161,7 @@ describe(' ', () => {
,
({ set }) => {
applyBaseState(set);
- }
+ },
);
const luisNode = await component.queryByText('Set up Language Understanding');
expect(luisNode).toBeNull();
diff --git a/Composer/packages/client/__tests__/components/home.test.tsx b/Composer/packages/client/__tests__/components/home.test.tsx
index 0d32354d18..f90b8397ac 100644
--- a/Composer/packages/client/__tests__/components/home.test.tsx
+++ b/Composer/packages/client/__tests__/components/home.test.tsx
@@ -18,7 +18,7 @@ describe(' ', () => {
];
const onItemChosen = jest.fn((item) => item.path);
const { container, queryByLabelText } = render(
-
+ ,
);
expect(container).toHaveTextContent('a');
expect(container).toHaveTextContent('b');
@@ -110,7 +110,7 @@ describe(' ', () => {
href={videoItem.url}
imageCover={videoItem.image}
title={videoItem.title}
- />
+ />,
);
expect(container).toHaveTextContent(videoItem.title);
});
diff --git a/Composer/packages/client/__tests__/components/onboarding.test.tsx b/Composer/packages/client/__tests__/components/onboarding.test.tsx
index b7e632ab04..512b43c0be 100644
--- a/Composer/packages/client/__tests__/components/onboarding.test.tsx
+++ b/Composer/packages/client/__tests__/components/onboarding.test.tsx
@@ -55,7 +55,7 @@ describe(' ', () => {
,
- onboardingDefaultState
+ onboardingDefaultState,
);
expect(rendered.baseElement).toHaveTextContent('Main dialog');
});
@@ -67,7 +67,7 @@ describe(' ', () => {
,
- onboardingDefaultState
+ onboardingDefaultState,
);
for (const { title } of stepSets) {
@@ -81,7 +81,7 @@ describe(' ', () => {
,
- onboardingDefaultState
+ onboardingDefaultState,
);
await findByText('Welcome');
});
diff --git a/Composer/packages/client/__tests__/components/skill.test.tsx b/Composer/packages/client/__tests__/components/skill.test.tsx
index 20afa38035..953b100071 100644
--- a/Composer/packages/client/__tests__/components/skill.test.tsx
+++ b/Composer/packages/client/__tests__/components/skill.test.tsx
@@ -135,7 +135,7 @@ describe(' ', () => {
projectId={projectId}
onDismiss={onDismiss}
/>,
- recoilInitState
+ recoilInitState,
);
const nextButton = getByTestId('SetAppIdNext');
@@ -153,7 +153,7 @@ describe(' ', () => {
});
expect(urlInput.getAttribute('value')).toBe(
- 'https://onenote-dev.azurewebsites.net/manifests/OneNoteSync-2-1-preview-1-manifest.json'
+ 'https://onenote-dev.azurewebsites.net/manifests/OneNoteSync-2-1-preview-1-manifest.json',
);
} finally {
jest.runOnlyPendingTimers();
@@ -186,7 +186,7 @@ describe(' ', () => {
expect(setFormDataErrors).toBeCalledWith(
expect.objectContaining({
manifestUrl: 'URL should start with http:// or https:// or file path of your system',
- })
+ }),
);
expect(setSkillManifest).not.toBeCalled();
});
@@ -257,7 +257,7 @@ describe(' ', () => {
expect(setFormDataErrors).toBeCalledWith(
expect.objectContaining({
manifestUrl: 'Manifest URL can not be accessed',
- })
+ }),
);
});
});
diff --git a/Composer/packages/client/__tests__/navItem.test.tsx b/Composer/packages/client/__tests__/navItem.test.tsx
index 5b7791bee6..0adce98955 100644
--- a/Composer/packages/client/__tests__/navItem.test.tsx
+++ b/Composer/packages/client/__tests__/navItem.test.tsx
@@ -10,7 +10,7 @@ import { renderWithRecoil } from './testUtils';
describe('', () => {
it('should render a nav item', async () => {
const { findByTestId } = renderWithRecoil(
-
+ ,
);
await findByTestId('ActiveLeftNavItem');
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/AllowedCallers.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/AllowedCallers.test.tsx
index 062dd71b61..d375c07a56 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/AllowedCallers.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/AllowedCallers.test.tsx
@@ -34,7 +34,7 @@ describe('Allowed Callers', () => {
};
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
// Create new caller
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/AppIdAndPassword.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/AppIdAndPassword.test.tsx
index 43aca1a3cc..6be431c7fd 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/AppIdAndPassword.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/AppIdAndPassword.test.tsx
@@ -29,7 +29,7 @@ describe('App Id and Password', () => {
};
const { getByTestId } = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const textField1 = getByTestId('MicrosoftAppId');
await act(async () => {
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/BotLanguage.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/BotLanguage.test.tsx
index 646af0eee1..a45b93caa3 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/BotLanguage.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/BotLanguage.test.tsx
@@ -33,7 +33,7 @@ describe('Bot Language', () => {
};
const { getByTestId } = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const defaultLanguageContainer = getByTestId('defaultLanguage');
expect(within(defaultLanguageContainer).getByText('English (United States)')).toBeInTheDocument();
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/BotProjectInfo.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/BotProjectInfo.test.tsx
index 07d09eb7e0..5aeca0cb7a 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/BotProjectInfo.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/BotProjectInfo.test.tsx
@@ -44,7 +44,7 @@ describe(' ', () => {
it('should render correct bot location', async () => {
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const locationNode = await component.findByTestId('botLocationString');
expect(locationNode.textContent).toBe(mockLocation);
@@ -53,7 +53,7 @@ describe(' ', () => {
it('should open read me', async () => {
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const readMeBtn = component.getByTestId('settingsReadMeBtn');
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/BotProjectSettings.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/BotProjectSettings.test.tsx
index 0b41fd2894..16c43d8eed 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/BotProjectSettings.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/BotProjectSettings.test.tsx
@@ -57,7 +57,7 @@ describe(' ', () => {
it('should toggle JSON view', async () => {
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const jsonToggleNode = await component.findByTestId('advancedSettingsToggle');
await act(async () => {
@@ -82,7 +82,7 @@ describe(' ', () => {
it('should nav to all tabs', async () => {
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const overviewTabNode = await component.findByText('Overview');
await act(async () => {
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/DeleteBotButton.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/DeleteBotButton.test.tsx
index 1af72d07b8..86e519173b 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/DeleteBotButton.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/DeleteBotButton.test.tsx
@@ -15,7 +15,7 @@ const state = {
describe('Delete Bot Button', () => {
it('should render Delete Bot Button', () => {
const { getByText } = renderWithRecoil(
-
+ ,
);
const deleteButton = getByText('Delete');
act(() => {
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/ExternalAdapterSettings.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/ExternalAdapterSettings.test.tsx
index c68d04c971..98bfc6efc5 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/ExternalAdapterSettings.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/ExternalAdapterSettings.test.tsx
@@ -67,14 +67,16 @@ jest.mock('../../../src/utils/navigation', () => ({
navigateTo: (...args) => mockNavigationTo(...args),
}));
-const makeInitialState = (newSettings: {}) => ({ set }) => {
- set(currentProjectIdState, PROJECT_ID);
- set(settingsState(PROJECT_ID), newSettings);
- set(dispatcherState, {
- setSettings: setSettingsMock,
- });
- set(schemasState(PROJECT_ID), mockSchemas);
-};
+const makeInitialState =
+ (newSettings: any) =>
+ ({ set }) => {
+ set(currentProjectIdState, PROJECT_ID);
+ set(settingsState(PROJECT_ID), newSettings);
+ set(dispatcherState, {
+ setSettings: setSettingsMock,
+ });
+ set(schemasState(PROJECT_ID), mockSchemas);
+ };
describe('ExternalAdapterSettings', () => {
let initRecoilState;
@@ -87,7 +89,7 @@ describe('ExternalAdapterSettings', () => {
it('brings up the modal', () => {
const { getByTestId, getByText, queryByTestId } = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const container = getByTestId('adapterSettings');
@@ -108,7 +110,7 @@ describe('ExternalAdapterSettings', () => {
it('sets settings on an adapter', async () => {
const { getByTestId, getByLabelText, queryByTestId } = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const container = getByTestId('adapterSettings');
const configureButton = within(container).queryAllByText('Configure')[0];
@@ -150,7 +152,7 @@ describe('ExternalAdapterSettings', () => {
it('does not proceed if required settings are missing', () => {
const { getByTestId } = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const container = getByTestId('adapterSettings');
const configureButton = within(container).queryAllByText('Configure')[0];
@@ -177,7 +179,7 @@ describe('ExternalAdapterSettings', () => {
const { queryByTestId } = renderWithRecoilAndCustomDispatchers(
,
- makeInitialState(initStateWithAdapter)
+ makeInitialState(initStateWithAdapter),
);
const toggle = queryByTestId('toggle_Adapter.Mock');
@@ -193,7 +195,7 @@ describe('ExternalAdapterSettings', () => {
runtimeSettings: {
adapters: [{ name: 'Adapter.Mock', enabled: false, route: 'mock', type: 'Adapter.Full.Type.Mock' }],
},
- })
+ }),
);
});
@@ -211,7 +213,7 @@ describe('ExternalAdapterSettings', () => {
const { queryByTestId } = renderWithRecoilAndCustomDispatchers(
,
- makeInitialState(initStateWithAdapter)
+ makeInitialState(initStateWithAdapter),
);
const toggle = queryByTestId('toggle_Adapter.Mock');
@@ -227,14 +229,14 @@ describe('ExternalAdapterSettings', () => {
runtimeSettings: {
adapters: [{ name: 'Adapter.Mock', enabled: true, route: 'mock', type: 'Adapter.Full.Type.Mock' }],
},
- })
+ }),
);
});
it('deep link should nav to package manager', async () => {
const { getByTestId } = renderWithRecoilAndCustomDispatchers(
,
- makeInitialState({})
+ makeInitialState({}),
);
fireEvent.click(getByTestId('packageManagerDeepLink'));
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/ExternalService.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/ExternalService.test.tsx
index 2c2af4086a..4663ff2e29 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/ExternalService.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/ExternalService.test.tsx
@@ -22,7 +22,7 @@ describe(' ', () => {
it('should render root external service view', async () => {
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const skillBotTextNode = await component.queryByTestId('skillQnaAuthoringBtn');
expect(skillBotTextNode).toBeFalsy();
@@ -31,7 +31,7 @@ describe(' ', () => {
it('should render skill external service view', async () => {
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const skillBotTextNode = await component.queryByTestId('skillQnaAuthoringBtn');
expect(skillBotTextNode).toBeTruthy();
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/GetAppInfoFromPublishProfileDialog.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/GetAppInfoFromPublishProfileDialog.test.tsx
index 2ced0e741e..7314df6848 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/GetAppInfoFromPublishProfileDialog.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/GetAppInfoFromPublishProfileDialog.test.tsx
@@ -48,7 +48,7 @@ describe(' ', () => {
onCancel={onCancelMock}
onOK={onOkayMock}
/>,
- initRecoilState
+ initRecoilState,
);
const errorNode = await component.findByText('No profiles were found containing a Microsoft App ID.');
expect(errorNode).toBeTruthy();
@@ -72,7 +72,7 @@ describe(' ', () => {
onCancel={onCancelMock}
onOK={onOkayMock}
/>,
- initRecoilState
+ initRecoilState,
);
const dropdown = component.getByTestId('publishProfileDropdown');
fireEvent.click(dropdown);
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/PublishTarget.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/PublishTarget.test.tsx
index 07902a39da..c5e80aa35c 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/PublishTarget.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/PublishTarget.test.tsx
@@ -36,7 +36,7 @@ describe('Publish Target', () => {
it('should add new publish profile', () => {
const { getByTestId, getByText } = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const addNewPublishProfile = getByTestId('addNewPublishProfile');
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/RootBotExternalService.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/RootBotExternalService.test.tsx
index 70c4ce36d3..de2a0de6de 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/RootBotExternalService.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/RootBotExternalService.test.tsx
@@ -74,7 +74,7 @@ describe('Root Bot External Service', () => {
const { getByTestId, findByText } = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const textFieldAuthoring = getByTestId('rootLUISAuthoringKey');
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/SkillBotExternalService.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/SkillBotExternalService.test.tsx
index cd2fe63aa7..aaba9ef9ab 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/SkillBotExternalService.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/SkillBotExternalService.test.tsx
@@ -110,7 +110,7 @@ describe(' ', () => {
//test
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const textFieldAuthoring = await component.getByTestId('skillLUISAuthoringKeyField');
@@ -123,7 +123,7 @@ describe(' ', () => {
it('should allow skill specific luis key that is updated in settings', async () => {
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const useSkillLuisKeyBtn = await component.getByTestId('skillLUISAuthoringKeyBtn');
await act(async () => {
@@ -149,7 +149,7 @@ describe(' ', () => {
it('should allow skill specific qna key that is updated in settings', async () => {
const component = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const useSkillQnaKeyBtn = await component.getByTestId('skillQnaAuthoringBtn');
await act(async () => {
diff --git a/Composer/packages/client/__tests__/pages/botProjectsSettings/SkillHostEndPoint.test.tsx b/Composer/packages/client/__tests__/pages/botProjectsSettings/SkillHostEndPoint.test.tsx
index 3d40d406f8..d3fe3724bc 100644
--- a/Composer/packages/client/__tests__/pages/botProjectsSettings/SkillHostEndPoint.test.tsx
+++ b/Composer/packages/client/__tests__/pages/botProjectsSettings/SkillHostEndPoint.test.tsx
@@ -29,7 +29,7 @@ describe('SkillHostEndPoint', () => {
};
const { getByTestId } = renderWithRecoilAndCustomDispatchers(
,
- initRecoilState
+ initRecoilState,
);
const textField = getByTestId('SkillHostEndPointTextField');
await act(async () => {
diff --git a/Composer/packages/client/__tests__/pages/design/DebugPanel/DiagnosticsContent.test.tsx b/Composer/packages/client/__tests__/pages/design/DebugPanel/DiagnosticsContent.test.tsx
index 8274def0dd..abfa3e9b88 100644
--- a/Composer/packages/client/__tests__/pages/design/DebugPanel/DiagnosticsContent.test.tsx
+++ b/Composer/packages/client/__tests__/pages/design/DebugPanel/DiagnosticsContent.test.tsx
@@ -141,14 +141,14 @@ describe(' ', () => {
set(schemasState(state.projectId), mockProjectResponse.schemas);
set(
formDialogSchemaIdsState(state.projectId),
- state.formDialogSchemas.map((fds) => fds.id)
+ state.formDialogSchemas.map((fds) => fds.id),
);
};
it('should render the DiagnosticList', () => {
const { container } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
expect(container).toHaveTextContent('server');
});
diff --git a/Composer/packages/client/__tests__/pages/knowledge-base/CreateQnAModal.test.tsx b/Composer/packages/client/__tests__/pages/knowledge-base/CreateQnAModal.test.tsx
index 7393f62acd..7c2b4d10fc 100644
--- a/Composer/packages/client/__tests__/pages/knowledge-base/CreateQnAModal.test.tsx
+++ b/Composer/packages/client/__tests__/pages/knowledge-base/CreateQnAModal.test.tsx
@@ -105,7 +105,7 @@ describe('QnA creation flow', () => {
qnaFiles={state.qnaFiles}
onSubmit={handleSubmit}
/>,
- initRecoilState
+ initRecoilState,
);
const nameField = getByTestId('knowledgeLocationTextField-name');
@@ -131,7 +131,7 @@ describe('QnA creation flow', () => {
qnaFiles={state.qnaFiles}
onSubmit={handleSubmit}
/>,
- initRecoilState
+ initRecoilState,
);
const nameField = getByTestId('knowledgeLocationTextField-name');
@@ -155,7 +155,7 @@ describe('QnA creation flow', () => {
qnaFiles={state.qnaFiles}
onSubmit={handleSubmit}
/>,
- initRecoilState
+ initRecoilState,
);
const nameField = getByTestId('knowledgeLocationTextField-name');
diff --git a/Composer/packages/client/__tests__/pages/knowledge-base/ImportQnAFromUrlModal.test.tsx b/Composer/packages/client/__tests__/pages/knowledge-base/ImportQnAFromUrlModal.test.tsx
index b93b35eae1..3dcdb69bb4 100644
--- a/Composer/packages/client/__tests__/pages/knowledge-base/ImportQnAFromUrlModal.test.tsx
+++ b/Composer/packages/client/__tests__/pages/knowledge-base/ImportQnAFromUrlModal.test.tsx
@@ -24,7 +24,7 @@ const qnaFile = {
describe('QnA page all up view', () => {
it('should render QnA page table view', () => {
const { getByText, getByTestId } = renderWithRecoil(
- {}} onSubmit={handleSubmit} />
+ {}} onSubmit={handleSubmit} />,
);
const urlField = getByTestId('ImportNewUrlToOverwriteQnAFile');
fireEvent.change(urlField, { target: { value: 'http://newUrl.pdf' } });
diff --git a/Composer/packages/client/__tests__/pages/knowledge-base/QnAPage.test.tsx b/Composer/packages/client/__tests__/pages/knowledge-base/QnAPage.test.tsx
index 6f53f962ce..f0f7e5863c 100644
--- a/Composer/packages/client/__tests__/pages/knowledge-base/QnAPage.test.tsx
+++ b/Composer/packages/client/__tests__/pages/knowledge-base/QnAPage.test.tsx
@@ -72,7 +72,7 @@ describe('QnA page all up view', () => {
it('should render QnA page table view', () => {
const { getByTestId, getByText } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
getByTestId('table-view');
getByText('Question');
@@ -81,7 +81,7 @@ describe('QnA page all up view', () => {
it('should render QnA page code editor', () => {
renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
});
@@ -98,7 +98,7 @@ describe('QnA page all up view', () => {
locale={'en-us'}
onChangeLocale={() => {}}
/>,
- initRecoilState
+ initRecoilState,
);
getByText('English (United States)(Default)');
getByText('Chinese (Simplified, China)');
diff --git a/Composer/packages/client/__tests__/pages/knowledge-base/ReplaceQnAFromModal.test.tsx b/Composer/packages/client/__tests__/pages/knowledge-base/ReplaceQnAFromModal.test.tsx
index 751bf6d9d2..0a04350c2f 100644
--- a/Composer/packages/client/__tests__/pages/knowledge-base/ReplaceQnAFromModal.test.tsx
+++ b/Composer/packages/client/__tests__/pages/knowledge-base/ReplaceQnAFromModal.test.tsx
@@ -33,7 +33,7 @@ describe('Replace QnA from portal Modal', () => {
qnaFile={qnaFile}
onDismiss={onDismiss}
onSubmit={handleSubmit}
- />
+ />,
);
const urlField = getByTestId('ImportNewUrlToOverwriteQnAFile');
fireEvent.change(urlField, { target: { value: 'http://newUrl.pdf' } });
@@ -52,7 +52,7 @@ describe('Replace QnA from portal Modal', () => {
qnaFile={qnaFile}
onDismiss={onDismiss}
onSubmit={handleSubmit}
- />
+ />,
);
const secondOption = getByText('Replace with an existing knowledge base from QnA maker portal');
fireEvent.click(secondOption);
@@ -60,7 +60,7 @@ describe('Replace QnA from portal Modal', () => {
fireEvent.click(next);
expect(
- getByText('Select the subscription and resource you want to choose a knowledge base from')
+ getByText('Select the subscription and resource you want to choose a knowledge base from'),
).toBeInTheDocument();
});
});
diff --git a/Composer/packages/client/__tests__/pages/knowledge-base/table-view.test.tsx b/Composer/packages/client/__tests__/pages/knowledge-base/table-view.test.tsx
index 425072fc02..245026a55b 100644
--- a/Composer/packages/client/__tests__/pages/knowledge-base/table-view.test.tsx
+++ b/Composer/packages/client/__tests__/pages/knowledge-base/table-view.test.tsx
@@ -76,7 +76,7 @@ describe('QnA page all up view', () => {
it('should render QnA page table view', () => {
const { getByTestId, getByText } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
const more = getByTestId('knowledgeBaseMore');
fireEvent.click(more);
diff --git a/Composer/packages/client/__tests__/pages/language-generation/LGPage.test.tsx b/Composer/packages/client/__tests__/pages/language-generation/LGPage.test.tsx
index 45b296d81a..b4a133c54c 100644
--- a/Composer/packages/client/__tests__/pages/language-generation/LGPage.test.tsx
+++ b/Composer/packages/client/__tests__/pages/language-generation/LGPage.test.tsx
@@ -60,7 +60,7 @@ describe('LG page all up view', () => {
it('should render lg page table view', () => {
const { getByText, getByTestId } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
getByTestId('table-view');
getByText('Name');
diff --git a/Composer/packages/client/__tests__/pages/language-understanding/LUPage.test.tsx b/Composer/packages/client/__tests__/pages/language-understanding/LUPage.test.tsx
index 909950eb8b..f944e1801b 100644
--- a/Composer/packages/client/__tests__/pages/language-understanding/LUPage.test.tsx
+++ b/Composer/packages/client/__tests__/pages/language-understanding/LUPage.test.tsx
@@ -59,7 +59,7 @@ describe('LU page all up view', () => {
it('should render lu page table view', () => {
const { getByText, getByTestId } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
getByTestId('table-view');
getByText('Intent');
diff --git a/Composer/packages/client/__tests__/pages/publish/CreatePublishProfileDialog.test.tsx b/Composer/packages/client/__tests__/pages/publish/CreatePublishProfileDialog.test.tsx
index bdd5e3cda6..5795405c6f 100644
--- a/Composer/packages/client/__tests__/pages/publish/CreatePublishProfileDialog.test.tsx
+++ b/Composer/packages/client/__tests__/pages/publish/CreatePublishProfileDialog.test.tsx
@@ -10,7 +10,7 @@ describe('CreatePublishProfileDialog', () => {
it("Call param function when 'Create new publish profile' is clicked", async () => {
const onShowPublishProfileDialogMock = jest.fn();
const component = render(
-
+ ,
);
const createNewBtn = component.getByTestId('addNewPublishProfile');
await act(async () => {
diff --git a/Composer/packages/client/__tests__/pages/publish/Publish.test.tsx b/Composer/packages/client/__tests__/pages/publish/Publish.test.tsx
index d4c0e943d8..ea26bd0d7e 100644
--- a/Composer/packages/client/__tests__/pages/publish/Publish.test.tsx
+++ b/Composer/packages/client/__tests__/pages/publish/Publish.test.tsx
@@ -115,7 +115,7 @@ describe('publish page', () => {
onManagePublishProfile={jest.fn()}
onRollbackClick={jest.fn()}
/>,
- initRecoilState
+ initRecoilState,
);
getByText('Bot');
getByText('Date');
@@ -151,7 +151,7 @@ describe('publish page', () => {
];
const { getByText } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
getByText('Publish');
getByText('You are about to publish your bot to the profile below. Do you want to proceed?');
diff --git a/Composer/packages/client/__tests__/recognizer.test.ts b/Composer/packages/client/__tests__/recognizer.test.ts
index 3b3bfd0c4a..6462e5ba93 100644
--- a/Composer/packages/client/__tests__/recognizer.test.ts
+++ b/Composer/packages/client/__tests__/recognizer.test.ts
@@ -21,7 +21,7 @@ describe('Test the generated recognizer dialogs', () => {
],
'qna',
false,
- QnALocales
+ QnALocales,
);
expect(result.id).toBe('test.qna.dialog');
@@ -34,7 +34,7 @@ describe('Test the generated recognizer dialogs', () => {
const result = getCrossTrainedRecognizerDialog(
'test',
[{ id: 'test.en-us', empty: false }] as LuFile[],
- [{ id: 'test.en-us', empty: false }] as QnAFile[]
+ [{ id: 'test.en-us', empty: false }] as QnAFile[],
);
expect(result.id).toBe('test.lu.qna.dialog');
expect(result.content.recognizers[0]).toBe('test.lu');
@@ -108,7 +108,7 @@ describe('Test the generated recognizer dialogs', () => {
[
{ id: 'test.en-us', content: 'test' },
{ id: 'test.fr-fr', empty: false },
- ]
+ ],
);
expect(result.length).toBe(1);
diff --git a/Composer/packages/client/__tests__/testUtils/react-recoil-hooks-testing-library.tsx b/Composer/packages/client/__tests__/testUtils/react-recoil-hooks-testing-library.tsx
index 58206190f0..e2ce6e40f5 100644
--- a/Composer/packages/client/__tests__/testUtils/react-recoil-hooks-testing-library.tsx
+++ b/Composer/packages/client/__tests__/testUtils/react-recoil-hooks-testing-library.tsx
@@ -40,8 +40,8 @@ function recoilStateWrapper(options?: RenderHookOptions) {
};
return result;
},
- {}
- )
+ {},
+ ),
);
useEffect(() => {
@@ -78,7 +78,7 @@ function renderRecoilHook(
callback: (props: P) => R,
options?: RenderHookOptions & {
initialProps?: P;
- }
+ },
): RenderHookResult
{
return renderHook(callback, {
...options,
diff --git a/Composer/packages/client/__tests__/testUtils/renderWithRecoil.tsx b/Composer/packages/client/__tests__/testUtils/renderWithRecoil.tsx
index 6d02164a2d..fff0e9a4b4 100644
--- a/Composer/packages/client/__tests__/testUtils/renderWithRecoil.tsx
+++ b/Composer/packages/client/__tests__/testUtils/renderWithRecoil.tsx
@@ -12,13 +12,13 @@ export function renderWithRecoil(subject, initRecoilState: (mutableSnapshot: Mut
return render(
{subject}
-
+ ,
);
}
export function renderWithRecoilAndCustomDispatchers(
subject,
- initRecoilState: (mutableSnapshot: MutableSnapshot) => void = noop
+ initRecoilState: (mutableSnapshot: MutableSnapshot) => void = noop,
) {
return render({subject} );
}
diff --git a/Composer/packages/client/__tests__/testUtils/renderWithRecoilAndContext.tsx b/Composer/packages/client/__tests__/testUtils/renderWithRecoilAndContext.tsx
index e41ce3bc7c..2a8ce9375f 100644
--- a/Composer/packages/client/__tests__/testUtils/renderWithRecoilAndContext.tsx
+++ b/Composer/packages/client/__tests__/testUtils/renderWithRecoilAndContext.tsx
@@ -10,11 +10,11 @@ import { DispatcherWrapper } from '../../src/recoilModel';
export function renderWithRecoilAndContext(
subject,
- initRecoilState: (mutableSnapshot: MutableSnapshot) => void = noop
+ initRecoilState: (mutableSnapshot: MutableSnapshot) => void = noop,
) {
return render(
{subject}
-
+ ,
);
}
diff --git a/Composer/packages/client/config/webpack.config.js b/Composer/packages/client/config/webpack.config.js
index 6cb1b2e42e..609da2f8a1 100644
--- a/Composer/packages/client/config/webpack.config.js
+++ b/Composer/packages/client/config/webpack.config.js
@@ -222,23 +222,6 @@ module.exports = function (webpackEnv) {
// Disable require.ensure as it's not a standard language feature.
{ parser: { requireEnsure: false } },
- // First, run the linter.
- // It's important to do this before Babel processes the JS.
- {
- test: /\.(js|mjs|jsx)$/,
- enforce: 'pre',
- use: [
- {
- options: {
- formatter: require.resolve('react-dev-utils/eslintFormatter'),
- eslintPath: require.resolve('eslint'),
- quiet: true,
- },
- loader: require.resolve('eslint-loader'),
- },
- ],
- include: paths.appSrc,
- },
{
test: /\.worker\.ts$/,
use: {
diff --git a/Composer/packages/client/package.json b/Composer/packages/client/package.json
index 141796f035..43f27c8b41 100644
--- a/Composer/packages/client/package.json
+++ b/Composer/packages/client/package.json
@@ -10,7 +10,7 @@
"scripts": {
"start": "node --max_old_space_size=6114 --max-http-header-size=16000 scripts/start.js",
"build": "node --max_old_space_size=6114 scripts/build.js",
- "clean": "rimraf build",
+ "clean": "rimraf build .swc",
"test": "jest",
"lint": "eslint --quiet --ext .js,.jsx,.ts,.tsx ./src ./__tests__",
"lint:fix": "yarn lint --fix",
@@ -78,7 +78,7 @@
"recoil": "^0.0.13",
"sanitize-html": "2.3.3",
"styled-components": "^4.1.3",
- "tslib": "2.4.0",
+ "tslib": "2.6.2",
"uuid": "^8.3.0",
"webpack-bundle-analyzer": "^4.4.2"
},
@@ -89,12 +89,12 @@
"not op_mini all"
],
"devDependencies": {
- "@babel/cli": "7.18.6",
- "@babel/core": "7.18.6",
+ "@babel/cli": "7.23.9",
+ "@babel/core": "7.24.0",
"@babel/runtime": "7.3.4",
"@botframework-composer/test-utils": "*",
"@emotion/babel-plugin": "^11.9.2",
- "@emotion/babel-preset-css-prop": "11.2.0",
+ "@emotion/babel-preset-css-prop": "11.11.0",
"@svgr/webpack": "4.1.0",
"@types/jwt-decode": "^2.2.1",
"@types/lodash": "^4.14.146",
@@ -115,7 +115,6 @@
"dotenv-expand": "4.2.0",
"esbuild-loader": "^2.8.0",
"eslint-config-react-app": "5.2.1",
- "eslint-loader": "4.0.0",
"file-loader": "4.2.0",
"format-message-cli": "6.2.4",
"fs-extra": "7.0.1",
diff --git a/Composer/packages/client/public/index.html b/Composer/packages/client/public/index.html
index 51d64d74e3..98621f2ba5 100644
--- a/Composer/packages/client/public/index.html
+++ b/Composer/packages/client/public/index.html
@@ -22,7 +22,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
-
BotFramework Composer
+ Bot Framework Composer
<% if (process.env.NODE_ENV === 'production') { %>
if (__nonce__) { ?>
diff --git a/Composer/packages/client/public/manifest.json b/Composer/packages/client/public/manifest.json
index 477da346d6..4eb20470e8 100644
--- a/Composer/packages/client/public/manifest.json
+++ b/Composer/packages/client/public/manifest.json
@@ -1,6 +1,6 @@
{
"short_name": "Composer",
- "name": "BotFramework Composer",
+ "name": "Bot Framework Composer",
"icons": [
{
"src": "composerfavicon.ico",
diff --git a/Composer/packages/client/setupTests.ts b/Composer/packages/client/setupTests.ts
index f56b1db07f..83c7fc286a 100644
--- a/Composer/packages/client/setupTests.ts
+++ b/Composer/packages/client/setupTests.ts
@@ -4,6 +4,10 @@
///
// for tests using Electron IPC to talk to main process
-(window as any).ipcRenderer = { on: jest.fn() };
+(window as any).ipcRenderer = {
+ on: jest.fn(),
+ invoke: jest.fn().mockReturnValue(Promise.resolve({})),
+ send: jest.fn()
+};
jest.mock('./src/utils/httpUtil');
diff --git a/Composer/packages/client/src/App.tsx b/Composer/packages/client/src/App.tsx
index 746f786135..6a2ba902cb 100644
--- a/Composer/packages/client/src/App.tsx
+++ b/Composer/packages/client/src/App.tsx
@@ -1,16 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-import React, { Fragment, useEffect } from 'react';
-import { useRecoilValue } from 'recoil';
+import React, { Fragment, useEffect, useState } from 'react';
+import { useRecoilValue, useRecoilCallback, CallbackInterface } from 'recoil';
+import { useMount, useUnmount } from '@fluentui/react-hooks';
import { Header } from './components/Header';
import { Announcement } from './components/AppComponents/Announcement';
import { MainContainer } from './components/AppComponents/MainContainer';
-import { dispatcherState, userSettingsState } from './recoilModel';
+import { dispatcherState, userSettingsState, lgFileState } from './recoilModel';
import { loadLocale } from './utils/fileUtil';
import { useInitializeLogger } from './telemetry/useInitializeLogger';
import { setupIcons } from './setupIcons';
+import { setOneAuthEnabled } from './utils/oneAuthUtil';
+import { LoadingSpinner } from './components/LoadingSpinner';
+import lgWorker from './recoilModel/parsers/lgWorker';
+import { LgEventType } from './recoilModel/parsers/types';
setupIcons();
@@ -23,13 +28,24 @@ const { ipcRenderer } = window;
export const App: React.FC = () => {
const { appLocale } = useRecoilValue(userSettingsState);
- const {
- fetchExtensions,
- fetchFeatureFlags,
- checkNodeVersion,
- performAppCleanupOnQuit,
- setMachineInfo,
- } = useRecoilValue(dispatcherState);
+ const [isClosing, setIsClosing] = useState(false);
+ const [listener, setListener] = useState<{ destroy(): boolean }>({} as any);
+
+ const { fetchExtensions, fetchFeatureFlags, checkNodeVersion, performAppCleanupOnQuit, setMachineInfo } =
+ useRecoilValue(dispatcherState);
+ const updateFile = useRecoilCallback((callbackHelpers: CallbackInterface) => async ({ projectId, value }) => {
+ callbackHelpers.set(lgFileState({ projectId, lgFileId: value.id }), value);
+ });
+
+ useMount(() => {
+ const listener = lgWorker.listen(LgEventType.OnUpdateLgFile, (msg) => {
+ const { projectId, payload } = msg.data;
+ updateFile({ projectId, value: payload });
+ });
+ setListener(listener);
+ });
+
+ useUnmount(() => listener.destroy());
useEffect(() => {
loadLocale(appLocale);
@@ -39,17 +55,22 @@ export const App: React.FC = () => {
checkNodeVersion();
fetchExtensions();
fetchFeatureFlags();
- ipcRenderer?.on('cleanup', (_event) => {
- performAppCleanupOnQuit();
+
+ ipcRenderer?.invoke('app-init').then(({ machineInfo, isOneAuthEnabled }) => {
+ setMachineInfo(machineInfo);
+ setOneAuthEnabled(isOneAuthEnabled);
});
- ipcRenderer?.on('machine-info', (_event, info) => {
- setMachineInfo(info);
+ ipcRenderer?.on('closing', async () => {
+ setIsClosing(true);
+ await performAppCleanupOnQuit();
+ ipcRenderer.send('closed');
});
}, []);
return (
+ {isClosing && }
diff --git a/Composer/packages/client/src/Onboarding/Onboarding.tsx b/Composer/packages/client/src/Onboarding/Onboarding.tsx
index b223ae2b28..30988750c9 100644
--- a/Composer/packages/client/src/Onboarding/Onboarding.tsx
+++ b/Composer/packages/client/src/Onboarding/Onboarding.tsx
@@ -115,8 +115,8 @@ const Onboarding: React.FC = () => {
const result = await OpenConfirmModal(
formatMessage('Leave Product Tour?'),
formatMessage(
- 'Are you sure you want to exit the Onboarding Product Tour? You can restart the tour in the onboarding settings.'
- )
+ 'Are you sure you want to exit the Onboarding Product Tour? You can restart the tour in the onboarding settings.',
+ ),
);
if (result) {
diff --git a/Composer/packages/client/src/Onboarding/content.tsx b/Composer/packages/client/src/Onboarding/content.tsx
index 160a3000c0..119943f149 100644
--- a/Composer/packages/client/src/Onboarding/content.tsx
+++ b/Composer/packages/client/src/Onboarding/content.tsx
@@ -102,7 +102,7 @@ export const getTeachingBubble = (id: string | undefined): TeachingBubble => {
case 'mainDialog':
return {
content: formatMessage(
- 'The main dialog is the foundation of every bot created in Composer. There is only one main dialog and all other dialogs are children of it. It gets initialized every time your bot runs and is the entry point into the bot.'
+ 'The main dialog is the foundation of every bot created in Composer. There is only one main dialog and all other dialogs are children of it. It gets initialized every time your bot runs and is the entry point into the bot.',
),
headline: formatMessage('Main dialog'),
helpLink: 'https://docs.microsoft.com/en-us/composer/concept-dialog',
@@ -111,7 +111,7 @@ export const getTeachingBubble = (id: string | undefined): TeachingBubble => {
case 'trigger':
return {
content: formatMessage(
- 'Triggers are the main component of a dialog, they are how you catch and respond to events. Each trigger has a condition and a collection of actions to execute when the condition is met.'
+ 'Triggers are the main component of a dialog, they are how you catch and respond to events. Each trigger has a condition and a collection of actions to execute when the condition is met.',
),
headline: formatMessage('Add a new trigger'),
helpLink: 'https://docs.microsoft.com/en-us/composer/concept-events-and-triggers',
@@ -120,7 +120,7 @@ export const getTeachingBubble = (id: string | undefined): TeachingBubble => {
case 'actions':
return {
content: formatMessage(
- 'Actions are the main component of a trigger; they are what enable your bot to take action whether in response to user input or any other event that may occur.'
+ 'Actions are the main component of a trigger; they are what enable your bot to take action whether in response to user input or any other event that may occur.',
),
headline: formatMessage('Actions'),
helpLink: 'https://docs.microsoft.com/en-us/composer/concept-dialog#action',
@@ -129,7 +129,7 @@ export const getTeachingBubble = (id: string | undefined): TeachingBubble => {
case 'userInput':
return {
content: formatMessage(
- 'The User Input page is where the Language Understanding editor locates. From here users can view all the Language Understanding templates and edit them.'
+ 'The User Input page is where the Language Understanding editor locates. From here users can view all the Language Understanding templates and edit them.',
),
headline: formatMessage('User input'),
helpLink: 'https://docs.microsoft.com/en-us/composer/concept-language-understanding',
@@ -138,7 +138,7 @@ export const getTeachingBubble = (id: string | undefined): TeachingBubble => {
case 'botResponses':
return {
content: formatMessage(
- 'The Bot Responses page is where the Language Generation (LG) editor locates. From here users can view all the LG templates and edit them.'
+ 'The Bot Responses page is where the Language Generation (LG) editor locates. From here users can view all the LG templates and edit them.',
),
headline: formatMessage('Bot responses'),
helpLink: 'https://docs.microsoft.com/en-us/composer/concept-language-generation',
@@ -159,7 +159,7 @@ export const getTeachingBubble = (id: string | undefined): TeachingBubble => {
{children}
),
- }
+ },
),
headline: formatMessage('Test with Web Chat or Emulator'),
calloutProps: {
diff --git a/Composer/packages/client/src/components/Adapters/TeamsManifestGeneratorModal.tsx b/Composer/packages/client/src/components/Adapters/TeamsManifestGeneratorModal.tsx
index 7d3dc35739..9c1bed5cd3 100644
--- a/Composer/packages/client/src/components/Adapters/TeamsManifestGeneratorModal.tsx
+++ b/Composer/packages/client/src/components/Adapters/TeamsManifestGeneratorModal.tsx
@@ -86,7 +86,7 @@ export const TeamsManifestGeneratorModal = (props: TeamsManifestGeneratorModalPr
dialogType={DialogTypes.CreateFlow}
isOpen={!props.hidden}
subText={formatMessage(
- 'Your Teams adapter is configured for your published bot. Copy the manifest, open App Studio in Teams and add the manifest so you can test your bot in Teams'
+ 'Your Teams adapter is configured for your published bot. Copy the manifest, open App Studio in Teams and add the manifest so you can test your bot in Teams',
)}
title={formatMessage('Teams Manifest')}
onDismiss={props.onDismiss}
diff --git a/Composer/packages/client/src/components/AddRemoteSkillModal/CreateSkillModal.tsx b/Composer/packages/client/src/components/AddRemoteSkillModal/CreateSkillModal.tsx
index 4781c4cc33..1544d86846 100644
--- a/Composer/packages/client/src/components/AddRemoteSkillModal/CreateSkillModal.tsx
+++ b/Composer/packages/client/src/components/AddRemoteSkillModal/CreateSkillModal.tsx
@@ -117,7 +117,7 @@ export const validateLocalZip = async (files: Record) => {
} else {
result.error = {
manifestUrl: formatMessage(
- 'Endpoints should not be empty or endpoint should have endpoint url field in manifest json'
+ 'Endpoints should not be empty or endpoint should have endpoint url field in manifest json',
),
};
}
@@ -140,7 +140,7 @@ export const getSkillManifest = async (
manifestUrl: string,
setSkillManifest,
setFormDataErrors,
- setShowDetail
+ setShowDetail,
) => {
try {
const { data } = await httpClient.get(`/projects/${projectId}/skill/retrieveSkillManifest`, {
@@ -208,9 +208,13 @@ export const CreateSkillModal: React.FC = (props) => {
const [zipContent, setZipContent] = useState({});
const publishTypes = useRecoilValue(publishTypesState(projectId));
- const { languages, luFeatures, runtime, publishTargets = [], MicrosoftAppId } = useRecoilValue(
- settingsState(projectId)
- );
+ const {
+ languages,
+ luFeatures,
+ runtime,
+ publishTargets = [],
+ MicrosoftAppId,
+ } = useRecoilValue(settingsState(projectId));
const { dialogId } = useRecoilValue(designPageLocationState(projectId));
const rootDialog = useRecoilValue(rootDialogSelector(projectId));
const luFiles = useRecoilValue(luFilesSelectorFamily(projectId));
@@ -243,7 +247,7 @@ export const CreateSkillModal: React.FC = (props) => {
formData: { manifestUrl: currentManifestUrl },
...validationHelpers,
},
- skillUrls
+ skillUrls,
);
setFormData({
...rest,
@@ -261,7 +265,7 @@ export const CreateSkillModal: React.FC = (props) => {
getSkillManifest(projectId, formData.manifestUrl, setSkillManifest, setFormDataErrors, setShowDetail);
setManifestDirPath(localManifestPath.substring(0, localManifestPath.lastIndexOf('/')));
},
- [projectId, formData]
+ [projectId, formData],
);
const handleSubmit = async (event, content: string, enable: boolean) => {
@@ -303,7 +307,7 @@ export const CreateSkillModal: React.FC = (props) => {
setMicrosoftAppProperties(
projectId,
configuration.settings.MicrosoftAppId,
- configuration.settings.MicrosoftAppPassword
+ configuration.settings.MicrosoftAppPassword,
);
setShowSetAppIdDialog(false);
diff --git a/Composer/packages/client/src/components/AddRemoteSkillModal/EnableOrchestrator.tsx b/Composer/packages/client/src/components/AddRemoteSkillModal/EnableOrchestrator.tsx
index 4c2e8d3904..c6da4e3082 100644
--- a/Composer/packages/client/src/components/AddRemoteSkillModal/EnableOrchestrator.tsx
+++ b/Composer/packages/client/src/components/AddRemoteSkillModal/EnableOrchestrator.tsx
@@ -44,7 +44,7 @@ const EnableOrchestrator: React.FC = (props) => {
,
manifestDirPath: string,
- locale: string
+ locale: string,
) => {
const luFiles: Record = {};
try {
diff --git a/Composer/packages/client/src/components/AddRemoteSkillModal/SetAppId.tsx b/Composer/packages/client/src/components/AddRemoteSkillModal/SetAppId.tsx
index e3de730efc..ae0149c46e 100644
--- a/Composer/packages/client/src/components/AddRemoteSkillModal/SetAppId.tsx
+++ b/Composer/packages/client/src/components/AddRemoteSkillModal/SetAppId.tsx
@@ -36,7 +36,7 @@ const getCreateProfileDescription = (botName, handleCreateProfile) => ({
},
title: formatMessage(`Add publishing profile for {botName}`, { botName }),
description: formatMessage(
- 'A publishing profile contains the information necessary to provision and publish your bot, including its App ID. '
+ 'A publishing profile contains the information necessary to provision and publish your bot, including its App ID. ',
),
link: {
text: formatMessage('Create profile'),
@@ -47,14 +47,14 @@ const getCreateProfileDescription = (botName, handleCreateProfile) => ({
const manifestUrl = () => ({
title: formatMessage('Enter skill manifest URL'),
description: formatMessage(
- 'To connect to a skill, your bot needs the information captured in the skill’s manifest. Contact the author or publisher of the skill for this information.'
+ 'To connect to a skill, your bot needs the information captured in the skill’s manifest. Contact the author or publisher of the skill for this information.',
),
});
const appIdInfo = () => ({
title: formatMessage('Ensure your bot’s Microsoft App ID is on the skill’s allowed callers list'),
description: formatMessage(
- 'For security purposes, your bot can only call a skill if its Microsoft App ID is in the skill’s allowed callers list. Once you create a publishing profile, share your bot’s App ID with the skill’s author to add it. You may also need to include the skill’s App Id in the root bot’s allowed callers list.'
+ 'For security purposes, your bot can only call a skill if its Microsoft App ID is in the skill’s allowed callers list. Once you create a publishing profile, share your bot’s App ID with the skill’s author to add it. You may also need to include the skill’s App Id in the root bot’s allowed callers list.',
),
});
@@ -159,7 +159,7 @@ export const SetAppId: React.FC = (props) => {
},
title: formatMessage('Select App ID and password'),
description: formatMessage(
- 'To ensure a secure connection, the remote skill needs to know the Microsoft App ID of your bot. '
+ 'To ensure a secure connection, the remote skill needs to know the Microsoft App ID of your bot. ',
),
link: {
text: formatMessage('Select App ID and password'),
@@ -173,7 +173,7 @@ export const SetAppId: React.FC = (props) => {
if (publishTargets.length === 0) return '';
const { settings } = JSON.parse(
- publishTargets.find((target) => target.name === currentTargetName)?.configuration || '{}'
+ publishTargets.find((target) => target.name === currentTargetName)?.configuration || '{}',
);
return settings?.MicrosoftAppId || '';
}, [publishTargets, currentTargetName]);
@@ -201,7 +201,7 @@ export const SetAppId: React.FC = (props) => {
{renderMicrosoftAppId(
appId,
formatMessage('Your bot’s Microsoft App ID'),
- formatMessage('Microsoft App ID')
+ formatMessage('Microsoft App ID'),
)}
) : (
diff --git a/Composer/packages/client/src/components/AddRemoteSkillModal/helper.ts b/Composer/packages/client/src/components/AddRemoteSkillModal/helper.ts
index 61e49d1951..2bae8a7dc4 100644
--- a/Composer/packages/client/src/components/AddRemoteSkillModal/helper.ts
+++ b/Composer/packages/client/src/components/AddRemoteSkillModal/helper.ts
@@ -12,7 +12,7 @@ import TelemetryClient from '../../telemetry/TelemetryClient';
const conflictConfirmationTitle = formatMessage('Conflicting changes detected');
const conflictConfirmationPrompt = formatMessage(
- 'This operation will overwrite changes made to previously imported files. Do you want to proceed?'
+ 'This operation will overwrite changes made to previously imported files. Do you want to proceed?',
);
/**
@@ -24,7 +24,7 @@ export const importOrchestrator = async (
projectId: string,
runtime: DialogSetting['runtime'],
reloadProject,
- setApplicationLevelError
+ setApplicationLevelError,
) => {
const runtimeInfo = parseRuntimeKey(runtime?.key);
@@ -70,7 +70,7 @@ export const importOrchestrator = async (
TelemetryClient.track('PackageInstallFailed', { ...reqBody, isUpdate: reqBody.isUpdating });
setApplicationLevelError({
status: err.response.status,
- message: err.response && err.response.data.message ? err.response.data.message : err,
+ message: err.response?.data?.message ?? err,
summary: formatMessage('Install Error'),
});
}
diff --git a/Composer/packages/client/src/components/AppComponents/SideBar.tsx b/Composer/packages/client/src/components/AppComponents/SideBar.tsx
index 234af2704f..a590d16501 100644
--- a/Composer/packages/client/src/components/AppComponents/SideBar.tsx
+++ b/Composer/packages/client/src/components/AppComponents/SideBar.tsx
@@ -113,7 +113,11 @@ export const SideBar: React.FC = () => {
);
if (link.isDisabledForPVA) {
- return {navItem} ;
+ return (
+
+ {navItem}
+
+ );
}
return navItem;
})}
diff --git a/Composer/packages/client/src/components/AppUpdater/AppUpdater.tsx b/Composer/packages/client/src/components/AppUpdater/AppUpdater.tsx
index a89c886ac8..b6d6d47389 100644
--- a/Composer/packages/client/src/components/AppUpdater/AppUpdater.tsx
+++ b/Composer/packages/client/src/components/AppUpdater/AppUpdater.tsx
@@ -95,10 +95,9 @@ type BreakingUpdateMetaData = {
// -------------------- AppUpdater -------------------- //
-export const AppUpdater: React.FC<{}> = () => {
- const { setAppUpdateError, setAppUpdateProgress, setAppUpdateShowing, setAppUpdateStatus } = useRecoilValue(
- dispatcherState
- );
+export const AppUpdater: React.FC = () => {
+ const { setAppUpdateError, setAppUpdateProgress, setAppUpdateShowing, setAppUpdateStatus } =
+ useRecoilValue(dispatcherState);
const { downloadSizeInBytes, error, progressPercent, showing, status, version } = useRecoilValue(appUpdateState);
const [downloadOption, setDownloadOption] = useState(downloadOptions.installAndUpdate);
const [breakingMetaData, setBreakingMetaData] = useState(undefined);
@@ -189,7 +188,7 @@ export const AppUpdater: React.FC<{}> = () => {
default:
break;
}
- }
+ },
);
}, []);
diff --git a/Composer/packages/client/src/components/AppUpdater/breakingUpdates/version1To2.tsx b/Composer/packages/client/src/components/AppUpdater/breakingUpdates/version1To2.tsx
index babfb9db74..864a650138 100644
--- a/Composer/packages/client/src/components/AppUpdater/breakingUpdates/version1To2.tsx
+++ b/Composer/packages/client/src/components/AppUpdater/breakingUpdates/version1To2.tsx
@@ -88,7 +88,7 @@ export const Version1To2Content: React.FC = (props) => {
>
{formatMessage(
- 'Bot Framework Composer 2.0 provides more built-in capabilities so you can build complex bots quickly. Update to Composer 2.0 for advanced bot templates, prebuilt components, and a runtime that is fully extensible through packages.'
+ 'Bot Framework Composer 2.0 provides more built-in capabilities so you can build complex bots quickly. Update to Composer 2.0 for advanced bot templates, prebuilt components, and a runtime that is fully extensible through packages.',
)}
@@ -102,7 +102,7 @@ export const Version1To2Content: React.FC = (props) => {
{children}
),
- }
+ },
)}
@@ -131,7 +131,7 @@ export const Version1To2Content: React.FC
= (props) => {
{formatMessage.rich(
'Update cancelled. Auto-update has been turned off for this release. You can update at any time by selecting Help > Check for updates. ',
- { b: ({ children }) => {children} }
+ { b: ({ children }) => {children} },
)}
diff --git a/Composer/packages/client/src/components/Auth/AuthCard.tsx b/Composer/packages/client/src/components/Auth/AuthCard.tsx
index 27e948faaa..eb00e6e095 100644
--- a/Composer/packages/client/src/components/Auth/AuthCard.tsx
+++ b/Composer/packages/client/src/components/Auth/AuthCard.tsx
@@ -51,9 +51,8 @@ const styles = {
export const AuthCard: React.FC = () => {
const [authCardVisible, setAuthCardVisible] = useState
(false);
- const { refreshLoginStatus, requireUserLogin, logoutUser, setShowAuthDialog, setShowTenantDialog } = useRecoilValue(
- dispatcherState
- );
+ const { refreshLoginStatus, requireUserLogin, logoutUser, setShowAuthDialog, setShowTenantDialog } =
+ useRecoilValue(dispatcherState);
const isAuthenticated = useRecoilValue(isAuthenticatedState);
const currentUser = useRecoilValue(currentUserState);
const showAuthDialog = useRecoilValue(showAuthDialogState);
diff --git a/Composer/packages/client/src/components/Auth/AuthDialog.tsx b/Composer/packages/client/src/components/Auth/AuthDialog.tsx
index ab3fdf42ac..c9073a33e2 100644
--- a/Composer/packages/client/src/components/Auth/AuthDialog.tsx
+++ b/Composer/packages/client/src/components/Auth/AuthDialog.tsx
@@ -76,7 +76,7 @@ export const AuthDialog: React.FC = (props) => {
type: DialogType.close,
title: formatMessage('Provide access tokens'),
subText: formatMessage(
- 'To perform provisioning and publishing actions, Composer requires access to your Azure and MS Graph accounts. Paste access tokens from the az command line tool using the commands highlighted below.'
+ 'To perform provisioning and publishing actions, Composer requires access to your Azure and MS Graph accounts. Paste access tokens from the az command line tool using the commands highlighted below.',
),
styles: authDialogStyles.dialog,
}}
diff --git a/Composer/packages/client/src/components/Auth/TenantDialog.tsx b/Composer/packages/client/src/components/Auth/TenantDialog.tsx
index b99935e139..617206e256 100644
--- a/Composer/packages/client/src/components/Auth/TenantDialog.tsx
+++ b/Composer/packages/client/src/components/Auth/TenantDialog.tsx
@@ -56,7 +56,7 @@ export const TenantDialog: React.FC = (props) => {
}}
dialogType={DialogTypes.Customer}
subText={formatMessage(
- 'The directory you choose will impact subscription, resource group, and region filters that are available when you select or create Azure resources. You can change this later.'
+ 'The directory you choose will impact subscription, resource group, and region filters that are available when you select or create Azure resources. You can change this later.',
)}
title={formatMessage('Select directory')}
onDismiss={props.onDismiss}
diff --git a/Composer/packages/client/src/components/BotConvertDialog.tsx b/Composer/packages/client/src/components/BotConvertDialog.tsx
index 2d822e5a7d..6c8dd8d493 100644
--- a/Composer/packages/client/src/components/BotConvertDialog.tsx
+++ b/Composer/packages/client/src/components/BotConvertDialog.tsx
@@ -17,7 +17,7 @@ export const BotConvertConfirmDialog = (showSubContent: boolean) => {
{formatMessage(
- 'This project was created in an older version of Composer. To open this project in Composer 2.0, we must copy your project and convert it to the latest format. Your original project will not be changed.'
+ 'This project was created in an older version of Composer. To open this project in Composer 2.0, we must copy your project and convert it to the latest format. Your original project will not be changed.',
)}
{showSubContent && (
@@ -33,7 +33,7 @@ export const BotConvertConfirmDialog = (showSubContent: boolean) => {
{children}
),
- }
+ },
)}
)}
diff --git a/Composer/packages/client/src/components/BotRuntimeController/BotController.tsx b/Composer/packages/client/src/components/BotRuntimeController/BotController.tsx
index dae5d80d83..0a44ed9187 100644
--- a/Composer/packages/client/src/components/BotRuntimeController/BotController.tsx
+++ b/Composer/packages/client/src/components/BotRuntimeController/BotController.tsx
@@ -154,7 +154,7 @@ const BotController: React.FC
= ({ onHideController, isContr
setBotsProcessing(botsProcessing);
const botOperationsCompleted = projectCollection.some(
- ({ status }) => status === BotStatus.connected || status === BotStatus.failed
+ ({ status }) => status === BotStatus.connected || status === BotStatus.failed,
);
setBotsStartOperationCompleted(botOperationsCompleted);
@@ -169,8 +169,8 @@ const BotController: React.FC = ({ onHideController, isContr
=1 {Stopping bot..}
other {Stopping bots.. ({running}/{total} running)}
}`,
- { running: runningBots.projectIds.length, total: runningBots.totalBots }
- )
+ { running: runningBots.projectIds.length, total: runningBots.totalBots },
+ ),
);
} else {
setStartPanelButtonText(
@@ -180,8 +180,8 @@ const BotController: React.FC = ({ onHideController, isContr
=1 {Starting bot..}
other {Starting bots.. ({running}/{total} running)}
}`,
- { running: runningBots.projectIds.length, total: runningBots.totalBots }
- )
+ { running: runningBots.projectIds.length, total: runningBots.totalBots },
+ ),
);
}
return;
@@ -199,7 +199,7 @@ const BotController: React.FC = ({ onHideController, isContr
formatMessage(`{ total, plural, =1 {Restart bot}other {Restart all bots ({running}/{total} running)}}`, {
running: runningBots.projectIds.length,
total: runningBots.totalBots,
- })
+ }),
);
return;
}
@@ -213,8 +213,8 @@ const BotController: React.FC = ({ onHideController, isContr
=1 {Start bot}
other {Start all}
}`,
- { total: runningBots.totalBots }
- )
+ { total: runningBots.totalBots },
+ ),
);
}, [runningBots, startAllBotsOperationQueued]);
@@ -223,7 +223,7 @@ const BotController: React.FC = ({ onHideController, isContr
(event: React.MouseEvent) => {
onHideController(true);
event.stopPropagation();
- }
+ },
);
const handleClick = async () => {
@@ -266,7 +266,7 @@ const BotController: React.FC = ({ onHideController, isContr
diff --git a/Composer/packages/client/src/components/BotRuntimeController/BotRuntimeStatus.tsx b/Composer/packages/client/src/components/BotRuntimeController/BotRuntimeStatus.tsx
index d4b155d289..cf550e2fee 100644
--- a/Composer/packages/client/src/components/BotRuntimeController/BotRuntimeStatus.tsx
+++ b/Composer/packages/client/src/components/BotRuntimeController/BotRuntimeStatus.tsx
@@ -31,7 +31,7 @@ export const BotRuntimeStatus = React.memo((props: BotRuntimeStatusProps) => {
() => {
getPublishStatus(projectId, defaultPublishConfig);
},
- isRunning ? pollingInterval : null
+ isRunning ? pollingInterval : null,
);
useEffect(() => {
diff --git a/Composer/packages/client/src/components/BotRuntimeController/publishDialog.tsx b/Composer/packages/client/src/components/BotRuntimeController/publishDialog.tsx
index 371fdda47d..a4fbd64f70 100644
--- a/Composer/packages/client/src/components/BotRuntimeController/publishDialog.tsx
+++ b/Composer/packages/client/src/components/BotRuntimeController/publishDialog.tsx
@@ -152,7 +152,7 @@ const PublishDialog: React.FC = (props) => {
};
onPublish(publishConfig);
},
- [hasErrors, formData]
+ [hasErrors, formData],
);
const luisTitleRender = () => {
diff --git a/Composer/packages/client/src/components/BotRuntimeController/useBotOperations.ts b/Composer/packages/client/src/components/BotRuntimeController/useBotOperations.ts
index 916bc23dda..1c3a88d2ef 100644
--- a/Composer/packages/client/src/components/BotRuntimeController/useBotOperations.ts
+++ b/Composer/packages/client/src/components/BotRuntimeController/useBotOperations.ts
@@ -22,14 +22,14 @@ export function useBotOperations() {
projectId: string,
config: IPublishConfig,
sensitiveSettings,
- botBuildRequired: boolean
+ botBuildRequired: boolean,
) => {
resetBotRuntimeLog(projectId);
setBotStatus(projectId, BotStatus.pending);
if (botBuildRequired) {
// Default recognizer
const matchedBuilder = builderEssentials.find(
- ({ projectId: currentProjectId }) => projectId === currentProjectId
+ ({ projectId: currentProjectId }) => projectId === currentProjectId,
);
if (matchedBuilder?.dialogs) {
await botRuntimeOperations?.buildWithDefaultRecognizer(projectId, {
diff --git a/Composer/packages/client/src/components/BotRuntimeController/useStartedRuntimesTracker.ts b/Composer/packages/client/src/components/BotRuntimeController/useStartedRuntimesTracker.ts
index 2b341dfc08..8131e2bfd2 100644
--- a/Composer/packages/client/src/components/BotRuntimeController/useStartedRuntimesTracker.ts
+++ b/Composer/packages/client/src/components/BotRuntimeController/useStartedRuntimesTracker.ts
@@ -7,7 +7,7 @@ import { useRecoilValue } from 'recoil';
import { trackBotStatusesSelector } from '../../recoilModel';
export function useStartedRuntimesTracker(postTrackedBotsStartedAction: () => void, trackedProjectIds: string[]) {
- const savedCallback: MutableRefObject = useRef();
+ const savedCallback: MutableRefObject<(() => void) | undefined> = useRef();
const areBotsStarting = useRecoilValue(trackBotStatusesSelector(trackedProjectIds));
// Remember the latest callback.
diff --git a/Composer/packages/client/src/components/CellFocusZone.tsx b/Composer/packages/client/src/components/CellFocusZone.tsx
index 44b729ecde..1d4bc7c4d7 100644
--- a/Composer/packages/client/src/components/CellFocusZone.tsx
+++ b/Composer/packages/client/src/components/CellFocusZone.tsx
@@ -18,7 +18,7 @@ export const formCell = css`
export const formCellFocus = mergeStyles(
getFocusStyle(getTheme(), {
inset: -3,
- })
+ }),
);
/**
diff --git a/Composer/packages/client/src/components/CreationFlow/AzureBotDialog.tsx b/Composer/packages/client/src/components/CreationFlow/AzureBotDialog.tsx
index c51bfd11a3..74ae33f447 100644
--- a/Composer/packages/client/src/components/CreationFlow/AzureBotDialog.tsx
+++ b/Composer/packages/client/src/components/CreationFlow/AzureBotDialog.tsx
@@ -20,11 +20,11 @@ type Props = {
onDismiss: () => void;
onJumpToOpenModal: (search?: string) => void;
onToggleCreateModal: (boolean) => void;
-} & RouteComponentProps<{}>;
+} & RouteComponentProps;
const dialogWrapperProps = DialogCreationCopy.CREATE_OPTIONS;
-const dialogStyle: { dialog: Partial; modal: {} } = {
+const dialogStyle: { dialog: Partial; modal: unknown } = {
dialog: {
title: {
fontWeight: FontWeights.bold,
diff --git a/Composer/packages/client/src/components/CreationFlow/CreateBot.tsx b/Composer/packages/client/src/components/CreationFlow/CreateBot.tsx
index ef75c5f706..7398224d83 100644
--- a/Composer/packages/client/src/components/CreationFlow/CreateBot.tsx
+++ b/Composer/packages/client/src/components/CreationFlow/CreateBot.tsx
@@ -126,7 +126,7 @@ type CreateBotProps = {
onUpdateLocalTemplatePath: (path: string) => void;
onDismiss: () => void;
onNext: (templateName: string, templateLanguage: string, urlData?: string) => void;
- fetchReadMe: (moduleName: string) => {};
+ fetchReadMe: (moduleName: string) => any;
};
export function CreateBot(props: CreateBotProps) {
@@ -326,7 +326,7 @@ export function CreateBot(props: CreateBotProps) {
{children}
),
- }
+ },
)}
diff --git a/Composer/packages/client/src/components/CreationFlow/CreateOptions.tsx b/Composer/packages/client/src/components/CreationFlow/CreateOptions.tsx
index b1ea8851d4..7013bff688 100644
--- a/Composer/packages/client/src/components/CreationFlow/CreateOptions.tsx
+++ b/Composer/packages/client/src/components/CreationFlow/CreateOptions.tsx
@@ -27,21 +27,14 @@ type CreateOptionsProps = {
onDismiss: () => void;
onNext: (templateName: string, templateLanguage: string, urlData?: string) => void;
onJumpToOpenModal: (search?: string) => void;
- fetchReadMe: (moduleName: string) => {};
-} & RouteComponentProps<{}>;
+ fetchReadMe: (moduleName: string) => any;
+} & RouteComponentProps;
export function CreateOptions(props: CreateOptionsProps) {
const [isOpenOptionsModal, setIsOpenOptionsModal] = useState(true);
const [isOpenCreateModal, setIsOpenCreateModal] = useState(false);
- const {
- templates,
- onDismiss,
- onNext,
- onJumpToOpenModal,
- fetchReadMe,
- onUpdateLocalTemplatePath,
- localTemplatePath,
- } = props;
+ const { templates, onDismiss, onNext, onJumpToOpenModal, fetchReadMe, onUpdateLocalTemplatePath, localTemplatePath } =
+ props;
const [showNodeModal, setShowNodeModal] = useState(false);
const userHasNode = useRecoilValue(userHasNodeInstalledState);
const creationFlowType = useRecoilValue(creationFlowTypeState);
@@ -106,7 +99,7 @@ export function CreateOptions(props: CreateOptionsProps) {
downloadLink={'https://nodejs.org/en/download/'}
downloadLinkText={formatMessage('Install Node.js')}
text={formatMessage(
- 'Bot Framework Composer requires Node.js in order to create and run a new bot. Click “Install Node.js” to install the latest version. You will need to restart Composer after installing Node.'
+ 'Bot Framework Composer requires Node.js in order to create and run a new bot. Click “Install Node.js” to install the latest version. You will need to restart Composer after installing Node.',
)}
title={formatMessage('Node.js required')}
onDismiss={() => setShowNodeModal(false)}
diff --git a/Composer/packages/client/src/components/CreationFlow/CreationFlow.tsx b/Composer/packages/client/src/components/CreationFlow/CreationFlow.tsx
index aaa25065c2..bdc4ba7499 100644
--- a/Composer/packages/client/src/components/CreationFlow/CreationFlow.tsx
+++ b/Composer/packages/client/src/components/CreationFlow/CreationFlow.tsx
@@ -30,7 +30,7 @@ import { OpenProject } from './OpenProject';
import { CreateOptions } from './CreateOptions';
import DefineConversation from './DefineConversation';
-type CreationFlowProps = RouteComponentProps<{}>;
+type CreationFlowProps = RouteComponentProps;
const CreationFlow: React.FC = () => {
const {
@@ -130,7 +130,7 @@ const CreationFlow: React.FC = () => {
{ profile: formData.profile, source: formData.source, alias: formData.alias },
(projectId) => {
TelemetryClient.track('BotProjectOpened', { method: 'toolbar', projectId });
- }
+ },
);
};
@@ -178,7 +178,7 @@ const CreationFlow: React.FC = () => {
formData.description,
formData.location,
formData.runtimeLanguage,
- formData.runtimeType
+ formData.runtimeType,
);
};
diff --git a/Composer/packages/client/src/components/CreationFlow/DefineConversation.tsx b/Composer/packages/client/src/components/CreationFlow/DefineConversation.tsx
index f7e81db722..eb359772a9 100644
--- a/Composer/packages/client/src/components/CreationFlow/DefineConversation.tsx
+++ b/Composer/packages/client/src/components/CreationFlow/DefineConversation.tsx
@@ -150,7 +150,7 @@ const DefineConversation: React.FC = (props) => {
currentTemplate.name
.trim()
.replace(/bot|maker/gi, '')
- .replace(/-/g, ' ')
+ .replace(/-/g, ' '),
);
return upperFirst(camelCasedName);
} else if (templateId && inBotMigration) {
@@ -327,7 +327,7 @@ const DefineConversation: React.FC = (props) => {
dataToSubmit.isLocalGenerator = isLocalGenerator;
onSubmit({ ...dataToSubmit }, generatorName || '');
},
- [hasErrors, formData]
+ [hasErrors, formData],
);
const onCurrentPathUpdateWrap = (newPath: string, storageId?: string) => {
@@ -349,7 +349,7 @@ const DefineConversation: React.FC = (props) => {
text: formatMessage('Azure Web App'),
data: {
description: formatMessage(
- 'Fully managed compute platform that is optimized for hosting websites and web applications.'
+ 'Fully managed compute platform that is optimized for hosting websites and web applications.',
),
},
};
@@ -359,7 +359,7 @@ const DefineConversation: React.FC = (props) => {
text: formatMessage('Azure Functions'),
data: {
description: formatMessage(
- 'Azure Functions is a solution for easily running small pieces of code, or "functions," in the cloud. '
+ 'Azure Functions is a solution for easily running small pieces of code, or "functions," in the cloud. ',
),
},
};
@@ -446,7 +446,7 @@ const DefineConversation: React.FC = (props) => {
dropdownItemSelected: { height: 'auto' },
}}
tooltip={formatMessage(
- 'Azure offers a number of ways to host your application code. The runtime type refers to the hosting model for the computing resources that your application runs on.'
+ 'Azure offers a number of ways to host your application code. The runtime type refers to the hosting model for the computing resources that your application runs on.',
)}
onChange={(_e, option) => updateField('runtimeType', option?.key.toString())}
onRenderOption={renderRuntimeDropdownOption}
diff --git a/Composer/packages/client/src/components/CreationFlow/FileSelector.tsx b/Composer/packages/client/src/components/CreationFlow/FileSelector.tsx
index 6f58f25fa8..958b3a158f 100644
--- a/Composer/packages/client/src/components/CreationFlow/FileSelector.tsx
+++ b/Composer/packages/client/src/components/CreationFlow/FileSelector.tsx
@@ -501,8 +501,8 @@ export const FileSelector: React.FC = (props) => {
return pathError
? pathError
: operationMode.write && !focusedStorageFolder.writable
- ? formatMessage('You do not have permission to save bots here')
- : '';
+ ? formatMessage('You do not have permission to save bots here')
+ : '';
};
return (
diff --git a/Composer/packages/client/src/components/CreationFlow/OpenProject.tsx b/Composer/packages/client/src/components/CreationFlow/OpenProject.tsx
index 4d83809e3f..8373be06b0 100644
--- a/Composer/packages/client/src/components/CreationFlow/OpenProject.tsx
+++ b/Composer/packages/client/src/components/CreationFlow/OpenProject.tsx
@@ -26,7 +26,7 @@ interface OpenProjectFormData {
alias?: string; // identifier that is used to track bots between imports
}
-interface OpenProjectProps extends RouteComponentProps<{}> {
+interface OpenProjectProps extends RouteComponentProps {
focusedStorageFolder: StorageFolder;
onOpen: (formData: OpenProjectFormData) => void;
onCurrentPathUpdate: (newPath?: string, storageId?: string) => void;
diff --git a/Composer/packages/client/src/components/CreationFlow/TemplateDetailView.tsx b/Composer/packages/client/src/components/CreationFlow/TemplateDetailView.tsx
index d1329011aa..2ff6f30acc 100644
--- a/Composer/packages/client/src/components/CreationFlow/TemplateDetailView.tsx
+++ b/Composer/packages/client/src/components/CreationFlow/TemplateDetailView.tsx
@@ -122,7 +122,7 @@ export const TemplateDetailView: React.FC = (props) =>
// result is a dir path
onValidateLocalTemplatePath(false);
return formatMessage(
- "Generator not found. Please enter the full path to the generator's index.js file including the filename"
+ "Generator not found. Please enter the full path to the generator's index.js file including the filename",
);
};
@@ -143,7 +143,7 @@ export const TemplateDetailView: React.FC = (props) =>
{children}
),
- }
+ },
)}
{
>
{formatMessage(
- 'Composer includes a telemetry feature that collects usage information. It is important that the Composer team understands how the tool is being used so that it can be improved.'
+ 'Composer includes a telemetry feature that collects usage information. It is important that the Composer team understands how the tool is being used so that it can be improved.',
)}
{formatMessage('You can turn data collection on or off at any time in the Application Settings.')}
diff --git a/Composer/packages/client/src/components/EditableField.tsx b/Composer/packages/client/src/components/EditableField.tsx
index a40e9ae2e0..bfe2777412 100644
--- a/Composer/packages/client/src/components/EditableField.tsx
+++ b/Composer/packages/client/src/components/EditableField.tsx
@@ -26,8 +26,8 @@ const defaultContainerStyle = (hasFocus, hasErrors) => css`
outline: ${hasErrors
? `2px solid ${SharedColors.red10}`
: hasFocus
- ? `2px solid ${SharedColors.cyanBlue10}`
- : undefined};
+ ? `2px solid ${SharedColors.cyanBlue10}`
+ : undefined};
}
:hover .ms-Button-icon,
:focus-within .ms-Button-icon {
@@ -286,7 +286,7 @@ const EditableField: React.FC = (props) => {
},
},
},
- styles
+ styles,
) as Partial
}
value={
@@ -317,7 +317,7 @@ const EditableField: React.FC = (props) => {
visibility: 'hidden',
},
},
- iconProps?.iconStyles
+ iconProps?.iconStyles,
),
}}
styles={{
diff --git a/Composer/packages/client/src/components/GetStarted/GetStartedNextSteps.tsx b/Composer/packages/client/src/components/GetStarted/GetStartedNextSteps.tsx
index 3755e8fc61..14bef845c9 100644
--- a/Composer/packages/client/src/components/GetStarted/GetStartedNextSteps.tsx
+++ b/Composer/packages/client/src/components/GetStarted/GetStartedNextSteps.tsx
@@ -160,7 +160,7 @@ export const GetStartedNextSteps: React.FC = (props) => {
key: 'luis',
label: formatMessage('Set up Language Understanding'),
description: formatMessage(
- 'Use machine learning to understand natural language input and direct the conversation flow.'
+ 'Use machine learning to understand natural language input and direct the conversation flow.',
),
learnMore: 'https://aka.ms/composer-luis-learnmore',
required: true,
@@ -183,7 +183,7 @@ export const GetStartedNextSteps: React.FC = (props) => {
key: 'qna',
label: formatMessage('Set up QnA Maker'),
description: formatMessage(
- 'Use Azure QnA Maker to create a simple question-and-answer bot from a website FAQ.'
+ 'Use Azure QnA Maker to create a simple question-and-answer bot from a website FAQ.',
),
learnMore: 'https://aka.ms/composer-addqnamaker-learnmore',
required: true,
@@ -227,7 +227,7 @@ export const GetStartedNextSteps: React.FC = (props) => {
key: 'publishing',
label: formatMessage('Create a publishing profile'),
description: formatMessage(
- 'A publishing profile provides the secure connectivity required to publish your bot.'
+ 'A publishing profile provides the secure connectivity required to publish your bot.',
),
checked: hasPublishingProfile,
learnMore: 'https://aka.ms/composer-getstarted-publishingprofile',
@@ -243,7 +243,7 @@ export const GetStartedNextSteps: React.FC = (props) => {
key: 'partialProfile',
label: formatMessage('Complete your publishing profile'),
description: formatMessage(
- 'Finish setting up your environment and provisioning resources so that you can publish your bot.'
+ 'Finish setting up your environment and provisioning resources so that you can publish your bot.',
),
checked: hasPublishingProfile && !hasPartialPublishingProfile,
learnMore: 'https://aka.ms/composer-getstarted-publishingprofile',
@@ -259,7 +259,7 @@ export const GetStartedNextSteps: React.FC = (props) => {
key: 'editlg',
label: formatMessage('Edit bot responses'),
description: formatMessage(
- "Define your bot's responses, add phrase variations, execute simple expressions based on context, or refer to conversational memory."
+ "Define your bot's responses, add phrase variations, execute simple expressions based on context, or refer to conversational memory.",
),
learnMore: 'https://aka.ms/composer-getstarted-editbotsays',
checked: false,
@@ -313,7 +313,7 @@ export const GetStartedNextSteps: React.FC = (props) => {
key: 'devops',
label: formatMessage('Set up continuous deployment (DevOps)'),
description: formatMessage(
- 'Build a continuous integration and deployment (CI/CD) pipeline with Azure Resource Manager templates.'
+ 'Build a continuous integration and deployment (CI/CD) pipeline with Azure Resource Manager templates.',
),
learnMore: 'https://aka.ms/bfcomposercicd',
checked: false,
diff --git a/Composer/packages/client/src/components/GetStarted/GetStartedTask.tsx b/Composer/packages/client/src/components/GetStarted/GetStartedTask.tsx
index 81aebfd54a..c00a7b9f86 100644
--- a/Composer/packages/client/src/components/GetStarted/GetStartedTask.tsx
+++ b/Composer/packages/client/src/components/GetStarted/GetStartedTask.tsx
@@ -35,8 +35,8 @@ export const GetStartedTask: React.FC = (props) => {
const color = props.step.checked
? FluentTheme.palette.green
: props.step.required
- ? SharedColors.orange20
- : SharedColors.cyanBlue10;
+ ? SharedColors.orange20
+ : SharedColors.cyanBlue10;
return (
{
onDismiss={hideTeachingBubble}
>
{formatMessage(
- 'Click start and your bot will be up and running. Once it’s running, you can select “Open in WebChat” to test.'
+ 'Click start and your bot will be up and running. Once it’s running, you can select “Open in WebChat” to test.',
)}
)}
@@ -395,7 +395,7 @@ export const Header = () => {
{formatMessage('Active language')}
{formatMessage(
- 'This is the bot language you are currently authoring. Change the active language in the dropdown below.'
+ 'This is the bot language you are currently authoring. Change the active language in the dropdown below.',
)}
diff --git a/Composer/packages/client/src/components/ImportModal/ImportModal.tsx b/Composer/packages/client/src/components/ImportModal/ImportModal.tsx
index 6f0f130af2..dd78842719 100644
--- a/Composer/packages/client/src/components/ImportModal/ImportModal.tsx
+++ b/Composer/packages/client/src/components/ImportModal/ImportModal.tsx
@@ -53,11 +53,11 @@ const CONNECTING_STATUS_DISPLAY_TIME = 2000;
export const signIn = async (
importSource: ExternalContentProviderType | undefined,
importPayload: ImportPayload,
- setModalState
+ setModalState,
) => {
try {
await axios.post(
- `/api/import/${importSource}/authenticate?payload=${encodeURIComponent(JSON.stringify(importPayload))}`
+ `/api/import/${importSource}/authenticate?payload=${encodeURIComponent(JSON.stringify(importPayload))}`,
);
setModalState('downloadingContent');
} catch (e) {
@@ -119,7 +119,7 @@ export const ImportModal: React.FC = (props) => {
res = await axios.post(
`/api/projects/${existingProject.id}/copyTemplateToExisting`,
{ eTag, templateDir },
- { headers: { 'Content-Type': 'application/json' } }
+ { headers: { 'Content-Type': 'application/json' } },
);
// open project and create a notification saying that import was complete
@@ -154,7 +154,7 @@ export const ImportModal: React.FC = (props) => {
const { description, name } = importPayload;
const res = await axios.post<{ alias: string; eTag: string; templateDir: string; urlSuffix: string }>(
- `/api/import/${importSource}?payload=${encodeURIComponent(JSON.stringify(importPayload))}`
+ `/api/import/${importSource}?payload=${encodeURIComponent(JSON.stringify(importPayload))}`,
);
const { alias, eTag, templateDir, urlSuffix } = res.data;
const projectInfo = {
diff --git a/Composer/packages/client/src/components/ManageLuis/ManageLuis.tsx b/Composer/packages/client/src/components/ManageLuis/ManageLuis.tsx
index 5c91167374..2a62194e65 100644
--- a/Composer/packages/client/src/components/ManageLuis/ManageLuis.tsx
+++ b/Composer/packages/client/src/components/ManageLuis/ManageLuis.tsx
@@ -24,7 +24,7 @@ export const ManageLuis = (props: ManageLuisProps) => {
subscriptionId: string,
resourceGroupName: string,
resourceName: string,
- region: string
+ region: string,
): Promise => {
const cognitiveServicesManagementClient = new CognitiveServicesManagementClient(tokenCredentials, subscriptionId);
await cognitiveServicesManagementClient.accounts.create(resourceGroupName, `${resourceName}-authoring`, {
@@ -37,7 +37,7 @@ export const ManageLuis = (props: ManageLuisProps) => {
const keys = await cognitiveServicesManagementClient.accounts.listKeys(
resourceGroupName,
- `${resourceName}-authoring`
+ `${resourceName}-authoring`,
);
if (!keys?.key1) {
throw new Error('No key found for newly created authoring resource');
@@ -50,11 +50,11 @@ export const ManageLuis = (props: ManageLuisProps) => {
{
resourceGroupName: string,
resourceName: string,
region: string,
- tier?: string
+ tier?: string,
): Promise => {
// hide modal
props.onToggleVisibility(false);
@@ -50,7 +50,7 @@ export const ManageQNA = (props: ManageQNAProps) => {
resourceGroupName,
resourceName,
region,
- tier || 'free'
+ tier || 'free',
);
return '';
};
@@ -60,7 +60,7 @@ export const ManageQNA = (props: ManageQNAProps) => {
createServiceInBackground
createService={createService}
handoffInstructions={formatMessage(
- '1. Using the Azure portal, please create a QnAMaker resource on my behalf.\n2. Once provisioned, securely share the resulting credentials with me as described in the link below.\n\nDetailed instructions:\nhttps://aka.ms/bfcomposerhandoffqnamaker'
+ '1. Using the Azure portal, please create a QnAMaker resource on my behalf.\n2. Once provisioned, securely share the resulting credentials with me as described in the link below.\n\nDetailed instructions:\nhttps://aka.ms/bfcomposerhandoffqnamaker',
)}
hidden={props.hidden}
introText={formatMessage('Use Azure QnA Maker to create a simple question-and-answer bot from a website FAQ. ')}
diff --git a/Composer/packages/client/src/components/ManageService/ManageService.tsx b/Composer/packages/client/src/components/ManageService/ManageService.tsx
index 6cbc970861..91b0141b5b 100644
--- a/Composer/packages/client/src/components/ManageService/ManageService.tsx
+++ b/Composer/packages/client/src/components/ManageService/ManageService.tsx
@@ -33,7 +33,7 @@ type ManageServiceProps = {
resourceGroupName: string,
resourceName: string,
region: string,
- tier?: string
+ tier?: string,
) => Promise;
createServiceInBackground?: boolean;
handoffInstructions: string;
@@ -115,7 +115,7 @@ export const ManageService: React.FC = (props: ManageService
setLocationList(
locations.map((location) => {
return { key: location.name || '', text: location.displayName || '' };
- })
+ }),
);
}
};
@@ -144,8 +144,8 @@ export const ManageService: React.FC = (props: ManageService
if (data.length === 0) {
setSubscriptionsErrorMessage(
formatMessage(
- 'Your subscription list is empty, please add your subscription, or login with another account.'
- )
+ 'Your subscription list is empty, please add your subscription, or login with another account.',
+ ),
);
}
})
@@ -212,7 +212,7 @@ export const ManageService: React.FC = (props: ManageService
const keylist: KeyRec[] = await fetchKeys(
cognitiveServicesManagementClient,
- accounts.filter((a) => a.kind === props.serviceKeyType)
+ accounts.filter((a) => a.kind === props.serviceKeyType),
);
setLoading(undefined);
if (keylist.length == 0) {
@@ -258,8 +258,8 @@ export const ManageService: React.FC = (props: ManageService
setOutcomeDescription(
formatMessage(
'Due to the following error, we were unable to successfully add your selected {service} keys to your bot project:',
- { service: props.serviceName }
- )
+ { service: props.serviceName },
+ ),
);
setOutcomeSummary({err.message}
);
setOutcomeError(true);
@@ -286,7 +286,7 @@ export const ManageService: React.FC = (props: ManageService
resourceGroupName,
resourceName,
region,
- tier
+ tier,
);
TelemetryClient.track('SettingsGetKeysCreateNewResourceCompleted', {
@@ -308,8 +308,8 @@ export const ManageService: React.FC = (props: ManageService
setOutcomeDescription(
formatMessage(
'Due to the following error, we were unable to successfully add your selected {service} keys to your bot project:',
- { service: props.serviceName }
- )
+ { service: props.serviceName },
+ ),
);
setOutcomeSummary({err.message}
);
setOutcomeError(true);
@@ -323,7 +323,7 @@ export const ManageService: React.FC = (props: ManageService
setOutcomeDescription(
formatMessage('The following {service} resource was successfully created and added to your bot project:', {
service: props.serviceName,
- })
+ }),
);
setOutcomeSummary(
@@ -343,7 +343,7 @@ export const ManageService: React.FC = (props: ManageService
{formatMessage('Resource name')}
{resourceName}
-
+ ,
);
setOutcomeError(false);
@@ -399,7 +399,7 @@ export const ManageService: React.FC = (props: ManageService
setOutcomeDescription(
formatMessage('The following {service} keys have been successfully added to your bot project:', {
service: props.serviceName,
- })
+ }),
);
setOutcomeSummary(
@@ -411,7 +411,7 @@ export const ManageService: React.FC = (props: ManageService
{formatMessage('Region')}
{region}
-
+ ,
);
setOutcomeError(false);
@@ -436,7 +436,7 @@ export const ManageService: React.FC = (props: ManageService
const onRenderOption = (option) => {
return (
- {option.data && option.data.icon && (
+ {option.data?.icon && (
)}
{option.text}
@@ -519,7 +519,7 @@ export const ManageService: React.FC
= (props: ManageService
'No existing {service} resources were found in this subscription. Select a different subscription, or click “Back” to create a new resource or generate a resource request to handoff to your Azure admin.',
{
service: props.serviceName,
- }
+ },
)}
)}
@@ -777,11 +777,11 @@ export const ManageService: React.FC = (props: ManageService
{
subscriptionId: string,
resourceGroupName: string,
resourceName: string,
- region: string
+ region: string,
): Promise => {
const cognitiveServicesManagementClient = new CognitiveServicesManagementClient(tokenCredentials, subscriptionId);
await cognitiveServicesManagementClient.accounts.create(resourceGroupName, resourceName, {
@@ -46,7 +46,7 @@ export const ManageSpeech = (props: ManageSpeechProps) => {
= (props) => {
const onDefaultLanguageChange = (
_event: React.FormEvent,
option?: IDropdownOption,
- _index?: number
+ _index?: number,
) => {
const selectedLang = option?.key as string;
if (selectedLang && selectedLang !== formData.defaultLang) {
@@ -91,7 +91,7 @@ const AddLanguageModal: React.FC = (props) => {
setFormData(initialFormData);
props.onSubmit(formData);
},
- [formData]
+ [formData],
);
const onDismiss = (e) => {
@@ -183,7 +183,7 @@ const AddLanguageModal: React.FC = (props) => {
other {# languages found}
}
`,
- { searchKeywords, hasFilter: !!searchKeywords, languagesCount: languageCheckBoxList.length }
+ { searchKeywords, hasFilter: !!searchKeywords, languagesCount: languageCheckBoxList.length },
)}
/>
= (props) => {
=1 {One language selected}
other {# languages selected}
}`,
- { languagesCount: formData.languages.length }
+ { languagesCount: formData.languages.length },
)}
/>
diff --git a/Composer/packages/client/src/components/MultiLanguage/DeleteLanguageModal.tsx b/Composer/packages/client/src/components/MultiLanguage/DeleteLanguageModal.tsx
index 4846d5e7c3..abf8e8fc89 100644
--- a/Composer/packages/client/src/components/MultiLanguage/DeleteLanguageModal.tsx
+++ b/Composer/packages/client/src/components/MultiLanguage/DeleteLanguageModal.tsx
@@ -55,7 +55,7 @@ const DeleteLanguageModal: React.FC
= (props) => {
props.onSubmit(formData);
setFormData(initialFormData);
},
- [formData]
+ [formData],
);
const onDismiss = useCallback((e) => {
diff --git a/Composer/packages/client/src/components/MultiLanguage/utils.ts b/Composer/packages/client/src/components/MultiLanguage/utils.ts
index 50d6baaa59..499fce5646 100644
--- a/Composer/packages/client/src/components/MultiLanguage/utils.ts
+++ b/Composer/packages/client/src/components/MultiLanguage/utils.ts
@@ -15,7 +15,7 @@ export type LanguageTemplate = {
export const languageListTemplatesSorted = (
languages: string[],
locale: string,
- defaultLanguage: string
+ defaultLanguage: string,
): LanguageTemplate[] => {
const defaultLanguageTemplate =
Locales.find((lang) => lang.locale === defaultLanguage) || Locales.find((lang) => lang.locale === 'en-us');
@@ -41,7 +41,7 @@ export const languageListTemplatesSorted = (
export const languageListTemplates = (
languages: string[],
locale: string,
- defaultLanguage: string
+ defaultLanguage: string,
): LanguageTemplate[] => {
const languageList = Locales.map((lang) => {
const isEnabled = languages.includes(lang.locale);
diff --git a/Composer/packages/client/src/components/NavItem.tsx b/Composer/packages/client/src/components/NavItem.tsx
index 8dd384a561..e5f2a45ad6 100644
--- a/Composer/packages/client/src/components/NavItem.tsx
+++ b/Composer/packages/client/src/components/NavItem.tsx
@@ -68,7 +68,7 @@ const icon = (active: boolean, disabled: boolean) =>
fontSize: `${FontSizes.size16}`,
width: '40px',
},
- } as IButtonStyles);
+ }) as IButtonStyles;
// -------------------- NavItem -------------------- //
@@ -99,9 +99,10 @@ export const NavItem: React.FC = (props) => {
const active = (pathname.startsWith(to) || match?.test(pathname)) ?? false;
- const addRef = useCallback((ref) => onboardingAddCoachMarkRef({ [`nav${labelName.replace(' ', '')}`]: ref }), [
- labelName,
- ]);
+ const addRef = useCallback(
+ (ref) => onboardingAddCoachMarkRef({ [`nav${labelName.replace(' ', '')}`]: ref }),
+ [labelName],
+ );
const getIcon = (iconName: string) => {
let navIcon;
diff --git a/Composer/packages/client/src/components/NavTree.tsx b/Composer/packages/client/src/components/NavTree.tsx
index 34a09eacc5..250a0218ea 100644
--- a/Composer/packages/client/src/components/NavTree.tsx
+++ b/Composer/packages/client/src/components/NavTree.tsx
@@ -89,33 +89,33 @@ interface INavTreeProps {
const NavTree: React.FC = (props) => {
const { navLinks, regionName } = props;
- const onRenderOverflowButton = (isSelected: boolean, item) => (
- menuItems: IOverflowSetItemProps[] | undefined
- ): JSX.Element => {
- const buttonStyles: Partial = {
- root: {
- minWidth: 0,
- padding: '0 4px',
- alignSelf: 'stretch',
- height: 'auto',
- background: isSelected ? NeutralColors.gray20 : NeutralColors.white,
- selectors: {
- '.ms-Icon': {
- visibility: isSelected ? 'inherit' : 'hidden',
+ const onRenderOverflowButton =
+ (isSelected: boolean, item) =>
+ (menuItems: IOverflowSetItemProps[] | undefined): JSX.Element => {
+ const buttonStyles: Partial = {
+ root: {
+ minWidth: 0,
+ padding: '0 4px',
+ alignSelf: 'stretch',
+ height: 'auto',
+ background: isSelected ? NeutralColors.gray20 : NeutralColors.white,
+ selectors: {
+ '.ms-Icon': {
+ visibility: isSelected ? 'inherit' : 'hidden',
+ },
},
},
- },
+ };
+ return (
+
+ );
};
- return (
-
- );
- };
return (
diff --git a/Composer/packages/client/src/components/Notifications/NotificationCard.tsx b/Composer/packages/client/src/components/Notifications/NotificationCard.tsx
index 21da6a2685..e0c6b752de 100644
--- a/Composer/packages/client/src/components/Notifications/NotificationCard.tsx
+++ b/Composer/packages/client/src/components/Notifications/NotificationCard.tsx
@@ -36,7 +36,9 @@ const cardContainer = (show: boolean, ref?: HTMLDivElement | null) => () => {
return css`
border-left: 4px solid #0078d4;
background: white;
- box-shadow: 0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132), 0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108);
+ box-shadow:
+ 0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132),
+ 0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108);
width: 340px;
border-radius: 2px;
display: flex;
@@ -206,7 +208,7 @@ const defaultCardContentRenderer = (props: CardProps) => {
{rightLinkList.map(
- (link) => link != null && {makeLinkLabel(link)}
+ (link) => link != null && {makeLinkLabel(link)} ,
)}
diff --git a/Composer/packages/client/src/components/Notifications/NotificationPanel.tsx b/Composer/packages/client/src/components/Notifications/NotificationPanel.tsx
index 62cc96693d..81868b8069 100644
--- a/Composer/packages/client/src/components/Notifications/NotificationPanel.tsx
+++ b/Composer/packages/client/src/components/Notifications/NotificationPanel.tsx
@@ -60,7 +60,7 @@ const NotificationPanel: React.FC = ({
{defaultRender?.(props)}
),
- [handleClearAll]
+ [handleClearAll],
);
return (
diff --git a/Composer/packages/client/src/components/Notifications/__tests__/NotificationCard.test.tsx b/Composer/packages/client/src/components/Notifications/__tests__/NotificationCard.test.tsx
index fba50e85cd..a3520d90d6 100644
--- a/Composer/packages/client/src/components/Notifications/__tests__/NotificationCard.test.tsx
+++ b/Composer/packages/client/src/components/Notifications/__tests__/NotificationCard.test.tsx
@@ -26,7 +26,7 @@ describe(' ', () => {
const onDismiss = jest.fn();
const handleHide = jest.fn();
const { container } = renderWithRecoil(
-
+ ,
);
expect(container).toHaveTextContent('There was error creating your knowledge base');
@@ -43,7 +43,7 @@ describe(' ', () => {
const onDismiss = jest.fn();
const handleHide = jest.fn();
const { container } = renderWithRecoil(
-
+ ,
);
expect(container).toHaveTextContent('customized');
diff --git a/Composer/packages/client/src/components/Notifications/__tests__/NotificationPanel.test.tsx b/Composer/packages/client/src/components/Notifications/__tests__/NotificationPanel.test.tsx
index 4887682861..c7a55b610e 100644
--- a/Composer/packages/client/src/components/Notifications/__tests__/NotificationPanel.test.tsx
+++ b/Composer/packages/client/src/components/Notifications/__tests__/NotificationPanel.test.tsx
@@ -32,7 +32,7 @@ describe(' ', () => {
notifications={notifications as Notification[]}
onDeleteNotification={jest.fn()}
onDismiss={jest.fn()}
- />
+ />,
);
const notificationCards = await findAllByTestId('NotificationCard');
expect(notificationCards.length).toBe(4);
@@ -46,7 +46,7 @@ describe(' ', () => {
notifications={notifications as Notification[]}
onDeleteNotification={deleteNotification}
onDismiss={jest.fn}
- />
+ />,
);
const clearAll = await findByTestId('ClearAll');
diff --git a/Composer/packages/client/src/components/Orchestrator/__tests__/OrchestratorForSkillsDialog.test.tsx b/Composer/packages/client/src/components/Orchestrator/__tests__/OrchestratorForSkillsDialog.test.tsx
index d24c4472d3..c1633e467a 100644
--- a/Composer/packages/client/src/components/Orchestrator/__tests__/OrchestratorForSkillsDialog.test.tsx
+++ b/Composer/packages/client/src/components/Orchestrator/__tests__/OrchestratorForSkillsDialog.test.tsx
@@ -142,7 +142,7 @@ describe(' ', () => {
'rootBotId',
{ key: 'adaptive-runtime-dotnet-webapp' },
expect.anything(),
- expect.anything()
+ expect.anything(),
);
});
@@ -183,7 +183,7 @@ describe(' ', () => {
command: expect.anything(),
},
expect.anything(),
- expect.anything()
+ expect.anything(),
);
});
diff --git a/Composer/packages/client/src/components/Page.tsx b/Composer/packages/client/src/components/Page.tsx
index 0b497269d8..09276b36aa 100644
--- a/Composer/packages/client/src/components/Page.tsx
+++ b/Composer/packages/client/src/components/Page.tsx
@@ -172,7 +172,7 @@ const Page: React.FC = (props) => {
};
})
.filter((item) => Boolean(item)) as IToolbarItem[],
- []
+ [],
);
const displayedToolbarItems = toolbarItems.concat(debugItems);
diff --git a/Composer/packages/client/src/components/PluginHost/PluginHost.tsx b/Composer/packages/client/src/components/PluginHost/PluginHost.tsx
index 8b71ed4361..7ffed162b2 100644
--- a/Composer/packages/client/src/components/PluginHost/PluginHost.tsx
+++ b/Composer/packages/client/src/components/PluginHost/PluginHost.tsx
@@ -50,7 +50,7 @@ async function attachPluginAPI(
bundleId: string,
type: PluginType,
shell?: object,
- settings?: ExtensionSettings
+ settings?: ExtensionSettings,
) {
const api = { ...PluginAPI[type], ...PluginAPI.auth };
diff --git a/Composer/packages/client/src/components/ProjectTree/ExpandableNode.tsx b/Composer/packages/client/src/components/ProjectTree/ExpandableNode.tsx
index 74210e9509..15127bbb4c 100644
--- a/Composer/packages/client/src/components/ProjectTree/ExpandableNode.tsx
+++ b/Composer/packages/client/src/components/ProjectTree/ExpandableNode.tsx
@@ -25,8 +25,8 @@ const listItemStyle = (isActive: boolean, isOpen: boolean, hasChildren: boolean)
${!hasChildren
? 'list-style: none'
: isOpen
- ? `list-style-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='16' width='16' viewBox='0 0 24 16'%3E%3Cpath style='fill:black%3B' d='M 8 8 h 16 l -8 8 l -8 -8'/%3E%3C/svg%3E");`
- : `list-style-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='16' width='16' viewBox='0 0 24 16'%3E%3Cpath style='fill:black%3B' d='M 16 0 v 16 l 8 -8 l -8 -8'/%3E%3C/svg%3E");`}
+ ? `list-style-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='16' width='16' viewBox='0 0 24 16'%3E%3Cpath style='fill:black%3B' d='M 8 8 h 16 l -8 8 l -8 -8'/%3E%3C/svg%3E");`
+ : `list-style-image: url("data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8' standalone='no'%3F%3E%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' height='16' width='16' viewBox='0 0 24 16'%3E%3Cpath style='fill:black%3B' d='M 16 0 v 16 l 8 -8 l -8 -8'/%3E%3C/svg%3E");`}
`;
const listStyle = css`
diff --git a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx
index f25fec824c..33a0027b2f 100644
--- a/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx
+++ b/Composer/packages/client/src/components/ProjectTree/ProjectTree.tsx
@@ -143,12 +143,8 @@ export const ProjectTree: React.FC = ({
headerAriaLabel = '',
headerPlaceholder = '',
}) => {
- const {
- onboardingAddCoachMarkRef,
- navigateToFormDialogSchema,
- setPageElementState,
- createQnADialogBegin,
- } = useRecoilValue(dispatcherState);
+ const { onboardingAddCoachMarkRef, navigateToFormDialogSchema, setPageElementState, createQnADialogBegin } =
+ useRecoilValue(dispatcherState);
const treeRef = useRef(null);
const pageElements = useRecoilValue(pageElementState).dialogs;
@@ -332,7 +328,7 @@ export const ProjectTree: React.FC = ({
},
dialog: DialogInfo,
projectId: string,
- dialogLink: TreeLink
+ dialogLink: TreeLink,
): React.ReactNode => {
const link: TreeLink = {
projectId: rootProjectId,
@@ -394,13 +390,13 @@ export const ProjectTree: React.FC = ({
const index = getTriggerIndex(tr, dialog);
const warningContent = triggerNotSupported(dialog, tr);
const errorContent = notificationMap[projectId][dialog.id].some(
- (diag) => diag.severity === DiagnosticSeverity.Error && diag.path?.match(RegExp(`triggers\\[${index}\\]`))
+ (diag) => diag.severity === DiagnosticSeverity.Error && diag.path?.match(RegExp(`triggers\\[${index}\\]`)),
);
return renderTrigger(
{ ...tr, index, displayName: getTriggerName(tr), warningContent, errorContent },
dialog,
projectId,
- dialogLink
+ dialogLink,
);
});
};
@@ -436,7 +432,7 @@ export const ProjectTree: React.FC = ({
dialog: DialogInfo,
groupName: string,
triggers: ITrigger[],
- startDepth: number
+ startDepth: number,
) => {
const groupDisplayName =
groupName === NoGroupingTriggerGroupName ? formatMessage('form-wide operations') : groupName;
@@ -625,7 +621,8 @@ export const ProjectTree: React.FC = ({
? dialogs
: dialogs.filter(
(dialog) =>
- filterMatch(dialog.displayName) || dialog.triggers.some((trigger) => filterMatch(getTriggerName(trigger)))
+ filterMatch(dialog.displayName) ||
+ dialog.triggers.some((trigger) => filterMatch(getTriggerName(trigger))),
);
// eventually we will filter on topic trigger phrases
const filteredTopics =
@@ -809,7 +806,7 @@ export const ProjectTree: React.FC = ({
0 {}
other {Press down arrow key to navigate the search results}
}`,
- { dialogNum: projectCollection.length, filter: filter, hasFilter: !!filter }
+ { dialogNum: projectCollection.length, filter: filter, hasFilter: !!filter },
)}
/>
{projectTree}
diff --git a/Composer/packages/client/src/components/ProjectTree/treeItem.tsx b/Composer/packages/client/src/components/ProjectTree/treeItem.tsx
index 4ff65867ae..53c1670619 100644
--- a/Composer/packages/client/src/components/ProjectTree/treeItem.tsx
+++ b/Composer/packages/client/src/components/ProjectTree/treeItem.tsx
@@ -97,7 +97,7 @@ const navContainer = (
isActive: boolean,
menuOpenHere: boolean,
textWidth: number,
- isBroken: boolean
+ isBroken: boolean,
) => css`
${isAnyMenuOpen
? ''
@@ -174,7 +174,7 @@ export const overflowSet = (isBroken: boolean) => css`
const moreButtonContainer = {
root: {
lineHeight: '1',
- display: 'flex' as 'flex',
+ display: 'flex' as const,
},
};
@@ -198,7 +198,7 @@ const diagnosticIcon = {
height: '20px',
fontSize: '12px',
lineHeight: '20px',
- textAlign: 'center' as 'center',
+ textAlign: 'center' as const,
};
const diagnosticErrorIcon = {
@@ -373,7 +373,7 @@ const DiagnosticIcons = (props: {
{errors.map((item) => {
let linkText = item.source;
if (item.source === 'appsettings.json') {
- linkText = 'Fix in bot settings';
+ linkText = 'Fix in Configure your bot';
}
return (
@@ -449,10 +449,10 @@ export const TreeItem: React.FC = ({
let errorContent = '';
if (showErrors) {
const warnings: Diagnostic[] = diagnostics.filter(
- (diag: Diagnostic) => diag.severity === DiagnosticSeverity.Warning
+ (diag: Diagnostic) => diag.severity === DiagnosticSeverity.Warning,
);
const errors: Diagnostic[] = diagnostics.filter(
- (diag: Diagnostic) => diag.severity === DiagnosticSeverity.Error
+ (diag: Diagnostic) => diag.severity === DiagnosticSeverity.Error,
);
warningContent = warnings.map((diag) => diag.message).join(',');
@@ -517,7 +517,7 @@ export const TreeItem: React.FC = ({
);
},
- [textWidth, overflowIconWidthActiveOrChildSelected, showErrors]
+ [textWidth, overflowIconWidthActiveOrChildSelected, showErrors],
);
const onRenderOverflowButton = useCallback(
@@ -525,7 +525,7 @@ export const TreeItem: React.FC = ({
isActive: boolean,
isChildSelected: boolean,
menuOpenCallback: (cb: boolean) => void,
- setThisItemSelected: (sel: boolean) => void
+ setThisItemSelected: (sel: boolean) => void,
) => {
const moreLabel = formatMessage('More options');
return (overflowItems: IContextualMenuItem[] | undefined) => {
@@ -568,7 +568,7 @@ export const TreeItem: React.FC = ({
);
};
},
- [isActive, isChildSelected, menuOpenCallback, setThisItemSelected]
+ [isActive, isChildSelected, menuOpenCallback, setThisItemSelected],
);
return (
@@ -601,7 +601,7 @@ export const TreeItem: React.FC = ({
!!isActive,
isChildSelected,
menuOpenCallback,
- setThisItemSelected
+ setThisItemSelected,
)}
/>
diff --git a/Composer/packages/client/src/components/QnA/CreateQnAFromQnAMaker.tsx b/Composer/packages/client/src/components/QnA/CreateQnAFromQnAMaker.tsx
index f73f4e5ee2..75325e121c 100644
--- a/Composer/packages/client/src/components/QnA/CreateQnAFromQnAMaker.tsx
+++ b/Composer/packages/client/src/components/QnA/CreateQnAFromQnAMaker.tsx
@@ -41,7 +41,7 @@ export const CreateQnAFromQnAMaker: React.FC = (props) =
{formatMessage(
- 'Import content from an existing knowledge base on the QnA maker portal. Your knowledge base will downloaded locally and source knowledge base will remain as-is.'
+ 'Import content from an existing knowledge base on the QnA maker portal. Your knowledge base will downloaded locally and source knowledge base will remain as-is.',
)}
diff --git a/Composer/packages/client/src/components/QnA/CreateQnAFromUrl.tsx b/Composer/packages/client/src/components/QnA/CreateQnAFromUrl.tsx
index 0ede605c55..c338d7a2d1 100644
--- a/Composer/packages/client/src/components/QnA/CreateQnAFromUrl.tsx
+++ b/Composer/packages/client/src/components/QnA/CreateQnAFromUrl.tsx
@@ -105,7 +105,7 @@ export const CreateQnAFromUrl: React.FC = (props) => {
{formatMessage(
- 'Select this option if you want to create a knowledge base from content hosted online such as an FAQ or document link (.csv, .xls or .doc format)'
+ 'Select this option if you want to create a knowledge base from content hosted online such as an FAQ or document link (.csv, .xls or .doc format)',
)}
diff --git a/Composer/packages/client/src/components/QnA/CreateQnAModal.tsx b/Composer/packages/client/src/components/QnA/CreateQnAModal.tsx
index 887145507b..0dca53a68b 100644
--- a/Composer/packages/client/src/components/QnA/CreateQnAModal.tsx
+++ b/Composer/packages/client/src/components/QnA/CreateQnAModal.tsx
@@ -180,8 +180,8 @@ export const CreateQnAModal: React.FC = (props) => {
if (data.length === 0) {
setSubscriptionsErrorMessage(
formatMessage(
- 'Your subscription list is empty, please add your subscription, or login with another account.'
- )
+ 'Your subscription list is empty, please add your subscription, or login with another account.',
+ ),
);
}
})
@@ -235,7 +235,7 @@ export const CreateQnAModal: React.FC = (props) => {
const keylist: KeyRec[] = await fetchKeys(
cognitiveServicesManagementClient,
- accounts.filter((a) => a.kind === serviceKeyType)
+ accounts.filter((a) => a.kind === serviceKeyType),
);
const kbsMap = {};
@@ -437,7 +437,7 @@ export const CreateQnAModal: React.FC = (props) => {
{noKeys && subscriptionId && (
{formatMessage(
- 'No existing QnA Maker resources were found in this subscription. Select a different subscription, or click “Back” to create a new resource or generate a resource request to handoff to your Azure admin.'
+ 'No existing QnA Maker resources were found in this subscription. Select a different subscription, or click “Back” to create a new resource or generate a resource request to handoff to your Azure admin.',
)}
)}
diff --git a/Composer/packages/client/src/components/QnA/ImportQnAFromUrl.tsx b/Composer/packages/client/src/components/QnA/ImportQnAFromUrl.tsx
index 89e9c0801e..c5406c801f 100644
--- a/Composer/packages/client/src/components/QnA/ImportQnAFromUrl.tsx
+++ b/Composer/packages/client/src/components/QnA/ImportQnAFromUrl.tsx
@@ -43,7 +43,7 @@ const title = {formatMessage('Replace knowledge base fro
const description = (
{formatMessage(
- 'Select this option if you want to replace current knowledge base from content hosted online such as an FAQ or document link (.csv, .xls or .doc format)'
+ 'Select this option if you want to replace current knowledge base from content hosted online such as an FAQ or document link (.csv, .xls or .doc format)',
)}
);
diff --git a/Composer/packages/client/src/components/QnA/PersonaCard.tsx b/Composer/packages/client/src/components/QnA/PersonaCard.tsx
index 14dbee6391..4183124ec7 100644
--- a/Composer/packages/client/src/components/QnA/PersonaCard.tsx
+++ b/Composer/packages/client/src/components/QnA/PersonaCard.tsx
@@ -20,13 +20,13 @@ export const PersonaCard: React.FC = (props) => {
const confirmed = await OpenConfirmModal(
formatMessage('Sign out of Azure'),
formatMessage(
- 'By signing out of Azure, your operation will be canceled and this dialog will close. Do you want to continue?'
+ 'By signing out of Azure, your operation will be canceled and this dialog will close. Do you want to continue?',
),
{
onRenderContent: (subtitle: string) =>
{subtitle}
,
confirmText: formatMessage('Sign out'),
cancelText: formatMessage('Cancel'),
- }
+ },
);
if (confirmed) {
await logoutUser();
diff --git a/Composer/packages/client/src/components/QnA/ReplaceQnAFromModal.tsx b/Composer/packages/client/src/components/QnA/ReplaceQnAFromModal.tsx
index 9e5d23e3fe..63e36dd4f4 100644
--- a/Composer/packages/client/src/components/QnA/ReplaceQnAFromModal.tsx
+++ b/Composer/packages/client/src/components/QnA/ReplaceQnAFromModal.tsx
@@ -145,8 +145,8 @@ export const ReplaceQnAFromModal: React.FC
= (props) => {
if (data.length === 0) {
setSubscriptionsErrorMessage(
formatMessage(
- 'Your subscription list is empty, please add your subscription, or login with another account.'
- )
+ 'Your subscription list is empty, please add your subscription, or login with another account.',
+ ),
);
}
})
@@ -199,7 +199,7 @@ export const ReplaceQnAFromModal: React.FC = (props) => {
const accounts = await cognitiveServicesManagementClient.accounts.list();
const keylist: KeyRec[] = await fetchKeys(
cognitiveServicesManagementClient,
- accounts.filter((a) => a.kind === serviceKeyType)
+ accounts.filter((a) => a.kind === serviceKeyType),
);
const kbsMap = {};
@@ -304,7 +304,7 @@ export const ReplaceQnAFromModal: React.FC = (props) => {
{formatMessage(
- 'Select this option when you want to import existing knowledge base from QnA maker portal. '
+ 'Select this option when you want to import existing knowledge base from QnA maker portal. ',
)}
@@ -359,7 +359,7 @@ export const ReplaceQnAFromModal: React.FC = (props) => {
{noKeys && subscriptionId && (
{formatMessage(
- 'No existing QnA Maker resources were found in this subscription. Select a different subscription, or click “Back” to create a new resource or generate a resource request to handoff to your Azure admin.'
+ 'No existing QnA Maker resources were found in this subscription. Select a different subscription, or click “Back” to create a new resource or generate a resource request to handoff to your Azure admin.',
)}
)}
diff --git a/Composer/packages/client/src/components/QnA/constants.ts b/Composer/packages/client/src/components/QnA/constants.ts
index cbbb5bec48..1275a074c9 100644
--- a/Composer/packages/client/src/components/QnA/constants.ts
+++ b/Composer/packages/client/src/components/QnA/constants.ts
@@ -102,16 +102,16 @@ export const validateName = (sources: QnAFile[]): FieldValidator => {
if (name) {
if (!FileNameRegex.test(name)) {
currentError = formatMessage(
- 'A knowledge base name cannot contain spaces or special characters. Use letters, numbers, -, or _.'
+ 'A knowledge base name cannot contain spaces or special characters. Use letters, numbers, -, or _.',
);
}
const duplicatedItemIndex = sources.findIndex(
- (item) => getBaseName(item.id.toLowerCase()) === `${name.toLowerCase()}.source`
+ (item) => getBaseName(item.id.toLowerCase()) === `${name.toLowerCase()}.source`,
);
if (duplicatedItemIndex > -1) {
currentError = formatMessage(
- 'You already have a knowledge base with that name. Choose another name and try again.'
+ 'You already have a knowledge base with that name. Choose another name and try again.',
);
}
}
diff --git a/Composer/packages/client/src/components/QnA/styles.ts b/Composer/packages/client/src/components/QnA/styles.ts
index 774a525b93..1ee77743d8 100644
--- a/Composer/packages/client/src/components/QnA/styles.ts
+++ b/Composer/packages/client/src/components/QnA/styles.ts
@@ -115,13 +115,13 @@ export const subText = css`
export const knowledgeBaseStyle = {
root: {
color: NeutralColors.gray160,
- fontWeight: '600' as '600',
+ fontWeight: '600' as const,
},
};
export const urlStackStyle = {
root: {
- overflowY: 'auto' as 'auto',
+ overflowY: 'auto' as const,
marginBottom: 10,
},
};
diff --git a/Composer/packages/client/src/components/Split/ThinSplitter.tsx b/Composer/packages/client/src/components/Split/ThinSplitter.tsx
index 40eef62c9f..aca804abe3 100644
--- a/Composer/packages/client/src/components/Split/ThinSplitter.tsx
+++ b/Composer/packages/client/src/components/Split/ThinSplitter.tsx
@@ -33,7 +33,7 @@ const Splitter = styled.div(
marginLeft: horizontal ? '0' : getCenteredMargin(splitterSize),
marginTop: horizontal ? getCenteredMargin(splitterSize) : '0',
background: dragging ? 'black' : 'silver',
- })
+ }),
);
/**
diff --git a/Composer/packages/client/src/components/TriggerCreationModal/TriggerCreationModal.tsx b/Composer/packages/client/src/components/TriggerCreationModal/TriggerCreationModal.tsx
index 7adb86d255..4f285333ff 100644
--- a/Composer/packages/client/src/components/TriggerCreationModal/TriggerCreationModal.tsx
+++ b/Composer/packages/client/src/components/TriggerCreationModal/TriggerCreationModal.tsx
@@ -97,7 +97,7 @@ export const TriggerCreationModal: React.FC = (props)
projectId,
dialogId,
localeLuFile,
- setLocaleLuFile
+ setLocaleLuFile,
);
return (
diff --git a/Composer/packages/client/src/components/TriggerCreationModal/TriggerDropdownGroup.tsx b/Composer/packages/client/src/components/TriggerCreationModal/TriggerDropdownGroup.tsx
index 9c43131469..a8d3a717f4 100644
--- a/Composer/packages/client/src/components/TriggerCreationModal/TriggerDropdownGroup.tsx
+++ b/Composer/packages/client/src/components/TriggerCreationModal/TriggerDropdownGroup.tsx
@@ -44,14 +44,14 @@ export const TriggerDropdownGroup: FC = ({
);
},
- [recognizerType]
+ [recognizerType],
);
const triggerOptionTree = useMemo(() => {
return generateTriggerOptionTree(
triggerUISchema,
formatMessage('What is the type of this trigger?'),
- formatMessage('Select a trigger type')
+ formatMessage('Select a trigger type'),
);
}, []);
diff --git a/Composer/packages/client/src/components/TriggerCreationModal/TriggerOptionTree.ts b/Composer/packages/client/src/components/TriggerCreationModal/TriggerOptionTree.ts
index f342206a3b..2a6df068b8 100644
--- a/Composer/packages/client/src/components/TriggerCreationModal/TriggerOptionTree.ts
+++ b/Composer/packages/client/src/components/TriggerCreationModal/TriggerOptionTree.ts
@@ -43,20 +43,20 @@ const getGroupKey = (submenu) => (typeof submenu === 'object' ? submenu.label :
export const generateTriggerOptionTree = (
triggerUIOptions: TriggerUISchema,
rootPrompt: string,
- rootPlaceHolder: string
+ rootPlaceHolder: string,
): TriggerOptionTree => {
const root = new TriggerOptionGroupNode('triggerTypeDropDown', rootPrompt, rootPlaceHolder);
const allOptionEntries = Object.entries(triggerUIOptions).filter(([, option]) => Boolean(option)) as [
string,
- TriggerUIOption
+ TriggerUIOption,
][];
const leafEntries = allOptionEntries.filter(([, options]) => !options.submenu);
const nonLeafEntries = allOptionEntries.filter(([, options]) => options.submenu);
// Build leaf nodes whose depth = 1.
const leafNodeList = leafEntries.map(
- ([$kind, options]) => new TriggerOptionLeafNode(options?.label ?? '', $kind, options?.order)
+ ([$kind, options]) => new TriggerOptionLeafNode(options?.label ?? '', $kind, options?.order),
);
// Insert depth 1 leaf nodes to tree.
@@ -66,17 +66,20 @@ export const generateTriggerOptionTree = (
// Build group nodes.
const groups = nonLeafEntries
.map(([, options]) => options.submenu)
- .reduce((result, submenu) => {
- const name = getGroupKey(submenu);
- if (!result[name]) result[name] = new TriggerOptionGroupNode(name, '', '');
- if (typeof submenu === 'object') {
- const tree: TriggerOptionGroupNode = result[name];
- tree.prompt = submenu.prompt;
- tree.placeholder = submenu.placeholder;
- tree.parent = root;
- }
- return result;
- }, {} as { [key: string]: TriggerOptionGroupNode });
+ .reduce(
+ (result, submenu) => {
+ const name = getGroupKey(submenu);
+ if (!result[name]) result[name] = new TriggerOptionGroupNode(name, '', '');
+ if (typeof submenu === 'object') {
+ const tree: TriggerOptionGroupNode = result[name];
+ tree.prompt = submenu.prompt;
+ tree.placeholder = submenu.placeholder;
+ tree.parent = root;
+ }
+ return result;
+ },
+ {} as { [key: string]: TriggerOptionGroupNode },
+ );
// Insert depth 1 group nodes to tree.
root.children.push(...Object.values(groups));
diff --git a/Composer/packages/client/src/components/TriggerCreationModal/resolveTriggerWidget.tsx b/Composer/packages/client/src/components/TriggerCreationModal/resolveTriggerWidget.tsx
index bf7483b234..48eb02f612 100644
--- a/Composer/packages/client/src/components/TriggerCreationModal/resolveTriggerWidget.tsx
+++ b/Composer/packages/client/src/components/TriggerCreationModal/resolveTriggerWidget.tsx
@@ -26,7 +26,7 @@ export function resolveTriggerWidget(
projectId: string,
dialogId: string,
luFile?: LuFile,
- setLuFile?: (data: LuFile) => void
+ setLuFile?: (data: LuFile) => void,
) {
const isRegEx = isRegExRecognizerType(dialogFile);
const isLUISnQnA = isLUISnQnARecognizerType(dialogFile) || isPVARecognizerType(dialogFile);
@@ -67,7 +67,7 @@ export function resolveTriggerWidget(
Name: PlaceHolderSectionName,
Body: body,
},
- {}
+ {},
);
setLuFile(shadowLuFile);
}
diff --git a/Composer/packages/client/src/components/TriggerCreationModal/validators.ts b/Composer/packages/client/src/components/TriggerCreationModal/validators.ts
index f0d6bbb84f..3468190ff8 100644
--- a/Composer/packages/client/src/components/TriggerCreationModal/validators.ts
+++ b/Composer/packages/client/src/components/TriggerCreationModal/validators.ts
@@ -23,7 +23,7 @@ const validateDupRegExIntent = (
selectedType: string,
intent: string,
isRegEx: boolean,
- regExIntents: [{ intent: string; pattern: string }]
+ regExIntents: [{ intent: string; pattern: string }],
): string | undefined => {
if (selectedType === SDKKinds.OnIntent && isRegEx && regExIntents.find((ri) => ri.intent === intent)) {
return formatMessage(`RegEx {intent} is already defined`, { intent });
@@ -53,7 +53,7 @@ const validateTriggerPhrases = (
selectedType: string,
isRegEx: boolean,
intent: string,
- triggerPhrases: string
+ triggerPhrases: string,
): string | undefined => {
if (selectedType === SDKKinds.OnIntent && !isRegEx && triggerPhrases) {
return getLuDiagnostics(intent, triggerPhrases);
@@ -64,7 +64,7 @@ export const validateForm = (
selectedType: string,
data: TriggerFormData,
isRegEx: boolean,
- regExIntents: [{ intent: string; pattern: string }]
+ regExIntents: [{ intent: string; pattern: string }],
): TriggerFormDataErrors => {
const errors: TriggerFormDataErrors = {};
const { $kind, event: eventName, intent, regEx, triggerPhrases } = data;
diff --git a/Composer/packages/client/src/components/WebChat/WebChatComposer.tsx b/Composer/packages/client/src/components/WebChat/WebChatComposer.tsx
index b23def1405..bface67a95 100644
--- a/Composer/packages/client/src/components/WebChat/WebChatComposer.tsx
+++ b/Composer/packages/client/src/components/WebChat/WebChatComposer.tsx
@@ -21,66 +21,73 @@ export type WebChatComposerProps = {
isDisabled: boolean;
};
-const createCardActionMiddleware = () => (next) => async ({ cardAction, getSignInUrl }) => {
- const { type, value } = cardAction;
-
- switch (type) {
- case 'signin': {
- // eslint-disable-next-line security/detect-non-literal-fs-filename
- const popup = window.open();
- const url = await getSignInUrl();
- if (popup) {
- popup.location.href = url;
+const createCardActionMiddleware =
+ () =>
+ (next) =>
+ async ({ cardAction, getSignInUrl }) => {
+ const { type, value } = cardAction;
+
+ switch (type) {
+ case 'signin': {
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
+ const popup = window.open();
+ const url = await getSignInUrl();
+ if (popup) {
+ popup.location.href = url;
+ }
+ break;
}
- break;
- }
- case 'downloadFile':
- //Fall through
+ case 'downloadFile':
+ //Fall through
- case 'playAudio':
- //Fall through
+ case 'playAudio':
+ //Fall through
- case 'playVideo':
- //Fall through
+ case 'playVideo':
+ //Fall through
- case 'showImage':
- //Fall through
+ case 'showImage':
+ //Fall through
- case 'openUrl':
- // eslint-disable-next-line security/detect-non-literal-fs-filename
- window.open(value, '_blank');
- break;
+ case 'openUrl':
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
+ window.open(value, '_blank');
+ break;
- default:
- return next({ cardAction, getSignInUrl });
- }
-};
+ default:
+ return next({ cardAction, getSignInUrl });
+ }
+ };
+
+const createActivityMiddleware =
+ () =>
+ (next: unknown) =>
+ (...setupArgs) =>
+ (...renderArgs) => {
+ const card = setupArgs[0];
+ switch (card.activity.type) {
+ case ActivityType.Trace:
+ return false;
-const createActivityMiddleware = () => (next: unknown) => (...setupArgs) => (...renderArgs) => {
- const card = setupArgs[0];
- switch (card.activity.type) {
- case ActivityType.Trace:
- return false;
-
- case ActivityType.EndOfConversation:
- return false;
-
- default:
- if (typeof next === 'function') {
- const middlewareResult = next(...setupArgs);
- if (middlewareResult) {
- return (
-
- {middlewareResult(...renderArgs)}
-
- );
+ case ActivityType.EndOfConversation:
+ return false;
+
+ default:
+ if (typeof next === 'function') {
+ const middlewareResult = next(...setupArgs);
+ if (middlewareResult) {
+ return (
+
+ {middlewareResult(...renderArgs)}
+
+ );
+ }
+ return false;
}
return false;
- }
- return false;
- }
-};
+ }
+ };
const areEqual = (prevProps: WebChatComposerProps, nextProps: WebChatComposerProps) => {
const result =
diff --git a/Composer/packages/client/src/components/WebChat/WebChatPanel.tsx b/Composer/packages/client/src/components/WebChat/WebChatPanel.tsx
index bd914198bc..1b650f36c5 100644
--- a/Composer/packages/client/src/components/WebChat/WebChatPanel.tsx
+++ b/Composer/packages/client/src/components/WebChat/WebChatPanel.tsx
@@ -70,10 +70,8 @@ export const WebChatPanel: React.FC = ({
webChatTrafficChannel.current = new WebSocket(`ws://${location.hostname}:${conversationServerPort}/ws/traffic`);
if (webChatTrafficChannel.current) {
webChatTrafficChannel.current.onmessage = (event) => {
- const data:
- | ConversationActivityTraffic
- | ConversationNetworkTrafficItem
- | ConversationNetworkErrorItem = JSON.parse(event.data);
+ const data: ConversationActivityTraffic | ConversationNetworkTrafficItem | ConversationNetworkErrorItem =
+ JSON.parse(event.data);
switch (data.trafficType) {
case 'network': {
@@ -88,7 +86,7 @@ export const WebChatPanel: React.FC = ({
id: uuid(),
timestamp: new Date(a.timestamp || Date.now()).getTime(),
trafficType: data.trafficType,
- }))
+ })),
);
break;
}
@@ -163,7 +161,7 @@ export const WebChatPanel: React.FC = ({
botUrl,
secret,
projectId,
- activeLocale
+ activeLocale,
);
if (mounted) {
setChatData({
@@ -191,7 +189,7 @@ export const WebChatPanel: React.FC = ({
oldChatData,
requireNewUserId,
activeLocale,
- secret
+ secret,
);
TelemetryClient.track('WebChatConversationRestarted', {
@@ -208,9 +206,9 @@ export const WebChatPanel: React.FC = ({
}
},
1000,
- { leading: true }
+ { leading: true },
),
- [secret, activeLocale]
+ [secret, activeLocale],
);
const onSaveTranscriptClick = async (conversationId: string) => {
diff --git a/Composer/packages/client/src/components/WebChat/__tests__/ActivityHighlightWrapper.test.tsx b/Composer/packages/client/src/components/WebChat/__tests__/ActivityHighlightWrapper.test.tsx
index 978c14538d..2be092edbe 100644
--- a/Composer/packages/client/src/components/WebChat/__tests__/ActivityHighlightWrapper.test.tsx
+++ b/Composer/packages/client/src/components/WebChat/__tests__/ActivityHighlightWrapper.test.tsx
@@ -36,7 +36,7 @@ describe(' ', () => {
trafficType: 'activity',
},
});
- }
+ },
);
getByTestId('composer-wc-activity-selected');
});
@@ -60,7 +60,7 @@ describe(' ', () => {
trafficType: 'activity',
},
});
- }
+ },
);
getByTestId('composer-wc-activity');
});
diff --git a/Composer/packages/client/src/components/WebChat/hooks/WebChatHooksContainer.tsx b/Composer/packages/client/src/components/WebChat/hooks/WebChatHooksContainer.tsx
index e6a268fb91..b1bf44843a 100644
--- a/Composer/packages/client/src/components/WebChat/hooks/WebChatHooksContainer.tsx
+++ b/Composer/packages/client/src/components/WebChat/hooks/WebChatHooksContainer.tsx
@@ -6,7 +6,7 @@ import React from 'react';
import { useActivityInspectionListener } from './useActivityInspectionListener';
import { useTranscriptFocusListener } from './useTranscriptFocusListener';
-export const WebChatHooksContainer: React.FC<{}> = () => {
+export const WebChatHooksContainer: React.FC = () => {
useActivityInspectionListener();
useTranscriptFocusListener();
diff --git a/Composer/packages/client/src/components/WebChat/hooks/useTranscriptFocusListener.ts b/Composer/packages/client/src/components/WebChat/hooks/useTranscriptFocusListener.ts
index f278e09aae..d916d63d79 100644
--- a/Composer/packages/client/src/components/WebChat/hooks/useTranscriptFocusListener.ts
+++ b/Composer/packages/client/src/components/WebChat/hooks/useTranscriptFocusListener.ts
@@ -45,7 +45,7 @@ export const useTranscriptFocusListener = () => {
setWebChatInspectionData(currentProjectId, { item: trafficItem });
}
},
- [activeDebugPanelTab, currentProjectId, rawWebChatTraffic, setDebugPanelActiveTab, setDebugPanelExpansion]
+ [activeDebugPanelTab, currentProjectId, rawWebChatTraffic, setDebugPanelActiveTab, setDebugPanelExpansion],
);
useObserveTranscriptFocus(onActivityFocused, [onActivityFocused]);
diff --git a/Composer/packages/client/src/components/WebChat/utils/conversationService.ts b/Composer/packages/client/src/components/WebChat/utils/conversationService.ts
index 541695cbd3..1ce1aec82b 100644
--- a/Composer/packages/client/src/components/WebChat/utils/conversationService.ts
+++ b/Composer/packages/client/src/components/WebChat/utils/conversationService.ts
@@ -37,7 +37,7 @@ export class ConversationService {
newConversationId: string,
userId: string,
activeLocale: string,
- secret: BotSecret
+ secret: BotSecret,
) {
const url = `${this.directlineHostUrl}/conversations/${oldConversationId}/updateConversation`;
return axios.put(
@@ -53,7 +53,7 @@ export class ConversationService {
headers: {
'Content-Type': 'application/json',
},
- }
+ },
);
}
@@ -67,7 +67,7 @@ export class ConversationService {
private async fetchDirectLineObject(
conversationId: string,
- directLineOptions: { mode: WebChatMode; endpointId: string; userId: string }
+ directLineOptions: { mode: WebChatMode; endpointId: string; userId: string },
) {
const options = {
conversationId,
@@ -100,7 +100,7 @@ export class ConversationService {
headers: {
'Content-Type': 'application/json',
},
- }
+ },
);
}
@@ -108,7 +108,7 @@ export class ConversationService {
botUrl: string,
secret: BotSecret,
projectId: string,
- activeLocale: string
+ activeLocale: string,
): Promise {
const webChatMode = 'livechat';
const user = this.getUser();
@@ -147,7 +147,7 @@ export class ConversationService {
oldChatData: ChatData,
requireNewUserID: boolean,
activeLocale: string,
- secret: BotSecret
+ secret: BotSecret,
) {
if (oldChatData.directline) {
oldChatData.directline.end();
@@ -165,7 +165,7 @@ export class ConversationService {
conversationId,
user.id,
activeLocale,
- secret
+ secret,
);
const { endpointId } = resp.data;
const directline = await this.fetchDirectLineObject(conversationId, {
diff --git a/Composer/packages/client/src/components/__tests__/BotRuntimeController/BotController.test.tsx b/Composer/packages/client/src/components/__tests__/BotRuntimeController/BotController.test.tsx
index c57881a9ed..ee9c81a647 100644
--- a/Composer/packages/client/src/components/__tests__/BotRuntimeController/BotController.test.tsx
+++ b/Composer/packages/client/src/components/__tests__/BotRuntimeController/BotController.test.tsx
@@ -63,7 +63,7 @@ describe(' ', () => {
};
const { findAllByText } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
await findAllByText('Restart all bots (2/3 running)');
});
@@ -78,7 +78,7 @@ describe(' ', () => {
};
const { findByText } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
await findByText('Start all');
});
@@ -93,7 +93,7 @@ describe(' ', () => {
};
const { findByTestId } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
const button = await findByTestId('button');
@@ -113,7 +113,7 @@ describe(' ', () => {
};
const { findByTestId } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
const button = await findByTestId('button');
@@ -135,7 +135,7 @@ describe(' ', () => {
};
const { findByText } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
await findByText('Starting bots.. (1/4 running)');
});
@@ -151,7 +151,7 @@ describe(' ', () => {
};
const { findByText } = renderWithRecoil(
,
- initRecoilState
+ initRecoilState,
);
await findByText('Stopping bots.. (2/4 running)');
});
diff --git a/Composer/packages/client/src/components/__tests__/BotRuntimeController/useBotOperations.test.tsx b/Composer/packages/client/src/components/__tests__/BotRuntimeController/useBotOperations.test.tsx
index f3a0b5daa7..460e878d2c 100644
--- a/Composer/packages/client/src/components/__tests__/BotRuntimeController/useBotOperations.test.tsx
+++ b/Composer/packages/client/src/components/__tests__/BotRuntimeController/useBotOperations.test.tsx
@@ -76,7 +76,7 @@ describe('useBotOperations', () => {
endpointKey: '',
subscriptionKey: '',
},
- }
+ },
);
});
diff --git a/Composer/packages/client/src/components/__tests__/DisableFeatureToolTip.test.tsx b/Composer/packages/client/src/components/__tests__/DisableFeatureToolTip.test.tsx
index 5a0db8ab66..3336c77ed5 100644
--- a/Composer/packages/client/src/components/__tests__/DisableFeatureToolTip.test.tsx
+++ b/Composer/packages/client/src/components/__tests__/DisableFeatureToolTip.test.tsx
@@ -25,7 +25,7 @@ describe(' ', () => {
},
},
});
- }
+ },
);
const tooltipElement = container.querySelector('#pva-disable-tooltip0');
expect(tooltipElement).toBeDefined();
@@ -46,7 +46,7 @@ describe(' ', () => {
},
},
});
- }
+ },
);
const tooltipElement = container.querySelector('#pva-disable-tooltip0');
expect(tooltipElement).toBeNull();
diff --git a/Composer/packages/client/src/constants.tsx b/Composer/packages/client/src/constants.tsx
index 9634860dca..7ae68efeac 100644
--- a/Composer/packages/client/src/constants.tsx
+++ b/Composer/packages/client/src/constants.tsx
@@ -24,12 +24,12 @@ export const UNDO_LIMIT = 10;
export const Tips = {
get PROJECT_NAME() {
return formatMessage(
- `Create a name for the project which will be used to name the application: (projectname-environment-LUfilename)`
+ `Create a name for the project which will be used to name the application: (projectname-environment-LUfilename)`,
);
},
get ENVIRONMENT() {
return formatMessage(
- `When multiple people are working with models you want to be able to work with models independently from each other tied to the source control.`
+ `When multiple people are working with models you want to be able to work with models independently from each other tied to the source control.`,
);
},
get AUTHORING_KEY() {
@@ -46,7 +46,7 @@ export const Tips = {
},
get DEFAULT_LANGUAGE() {
return formatMessage(
- `Configures default language model to use if there is no culture code in the file name (Default: en-us)`
+ `Configures default language model to use if there is no culture code in the file name (Default: en-us)`,
);
},
};
@@ -77,12 +77,12 @@ export const Text = {
},
get LUISDEPLOY() {
return formatMessage(
- `If you already have a LUIS account, provide the information below. If you do not have an account yet, create a (free) account first.`
+ `If you already have a LUIS account, provide the information below. If you do not have an account yet, create a (free) account first.`,
);
},
get QNADEPLOY() {
return formatMessage(
- `If you already have a QNA account, provide the information below. If you do not have an account yet, create a (free) account first.`
+ `If you already have a QNA account, provide the information below. If you do not have an account yet, create a (free) account first.`,
);
},
get LUISDEPLOYSUCCESS() {
@@ -202,7 +202,7 @@ export const DialogCreationCopy = {
return {
title: formatMessage('Choose a bot project for your Azure Bot'),
subText: formatMessage(
- 'Use your Azure Bot resource with a new or existing bot project. You can publish your bot project directly to Azure using the publishing profile created for you.'
+ 'Use your Azure Bot resource with a new or existing bot project. You can publish your bot project directly to Azure using the publishing profile created for you.',
),
};
},
@@ -222,7 +222,7 @@ export const DialogCreationCopy = {
return {
title: formatMessage('Define conversation objective'),
subText: formatMessage(
- `What can the user accomplish through this conversation? For example, BookATable, OrderACoffee etc.`
+ `What can the user accomplish through this conversation? For example, BookATable, OrderACoffee etc.`,
),
};
},
@@ -260,7 +260,7 @@ export const DialogCreationCopy = {
return {
title: formatMessage('Add QnA Maker knowledge base'),
subText: formatMessage(
- 'Extract question-and-answer pairs from an online FAQ, product manuals, or other files. Supported formats are .tsv, .pdf, .doc, .docx, .xlsx, containing questions and answers in sequence. Learn more about knowledge base sources. Skip this step to add questions and answers manually after creation. The number of sources and file size you can add depends on the QnA service SKU you choose. Learn more about QnA Maker SKUs.'
+ 'Extract question-and-answer pairs from an online FAQ, product manuals, or other files. Supported formats are .tsv, .pdf, .doc, .docx, .xlsx, containing questions and answers in sequence. Learn more about knowledge base sources. Skip this step to add questions and answers manually after creation. The number of sources and file size you can add depends on the QnA service SKU you choose. Learn more about QnA Maker SKUs.',
),
};
},
@@ -281,7 +281,7 @@ export const DialogDeleting = {
},
get CONTENT() {
return formatMessage(
- `The dialog you have tried to delete is currently used in the below dialog(s). Removing this dialog will cause your Bot to malfunction without additional action.`
+ `The dialog you have tried to delete is currently used in the below dialog(s). Removing this dialog will cause your Bot to malfunction without additional action.`,
);
},
get CONFIRM_CONTENT() {
@@ -294,15 +294,15 @@ export const MultiLanguagesDialog = {
return {
title: formatMessage('Copy content for translation'),
subText: formatMessage(
- `Composer cannot yet translate your bot automatically.\nTo create a translation manually, Composer will create a copy of your bot’s content with the name of the additional language. This content can then be translated without affecting the original bot logic or flow and you can switch between languages to ensure the responses are correctly and appropriately translated.`
+ `Composer cannot yet translate your bot automatically.\nTo create a translation manually, Composer will create a copy of your bot’s content with the name of the additional language. This content can then be translated without affecting the original bot logic or flow and you can switch between languages to ensure the responses are correctly and appropriately translated.`,
),
selectDefaultLangTitle: formatMessage(
- 'This language will be copied and used as the basis (and fallback language) for the translation.'
+ 'This language will be copied and used as the basis (and fallback language) for the translation.',
),
selectionTitle: formatMessage('To which language will you be translating your bot?'),
searchPlaceHolder: formatMessage('Search'),
whenDoneText: formatMessage(
- 'When done, switch to the newly created language and start the (manual) translation process.'
+ 'When done, switch to the newly created language and start the (manual) translation process.',
),
};
},
@@ -310,7 +310,7 @@ export const MultiLanguagesDialog = {
return {
title: formatMessage('Select language to delete'),
subText: formatMessage(
- `When deleting a language, only the content will be removed. The flow and logic of the conversation and dialog will remain functional.`
+ `When deleting a language, only the content will be removed. The flow and logic of the conversation and dialog will remain functional.`,
),
};
},
@@ -321,7 +321,7 @@ export const addSkillDialog = {
return {
title: formatMessage('Connect to a skill'),
subText: formatMessage(
- "To connect to a skill, your bot needs the information captured in the skill’s manifest, and, for secure access, the skill needs to know your bot's App ID. Follow the steps below to proceed."
+ "To connect to a skill, your bot needs the information captured in the skill’s manifest, and, for secure access, the skill needs to know your bot's App ID. Follow the steps below to proceed.",
),
};
},
@@ -343,7 +343,7 @@ export const addSkillDialog = {
{children}
),
- }
+ },
),
};
},
@@ -380,7 +380,7 @@ export const enableOrchestratorDialog = {
},
get subText() {
return formatMessage(
- 'A bot that consists of multiple bots or connects to skills (multi-bot project) needs Orchestrator to detect and route user input to the appropriate bot or skill.'
+ 'A bot that consists of multiple bots or connects to skills (multi-bot project) needs Orchestrator to detect and route user input to the appropriate bot or skill.',
);
},
};
@@ -396,10 +396,10 @@ export const removeSkillDialog = () => {
return {
title: formatMessage('Warning'),
subText: formatMessage(
- 'The skill you tried to remove from the project is currently used in the below bot(s). Removing this skill won’t delete the files, but it will cause your Bot to malfunction without additional action.'
+ 'The skill you tried to remove from the project is currently used in the below bot(s). Removing this skill won’t delete the files, but it will cause your Bot to malfunction without additional action.',
),
subTextNoUse: formatMessage(
- 'You are about to remove the skill from this project. Removing this skill won’t delete the files.'
+ 'You are about to remove the skill from this project. Removing this skill won’t delete the files.',
),
footerText: formatMessage('Do you wish to continue?'),
};
@@ -471,7 +471,7 @@ export const authUrl = `https://login.microsoftonline.com/${authConfig.tenantId}
export const triggerNotSupportedWarning = () =>
formatMessage(
- 'This trigger type is not supported by the RegEx recognizer. To ensure this trigger is fired, change the recognizer type.'
+ 'This trigger type is not supported by the RegEx recognizer. To ensure this trigger is fired, change the recognizer type.',
);
// TODO: replace language options with available languages pertinent to the selected template (issue #5554)
diff --git a/Composer/packages/client/src/hooks/useResizeObserver.ts b/Composer/packages/client/src/hooks/useResizeObserver.ts
index 6357cdebd8..6e4a9bd5cf 100644
--- a/Composer/packages/client/src/hooks/useResizeObserver.ts
+++ b/Composer/packages/client/src/hooks/useResizeObserver.ts
@@ -1,4 +1,4 @@
-/* eslint-disable @typescript-eslint/ban-ts-ignore */
+/* eslint-disable @typescript-eslint/ban-ts-comment */
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
@@ -20,7 +20,7 @@ export const useResizeObserver = (
// @ts-ignore
resizeCallback: (entries: ResizeObserverEntry[]) => void,
// @ts-ignore
- options?: ResizeObserverOptions
+ options?: ResizeObserverOptions,
) => {
// @ts-ignore
const resizeObserver = React.useRef(new ResizeObserver(resizeCallback));
diff --git a/Composer/packages/client/src/index.tsx b/Composer/packages/client/src/index.tsx
index 343c5c4114..1faea7ee7f 100644
--- a/Composer/packages/client/src/index.tsx
+++ b/Composer/packages/client/src/index.tsx
@@ -16,7 +16,7 @@ const appHostElm = document.getElementById('root');
const emotionCache = createCache({
key: 'client-cache',
- // @ts-expect-error
+ // @ts-expect-error nonce is defined during initial page rendering
nonce: window.__nonce__,
});
@@ -32,7 +32,7 @@ const renderApp = (AppComponent: typeof App) => {
,
- appHostElm
+ appHostElm,
);
};
@@ -44,6 +44,7 @@ renderApp(App);
*/
if (module.hot) {
module.hot.accept('./App', () => {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
const NextApp = require<{ App: typeof App }>('./App').App;
renderApp(NextApp);
});
diff --git a/Composer/packages/client/src/pages/about/About.tsx b/Composer/packages/client/src/pages/about/About.tsx
index 9705b73560..f5240780d9 100644
--- a/Composer/packages/client/src/pages/about/About.tsx
+++ b/Composer/packages/client/src/pages/about/About.tsx
@@ -39,7 +39,7 @@ export const About: React.FC = () => {
{children}
),
- }
+ },
)}
@@ -51,7 +51,7 @@ export const About: React.FC
= () => {
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`,
{
p: ({ children }) => {children}
,
- }
+ },
)}
diff --git a/Composer/packages/client/src/pages/botProject/AllowedCallers.tsx b/Composer/packages/client/src/pages/botProject/AllowedCallers.tsx
index dfc1ddaeab..17e6f10b92 100644
--- a/Composer/packages/client/src/pages/botProject/AllowedCallers.tsx
+++ b/Composer/packages/client/src/pages/botProject/AllowedCallers.tsx
@@ -117,13 +117,15 @@ export const AllowedCallers: React.FC
= ({ projectId }) => {
};
setSettings(projectId, updatedSetting);
},
- [mergedSettings, projectId, runtimeSettings?.skills]
+ [mergedSettings, projectId, runtimeSettings?.skills],
);
- const { arrayItems: allowedCallers = [], addItem, handleChange, handleResetCache } = useArrayItems(
- runtimeSettings?.skills?.allowedCallers || [],
- updateAllowedCallers
- );
+ const {
+ arrayItems: allowedCallers = [],
+ addItem,
+ handleChange,
+ handleResetCache,
+ } = useArrayItems(runtimeSettings?.skills?.allowedCallers || [], updateAllowedCallers);
// Reset array cache when user switches between project settings
const didMount = React.useRef(false);
@@ -144,16 +146,17 @@ export const AllowedCallers: React.FC = ({ projectId }) => {
updatedAllowedCallers.splice(index, 1);
handleChange(updatedAllowedCallers);
},
- [allowedCallers, handleChange]
+ [allowedCallers, handleChange],
);
const onChange = React.useCallback(
- (index: number) => (_: React.FormEvent, newValue = '') => {
- const updatedAllowedCallers = allowedCallers.slice();
- updatedAllowedCallers[index].value = newValue;
- handleChange(updatedAllowedCallers);
- },
- [allowedCallers, handleChange]
+ (index: number) =>
+ (_: React.FormEvent, newValue = '') => {
+ const updatedAllowedCallers = allowedCallers.slice();
+ updatedAllowedCallers[index].value = newValue;
+ handleChange(updatedAllowedCallers);
+ },
+ [allowedCallers, handleChange],
);
const onBlur = React.useCallback(() => {
@@ -177,7 +180,7 @@ export const AllowedCallers: React.FC = ({ projectId }) => {
{children}
),
- }
+ },
)}
diff --git a/Composer/packages/client/src/pages/botProject/AppIdAndPassword.tsx b/Composer/packages/client/src/pages/botProject/AppIdAndPassword.tsx
index 3a89e78859..bd5437ed83 100644
--- a/Composer/packages/client/src/pages/botProject/AppIdAndPassword.tsx
+++ b/Composer/packages/client/src/pages/botProject/AppIdAndPassword.tsx
@@ -95,7 +95,7 @@ export const AppIdAndPassword: React.FC = (props) => {
{children}
),
- }
+ },
)}
diff --git a/Composer/packages/client/src/pages/botProject/BotLanguage.tsx b/Composer/packages/client/src/pages/botProject/BotLanguage.tsx
index ef2a8649f2..b1b9798a94 100644
--- a/Composer/packages/client/src/pages/botProject/BotLanguage.tsx
+++ b/Composer/packages/client/src/pages/botProject/BotLanguage.tsx
@@ -121,14 +121,8 @@ export const BotLanguage: React.FC
= (props) => {
const mergedSettings = mergePropertiesManagedByRootBot(projectId, rootBotProjectId, settings);
const locale = useRecoilValue(localeState(projectId));
const showAddLanguageModal = useRecoilValue(showAddLanguageModalState(projectId));
- const {
- addLanguageDialogBegin,
- setSettings,
- deleteLanguages,
- setLocale,
- addLanguageDialogCancel,
- addLanguages,
- } = useRecoilValue(dispatcherState);
+ const { addLanguageDialogBegin, setSettings, deleteLanguages, setLocale, addLanguageDialogCancel, addLanguages } =
+ useRecoilValue(dispatcherState);
const languageListOptions = useMemo(() => {
const languageList = languageListTemplates(languages, locale, defaultLanguage);
@@ -170,7 +164,7 @@ export const BotLanguage: React.FC = (props) => {
{formatMessage(
- 'List of languages that bot will be able to understand (User input) and respond to (Bot responses). To make this bot available in other languages, click ‘Manage languages’ to create a copy of the default language, and translate the content into the new language.'
+ 'List of languages that bot will be able to understand (User input) and respond to (Bot responses). To make this bot available in other languages, click ‘Manage languages’ to create a copy of the default language, and translate the content into the new language.',
)}
> = (props) => {
+export const BotProjectInfo: React.FC<
+ RouteComponentProps<{
+ projectId?: string;
+ isRootBot?: boolean;
+ }>
+> = (props) => {
const { projectId = '', isRootBot = false } = props;
const botProjects = useRecoilValue(localBotsDataSelector);
const botProject = botProjects.find((b) => b.projectId === projectId);
diff --git a/Composer/packages/client/src/pages/botProject/BotProjectsSettingsTabView.tsx b/Composer/packages/client/src/pages/botProject/BotProjectsSettingsTabView.tsx
index 99fe7fe256..0d3a91a98c 100644
--- a/Composer/packages/client/src/pages/botProject/BotProjectsSettingsTabView.tsx
+++ b/Composer/packages/client/src/pages/botProject/BotProjectsSettingsTabView.tsx
@@ -62,10 +62,12 @@ enum PivotItemKey {
// -------------------- BotProjectSettingsTabView -------------------- //
-export const BotProjectSettingsTabView: React.FC
> = (props) => {
+export const BotProjectSettingsTabView: React.FC<
+ RouteComponentProps<{
+ projectId: string;
+ scrollToSectionId: string;
+ }>
+> = (props) => {
const { projectId = '', scrollToSectionId = '' } = props;
const botProjects = useRecoilValue(localBotsDataSelector);
const botProject = botProjects.find((b) => b.projectId === projectId);
diff --git a/Composer/packages/client/src/pages/botProject/CreatePublishProfileDialog.tsx b/Composer/packages/client/src/pages/botProject/CreatePublishProfileDialog.tsx
index 410c724b36..12de04701f 100644
--- a/Composer/packages/client/src/pages/botProject/CreatePublishProfileDialog.tsx
+++ b/Composer/packages/client/src/pages/botProject/CreatePublishProfileDialog.tsx
@@ -36,7 +36,7 @@ export const CreatePublishProfileDialog: React.FC Promise) => {
const warningText = formatMessage(
- 'Are you sure you want to delete your bot? This action cannot be undone and your bot and all related files in the bot project folder will be permanently deleted. Your Azure resources will remain unchanged.'
+ 'Are you sure you want to delete your bot? This action cannot be undone and your bot and all related files in the bot project folder will be permanently deleted. Your Azure resources will remain unchanged.',
);
const title = formatMessage('Delete Bot');
const settings = {
diff --git a/Composer/packages/client/src/pages/botProject/GetAppInfoFromPublishProfileDialog.tsx b/Composer/packages/client/src/pages/botProject/GetAppInfoFromPublishProfileDialog.tsx
index 153197023b..4e1c71fe2f 100644
--- a/Composer/packages/client/src/pages/botProject/GetAppInfoFromPublishProfileDialog.tsx
+++ b/Composer/packages/client/src/pages/botProject/GetAppInfoFromPublishProfileDialog.tsx
@@ -66,7 +66,7 @@ export const GetAppInfoFromPublishProfileDialog: React.FC = (props) => {
const dialogTitle = {
title: formatMessage('Retrieve App ID from publishing profile'),
subText: formatMessage(
- 'A publishing profile contains the information necessary to provision and publish your bot, including its App ID.'
+ 'A publishing profile contains the information necessary to provision and publish your bot, including its App ID.',
),
};
diff --git a/Composer/packages/client/src/pages/botProject/PublishProfieWrapperDialog.tsx b/Composer/packages/client/src/pages/botProject/PublishProfieWrapperDialog.tsx
index 6682f0a405..195947da23 100644
--- a/Composer/packages/client/src/pages/botProject/PublishProfieWrapperDialog.tsx
+++ b/Composer/packages/client/src/pages/botProject/PublishProfieWrapperDialog.tsx
@@ -28,7 +28,7 @@ export const PublishProfileWrapperDialog: React.FC(
- null
+ null,
);
useEffect(() => {
diff --git a/Composer/packages/client/src/pages/botProject/PublishTargets.tsx b/Composer/packages/client/src/pages/botProject/PublishTargets.tsx
index e635384026..004cbd884f 100644
--- a/Composer/packages/client/src/pages/botProject/PublishTargets.tsx
+++ b/Composer/packages/client/src/pages/botProject/PublishTargets.tsx
@@ -101,8 +101,8 @@ export const PublishTargets: React.FC = (props) => {
formatMessage('Delete?'),
formatMessage(
'Are you sure you want to remove {targetName}? This will remove only the profile and will not delete provisioned resources.',
- { targetName }
- )
+ { targetName },
+ ),
);
if (confirmed) {
const newPublishTargets = publishTargets.filter((t) => t.name !== targetName);
diff --git a/Composer/packages/client/src/pages/botProject/RootBotExternalService.tsx b/Composer/packages/client/src/pages/botProject/RootBotExternalService.tsx
index e93f81b957..c3a959e810 100644
--- a/Composer/packages/client/src/pages/botProject/RootBotExternalService.tsx
+++ b/Composer/packages/client/src/pages/botProject/RootBotExternalService.tsx
@@ -155,7 +155,9 @@ export const RootBotExternalService: React.FC = (pr
setLocalRootLuisKey(value);
} else {
setLuisKeyErrorMsg(
- formatMessage('LUIS key is required with the current recognizer setting to start your bot locally, and publish')
+ formatMessage(
+ 'LUIS key is required with the current recognizer setting to start your bot locally, and publish',
+ ),
);
setLocalRootLuisKey('');
}
@@ -185,8 +187,8 @@ export const RootBotExternalService: React.FC = (pr
if (!localRootLuisKey) {
setLuisKeyErrorMsg(
formatMessage(
- 'LUIS authoring key is required with the current recognizer setting to start your bot locally, and publish'
- )
+ 'LUIS authoring key is required with the current recognizer setting to start your bot locally, and publish',
+ ),
);
} else {
setLuisKeyErrorMsg('');
@@ -252,7 +254,9 @@ export const RootBotExternalService: React.FC = (pr
const handleRootLuisAuthoringKeyOnBlur = () => {
if (!localRootLuisKey) {
setLuisKeyErrorMsg(
- formatMessage('LUIS key is required with the current recognizer setting to start your bot locally, and publish')
+ formatMessage(
+ 'LUIS key is required with the current recognizer setting to start your bot locally, and publish',
+ ),
);
}
setSettings(projectId, {
@@ -325,7 +329,7 @@ export const RootBotExternalService: React.FC = (pr
{children}
),
- }
+ },
)}
@@ -393,7 +397,7 @@ export const RootBotExternalService: React.FC = (pr
@@ -410,7 +414,7 @@ export const RootBotExternalService: React.FC = (pr
{children}
),
- }
+ },
)}
)}
@@ -439,7 +443,7 @@ export const RootBotExternalService: React.FC = (pr
{children}
),
- }
+ },
)}
diff --git a/Composer/packages/client/src/pages/botProject/SkillBotExternalService.tsx b/Composer/packages/client/src/pages/botProject/SkillBotExternalService.tsx
index 415a8b3be6..3a6cbe3dbc 100644
--- a/Composer/packages/client/src/pages/botProject/SkillBotExternalService.tsx
+++ b/Composer/packages/client/src/pages/botProject/SkillBotExternalService.tsx
@@ -168,7 +168,7 @@ export const SkillBotExternalService: React.FC = (
{children}
),
- }
+ },
)}
@@ -223,7 +223,7 @@ export const SkillBotExternalService: React.FC = (
= (
{children}
),
- }
+ },
)}
diff --git a/Composer/packages/client/src/pages/botProject/SkillHostEndPoint.tsx b/Composer/packages/client/src/pages/botProject/SkillHostEndPoint.tsx
index 33d2252512..49d5751331 100644
--- a/Composer/packages/client/src/pages/botProject/SkillHostEndPoint.tsx
+++ b/Composer/packages/client/src/pages/botProject/SkillHostEndPoint.tsx
@@ -60,7 +60,7 @@ export const SkillHostEndPoint: React.FC = (props) => {
{children}
),
- }
+ },
)}
= (props) => {
{children}
),
- }
+ },
)}
),
@@ -437,8 +437,8 @@ export const ABSChannels: React.FC = (props) => {
const result = await OpenConfirmModal(
formatMessage('Enable speech'),
formatMessage(
- 'This cognitive service account is already set as the default for another bot. Do you want to enable this service without setting it as default?'
- )
+ 'This cognitive service account is already set as the default for another bot. Do you want to enable this service without setting it as default?',
+ ),
);
if (result) {
toggleSpeechOn(settings, false);
@@ -588,7 +588,7 @@ export const ABSChannels: React.FC = (props) => {
>
{formatMessage(
- 'Teams requires a few more steps to get your connection up and running. Follow the instructions on our documentation page to learn how.'
+ 'Teams requires a few more steps to get your connection up and running. Follow the instructions on our documentation page to learn how.',
)}
diff --git a/Composer/packages/client/src/pages/botProject/adapters/AdapterSection.tsx b/Composer/packages/client/src/pages/botProject/adapters/AdapterSection.tsx
index 7351a40f9c..853a60df5d 100644
--- a/Composer/packages/client/src/pages/botProject/adapters/AdapterSection.tsx
+++ b/Composer/packages/client/src/pages/botProject/adapters/AdapterSection.tsx
@@ -43,7 +43,7 @@ const AdapterSection = ({ projectId, scrollToSectionId }: Props) => {
{children}
),
- }
+ },
)}
@@ -78,7 +78,7 @@ const AdapterSection = ({ projectId, scrollToSectionId }: Props) => {
{children}
),
- }
+ },
)}
diff --git a/Composer/packages/client/src/pages/botProject/create-publish-profile/ProfileFormDialog.tsx b/Composer/packages/client/src/pages/botProject/create-publish-profile/ProfileFormDialog.tsx
index eb1a117117..7e3900c038 100644
--- a/Composer/packages/client/src/pages/botProject/create-publish-profile/ProfileFormDialog.tsx
+++ b/Composer/packages/client/src/pages/botProject/create-publish-profile/ProfileFormDialog.tsx
@@ -91,7 +91,7 @@ export const ProfileFormDialog: React.FC = (props) => {
setTargetType(type.name);
}
},
- [types]
+ [types],
);
const saveDisabled = useMemo(() => {
diff --git a/Composer/packages/client/src/pages/botProject/create-publish-profile/PublishProfileDialog.tsx b/Composer/packages/client/src/pages/botProject/create-publish-profile/PublishProfileDialog.tsx
index 7cffe90f13..424e5d83a3 100644
--- a/Composer/packages/client/src/pages/botProject/create-publish-profile/PublishProfileDialog.tsx
+++ b/Composer/packages/client/src/pages/botProject/create-publish-profile/PublishProfileDialog.tsx
@@ -41,21 +41,14 @@ const formatDialogTitle = (current) => {
subText: formatMessage(
'To test, run and publish your bot, it needs Azure resources such as app registration, hosting and channels.' +
' Other resources, such as language understanding and storage are optional.' +
- ' A publishing profile contains all of the information necessary to provision and publish your bot, including its Azure resources.'
+ ' A publishing profile contains all of the information necessary to provision and publish your bot, including its Azure resources.',
),
};
};
export const PublishProfileDialog: React.FC = (props) => {
- const {
- current,
- types,
- projectId,
- closeDialog,
- targets,
- setPublishTargets,
- onUpdateIsCreateProfileFromSkill,
- } = props;
+ const { current, types, projectId, closeDialog, targets, setPublishTargets, onUpdateIsCreateProfileFromSkill } =
+ props;
const [name, setName] = useState(current?.item.name || '');
const [targetType, setTargetType] = useState(current?.item.type || '');
@@ -146,7 +139,7 @@ export const PublishProfileDialog: React.FC = (props)
TelemetryClient.track('NewPublishingProfileSaved', { type });
}
},
- [targets, projectId]
+ [targets, projectId],
);
useEffect(() => {
diff --git a/Composer/packages/client/src/pages/botProject/runtime-settings/RuntimeSettings.tsx b/Composer/packages/client/src/pages/botProject/runtime-settings/RuntimeSettings.tsx
index 0b3f4a5306..d390224a79 100644
--- a/Composer/packages/client/src/pages/botProject/runtime-settings/RuntimeSettings.tsx
+++ b/Composer/packages/client/src/pages/botProject/runtime-settings/RuntimeSettings.tsx
@@ -83,7 +83,7 @@ export const RuntimeSettings: React.FC = React.memo(({ projectId }) => {
};
})
.filter((item) => Boolean(item)) as IToolbarItem[],
- []
+ [],
);
const toolbarItems: IToolbarItem[] = useMemo(
@@ -179,7 +179,7 @@ const CommandBar: React.FC = React.memo(({ projectId }) => {
},
},
],
- [showDisableBtn, showEnableBtn, actionSelected, canUndo, canRedo, debugItems]
+ [showDisableBtn, showEnableBtn, actionSelected, canUndo, canRedo, debugItems],
);
const addNewBtnRef = useCallback((addNew) => {
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/DiagnosticType.ts b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/DiagnosticType.ts
index 8324d0979d..5181587ee1 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/DiagnosticType.ts
+++ b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/DiagnosticType.ts
@@ -44,7 +44,7 @@ function generateResourcePageUrl(
skillId: string | null,
resourceType: ResourceType,
resourceId: string,
- line = 0
+ line = 0,
) {
let uri = `/bot/${rootProjectId}`;
if (skillId !== null && skillId !== rootProjectId) {
@@ -60,13 +60,13 @@ const getFriendlyPath = (dialogPath: string | undefined, dialogs: DialogInfo[])
if (!dialogPath) {
return [];
}
- const [dialogName, triggerPath, ...actionPaths] = dialogPath.split('#')[0]?.split('.');
+ const [dialogName, triggerPath, ...actionPaths] = dialogPath.split('#')[0]?.split('.') ?? [];
if (dialogName) {
const matchedDialog = dialogs.find(({ displayName }) => displayName === dialogName);
if (matchedDialog && triggerPath) {
breadcrumb.push(matchedDialog.displayName);
- const trigger: ITrigger = get(matchedDialog, triggerPath, '');
+ const trigger = get(matchedDialog, triggerPath, '') as unknown as ITrigger;
if (trigger.displayName) {
breadcrumb.push(trigger.displayName);
}
@@ -151,7 +151,7 @@ export class DialogDiagnostic extends DiagnosticInfo {
id: string,
location: string,
diagnostic: Diagnostic,
- dialogs: DialogInfo[]
+ dialogs: DialogInfo[],
) {
super(rootProjectId, projectId, id, location, diagnostic);
this.message = `In ${replaceDialogDiagnosticLabel(diagnostic.path)} ${diagnostic.message}`;
@@ -178,7 +178,7 @@ export class SchemaDiagnostic extends DialogDiagnostic {
id: string,
location: string,
diagnostic: Diagnostic,
- dialogs: DialogInfo[]
+ dialogs: DialogInfo[],
) {
super(rootProjectId, projectId, id, location, diagnostic, dialogs);
this.message = diagnostic.message;
@@ -211,7 +211,7 @@ export class SettingDiagnostic extends DiagnosticInfo {
super(rootProjectId, projectId, id, location, diagnostic);
this.message = `${replaceDialogDiagnosticLabel(diagnostic.path)} ${diagnostic.message}`;
this.dialogPath = diagnostic.path;
- this.friendlyLocationBreadcrumbItems = ['Settings'];
+ this.friendlyLocationBreadcrumbItems = ['Configure'];
}
getUrl = (hash?: string) => {
return createBotSettingUrl(this.rootProjectId, this.projectId, hash);
@@ -227,7 +227,7 @@ export class LgDiagnostic extends DiagnosticInfo {
location: string,
diagnostic: Diagnostic,
lgFile: LgFile,
- dialogs: DialogInfo[]
+ dialogs: DialogInfo[],
) {
super(rootProjectId, projectId, id, location, diagnostic);
this.message = createSingleMessage(diagnostic);
@@ -242,7 +242,7 @@ export class LgDiagnostic extends DiagnosticInfo {
const mappedTemplate = lgFile.templates.find(
(t) =>
get(diagnostic, 'range.start.line') >= get(t, 'range.start.line') &&
- get(diagnostic, 'range.end.line') <= get(t, 'range.end.line')
+ get(diagnostic, 'range.end.line') <= get(t, 'range.end.line'),
);
if (mappedTemplate?.name?.match(LgNamePattern)) {
//should navigate to design page
@@ -262,7 +262,7 @@ export class LgDiagnostic extends DiagnosticInfo {
projectId,
'language-generation',
resourceId,
- diagnostic.range?.start.line
+ diagnostic.range?.start.line,
);
//the format of item.id is lgFile#inlineTemplateId
if (dialogPath) {
@@ -281,7 +281,7 @@ export class LuDiagnostic extends DiagnosticInfo {
location: string,
diagnostic: Diagnostic,
luFile: LuFile,
- dialogs: DialogInfo[]
+ dialogs: DialogInfo[],
) {
super(rootProjectId, projectId, id, location, diagnostic);
this.dialogPath = this.findDialogPath(luFile, dialogs, diagnostic);
@@ -311,7 +311,7 @@ export class LuDiagnostic extends DiagnosticInfo {
projectId,
'language-understanding',
resourceId,
- diagnostic.range?.start.line
+ diagnostic.range?.start.line,
);
if (dialogPath) {
uri = convertPathToUrl(rootProjectId, rootProjectId === projectId ? null : projectId, resourceId, dialogPath);
@@ -335,7 +335,7 @@ export class QnADiagnostic extends DiagnosticInfo {
projectId,
'knowledge-base',
resourceId,
- diagnostic.range?.start.line
+ diagnostic.range?.start.line,
);
};
}
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/DiagnosticsStatus.tsx b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/DiagnosticsStatus.tsx
index 9b4921b569..d6ade59328 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/DiagnosticsStatus.tsx
+++ b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/DiagnosticsStatus.tsx
@@ -32,7 +32,7 @@ export const DiagnosticsStatus = () => {
=1 {One error}
other {# errors}
}`,
- { errorsCount }
+ { errorsCount },
);
const warningLabel = formatMessage(
@@ -42,7 +42,7 @@ export const DiagnosticsStatus = () => {
=1 {One warning}
other {# warnings}
}`,
- { warningsCount }
+ { warningsCount },
);
return (
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/useDiagnostics.ts b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/useDiagnostics.ts
index 0f954c9bf0..f4d98bfa33 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/useDiagnostics.ts
+++ b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/DiagnosticsTab/useDiagnostics.ts
@@ -10,7 +10,7 @@ import { IDiagnosticInfo } from './DiagnosticType';
export const useDiagnosticsData = (): IDiagnosticInfo[] => {
const diagnosticData = useRecoilValue(
- allDiagnosticsSelectorFamily([DiagnosticSeverity.Error, DiagnosticSeverity.Warning])
+ allDiagnosticsSelectorFamily([DiagnosticSeverity.Error, DiagnosticSeverity.Warning]),
);
return diagnosticData ?? [];
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WatchTab/WatchTabContent.tsx b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WatchTab/WatchTabContent.tsx
index 51540ef25e..56fc9fc07c 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WatchTab/WatchTabContent.tsx
+++ b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WatchTab/WatchTabContent.tsx
@@ -129,7 +129,7 @@ const watchTableLayout: DetailsListLayoutMode = DetailsListLayoutMode.justified;
// Ex. getValueFromBotTraceMemory('user.address.city', trace)
export const getValueFromBotTraceMemory = (
valuePath: string,
- botTrace: Activity
+ botTrace: Activity,
): { value: any; propertyIsAvailable: boolean } => {
const pathSegments = valuePath.split('.');
if (pathSegments.length === 1) {
@@ -164,7 +164,7 @@ export const WatchTabContent: React.FC = ({ isActive }
setSelectedVariables(watchedVariablesSelection.current.getSelection());
},
selectionMode: SelectionMode.multiple,
- })
+ }),
);
// reset state when switching to a new project
@@ -174,7 +174,7 @@ export const WatchTabContent: React.FC = ({ isActive }
const mostRecentBotState = useMemo(() => {
const botStateTraffic = rawWebChatTraffic.filter(
- (t) => t.trafficType === 'activity' && t.activity.type === 'trace' && t.activity.name === 'BotState'
+ (t) => t.trafficType === 'activity' && t.activity.type === 'trace' && t.activity.name === 'BotState',
) as ConversationActivityTrafficItem[];
if (botStateTraffic.length) {
return botStateTraffic[botStateTraffic.length - 1];
@@ -185,7 +185,7 @@ export const WatchTabContent: React.FC = ({ isActive }
(item: { key: string; value: string }, index: number | undefined, column: IColumn | undefined) => {
return ;
},
- []
+ [],
);
const onRenderVariableValue = useCallback(
@@ -221,7 +221,7 @@ export const WatchTabContent: React.FC = ({ isActive }
) : null;
}
},
- [mostRecentBotState, userSettings, watchedVariables]
+ [mostRecentBotState, userSettings, watchedVariables],
);
// TODO: update to office-ui-fabric-react@7.170.x to gain access to "flexGrow" column property to distribute proprotional column widths
@@ -247,7 +247,7 @@ export const WatchTabContent: React.FC = ({ isActive }
onRender: onRenderVariableValue,
},
],
- [onRenderVariableName, onRenderVariableValue]
+ [onRenderVariableName, onRenderVariableValue],
);
// we need to refresh the details list when we get a new bot state, add a new row, or submit a variable to watch
@@ -363,7 +363,7 @@ export const WatchTabContent: React.FC = ({ isActive }
= ({ isActive }
{children}
),
- }
+ },
)}
)}
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatInspectorPane.tsx b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatInspectorPane.tsx
index f17d4dd75d..cb6c58f86a 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatInspectorPane.tsx
+++ b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatInspectorPane.tsx
@@ -55,7 +55,7 @@ export const WebChatInspectorPane: React.FC = (props)
}
}
},
- [inspectionData, onSetInspectionData]
+ [inspectionData, onSetInspectionData],
);
const renderHeader = useCallback(
(inspectionData: WebChatInspectionData) => {
@@ -81,7 +81,7 @@ export const WebChatInspectorPane: React.FC = (props)
return null;
}
},
- [handleInspectorTabClick]
+ [handleInspectorTabClick],
);
const getInspectedData = (inspectionData: WebChatInspectionData) => {
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatLogContent.tsx b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatLogContent.tsx
index 4e82735366..96b983264a 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatLogContent.tsx
+++ b/Composer/packages/client/src/pages/design/DebugPanel/TabExtensions/WebChatLog/WebChatLogContent.tsx
@@ -102,7 +102,7 @@ export const WebChatLogContent: React.FC = ({ isActive
setWebChatInspectionData(currentProjectId, { item: trafficItem });
}
}
- }, 500)
+ }, 500),
).current;
const inspectLatestLogMessage = () => {
@@ -139,7 +139,7 @@ export const WebChatLogContent: React.FC = ({ isActive
setWebChatInspectionData(currentProjectId, data);
}
},
- [currentProjectId]
+ [currentProjectId],
);
const renderLogItem = useCallback(
@@ -180,7 +180,7 @@ export const WebChatLogContent: React.FC = ({ isActive
return null;
}
},
- [onClickTraffic]
+ [onClickTraffic],
);
const displayedTraffic = useMemo(() => {
@@ -222,7 +222,7 @@ export const WebChatLogContent: React.FC = ({ isActive
{children}
),
- }
+ },
)}
);
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/WatchVariablePicker.tsx b/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/WatchVariablePicker.tsx
index e3181fc542..1664492d35 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/WatchVariablePicker.tsx
+++ b/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/WatchVariablePicker.tsx
@@ -206,7 +206,7 @@ export const WatchVariablePicker = React.memo((props: WatchVariablePickerProps)
setItems(menuItems);
}
}, 500),
- [getFilterPredicate, menuItems]
+ [getFilterPredicate, menuItems],
);
const onInputChange = useCallback(
@@ -214,7 +214,7 @@ export const WatchVariablePicker = React.memo((props: WatchVariablePickerProps)
setQuery(val ?? '');
performDebouncedSearch(val);
},
- [performDebouncedSearch]
+ [performDebouncedSearch],
);
const onTextBoxFocus = (event: FocusEvent) => {
@@ -238,7 +238,7 @@ export const WatchVariablePicker = React.memo((props: WatchVariablePickerProps)
}
}
},
- [currentProjectId, onHideContextualMenu, variableId, query, watchedVariables]
+ [currentProjectId, onHideContextualMenu, variableId, query, watchedVariables],
);
const onDismiss = useCallback(() => {
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/components/PickerContextualMenuItem.tsx b/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/components/PickerContextualMenuItem.tsx
index 40fabf7ed1..9f7c483c63 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/components/PickerContextualMenuItem.tsx
+++ b/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/components/PickerContextualMenuItem.tsx
@@ -19,53 +19,52 @@ const labelContainerStyle: IStackStyles = {
},
};
-export const getPickerContextualMenuItem = (query: string, propertyTreeExpanded: Record) => (
- itemProps: IContextualMenuItemProps
-) => {
- const {
- item: { secondaryText: path },
- } = itemProps;
+export const getPickerContextualMenuItem =
+ (query: string, propertyTreeExpanded: Record) => (itemProps: IContextualMenuItemProps) => {
+ const {
+ item: { secondaryText: path },
+ } = itemProps;
- const { onToggleExpand, level, node } = itemProps.item.data as {
- node: PropertyItem;
- onToggleExpand: (itemId: string, expanded: boolean) => void;
- level: number;
- };
+ const { onToggleExpand, level, node } = itemProps.item.data as {
+ node: PropertyItem;
+ onToggleExpand: (itemId: string, expanded: boolean) => void;
+ level: number;
+ };
- const renderLabel = () => {
- const pathNodes = (path ?? '').split('.');
- return (
-
- {pathNodes.map((pathNode, idx) => (
-
- {`${pathNode}${idx === pathNodes.length - 1 && node.children.length === 0 ? '' : '.'}`}
-
- ))}
+ const renderLabel = () => {
+ const pathNodes = (path ?? '').split('.');
+ return (
+
+ {pathNodes.map((pathNode, idx) => (
+
+ {`${pathNode}${idx === pathNodes.length - 1 && node.children.length === 0 ? '' : '.'}`}
+
+ ))}
+
+ );
+ };
+
+ const renderSearchResultLabel = () => (
+
+ {path}
);
- };
-
- const renderSearchResultLabel = () => (
-
- {path}
-
- );
- return (
-
- );
-};
+ return (
+
+ );
+ };
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/components/PropertyTreeItem.tsx b/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/components/PropertyTreeItem.tsx
index a5acdf2cd6..b2784ab088 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/components/PropertyTreeItem.tsx
+++ b/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/components/PropertyTreeItem.tsx
@@ -67,7 +67,7 @@ export const PropertyTreeItem = React.memo((props: PropertyTreeItemProps) => {
e.stopPropagation();
onToggleExpand?.(item.id, !expanded);
},
- [expanded, onToggleExpand, item]
+ [expanded, onToggleExpand, item],
);
const isExpandable = !!item.children?.length && onToggleExpand;
diff --git a/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/helpers.ts b/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/helpers.ts
index 1e3696297a..11acdf698e 100644
--- a/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/helpers.ts
+++ b/Composer/packages/client/src/pages/design/DebugPanel/WatchVariablePicker/utils/helpers.ts
@@ -40,7 +40,7 @@ export const computePropertyItemTree = (properties: readonly string[]): Property
n,
`${prefix}${prefix ? '.' : ''}${n.name}`,
items.filter((i) => i.startsWith(`${prefix}${prefix ? '.' : ''}${n.name}`)),
- level + 1
+ level + 1,
);
}
currentNode.children = children;
@@ -73,7 +73,7 @@ const getPath = (item: T
*/
export const getAllNodes = (
root: T,
- options?: Partial<{ expanded: Record; skipRoot: boolean }>
+ options?: Partial<{ expanded: Record; skipRoot: boolean }>,
): {
nodes: T[];
levels: Record;
diff --git a/Composer/packages/client/src/pages/design/DesignPage.tsx b/Composer/packages/client/src/pages/design/DesignPage.tsx
index 19d478ac35..a2ad4628a0 100644
--- a/Composer/packages/client/src/pages/design/DesignPage.tsx
+++ b/Composer/packages/client/src/pages/design/DesignPage.tsx
@@ -25,7 +25,7 @@ const splitContainer = css`
`;
const DesignPage: React.FC> = (
- props
+ props,
) => {
const { projectId = '', skillId, location } = props;
diff --git a/Composer/packages/client/src/pages/design/ManifestEditor.tsx b/Composer/packages/client/src/pages/design/ManifestEditor.tsx
index fa46b06e09..c5b32b27fe 100644
--- a/Composer/packages/client/src/pages/design/ManifestEditor.tsx
+++ b/Composer/packages/client/src/pages/design/ManifestEditor.tsx
@@ -6,6 +6,8 @@ import { jsx, css } from '@emotion/react';
import formatMessage from 'format-message';
import ErrorBoundary from 'react-error-boundary';
import React from 'react';
+import { useRecoilValue } from 'recoil';
+import { useShellApi } from '@bfc/extension-client';
import { LoadingTimeout } from '@bfc/adaptive-form/lib/components/LoadingTimeout';
import { FieldLabel } from '@bfc/adaptive-form/lib/components/FieldLabel';
import ErrorInfo from '@bfc/adaptive-form/lib/components/ErrorInfo';
@@ -15,7 +17,8 @@ import { DetailsList, DetailsListLayoutMode, SelectionMode } from '@fluentui/rea
import { Link } from '@fluentui/react/lib/Link';
import get from 'lodash/get';
-import { SkillInfo } from '../../recoilModel';
+import { SkillInfo, skillNameIdentifierByProjectIdSelector } from '../../recoilModel';
+import { isExternalLink } from '../../utils/urlUtil';
import { formEditor } from './styles';
import { PropertyEditorHeader } from './PropertyEditorHeader';
@@ -82,6 +85,12 @@ export const ManifestEditor: React.FC = (props) => {
const { formData } = props;
const { manifest } = formData;
+ const skillsByProjectId = useRecoilValue(skillNameIdentifierByProjectIdSelector);
+ const { shellApi } = useShellApi();
+
+ const skillNameIdentifier = skillsByProjectId[formData.id];
+ const { displayManifestModal } = shellApi;
+
if (!manifest) {
return (
@@ -117,9 +126,13 @@ export const ManifestEditor: React.FC = (props) => {
label={formatMessage('Manifest URL')}
/>
-
- {formData.location}
-
+ {isExternalLink(formData.location) ? (
+
+ {formData.location}
+
+ ) : (
+ manifest && displayManifestModal(skillNameIdentifier)}>{formData.location}
+ )}
diff --git a/Composer/packages/client/src/pages/design/Modals.tsx b/Composer/packages/client/src/pages/design/Modals.tsx
index 38a8bffba1..0dba06553f 100644
--- a/Composer/packages/client/src/pages/design/Modals.tsx
+++ b/Composer/packages/client/src/pages/design/Modals.tsx
@@ -146,7 +146,7 @@ const Modals: React.FC = ({ projectId = '', rootBotId = '' }) => {
await addRemoteSkillToBotProject(manifestUrl, endpointName, zipContent);
}}
addTriggerToRoot={async (dialogId, formData, skillId) => {
- await createTriggerForRemoteSkill(projectId, dialogId, formData, skillId);
+ await createTriggerForRemoteSkill(rootBotId, dialogId, formData, skillId);
commitChanges();
}}
projectId={rootBotId}
diff --git a/Composer/packages/client/src/pages/design/PropertyEditor.tsx b/Composer/packages/client/src/pages/design/PropertyEditor.tsx
index efbd961d4d..107d08a5ad 100644
--- a/Composer/packages/client/src/pages/design/PropertyEditor.tsx
+++ b/Composer/packages/client/src/pages/design/PropertyEditor.tsx
@@ -58,7 +58,7 @@ const PropertyEditor: React.FC = () => {
if (!isEqual(shellData, localData)) {
setLocalData(shellData);
}
- }, 300)
+ }, 300),
).current;
useEffect(() => {
diff --git a/Composer/packages/client/src/pages/design/PropertyPanel.tsx b/Composer/packages/client/src/pages/design/PropertyPanel.tsx
index 3648cc65dc..27f6fe66a2 100644
--- a/Composer/packages/client/src/pages/design/PropertyPanel.tsx
+++ b/Composer/packages/client/src/pages/design/PropertyPanel.tsx
@@ -43,7 +43,7 @@ const PropertyPanel: React.FC = React.memo(({ projectId = '',
const skillNameIdentifier = skillsByProjectId[projectId];
return skills[skillNameIdentifier];
- }, [skills, isSkill, skillsByProjectId]);
+ }, [projectId, skills, isSkill, skillsByProjectId]);
const shellForPropertyEditor = useShell('PropertyEditor', projectId);
diff --git a/Composer/packages/client/src/pages/design/SideBar.tsx b/Composer/packages/client/src/pages/design/SideBar.tsx
index bf6c799c21..cf3f79c229 100644
--- a/Composer/packages/client/src/pages/design/SideBar.tsx
+++ b/Composer/packages/client/src/pages/design/SideBar.tsx
@@ -95,7 +95,7 @@ const SideBar: React.FC = React.memo(({ projectId }) => {
const skillUsedInBotsMap = useRecoilValue(skillUsedInBotsSelector);
const selected = decodeDesignerPathToArrayPath(
dialogs.find((x) => x.id === dialogId)?.content,
- encodedSelected || ''
+ encodedSelected || '',
);
const setTriggerModalInfo = useSetRecoilState(triggerModalInfoState);
@@ -185,7 +185,7 @@ const SideBar: React.FC = React.memo(({ projectId }) => {
const content = DialogdeleteTrigger(projectDialogsMap[projectId], dialogId, index, async (trigger) => {
await deleteTrigger(projectId, dialogId, trigger);
announce(
- formatMessage(`The trigger {triggerName} has been deleted`, { triggerName: trigger.$designer?.name ?? '' })
+ formatMessage(`The trigger {triggerName} has been deleted`, { triggerName: trigger.$designer?.name ?? '' }),
);
});
diff --git a/Composer/packages/client/src/pages/design/__tests__/PropertyEditorHeader.test.tsx b/Composer/packages/client/src/pages/design/__tests__/PropertyEditorHeader.test.tsx
index 11133b8265..82ba64c63b 100644
--- a/Composer/packages/client/src/pages/design/__tests__/PropertyEditorHeader.test.tsx
+++ b/Composer/packages/client/src/pages/design/__tests__/PropertyEditorHeader.test.tsx
@@ -43,7 +43,7 @@ describe(' ', () => {
};
const helpLink = 'https://botframework-skill/manifest';
const { findByText } = render(
-
+ ,
);
expect(findByText('Remote Skill'));
expect(findByText('Learn more'));
diff --git a/Composer/packages/client/src/pages/design/__tests__/WatchTabContent.test.tsx b/Composer/packages/client/src/pages/design/__tests__/WatchTabContent.test.tsx
index f62348cee5..a264f39727 100644
--- a/Composer/packages/client/src/pages/design/__tests__/WatchTabContent.test.tsx
+++ b/Composer/packages/client/src/pages/design/__tests__/WatchTabContent.test.tsx
@@ -31,7 +31,7 @@ describe(' ', () => {
isRootBot: true,
isRemote: false,
});
- }
+ },
);
const addButton = await findByText('Add property');
const removeButton = await findByText('Remove from list');
diff --git a/Composer/packages/client/src/pages/design/__tests__/WebChatLogItemHeader.test.tsx b/Composer/packages/client/src/pages/design/__tests__/WebChatLogItemHeader.test.tsx
index 69240c6892..aab7d65284 100644
--- a/Composer/packages/client/src/pages/design/__tests__/WebChatLogItemHeader.test.tsx
+++ b/Composer/packages/client/src/pages/design/__tests__/WebChatLogItemHeader.test.tsx
@@ -46,7 +46,7 @@ describe(' ', () => {
response: { payload: {}, statusCode: 400 },
},
]);
- }
+ },
);
await findByTestId('DebugErrorIndicator');
@@ -73,7 +73,7 @@ describe(' ', () => {
response: { payload: {}, statusCode: 400 },
},
]);
- })
+ }),
);
expect(queryByTestId('DebugErrorIndicator')).toBeNull();
});
diff --git a/Composer/packages/client/src/pages/design/createDialogModal.tsx b/Composer/packages/client/src/pages/design/createDialogModal.tsx
index 84322a5681..bb7311413b 100644
--- a/Composer/packages/client/src/pages/design/createDialogModal.tsx
+++ b/Composer/packages/client/src/pages/design/createDialogModal.tsx
@@ -103,7 +103,7 @@ export const CreateDialogModal: React.FC = (props) => {
onSubmit(formData.name, dialogData);
TelemetryClient.track('AddNewDialogCompleted');
},
- [hasErrors, formData]
+ [hasErrors, formData],
);
return (
diff --git a/Composer/packages/client/src/pages/design/exportSkillModal/__tests__/generateSkillManifest.test.ts b/Composer/packages/client/src/pages/design/exportSkillModal/__tests__/generateSkillManifest.test.ts
index 0106f803e0..fe91a79eb3 100644
--- a/Composer/packages/client/src/pages/design/exportSkillModal/__tests__/generateSkillManifest.test.ts
+++ b/Composer/packages/client/src/pages/design/exportSkillModal/__tests__/generateSkillManifest.test.ts
@@ -63,7 +63,7 @@ describe('generateOtherActivities', () => {
conversationUpdate: {
type: 'conversationUpdate',
},
- })
+ }),
);
expect(generateOtherActivities(SDKKinds.OnEndOfConversationActivity)).toEqual(
@@ -71,7 +71,7 @@ describe('generateOtherActivities', () => {
endOfConversation: {
type: 'endOfConversation',
},
- })
+ }),
);
expect(generateOtherActivities(SDKKinds.OnIntent)).toEqual(
@@ -79,7 +79,7 @@ describe('generateOtherActivities', () => {
message: {
type: 'message',
},
- })
+ }),
);
});
});
@@ -95,7 +95,7 @@ describe('generateActivity', () => {
type: 'event',
name: 'test',
},
- })
+ }),
);
});
@@ -126,7 +126,7 @@ describe('generateActivity', () => {
},
},
},
- })
+ }),
);
});
});
@@ -161,7 +161,7 @@ describe('generateActivities', () => {
resultValue: expect.any(Object),
}),
},
- })
+ }),
);
});
});
@@ -184,7 +184,7 @@ describe('getDefinitions', () => {
equalsExpression: expect.any(Object),
integerExpression: expect.any(Object),
},
- })
+ }),
);
});
});
@@ -203,7 +203,7 @@ describe('generateDispatchModels', () => {
luFiles,
qnaFiles,
currentTarget,
- projectId
+ projectId,
);
expect(result).toEqual({});
});
@@ -224,7 +224,7 @@ describe('generateDispatchModels', () => {
luFiles,
qnaFiles,
currentTarget,
- projectId
+ projectId,
);
expect(result).toEqual({});
});
@@ -245,7 +245,7 @@ describe('generateDispatchModels', () => {
luFiles,
qnaFiles,
currentTarget,
- projectId
+ projectId,
);
expect(result).toEqual({});
});
@@ -266,7 +266,7 @@ describe('generateDispatchModels', () => {
luFiles,
qnaFiles,
currentTarget,
- projectId
+ projectId,
);
expect(result).toEqual(
expect.objectContaining({
@@ -299,7 +299,7 @@ describe('generateDispatchModels', () => {
],
},
},
- })
+ }),
);
});
});
diff --git a/Composer/packages/client/src/pages/design/exportSkillModal/constants.tsx b/Composer/packages/client/src/pages/design/exportSkillModal/constants.tsx
index ccce90dc4f..63aa4779b1 100644
--- a/Composer/packages/client/src/pages/design/exportSkillModal/constants.tsx
+++ b/Composer/packages/client/src/pages/design/exportSkillModal/constants.tsx
@@ -178,7 +178,7 @@ export const editorSteps: { [key in ManifestEditorSteps]: EditorStep } = {
title: () => formatMessage('Export your bot'),
subText: () =>
formatMessage(
- 'A skill is a bot that can perform a set of tasks one or more bots. To make your bot available as a skill, it needs a manifest - a JSON file that describes the actions the skill can perform.'
+ 'A skill is a bot that can perform a set of tasks one or more bots. To make your bot available as a skill, it needs a manifest - a JSON file that describes the actions the skill can perform.',
),
validate,
},
@@ -190,13 +190,7 @@ export const editorSteps: { [key in ManifestEditorSteps]: EditorStep } = {
disabled: ({ publishTarget }) => {
try {
const config = JSON.parse(publishTarget.configuration);
- return !(
- config.settings &&
- config.settings.MicrosoftAppId &&
- config.hostname &&
- config.settings.MicrosoftAppId.length > 0 &&
- config.hostname.length > 0
- );
+ return !(config.settings?.MicrosoftAppId?.length > 0 && config.hostname?.length > 0);
} catch (err) {
console.log(err.message);
return true;
@@ -205,11 +199,13 @@ export const editorSteps: { [key in ManifestEditorSteps]: EditorStep } = {
primary: true,
text: () => formatMessage('Generate and Publish'),
- onClick: ({ generateManifest, onNext, onPublish }) => () => {
- generateManifest();
- onNext({ dismiss: true, save: true });
- onPublish();
- },
+ onClick:
+ ({ generateManifest, onNext, onPublish }) =>
+ () => {
+ generateManifest();
+ onNext({ dismiss: true, save: true });
+ onPublish();
+ },
},
],
editJson: false,
@@ -225,17 +221,19 @@ export const editorSteps: { [key in ManifestEditorSteps]: EditorStep } = {
{
primary: true,
text: () => formatMessage('Next'),
- onClick: ({ onNext, onSaveSkill }) => () => {
- onSaveSkill();
- onNext();
- },
+ onClick:
+ ({ onNext, onSaveSkill }) =>
+ () => {
+ onSaveSkill();
+ onNext();
+ },
},
],
editJson: false,
content: AddCallers,
subText: () =>
formatMessage(
- 'To ensure a secure connection, provide the App ID of the bots that can connect to your skill. If you don’t have this information, you can also add this information in Skill Configuration.'
+ 'To ensure a secure connection, provide the App ID of the bots that can connect to your skill. If you don’t have this information, you can also add this information in Skill Configuration.',
),
title: () => formatMessage('Which bots can connect to this skill?'),
helpLink,
@@ -268,7 +266,7 @@ export const editorSteps: { [key in ManifestEditorSteps]: EditorStep } = {
editJson: false,
subText: () =>
formatMessage(
- 'The capabilities of your bot are defined in its dialogs and triggers. Selected dialogs will be included in the manifest. Internal dialogs or actions may not be relevant to other bots.'
+ 'The capabilities of your bot are defined in its dialogs and triggers. Selected dialogs will be included in the manifest. Internal dialogs or actions may not be relevant to other bots.',
),
title: () => formatMessage('Select dialogs'),
helpLink,
@@ -280,9 +278,11 @@ export const editorSteps: { [key in ManifestEditorSteps]: EditorStep } = {
{
primary: true,
text: () => formatMessage('Next'),
- onClick: ({ onNext }) => () => {
- onNext();
- },
+ onClick:
+ ({ onNext }) =>
+ () => {
+ onNext();
+ },
},
],
content: SelectTriggers,
diff --git a/Composer/packages/client/src/pages/design/exportSkillModal/content/Description.tsx b/Composer/packages/client/src/pages/design/exportSkillModal/content/Description.tsx
index c0b57c22fd..6fbf8c4233 100644
--- a/Composer/packages/client/src/pages/design/exportSkillModal/content/Description.tsx
+++ b/Composer/packages/client/src/pages/design/exportSkillModal/content/Description.tsx
@@ -97,7 +97,7 @@ export const Description: React.FC = ({
properties: { ...properties, [key]: { field: InlineLabelField, hideError: true, serializer } },
};
},
- { hidden: [], properties: {} } as any
+ { hidden: [], properties: {} } as any,
);
}, [schema]);
diff --git a/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectDialogs.tsx b/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectDialogs.tsx
index 4d8f839697..c017b4e8c0 100644
--- a/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectDialogs.tsx
+++ b/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectDialogs.tsx
@@ -14,9 +14,10 @@ import { SelectItems } from './SelectItems';
export const SelectDialogs: React.FC = ({ selectedDialogs, setSelectedDialogs, projectId }) => {
const dialogs = useRecoilValue(dialogsSelectorFamily(projectId));
- const items = useMemo(() => dialogs.map(({ id, content, displayName }) => ({ id, content, displayName })), [
- projectId,
- ]);
+ const items = useMemo(
+ () => dialogs.map(({ id, content, displayName }) => ({ id, content, displayName })),
+ [projectId],
+ );
// for detail file list in open panel
const tableColumns = useMemo(
@@ -39,17 +40,17 @@ export const SelectDialogs: React.FC = ({ selectedDialogs, setSele
isPadded: true,
},
],
- [projectId]
+ [projectId],
);
const selectionRef = useRef(
- new Selection({
+ new Selection({
getKey: (item) => item.id,
onSelectionChanged: () => {
const selectedItems = selectionRef.current.getSelection();
setSelectedDialogs(selectedItems);
},
- })
+ }),
);
useEffect(() => {
diff --git a/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectProfile.tsx b/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectProfile.tsx
index e460445f9d..f7d0e64c78 100644
--- a/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectProfile.tsx
+++ b/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectProfile.tsx
@@ -110,7 +110,7 @@ export const SelectProfile: React.FC = ({
});
setCurrentTarget(target);
},
- [publishingTargets]
+ [publishingTargets],
);
useEffect(() => {
@@ -147,22 +147,17 @@ export const SelectProfile: React.FC = ({
try {
const config = JSON.parse(publishTarget.configuration);
- return (
- config.settings &&
- config.settings.MicrosoftAppId &&
- config.hostname &&
- config.settings.MicrosoftAppId.length > 0 &&
- config.hostname.length > 0
- );
+ return config.settings?.MicrosoftAppId?.length > 0 && config.hostname?.length > 0;
} catch (err) {
console.log(err.message);
return false;
}
};
- const hasValidProfile = useMemo(() => !!publishingTargets.some((target) => isValidProfile(target)), [
- publishingTargets,
- ]);
+ const hasValidProfile = useMemo(
+ () => !!publishingTargets.some((target) => isValidProfile(target)),
+ [publishingTargets],
+ );
const publishingOptions = useMemo(() => {
return publishingTargets.map((t) => ({
diff --git a/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectTriggers.tsx b/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectTriggers.tsx
index 200674b24b..08df556de6 100644
--- a/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectTriggers.tsx
+++ b/Composer/packages/client/src/pages/design/exportSkillModal/content/SelectTriggers.tsx
@@ -35,8 +35,8 @@ export const SelectTriggers: React.FC = ({ selectedTriggers, setSe
? 1
: -1
: a.type > b.type
- ? 1
- : -1
+ ? 1
+ : -1,
);
}, [dialogs]);
@@ -81,13 +81,13 @@ export const SelectTriggers: React.FC = ({ selectedTriggers, setSe
];
const selectionRef = useRef(
- new Selection({
+ new Selection({
getKey: (item) => item.id,
onSelectionChanged: () => {
const selectedItems = selectionRef.current.getSelection();
setSelectedTriggers(selectedItems);
},
- })
+ }),
);
useEffect(() => {
diff --git a/Composer/packages/client/src/pages/design/exportSkillModal/generateSkillManifest.ts b/Composer/packages/client/src/pages/design/exportSkillModal/generateSkillManifest.ts
index 6984908364..44e5bde3b1 100644
--- a/Composer/packages/client/src/pages/design/exportSkillModal/generateSkillManifest.ts
+++ b/Composer/packages/client/src/pages/design/exportSkillModal/generateSkillManifest.ts
@@ -33,7 +33,7 @@ export const generateSkillManifest = (
selectedTriggers: ITrigger[],
selectedDialogs: Partial[],
currentTarget: PublishTarget,
- projectId: string
+ projectId: string,
) => {
const {
activities: previousActivities,
@@ -71,7 +71,7 @@ export const generateSkillManifest = (
export const generateActivities = (
dialogSchemas: DialogSchemaFile[],
triggers: ITrigger[],
- dialogs: DialogInfo[]
+ dialogs: DialogInfo[],
): { activities?: { [name: string]: Activity } } => {
const dialogActivities = dialogs.reduce((acc: any, dialog) => {
const activity = generateActivity(dialogSchemas, dialog);
@@ -120,7 +120,7 @@ export const generateDispatchModels = (
luFiles: LuFile[],
qnaFiles: QnAFile[],
target: PublishTarget,
- projectId: string
+ projectId: string,
): { dispatchModels?: DispatchModels } => {
const intents = selectedTriggers.filter(({ $kind }) => $kind === SDKKinds.OnIntent).map(({ intent }) => intent);
const { id: rootId } = dialogs.find((dialog) => dialog?.isRoot) || {};
@@ -214,7 +214,7 @@ export const generateDispatchModels = (
export const getDefinitions = (
dialogSchema: DialogSchemaFile[],
- selectedDialogs: DialogInfo[]
+ selectedDialogs: DialogInfo[],
): { definitions?: { [key: string]: any } } => {
const definitions = dialogSchema.reduce((acc, { content = {}, id }) => {
if (selectedDialogs.some(({ id: dialogId }) => dialogId === id)) {
diff --git a/Composer/packages/client/src/pages/design/exportSkillModal/index.tsx b/Composer/packages/client/src/pages/design/exportSkillModal/index.tsx
index a3d0423004..133e85ba04 100644
--- a/Composer/packages/client/src/pages/design/exportSkillModal/index.tsx
+++ b/Composer/packages/client/src/pages/design/exportSkillModal/index.tsx
@@ -80,7 +80,7 @@ const ExportSkillModal: React.FC = ({ onSubmit, onDismiss
const { setSettings } = useRecoilValue(dispatcherState);
const isAdaptive = isUsingAdaptiveRuntime(runtime);
const [callers, setCallers] = useState(
- !isAdaptive ? skillConfiguration?.allowedCallers : runtimeSettings?.skills?.allowedCallers ?? []
+ !isAdaptive ? skillConfiguration?.allowedCallers : runtimeSettings?.skills?.allowedCallers ?? [],
);
const [isCreateProfileFromSkill, setIsCreateProfileFromSkill] = useState(false);
@@ -92,7 +92,7 @@ const ExportSkillModal: React.FC = ({ onSubmit, onDismiss
};
// stop polling updater
const stopUpdater = () => {
- publishUpdaterRef.current && publishUpdaterRef.current.stop();
+ publishUpdaterRef.current?.stop?.();
publishUpdaterRef.current = undefined;
resetDialog();
};
@@ -131,13 +131,7 @@ const ExportSkillModal: React.FC = ({ onSubmit, onDismiss
if (!publishTargets || publishTargets.length === 0) return;
const currentTarget = publishTargets.find((item) => {
const config = JSON.parse(item.configuration);
- return (
- config.settings &&
- config.settings.MicrosoftAppId &&
- config.hostname &&
- config.settings.MicrosoftAppId.length > 0 &&
- config.hostname.length > 0
- );
+ return config.settings?.MicrosoftAppId?.length > 0 && config.hostname?.length > 0;
});
if (isCreateProfileFromSkill && currentTarget) {
handleGenerateManifest(currentTarget);
@@ -185,7 +179,7 @@ const ExportSkillModal: React.FC = ({ onSubmit, onDismiss
};
setSettings(projectId, updatedSetting);
},
- [mergedSettings, projectId, isAdaptive, skillConfiguration, runtimeSettings]
+ [mergedSettings, projectId, isAdaptive, skillConfiguration, runtimeSettings],
);
const handleGenerateManifest = (currentTarget?: PublishTarget) => {
@@ -199,7 +193,7 @@ const ExportSkillModal: React.FC = ({ onSubmit, onDismiss
selectedTriggers,
selectedDialogs,
currentTarget || currentPublishTarget,
- projectId
+ projectId,
);
setSkillManifest(manifest);
if (manifest.content && manifest.id) {
@@ -233,7 +227,7 @@ const ExportSkillModal: React.FC = ({ onSubmit, onDismiss
selectedTriggers,
selectedDialogs,
currentPublishTarget,
- projectId
+ projectId,
);
if (manifest.content && manifest.id) {
updateSkillManifest(manifest as SkillManifestFile, projectId);
diff --git a/Composer/packages/client/src/pages/design/exportSkillModal/styles.ts b/Composer/packages/client/src/pages/design/exportSkillModal/styles.ts
index 86f916e049..6a47c26b5e 100644
--- a/Composer/packages/client/src/pages/design/exportSkillModal/styles.ts
+++ b/Composer/packages/client/src/pages/design/exportSkillModal/styles.ts
@@ -23,7 +23,7 @@ export const styles = {
width: '960px !important',
},
scrollableContent: {
- overflow: 'hidden' as 'hidden',
+ overflow: 'hidden' as const,
},
},
container: css`
diff --git a/Composer/packages/client/src/pages/design/useEmptyPropsHandler.tsx b/Composer/packages/client/src/pages/design/useEmptyPropsHandler.tsx
index 1819a7d4ce..343e242434 100644
--- a/Composer/packages/client/src/pages/design/useEmptyPropsHandler.tsx
+++ b/Composer/packages/client/src/pages/design/useEmptyPropsHandler.tsx
@@ -34,7 +34,7 @@ export const useEmptyPropsHandler = (
projectId: string,
location?: WindowLocation,
skillId?: string,
- dialogId?: string
+ dialogId?: string,
) => {
const activeBot = skillId ?? projectId;
@@ -42,13 +42,13 @@ export const useEmptyPropsHandler = (
const locale = useRecoilValue(localeState(activeBot));
const settings = useRecoilValue(settingsState(activeBot));
const [currentLg, setCurrentLg] = useRecoilState(
- lgFileState({ projectId: activeBot, lgFileId: `${dialogId}.${locale}` })
+ lgFileState({ projectId: activeBot, lgFileId: `${dialogId}.${locale}` }),
);
const [currentLu, setCurrentLu] = useRecoilState(
- luFileState({ projectId: activeBot, luFileId: `${dialogId}.${locale}` })
+ luFileState({ projectId: activeBot, luFileId: `${dialogId}.${locale}` }),
);
const [currentQna, setCurrentQna] = useRecoilState(
- qnaFileState({ projectId: activeBot, qnaFileId: `${dialogId}.${locale}` })
+ qnaFileState({ projectId: activeBot, qnaFileId: `${dialogId}.${locale}` }),
);
const lgFiles = useRecoilValue(lgFilesSelectorFamily(projectId));
const luFiles = useRecoilValue(luFilesSelectorFamily(projectId));
@@ -143,8 +143,8 @@ export const useEmptyPropsHandler = (
});
/* eslint-disable no-underscore-dangle */
- // @ts-ignore
- globalHistory._onTransitionComplete();
+ // @ts-expect-error undocumented API
+ globalHistory?._onTransitionComplete();
/* eslint-enable */
}, [location, activeBot, currentDialog, dialogId]);
};
diff --git a/Composer/packages/client/src/pages/extensions/ExtensionSearchResults.tsx b/Composer/packages/client/src/pages/extensions/ExtensionSearchResults.tsx
index 842e9ab0fb..add4ccc2d7 100644
--- a/Composer/packages/client/src/pages/extensions/ExtensionSearchResults.tsx
+++ b/Composer/packages/client/src/pages/extensions/ExtensionSearchResults.tsx
@@ -42,7 +42,7 @@ const ExtensionSearchResults: React.FC = (props) =>
onSelectionChanged: () => {
onSelect(selection.getSelection()[0] as ExtensionSearchResult);
},
- })
+ }),
).current;
const searchColumns: IColumn[] = [
diff --git a/Composer/packages/client/src/pages/extensions/ExtensionsPage.tsx b/Composer/packages/client/src/pages/extensions/ExtensionsPage.tsx
index abd1918767..2dd94d51df 100644
--- a/Composer/packages/client/src/pages/extensions/ExtensionsPage.tsx
+++ b/Composer/packages/client/src/pages/extensions/ExtensionsPage.tsx
@@ -54,7 +54,7 @@ const ExtensionsPage: React.FC = () => {
onSelectionChanged: () => {
setSelectedExtensions(selection.getSelection() as ExtensionMetadata[]);
},
- })
+ }),
).current;
const fetchSettings = async () => {
diff --git a/Composer/packages/client/src/pages/form-dialog/CreateFormDialogSchemaModal.tsx b/Composer/packages/client/src/pages/form-dialog/CreateFormDialogSchemaModal.tsx
index ec55a91903..40641dec8e 100644
--- a/Composer/packages/client/src/pages/form-dialog/CreateFormDialogSchemaModal.tsx
+++ b/Composer/packages/client/src/pages/form-dialog/CreateFormDialogSchemaModal.tsx
@@ -55,7 +55,7 @@ const CreateFormDialogSchemaModal: React.FC = (props) => {
onSubmit(formData.name);
},
- [hasErrors, formData]
+ [hasErrors, formData],
);
return (
@@ -74,7 +74,6 @@ const CreateFormDialogSchemaModal: React.FC = (props) => {
autoComplete="off"
errorMessage={formErrors.name}
label={formatMessage('Name')}
- styles={name}
value={formData.name}
onChange={(_e, val) => updateField('name', val)}
/>
diff --git a/Composer/packages/client/src/pages/form-dialog/FormDialogPage.tsx b/Composer/packages/client/src/pages/form-dialog/FormDialogPage.tsx
index acb7c974a9..06ce5c7689 100644
--- a/Composer/packages/client/src/pages/form-dialog/FormDialogPage.tsx
+++ b/Composer/packages/client/src/pages/form-dialog/FormDialogPage.tsx
@@ -63,9 +63,10 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
loadFormDialogSchemaTemplates();
}, []);
- const availableTemplates = React.useMemo(() => formDialogLibraryTemplates.filter((t) => !t.$global), [
- formDialogLibraryTemplates,
- ]);
+ const availableTemplates = React.useMemo(
+ () => formDialogLibraryTemplates.filter((t) => !t.$global),
+ [formDialogLibraryTemplates],
+ );
const validSchemaId = React.useMemo(() => formDialogSchemaIds.includes(schemaId), [formDialogSchemaIds, schemaId]);
@@ -79,7 +80,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
async (id: string) => {
const res = await OpenConfirmModal(
formatMessage('Delete form dialog schema?'),
- formatMessage('Are you sure you want to remove form dialog schema "{id}"?', { id })
+ formatMessage('Are you sure you want to remove form dialog schema "{id}"?', { id }),
);
if (res) {
removeFormDialogSchema({ id, projectId });
@@ -88,7 +89,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
}
}
},
- [selectItem, removeFormDialogSchema, schemaId]
+ [selectItem, removeFormDialogSchema, schemaId],
);
const generateDialog = React.useCallback(
@@ -108,7 +109,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
generateFormDialog({ projectId, schemaId });
}
},
- [generateFormDialog, projectId]
+ [generateFormDialog, projectId],
);
const viewDialog = React.useCallback(
@@ -117,7 +118,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
navigateToGeneratedDialog({ projectId, schemaId });
}
},
- [navigateToGeneratedDialog, projectId]
+ [navigateToGeneratedDialog, projectId],
);
React.useEffect(() => {
@@ -143,7 +144,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
label: formatMessage('View dialog'),
onClick: () => generatingSchemaId && viewDialog(generatingSchemaId),
},
- })
+ }),
);
} else {
// error, show failed message with error.
@@ -152,7 +153,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
type: 'error',
title: formatMessage('Dialog generation has failed.'),
description: formDialogError.message,
- })
+ }),
);
}
} else {
@@ -164,7 +165,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
type: 'error',
title: formatMessage('Form dialog error'),
description: formDialogError.message,
- })
+ }),
);
}
}
@@ -176,7 +177,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
updateFormDialogSchema({ id, content, projectId });
}
},
- [updateFormDialogSchema, schemaId]
+ [updateFormDialogSchema, schemaId],
);
const createItem = React.useCallback(
@@ -184,7 +185,7 @@ const FormDialogPage: React.FC = React.memo((props: Props) => {
createFormDialogSchema({ id: formDialogName, projectId });
setCreateSchemaDialogOpen(false);
},
- [createFormDialogSchema, setCreateSchemaDialogOpen]
+ [createFormDialogSchema, setCreateSchemaDialogOpen],
);
const onMeasuredSizesChanged = (sizes: SplitMeasuredSizes) => {
diff --git a/Composer/packages/client/src/pages/form-dialog/FormDialogSchemaList.tsx b/Composer/packages/client/src/pages/form-dialog/FormDialogSchemaList.tsx
index acd1706502..14eeb42d66 100644
--- a/Composer/packages/client/src/pages/form-dialog/FormDialogSchemaList.tsx
+++ b/Composer/packages/client/src/pages/form-dialog/FormDialogSchemaList.tsx
@@ -59,7 +59,7 @@ const Root = styled(Stack)<{
zIndex: 1,
},
}
- : null
+ : null,
);
const oneLinerStyles = classNamesFunction()({
@@ -110,7 +110,7 @@ const FormDialogSchemaItem = React.memo((props: FormDialogSchemaItemProps) => {
onDelete(schemaId);
},
- [schemaId, onDelete]
+ [schemaId, onDelete],
);
const generateDialog = React.useCallback(
@@ -119,7 +119,7 @@ const FormDialogSchemaItem = React.memo((props: FormDialogSchemaItemProps) => {
onGenerate(schemaId);
},
- [schemaId, onGenerate]
+ [schemaId, onGenerate],
);
const viewDialog = React.useCallback(
@@ -128,12 +128,12 @@ const FormDialogSchemaItem = React.memo((props: FormDialogSchemaItemProps) => {
onViewDialog(schemaId);
},
- [schemaId, onViewDialog]
+ [schemaId, onViewDialog],
);
const renderOverflowItem = React.useCallback(
(item: IOverflowSetItemProps) => ,
- []
+ [],
);
const renderOverflowButton = React.useCallback(
@@ -150,7 +150,7 @@ const FormDialogSchemaItem = React.memo((props: FormDialogSchemaItemProps) => {
/>
),
- []
+ [],
);
return (
@@ -245,7 +245,7 @@ export const FormDialogSchemaList: React.FC = React.m
onViewDialog={onViewDialog}
/>
),
- [selectedId, onSelectItem, onDeleteItem, onGenerate]
+ [selectedId, onSelectItem, onDeleteItem, onGenerate],
);
return (
@@ -270,7 +270,7 @@ export const FormDialogSchemaList: React.FC = React.m
0 {}
other {Press down arrow key to navigate the search results}
}`,
- { itemCount: items.length }
+ { itemCount: items.length },
)}
aria-live="polite"
/>
diff --git a/Composer/packages/client/src/pages/form-dialog/VisualFormDialogSchemaEditor.tsx b/Composer/packages/client/src/pages/form-dialog/VisualFormDialogSchemaEditor.tsx
index ebe39da145..4c2e87d422 100644
--- a/Composer/packages/client/src/pages/form-dialog/VisualFormDialogSchemaEditor.tsx
+++ b/Composer/packages/client/src/pages/form-dialog/VisualFormDialogSchemaEditor.tsx
@@ -37,7 +37,7 @@ const Root = styled(Stack)<{
background: 'rgba(255,255,255, 0.6)',
},
}
- : null
+ : null,
);
const noop = () => {};
diff --git a/Composer/packages/client/src/pages/home/CardWidget.tsx b/Composer/packages/client/src/pages/home/CardWidget.tsx
index 74f2174470..3ca910861c 100644
--- a/Composer/packages/client/src/pages/home/CardWidget.tsx
+++ b/Composer/packages/client/src/pages/home/CardWidget.tsx
@@ -54,8 +54,8 @@ export const CardWidget: React.FC = ({
rest.styles || cardType === 'resource'
? home.cardItem
: imageCover
- ? home.mediaCardItem
- : home.mediaCardNoCoverItem;
+ ? home.mediaCardItem
+ : home.mediaCardNoCoverItem;
const onImageLoading = (state: ImageLoadState) => {
if (state === ImageLoadState.error) {
diff --git a/Composer/packages/client/src/pages/home/Home.tsx b/Composer/packages/client/src/pages/home/Home.tsx
index 4153e0a6da..faba43721d 100644
--- a/Composer/packages/client/src/pages/home/Home.tsx
+++ b/Composer/packages/client/src/pages/home/Home.tsx
@@ -78,13 +78,8 @@ const Home: React.FC = () => {
const recentProjects = useRecoilValue(recentProjectsState);
const feed = useRecoilValue(feedState);
- const {
- openProject,
- setCreationFlowStatus,
- setCreationFlowType,
- setWarnAboutDotNet,
- setWarnAboutFunctions,
- } = useRecoilValue(dispatcherState);
+ const { openProject, setCreationFlowStatus, setCreationFlowType, setWarnAboutDotNet, setWarnAboutFunctions } =
+ useRecoilValue(dispatcherState);
const warnAboutDotNet = useRecoilValue(warnAboutDotNetState);
const warnAboutFunctions = useRecoilValue(warnAboutFunctionsState);
diff --git a/Composer/packages/client/src/pages/knowledge-base/QnAPage.tsx b/Composer/packages/client/src/pages/knowledge-base/QnAPage.tsx
index 5bc2b6cc43..84101aefdc 100644
--- a/Composer/packages/client/src/pages/knowledge-base/QnAPage.tsx
+++ b/Composer/packages/client/src/pages/knowledge-base/QnAPage.tsx
@@ -37,12 +37,14 @@ const qnaContentStyle = css`
padding: 0px;
`;
-const QnAPage: React.FC> = (props) => {
+const QnAPage: React.FC<
+ RouteComponentProps<{
+ dialogId: string;
+ projectId: string;
+ skillId: string;
+ qnaFileId: string;
+ }>
+> = (props) => {
const { dialogId = '', projectId = '', skillId, qnaFileId = '' } = props;
const actualProjectId = skillId ?? projectId;
@@ -89,7 +91,7 @@ const QnAPage: React.FC {
diff --git a/Composer/packages/client/src/pages/knowledge-base/TabHeader.tsx b/Composer/packages/client/src/pages/knowledge-base/TabHeader.tsx
index 8d4f2fafac..cfd818ab35 100644
--- a/Composer/packages/client/src/pages/knowledge-base/TabHeader.tsx
+++ b/Composer/packages/client/src/pages/knowledge-base/TabHeader.tsx
@@ -27,7 +27,7 @@ export const TabHeader: React.FC = (props) => {
const currentLocale = languageList.find(
(l) =>
(!l.isDefault && l.language === item.props.headerText) ||
- (l.isDefault && `${l.language}(Default)` === item.props.headerText)
+ (l.isDefault && `${l.language}(Default)` === item.props.headerText),
)?.locale as string;
setSelectedKey(languageList.findIndex((l) => l.locale === currentLocale));
onChangeLocale(currentLocale);
diff --git a/Composer/packages/client/src/pages/knowledge-base/code-editor.tsx b/Composer/packages/client/src/pages/knowledge-base/code-editor.tsx
index bbaad59e25..d143dd6d99 100644
--- a/Composer/packages/client/src/pages/knowledge-base/code-editor.tsx
+++ b/Composer/packages/client/src/pages/knowledge-base/code-editor.tsx
@@ -20,7 +20,7 @@ import TelemetryClient from '../../telemetry/TelemetryClient';
import { backIcon } from './styles';
import { qnaSuffix } from './table-view';
-interface CodeEditorProps extends RouteComponentProps<{}> {
+interface CodeEditorProps extends RouteComponentProps {
dialogId: string;
projectId: string;
locale: string;
@@ -84,7 +84,7 @@ const CodeEditor: React.FC = (props) => {
debounce((newContent: string) => {
actions.updateQnAFile({ id: targetFileId, content: newContent, projectId: actualProjectId });
}, 500),
- [actualProjectId]
+ [actualProjectId],
);
return (
diff --git a/Composer/packages/client/src/pages/knowledge-base/table-view.tsx b/Composer/packages/client/src/pages/knowledge-base/table-view.tsx
index 0a83714e7e..dcb9039471 100644
--- a/Composer/packages/client/src/pages/knowledge-base/table-view.tsx
+++ b/Composer/packages/client/src/pages/knowledge-base/table-view.tsx
@@ -162,7 +162,7 @@ const TableView: React.FC = (props) => {
const currentDialogImportedFileIds = qnaFile?.imports.map(({ id }) => `${getBaseName(id)}.${locale}`) || [];
const currentDialogImportedFiles = qnaFiles.filter(({ id }) => currentDialogImportedFileIds.includes(id));
const currentDialogImportedSourceFiles = currentDialogImportedFiles.filter(({ id }) =>
- id.endsWith(qnaSuffix(locale))
+ id.endsWith(qnaSuffix(locale)),
);
const allSourceFiles = qnaFiles.filter(({ id }) => id.endsWith(qnaSuffix(locale)));
@@ -171,7 +171,7 @@ const TableView: React.FC = (props) => {
const allSections = flatMap(
qnaFiles.filter(({ id }) => id.endsWith(qnaSuffix(locale))),
- generateQnASections
+ generateQnASections,
);
if (dialogId === 'all') {
return allSections;
@@ -188,7 +188,7 @@ const TableView: React.FC = (props) => {
const allSections = flatMap(
qnaFiles.filter(({ id }) => id.endsWith(qnaSuffix(locale))),
- generateQnASections
+ generateQnASections,
);
if (dialogId === 'all') {
setQnASections(allSections);
@@ -297,7 +297,7 @@ const TableView: React.FC = (props) => {
name: name,
projectId: actualProjectId,
});
- })
+ }),
);
if (!qnaFile) return;
@@ -309,7 +309,7 @@ const TableView: React.FC = (props) => {
newSourceId,
projectId: actualProjectId,
});
- })
+ }),
);
setEditQnAFile(undefined);
};
@@ -401,7 +401,7 @@ const TableView: React.FC = (props) => {
};
const title = formatMessage('Warning');
const subTitle = formatMessage(
- 'Deleting one source file will also delete qna files with the same name on other locales'
+ 'Deleting one source file will also delete qna files with the same name on other locales',
);
setting = {
@@ -521,7 +521,7 @@ const TableView: React.FC = (props) => {
return null;
},
- [dialogId, qnaSections]
+ [dialogId, qnaSections],
);
const getTableColums = () => {
@@ -875,7 +875,7 @@ const TableView: React.FC = (props) => {
);
},
- [dialogId]
+ [dialogId],
);
const onRenderRow = useCallback(
@@ -892,7 +892,7 @@ const TableView: React.FC = (props) => {
}
return null;
},
- [dialogId, expandedIndex]
+ [dialogId, expandedIndex],
);
const existedImports = qnaFile?.imports.filter((item) => {
diff --git a/Composer/packages/client/src/pages/language-generation/LGPage.tsx b/Composer/packages/client/src/pages/language-generation/LGPage.tsx
index 2fb1bd3d04..0dea831eba 100644
--- a/Composer/packages/client/src/pages/language-generation/LGPage.tsx
+++ b/Composer/packages/client/src/pages/language-generation/LGPage.tsx
@@ -7,36 +7,57 @@ import React, { Fragment, useCallback, Suspense, useEffect } from 'react';
import formatMessage from 'format-message';
import { ActionButton } from '@fluentui/react/lib/Button';
import { RouteComponentProps, Router } from '@reach/router';
-import { useRecoilValue } from 'recoil';
+import { useRecoilState, useRecoilValue } from 'recoil';
+import { LgFile } from '@botframework-composer/types';
import { LoadingSpinner } from '../../components/LoadingSpinner';
import { navigateTo } from '../../utils/navigation';
import { Page } from '../../components/Page';
-import { lgFilesSelectorFamily, localeState } from '../../recoilModel';
+import { lgFileState, lgFilesSelectorFamily, localeState } from '../../recoilModel';
import TelemetryClient from '../../telemetry/TelemetryClient';
+import lgWorker from '../../recoilModel/parsers/lgWorker';
import TableView from './table-view';
const CodeEditor = React.lazy(() => import('./code-editor'));
-const LGPage: React.FC> = (props) => {
+const LGPage: React.FC<
+ RouteComponentProps<{
+ dialogId: string;
+ projectId: string;
+ skillId: string;
+ lgFileId: string;
+ }>
+> = (props) => {
const { dialogId = '', projectId = '', skillId, lgFileId = '' } = props;
const actualProjectId = skillId ?? projectId;
const locale = useRecoilValue(localeState(actualProjectId));
const lgFiles = useRecoilValue(lgFilesSelectorFamily(skillId ?? projectId));
+ const [currentLg, setCurrentLg] = useRecoilState(
+ lgFileState({ projectId: actualProjectId, lgFileId: `${dialogId}.${locale}` }),
+ );
const path = props.location?.pathname ?? '';
const edit = /\/edit(\/)?$/.test(path);
const baseURL = skillId == null ? `/bot/${projectId}/` : `/bot/${projectId}/skill/${skillId}/`;
- const activeFile = lgFileId
- ? lgFiles.find(({ id }) => id === lgFileId || id === `${lgFileId}.${locale}`)
- : lgFiles.find(({ id }) => id === dialogId || id === `${dialogId}.${locale}`);
+ const getActiveFile = () => {
+ let lgFile: LgFile | undefined;
+ if (lgFileId) {
+ lgFile = lgFiles.find(({ id }) => id === lgFileId || id === `${lgFileId}.${locale}`);
+ } else {
+ lgFile = lgFiles.find(({ id }) => id === dialogId || id === `${dialogId}.${locale}`);
+ }
+ if (lgFile?.isContentUnparsed) {
+ lgWorker.parse(actualProjectId, currentLg.id, currentLg.content, lgFiles).then((result) => {
+ setCurrentLg(result as LgFile);
+ return currentLg;
+ });
+ }
+ return lgFile;
+ };
+
+ const activeFile = getActiveFile();
useEffect(() => {
if (!activeFile && lgFiles.length) {
@@ -52,7 +73,7 @@ const LGPage: React.FC {
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 c2d12ed6a7..ec6221d9a6 100644
--- a/Composer/packages/client/src/pages/language-generation/code-editor.tsx
+++ b/Composer/packages/client/src/pages/language-generation/code-editor.tsx
@@ -25,7 +25,7 @@ import { DiffCodeEditor } from '../language-understanding/diff-editor';
const lspServerPath = '/lg-language-server';
-interface CodeEditorProps extends RouteComponentProps<{}> {
+interface CodeEditorProps extends RouteComponentProps {
dialogId: string;
projectId: string;
skillId?: string;
@@ -66,8 +66,8 @@ const CodeEditor: React.FC = (props) => {
const templateId = Array.isArray(searchTemplateName)
? searchTemplateName[0]
: typeof searchTemplateName === 'string'
- ? searchTemplateName
- : undefined;
+ ? searchTemplateName
+ : undefined;
const template = templateId && file ? file.templates.find(({ name }) => name === templateId) : undefined;
const hash = props.location?.hash ?? '';
@@ -131,7 +131,7 @@ const CodeEditor: React.FC = (props) => {
};
updateLgTemplateDispatcher(payload);
}, 500),
- [file, template, actualProjectId]
+ [file, template, actualProjectId],
);
const updateLgFile = useMemo(
@@ -146,7 +146,7 @@ const CodeEditor: React.FC = (props) => {
};
updateLgFileDispatcher(payload);
}, 500),
- [file, actualProjectId]
+ [file, actualProjectId],
);
const onChange = useCallback(
@@ -163,7 +163,7 @@ const CodeEditor: React.FC = (props) => {
updateLgFile(value);
}
},
- [file, template, actualProjectId]
+ [file, template, actualProjectId],
);
const handleSettingsChange = (settings: Partial) => {
@@ -191,7 +191,7 @@ const CodeEditor: React.FC = (props) => {
}
navigateTo(url);
},
- [actualProjectId, locale]
+ [actualProjectId, locale],
);
const currentLanguageFileEditor = useMemo(() => {
diff --git a/Composer/packages/client/src/pages/language-generation/table-view.tsx b/Composer/packages/client/src/pages/language-generation/table-view.tsx
index 0ab0e95eff..28372e166e 100644
--- a/Composer/packages/client/src/pages/language-generation/table-view.tsx
+++ b/Composer/packages/client/src/pages/language-generation/table-view.tsx
@@ -16,18 +16,19 @@ import formatMessage from 'format-message';
import { NeutralColors, FontSizes } from '@fluentui/theme';
import { RouteComponentProps } from '@reach/router';
import { LgTemplate } from '@bfc/shared';
-import { useRecoilValue } from 'recoil';
+import { useRecoilState, useRecoilValue } from 'recoil';
import { lgUtil } from '@bfc/indexers';
import { LgFile } from '@botframework-composer/types/src';
import { EditableField } from '../../components/EditableField';
import { navigateTo } from '../../utils/navigation';
import { actionButton, editableFieldContainer } from '../language-understanding/styles';
-import { dispatcherState, localeState, settingsState, dialogsSelectorFamily } from '../../recoilModel';
+import { dispatcherState, localeState, settingsState, dialogsSelectorFamily, lgFileState } from '../../recoilModel';
import { languageListTemplates } from '../../components/MultiLanguage';
import TelemetryClient from '../../telemetry/TelemetryClient';
import { lgFilesSelectorFamily } from '../../recoilModel/selectors/lg';
import { CellFocusZone } from '../../components/CellFocusZone';
+import lgWorker from '../../recoilModel/parsers/lgWorker';
interface TableViewProps extends RouteComponentProps<{ dialogId: string; skillId: string; projectId: string }> {
projectId: string;
@@ -46,15 +47,31 @@ const TableView: React.FC = (props) => {
const locale = useRecoilValue(localeState(actualProjectId));
const settings = useRecoilValue(settingsState(actualProjectId));
const dialogs = useRecoilValue(dialogsSelectorFamily(actualProjectId));
- const { createLgTemplate, copyLgTemplate, removeLgTemplate, setMessage, updateLgTemplate } = useRecoilValue(
- dispatcherState
- );
+ const { createLgTemplate, copyLgTemplate, removeLgTemplate, setMessage, updateLgTemplate } =
+ useRecoilValue(dispatcherState);
const { languages, defaultLanguage } = settings;
+ const [defaultLg, setDefaultLg] = useRecoilState(
+ lgFileState({ projectId: actualProjectId, lgFileId: `${dialogId}.${defaultLanguage}` }),
+ );
+
+ const getDefaultLangFile = () => {
+ let lgFile: LgFile | undefined;
+ if (lgFileId) {
+ lgFile = lgFiles.find(({ id }) => id === lgFileId);
+ } else {
+ lgFile = lgFiles.find(({ id }) => id === `${dialogId}.${defaultLanguage}`);
+ }
+ if (lgFile?.isContentUnparsed) {
+ lgWorker.parse(actualProjectId, defaultLg.id, defaultLg.content, lgFiles).then((result) => {
+ setDefaultLg(result as LgFile);
+ return defaultLg;
+ });
+ }
+ return lgFile;
+ };
- const defaultLangFile = lgFileId
- ? lgFiles.find(({ id }) => id === lgFileId)
- : lgFiles.find(({ id }) => id === `${dialogId}.${defaultLanguage}`);
+ const defaultLangFile = getDefaultLangFile();
const [templates, setTemplates] = useState([]);
const listRef = useRef(null);
@@ -74,7 +91,7 @@ const TableView: React.FC = (props) => {
const baseURL = skillId == null ? `/bot/${projectId}/` : `/bot/${projectId}/skill/${skillId}/`;
navigateTo(`${baseURL}language-generation/${dialogId}/edit?t=${encodeURIComponent(name)}`);
},
- [dialogId, projectId, skillId]
+ [dialogId, projectId, skillId],
);
const onCreateNewTemplate = useCallback(() => {
@@ -103,7 +120,7 @@ const TableView: React.FC = (props) => {
removeLgTemplate(payload);
}
},
- [file, actualProjectId]
+ [file, actualProjectId],
);
const onCopyTemplate = useCallback(
@@ -119,7 +136,7 @@ const TableView: React.FC = (props) => {
copyLgTemplate(payload);
}
},
- [file, actualProjectId]
+ [file, actualProjectId],
);
const handleTemplateUpdate = useCallback(
@@ -134,7 +151,7 @@ const TableView: React.FC = (props) => {
updateLgTemplate(payload);
}
},
- [file, actualProjectId]
+ [file, actualProjectId],
);
const handleTemplateUpdateDefaultLocale = useCallback(
@@ -149,7 +166,7 @@ const TableView: React.FC = (props) => {
updateLgTemplate(payload);
}
},
- [defaultLangFile, actualProjectId]
+ [defaultLangFile, actualProjectId],
);
const getTemplatesMoreButtons = useCallback(
@@ -182,7 +199,7 @@ const TableView: React.FC = (props) => {
return buttons;
},
- [activeDialog, templates, onClickEdit, onRemoveTemplate, onCopyTemplate, setMessage]
+ [activeDialog, templates, onClickEdit, onRemoveTemplate, onCopyTemplate, setMessage],
);
const getTableColums = useCallback((): IColumn[] => {
@@ -387,7 +404,7 @@ const TableView: React.FC = (props) => {
// show compairable column when current lang is not default lang
if (locale === defaultLanguage) {
tableColums = tableColums.filter(
- ({ key }) => ['responses-default-lang', 'responses-lang'].includes(key) === false
+ ({ key }) => ['responses-default-lang', 'responses-lang'].includes(key) === false,
);
} else {
tableColums = tableColums.filter(({ key }) => ['responses'].includes(key) === false);
diff --git a/Composer/packages/client/src/pages/language-understanding/LUPage.tsx b/Composer/packages/client/src/pages/language-understanding/LUPage.tsx
index 2d3ed8dc9f..336c889217 100644
--- a/Composer/packages/client/src/pages/language-understanding/LUPage.tsx
+++ b/Composer/packages/client/src/pages/language-understanding/LUPage.tsx
@@ -17,12 +17,14 @@ import TableView from './table-view';
const CodeEditor = React.lazy(() => import('./code-editor'));
-const LUPage: React.FC> = (props) => {
+const LUPage: React.FC<
+ RouteComponentProps<{
+ dialogId: string;
+ projectId: string;
+ skillId: string;
+ luFileId: string;
+ }>
+> = (props) => {
const { dialogId = '', projectId = '', skillId, luFileId = '' } = props;
const actualProjectId = skillId ?? projectId;
const locale = useRecoilValue(localeState(actualProjectId));
diff --git a/Composer/packages/client/src/pages/language-understanding/code-editor.tsx b/Composer/packages/client/src/pages/language-understanding/code-editor.tsx
index 4db4524cae..4f7320245f 100644
--- a/Composer/packages/client/src/pages/language-understanding/code-editor.tsx
+++ b/Composer/packages/client/src/pages/language-understanding/code-editor.tsx
@@ -22,7 +22,7 @@ import { DiffCodeEditor } from './diff-editor';
const lspServerPath = '/lu-language-server';
-interface CodeEditorProps extends RouteComponentProps<{}> {
+interface CodeEditorProps extends RouteComponentProps {
dialogId: string;
projectId: string;
skillId?: string;
@@ -60,8 +60,8 @@ const CodeEditor: React.FC = (props) => {
const sectionId = Array.isArray(searchSectionName)
? searchSectionName[0]
: typeof searchSectionName === 'string'
- ? searchSectionName
- : undefined;
+ ? searchSectionName
+ : undefined;
const intent = sectionId && file ? file.intents.find(({ Name }) => Name === sectionId) : undefined;
const hash = props.location?.hash ?? '';
@@ -105,7 +105,7 @@ const CodeEditor: React.FC = (props) => {
};
updateLuIntentDispatcher(payload);
}, 500),
- [file, intent, actualProjectId]
+ [file, intent, actualProjectId],
);
const updateLuFile = useMemo(
@@ -120,7 +120,7 @@ const CodeEditor: React.FC = (props) => {
};
updateLuFileDispatcher(payload);
}, 500),
- [file, actualProjectId]
+ [file, actualProjectId],
);
const onChange = useCallback(
@@ -132,7 +132,7 @@ const CodeEditor: React.FC = (props) => {
updateLuFile(value);
}
},
- [file, intent, actualProjectId]
+ [file, intent, actualProjectId],
);
const luFeatures = settings?.luFeatures || {};
@@ -157,7 +157,7 @@ const CodeEditor: React.FC = (props) => {
: `/bot/${projectId}/language-understanding/${fileId}${sectionId ? `/edit?t=${sectionId}` : ''}`;
navigateTo(url);
},
- [projectId, locale, currentDialog]
+ [projectId, locale, currentDialog],
);
const currentLanguageFileEditor = useMemo(() => {
diff --git a/Composer/packages/client/src/pages/language-understanding/table-view.tsx b/Composer/packages/client/src/pages/language-understanding/table-view.tsx
index 59c62d4c5b..ef1f9f3820 100644
--- a/Composer/packages/client/src/pages/language-understanding/table-view.tsx
+++ b/Composer/packages/client/src/pages/language-understanding/table-view.tsx
@@ -144,7 +144,7 @@ const TableView: React.FC = (props) => {
};
updateLuIntent(payload);
},
- [actualProjectId]
+ [actualProjectId],
);
const handleTemplateUpdateDefaultLocale = useCallback(
@@ -159,7 +159,7 @@ const TableView: React.FC = (props) => {
updateLuIntent(payload);
}
},
- [defaultLangFile, actualProjectId]
+ [defaultLangFile, actualProjectId],
);
const getTemplatesMoreButtons = (item, index, luFileId): IContextualMenuItem[] => {
@@ -172,7 +172,7 @@ const TableView: React.FC = (props) => {
navigateTo(
`${baseURL}language-understanding/${dialogId}${
luFileId ? `/item/${luFileId}/` : '/'
- }edit?t=${encodeURIComponent(name)}`
+ }edit?t=${encodeURIComponent(name)}`,
);
},
},
diff --git a/Composer/packages/client/src/pages/plugin/PluginPageContainer.tsx b/Composer/packages/client/src/pages/plugin/PluginPageContainer.tsx
index 1159393e5e..e910daaa1c 100644
--- a/Composer/packages/client/src/pages/plugin/PluginPageContainer.tsx
+++ b/Composer/packages/client/src/pages/plugin/PluginPageContainer.tsx
@@ -7,7 +7,7 @@ import { RouteComponentProps } from '@reach/router';
import { PluginHost } from '../../components/PluginHost/PluginHost';
const PluginPageContainer: React.FC> = (
- props
+ props,
) => {
const { pluginId, bundleId, projectId } = props;
diff --git a/Composer/packages/client/src/pages/publish/BotStatusList.tsx b/Composer/packages/client/src/pages/publish/BotStatusList.tsx
index 8b5ad34eff..0a819da6c3 100644
--- a/Composer/packages/client/src/pages/publish/BotStatusList.tsx
+++ b/Composer/packages/client/src/pages/publish/BotStatusList.tsx
@@ -101,13 +101,12 @@ export const BotStatusList: React.FC = ({
const getPublishTargetOptions = (item: BotStatus): IDropdownOption[] => {
const options: IDropdownOption[] = [];
- item.publishTargets &&
- item.publishTargets.forEach((target, index) => {
- options.push({
- key: target.name,
- text: target.name,
- });
+ item.publishTargets?.forEach((target, index) => {
+ options.push({
+ key: target.name,
+ text: target.name,
});
+ });
options.push({
key: 'manageProfiles',
text: formatMessage('Manage profiles'),
@@ -130,7 +129,7 @@ export const BotStatusList: React.FC = ({
const handleChangePublishTarget = (
event: React.FormEvent,
item: BotStatus,
- option?: IDropdownOption
+ option?: IDropdownOption,
): void => {
if (option) {
if (option.key === 'manageProfiles') {
diff --git a/Composer/packages/client/src/pages/publish/Notifications.tsx b/Composer/packages/client/src/pages/publish/Notifications.tsx
index f983179d79..9f77225ab1 100644
--- a/Composer/packages/client/src/pages/publish/Notifications.tsx
+++ b/Composer/packages/client/src/pages/publish/Notifications.tsx
@@ -73,7 +73,7 @@ export const getPublishedNotificationCardProps = (item: BotStatus): CardProps =>
export const getSkillPublishedNotificationCardProps = (
item: { status: number } & Record,
- url?: string
+ url?: string,
): CardProps => {
const skillCardContent = css`
display: flex;
@@ -121,7 +121,7 @@ export const getSkillPublishedNotificationCardProps = (
description:
item.status === 200
? formatMessage(
- 'Keep this URL handy to share it with other developers to use in their bot projects. You can find this URL in the project settings tab.'
+ 'Keep this URL handy to share it with other developers to use in their bot projects. You can find this URL in the project settings tab.',
)
: formatMessage(`Your skill could not be published.`),
type: item.status === 200 ? 'success' : 'error',
@@ -171,7 +171,7 @@ export const getPendingNotificationCardProps = (items: BotStatus[], isSkill = fa
=1 {one bot}
other {# bots}
}`,
- { count: items.length }
+ { count: items.length },
);
return {
title: '',
diff --git a/Composer/packages/client/src/pages/publish/Publish.tsx b/Composer/packages/client/src/pages/publish/Publish.tsx
index 0b65f23e93..9b7229b897 100644
--- a/Composer/packages/client/src/pages/publish/Publish.tsx
+++ b/Composer/packages/client/src/pages/publish/Publish.tsx
@@ -95,7 +95,7 @@ const Publish: React.FC(
- initUpdaterStatus(publishHistoryList)
+ initUpdaterStatus(publishHistoryList),
);
const [checkedSkillIds, setCheckedSkillIds] = useState([]);
@@ -162,7 +162,7 @@ const Publish: React.FC !!bot.publishTarget && !pollingUpdaterList.some((u) => u.isSameUpdater(bot.id, bot.publishTarget))
+ (bot) => !!bot.publishTarget && !pollingUpdaterList.some((u) => u.isSameUpdater(bot.id, bot.publishTarget)),
)
.forEach((bot) => {
if (pollingUpdaterList.some((updater) => updater.isSameUpdater(bot.id, bot.publishTarget))) return;
@@ -232,7 +232,7 @@ const Publish: React.FC ', () => {
it('should render', async () => {
const { findByText } = render( );
await findByText(
- 'You are about to pull project files from the selected publish profiles. The current project will be overwritten by the pulled files, and will be saved as a backup automatically. You will be able to retrieve the backup anytime in the future.'
+ 'You are about to pull project files from the selected publish profiles. The current project will be overwritten by the pulled files, and will be saved as a backup automatically. You will be able to retrieve the backup anytime in the future.',
);
});
diff --git a/Composer/packages/client/src/pages/publish/publishPageUtils.tsx b/Composer/packages/client/src/pages/publish/publishPageUtils.tsx
index fb76032a6f..e4f176c7e6 100644
--- a/Composer/packages/client/src/pages/publish/publishPageUtils.tsx
+++ b/Composer/packages/client/src/pages/publish/publishPageUtils.tsx
@@ -46,7 +46,7 @@ const findSkillManifestUrl = (skillManifests: SkillManifestFile[], hostname: str
export const generateBotStatusList = (
botList: Bot[],
botPropertyData: BotPropertyType,
- botPublishHistoryList: BotPublishHistory
+ botPublishHistoryList: BotPublishHistory,
): BotStatus[] => {
const bots = botList.map((bot) => {
const botStatus: BotStatus = Object.assign({ skillManifestUrl: '' }, bot);
@@ -70,7 +70,7 @@ export const generateBotStatusList = (
botStatus.skillManifestUrl = findSkillManifestUrl(
botPropertyData[bot.id].skillManifests,
config.hostname,
- appId
+ appId,
);
}
}
diff --git a/Composer/packages/client/src/pages/publish/pullConfirmationDialog.tsx b/Composer/packages/client/src/pages/publish/pullConfirmationDialog.tsx
index 60b5f3e876..21b29e798a 100644
--- a/Composer/packages/client/src/pages/publish/pullConfirmationDialog.tsx
+++ b/Composer/packages/client/src/pages/publish/pullConfirmationDialog.tsx
@@ -31,7 +31,7 @@ export const PullConfirmationDialog: React.FC = (pr
>
{formatMessage(
- 'You are about to pull project files from the selected publish profiles. The current project will be overwritten by the pulled files, and will be saved as a backup automatically. You will be able to retrieve the backup anytime in the future.'
+ 'You are about to pull project files from the selected publish profiles. The current project will be overwritten by the pulled files, and will be saved as a backup automatically. You will be able to retrieve the backup anytime in the future.',
)}
{formatMessage('Do you want to proceed?')}
diff --git a/Composer/packages/client/src/pages/publish/pullDialog.tsx b/Composer/packages/client/src/pages/publish/pullDialog.tsx
index 61b409e01b..bf892dd195 100644
--- a/Composer/packages/client/src/pages/publish/pullDialog.tsx
+++ b/Composer/packages/client/src/pages/publish/pullDialog.tsx
@@ -43,7 +43,7 @@ export const PullDialog: React.FC = (props) => {
try {
// wait for pull result from server
const res = await axios.post<{ backupLocation: string }>(
- `/api/publish/${projectId}/pull/${selectedTarget.name}`
+ `/api/publish/${projectId}/pull/${selectedTarget.name}`,
);
const { backupLocation } = res.data;
// show notification indicating success and close dialog
diff --git a/Composer/packages/client/src/pages/publish/pullFailedDialog.tsx b/Composer/packages/client/src/pages/publish/pullFailedDialog.tsx
index 444ebec0a3..73cc3dff37 100644
--- a/Composer/packages/client/src/pages/publish/pullFailedDialog.tsx
+++ b/Composer/packages/client/src/pages/publish/pullFailedDialog.tsx
@@ -45,7 +45,7 @@ export const PullFailedDialog: React.FC = (props) => {
{formatMessage.rich(
'There was an unexpected error pulling from publish profile { selectedTargetName } ',
- { b: Bold, selectedTargetName }
+ { b: Bold, selectedTargetName },
)}
{typeof error === 'object' ? JSON.stringify(error, undefined, 2) : error}
diff --git a/Composer/packages/client/src/pages/setting/SettingsPage.tsx b/Composer/packages/client/src/pages/setting/SettingsPage.tsx
index 2292203e42..c7075bc4f9 100644
--- a/Composer/packages/client/src/pages/setting/SettingsPage.tsx
+++ b/Composer/packages/client/src/pages/setting/SettingsPage.tsx
@@ -47,13 +47,8 @@ const getProjectLink = (path: string, id?: string) => {
};
const SettingPage: React.FC = () => {
- const {
- addLanguageDialogCancel,
- delLanguageDialogCancel,
- addLanguages,
- deleteLanguages,
- fetchProjectById,
- } = useRecoilValue(dispatcherState);
+ const { addLanguageDialogCancel, delLanguageDialogCancel, addLanguages, deleteLanguages, fetchProjectById } =
+ useRecoilValue(dispatcherState);
const projectId = useRecoilValue(currentProjectIdState);
const locale = useRecoilValue(localeState(projectId));
const showDelLanguageModal = useRecoilValue(showDelLanguageModalState(projectId));
diff --git a/Composer/packages/client/src/pages/setting/app-settings/AppSettings.tsx b/Composer/packages/client/src/pages/setting/app-settings/AppSettings.tsx
index 0ff3973b40..f8af82f70e 100644
--- a/Composer/packages/client/src/pages/setting/app-settings/AppSettings.tsx
+++ b/Composer/packages/client/src/pages/setting/app-settings/AppSettings.tsx
@@ -26,7 +26,7 @@ import { PreviewFeatureToggle } from './PreviewFeatureToggle';
import { TemplateFeedForm } from './TemplateFeedForm';
const ElectronSettings = lazy(() =>
- import('./electronSettings').then((module) => ({ default: module.ElectronSettings }))
+ import('./electronSettings').then((module) => ({ default: module.ElectronSettings })),
);
const AppSettings: React.FC = () => {
@@ -41,7 +41,7 @@ const AppSettings: React.FC = () => {
onboardingSetComplete(!checked);
showCallout(checked);
},
- [onboardingSetComplete]
+ [onboardingSetComplete],
);
const onCodeEditorChange = (key: string) => (value: boolean | Record) => {
@@ -179,7 +179,7 @@ const AppSettings: React.FC = () => {
= () => {
{
featureFlagKey={key as FeatureFlagKey}
featureFlagName={featureFlag.displayName}
toggleFeatureFlag={toggleFeatureFlag}
- />
+ />,
);
}
});
@@ -42,7 +42,7 @@ export const PreviewFeatureToggle: React.FC = () => {
result.push(
{formatMessage('There are no preview features at this time.')}
-
+ ,
);
}
return {result}
;
@@ -54,7 +54,7 @@ export const PreviewFeatureToggle: React.FC = () => {
hideToggle
checked={featureFlagVisible}
description={formatMessage(
- 'Try new features in preview and help us make Composer better. You can turn them on or off at any time.'
+ 'Try new features in preview and help us make Composer better. You can turn them on or off at any time.',
)}
image={images.previewFeatures}
title={formatMessage('Preview features')}
diff --git a/Composer/packages/client/src/pages/setting/app-settings/TemplateFeedForm.tsx b/Composer/packages/client/src/pages/setting/app-settings/TemplateFeedForm.tsx
index e24c79a7de..123d6d3830 100644
--- a/Composer/packages/client/src/pages/setting/app-settings/TemplateFeedForm.tsx
+++ b/Composer/packages/client/src/pages/setting/app-settings/TemplateFeedForm.tsx
@@ -60,7 +60,7 @@ export const TemplateFeedForm = () => {
setFieldDisabled(false);
if (templateProjects.length < 1) {
setErrorMessage(
- formatMessage('This feed did not return any templates, please confirm that this is a valid template feed URL.')
+ formatMessage('This feed did not return any templates, please confirm that this is a valid template feed URL.'),
);
} else {
setErrorMessage('');
diff --git a/Composer/packages/client/src/pages/setting/app-settings/electronSettings.tsx b/Composer/packages/client/src/pages/setting/app-settings/electronSettings.tsx
index 019f3e8eb9..06ea2aa644 100644
--- a/Composer/packages/client/src/pages/setting/app-settings/electronSettings.tsx
+++ b/Composer/packages/client/src/pages/setting/app-settings/electronSettings.tsx
@@ -50,7 +50,7 @@ export const ElectronSettings: React.FC = () => {
{props.children}
;
},
- }
+ },
) as any
}
image={images.earlyAdopters}
diff --git a/Composer/packages/client/src/pages/setting/dialog-settings/DialogSettings.tsx b/Composer/packages/client/src/pages/setting/dialog-settings/DialogSettings.tsx
index 82d8d55ea9..84c36ef251 100644
--- a/Composer/packages/client/src/pages/setting/dialog-settings/DialogSettings.tsx
+++ b/Composer/packages/client/src/pages/setting/dialog-settings/DialogSettings.tsx
@@ -55,7 +55,7 @@ export const DialogSettings: React.FC
const onDefaultLanguageChange = (
_event: React.FormEvent,
option?: IDropdownOption,
- _index?: number
+ _index?: number,
) => {
const selectedLang = option?.key as string;
if (selectedLang && selectedLang !== defaultLanguage) {
diff --git a/Composer/packages/client/src/pages/setting/dialog-settings/constants.ts b/Composer/packages/client/src/pages/setting/dialog-settings/constants.ts
index e83cabcd41..44d20a3c88 100644
--- a/Composer/packages/client/src/pages/setting/dialog-settings/constants.ts
+++ b/Composer/packages/client/src/pages/setting/dialog-settings/constants.ts
@@ -10,10 +10,11 @@ export const BotSettings = {
botSettings: formatMessage('Settings'),
generalTitle: formatMessage('General'),
botSettingDescription: formatMessage(
- 'Settings contains detailed information about your bot. For security reasons, they are hidden by default. To test your bot or publish to Azure, you may need to provide these settings.'
+ 'Settings contains detailed information about your bot. For security reasons, they are hidden by default. To test your bot or publish to Azure, you may need to provide these settings.',
),
languageTitle: formatMessage('Bot language'),
- languagesubTitle: formatMessage(`Select the language that bot will be able to understand (User input) and respond to (Bot responses).
+ languagesubTitle:
+ formatMessage(`Select the language that bot will be able to understand (User input) and respond to (Bot responses).
To make this bot available in other languages, click “Add’ to create a copy of the default language, and translate the content into the new language.`),
languageBotLanauge: formatMessage('Bot language (active)'),
languageDefaultLanauge: formatMessage('Default language'),
diff --git a/Composer/packages/client/src/plugin-host-preload.ts b/Composer/packages/client/src/plugin-host-preload.ts
index f014fc023d..1733b1a077 100644
--- a/Composer/packages/client/src/plugin-host-preload.ts
+++ b/Composer/packages/client/src/plugin-host-preload.ts
@@ -33,7 +33,7 @@ if (!document.getElementById('plugin-host-default-styles')) {
flex-flow: column nowrap;
height: 100%;
}
- `)
+ `),
);
document.head.appendChild(styles);
}
diff --git a/Composer/packages/client/src/plugins.ts b/Composer/packages/client/src/plugins.ts
index c9a93f630b..356b8f942e 100644
--- a/Composer/packages/client/src/plugins.ts
+++ b/Composer/packages/client/src/plugins.ts
@@ -46,5 +46,5 @@ export default mergePluginConfigs(
lu,
orchestrator,
crossTrained,
- schemaEditor
+ schemaEditor,
);
diff --git a/Composer/packages/client/src/plugins/api.ts b/Composer/packages/client/src/plugins/api.ts
index 89a12f2e0a..6823d2b187 100644
--- a/Composer/packages/client/src/plugins/api.ts
+++ b/Composer/packages/client/src/plugins/api.ts
@@ -7,9 +7,9 @@ import { AuthClient } from '../utils/authClient';
interface IAPI {
auth: AuthAPI;
- page?: {};
+ page?: any;
publish: PublishAPI;
- storage?: {};
+ storage?: any;
}
interface PublishConfig {
diff --git a/Composer/packages/client/src/recoilModel/DispatcherWrapper.tsx b/Composer/packages/client/src/recoilModel/DispatcherWrapper.tsx
index 108b852c75..72833da012 100644
--- a/Composer/packages/client/src/recoilModel/DispatcherWrapper.tsx
+++ b/Composer/packages/client/src/recoilModel/DispatcherWrapper.tsx
@@ -2,15 +2,12 @@
// Licensed under the MIT License.
import React, { useRef, useState, Fragment, useLayoutEffect, MutableRefObject } from 'react';
-// eslint-disable-next-line @typescript-eslint/camelcase
import { useRecoilTransactionObserver_UNSTABLE, Snapshot, useRecoilState } from 'recoil';
import once from 'lodash/once';
import { BotAssets } from '@bfc/shared';
import { useRecoilValue } from 'recoil';
import isEmpty from 'lodash/isEmpty';
-import { createMissingLgTemplatesForDialogs } from '../utils/lgUtil';
-
import { dialogsSelectorFamily, luFilesSelectorFamily, qnaFilesSelectorFamily } from './selectors';
import { UndoRoot } from './undo/history';
import { prepareAxios } from './../utils/auth';
@@ -24,7 +21,6 @@ import {
jsonSchemaFilesState,
crossTrainConfigState,
dispatcherState,
- projectIndexingState,
} from './atoms';
import { localBotsWithoutErrorsSelector, formDialogSchemasSelectorFamily } from './selectors';
import { Recognizer } from './Recognizers';
@@ -94,19 +90,6 @@ const InitDispatcher = ({ onLoad }) => {
return null;
};
-const repairBotProject = async (projectId: string, snapshot: Snapshot, previousSnapshot: Snapshot) => {
- const indexingState = await snapshot.getPromise(projectIndexingState(projectId));
- const preIndexingState = await previousSnapshot.getPromise(projectIndexingState(projectId));
- if (indexingState === false && preIndexingState == true) {
- const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
- const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
-
- const updatedLgFiles = await createMissingLgTemplatesForDialogs(projectId, dialogs, lgFiles);
- const { updateAllLgFiles } = await snapshot.getPromise(dispatcherState);
- updateAllLgFiles({ projectId, lgFiles: updatedLgFiles });
- }
-};
-
export const DispatcherWrapper = ({ children }) => {
const [loaded, setLoaded] = useState(false);
const botProjects = useRecoilValue(localBotsWithoutErrorsSelector);
@@ -119,7 +102,6 @@ export const DispatcherWrapper = ({ children }) => {
const previousAssets = await getBotAssets(projectId, previousSnapshot);
const filePersistence = await snapshot.getPromise(filePersistenceState(projectId));
if (!isEmpty(filePersistence)) {
- await repairBotProject(projectId, snapshot, previousSnapshot);
if (filePersistence.isErrorHandlerEmpty()) {
filePersistence.registerErrorHandler(setProjectError);
}
diff --git a/Composer/packages/client/src/recoilModel/Recognizers.tsx b/Composer/packages/client/src/recoilModel/Recognizers.tsx
index 0f52f18adf..bea7354f15 100644
--- a/Composer/packages/client/src/recoilModel/Recognizers.tsx
+++ b/Composer/packages/client/src/recoilModel/Recognizers.tsx
@@ -80,7 +80,7 @@ export const getMultiLanguagueRecognizerDialog = (
fileType: 'lu' | 'qna',
isOrchestrator = false,
supportedLanguages: string[] = [],
- defaultLanguage = 'en-us'
+ defaultLanguage = 'en-us',
) => {
const key = fileType === 'qna' ? 'QnA' : isOrchestrator ? 'ORCHESTRATOR' : 'LUIS';
@@ -150,7 +150,7 @@ export const generateRecognizers = (
luFiles: LuFile[],
qnaFiles: QnAFile[],
luProvide?: LuProviderType,
- defaultLanguage = 'en-us'
+ defaultLanguage = 'en-us',
) => {
const isCrossTrain = isCrossTrainedRecognizerSet(dialog);
const isOrchestrator = luProvide === SDKKinds.OrchestratorRecognizer;
@@ -163,7 +163,7 @@ export const generateRecognizers = (
'lu',
isOrchestrator,
LUISLocales,
- defaultLanguage
+ defaultLanguage,
);
const crossTrainedRecognizer = getCrossTrainedRecognizerDialog(dialog.id, luFiles, qnaFiles);
@@ -173,7 +173,7 @@ export const generateRecognizers = (
'qna',
false,
QnALocales,
- defaultLanguage
+ defaultLanguage,
);
const qnaMakeRecognizers = getQnAMakerRecognizerDialogs(dialog.id, qnaFiles);
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/application.test.ts b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/application.test.ts
index dbe968e1af..7dbb8fe11b 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/application.test.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/application.test.ts
@@ -55,7 +55,7 @@ describe('application dispatchers', () => {
applicationDispatcher,
},
},
- }
+ },
);
renderedComponent = rendered.result;
dispatcher = renderedComponent.current.dispatcher;
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/botProjectFile.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/botProjectFile.test.tsx
index 0be4292452..cdce0f733b 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/botProjectFile.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/botProjectFile.test.tsx
@@ -30,11 +30,13 @@ describe('Bot Project File dispatcher', () => {
const skillsDataSelector = selectorFamily({
key: 'skillsDataSelector-botProjectFile',
get: (skillId: string) => noop,
- set: (skillId: string) => ({ set }, stateUpdater: any) => {
- const { botNameIdentifier, location } = stateUpdater;
- set(botNameIdentifierState(skillId), botNameIdentifier);
- set(locationState(skillId), location);
- },
+ set:
+ (skillId: string) =>
+ ({ set }, stateUpdater: any) => {
+ const { botNameIdentifier, location } = stateUpdater;
+ set(botNameIdentifierState(skillId), botNameIdentifier);
+ set(locationState(skillId), location);
+ },
});
const botStatesSelector = selector({
@@ -118,7 +120,7 @@ describe('Bot Project File dispatcher', () => {
settingsDispatcher,
},
},
- }
+ },
);
renderedComponent = rendered.result;
dispatcher = renderedComponent.current.currentDispatcher;
@@ -137,7 +139,7 @@ describe('Bot Project File dispatcher', () => {
});
expect(renderedComponent.current.botProjectFile.content.skills.todoSkill.workspace).toMatch(
- /\.\.(\/|\\)Todo-Skill/
+ /\.\.(\/|\\)Todo-Skill/,
);
expect(renderedComponent.current.botProjectFile.content.skills.todoSkill.remote).toBeFalsy();
});
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/dialogSchema.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/dialogSchema.test.tsx
index 38384a53c8..d3babb7e53 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/dialogSchema.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/dialogSchema.test.tsx
@@ -52,7 +52,7 @@ describe('dialog schema dispatcher', () => {
await dispatcher.updateDialogSchema({ id: '100', content: 'abcde' }, projectId);
});
expect(renderedComponent.current.dialogSchemas.find((dialogSchema) => dialogSchema.id === '100').content).toEqual(
- 'abcde'
+ 'abcde',
);
});
});
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lg.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lg.test.tsx
index 8a3bd45888..1e8dfb374b 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lg.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lg.test.tsx
@@ -23,18 +23,23 @@ jest.mock('../../parsers/lgWorker', () => {
return {
parse: (projectId, id, content) => ({ id, content }),
addTemplate: (projectId, lgFile, template) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/lgUtil').addTemplate(lgFile, template)),
addTemplates: (projectId, lgFile, templates) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/lgUtil').addTemplates(lgFile, templates)),
updateTemplate: (projectId, lgFile, templateName, template) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/lgUtil').updateTemplate(lgFile, templateName, template)),
removeTemplate: (projectId, lgFile, templateName) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/lgUtil').removeTemplate(lgFile, templateName)),
removeTemplates: (projectId, lgFile, templateNames) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/lgUtil').removeTemplates(lgFile, templateNames)),
copyTemplate: (projectId, lgFile, fromTemplateName, toTemplateName) =>
filterParseResult(
- require('@bfc/indexers/lib/utils/lgUtil').copyTemplate(lgFile, fromTemplateName, toTemplateName)
+ require('@bfc/indexers/lib/utils/lgUtil').copyTemplate(lgFile, fromTemplateName, toTemplateName),
),
};
});
@@ -56,7 +61,7 @@ const getLgTemplate = (name, body): LgTemplate =>
({
name,
body,
- } as LgTemplate);
+ }) as LgTemplate;
describe('Lg dispatcher', () => {
const useRecoilTestHook = () => {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lu.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lu.test.tsx
index 504fd0c5f4..dedd49f8ff 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lu.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/lu.test.tsx
@@ -18,10 +18,15 @@ const luFeatures = {};
jest.mock('../../parsers/luWorker', () => {
return {
parse: (id: string, content, luFeatures) => ({ id, content, luFeatures }),
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
addIntent: require('@bfc/indexers/lib/utils/luUtil').addIntent,
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
addIntents: require('@bfc/indexers/lib/utils/luUtil').addIntents,
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
updateIntent: require('@bfc/indexers/lib/utils/luUtil').updateIntent,
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
removeIntent: require('@bfc/indexers/lib/utils/luUtil').removeIntent,
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
removeIntents: require('@bfc/indexers/lib/utils/luUtil').removeIntents,
};
});
@@ -37,7 +42,7 @@ const getLuIntent = (Name, Body): LuIntentSection =>
({
Name,
Body,
- } as LuIntentSection);
+ }) as LuIntentSection;
describe('Lu dispatcher', () => {
const useRecoilTestHook = () => {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/mocks/mockProjectResponse.json b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/mocks/mockProjectResponse.json
index f5ea636495..7413d32a0d 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/mocks/mockProjectResponse.json
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/mocks/mockProjectResponse.json
@@ -3085,7 +3085,7 @@
"title": "speak"
},
"inputHint": {
- "description": "Indicates whether your bot is accepting,\nexpecting, or ignoring user input after the message is delivered to the client. Possible\nvalues include: 'acceptingInput', 'ignoringInput', 'expectingInput'",
+ "description": "Indicates whether your bot is accepting,\nexpecting, or ignoring user input after the message is delivered to the client. Possible\nvalues include: 'acceptingInput', 'ignoringInput', 'expectingInput', 'ignoringSpeechInput', 'ignoringNonSpeechInput'",
"type": "string",
"title": "inputHint"
},
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/orchestrator.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/orchestrator.test.tsx
index 6c2194a667..9d61b5a15f 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/orchestrator.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/orchestrator.test.tsx
@@ -44,63 +44,63 @@ describe('Orchestrator model picking logic', () => {
expect(
await getAvailableLanguageModels([
{ id: 'test.en-us.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } },
- ])
+ ]),
).toEqual([enModel]);
expect(
await getAvailableLanguageModels([
{ id: 'test.EN-us.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } },
- ])
+ ]),
).toEqual([enModel]);
expect(
await getAvailableLanguageModels([
{ id: 'test.en-US.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } },
- ])
+ ]),
).toEqual([enModel]);
expect(
- await getAvailableLanguageModels([{ id: 'test.en.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } }])
+ await getAvailableLanguageModels([{ id: 'test.en.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } }]),
).toEqual([enModel]);
expect(
await getAvailableLanguageModels([
{ id: 'test.en-anything.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } },
- ])
+ ]),
).toEqual([enModel]);
});
it('return multilang model under correct circumstances', async () => {
const multilingualModel = { kind: 'multilingual_intent', name: 'default' };
expect(
- await getAvailableLanguageModels([{ id: 'test.it.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } }])
+ await getAvailableLanguageModels([{ id: 'test.it.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } }]),
).toEqual([multilingualModel]);
expect(
- await getAvailableLanguageModels([{ id: 'test.jp.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } }])
+ await getAvailableLanguageModels([{ id: 'test.jp.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } }]),
).toHaveLength(0);
expect(
- await getAvailableLanguageModels([{ id: 'test.ja.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } }])
+ await getAvailableLanguageModels([{ id: 'test.ja.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } }]),
).toHaveLength(1);
expect(
await getAvailableLanguageModels([
{ id: 'test.zh-cn.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } },
- ])
+ ]),
).toEqual([multilingualModel]);
expect(
await getAvailableLanguageModels([
{ id: 'test.zh-CN.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } },
- ])
+ ]),
).toEqual([multilingualModel]);
expect(
await getAvailableLanguageModels([
{ id: 'test.rwk-tz.dialog', content: { $kind: SDKKinds.OrchestratorRecognizer } },
- ])
+ ]),
).toEqual([multilingualModel]);
expect(
- await getAvailableLanguageModels([{ id: 'test.pap', content: { $kind: SDKKinds.OrchestratorRecognizer } }])
+ await getAvailableLanguageModels([{ id: 'test.pap', content: { $kind: SDKKinds.OrchestratorRecognizer } }]),
).toEqual([multilingualModel]);
expect(
- await getAvailableLanguageModels([{ id: 'test.tr-cy', content: { $kind: SDKKinds.OrchestratorRecognizer } }])
+ await getAvailableLanguageModels([{ id: 'test.tr-cy', content: { $kind: SDKKinds.OrchestratorRecognizer } }]),
).toEqual([multilingualModel]);
expect(
- await getAvailableLanguageModels([{ id: 'test.nope', content: { $kind: SDKKinds.OrchestratorRecognizer } }])
+ await getAvailableLanguageModels([{ id: 'test.nope', content: { $kind: SDKKinds.OrchestratorRecognizer } }]),
).toHaveLength(0);
});
@@ -131,8 +131,8 @@ describe('Orchestrator model picking logic', () => {
(httpClient.get as jest.Mock).mockResolvedValueOnce({
data: {
defaults: {
- en_intent: 'fake_english_model_name', // eslint-disable-line @typescript-eslint/camelcase
- multilingual_intent: 'fake_multilingual_model_name', // eslint-disable-line @typescript-eslint/camelcase
+ en_intent: 'fake_english_model_name',
+ multilingual_intent: 'fake_multilingual_model_name',
},
},
});
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/project.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/project.test.tsx
index 3b96cf18c7..8837a912af 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/project.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/project.test.tsx
@@ -72,8 +72,8 @@ jest.mock('../../parsers/lgWorker', () => {
const result = require('@bfc/indexers').lgUtil.parse(id, content, files);
delete result.parseResult;
return result;
- })
- )
+ }),
+ ),
),
};
});
@@ -83,7 +83,7 @@ jest.mock('../../parsers/luWorker', () => {
flush: () => new Promise((resolve) => resolve(null)),
parseAll: (files, luFeatures) =>
new Promise((resolve) =>
- resolve(files.map(({ id, content }) => require('@bfc/indexers').luUtil.parse(id, content, luFeatures)))
+ resolve(files.map(({ id, content }) => require('@bfc/indexers').luUtil.parse(id, content, luFeatures))),
),
};
});
@@ -93,7 +93,7 @@ jest.mock('../../parsers/qnaWorker', () => {
flush: () => new Promise((resolve) => resolve(null)),
parseAll: (files) =>
new Promise((resolve) =>
- resolve(files.map(({ id, content }) => require('@bfc/indexers').qnaUtil.parse(id, content)))
+ resolve(files.map(({ id, content }) => require('@bfc/indexers').qnaUtil.parse(id, content))),
),
};
});
@@ -209,7 +209,7 @@ describe('Project dispatcher', () => {
settingsDispatcher,
},
},
- }
+ },
);
renderedComponent = rendered.result;
dispatcher = renderedComponent.current.currentDispatcher;
@@ -427,13 +427,13 @@ describe('Project dispatcher', () => {
await dispatcher.addRemoteSkillToBotProject(
'https://test-dev.azurewebsites.net/manifests/onenote-2-1-preview-1-manifest.json',
'remote',
- {}
+ {},
);
});
expect(renderedComponent.current.botStates.oneNoteSync).toBeDefined();
expect(renderedComponent.current.botStates.oneNoteSync.botDisplayName).toBe('OneNoteSync');
expect(renderedComponent.current.botStates.oneNoteSync.location).toBe(
- 'https://test-dev.azurewebsites.net/manifests/onenote-2-1-preview-1-manifest.json'
+ 'https://test-dev.azurewebsites.net/manifests/onenote-2-1-preview-1-manifest.json',
);
expect(navigateTo).toHaveBeenLastCalledWith(`/bot/${projectId}/skill/${skillId}`);
mockImplementation.mockClear();
@@ -463,7 +463,7 @@ describe('Project dispatcher', () => {
await dispatcher.addRemoteSkillToBotProject(
'https://test-dev.azurewebsites.net/manifests/onenote-2-1-preview-1-manifest.json',
'remote',
- {}
+ {},
);
});
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/qna.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/qna.test.tsx
index 09df276f29..0071cfae89 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/qna.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/qna.test.tsx
@@ -21,24 +21,30 @@ jest.mock('../../parsers/qnaWorker', () => {
return {
parse: (id: string, content) => ({ id, content }),
removeSection: (projectId: string, qnaFile, sectionId: string) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/qnaUtil').removeSection(qnaFile, sectionId)),
insertSection: (projectId: string, qnaFile, position, sectionContent) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/qnaUtil').insertSection(qnaFile, position, sectionContent)),
createQnAQuestion: (projectId: string, qnaFile, sectionId: string, questionContent) =>
filterParseResult(
- require('@bfc/indexers/lib/utils/qnaUtil').createQnAQuestion(qnaFile, sectionId, questionContent)
+ require('@bfc/indexers/lib/utils/qnaUtil').createQnAQuestion(qnaFile, sectionId, questionContent),
),
updateQnAQuestion: (projectId: string, qnaFile, sectionId: string, questionId: string, questionContent) =>
filterParseResult(
- require('@bfc/indexers/lib/utils/qnaUtil').updateQnAQuestion(qnaFile, sectionId, questionId, questionContent)
+ require('@bfc/indexers/lib/utils/qnaUtil').updateQnAQuestion(qnaFile, sectionId, questionId, questionContent),
),
removeQnAQuestion: (projectId: string, qnaFile, sectionId: string, questionId: string) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/qnaUtil').removeQnAQuestion(qnaFile, sectionId, questionId)),
updateQnAAnswer: (projectId: string, qnaFile, sectionId: string, answerContent) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/qnaUtil').updateQnAAnswer(qnaFile, sectionId, answerContent)),
addImport: (projectId: string, qnaFile: string, path: string) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/qnaUtil').addImport(qnaFile, path)),
removeImport: (projectId: string, qnaFile, path: string) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
filterParseResult(require('@bfc/indexers/lib/utils/qnaUtil').removeImport(qnaFile, path)),
};
});
@@ -121,7 +127,7 @@ describe('QnA dispatcher', () => {
});
expect(renderedComponent.current.qnaFiles[0].qnaSections[0].Questions[0].content).toContain(
- 'What is your name, my friend?'
+ 'What is your name, my friend?',
);
});
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/setting.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/setting.test.tsx
index dc2ef83dac..d28862ec38 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/setting.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/setting.test.tsx
@@ -129,7 +129,7 @@ describe('setting dispatcher', () => {
lastPublished: new Date(),
},
],
- projectId
+ projectId,
);
});
@@ -146,7 +146,7 @@ describe('setting dispatcher', () => {
expect(renderedComponent.current.settings.runtime.path).toBe('path');
expect(renderedComponent.current.settings.runtime.command).toBe('command');
expect(renderedComponent.current.settings.runtime.key).toBe('key');
- // @ts-ignore - runtime has 'name' in practice and is of a type that has 'name', but TS isn't seeing it somehow
+ // @ts-expect-error - runtime has 'name' in practice and is of a type that has 'name', but TS isn't seeing it somehow
expect(renderedComponent.current.settings.runtime.name).toBe('name');
});
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/skill.test.ts b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/skill.test.ts
index de3b47662f..5d4ea91b70 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/skill.test.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/skill.test.ts
@@ -35,19 +35,23 @@ const skillIds = ['1234.123', '234.234'];
describe('skill dispatcher', () => {
const skillsDataSelector = selectorFamily({
key: 'skillSelector-skill',
- get: (skillId: string) => ({ get }) => {
- return {
- skillNameIdentifier: get(botNameIdentifierState(skillId)),
- location: get(locationState(skillId)),
- };
- },
- set: (skillId: string) => ({ set }, stateUpdater: any) => {
- const { botNameIdentifier, location, displayName, settings } = stateUpdater;
- set(botNameIdentifierState(skillId), botNameIdentifier);
- set(locationState(skillId), location);
- set(settingsState(skillId), settings);
- set(botDisplayNameState(skillId), displayName);
- },
+ get:
+ (skillId: string) =>
+ ({ get }) => {
+ return {
+ skillNameIdentifier: get(botNameIdentifierState(skillId)),
+ location: get(locationState(skillId)),
+ };
+ },
+ set:
+ (skillId: string) =>
+ ({ set }, stateUpdater: any) => {
+ const { botNameIdentifier, location, displayName, settings } = stateUpdater;
+ set(botNameIdentifierState(skillId), botNameIdentifier);
+ set(locationState(skillId), location);
+ set(settingsState(skillId), settings);
+ set(botDisplayNameState(skillId), displayName);
+ },
});
const useRecoilTestHook = () => {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/storage.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/storage.test.tsx
index 6f35838b10..24bee2e404 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/storage.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/storage.test.tsx
@@ -21,20 +21,20 @@ jest.mock('../../../utils/navigation', () => {
jest.mock('../../parsers/lgWorker', () => {
return {
- flush: () => new Promise((resolve) => resolve()),
- addProject: () => new Promise((resolve) => resolve()),
+ flush: () => new Promise((resolve) => resolve()),
+ addProject: () => new Promise((resolve) => resolve()),
};
});
jest.mock('../../parsers/luWorker', () => {
return {
- flush: () => new Promise((resolve) => resolve()),
+ flush: () => new Promise((resolve) => resolve()),
};
});
jest.mock('../../persistence/FilePersistence', () => {
return jest.fn().mockImplementation(() => {
- return { flush: () => new Promise((resolve) => resolve()) };
+ return { flush: () => new Promise((resolve) => resolve()) };
});
});
@@ -63,7 +63,7 @@ describe('Storage dispatcher', () => {
storageDispatcher,
},
},
- }
+ },
);
renderedComponent = rendered.result;
dispatcher = renderedComponent.current.currentDispatcher;
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/trigger.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/trigger.test.tsx
index d5638dc82b..5c2f5090e7 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/trigger.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/trigger.test.tsx
@@ -207,7 +207,6 @@ describe('trigger dispatcher', () => {
const targetTrigger = (updatedDialog?.content as any).triggers[0];
await act(async () => {
- // @ts-ignore - targetTrigger should be an ITriggerCondition, but we give it an ITrigger
await dispatcher.deleteTrigger(projectId, dialogId, targetTrigger);
});
const updatedDialog2 = renderedComponent.current.dialogs.find(({ id }) => id === dialogId);
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/webchat.test.tsx b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/webchat.test.tsx
index 34e83fbdfd..74043f722d 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/__tests__/webchat.test.tsx
+++ b/Composer/packages/client/src/recoilModel/dispatchers/__tests__/webchat.test.tsx
@@ -53,7 +53,7 @@ describe('web chat dispatcher', () => {
activity: {} as any,
id: '',
timestamp: Date.now(),
- trafficType: 'activity' as 'activity',
+ trafficType: 'activity' as const,
};
await act(async () => {
await dispatcher.appendWebChatTraffic(projectId, trafficItem);
@@ -67,13 +67,13 @@ describe('web chat dispatcher', () => {
activity: {} as any,
id: '',
timestamp: Date.now(),
- trafficType: 'activity' as 'activity',
+ trafficType: 'activity' as const,
};
const trafficItem2 = {
activity: {} as any,
id: '',
timestamp: Date.now() + 5,
- trafficType: 'activity' as 'activity',
+ trafficType: 'activity' as const,
};
await act(async () => {
await dispatcher.appendWebChatTraffic(projectId, [trafficItem1, trafficItem2]);
@@ -87,7 +87,7 @@ describe('web chat dispatcher', () => {
activity: {} as any,
id: '',
timestamp: Date.now(),
- trafficType: 'activity' as 'activity',
+ trafficType: 'activity' as const,
};
await act(async () => {
await dispatcher.appendWebChatTraffic(projectId, trafficItem);
@@ -105,7 +105,7 @@ describe('web chat dispatcher', () => {
it('should set inspection data state', async () => {
const inspectionData = {
item: {} as any,
- mode: 'request' as 'request',
+ mode: 'request' as const,
};
await act(async () => {
await dispatcher.setWebChatInspectionData(projectId, inspectionData);
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/application.ts b/Composer/packages/client/src/recoilModel/dispatchers/application.ts
index 8dca6a0c1d..ccc593b62d 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/application.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/application.ts
@@ -36,24 +36,25 @@ import { flushExistingTasks } from './utils/project';
export const applicationDispatcher = () => {
const setAppUpdateStatus = useRecoilCallback(
- ({ set }: CallbackInterface) => (status: AppUpdaterStatus, version: string | undefined) => {
- set(appUpdateState, (currentAppUpdate) => {
- const newAppUpdateState = {
- ...currentAppUpdate,
- };
- if (status === AppUpdaterStatus.UPDATE_AVAILABLE || status === AppUpdaterStatus.BREAKING_UPDATE_AVAILABLE) {
- newAppUpdateState.version = version;
- }
- if (status === AppUpdaterStatus.IDLE) {
- newAppUpdateState.progressPercent = 0;
- newAppUpdateState.version = undefined;
- }
-
- newAppUpdateState.status = status;
-
- return newAppUpdateState;
- });
- }
+ ({ set }: CallbackInterface) =>
+ (status: AppUpdaterStatus, version: string | undefined) => {
+ set(appUpdateState, (currentAppUpdate) => {
+ const newAppUpdateState = {
+ ...currentAppUpdate,
+ };
+ if (status === AppUpdaterStatus.UPDATE_AVAILABLE || status === AppUpdaterStatus.BREAKING_UPDATE_AVAILABLE) {
+ newAppUpdateState.version = version;
+ }
+ if (status === AppUpdaterStatus.IDLE) {
+ newAppUpdateState.progressPercent = 0;
+ newAppUpdateState.version = undefined;
+ }
+
+ newAppUpdateState.status = status;
+
+ return newAppUpdateState;
+ });
+ },
);
const setAppUpdateShowing = useRecoilCallback(({ set }: CallbackInterface) => (isShowing: boolean) => {
@@ -75,38 +76,43 @@ export const applicationDispatcher = () => {
});
const setAppUpdateProgress = useRecoilCallback(
- ({ set }: CallbackInterface) => (progressPercent: number, downloadSizeInBytes: number) => {
- set(appUpdateState, (updaterState: AppUpdateState) => {
- return {
- ...updaterState,
- progressPercent,
- downloadSizeInBytes,
- };
- });
- }
+ ({ set }: CallbackInterface) =>
+ (progressPercent: number, downloadSizeInBytes: number) => {
+ set(appUpdateState, (updaterState: AppUpdateState) => {
+ return {
+ ...updaterState,
+ progressPercent,
+ downloadSizeInBytes,
+ };
+ });
+ },
);
const setMessage = useRecoilCallback(({ set }: CallbackInterface) => (message: string) => {
set(announcementState, message);
});
- const setPageElementState = useRecoilCallback(({ set }: CallbackInterface) => (mode: PageMode, settings: {}) => {
- set(pageElementState, (currentElementState) => ({
- ...currentElementState,
- [mode]: settings,
- }));
- });
+ const setPageElementState = useRecoilCallback(
+ ({ set }: CallbackInterface) =>
+ (mode: PageMode, settings: Record) => {
+ set(pageElementState, (currentElementState) => ({
+ ...currentElementState,
+ [mode]: settings,
+ }));
+ },
+ );
const onboardingAddCoachMarkRef = useRecoilCallback(
- ({ set }: CallbackInterface) => (coachMarkRef: { [key: string]: any }) => {
- set(onboardingState, (onboardingObj) => ({
- ...onboardingObj,
- coachMarkRefs: {
- ...onboardingObj.coachMarkRefs,
- ...coachMarkRef,
- },
- }));
- }
+ ({ set }: CallbackInterface) =>
+ (coachMarkRef: { [key: string]: any }) => {
+ set(onboardingState, (onboardingObj) => ({
+ ...onboardingObj,
+ coachMarkRefs: {
+ ...onboardingObj.coachMarkRefs,
+ ...coachMarkRef,
+ },
+ }));
+ },
);
const onboardingSetComplete = useRecoilCallback(({ set }: CallbackInterface) => (isComplete: boolean) => {
@@ -128,7 +134,7 @@ export const applicationDispatcher = () => {
const setApplicationLevelError = useRecoilCallback(
(callbackHelpers: CallbackInterface) => (errorObj: StateError | undefined) => {
setError(callbackHelpers, errorObj);
- }
+ },
);
const setDebugPanelExpansion = useRecoilCallback(({ set }: CallbackInterface) => (isExpanded: boolean) => {
@@ -136,9 +142,10 @@ export const applicationDispatcher = () => {
});
const setActiveTabInDebugPanel = useRecoilCallback(
- ({ set }: CallbackInterface) => (activeTab: DebugDrawerKeys | undefined) => {
- set(debugPanelActiveTabState, activeTab);
- }
+ ({ set }: CallbackInterface) =>
+ (activeTab: DebugDrawerKeys | undefined) => {
+ set(debugPanelActiveTabState, activeTab);
+ },
);
const checkNodeVersion = useRecoilCallback(({ set }: CallbackInterface) => async () => {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/auth.ts b/Composer/packages/client/src/recoilModel/dispatchers/auth.ts
index 7c595f00f2..2c515644ec 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/auth.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/auth.ts
@@ -51,58 +51,61 @@ export const authDispatcher = () => {
});
const setCurrentTenant = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (tenant: string, notify = true) => {
- callbackHelpers.set(currentTenantIdState, tenant);
- setTenantId(tenant);
- if (tenant) {
- // get arm token for tenant
- try {
- const token = await AuthClient.getARMTokenForTenant(tenant);
- const graph = await AuthClient.getAccessToken(graphScopes);
- const isAlreadyAuthenticated = await callbackHelpers.snapshot.getPromise(isAuthenticatedState);
-
- if (token) {
- setCurrentUser(token, graph);
-
- // fire notification
- if (notify !== false) {
- let notification;
- if (isAlreadyAuthenticated) {
- // set notification
- notification = createNotification({
- title: formatMessage('Azure sign in'),
- description: formatMessage("You've successfully switched directories."),
- type: 'success',
- retentionTime: 5000,
- });
- } else {
- // set notification
- notification = createNotification({
- title: formatMessage('Azure sign in'),
- description: formatMessage("You've successfully signed in."),
- type: 'success',
- retentionTime: 5000,
- });
+ (callbackHelpers: CallbackInterface) =>
+ async (tenant: string, notify = true) => {
+ callbackHelpers.set(currentTenantIdState, tenant);
+ setTenantId(tenant);
+ if (tenant) {
+ // get arm token for tenant
+ try {
+ const token = await AuthClient.getARMTokenForTenant(tenant);
+ const graph = await AuthClient.getAccessToken(graphScopes);
+ const isAlreadyAuthenticated = await callbackHelpers.snapshot.getPromise(isAuthenticatedState);
+
+ if (token) {
+ setCurrentUser(token, graph);
+
+ // fire notification
+ if (notify !== false) {
+ let notification;
+ if (isAlreadyAuthenticated) {
+ // set notification
+ notification = createNotification({
+ title: formatMessage('Azure sign in'),
+ description: formatMessage("You've successfully switched directories."),
+ type: 'success',
+ retentionTime: 5000,
+ });
+ } else {
+ // set notification
+ notification = createNotification({
+ title: formatMessage('Azure sign in'),
+ description: formatMessage("You've successfully signed in."),
+ type: 'success',
+ retentionTime: 5000,
+ });
+ }
+ addNotificationInternal(callbackHelpers, notification);
}
- addNotificationInternal(callbackHelpers, notification);
+ } else {
+ throw new Error('Could not get fetch token.');
}
- } else {
- throw new Error('Could not get fetch token.');
+ } catch (err) {
+ console.error(`Error in auth: ${err.message || err.toString()}`);
+ const notification = createNotification({
+ title: formatMessage('Azure sign in'),
+ description: formatMessage(`Sign in failed. Please try again.`, {
+ message: err.message || err.toString(),
+ }),
+ type: 'error',
+ retentionTime: 5000,
+ });
+ addNotificationInternal(callbackHelpers, notification);
+ // clear out app state
+ resetCreds();
}
- } catch (err) {
- console.error(`Error in auth: ${err.message || err.toString()}`);
- const notification = createNotification({
- title: formatMessage('Azure sign in'),
- description: formatMessage(`Sign in failed. Please try again.`, { message: err.message || err.toString() }),
- type: 'error',
- retentionTime: 5000,
- });
- addNotificationInternal(callbackHelpers, notification);
- // clear out app state
- resetCreds();
}
- }
- }
+ },
);
const setShowTenantDialog = useRecoilCallback(({ set }: CallbackInterface) => (show: boolean) => {
@@ -110,34 +113,35 @@ export const authDispatcher = () => {
});
const setCurrentUser = useRecoilCallback(
- ({ set }: CallbackInterface) => (token: string | undefined, graph?: string) => {
- setPrimaryToken(token || '');
- setGraphToken(graph || '');
-
- if (token) {
- const decoded = decodeToken(token);
-
- set(currentUserState, {
- token: token ?? null,
- graph: graph ?? null,
- email: decoded.upn,
- name: decoded.name,
- expiration: (decoded.exp || 0) * 1000, // convert to ms,
- sessionExpired: false,
- });
- set(isAuthenticatedState, true);
-
- set(currentTenantIdState, decoded.tid);
- setTenantId(decoded.tid);
- } else {
- set(currentUserState, {
- token: '',
- graph: '',
- sessionExpired: true,
- });
- set(isAuthenticatedState, false);
- }
- }
+ ({ set }: CallbackInterface) =>
+ (token: string | undefined, graph?: string) => {
+ setPrimaryToken(token || '');
+ setGraphToken(graph || '');
+
+ if (token) {
+ const decoded = decodeToken(token);
+
+ set(currentUserState, {
+ token: token ?? null,
+ graph: graph ?? null,
+ email: decoded.upn,
+ name: decoded.name,
+ expiration: (decoded.exp || 0) * 1000, // convert to ms,
+ sessionExpired: false,
+ });
+ set(isAuthenticatedState, true);
+
+ set(currentTenantIdState, decoded.tid);
+ setTenantId(decoded.tid);
+ } else {
+ set(currentUserState, {
+ token: '',
+ graph: '',
+ sessionExpired: true,
+ });
+ set(isAuthenticatedState, false);
+ }
+ },
);
const refreshLoginStatus = useRecoilCallback(() => async () => {
@@ -200,7 +204,7 @@ export const authDispatcher = () => {
resetCreds();
}
}
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/botProjectFile.ts b/Composer/packages/client/src/recoilModel/dispatchers/botProjectFile.ts
index 82d26a077d..44e743358c 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/botProjectFile.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/botProjectFile.ts
@@ -8,14 +8,13 @@ import { CallbackInterface, useRecoilCallback } from 'recoil';
import { produce } from 'immer';
import { BotProjectFile, BotProjectSpaceSkill, Skill } from '@bfc/shared';
+import { isExternalLink } from '../../utils/urlUtil';
import { botNameIdentifierState, botProjectFileState, dispatcherState, locationState, settingsState } from '../atoms';
import { rootBotProjectIdSelector } from '../selectors';
import { setRootBotSettingState } from './setting';
import { addSkillFiles, deleteSkillFiles } from './utils/skills';
-const urlRegex = /^http[s]?:\/\/\w+/;
-
export const botProjectFileDispatcher = () => {
const addLocalSkill = useRecoilCallback(({ set, snapshot }: CallbackInterface) => async (skillId: string) => {
const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
@@ -40,40 +39,36 @@ export const botProjectFileDispatcher = () => {
});
const addRemoteSkill = useRecoilCallback(
- ({ set, snapshot }: CallbackInterface) => async (
- skillId: string,
- manifestUrl: string,
- zipContent: Record,
- endpointName: string
- ) => {
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (!rootBotProjectId) {
- return;
- }
- const botName = await snapshot.getPromise(botNameIdentifierState(skillId));
- let finalManifestUrl: string | undefined;
- if (urlRegex.test(manifestUrl)) {
- finalManifestUrl = manifestUrl;
- } else {
- const data = await addSkillFiles(rootBotProjectId, botName, manifestUrl, zipContent);
- if (data.error) {
- throw data.error;
+ ({ set, snapshot }: CallbackInterface) =>
+ async (skillId: string, manifestUrl: string, zipContent: Record, endpointName: string) => {
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (!rootBotProjectId) {
+ return;
+ }
+ const botName = await snapshot.getPromise(botNameIdentifierState(skillId));
+ let finalManifestUrl: string | undefined;
+ if (isExternalLink(manifestUrl)) {
+ finalManifestUrl = manifestUrl;
+ } else {
+ const data = await addSkillFiles(rootBotProjectId, botName, manifestUrl, zipContent);
+ if (data.error) {
+ throw data.error;
+ }
+ finalManifestUrl = data.manifest?.relativePath;
}
- finalManifestUrl = data.manifest?.relativePath;
- }
- set(botProjectFileState(rootBotProjectId), (current) => {
- const result = produce(current, (draftState) => {
- const skill: BotProjectSpaceSkill = {
- manifest: finalManifestUrl,
- remote: true,
- endpointName,
- };
-
- draftState.content.skills[botName] = skill;
+ set(botProjectFileState(rootBotProjectId), (current) => {
+ const result = produce(current, (draftState) => {
+ const skill: BotProjectSpaceSkill = {
+ manifest: finalManifestUrl,
+ remote: true,
+ endpointName,
+ };
+
+ draftState.content.skills[botName] = skill;
+ });
+ return result;
});
- return result;
- });
- }
+ },
);
const removeSkill = useRecoilCallback((callbackHelpers: CallbackInterface) => async (skillId: string) => {
@@ -108,7 +103,7 @@ export const botProjectFileDispatcher = () => {
draftState?.skillConfiguration?.allowedCallers.length > 0
) {
draftState.skillConfiguration.allowedCallers = draftState.skillConfiguration.allowedCallers.filter(
- (item) => item !== msAppId
+ (item) => item !== msAppId,
);
}
if (
@@ -117,7 +112,7 @@ export const botProjectFileDispatcher = () => {
draftState?.runtimeSettings?.skills?.allowedCallers.length > 0
) {
draftState.runtimeSettings.skills.allowedCallers = draftState.runtimeSettings.skills.allowedCallers.filter(
- (item) => item !== msAppId
+ (item) => item !== msAppId,
);
}
});
@@ -126,101 +121,100 @@ export const botProjectFileDispatcher = () => {
});
const updateManifest = useRecoilCallback(
- ({ set, snapshot }: CallbackInterface) => async (skillProjectId: string, manifestId?: string) => {
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (!rootBotProjectId) {
- return;
- }
-
- const skillNameIdentifier = await snapshot.getPromise(botNameIdentifierState(skillProjectId));
- set(botProjectFileState(rootBotProjectId), (current: BotProjectFile) => {
- const result = produce(current, (draftState) => {
- if (skillNameIdentifier) {
- if (!manifestId) {
- delete draftState.content.skills[skillNameIdentifier].manifest;
- } else {
- draftState.content.skills[skillNameIdentifier] = {
- ...draftState.content.skills[skillNameIdentifier],
- manifest: manifestId,
- };
+ ({ set, snapshot }: CallbackInterface) =>
+ async (skillProjectId: string, manifestId?: string) => {
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (!rootBotProjectId) {
+ return;
+ }
+
+ const skillNameIdentifier = await snapshot.getPromise(botNameIdentifierState(skillProjectId));
+ set(botProjectFileState(rootBotProjectId), (current: BotProjectFile) => {
+ const result = produce(current, (draftState) => {
+ if (skillNameIdentifier) {
+ if (!manifestId) {
+ delete draftState.content.skills[skillNameIdentifier].manifest;
+ } else {
+ draftState.content.skills[skillNameIdentifier] = {
+ ...draftState.content.skills[skillNameIdentifier],
+ manifest: manifestId,
+ };
+ }
}
- }
+ });
+ return result;
});
- return result;
- });
- }
+ },
);
const updateSkillsData = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- skillNameIdentifier: string,
- skillsData: Skill,
- selectedEndpointIndex: number
- ) => {
- const { set, snapshot } = callbackHelpers;
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (!rootBotProjectId) {
- return;
- }
-
- const settings = await snapshot.getPromise(settingsState(rootBotProjectId));
- const dispatcher = await snapshot.getPromise(dispatcherState);
-
- let msAppId = '',
- endpointUrl = '',
- endpointName = '';
-
- if (selectedEndpointIndex !== -1 && skillsData.manifest) {
- const data = skillsData.manifest?.endpoints[selectedEndpointIndex];
- msAppId = data.msAppId;
- endpointUrl = data.endpointUrl;
- endpointName = data.name;
+ (callbackHelpers: CallbackInterface) =>
+ async (skillNameIdentifier: string, skillsData: Skill, selectedEndpointIndex: number) => {
+ const { set, snapshot } = callbackHelpers;
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (!rootBotProjectId) {
+ return;
+ }
- set(botProjectFileState(rootBotProjectId), (current) => {
- const result = produce(current, (draftState) => {
- draftState.content.skills[skillNameIdentifier].endpointName = endpointName;
+ const settings = await snapshot.getPromise(settingsState(rootBotProjectId));
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+
+ let msAppId = '',
+ endpointUrl = '',
+ endpointName = '';
+
+ if (selectedEndpointIndex !== -1 && skillsData.manifest) {
+ const data = skillsData.manifest?.endpoints[selectedEndpointIndex];
+ msAppId = data.msAppId;
+ endpointUrl = data.endpointUrl;
+ endpointName = data.name;
+
+ set(botProjectFileState(rootBotProjectId), (current) => {
+ const result = produce(current, (draftState) => {
+ draftState.content.skills[skillNameIdentifier].endpointName = endpointName;
+ });
+ return result;
});
- return result;
- });
- } else {
- set(botProjectFileState(rootBotProjectId), (current) => {
- const result = produce(current, (draftState) => {
- delete draftState.content.skills[skillNameIdentifier].endpointName;
+ } else {
+ set(botProjectFileState(rootBotProjectId), (current) => {
+ const result = produce(current, (draftState) => {
+ delete draftState.content.skills[skillNameIdentifier].endpointName;
+ });
+ return result;
});
- return result;
- });
- }
- if (settings.skill) {
- dispatcher.setSettings(
- rootBotProjectId,
- produce(settings, (draftSettings) => {
- draftSettings.skill = {
- ...settings.skill,
- [skillNameIdentifier]: {
- endpointUrl,
- msAppId,
- },
- };
- })
- );
- }
- }
+ }
+ if (settings.skill) {
+ dispatcher.setSettings(
+ rootBotProjectId,
+ produce(settings, (draftSettings) => {
+ draftSettings.skill = {
+ ...settings.skill,
+ [skillNameIdentifier]: {
+ endpointUrl,
+ msAppId,
+ },
+ };
+ }),
+ );
+ }
+ },
);
const updateEndpointName = useRecoilCallback(
- ({ set, snapshot }: CallbackInterface) => async (skillNameIdentifier: string, endpointName: string) => {
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (!rootBotProjectId) {
- return;
- }
-
- set(botProjectFileState(rootBotProjectId), (current) => {
- const result = produce(current, (draftState) => {
- draftState.content.skills[skillNameIdentifier].endpointName = endpointName;
+ ({ set, snapshot }: CallbackInterface) =>
+ async (skillNameIdentifier: string, endpointName: string) => {
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (!rootBotProjectId) {
+ return;
+ }
+
+ set(botProjectFileState(rootBotProjectId), (current) => {
+ const result = produce(current, (draftState) => {
+ draftState.content.skills[skillNameIdentifier].endpointName = endpointName;
+ });
+ return result;
});
- return result;
- });
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/builder.ts b/Composer/packages/client/src/recoilModel/dispatchers/builder.ts
index 4f07c26317..d2b108a7d1 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/builder.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/builder.ts
@@ -20,56 +20,57 @@ const checkEmptyQuestionOrAnswerInQnAFile = (sections) => {
export const builderDispatcher = () => {
const build = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- projectId: string,
- luisConfig: ILuisConfig,
- qnaConfig: IQnAConfig,
- orchestratorConfig: IOrchestratorConfig
- ) => {
- const { set, snapshot } = callbackHelpers;
- const dialogs = await snapshot.getPromise(dialogsWithLuProviderSelectorFamily(projectId));
- const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const referredLuFiles = luUtil.checkLuisBuild(luFiles, dialogs);
- const referredQnaFiles = qnaUtil.checkQnaBuild(qnaFiles, dialogs);
- const errorMsg = referredQnaFiles.reduce(
- (result, file) => {
- if (
- file.qnaSections &&
- file.qnaSections.length > 0 &&
- checkEmptyQuestionOrAnswerInQnAFile(file.qnaSections)
- ) {
- result.message = result.message + `${file.id}.qna file contains empty answer or questions`;
- }
- return result;
- },
- { title: Text.LUISDEPLOYFAILURE, message: '' }
- );
- if (errorMsg.message) {
- set(botBuildTimeErrorState(projectId), errorMsg);
- set(botStatusState(projectId), BotStatus.failed);
- return;
- }
- try {
- await httpClient.post(`/projects/${projectId}/build`, {
- luisConfig,
- qnaConfig,
- orchestratorConfig,
- projectId,
- luFiles: referredLuFiles.map((file) => ({ id: file.id, isEmpty: file.empty })),
- qnaFiles: referredQnaFiles.map((file) => ({ id: file.id, isEmpty: file.empty })),
- });
- luFileStatusStorage.publishAll(projectId);
- qnaFileStatusStorage.publishAll(projectId);
- set(botStatusState(projectId), BotStatus.published);
- } catch (err) {
- set(botStatusState(projectId), BotStatus.failed);
- set(botBuildTimeErrorState(projectId), {
- title: Text.LUISDEPLOYFAILURE,
- message: err.response?.data?.message || err.message,
- });
- }
- }
+ (callbackHelpers: CallbackInterface) =>
+ async (
+ projectId: string,
+ luisConfig: ILuisConfig,
+ qnaConfig: IQnAConfig,
+ orchestratorConfig: IOrchestratorConfig,
+ ) => {
+ const { set, snapshot } = callbackHelpers;
+ const dialogs = await snapshot.getPromise(dialogsWithLuProviderSelectorFamily(projectId));
+ const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const referredLuFiles = luUtil.checkLuisBuild(luFiles, dialogs);
+ const referredQnaFiles = qnaUtil.checkQnaBuild(qnaFiles, dialogs);
+ const errorMsg = referredQnaFiles.reduce(
+ (result, file) => {
+ if (
+ file.qnaSections &&
+ file.qnaSections.length > 0 &&
+ checkEmptyQuestionOrAnswerInQnAFile(file.qnaSections)
+ ) {
+ result.message = result.message + `${file.id}.qna file contains empty answer or questions`;
+ }
+ return result;
+ },
+ { title: Text.LUISDEPLOYFAILURE, message: '' },
+ );
+ if (errorMsg.message) {
+ set(botBuildTimeErrorState(projectId), errorMsg);
+ set(botStatusState(projectId), BotStatus.failed);
+ return;
+ }
+ try {
+ await httpClient.post(`/projects/${projectId}/build`, {
+ luisConfig,
+ qnaConfig,
+ orchestratorConfig,
+ projectId,
+ luFiles: referredLuFiles.map((file) => ({ id: file.id, isEmpty: file.empty })),
+ qnaFiles: referredQnaFiles.map((file) => ({ id: file.id, isEmpty: file.empty })),
+ });
+ luFileStatusStorage.publishAll(projectId);
+ qnaFileStatusStorage.publishAll(projectId);
+ set(botStatusState(projectId), BotStatus.published);
+ } catch (err) {
+ set(botStatusState(projectId), BotStatus.failed);
+ set(botBuildTimeErrorState(projectId), {
+ title: Text.LUISDEPLOYFAILURE,
+ message: err.response?.data?.message || err.message,
+ });
+ }
+ },
);
return {
build,
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/dialogSchema.ts b/Composer/packages/client/src/recoilModel/dispatchers/dialogSchema.ts
index 717a6a06a4..5eb9b49e22 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/dialogSchema.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/dialogSchema.ts
@@ -12,7 +12,7 @@ const createDialogSchema = ({ set }: CallbackInterface, dialogSchema: DialogSche
export const removeDialogSchema = (
{ set }: CallbackInterface,
- { id, projectId }: { id: string; projectId: string }
+ { id, projectId }: { id: string; projectId: string },
) => {
set(dialogSchemasState(projectId), (dialogSchemas) => dialogSchemas.filter((dialogSchema) => dialogSchema.id !== id));
};
@@ -28,9 +28,9 @@ export const dialogSchemaDispatcher = () => {
}
set(dialogSchemasState(projectId), (dialogSchemas) =>
- dialogSchemas.map((schema) => (schema.id === dialogSchema.id ? dialogSchema : schema))
+ dialogSchemas.map((schema) => (schema.id === dialogSchema.id ? dialogSchema : schema)),
);
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/dialogs.ts b/Composer/packages/client/src/recoilModel/dispatchers/dialogs.ts
index c3a47be533..1ef8734282 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/dialogs.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/dialogs.ts
@@ -42,22 +42,23 @@ export const dialogsDispatcher = () => {
await removeLuFileState(callbackHelpers, { id, projectId });
await removeQnAFileState(callbackHelpers, { id, projectId });
removeDialogSchema(callbackHelpers, { id, projectId });
- }
+ },
);
const updateDialog = useRecoilCallback(
- ({ snapshot, set }: CallbackInterface) => async ({ id, content, projectId }) => {
- // migration: add id for dialog
- if (typeof content === 'object' && !content.id) {
- content.id = id;
- }
-
- const fixedContent = JSON.parse(autofixReferInDialog(id, JSON.stringify(content)));
-
- const dialog = await snapshot.getPromise(dialogState({ projectId, dialogId: id }));
- const newDialog: DialogInfo = { ...dialog, ...dialogIndexer.parse(dialog.id, fixedContent) };
- set(dialogState({ projectId, dialogId: id }), newDialog);
- }
+ ({ snapshot, set }: CallbackInterface) =>
+ async ({ id, content, projectId }) => {
+ // migration: add id for dialog
+ if (typeof content === 'object' && !content.id) {
+ content.id = id;
+ }
+
+ const fixedContent = JSON.parse(autofixReferInDialog(id, JSON.stringify(content)));
+
+ const dialog = await snapshot.getPromise(dialogState({ projectId, dialogId: id }));
+ const newDialog: DialogInfo = { ...dialog, ...dialogIndexer.parse(dialog.id, fixedContent) };
+ set(dialogState({ projectId, dialogId: id }), newDialog);
+ },
);
const createDialogBegin = useRecoilCallback(
@@ -66,7 +67,7 @@ export const dialogsDispatcher = () => {
set(actionsSeedState(projectId), actions);
set(onCreateDialogCompleteState(projectId), { func: onComplete });
set(showCreateDialogModalState, true);
- }
+ },
);
const createDialogCancel = useRecoilCallback((callbackHelpers: CallbackInterface) => async (projectId: string) => {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/editor.ts b/Composer/packages/client/src/recoilModel/dispatchers/editor.ts
index d32193dee8..749840bdd2 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/editor.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/editor.ts
@@ -8,9 +8,10 @@ import { clipboardActionsState, visualEditorSelectionState } from '../atoms/appS
export const editorDispatcher = () => {
const setVisualEditorClipboard = useRecoilCallback(
- ({ set }: CallbackInterface) => (clipboardActions: any[], projectId: string) => {
- set(clipboardActionsState(projectId), [...clipboardActions]);
- }
+ ({ set }: CallbackInterface) =>
+ (clipboardActions: any[], projectId: string) => {
+ set(clipboardActionsState(projectId), [...clipboardActions]);
+ },
);
const setVisualEditorSelection = useRecoilCallback(({ set }: CallbackInterface) => (selection: string[]) => {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/extensions.ts b/Composer/packages/client/src/recoilModel/dispatchers/extensions.ts
index 7730050e3e..8052909b29 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/extensions.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/extensions.ts
@@ -48,7 +48,7 @@ export const extensionsDispatcher = () => {
// eslint-disable-next-line no-console
console.error(err);
}
- }
+ },
);
const removeExtension = useRecoilCallback((callbackHelpers: CallbackInterface) => async (extensionName: string) => {
@@ -86,7 +86,7 @@ export const extensionsDispatcher = () => {
// eslint-disable-next-line no-console
console.error(err);
}
- }
+ },
);
const updateExtensionSettings = useRecoilCallback(
@@ -100,7 +100,7 @@ export const extensionsDispatcher = () => {
// eslint-disable-next-line no-console
console.error(err);
}
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts b/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts
index 44e3ee7181..21d1b31a2f 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/formDialogs.ts
@@ -28,8 +28,10 @@ export const formDialogsDispatcher = () => {
navigate(`/bot/${projectId}/forms/${id}`);
});
- const updateFormDialogSchema = useRecoilCallback(({ set }: CallbackInterface) => ({ id, content, projectId }) =>
- set(formDialogSchemaState({ projectId, schemaId: id }), { id, content })
+ const updateFormDialogSchema = useRecoilCallback(
+ ({ set }: CallbackInterface) =>
+ ({ id, content, projectId }) =>
+ set(formDialogSchemaState({ projectId, schemaId: id }), { id, content }),
);
const removeFormDialogSchema = useRecoilCallback(({ set, reset }: CallbackInterface) => async ({ id, projectId }) => {
@@ -50,9 +52,8 @@ export const formDialogsDispatcher = () => {
}
try {
- const { data } = await httpClient.get>>(
- '/formDialogs/templateSchemas'
- );
+ const { data } =
+ await httpClient.get>>('/formDialogs/templateSchemas');
const templates = Object.keys(data).map((id) => ({ id, ...data[id] }));
set(formDialogLibraryTemplatesState, templates);
@@ -66,63 +67,68 @@ export const formDialogsDispatcher = () => {
});
const generateFormDialog = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ projectId, schemaId }) => {
- const { set, reset, snapshot } = callbackHelpers;
- reset(formDialogErrorState);
-
- const { reloadProject } = await snapshot.getPromise(dispatcherState);
- try {
- set(formDialogGenerationProgressingState, true);
-
- const formDialogSchema = await snapshot.getPromise(formDialogSchemaState({ projectId, schemaId }));
- if (!formDialogSchema) {
- return;
+ (callbackHelpers: CallbackInterface) =>
+ async ({ projectId, schemaId }) => {
+ const { set, reset, snapshot } = callbackHelpers;
+ reset(formDialogErrorState);
+
+ const { reloadProject } = await snapshot.getPromise(dispatcherState);
+ try {
+ set(formDialogGenerationProgressingState, true);
+
+ const formDialogSchema = await snapshot.getPromise(formDialogSchemaState({ projectId, schemaId }));
+ if (!formDialogSchema) {
+ return;
+ }
+
+ const generateStartTime = Date.now();
+ const response = await httpClient.post(`/formDialogs/${projectId}/generate`, {
+ name: schemaId,
+ });
+ TelemetryClient.track('FormDialogGenerated', { durationMilliseconds: Date.now() - generateStartTime });
+ await reloadProject(response.data.id);
+ } catch (ex) {
+ set(formDialogErrorState, {
+ ...ex,
+ message: formatMessage(
+ 'Generating form dialog using "{ schemaId }" schema failed. Please try again later.',
+ {
+ schemaId,
+ },
+ ),
+ kind: 'generation',
+ logs: ex.data?.logs,
+ });
+ } finally {
+ set(formDialogGenerationProgressingState, false);
}
-
- const generateStartTime = Date.now();
- const response = await httpClient.post(`/formDialogs/${projectId}/generate`, {
- name: schemaId,
- });
- TelemetryClient.track('FormDialogGenerated', { durationMilliseconds: Date.now() - generateStartTime });
- await reloadProject(response.data.id);
- } catch (ex) {
- set(formDialogErrorState, {
- ...ex,
- message: formatMessage('Generating form dialog using "{ schemaId }" schema failed. Please try again later.', {
- schemaId,
- }),
- kind: 'generation',
- logs: ex.data?.logs,
- });
- } finally {
- set(formDialogGenerationProgressingState, false);
- }
- }
+ },
);
const removeFormDialog = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ projectId, dialogId }) => {
- const { set, reset, snapshot } = callbackHelpers;
- reset(formDialogErrorState);
-
- const dialog = await snapshot.getPromise(dialogState({ projectId, dialogId }));
- const { reloadProject } = await snapshot.getPromise(dispatcherState);
-
- try {
- if (!dialog) {
- return;
+ (callbackHelpers: CallbackInterface) =>
+ async ({ projectId, dialogId }) => {
+ const { set, reset, snapshot } = callbackHelpers;
+ reset(formDialogErrorState);
+
+ const dialog = await snapshot.getPromise(dialogState({ projectId, dialogId }));
+ const { reloadProject } = await snapshot.getPromise(dispatcherState);
+
+ try {
+ if (!dialog) {
+ return;
+ }
+
+ const response = await httpClient.delete(`/formDialogs/${projectId}/${dialogId}`);
+ await reloadProject(response.data.id);
+ } catch (ex) {
+ set(formDialogErrorState, {
+ ...ex,
+ message: formatMessage('Deleting "{ dialogId }" failed.', { dialogId }),
+ kind: 'deletion',
+ });
}
-
- const response = await httpClient.delete(`/formDialogs/${projectId}/${dialogId}`);
- await reloadProject(response.data.id);
- } catch (ex) {
- set(formDialogErrorState, {
- ...ex,
- message: formatMessage('Deleting "{ dialogId }" failed.', { dialogId }),
- kind: 'deletion',
- });
- }
- }
+ },
);
const navigateToGeneratedDialog = ({ projectId, schemaId }) => {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/lg.ts b/Composer/packages/client/src/recoilModel/dispatchers/lg.ts
index 9245a2d2ff..beb414f53e 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/lg.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/lg.ts
@@ -38,14 +38,14 @@ const updateLgFiles = (
deletes?: LgFile[];
updates?: LgFile[];
},
- needUpdate?: (current: LgFile, changed: LgFile) => boolean
+ needUpdate?: (current: LgFile, changed: LgFile) => boolean,
) => {
const { updates, adds, deletes } = changes;
// updates
updates?.forEach((lgFile) => {
set(lgFileState({ projectId, lgFileId: lgFile.id }), (preFile) =>
- needUpdate ? (needUpdate(preFile, lgFile) ? lgFile : preFile) : lgFile
+ needUpdate ? (needUpdate(preFile, lgFile) ? lgFile : preFile) : lgFile,
);
});
@@ -58,7 +58,7 @@ const updateLgFiles = (
if (adds?.length) {
adds.forEach((lgFile) => {
set(lgFileState({ projectId, lgFileId: lgFile.id }), (preFile) =>
- needUpdate ? (needUpdate(preFile, lgFile) ? lgFile : preFile) : lgFile
+ needUpdate ? (needUpdate(preFile, lgFile) ? lgFile : preFile) : lgFile,
);
});
set(lgFileIdsState(projectId), (ids) => ids.concat(adds.map((file) => file.id)));
@@ -69,7 +69,7 @@ const updateLgFiles = (
export const getRelatedLgFileChanges = async (
projectId: string,
originLgFiles: LgFile[],
- updatedLgFile: LgFile
+ updatedLgFile: LgFile,
): Promise => {
const { id } = updatedLgFile;
const dialogId = getBaseName(id);
@@ -97,7 +97,7 @@ export const getRelatedLgFileChanges = async (
};
});
const deletedTemplates = differenceBy(originLgFile.templates, updatedLgFile.templates, 'name').filter(
- templateIsNotEmpty
+ templateIsNotEmpty,
);
const onlyAdds = addedTemplates.length && !deletedTemplates.length;
const onlyDeletes = !addedTemplates.length && deletedTemplates.length;
@@ -117,7 +117,7 @@ export const getRelatedLgFileChanges = async (
projectId,
newLgFile,
deletedTemplates.map(({ name }) => name),
- lgFiles
+ lgFiles,
)) as LgFile;
changes.push(newLgFile);
}
@@ -129,7 +129,7 @@ export const getRelatedLgFileChanges = async (
file,
deletedTemplates[0].name,
addedTemplates[0],
- lgFiles
+ lgFiles,
)) as LgFile;
changes.push(newLgFile);
}
@@ -141,7 +141,7 @@ export const getRelatedLgFileChanges = async (
// when do create, passed id do not carried with locale
export const createLgFileState = async (
callbackHelpers: CallbackInterface,
- { id, content, projectId }: { id: string; content: string; projectId: string }
+ { id, content, projectId }: { id: string; content: string; projectId: string },
) => {
try {
const { snapshot } = callbackHelpers;
@@ -178,7 +178,7 @@ export const createLgFileState = async (
export const removeLgFileState = async (
callbackHelpers: CallbackInterface,
- { id, projectId }: { id: string; projectId: string }
+ { id, projectId }: { id: string; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
@@ -195,291 +195,254 @@ export const removeLgFileState = async (
export const lgDispatcher = () => {
const createLgFile = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- content,
- projectId,
- }: {
- id: string;
- content: string;
- projectId: string;
- }) => {
- try {
- await createLgFileState(callbackHelpers, { id, content, projectId });
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, content, projectId }: { id: string; content: string; projectId: string }) => {
+ try {
+ await createLgFileState(callbackHelpers, { id, content, projectId });
+ } catch (error) {
+ setError(callbackHelpers, error);
+ }
+ },
);
const removeLgFile = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ id, projectId }: { id: string; projectId: string }) => {
- await removeLgFileState(callbackHelpers, { id, projectId });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, projectId }: { id: string; projectId: string }) => {
+ await removeLgFileState(callbackHelpers, { id, projectId });
+ },
);
const updateLgFile = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- content,
- projectId,
- }: {
- id: string;
- content: string;
- projectId: string;
- }) => {
- try {
- const { set, snapshot } = callbackHelpers;
- //set content first
- set(lgFileState({ projectId, lgFileId: id }), (prevLgFile) => {
- return {
- ...prevLgFile,
- content,
- };
- });
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, content, projectId }: { id: string; content: string; projectId: string }) => {
+ try {
+ const { set, snapshot } = callbackHelpers;
+ //set content first
+ set(lgFileState({ projectId, lgFileId: id }), (prevLgFile) => {
+ return {
+ ...prevLgFile,
+ content,
+ };
+ });
+
+ const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
+ const updatedFile = (await LgWorker.parse(projectId, id, content, lgFiles)) as LgFile;
+ const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
+
+ // compare to drop expired change on current id lg file.
+ /**
+ * Why other methods do not need double check content?
+ * Because this method already did set content before call updateLgFiles.
+ */
+
+ updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles }, (current, changed) => {
+ // compare to drop expired content already setted above.
+ return current.id === id ? current?.content === changed?.content : true;
+ });
+
+ // if changes happen on common.lg, async re-parse all.
+ if (getBaseName(id) === 'common') {
+ const { reparseAllLgFiles } = await snapshot.getPromise(dispatcherState);
+ reparseAllLgFiles({ projectId });
+ }
+ } catch (error) {
+ setError(callbackHelpers, error);
+ }
+ },
+ );
+ const updateLgTemplate = useRecoilCallback(
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ templateName,
+ template,
+ projectId,
+ }: {
+ id: string;
+ templateName: string;
+ template: LgTemplate;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
- const updatedFile = (await LgWorker.parse(projectId, id, content, lgFiles)) as LgFile;
- const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
-
- // compare to drop expired change on current id lg file.
- /**
- * Why other methods do not need double check content?
- * Because this method already did set content before call updateLgFiles.
- */
-
- updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles }, (current, changed) => {
- // compare to drop expired content already setted above.
- return current.id === id ? current?.content === changed?.content : true;
- });
+ const lgFile = lgFiles.find((file) => file.id === id);
+ if (!lgFile) return lgFiles;
+ const sameIdOtherLocaleFiles = lgFiles.filter((file) => getBaseName(file.id) === getBaseName(id));
- // if changes happen on common.lg, async re-parse all.
- if (getBaseName(id) === 'common') {
- const { reparseAllLgFiles } = await snapshot.getPromise(dispatcherState);
- reparseAllLgFiles({ projectId });
+ // create need sync to multi locale file.
+ const originTemplate = lgFile.templates.find(({ name }) => name === templateName);
+ if (!originTemplate) {
+ await createLgTemplate({ id, template, projectId });
+ return;
}
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
- );
- const updateLgTemplate = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- templateName,
- template,
- projectId,
- }: {
- id: string;
- templateName: string;
- template: LgTemplate;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
- const lgFile = lgFiles.find((file) => file.id === id);
- if (!lgFile) return lgFiles;
- const sameIdOtherLocaleFiles = lgFiles.filter((file) => getBaseName(file.id) === getBaseName(id));
-
- // create need sync to multi locale file.
- const originTemplate = lgFile.templates.find(({ name }) => name === templateName);
- if (!originTemplate) {
- await createLgTemplate({ id, template, projectId });
- return;
- }
-
- try {
- if (template.name !== templateName) {
- // name change, need update cross multi locale file.
- const changes: LgFile[] = [];
-
- for (const item of sameIdOtherLocaleFiles) {
+ try {
+ if (template.name !== templateName) {
+ // name change, need update cross multi locale file.
+ const changes: LgFile[] = [];
+
+ for (const item of sameIdOtherLocaleFiles) {
+ const updatedFile = (await LgWorker.updateTemplate(
+ projectId,
+ item,
+ templateName,
+ { name: template.name },
+ lgFiles,
+ )) as LgFile;
+ changes.push(updatedFile);
+ }
+ updateLgFiles(callbackHelpers, projectId, { updates: changes });
+ } else {
+ // body change, only update current locale file
const updatedFile = (await LgWorker.updateTemplate(
projectId,
- item,
+ lgFile,
templateName,
- { name: template.name },
- lgFiles
+ { body: template.body },
+ lgFiles,
)) as LgFile;
- changes.push(updatedFile);
+ updateLgFiles(callbackHelpers, projectId, { updates: [updatedFile] });
}
- updateLgFiles(callbackHelpers, projectId, { updates: changes });
- } else {
- // body change, only update current locale file
- const updatedFile = (await LgWorker.updateTemplate(
- projectId,
- lgFile,
- templateName,
- { body: template.body },
- lgFiles
- )) as LgFile;
- updateLgFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ } catch (error) {
+ setError(callbackHelpers, error);
+ return;
}
- } catch (error) {
- setError(callbackHelpers, error);
- return;
- }
-
- // if changes happen on common.lg, async re-parse all.
- if (getBaseName(id) === 'common') {
- const { reparseAllLgFiles } = await snapshot.getPromise(dispatcherState);
- reparseAllLgFiles({ projectId });
- }
- }
- );
- const createLgTemplate = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- template,
- projectId,
- }: {
- id: string;
- template: LgTemplate;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
- const lgFile = lgFiles.find((file) => file.id === id);
- if (!lgFile) return lgFiles;
- const updatedFile = (await LgWorker.addTemplate(projectId, lgFile, template, lgFiles)) as LgFile;
- const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
- updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles });
- }
+ // if changes happen on common.lg, async re-parse all.
+ if (getBaseName(id) === 'common') {
+ const { reparseAllLgFiles } = await snapshot.getPromise(dispatcherState);
+ reparseAllLgFiles({ projectId });
+ }
+ },
);
- const createLgTemplates = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- templates,
- projectId,
- }: {
- id: string;
- templates: LgTemplate[];
- projectId: string;
- }) => {
- try {
+ const createLgTemplate = useRecoilCallback(
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, template, projectId }: { id: string; template: LgTemplate; projectId: string }) => {
const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
const lgFile = lgFiles.find((file) => file.id === id);
if (!lgFile) return lgFiles;
- const updatedFile = (await LgWorker.addTemplates(projectId, lgFile, templates, lgFiles)) as LgFile;
+ const updatedFile = (await LgWorker.addTemplate(projectId, lgFile, template, lgFiles)) as LgFile;
const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles });
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ },
);
- const removeLgTemplate = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- templateName,
- projectId,
- }: {
- id: string;
- templateName: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
- const lgFile = lgFiles.find((file) => file.id === id);
- if (!lgFile) return lgFiles;
- try {
- const updatedFile = (await LgWorker.removeTemplate(projectId, lgFile, templateName, lgFiles)) as LgFile;
-
- const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
- updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles });
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ const createLgTemplates = useRecoilCallback(
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, templates, projectId }: { id: string; templates: LgTemplate[]; projectId: string }) => {
+ try {
+ const { snapshot } = callbackHelpers;
+ const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
+ const lgFile = lgFiles.find((file) => file.id === id);
+ if (!lgFile) return lgFiles;
+ const updatedFile = (await LgWorker.addTemplates(projectId, lgFile, templates, lgFiles)) as LgFile;
+ const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
+ updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles });
+ } catch (error) {
+ setError(callbackHelpers, error);
+ }
+ },
);
- const removeLgTemplates = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- templateNames,
- projectId,
- }: {
- id: string;
- templateNames: string[];
- projectId: string;
- }) => {
- try {
+ const removeLgTemplate = useRecoilCallback(
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, templateName, projectId }: { id: string; templateName: string; projectId: string }) => {
const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
const lgFile = lgFiles.find((file) => file.id === id);
if (!lgFile) return lgFiles;
+ try {
+ const updatedFile = (await LgWorker.removeTemplate(projectId, lgFile, templateName, lgFiles)) as LgFile;
- const updatedFile = (await LgWorker.removeTemplates(projectId, lgFile, templateNames, lgFiles)) as LgFile;
+ const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
+ updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles });
+ } catch (error) {
+ setError(callbackHelpers, error);
+ }
+ },
+ );
- const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
- updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles });
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ const removeLgTemplates = useRecoilCallback(
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, templateNames, projectId }: { id: string; templateNames: string[]; projectId: string }) => {
+ try {
+ const { snapshot } = callbackHelpers;
+ const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
+ const lgFile = lgFiles.find((file) => file.id === id);
+ if (!lgFile) return lgFiles;
+
+ const updatedFile = (await LgWorker.removeTemplates(projectId, lgFile, templateNames, lgFiles)) as LgFile;
+
+ const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
+ updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles });
+ } catch (error) {
+ setError(callbackHelpers, error);
+ }
+ },
);
const copyLgTemplate = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- fromTemplateName,
- toTemplateName,
- projectId,
- }: {
- id: string;
- fromTemplateName: string;
- toTemplateName: string;
- projectId: string;
- }) => {
- try {
- const { snapshot } = callbackHelpers;
- const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
- const lgFile = lgFiles.find((file) => file.id === id);
- if (!lgFile) return lgFiles;
- const updatedFile = (await LgWorker.copyTemplate(
- projectId,
- lgFile,
- fromTemplateName,
- toTemplateName,
- lgFiles
- )) as LgFile;
- const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
- updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles });
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ fromTemplateName,
+ toTemplateName,
+ projectId,
+ }: {
+ id: string;
+ fromTemplateName: string;
+ toTemplateName: string;
+ projectId: string;
+ }) => {
+ try {
+ const { snapshot } = callbackHelpers;
+ const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
+ const lgFile = lgFiles.find((file) => file.id === id);
+ if (!lgFile) return lgFiles;
+ const updatedFile = (await LgWorker.copyTemplate(
+ projectId,
+ lgFile,
+ fromTemplateName,
+ toTemplateName,
+ lgFiles,
+ )) as LgFile;
+ const updatedFiles = await getRelatedLgFileChanges(projectId, lgFiles, updatedFile);
+ updateLgFiles(callbackHelpers, projectId, { updates: updatedFiles });
+ } catch (error) {
+ setError(callbackHelpers, error);
+ }
+ },
);
const reparseAllLgFiles = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ projectId }: { projectId: string }) => {
- try {
- const { snapshot } = callbackHelpers;
- const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
- const reparsedLgFiles: LgFile[] = [];
- for (const file of lgFiles) {
- const reparsedFile = (await LgDiagnosticWorker.parse(projectId, file.id, file.content, lgFiles)) as LgFile;
- reparsedLgFiles.push({ ...file, diagnostics: reparsedFile.diagnostics });
+ (callbackHelpers: CallbackInterface) =>
+ async ({ projectId }: { projectId: string }) => {
+ try {
+ const { snapshot } = callbackHelpers;
+ const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
+ const reparsedLgFiles: LgFile[] = [];
+ for (const file of lgFiles) {
+ const reparsedFile = (await LgDiagnosticWorker.parse(projectId, file.id, file.content, lgFiles)) as LgFile;
+ reparsedLgFiles.push({ ...file, diagnostics: reparsedFile.diagnostics });
+ }
+ updateLgFiles(callbackHelpers, projectId, { updates: reparsedLgFiles }, (current, changed) => {
+ // compare to drop expired content already setted above.
+ return current?.content === changed?.content;
+ });
+ } catch (error) {
+ setError(callbackHelpers, error);
}
- updateLgFiles(callbackHelpers, projectId, { updates: reparsedLgFiles }, (current, changed) => {
- // compare to drop expired content already setted above.
- return current?.content === changed?.content;
- });
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ },
);
const updateAllLgFiles = useRecoilCallback(
- ({ set }: CallbackInterface) => ({ projectId, lgFiles }: { projectId: string; lgFiles: LgFile[] }) => {
- set(lgFilesSelectorFamily(projectId), lgFiles);
- }
+ ({ set }: CallbackInterface) =>
+ ({ projectId, lgFiles }: { projectId: string; lgFiles: LgFile[] }) => {
+ set(lgFilesSelectorFamily(projectId), lgFiles);
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/lu.ts b/Composer/packages/client/src/recoilModel/dispatchers/lu.ts
index c368b3e564..431c2deffb 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/lu.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/lu.ts
@@ -38,14 +38,14 @@ const updateLuFiles = (
deletes?: LuFile[];
updates?: LuFile[];
},
- getLatestFile?: (current: LuFile, changed: LuFile) => LuFile
+ getLatestFile?: (current: LuFile, changed: LuFile) => LuFile,
) => {
const { updates, adds, deletes } = changes;
// updates
updates?.forEach((luFile) => {
set(luFileState({ projectId, luFileId: luFile.id }), (oldLuFile) =>
- getLatestFile ? getLatestFile(oldLuFile, luFile) : luFile
+ getLatestFile ? getLatestFile(oldLuFile, luFile) : luFile,
);
});
@@ -60,7 +60,7 @@ const updateLuFiles = (
const addedIds = adds.map((file) => file.id);
adds.forEach((luFile) => {
set(luFileState({ projectId, luFileId: luFile.id }), (oldLuFile) =>
- getLatestFile ? getLatestFile(oldLuFile, luFile) : luFile
+ getLatestFile ? getLatestFile(oldLuFile, luFile) : luFile,
);
});
set(luFileIdsState(projectId), (ids) => [...ids, ...addedIds]);
@@ -70,7 +70,7 @@ const getRelatedLuFileChanges = async (
originLuFiles: LuFile[],
updatedLuFile: LuFile,
projectId: string,
- luFeatures: ILUFeaturesConfig
+ luFeatures: ILUFeaturesConfig,
): Promise => {
const { id } = updatedLuFile;
const dialogId = getBaseName(id);
@@ -108,7 +108,7 @@ const getRelatedLuFileChanges = async (
newLuFile,
deletedIntents.map(({ Name }) => Name),
luFeatures,
- luFiles
+ luFiles,
)) as LuFile;
changes.push(newLuFile);
}
@@ -126,7 +126,7 @@ const getRelatedLuFileChanges = async (
export const createLuFileState = async (
callbackHelpers: CallbackInterface,
- { id, content, projectId }: { id: string; content: string; projectId: string }
+ { id, content, projectId }: { id: string; content: string; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
@@ -155,7 +155,7 @@ export const createLuFileState = async (
export const removeLuFileState = async (
callbackHelpers: CallbackInterface,
- { id, projectId }: { id: string; projectId: string }
+ { id, projectId }: { id: string; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
@@ -178,181 +178,162 @@ export const removeLuFileState = async (
export const luDispatcher = () => {
const batchUpdateLuFiles = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- payloads: {
- id: string;
- content: string;
- projectId: string;
- }[]
- ) => {
- const { snapshot } = callbackHelpers;
- payloads.map(async ({ id, content, projectId }) => {
+ (callbackHelpers: CallbackInterface) =>
+ async (
+ payloads: {
+ id: string;
+ content: string;
+ projectId: string;
+ }[],
+ ) => {
+ const { snapshot } = callbackHelpers;
+ payloads.map(async ({ id, content, projectId }) => {
+ const luFeatures = await snapshot.getPromise(luFileLuFeatureSelector({ projectId, id }));
+ try {
+ const updatedFile = (await luWorker.parse(id, content, luFeatures, [])) as LuFile;
+ // compare to drop expired change on current id file.
+ /**
+ * Why other methods do not need double check content?
+ * Because this method already did set content before call luFilesAtomUpdater.
+ */
+ updateLuFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ } catch (error) {
+ setError(callbackHelpers, error);
+ }
+ });
+ },
+ );
+
+ const updateLuFile = useRecoilCallback(
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, content, projectId }: { id: string; content: string; projectId: string }) => {
+ const { set, snapshot } = callbackHelpers;
+ //set content first
+ set(luFileState({ projectId, luFileId: id }), (prevLuFile) => {
+ return {
+ ...prevLuFile,
+ content,
+ };
+ });
+
+ const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
const luFeatures = await snapshot.getPromise(luFileLuFeatureSelector({ projectId, id }));
+
try {
- const updatedFile = (await luWorker.parse(id, content, luFeatures, [])) as LuFile;
+ const updatedFile = (await luWorker.parse(id, content, luFeatures, luFiles)) as LuFile;
+ const updatedFiles = await getRelatedLuFileChanges(luFiles, updatedFile, projectId, luFeatures);
// compare to drop expired change on current id file.
/**
* Why other methods do not need double check content?
* Because this method already did set content before call luFilesAtomUpdater.
*/
- updateLuFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ updateLuFiles(callbackHelpers, projectId, { updates: updatedFiles }, (current, changed) => {
+ // compare to drop expired content already setted above.
+ if (current.id === id && current?.content !== changed?.content) return current;
+ return changed;
+ });
} catch (error) {
setError(callbackHelpers, error);
}
- });
- }
- );
-
- const updateLuFile = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- content,
- projectId,
- }: {
- id: string;
- content: string;
- projectId: string;
- }) => {
- const { set, snapshot } = callbackHelpers;
- //set content first
- set(luFileState({ projectId, luFileId: id }), (prevLuFile) => {
- return {
- ...prevLuFile,
- content,
- };
- });
-
- const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
- const luFeatures = await snapshot.getPromise(luFileLuFeatureSelector({ projectId, id }));
-
- try {
- const updatedFile = (await luWorker.parse(id, content, luFeatures, luFiles)) as LuFile;
- const updatedFiles = await getRelatedLuFileChanges(luFiles, updatedFile, projectId, luFeatures);
- // compare to drop expired change on current id file.
- /**
- * Why other methods do not need double check content?
- * Because this method already did set content before call luFilesAtomUpdater.
- */
- updateLuFiles(callbackHelpers, projectId, { updates: updatedFiles }, (current, changed) => {
- // compare to drop expired content already setted above.
- if (current.id === id && current?.content !== changed?.content) return current;
- return changed;
- });
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ },
);
const updateLuIntent = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- intentName,
- intent,
- projectId,
- }: {
- id: string;
- intentName: string;
- intent: LuIntentSection;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
- const luFeatures = await snapshot.getPromise(luFileLuFeatureSelector({ projectId, id }));
- const luFile = luFiles.find((temp) => temp.id === id);
- if (!luFile) return luFiles;
-
- // create need sync to multi locale file.
- const originIntent = luFile.intents.find(({ Name }) => Name === intentName);
- if (!originIntent) {
- await createLuIntent({ id, intent, projectId });
- return;
- }
-
- try {
- const sameIdOtherLocaleFiles = luFiles.filter((file) => getBaseName(file.id) === getBaseName(id));
-
- // name change, need update cross multi locale file.
- if (intent.Name !== intentName) {
- const changes: LuFile[] = [];
- for (const item of sameIdOtherLocaleFiles) {
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ intentName,
+ intent,
+ projectId,
+ }: {
+ id: string;
+ intentName: string;
+ intent: LuIntentSection;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
+ const luFeatures = await snapshot.getPromise(luFileLuFeatureSelector({ projectId, id }));
+ const luFile = luFiles.find((temp) => temp.id === id);
+ if (!luFile) return luFiles;
+
+ // create need sync to multi locale file.
+ const originIntent = luFile.intents.find(({ Name }) => Name === intentName);
+ if (!originIntent) {
+ await createLuIntent({ id, intent, projectId });
+ return;
+ }
+
+ try {
+ const sameIdOtherLocaleFiles = luFiles.filter((file) => getBaseName(file.id) === getBaseName(id));
+
+ // name change, need update cross multi locale file.
+ if (intent.Name !== intentName) {
+ const changes: LuFile[] = [];
+ for (const item of sameIdOtherLocaleFiles) {
+ const updatedFile = (await luWorker.updateIntent(
+ item,
+ intentName,
+ { Name: intent.Name },
+ luFeatures,
+ luFiles,
+ )) as LuFile;
+ changes.push(updatedFile);
+ }
+ updateLuFiles(callbackHelpers, projectId, { updates: changes });
+ // body change, only update current locale file
+ } else {
const updatedFile = (await luWorker.updateIntent(
- item,
+ luFile,
intentName,
- { Name: intent.Name },
+ { Body: intent.Body },
luFeatures,
- luFiles
+ luFiles,
)) as LuFile;
- changes.push(updatedFile);
+ updateLuFiles(callbackHelpers, projectId, { updates: [updatedFile] });
}
- updateLuFiles(callbackHelpers, projectId, { updates: changes });
- // body change, only update current locale file
- } else {
- const updatedFile = (await luWorker.updateIntent(
- luFile,
- intentName,
- { Body: intent.Body },
- luFeatures,
- luFiles
- )) as LuFile;
- updateLuFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ } catch (error) {
+ setError(callbackHelpers, error);
}
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ },
);
const createLuIntent = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- intent,
- projectId,
- }: {
- id: string;
- intent: LuIntentSection;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
- const luFeatures = await snapshot.getPromise(luFileLuFeatureSelector({ projectId, id }));
-
- const file = luFiles.find((temp) => temp.id === id);
- if (!file) return luFiles;
- try {
- const updatedFile = (await luWorker.addIntent(file, intent, luFeatures, luFiles)) as LuFile;
- const updatedFiles = await getRelatedLuFileChanges(luFiles, updatedFile, projectId, luFeatures);
- updateLuFiles(callbackHelpers, projectId, { updates: updatedFiles });
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, intent, projectId }: { id: string; intent: LuIntentSection; projectId: string }) => {
+ const { snapshot } = callbackHelpers;
+ const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
+ const luFeatures = await snapshot.getPromise(luFileLuFeatureSelector({ projectId, id }));
+
+ const file = luFiles.find((temp) => temp.id === id);
+ if (!file) return luFiles;
+ try {
+ const updatedFile = (await luWorker.addIntent(file, intent, luFeatures, luFiles)) as LuFile;
+ const updatedFiles = await getRelatedLuFileChanges(luFiles, updatedFile, projectId, luFeatures);
+ updateLuFiles(callbackHelpers, projectId, { updates: updatedFiles });
+ } catch (error) {
+ setError(callbackHelpers, error);
+ }
+ },
);
const removeLuIntent = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- intentName,
- projectId,
- }: {
- id: string;
- intentName: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
- const luFeatures = await snapshot.getPromise(luFileLuFeatureSelector({ projectId, id }));
-
- const file = luFiles.find((temp) => temp.id === id);
- if (!file) return luFiles;
- try {
- const updatedFile = (await luWorker.removeIntent(file, intentName, luFeatures, luFiles)) as LuFile;
- const updatedFiles = await getRelatedLuFileChanges(luFiles, updatedFile, projectId, luFeatures);
- updateLuFiles(callbackHelpers, projectId, { updates: updatedFiles });
- } catch (error) {
- setError(callbackHelpers, error);
- }
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, intentName, projectId }: { id: string; intentName: string; projectId: string }) => {
+ const { snapshot } = callbackHelpers;
+ const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
+ const luFeatures = await snapshot.getPromise(luFileLuFeatureSelector({ projectId, id }));
+
+ const file = luFiles.find((temp) => temp.id === id);
+ if (!file) return luFiles;
+ try {
+ const updatedFile = (await luWorker.removeIntent(file, intentName, luFeatures, luFiles)) as LuFile;
+ const updatedFiles = await getRelatedLuFileChanges(luFiles, updatedFile, projectId, luFeatures);
+ updateLuFiles(callbackHelpers, projectId, { updates: updatedFiles });
+ } catch (error) {
+ setError(callbackHelpers, error);
+ }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/multilang.ts b/Composer/packages/client/src/recoilModel/dispatchers/multilang.ts
index 748a5024cb..fad86d7bf0 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/multilang.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/multilang.ts
@@ -51,7 +51,7 @@ const copyLanguageResources = (files: any[], fromLanguage: string, toLanguages:
// pull out target language file
const deleteLanguageResources = (
files: any[],
- languages: string[]
+ languages: string[],
): {
left: any[];
deletes: any[];
@@ -67,123 +67,129 @@ const deleteLanguageResources = (
export const multilangDispatcher = () => {
// When skill bot do not have the locale to be set in root bot, create it for skill bot.
const setLocale = useRecoilCallback(
- ({ set, snapshot }: CallbackInterface) => async (locale: string, projectId: string) => {
- const botName = await snapshot.getPromise(botDisplayNameState(projectId));
- const botProjects = await snapshot.getPromise(localBotsDataSelector);
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (projectId === rootBotProjectId) {
- for (let i = 0; i < botProjects.length; i++) {
- if (!botProjects[i].isRootBot && !botProjects[i].isRemote) {
- const skillBotProjectId = botProjects[i].projectId;
- const settings = await snapshot.getPromise(settingsState(skillBotProjectId));
- const languages = settings.languages;
- const defaultLang = settings.defaultLanguage;
- if (!languages.includes(locale)) {
- addLanguages({
- languages: [locale],
- projectId: skillBotProjectId,
- defaultLang: defaultLang,
- switchTo: true,
- });
+ ({ set, snapshot }: CallbackInterface) =>
+ async (locale: string, projectId: string) => {
+ const botName = await snapshot.getPromise(botDisplayNameState(projectId));
+ const botProjects = await snapshot.getPromise(localBotsDataSelector);
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (projectId === rootBotProjectId) {
+ for (let i = 0; i < botProjects.length; i++) {
+ if (!botProjects[i].isRootBot && !botProjects[i].isRemote) {
+ const skillBotProjectId = botProjects[i].projectId;
+ const settings = await snapshot.getPromise(settingsState(skillBotProjectId));
+ const languages = settings.languages;
+ const defaultLang = settings.defaultLanguage;
+ if (!languages.includes(locale)) {
+ addLanguages({
+ languages: [locale],
+ projectId: skillBotProjectId,
+ defaultLang: defaultLang,
+ switchTo: true,
+ });
+ }
}
}
}
- }
- set(localeState(projectId), locale);
- languageStorage.setLocale(botName, locale);
- }
+ set(localeState(projectId), locale);
+ languageStorage.setLocale(botName, locale);
+ },
);
const addLanguages = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ languages, defaultLang, switchTo = false, projectId }) => {
- const { set, snapshot } = callbackHelpers;
- const onAddLanguageDialogComplete = (await snapshot.getPromise(onAddLanguageDialogCompleteState(projectId))).func;
-
- // copy files from default language
- set(lgFilesSelectorFamily(projectId), (oldLgFiles) => {
- const addedLgFiles = copyLanguageResources(oldLgFiles, defaultLang, languages);
- return [...oldLgFiles, ...addedLgFiles];
- });
- set(luFilesSelectorFamily(projectId), (prevluFiles) => {
- const addedLuFiles = copyLanguageResources(prevluFiles, defaultLang, languages);
- return [...prevluFiles, ...addedLuFiles];
- });
- set(qnaFilesSelectorFamily(projectId), (prevQnAFiles) => {
- const addedQnAFiles = copyLanguageResources(prevQnAFiles, defaultLang, languages);
- return [...prevQnAFiles, ...addedQnAFiles];
- });
- set(settingsState(projectId), (prevSettings) => {
- const settings: any = cloneDeep(prevSettings);
- if (Array.isArray(settings.languages)) {
- settings.languages.push(...languages);
- } else {
- settings.languages = languages;
- }
- if (typeof onAddLanguageDialogComplete === 'function') {
- onAddLanguageDialogComplete(languages);
- }
- return settings;
- });
+ (callbackHelpers: CallbackInterface) =>
+ async ({ languages, defaultLang, switchTo = false, projectId }) => {
+ const { set, snapshot } = callbackHelpers;
+ const onAddLanguageDialogComplete = (await snapshot.getPromise(onAddLanguageDialogCompleteState(projectId)))
+ .func;
+
+ // copy files from default language
+ set(lgFilesSelectorFamily(projectId), (oldLgFiles) => {
+ const addedLgFiles = copyLanguageResources(oldLgFiles, defaultLang, languages);
+ return [...oldLgFiles, ...addedLgFiles];
+ });
+ set(luFilesSelectorFamily(projectId), (prevluFiles) => {
+ const addedLuFiles = copyLanguageResources(prevluFiles, defaultLang, languages);
+ return [...prevluFiles, ...addedLuFiles];
+ });
+ set(qnaFilesSelectorFamily(projectId), (prevQnAFiles) => {
+ const addedQnAFiles = copyLanguageResources(prevQnAFiles, defaultLang, languages);
+ return [...prevQnAFiles, ...addedQnAFiles];
+ });
+ set(settingsState(projectId), (prevSettings) => {
+ const settings: any = cloneDeep(prevSettings);
+ if (Array.isArray(settings.languages)) {
+ settings.languages.push(...languages);
+ } else {
+ settings.languages = languages;
+ }
+ if (typeof onAddLanguageDialogComplete === 'function') {
+ onAddLanguageDialogComplete(languages);
+ }
+ return settings;
+ });
- //Set active language and update skill bot's active language
- if (switchTo) {
- const switchToLocale = languages[0];
- setLocale(switchToLocale, projectId);
- }
+ //Set active language and update skill bot's active language
+ if (switchTo) {
+ const switchToLocale = languages[0];
+ setLocale(switchToLocale, projectId);
+ }
- set(showAddLanguageModalState(projectId), false);
- set(onAddLanguageDialogCompleteState(projectId), { func: undefined });
- }
+ set(showAddLanguageModalState(projectId), false);
+ set(onAddLanguageDialogCompleteState(projectId), { func: undefined });
+ },
);
const deleteLanguages = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ languages, projectId }) => {
- const { set, snapshot } = callbackHelpers;
- const onDelLanguageDialogComplete = (await snapshot.getPromise(onDelLanguageDialogCompleteState(projectId))).func;
-
- // copy files from default language
- set(lgFilesSelectorFamily(projectId), (prevLgFiles) => {
- const { left: leftLgFiles } = deleteLanguageResources(prevLgFiles, languages);
- return leftLgFiles;
- });
- set(luFilesSelectorFamily(projectId), (prevLuFiles) => {
- const { left: leftLuFiles } = deleteLanguageResources(prevLuFiles, languages);
- return leftLuFiles;
- });
- set(qnaFilesSelectorFamily(projectId), (prevQnAFiles) => {
- const { left: leftQnAFiles } = deleteLanguageResources(prevQnAFiles, languages);
- return leftQnAFiles;
- });
- set(settingsState(projectId), (prevSettings) => {
- const settings: any = cloneDeep(prevSettings);
-
- const leftLanguages = difference(settings.languages, languages);
- settings.languages = leftLanguages;
- if (typeof onDelLanguageDialogComplete === 'function') {
- onDelLanguageDialogComplete(leftLanguages);
+ (callbackHelpers: CallbackInterface) =>
+ async ({ languages, projectId }) => {
+ const { set, snapshot } = callbackHelpers;
+ const onDelLanguageDialogComplete = (await snapshot.getPromise(onDelLanguageDialogCompleteState(projectId)))
+ .func;
+
+ // copy files from default language
+ set(lgFilesSelectorFamily(projectId), (prevLgFiles) => {
+ const { left: leftLgFiles } = deleteLanguageResources(prevLgFiles, languages);
+ return leftLgFiles;
+ });
+ set(luFilesSelectorFamily(projectId), (prevLuFiles) => {
+ const { left: leftLuFiles } = deleteLanguageResources(prevLuFiles, languages);
+ return leftLuFiles;
+ });
+ set(qnaFilesSelectorFamily(projectId), (prevQnAFiles) => {
+ const { left: leftQnAFiles } = deleteLanguageResources(prevQnAFiles, languages);
+ return leftQnAFiles;
+ });
+ set(settingsState(projectId), (prevSettings) => {
+ const settings: any = cloneDeep(prevSettings);
+
+ const leftLanguages = difference(settings.languages, languages);
+ settings.languages = leftLanguages;
+ if (typeof onDelLanguageDialogComplete === 'function') {
+ onDelLanguageDialogComplete(leftLanguages);
+ }
+ return settings;
+ });
+
+ set(showDelLanguageModalState(projectId), false);
+ set(onDelLanguageDialogCompleteState(projectId), { func: undefined });
+
+ //use default language as active language if active language is deleted
+ const botName = await snapshot.getPromise(botDisplayNameState(projectId));
+ const currentActiveLanguage = languageStorage.get(botName)?.locale;
+ if (languages.includes(currentActiveLanguage)) {
+ const { defaultLanguage } = await snapshot.getPromise(settingsState(projectId));
+ set(localeState(projectId), defaultLanguage);
+ languageStorage.setLocale(botName, defaultLanguage);
}
- return settings;
- });
-
- set(showDelLanguageModalState(projectId), false);
- set(onDelLanguageDialogCompleteState(projectId), { func: undefined });
-
- //use default language as active language if active language is deleted
- const botName = await snapshot.getPromise(botDisplayNameState(projectId));
- const currentActiveLanguage = languageStorage.get(botName)?.locale;
- if (languages.includes(currentActiveLanguage)) {
- const { defaultLanguage } = await snapshot.getPromise(settingsState(projectId));
- set(localeState(projectId), defaultLanguage);
- languageStorage.setLocale(botName, defaultLanguage);
- }
- }
+ },
);
const addLanguageDialogBegin = useRecoilCallback(
- ({ set }: CallbackInterface) => async (projectId: string, onComplete) => {
- set(showAddLanguageModalState(projectId), true);
- set(onAddLanguageDialogCompleteState(projectId), { func: onComplete });
- }
+ ({ set }: CallbackInterface) =>
+ async (projectId: string, onComplete) => {
+ set(showAddLanguageModalState(projectId), true);
+ set(onAddLanguageDialogCompleteState(projectId), { func: onComplete });
+ },
);
const addLanguageDialogCancel = useRecoilCallback(({ set }: CallbackInterface) => async (projectId: string) => {
@@ -192,10 +198,11 @@ export const multilangDispatcher = () => {
});
const delLanguageDialogBegin = useRecoilCallback(
- ({ set }: CallbackInterface) => async (projectId: string, onComplete) => {
- set(showDelLanguageModalState(projectId), true);
- set(onDelLanguageDialogCompleteState(projectId), { func: onComplete });
- }
+ ({ set }: CallbackInterface) =>
+ async (projectId: string, onComplete) => {
+ set(showDelLanguageModalState(projectId), true);
+ set(onDelLanguageDialogCompleteState(projectId), { func: onComplete });
+ },
);
const delLanguageDialogCancel = useRecoilCallback(({ set }: CallbackInterface) => async (projectId: string) => {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/navigation.ts b/Composer/packages/client/src/recoilModel/dispatchers/navigation.ts
index fce914a140..e1c1228fc6 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/navigation.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/navigation.ts
@@ -38,177 +38,168 @@ export const navigationDispatcher = () => {
const focusPath = `${dialogId}#${focused ? `.${focused}` : selected ? `.${selected}` : ''}`;
set(focusPathState(projectId), focusPath);
set(designPageLocationState(projectId), location);
- }
+ },
);
const navTo = useRecoilCallback(
- (callbackInterface: CallbackInterface) => async (
- skillId: string | null,
- dialogId: string | null,
- trigger?: string
- ) => {
- const { set, snapshot } = callbackInterface;
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (rootBotProjectId == null) return;
+ (callbackInterface: CallbackInterface) =>
+ async (skillId: string | null, dialogId: string | null, trigger?: string) => {
+ const { set, snapshot } = callbackInterface;
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (rootBotProjectId == null) return;
+
+ const projectId = skillId ?? rootBotProjectId;
+ const topics = await snapshot.getPromise(topicsSelectorFamily(projectId));
+
+ await setCurrentProjectId(callbackInterface, projectId);
+
+ // check to see if navigating to PVA topic
+ const topic = topics.find((t) => t.content?.id === dialogId);
+ if (topic) {
+ if (topic?.content?.$designer?.link) {
+ // eslint-disable-next-line security/detect-non-literal-fs-filename
+ window.open(topic.content.$designer.link as string, '_blank');
+ }
+ // no-op even if topic has no link
+ return;
+ }
- const projectId = skillId ?? rootBotProjectId;
- const topics = await snapshot.getPromise(topicsSelectorFamily(projectId));
+ const currentUri =
+ trigger == null
+ ? convertPathToUrl(rootBotProjectId, skillId, dialogId)
+ : convertPathToUrl(rootBotProjectId, skillId, dialogId, `selected=triggers[${trigger}]`);
- await setCurrentProjectId(callbackInterface, projectId);
-
- // check to see if navigating to PVA topic
- const topic = topics.find((t) => t.content?.id === dialogId);
- if (topic) {
- if (topic?.content?.$designer?.link) {
- // eslint-disable-next-line security/detect-non-literal-fs-filename
- window.open(topic.content.$designer.link as string, '_blank');
- }
- // no-op even if topic has no link
- return;
- }
-
- const currentUri =
- trigger == null
- ? convertPathToUrl(rootBotProjectId, skillId, dialogId)
- : convertPathToUrl(rootBotProjectId, skillId, dialogId, `selected=triggers[${trigger}]`);
-
- set(designPageLocationState(projectId), {
- dialogId: dialogId ?? '',
- selected: trigger ?? '',
- focused: '',
- promptTab: undefined,
- });
- navigateTo(currentUri);
- }
+ set(designPageLocationState(projectId), {
+ dialogId: dialogId ?? '',
+ selected: trigger ?? '',
+ focused: '',
+ promptTab: undefined,
+ });
+ navigateTo(currentUri);
+ },
);
const selectTo = useRecoilCallback(
- (callbackInterface: CallbackInterface) => async (
- skillId: string | null,
- destinationDialogId: string | null,
- selectPath: string
- ) => {
- if (!selectPath) return;
+ (callbackInterface: CallbackInterface) =>
+ async (skillId: string | null, destinationDialogId: string | null, selectPath: string) => {
+ if (!selectPath) return;
- const { set, snapshot } = callbackInterface;
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (rootBotProjectId == null) return;
+ const { set, snapshot } = callbackInterface;
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (rootBotProjectId == null) return;
- const projectId = skillId ?? rootBotProjectId;
+ const projectId = skillId ?? rootBotProjectId;
- await setCurrentProjectId(callbackInterface, projectId);
+ await setCurrentProjectId(callbackInterface, projectId);
- const designPageLocation = await snapshot.getPromise(designPageLocationState(projectId));
-
- // target dialogId, projectId maybe empty string ""
- const dialogId = destinationDialogId ?? designPageLocation.dialogId ?? 'Main';
-
- const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
- const currentDialog = dialogs.find(({ id }) => id === dialogId);
- const encodedSelectPath = encodeArrayPathToDesignerPath(currentDialog?.content, selectPath);
- const currentUri = convertPathToUrl(rootBotProjectId, skillId, dialogId, encodedSelectPath);
-
- if (checkUrl(currentUri, rootBotProjectId, skillId, designPageLocation)) return;
- set(designPageLocationState(projectId), {
- dialogId,
- selected: selectPath,
- focused: '',
- promptTab: undefined,
- });
- navigateTo(currentUri);
- }
- );
+ const designPageLocation = await snapshot.getPromise(designPageLocationState(projectId));
- const focusTo = useRecoilCallback(
- (callbackInterface: CallbackInterface) => async (
- projectId: string,
- skillId: string | null,
- focusPath: string,
- fragment: string
- ) => {
- const { set, snapshot } = callbackInterface;
- await setCurrentProjectId(callbackInterface, skillId ?? projectId);
+ // target dialogId, projectId maybe empty string ""
+ const dialogId = destinationDialogId ?? designPageLocation.dialogId ?? 'Main';
- const designPageLocation = await snapshot.getPromise(designPageLocationState(skillId ?? projectId));
- const { dialogId, selected } = designPageLocation;
+ const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
+ const currentDialog = dialogs.find(({ id }) => id === dialogId);
+ const encodedSelectPath = encodeArrayPathToDesignerPath(currentDialog?.content, selectPath);
+ const currentUri = convertPathToUrl(rootBotProjectId, skillId, dialogId, encodedSelectPath);
- const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
- const currentDialog = dialogs.find(({ id }) => id === dialogId);
+ if (checkUrl(currentUri, rootBotProjectId, skillId, designPageLocation)) return;
+ set(designPageLocationState(projectId), {
+ dialogId,
+ selected: selectPath,
+ focused: '',
+ promptTab: undefined,
+ });
+ navigateTo(currentUri);
+ },
+ );
- const encodedSelectPath = encodeArrayPathToDesignerPath(currentDialog?.content, selected);
+ const focusTo = useRecoilCallback(
+ (callbackInterface: CallbackInterface) =>
+ async (projectId: string, skillId: string | null, focusPath: string, fragment: string) => {
+ const { set, snapshot } = callbackInterface;
+ await setCurrentProjectId(callbackInterface, skillId ?? projectId);
- let currentUri =
- skillId == null || skillId === projectId
- ? `/bot/${projectId}/dialogs/${dialogId}`
- : `/bot/${projectId}/skill/${skillId}/dialogs/${dialogId}`;
+ const designPageLocation = await snapshot.getPromise(designPageLocationState(skillId ?? projectId));
+ const { dialogId, selected } = designPageLocation;
- if (focusPath) {
- const dialogs = await snapshot.getPromise(dialogsSelectorFamily(skillId ?? projectId));
+ const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
const currentDialog = dialogs.find(({ id }) => id === dialogId);
- const encodedFocusPath = encodeArrayPathToDesignerPath(currentDialog?.content, focusPath);
-
- const targetSelected = getSelected(encodedFocusPath);
-
- currentUri = `${currentUri}?selected=${targetSelected}&focused=${encodedFocusPath}`;
- } else {
- currentUri = `${currentUri}?selected=${encodedSelectPath}`;
- }
-
- if (fragment && typeof fragment === 'string') {
- currentUri += `#${fragment}`;
- }
- if (checkUrl(currentUri, projectId, skillId, designPageLocation)) return;
-
- set(designPageLocationState(skillId || projectId), {
- dialogId,
- selected: getSelected(focusPath) || encodedSelectPath,
- focused: focusPath ?? '',
- promptTab: Object.values(PromptTab).find((value) => fragment === value),
- });
- navigateTo(currentUri);
- }
- );
- const selectAndFocus = useRecoilCallback(
- ({ snapshot, set }: CallbackInterface) => async (
- projectId: string,
- skillId: string | null,
- dialogId: string,
- selectPath: string,
- focusPath: string,
- fragment?: string
- ) => {
- set(currentProjectIdState, projectId);
-
- const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
- const currentDialog = dialogs.find(({ id }) => id === dialogId)?.content;
- const encodedSelectPath = encodeArrayPathToDesignerPath(currentDialog, selectPath);
- const encodedFocusPath = encodeArrayPathToDesignerPath(currentDialog, focusPath);
- const search = getUrlSearch(encodedSelectPath, encodedFocusPath);
- const designPageLocation = await snapshot.getPromise(designPageLocationState(projectId));
- if (search) {
+ const encodedSelectPath = encodeArrayPathToDesignerPath(currentDialog?.content, selected);
+
let currentUri =
skillId == null || skillId === projectId
- ? `/bot/${projectId}/dialogs/${dialogId}${search}`
- : `/bot/${projectId}/skill/${skillId}/dialogs/${dialogId}${search}`;
+ ? `/bot/${projectId}/dialogs/${dialogId}`
+ : `/bot/${projectId}/skill/${skillId}/dialogs/${dialogId}`;
+
+ if (focusPath) {
+ const dialogs = await snapshot.getPromise(dialogsSelectorFamily(skillId ?? projectId));
+ const currentDialog = dialogs.find(({ id }) => id === dialogId);
+ const encodedFocusPath = encodeArrayPathToDesignerPath(currentDialog?.content, focusPath);
+
+ const targetSelected = getSelected(encodedFocusPath);
+
+ currentUri = `${currentUri}?selected=${targetSelected}&focused=${encodedFocusPath}`;
+ } else {
+ currentUri = `${currentUri}?selected=${encodedSelectPath}`;
+ }
if (fragment && typeof fragment === 'string') {
currentUri += `#${fragment}`;
}
-
if (checkUrl(currentUri, projectId, skillId, designPageLocation)) return;
- set(designPageLocationState(projectId), {
+ set(designPageLocationState(skillId || projectId), {
dialogId,
- selected: getSelected(focusPath) || selectPath,
+ selected: getSelected(focusPath) || encodedSelectPath,
focused: focusPath ?? '',
promptTab: Object.values(PromptTab).find((value) => fragment === value),
});
navigateTo(currentUri);
- } else {
- navTo(skillId ?? projectId, dialogId);
- }
- }
+ },
+ );
+
+ const selectAndFocus = useRecoilCallback(
+ ({ snapshot, set }: CallbackInterface) =>
+ async (
+ projectId: string,
+ skillId: string | null,
+ dialogId: string,
+ selectPath: string,
+ focusPath: string,
+ fragment?: string,
+ ) => {
+ set(currentProjectIdState, projectId);
+
+ const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
+ const currentDialog = dialogs.find(({ id }) => id === dialogId)?.content;
+ const encodedSelectPath = encodeArrayPathToDesignerPath(currentDialog, selectPath);
+ const encodedFocusPath = encodeArrayPathToDesignerPath(currentDialog, focusPath);
+ const search = getUrlSearch(encodedSelectPath, encodedFocusPath);
+ const designPageLocation = await snapshot.getPromise(designPageLocationState(projectId));
+ if (search) {
+ let currentUri =
+ skillId == null || skillId === projectId
+ ? `/bot/${projectId}/dialogs/${dialogId}${search}`
+ : `/bot/${projectId}/skill/${skillId}/dialogs/${dialogId}${search}`;
+
+ if (fragment && typeof fragment === 'string') {
+ currentUri += `#${fragment}`;
+ }
+
+ if (checkUrl(currentUri, projectId, skillId, designPageLocation)) return;
+
+ set(designPageLocationState(projectId), {
+ dialogId,
+ selected: getSelected(focusPath) || selectPath,
+ focused: focusPath ?? '',
+ promptTab: Object.values(PromptTab).find((value) => fragment === value),
+ });
+ navigateTo(currentUri);
+ } else {
+ navTo(skillId ?? projectId, dialogId);
+ }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/notification.ts b/Composer/packages/client/src/recoilModel/dispatchers/notification.ts
index 1b0fa5c63e..5ff43473cb 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/notification.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/notification.ts
@@ -56,7 +56,7 @@ export const notificationDispatcher = () => {
const updateNotification = useRecoilCallback(
(callbackHelper: CallbackInterface) => (id: string, newValue: Partial) => {
updateNotificationInternal(callbackHelper, id, newValue);
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/orchestrator.ts b/Composer/packages/client/src/recoilModel/dispatchers/orchestrator.ts
index d7cebd146d..e37ff96479 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/orchestrator.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/orchestrator.ts
@@ -42,7 +42,7 @@ const pollUntilDone = (predicate: () => Promise, pollingIntervalMs: num
export const downloadModel = async (
addr: string,
modelRequest: OrchestratorModelRequest,
- notificationStartCallback: () => void
+ notificationStartCallback: () => void,
) => {
const resp = await httpClient.post(addr, { modelData: modelRequest });
@@ -58,17 +58,17 @@ export const downloadModel = async (
export const getAvailableLanguageModels = async (
recognizerFiles: RecognizerFile[],
- botSettings?: DialogSetting
+ botSettings?: DialogSetting,
): Promise => {
const dialogsUsingOrchestrator = recognizerFiles.filter(
- ({ content }) => content.$kind === SDKKinds.OrchestratorRecognizer
+ ({ content }) => content.$kind === SDKKinds.OrchestratorRecognizer,
);
let languageModels: OrchestratorModelRequest[] = [];
if (dialogsUsingOrchestrator.length) {
// pull out languages that Orchestrator has to support
const [enLuFiles, multiLangLuFiles] = partition(dialogsUsingOrchestrator, (f) =>
- f.id.split('.')?.[1]?.toLowerCase()?.startsWith('en')
+ f.id.split('.')?.[1]?.toLowerCase()?.startsWith('en'),
);
if (enLuFiles.length) {
@@ -96,7 +96,7 @@ export const getAvailableLanguageModels = async (
const modelList = resp.data;
if (modelList?.defaults) {
languageModels = languageModels.map((r) =>
- r.name === 'default' ? { ...r, name: modelList.defaults[r.kind] } : r
+ r.name === 'default' ? { ...r, name: modelList.defaults[r.kind] } : r,
);
}
}
@@ -143,14 +143,14 @@ export const orchestratorDispatcher = () => {
filePersistence.flush();
} catch (err) {
const errorNotification = createNotification(
- orchestratorDownloadErrorProps(err?.response?.data?.message || err.message)
+ orchestratorDownloadErrorProps(err?.response?.data?.message || err.message),
);
addNotification(errorNotification);
} finally {
deleteNotification(downloadNotification.id);
}
}
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/project.ts b/Composer/packages/client/src/recoilModel/dispatchers/project.ts
index d4bf67ae37..bc06fe7e6c 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/project.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/project.ts
@@ -6,6 +6,7 @@ import formatMessage from 'format-message';
import findIndex from 'lodash/findIndex';
import { PublishTarget, QnABotTemplateId, RootBotManagedProperties } from '@bfc/shared';
import get from 'lodash/get';
+import camelCase from 'lodash/camelCase';
import { CallbackInterface, useRecoilCallback } from 'recoil';
import { BotStatus, CreationFlowStatus, FEEDVERSION } from '../../constants';
@@ -97,14 +98,14 @@ export const projectDispatcher = () => {
// remove the same identifier trigger in root bot
if (rootBotProjectId && rootDialog && rootDialog.triggers.length > 0) {
const index = rootDialog.triggers.findIndex(
- (item) => item.displayName === triggerName.replace(skillNameRegex, '')
+ (item) => item.displayName === triggerName.replace(skillNameRegex, ''),
);
if (index >= 0) {
const content = DialogdeleteTrigger(
projectDialogsMap[rootBotProjectId],
rootDialog?.id,
index,
- async (trigger) => await dispatcher.deleteTrigger(rootBotProjectId, rootDialog?.id, trigger)
+ async (trigger) => await dispatcher.deleteTrigger(rootBotProjectId, rootDialog?.id, trigger),
);
if (content) {
await dispatcher.updateDialog({ id: rootDialog?.id, content, projectId: rootBotProjectId });
@@ -118,113 +119,114 @@ export const projectDispatcher = () => {
} catch (ex) {
setError(callbackHelpers, ex);
}
- }
+ },
);
const replaceSkillInBotProject = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (projectIdToRemove: string, path: string, storageId = 'default') => {
- try {
- const { snapshot } = callbackHelpers;
- const dispatcher = await snapshot.getPromise(dispatcherState);
- const projectIds = await snapshot.getPromise(botProjectIdsState);
- const indexToReplace = findIndex(projectIds, (id) => id === projectIdToRemove);
- if (indexToReplace === -1) {
- return;
+ (callbackHelpers: CallbackInterface) =>
+ async (projectIdToRemove: string, path: string, storageId = 'default') => {
+ try {
+ const { snapshot } = callbackHelpers;
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+ const projectIds = await snapshot.getPromise(botProjectIdsState);
+ const indexToReplace = findIndex(projectIds, (id) => id === projectIdToRemove);
+ if (indexToReplace === -1) {
+ return;
+ }
+ await dispatcher.removeSkillFromBotProject(projectIdToRemove);
+ await dispatcher.addExistingSkillToBotProject(path, storageId);
+ } catch (ex) {
+ setError(callbackHelpers, ex);
}
- await dispatcher.removeSkillFromBotProject(projectIdToRemove);
- await dispatcher.addExistingSkillToBotProject(path, storageId);
- } catch (ex) {
- setError(callbackHelpers, ex);
- }
- }
+ },
);
const addExistingSkillToBotProject = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- path: string,
- storageId = 'default',
- templateId?: string
- ): Promise => {
- const { set, snapshot } = callbackHelpers;
- try {
- set(botOpeningState, true);
- const dispatcher = await snapshot.getPromise(dispatcherState);
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (!rootBotProjectId) return;
+ (callbackHelpers: CallbackInterface) =>
+ async (path: string, storageId = 'default', templateId?: string): Promise => {
+ const { set, snapshot } = callbackHelpers;
+ try {
+ set(botOpeningState, true);
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (!rootBotProjectId) return;
+
+ const botExists = await checkIfBotExistsInBotProjectFile(callbackHelpers, path);
+ if (botExists) {
+ throw new Error(
+ formatMessage('This operation cannot be completed. The bot is already part of the Bot Project'),
+ );
+ }
+ const skillNameIdentifier: string = await getSkillNameIdentifier(callbackHelpers, getFileNameFromPath(path));
- const botExists = await checkIfBotExistsInBotProjectFile(callbackHelpers, path);
- if (botExists) {
- throw new Error(
- formatMessage('This operation cannot be completed. The bot is already part of the Bot Project')
- );
- }
- const skillNameIdentifier: string = await getSkillNameIdentifier(callbackHelpers, getFileNameFromPath(path));
+ const { projectId, mainDialog } = await openLocalSkill(callbackHelpers, path, storageId, skillNameIdentifier);
+ if (!mainDialog) {
+ const error = await snapshot.getPromise(botErrorState(projectId));
+ throw error;
+ }
- const { projectId, mainDialog } = await openLocalSkill(callbackHelpers, path, storageId, skillNameIdentifier);
- if (!mainDialog) {
- const error = await snapshot.getPromise(botErrorState(projectId));
- throw error;
- }
+ if (templateId === QnABotTemplateId) {
+ callbackHelpers.set(createQnAOnState, { projectId, dialogId: mainDialog });
+ callbackHelpers.set(showCreateQnADialogState(projectId), true);
+ }
- if (templateId === QnABotTemplateId) {
- callbackHelpers.set(createQnAOnState, { projectId, dialogId: mainDialog });
- callbackHelpers.set(showCreateQnADialogState(projectId), true);
+ set(botProjectIdsState, (current) => [...current, projectId]);
+ await dispatcher.addLocalSkillToBotProjectFile(projectId);
+ navigateToSkillBot(rootBotProjectId, projectId, mainDialog);
+ callbackHelpers.set(orchestratorForSkillsDialogState, true);
+ } catch (ex) {
+ handleProjectFailure(callbackHelpers, ex);
+ } finally {
+ set(botOpeningState, false);
}
-
- set(botProjectIdsState, (current) => [...current, projectId]);
- await dispatcher.addLocalSkillToBotProjectFile(projectId);
- navigateToSkillBot(rootBotProjectId, projectId, mainDialog);
- callbackHelpers.set(orchestratorForSkillsDialogState, true);
- } catch (ex) {
- handleProjectFailure(callbackHelpers, ex);
- } finally {
- set(botOpeningState, false);
- }
- }
+ },
);
const addRemoteSkillToBotProject = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- manifestUrl: string,
- endpointName: string,
- zipContent: Record
- ) => {
- const { set, snapshot } = callbackHelpers;
- try {
- const dispatcher = await snapshot.getPromise(dispatcherState);
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (!rootBotProjectId) return;
-
- const manifestFromZip = getManifestJsonFromZip(zipContent);
- const botExists = await checkIfBotExistsInBotProjectFile(
- callbackHelpers,
- manifestFromZip.name ? manifestFromZip.name : manifestUrl,
- true
- );
- if (botExists) {
- throw new Error(
- formatMessage('This operation cannot be completed. The skill is already part of the Bot Project')
+ (callbackHelpers: CallbackInterface) =>
+ async (manifestUrl: string, endpointName: string, zipContent: Record) => {
+ const { set, snapshot } = callbackHelpers;
+ try {
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (!rootBotProjectId) return;
+
+ const manifestFromZip = getManifestJsonFromZip(zipContent);
+ let botNameIdentifier;
+ if (manifestFromZip.content?.name) {
+ botNameIdentifier = camelCase(manifestFromZip.content.name);
+ manifestFromZip.name = `skills/${botNameIdentifier}/${manifestFromZip.name}`;
+ }
+ const botExists = await checkIfBotExistsInBotProjectFile(
+ callbackHelpers,
+ manifestFromZip.name ? manifestFromZip.name : manifestUrl,
+ true,
);
- }
-
- set(botOpeningState, true);
+ if (botExists) {
+ throw new Error(
+ formatMessage('This operation cannot be completed. The skill is already part of the Bot Project'),
+ );
+ }
- const { projectId } = await openRemoteSkill(callbackHelpers, {
- manifestUrl,
- manifestFromZip,
- rootBotProjectId,
- });
- set(botProjectIdsState, (current) => [...current, projectId]);
- await dispatcher.addRemoteSkillToBotProjectFile(projectId, manifestUrl, zipContent, endpointName);
- // update appsetting
- await dispatcher.setSkillAndAllowCaller(rootBotProjectId, projectId, endpointName);
- navigateToSkillBot(rootBotProjectId, projectId);
- } catch (ex) {
- handleProjectFailure(callbackHelpers, ex);
- } finally {
- set(botOpeningState, false);
- }
- }
+ set(botOpeningState, true);
+
+ const { projectId } = await openRemoteSkill(callbackHelpers, {
+ manifestUrl,
+ manifestFromZip,
+ rootBotProjectId,
+ botNameIdentifier,
+ });
+ set(botProjectIdsState, (current) => [...current, projectId]);
+ await dispatcher.addRemoteSkillToBotProjectFile(projectId, manifestUrl, zipContent, endpointName);
+ // update appsetting
+ await dispatcher.setSkillAndAllowCaller(rootBotProjectId, projectId, endpointName);
+ navigateToSkillBot(rootBotProjectId, projectId);
+ } catch (ex) {
+ handleProjectFailure(callbackHelpers, ex);
+ } finally {
+ set(botOpeningState, false);
+ }
+ },
);
const forceMigrate = useRecoilCallback(
@@ -235,86 +237,87 @@ export const projectDispatcher = () => {
} else {
navigateTo(`/home`);
}
- }
+ },
);
const openProject = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- path: string,
- storageId = 'default',
- navigate = true,
- absData?: any,
- callback?: (projectId: string) => void
- ) => {
- const { reset, set, snapshot } = callbackHelpers;
- try {
- set(botOpeningState, true);
+ (callbackHelpers: CallbackInterface) =>
+ async (
+ path: string,
+ storageId = 'default',
+ navigate = true,
+ absData?: any,
+ callback?: (projectId: string) => void,
+ ) => {
+ const { reset, set, snapshot } = callbackHelpers;
+ try {
+ set(botOpeningState, true);
- await flushExistingTasks(callbackHelpers);
- const { projectId, mainDialog, requiresMigrate, hasOldCustomRuntime } = await openRootBotAndSkillsByPath(
- callbackHelpers,
- path,
- storageId
- );
- reset(watchedVariablesState(projectId));
-
- if (requiresMigrate) {
- await forceMigrate(projectId, hasOldCustomRuntime);
- return;
- }
+ await flushExistingTasks(callbackHelpers);
+ const { projectId, mainDialog, requiresMigrate, hasOldCustomRuntime } = await openRootBotAndSkillsByPath(
+ callbackHelpers,
+ path,
+ storageId,
+ );
+ reset(watchedVariablesState(projectId));
- // ABS open Flow, update publishProfile & set alias for project after open project
- if (absData) {
- const { profile, source, alias } = absData;
-
- if (profile && alias) {
- const dispatcher = await snapshot.getPromise(dispatcherState);
- const { publishTargets } = await snapshot.getPromise(settingsState(projectId));
- const newProfile = await getPublishProfileFromPayload(profile, source);
- if (newProfile) {
- const newPublishTargets = publishTargets
- ? publishTargets.filter((item) => item.name !== newProfile.name)
- : [];
- newPublishTargets.push(newProfile);
- dispatcher.setPublishTargets(newPublishTargets, projectId);
- }
- await httpClient.post(`/projects/${projectId}/alias/set`, { alias });
+ if (requiresMigrate) {
+ await forceMigrate(projectId, hasOldCustomRuntime);
+ return;
}
- }
- // Post project creation
- set(projectMetaDataState(projectId), {
- isRootBot: true,
- isRemote: false,
- });
- projectIdCache.set(projectId);
+ // ABS open Flow, update publishProfile & set alias for project after open project
+ if (absData) {
+ const { profile, source, alias } = absData;
+
+ if (profile && alias) {
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+ const { publishTargets } = await snapshot.getPromise(settingsState(projectId));
+ const newProfile = await getPublishProfileFromPayload(profile, source);
+ if (newProfile) {
+ const newPublishTargets = publishTargets
+ ? publishTargets.filter((item) => item.name !== newProfile.name)
+ : [];
+ newPublishTargets.push(newProfile);
+ dispatcher.setPublishTargets(newPublishTargets, projectId);
+ }
+ await httpClient.post(`/projects/${projectId}/alias/set`, { alias });
+ }
+ }
- //migration on some sensitive property in browser local storage
- for (const property of RootBotManagedProperties) {
- const settings = settingStorage.get(projectId);
- const value = get(settings, property, '');
- if (!value.root && value.root !== '') {
- const newValue = { root: value };
- settingStorage.setField(projectId, property, newValue);
+ // Post project creation
+ set(projectMetaDataState(projectId), {
+ isRootBot: true,
+ isRemote: false,
+ });
+ projectIdCache.set(projectId);
+
+ //migration on some sensitive property in browser local storage
+ for (const property of RootBotManagedProperties) {
+ const settings = settingStorage.get(projectId);
+ const value = get(settings, property, '');
+ if (!value.root && value.root !== '') {
+ const newValue = { root: value };
+ settingStorage.setField(projectId, property, newValue);
+ }
}
- }
- if (navigate) {
- navigateToBot(callbackHelpers, projectId, mainDialog);
- }
+ if (navigate) {
+ navigateToBot(callbackHelpers, projectId, mainDialog);
+ }
- if (typeof callback === 'function') {
- callback(projectId);
+ if (typeof callback === 'function') {
+ callback(projectId);
+ }
+ } catch (ex) {
+ set(botProjectIdsState, []);
+ removeRecentProject(callbackHelpers, path);
+ handleProjectFailure(callbackHelpers, ex);
+ navigateTo('/home');
+ } finally {
+ set(botOpeningState, false);
}
- } catch (ex) {
- set(botProjectIdsState, []);
- removeRecentProject(callbackHelpers, path);
- handleProjectFailure(callbackHelpers, ex);
- navigateTo('/home');
- } finally {
- set(botOpeningState, false);
- }
- }
+ },
);
const fetchProjectById = useRecoilCallback((callbackHelpers: CallbackInterface) => async (projectId: string) => {
@@ -324,7 +327,7 @@ export const projectDispatcher = () => {
set(botOpeningState, true);
const { requiresMigrate, hasOldCustomRuntime } = await openRootBotAndSkillsByProjectId(
callbackHelpers,
- projectId
+ projectId,
);
if (requiresMigrate) {
await forceMigrate(projectId, hasOldCustomRuntime);
@@ -438,43 +441,44 @@ export const projectDispatcher = () => {
} finally {
set(botOpeningState, false);
}
- }
+ },
);
const migrateProjectTo = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- oldProjectId: string,
- name: string,
- description: string,
- location: string,
- runtimeLanguage: string,
- runtimeType: string
- ) => {
- const { set, snapshot } = callbackHelpers;
- try {
- const dispatcher = await snapshot.getPromise(dispatcherState);
- set(botOpeningState, true);
-
- // starts the creation process and stores the jobID in state for tracking
- const response = await migrateToV2(
- callbackHelpers,
- oldProjectId,
- name,
- description,
- location,
- runtimeLanguage,
- runtimeType
- );
+ (callbackHelpers: CallbackInterface) =>
+ async (
+ oldProjectId: string,
+ name: string,
+ description: string,
+ location: string,
+ runtimeLanguage: string,
+ runtimeType: string,
+ ) => {
+ const { set, snapshot } = callbackHelpers;
+ try {
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+ set(botOpeningState, true);
+
+ // starts the creation process and stores the jobID in state for tracking
+ const response = await migrateToV2(
+ callbackHelpers,
+ oldProjectId,
+ name,
+ description,
+ location,
+ runtimeLanguage,
+ runtimeType,
+ );
- if (response.data.jobId) {
- dispatcher.updateCreationMessage(response.data.jobId);
+ if (response.data.jobId) {
+ dispatcher.updateCreationMessage(response.data.jobId);
+ }
+ } catch (ex) {
+ set(botProjectIdsState, []);
+ handleProjectFailure(callbackHelpers, ex);
+ navigateTo('/home');
}
- } catch (ex) {
- set(botProjectIdsState, []);
- handleProjectFailure(callbackHelpers, ex);
- navigateTo('/home');
- }
- }
+ },
);
const deleteBot = useRecoilCallback((callbackHelpers: CallbackInterface) => async (projectId: string) => {
@@ -525,15 +529,17 @@ export const projectDispatcher = () => {
});
const setBotStatus = useRecoilCallback<[string, BotStatus], void>(
- ({ set }: CallbackInterface) => (projectId: string, status: BotStatus) => {
- set(botStatusState(projectId), status);
- }
+ ({ set }: CallbackInterface) =>
+ (projectId: string, status: BotStatus) => {
+ set(botStatusState(projectId), status);
+ },
);
const updateCurrentTarget = useRecoilCallback<[string, PublishTarget], void>(
- ({ set }: CallbackInterface) => (projectId: string, currentTarget) => {
- set(currentPublishTargetState(projectId), currentTarget);
- }
+ ({ set }: CallbackInterface) =>
+ (projectId: string, currentTarget) => {
+ set(currentPublishTargetState(projectId), currentTarget);
+ },
);
const saveTemplateId = useRecoilCallback<[string], void>(({ set }: CallbackInterface) => (templateId) => {
@@ -574,64 +580,59 @@ export const projectDispatcher = () => {
});
const updateCreationMessage = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- jobId: string,
- templateId?: string,
- urlSuffix?: string,
- profile?: any,
- source?: any
- ) => {
- const timer = setInterval(async () => {
- try {
- const response = await httpClient.get(`/status/${jobId}`);
- if (response.data?.httpStatusCode === 200 && response.data.result) {
- // Bot creation successful
- clearInterval(timer);
- const creationFlowType = await callbackHelpers.snapshot.getPromise(creationFlowTypeState);
-
- callbackHelpers.set(botOpeningMessage, response.data.latestMessage);
- const { botFiles, projectData } = await loadProjectData(response.data.result);
- const projectId = response.data.result.id;
+ (callbackHelpers: CallbackInterface) =>
+ async (jobId: string, templateId?: string, urlSuffix?: string, profile?: any, source?: any) => {
+ const timer = setInterval(async () => {
+ try {
+ const response = await httpClient.get(`/status/${jobId}`);
+ if (response.data?.httpStatusCode === 200 && response.data.result) {
+ // Bot creation successful
+ clearInterval(timer);
+ const creationFlowType = await callbackHelpers.snapshot.getPromise(creationFlowTypeState);
- if (creationFlowType === 'Skill') {
- // Skill Creation
- await addExistingSkillToBotProject(projectData.location, 'default', templateId);
- } else {
- // Root Bot Creation
- await postRootBotCreation(
- callbackHelpers,
- projectId,
- botFiles,
- projectData,
- templateId,
- profile,
- source,
- projectIdCache
- );
- }
- callbackHelpers.set(botOpeningMessage, '');
- callbackHelpers.set(botOpeningState, false);
- } else {
- if (response.data.httpStatusCode !== 500) {
- // pending
callbackHelpers.set(botOpeningMessage, response.data.latestMessage);
- } else {
- // failure
+ const { botFiles, projectData } = await loadProjectData(response.data.result);
+ const projectId = response.data.result.id;
+
+ if (creationFlowType === 'Skill') {
+ // Skill Creation
+ await addExistingSkillToBotProject(projectData.location, 'default', templateId);
+ } else {
+ // Root Bot Creation
+ await postRootBotCreation(
+ callbackHelpers,
+ projectId,
+ botFiles,
+ projectData,
+ templateId,
+ profile,
+ source,
+ projectIdCache,
+ );
+ }
+ callbackHelpers.set(botOpeningMessage, '');
callbackHelpers.set(botOpeningState, false);
-
- callbackHelpers.set(botOpeningMessage, response.data.latestMessage);
- clearInterval(timer);
+ } else {
+ if (response.data.httpStatusCode !== 500) {
+ // pending
+ callbackHelpers.set(botOpeningMessage, response.data.latestMessage);
+ } else {
+ // failure
+ callbackHelpers.set(botOpeningState, false);
+
+ callbackHelpers.set(botOpeningMessage, response.data.latestMessage);
+ clearInterval(timer);
+ }
}
+ } catch (err) {
+ clearInterval(timer);
+ callbackHelpers.set(botProjectIdsState, []);
+ handleProjectFailure(callbackHelpers, err);
+ callbackHelpers.set(botOpeningState, false);
+ navigateTo('/home');
}
- } catch (err) {
- clearInterval(timer);
- callbackHelpers.set(botProjectIdsState, []);
- handleProjectFailure(callbackHelpers, err);
- callbackHelpers.set(botOpeningState, false);
- navigateTo('/home');
- }
- }, 5000);
- }
+ }, 5000);
+ },
);
const setCurrentProjectId = useRecoilCallback(({ set }: CallbackInterface) => async (projectId: string) => {
@@ -652,7 +653,7 @@ export const projectDispatcher = () => {
handleProjectFailure(callbackHelpers, err);
callbackHelpers.set(
selectedTemplateReadMeState,
- `### ${formatMessage('Error encountered when getting template read-me file')}`
+ `### ${formatMessage('Error encountered when getting template read-me file')}`,
);
} finally {
callbackHelpers.set(fetchReadMePendingState, false);
@@ -674,7 +675,7 @@ export const projectDispatcher = () => {
const setSelectedTemplateVersion = useRecoilCallback(
(callbackHelpers: CallbackInterface) => (selectedVersion: string) => {
callbackHelpers.set(selectedTemplateVersionState, selectedVersion);
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/provision.ts b/Composer/packages/client/src/recoilModel/dispatchers/provision.ts
index b237450cfd..fdc8ed2205 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/provision.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/provision.ts
@@ -58,58 +58,59 @@ export const provisionDispatcher = () => {
};
const provisionToTarget = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- config: any,
- type: string,
- projectId: string,
- armToken = '',
- graphToken = '',
- currentProfile: PublishTarget | undefined = undefined
- ) => {
- try {
- TelemetryClient.track('NewPublishingProfileStarted');
- const result = await httpClient.post(`/provision/${projectId}/${type}`, {
- ...config,
- graphToken: graphToken,
- currentProfile,
- accessToken: armToken,
- });
- // set notification
- const notification = createNotification(getProvisionPendingNotification(result.data.message));
- addNotificationInternal(callbackHelpers, notification);
- // initialize this profile's provision status state
- callbackHelpers.set(provisionStatusState(projectId), (provisionStatus) => {
- const newStat = {
- ...provisionStatus,
- [result.data.processName]: {
- ...result.data,
- notificationId: notification.id,
- },
- };
- return newStat;
- });
+ (callbackHelpers: CallbackInterface) =>
+ async (
+ config: any,
+ type: string,
+ projectId: string,
+ armToken = '',
+ graphToken = '',
+ currentProfile: PublishTarget | undefined = undefined,
+ ) => {
+ try {
+ TelemetryClient.track('NewPublishingProfileStarted');
+ const result = await httpClient.post(`/provision/${projectId}/${type}`, {
+ ...config,
+ graphToken: graphToken,
+ currentProfile,
+ accessToken: armToken,
+ });
+ // set notification
+ const notification = createNotification(getProvisionPendingNotification(result.data.message));
+ addNotificationInternal(callbackHelpers, notification);
+ // initialize this profile's provision status state
+ callbackHelpers.set(provisionStatusState(projectId), (provisionStatus) => {
+ const newStat = {
+ ...provisionStatus,
+ [result.data.processName]: {
+ ...result.data,
+ notificationId: notification.id,
+ },
+ };
+ return newStat;
+ });
- // call provision status api interval to update the state.
- await updateProvisionStatus(
- callbackHelpers,
- result.data.id,
- projectId,
- result.data.processName,
- type,
- notification.id
- );
- } catch (error) {
- TelemetryClient.track('ProvisioningProfileCreateFailure', {
- message: error.response?.data || 'Error when provision target',
- });
+ // call provision status api interval to update the state.
+ await updateProvisionStatus(
+ callbackHelpers,
+ result.data.id,
+ projectId,
+ result.data.processName,
+ type,
+ notification.id,
+ );
+ } catch (error) {
+ TelemetryClient.track('ProvisioningProfileCreateFailure', {
+ message: error.response?.data || 'Error when provision target',
+ });
- // set notification
- const notification = createNotification(
- getProvisionFailureNotification(error.response?.data || 'Error when provision target')
- );
- addNotificationInternal(callbackHelpers, notification);
- }
- }
+ // set notification
+ const notification = createNotification(
+ getProvisionFailureNotification(error.response?.data || 'Error when provision target'),
+ );
+ addNotificationInternal(callbackHelpers, notification);
+ }
+ },
);
// update provision status interval
@@ -119,18 +120,14 @@ export const provisionDispatcher = () => {
projectId: string,
targetName: string,
targetType: string,
- notificationId: string
+ notificationId: string,
) => {
const timer = setInterval(async () => {
let notification,
isCleanTimer = false;
try {
const response = await httpClient.get(`/provision/${projectId}/status/${targetType}/${targetName}/${jobId}`);
- if (
- (response.data?.status === 200 || response.data?.status === 206) &&
- response.data.config &&
- response.data.config != {}
- ) {
+ if ((response.data?.status === 200 || response.data?.status === 206) && response.data.config) {
// delete provisionStatus
callbackHelpers.set(provisionStatusState(projectId), (status) => {
const newStatus = { ...status };
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/provisionQNA.ts b/Composer/packages/client/src/recoilModel/dispatchers/provisionQNA.ts
index 434d72cd96..0b105c6952 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/provisionQNA.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/provisionQNA.ts
@@ -96,186 +96,193 @@ const fetchEndpointKey = async (projectId: string, subscriptionKey: string): Pro
export const provisionQNADispatcher = () => {
const createQNA = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- projectId: string,
- tokenCredentials: TokenCredentials,
- subscriptionId: string,
- resourceGroupName: string,
- resourceName: string,
- region: string,
- tier: string
- ) => {
- const { snapshot } = callbackHelpers;
- const startTime = new Date().getTime();
- const skus: SkuList = tier === 'free' ? FREE_SKUS : PAID_SKUS;
+ (callbackHelpers: CallbackInterface) =>
+ async (
+ projectId: string,
+ tokenCredentials: TokenCredentials,
+ subscriptionId: string,
+ resourceGroupName: string,
+ resourceName: string,
+ region: string,
+ tier: string,
+ ) => {
+ const { snapshot } = callbackHelpers;
+ const startTime = new Date().getTime();
+ const skus: SkuList = tier === 'free' ? FREE_SKUS : PAID_SKUS;
- const notification = createNotification(getPendingQNANotificationCardProps());
- // add that notification
- addNotificationInternal(callbackHelpers, notification);
+ const notification = createNotification(getPendingQNANotificationCardProps());
+ // add that notification
+ addNotificationInternal(callbackHelpers, notification);
- try {
- const qnaMakerSearchName = `${resourceName}-search`.toLowerCase().replace('_', '');
- const qnaMakerWebAppName = `${resourceName}-qnahost`.toLowerCase().replace('_', '');
- const qnaMakerServiceName = `${resourceName}-qna`;
+ try {
+ const qnaMakerSearchName = `${resourceName}-search`.toLowerCase().replace('_', '');
+ const qnaMakerWebAppName = `${resourceName}-qnahost`.toLowerCase().replace('_', '');
+ const qnaMakerServiceName = `${resourceName}-qna`;
- const searchManagementClient = new SearchManagementClient(tokenCredentials as any, subscriptionId);
- await searchManagementClient.services.createOrUpdate(resourceGroupName, qnaMakerSearchName, {
- location: region,
- sku: skus.search,
- replicaCount: 1,
- partitionCount: 1,
- hostingMode: 'default',
- });
+ const searchManagementClient = new SearchManagementClient(tokenCredentials as any, subscriptionId);
+ await searchManagementClient.services.createOrUpdate(resourceGroupName, qnaMakerSearchName, {
+ location: region,
+ sku: skus.search,
+ replicaCount: 1,
+ partitionCount: 1,
+ hostingMode: 'default',
+ });
- const webSiteManagementClient = new WebSiteManagementClient(tokenCredentials, subscriptionId);
- await webSiteManagementClient.appServicePlans.createOrUpdate(resourceGroupName, resourceGroupName, {
- location: region,
- sku: skus.appservice,
- });
+ const webSiteManagementClient = new WebSiteManagementClient(tokenCredentials, subscriptionId);
+ await webSiteManagementClient.appServicePlans.createOrUpdate(resourceGroupName, resourceGroupName, {
+ location: region,
+ sku: skus.appservice,
+ });
- // add web config for websites
- const primaryEndpointKey = `${qnaMakerWebAppName}-PrimaryEndpointKey`;
- const secondaryEndpointKey = `${qnaMakerWebAppName}-SecondaryEndpointKey`;
- const defaultAnswer = 'No good match found in knowledge base.';
- const QNAMAKER_EXTENSION_VERSION = 'latest';
+ // add web config for websites
+ const primaryEndpointKey = `${qnaMakerWebAppName}-PrimaryEndpointKey`;
+ const secondaryEndpointKey = `${qnaMakerWebAppName}-SecondaryEndpointKey`;
+ const defaultAnswer = 'No good match found in knowledge base.';
+ const QNAMAKER_EXTENSION_VERSION = 'latest';
- const azureSearchAdminKey = (await searchManagementClient.adminKeys.get(resourceGroupName, qnaMakerSearchName))
- .primaryKey;
+ const azureSearchAdminKey = (
+ await searchManagementClient.adminKeys.get(resourceGroupName, qnaMakerSearchName)
+ ).primaryKey;
- // if app insights is included, set this up too
- let userAppInsightsAppId, userAppInsightsKey, userAppInsightsName;
- if (skus.appinsights) {
- // deploy or update exisiting app insights component
- const applicationInsightsManagementClient = new ApplicationInsightsManagementClient(
- tokenCredentials,
- subscriptionId
- );
- await applicationInsightsManagementClient.components.createOrUpdate(resourceGroupName, resourceGroupName, {
- location: region,
- applicationType: 'web',
- kind: 'web',
- });
+ // if app insights is included, set this up too
+ let userAppInsightsAppId, userAppInsightsKey, userAppInsightsName;
+ if (skus.appinsights) {
+ // deploy or update exisiting app insights component
+ const applicationInsightsManagementClient = new ApplicationInsightsManagementClient(
+ tokenCredentials,
+ subscriptionId,
+ );
+ await applicationInsightsManagementClient.components.createOrUpdate(resourceGroupName, resourceGroupName, {
+ location: region,
+ applicationType: 'web',
+ kind: 'web',
+ });
- const appInsightsComponent = await applicationInsightsManagementClient.components.get(
- resourceGroupName,
- resourceGroupName
- );
- userAppInsightsKey = appInsightsComponent.instrumentationKey;
- userAppInsightsName = resourceGroupName;
- userAppInsightsAppId = appInsightsComponent.appId;
- }
+ const appInsightsComponent = await applicationInsightsManagementClient.components.get(
+ resourceGroupName,
+ resourceGroupName,
+ );
+ userAppInsightsKey = appInsightsComponent.instrumentationKey;
+ userAppInsightsName = resourceGroupName;
+ userAppInsightsAppId = appInsightsComponent.appId;
+ }
- // deploy qna host webapp
- const webAppResult = await webSiteManagementClient.webApps.createOrUpdate(
- resourceGroupName,
- qnaMakerWebAppName,
- {
- name: qnaMakerWebAppName,
- serverFarmId: resourceGroupName,
- location: region,
- siteConfig: {
- cors: {
- allowedOrigins: ['*'],
- },
- appSettings: [
- {
- name: 'AzureSearchName',
- value: qnaMakerSearchName,
- },
- {
- name: 'AzureSearchAdminKey',
- value: azureSearchAdminKey,
- },
- {
- name: 'UserAppInsightsKey',
- value: userAppInsightsKey,
- },
- {
- name: 'UserAppInsightsName',
- value: userAppInsightsName,
- },
- {
- name: 'UserAppInsightsAppId',
- value: userAppInsightsAppId,
- },
- {
- name: 'PrimaryEndpointKey',
- value: primaryEndpointKey,
- },
- {
- name: 'SecondaryEndpointKey',
- value: secondaryEndpointKey,
- },
- {
- name: 'DefaultAnswer',
- value: defaultAnswer,
- },
- {
- name: 'QNAMAKER_EXTENSION_VERSION',
- value: QNAMAKER_EXTENSION_VERSION,
+ // deploy qna host webapp
+ const webAppResult = await webSiteManagementClient.webApps.createOrUpdate(
+ resourceGroupName,
+ qnaMakerWebAppName,
+ {
+ name: qnaMakerWebAppName,
+ serverFarmId: resourceGroupName,
+ location: region,
+ siteConfig: {
+ cors: {
+ allowedOrigins: ['*'],
},
- ],
+ appSettings: [
+ {
+ name: 'AzureSearchName',
+ value: qnaMakerSearchName,
+ },
+ {
+ name: 'AzureSearchAdminKey',
+ value: azureSearchAdminKey,
+ },
+ {
+ name: 'UserAppInsightsKey',
+ value: userAppInsightsKey,
+ },
+ {
+ name: 'UserAppInsightsName',
+ value: userAppInsightsName,
+ },
+ {
+ name: 'UserAppInsightsAppId',
+ value: userAppInsightsAppId,
+ },
+ {
+ name: 'PrimaryEndpointKey',
+ value: primaryEndpointKey,
+ },
+ {
+ name: 'SecondaryEndpointKey',
+ value: secondaryEndpointKey,
+ },
+ {
+ name: 'DefaultAnswer',
+ value: defaultAnswer,
+ },
+ {
+ name: 'QNAMAKER_EXTENSION_VERSION',
+ value: QNAMAKER_EXTENSION_VERSION,
+ },
+ ],
+ },
+ enabled: true,
},
- enabled: true,
- }
- );
+ );
- if (!webAppResult?.hostNames?.length) {
- throw new Error('App service creation failed to return host name.');
- }
+ if (!webAppResult?.hostNames?.length) {
+ throw new Error('App service creation failed to return host name.');
+ }
- // Create qna account
- const cognitiveServicesManagementClient = new CognitiveServicesManagementClient(
- tokenCredentials,
- subscriptionId
- );
- await cognitiveServicesManagementClient.accounts.create(resourceGroupName, qnaMakerServiceName, {
- kind: 'QnAMaker',
- sku: skus.qna,
- location: region,
- properties: {
- apiProperties: {
- qnaRuntimeEndpoint: `https://${webAppResult.hostNames[0]}`,
+ // Create qna account
+ const cognitiveServicesManagementClient = new CognitiveServicesManagementClient(
+ tokenCredentials,
+ subscriptionId,
+ );
+ await cognitiveServicesManagementClient.accounts.create(resourceGroupName, qnaMakerServiceName, {
+ kind: 'QnAMaker',
+ sku: skus.qna,
+ location: region,
+ properties: {
+ apiProperties: {
+ qnaRuntimeEndpoint: `https://${webAppResult.hostNames[0]}`,
+ },
},
- },
- });
+ });
- const keys = await cognitiveServicesManagementClient.accounts.listKeys(resourceGroupName, qnaMakerServiceName);
- if (!keys?.key1) {
- throw new Error('No key found for newly created authoring resource');
- } else {
- const endpointKey = await fetchEndpointKey(projectId, keys.key1);
+ const keys = await cognitiveServicesManagementClient.accounts.listKeys(
+ resourceGroupName,
+ qnaMakerServiceName,
+ );
+ if (!keys?.key1) {
+ throw new Error('No key found for newly created authoring resource');
+ } else {
+ const endpointKey = await fetchEndpointKey(projectId, keys.key1);
- const dispatcher = await snapshot.getPromise(dispatcherState);
- const currentSettings = await snapshot.getPromise(settingsState(projectId));
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+ const currentSettings = await snapshot.getPromise(settingsState(projectId));
- dispatcher.setSettings(projectId, {
- ...currentSettings,
- qna: {
- ...currentSettings.qna,
- subscriptionKey: keys.key1,
- endpointKey: endpointKey,
- },
- });
- settingStorage.setField(projectId, 'qna.endpointKey', endpointKey);
+ dispatcher.setSettings(projectId, {
+ ...currentSettings,
+ qna: {
+ ...currentSettings.qna,
+ subscriptionKey: keys.key1,
+ endpointKey: endpointKey,
+ },
+ });
+ settingStorage.setField(projectId, 'qna.endpointKey', endpointKey);
- TelemetryClient.track('SettingsGetKeysCreateNewResourceCompleted', {
- subscriptionId,
- region,
- createNewResourceGroup: false,
- resourceType: 'QnA Maker',
- });
+ TelemetryClient.track('SettingsGetKeysCreateNewResourceCompleted', {
+ subscriptionId,
+ region,
+ createNewResourceGroup: false,
+ resourceType: 'QnA Maker',
+ });
- deleteNotificationInternal(callbackHelpers, notification.id);
- const timeElapsed = Math.floor((new Date().getTime() - startTime) / (60 * 1000));
- const completedNotification = createNotification(getCompletedQNANotificationCardProps({ time: timeElapsed }));
- addNotificationInternal(callbackHelpers, completedNotification);
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ const timeElapsed = Math.floor((new Date().getTime() - startTime) / (60 * 1000));
+ const completedNotification = createNotification(
+ getCompletedQNANotificationCardProps({ time: timeElapsed }),
+ );
+ addNotificationInternal(callbackHelpers, completedNotification);
+ }
+ } catch (error) {
+ if (notification) deleteNotificationInternal(callbackHelpers, notification.id);
+ setError(callbackHelpers, error);
}
- } catch (error) {
- if (notification) deleteNotificationInternal(callbackHelpers, notification.id);
- setError(callbackHelpers, error);
- }
- }
+ },
);
return { createQNA };
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/publisher.ts b/Composer/packages/client/src/recoilModel/dispatchers/publisher.ts
index 64524c5ad4..f96070898f 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/publisher.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/publisher.ts
@@ -96,7 +96,7 @@ export const publisherDispatcher = () => {
callbackHelpers: CallbackInterface,
projectId: string,
target: any,
- data: PublishResult
+ data: PublishResult,
) => {
if (data == null) return;
const { set, snapshot } = callbackHelpers;
@@ -196,42 +196,37 @@ export const publisherDispatcher = () => {
});
const publishToTarget = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- projectId: string,
- target: PublishTarget,
- metadata: any,
- sensitiveSettings,
- token = ''
- ) => {
- try {
- const { snapshot } = callbackHelpers;
- const dialogs = await snapshot.getPromise(dialogsWithLuProviderSelectorFamily(projectId));
- const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const referredLuFiles = luUtil.checkLuisBuild(luFiles, dialogs);
- const referredQnaFiles = qnaUtil.checkQnaBuild(qnaFiles, dialogs);
- const response = await httpClient.post(`/publish/${projectId}/publish/${target.name}`, {
- publishTarget: target,
- accessToken: token,
- metadata: {
- ...metadata,
- luResources: referredLuFiles.map((file) => ({ id: file.id, isEmpty: file.empty })),
- qnaResources: referredQnaFiles.map((file) => ({ id: file.id, isEmpty: file.empty })),
- },
- sensitiveSettings,
- });
+ (callbackHelpers: CallbackInterface) =>
+ async (projectId: string, target: PublishTarget, metadata: any, sensitiveSettings, token = '') => {
+ try {
+ const { snapshot } = callbackHelpers;
+ const dialogs = await snapshot.getPromise(dialogsWithLuProviderSelectorFamily(projectId));
+ const luFiles = await snapshot.getPromise(luFilesSelectorFamily(projectId));
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const referredLuFiles = luUtil.checkLuisBuild(luFiles, dialogs);
+ const referredQnaFiles = qnaUtil.checkQnaBuild(qnaFiles, dialogs);
+ const response = await httpClient.post(`/publish/${projectId}/publish/${target.name}`, {
+ publishTarget: target,
+ accessToken: token,
+ metadata: {
+ ...metadata,
+ luResources: referredLuFiles.map((file) => ({ id: file.id, isEmpty: file.empty })),
+ qnaResources: referredQnaFiles.map((file) => ({ id: file.id, isEmpty: file.empty })),
+ },
+ sensitiveSettings,
+ });
- // add job id to storage
- const publishJobIds = publishStorage.get('jobIds') || {};
- publishJobIds[`${projectId}-${target.name}`] = response.data.id;
- publishStorage.set('jobIds', publishJobIds);
+ // add job id to storage
+ const publishJobIds = publishStorage.get('jobIds') || {};
+ publishJobIds[`${projectId}-${target.name}`] = response.data.id;
+ publishStorage.set('jobIds', publishJobIds);
- await publishSuccess(callbackHelpers, projectId, response.data, target);
- } catch (err) {
- // special case to handle dotnet issues
- await publishFailure(callbackHelpers, Text.CONNECTBOTFAILURE, err.response?.data, target, projectId);
- }
- }
+ await publishSuccess(callbackHelpers, projectId, response.data, target);
+ } catch (err) {
+ // special case to handle dotnet issues
+ await publishFailure(callbackHelpers, Text.CONNECTBOTFAILURE, err.response?.data, target, projectId);
+ }
+ },
);
const rollbackToVersion = useRecoilCallback(
@@ -245,14 +240,14 @@ export const publisherDispatcher = () => {
} catch (err) {
await publishFailure(callbackHelpers, Text.CONNECTBOTFAILURE, err.response.data, target, projectId);
}
- }
+ },
);
// get bot status from target publisher
const getPublishStatusV2 = useRecoilCallback(
(callbackHelpers: CallbackInterface) => async (projectId: string, target: any, response: any) => {
updatePublishStatus(callbackHelpers, projectId, target, response?.data);
- }
+ },
);
// get bot status from target publisher
@@ -263,14 +258,14 @@ export const publisherDispatcher = () => {
jobId ??
(publishStorage.get('jobIds') ? publishStorage.get('jobIds')[`${projectId}-${target.name}`] : undefined);
const response = await httpClient.get(
- `/publish/${projectId}/status/${target.name}${currentJobId ? '/' + currentJobId : ''}`
+ `/publish/${projectId}/status/${target.name}${currentJobId ? '/' + currentJobId : ''}`,
);
updatePublishStatus(callbackHelpers, projectId, target, response.data);
} catch (err) {
updatePublishStatus(callbackHelpers, projectId, target, err.response?.data);
}
- }
+ },
);
const getPublishHistory = useRecoilCallback(
(callbackHelpers: CallbackInterface) => async (projectId: string, target: any) => {
@@ -287,30 +282,31 @@ export const publisherDispatcher = () => {
//TODO: error
logMessage(callbackHelpers, err.response?.data?.message || err.message);
}
- }
+ },
);
// only support local publish
const stopPublishBot = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (projectId: string, target: any = defaultPublishConfig) => {
- const { set, snapshot } = callbackHelpers;
- try {
- const currentBotStatus = await snapshot.getPromise(botStatusState(projectId));
- // Change to "Stopping" status only if the Bot is not in a failed state or inactive state
- if (currentBotStatus !== BotStatus.failed && currentBotStatus !== BotStatus.inactive) {
- set(botStatusState(projectId), BotStatus.stopping);
- }
+ (callbackHelpers: CallbackInterface) =>
+ async (projectId: string, target: any = defaultPublishConfig) => {
+ const { set, snapshot } = callbackHelpers;
+ try {
+ const currentBotStatus = await snapshot.getPromise(botStatusState(projectId));
+ // Change to "Stopping" status only if the Bot is not in a failed state or inactive state
+ if (currentBotStatus !== BotStatus.failed && currentBotStatus !== BotStatus.inactive) {
+ set(botStatusState(projectId), BotStatus.stopping);
+ }
- await httpClient.post(`/publish/${projectId}/stopPublish/${target.name}`);
+ await httpClient.post(`/publish/${projectId}/stopPublish/${target.name}`);
- if (currentBotStatus !== BotStatus.failed) {
- set(botStatusState(projectId), BotStatus.inactive);
+ if (currentBotStatus !== BotStatus.failed) {
+ set(botStatusState(projectId), BotStatus.inactive);
+ }
+ } catch (err) {
+ setError(callbackHelpers, err);
+ logMessage(callbackHelpers, err.message);
}
- } catch (err) {
- setError(callbackHelpers, err);
- logMessage(callbackHelpers, err.message);
- }
- }
+ },
);
const resetBotRuntimeLog = useRecoilCallback((callbackHelpers: CallbackInterface) => async (projectId: string) => {
@@ -328,7 +324,7 @@ export const publisherDispatcher = () => {
botEndpoints[projectId]?.url || defaultBotEndpoint,
settings.MicrosoftAppId && settings.MicrosoftAppPassword
? { MicrosoftAppId: settings.MicrosoftAppId, MicrosoftAppPassword: settings.MicrosoftAppPassword }
- : { MicrosoftAppPassword: '', MicrosoftAppId: '' }
+ : { MicrosoftAppPassword: '', MicrosoftAppId: '' },
);
} catch (err) {
setError(callbackHelpers, err);
@@ -345,7 +341,7 @@ export const publisherDispatcher = () => {
setError(callbackHelpers, err);
logMessage(callbackHelpers, err.message);
}
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/qna.ts b/Composer/packages/client/src/recoilModel/dispatchers/qna.ts
index 3d0dce65a0..faebe11711 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/qna.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/qna.ts
@@ -46,14 +46,14 @@ const updateQnaFiles = (
deletes?: QnAFile[];
updates?: QnAFile[];
},
- getLatestFile?: (current: QnAFile, changed: QnAFile) => QnAFile
+ getLatestFile?: (current: QnAFile, changed: QnAFile) => QnAFile,
) => {
const { updates, adds, deletes } = changes;
// updates
updates?.forEach((qnaFile) => {
set(qnaFileState({ projectId, qnaFileId: qnaFile.id }), (oldQnaFile) =>
- getLatestFile ? getLatestFile(oldQnaFile, qnaFile) : qnaFile
+ getLatestFile ? getLatestFile(oldQnaFile, qnaFile) : qnaFile,
);
});
@@ -68,7 +68,7 @@ const updateQnaFiles = (
const addedIds = adds.map((file) => file.id);
adds.forEach((qnaFile) => {
set(qnaFileState({ projectId, qnaFileId: qnaFile.id }), (oldQnaFile) =>
- getLatestFile ? getLatestFile(oldQnaFile, qnaFile) : qnaFile
+ getLatestFile ? getLatestFile(oldQnaFile, qnaFile) : qnaFile,
);
});
set(qnaFileIdsState(projectId), (ids) => [...ids, ...addedIds]);
@@ -77,7 +77,7 @@ const updateQnaFiles = (
export const updateQnAFileState = async (
callbackHelpers: CallbackInterface,
- { id, content, projectId }: { id: string; content: string; projectId: string }
+ { id, content, projectId }: { id: string; content: string; projectId: string },
) => {
const updatedQnAFile = (await qnaWorker.parse(id, content)) as QnAFile;
@@ -86,7 +86,7 @@ export const updateQnAFileState = async (
export const createQnAFileState = async (
callbackHelpers: CallbackInterface,
- { id, content, projectId }: { id: string; content: string; projectId: string }
+ { id, content, projectId }: { id: string; content: string; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
@@ -111,7 +111,7 @@ export const createQnAFileState = async (
export const createSourceQnAFileByLocaleState = async (
callbackHelpers: CallbackInterface,
- { id, content, locale, projectId }: { id: string; content: string; locale: string; projectId: string }
+ { id, content, locale, projectId }: { id: string; content: string; locale: string; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
@@ -131,7 +131,7 @@ export const createSourceQnAFileByLocaleState = async (
*/
export const removeQnAFileState = async (
callbackHelpers: CallbackInterface,
- { id, projectId }: { id: string; projectId: string }
+ { id, projectId }: { id: string; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
@@ -153,7 +153,7 @@ export const removeQnAFileState = async (
export const createKBFileState = async (
callbackHelpers: CallbackInterface,
- { id, name, content, projectId }: { id: string; name: string; content: string; projectId: string }
+ { id, name, content, projectId }: { id: string; name: string; content: string; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
@@ -183,7 +183,7 @@ export const createKBFileByLocaleState = async (
content,
locale,
projectId,
- }: { id: string; name: string; content: string; locale: string; projectId: string }
+ }: { id: string; name: string; content: string; locale: string; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const allQnAFiles: QnAFile[] = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
@@ -206,7 +206,7 @@ export const createKBFileByLocaleState = async (
const updateDialogQnARef = (
callbackHelpers: CallbackInterface,
- params: { id: string; name: string; projectId: string; qnaFiles: QnAFile[] }
+ params: { id: string; name: string; projectId: string; qnaFiles: QnAFile[] },
) => {
const { id, name, projectId, qnaFiles } = params;
@@ -226,7 +226,7 @@ const updateDialogQnARef = (
export const removeKBFileState = async (
callbackHelpers: CallbackInterface,
- { id, projectId }: { id: string; projectId: string }
+ { id, projectId }: { id: string; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
@@ -248,7 +248,7 @@ export const removeKBFileState = async (
export const renameKBFileState = async (
callbackHelpers: CallbackInterface,
- { id, name, projectId }: { id: string; name: string; projectId: string }
+ { id, name, projectId }: { id: string; name: string; projectId: string },
) => {
const { set, snapshot } = callbackHelpers;
const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
@@ -283,458 +283,456 @@ export const renameKBFileState = async (
export const qnaDispatcher = () => {
const createQnADialogBegin = useRecoilCallback(
- ({ set }: CallbackInterface) => async ({
- onComplete,
- projectId,
- dialogId,
- }: {
- onComplete?: () => void;
- projectId: string;
- dialogId: string;
- }) => {
- set(createQnAOnState, { projectId, dialogId });
- set(showCreateQnADialogState(projectId), true);
- set(onCreateQnADialogCompleteState(projectId), { func: onComplete });
- }
+ ({ set }: CallbackInterface) =>
+ async ({ onComplete, projectId, dialogId }: { onComplete?: () => void; projectId: string; dialogId: string }) => {
+ set(createQnAOnState, { projectId, dialogId });
+ set(showCreateQnADialogState(projectId), true);
+ set(onCreateQnADialogCompleteState(projectId), { func: onComplete });
+ },
);
const createQnADialogCancel = useRecoilCallback(
- ({ set }: CallbackInterface) => ({ projectId }: { projectId: string }) => {
- set(createQnAOnState, { projectId: '', dialogId: '' });
- set(showCreateQnADialogState(projectId), false);
- set(onCreateQnADialogCompleteState(projectId), { func: undefined });
- }
+ ({ set }: CallbackInterface) =>
+ ({ projectId }: { projectId: string }) => {
+ set(createQnAOnState, { projectId: '', dialogId: '' });
+ set(showCreateQnADialogState(projectId), false);
+ set(onCreateQnADialogCompleteState(projectId), { func: undefined });
+ },
);
const createQnADialogSuccess = useRecoilCallback(
- ({ set, snapshot }: CallbackInterface) => async ({ projectId }: { projectId: string }) => {
- const onCreateQnAFromUrlDialogComplete = (await snapshot.getPromise(onCreateQnADialogCompleteState(projectId)))
- .func;
- if (typeof onCreateQnAFromUrlDialogComplete === 'function') {
- onCreateQnAFromUrlDialogComplete();
- }
- set(showCreateQnADialogState(projectId), false);
- set(onCreateQnADialogCompleteState(projectId), { func: undefined });
- }
+ ({ set, snapshot }: CallbackInterface) =>
+ async ({ projectId }: { projectId: string }) => {
+ const onCreateQnAFromUrlDialogComplete = (await snapshot.getPromise(onCreateQnADialogCompleteState(projectId)))
+ .func;
+ if (typeof onCreateQnAFromUrlDialogComplete === 'function') {
+ onCreateQnAFromUrlDialogComplete();
+ }
+ set(showCreateQnADialogState(projectId), false);
+ set(onCreateQnADialogCompleteState(projectId), { func: undefined });
+ },
);
const updateQnAFile = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id, //qna file id: dialogName.locale or kbName.source.locale
- content,
- projectId,
- }: {
- id: string;
- content: string;
- projectId: string;
- }) => {
- await updateQnAFileState(callbackHelpers, { id, content, projectId });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id, //qna file id: dialogName.locale or kbName.source.locale
+ content,
+ projectId,
+ }: {
+ id: string;
+ content: string;
+ projectId: string;
+ }) => {
+ await updateQnAFileState(callbackHelpers, { id, content, projectId });
+ },
);
const updateContainerQnAFile = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- content,
- projectId,
- }: {
- id: string;
- content: string;
- projectId: string;
- }) => {
- const updatedQnAFile = (await qnaWorker.parse(id, content)) as QnAFile;
-
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedQnAFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, content, projectId }: { id: string; content: string; projectId: string }) => {
+ const updatedQnAFile = (await qnaWorker.parse(id, content)) as QnAFile;
+
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedQnAFile] });
+ },
);
const createQnAFile = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- content,
- projectId,
- }: {
- id: string;
- locale: string;
- content: string;
- projectId: string;
- filteredLocales: string[];
- }) => {
- await createQnAFileState(callbackHelpers, { id, content, projectId });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ content,
+ projectId,
+ }: {
+ id: string;
+ locale: string;
+ content: string;
+ projectId: string;
+ filteredLocales: string[];
+ }) => {
+ await createQnAFileState(callbackHelpers, { id, content, projectId });
+ },
);
const removeQnAFile = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ id, projectId }: { id: string; projectId: string }) => {
- await removeQnAFileState(callbackHelpers, { id, projectId });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, projectId }: { id: string; projectId: string }) => {
+ await removeQnAFileState(callbackHelpers, { id, projectId });
+ },
);
const removeQnAFileOnAllLocales = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ id, projectId }: { id: string; projectId: string }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
-
- const targetQnAFiles = qnaFiles.filter((item) => getBaseName(item.id) === id);
- if (!targetQnAFiles || targetQnAFiles.length === 0) {
- throw new Error(`remove qna files ${id} not exist`);
- }
-
- targetQnAFiles.forEach((file) => {
- qnaFileStatusStorage.removeFileStatus(projectId, file.id);
- });
- updateQnaFiles(callbackHelpers, projectId, { deletes: [...targetQnAFiles] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, projectId }: { id: string; projectId: string }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+
+ const targetQnAFiles = qnaFiles.filter((item) => getBaseName(item.id) === id);
+ if (!targetQnAFiles || targetQnAFiles.length === 0) {
+ throw new Error(`remove qna files ${id} not exist`);
+ }
+
+ targetQnAFiles.forEach((file) => {
+ qnaFileStatusStorage.removeFileStatus(projectId, file.id);
+ });
+ updateQnaFiles(callbackHelpers, projectId, { deletes: [...targetQnAFiles] });
+ },
);
const dismissCreateQnAModal = useRecoilCallback(
- ({ set }: CallbackInterface) => async ({ projectId }: { projectId: string }) => {
- set(showCreateQnADialogState(projectId), false);
- }
+ ({ set }: CallbackInterface) =>
+ async ({ projectId }: { projectId: string }) => {
+ set(showCreateQnADialogState(projectId), false);
+ },
);
const importQnAFromUrl = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- containerId,
- dialogId,
- url,
- multiTurn,
- projectId,
- }: {
- containerId: string; // qna container file id: {name}.source.{locale}
- dialogId: string;
- url: string;
- multiTurn: boolean;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const notification = createNotification(getQnaPendingNotification(url));
- addNotificationInternal(callbackHelpers, notification);
-
- let response;
- try {
- response = await httpClient.get(`/utilities/qna/parse`, {
- params: { url: encodeURIComponent(url), multiTurn },
- });
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- const notification = createNotification(
- getQnaSuccessNotification(() => {
- navigateTo(
- rootBotProjectId === projectId
- ? `/bot/${projectId}/knowledge-base/${dialogId}`
- : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${dialogId}`
- );
- deleteNotificationInternal(callbackHelpers, notification.id);
- })
- );
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ containerId,
+ dialogId,
+ url,
+ multiTurn,
+ projectId,
+ }: {
+ containerId: string; // qna container file id: {name}.source.{locale}
+ dialogId: string;
+ url: string;
+ multiTurn: boolean;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ const notification = createNotification(getQnaPendingNotification(url));
addNotificationInternal(callbackHelpers, notification);
- } catch (err) {
- addNotificationInternal(
- callbackHelpers,
- createNotification(getQnaFailedNotification(err.response?.data?.message))
- );
- TelemetryClient.track('UpdateKnowledgeBaseError', { error: err.response?.data?.message });
- return;
- } finally {
- deleteNotificationInternal(callbackHelpers, notification.id);
- }
- const contentForSourceQnA = `> !# @source.url=${url}
+ let response;
+ try {
+ response = await httpClient.get(`/utilities/qna/parse`, {
+ params: { url: encodeURIComponent(url), multiTurn },
+ });
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ const notification = createNotification(
+ getQnaSuccessNotification(() => {
+ navigateTo(
+ rootBotProjectId === projectId
+ ? `/bot/${projectId}/knowledge-base/${dialogId}`
+ : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${dialogId}`,
+ );
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }),
+ );
+ addNotificationInternal(callbackHelpers, notification);
+ } catch (err) {
+ addNotificationInternal(
+ callbackHelpers,
+ createNotification(getQnaFailedNotification(err.response?.data?.message)),
+ );
+ TelemetryClient.track('UpdateKnowledgeBaseError', { error: err.response?.data?.message });
+ return;
+ } finally {
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }
+
+ const contentForSourceQnA = `> !# @source.url=${url}
> !# @source.multiTurn=${multiTurn}
${response.data}
`;
- await updateContainerQnAFile({ id: containerId, content: contentForSourceQnA, projectId });
- }
+ await updateContainerQnAFile({ id: containerId, content: contentForSourceQnA, projectId });
+ },
);
const createQnAKBFromUrl = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- name,
- url,
- locale,
- multiTurn,
- projectId,
- }: {
- id: string; // dialogId.locale
- name: string;
- url: string;
- locale: string;
- multiTurn: boolean;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- await dismissCreateQnAModal({ projectId });
- const notification = createNotification(getQnaPendingNotification(url));
- addNotificationInternal(callbackHelpers, notification);
-
- let response;
- try {
- response = await httpClient.get(`/utilities/qna/parse`, {
- params: { url: encodeURIComponent(url), multiTurn },
- });
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- const notification = createNotification(
- getQnaSuccessNotification(() => {
- navigateTo(
- rootBotProjectId === projectId
- ? `/bot/${projectId}/knowledge-base/${getBaseName(id)}`
- : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${getBaseName(id)}`
- );
- deleteNotificationInternal(callbackHelpers, notification.id);
- })
- );
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ name,
+ url,
+ locale,
+ multiTurn,
+ projectId,
+ }: {
+ id: string; // dialogId.locale
+ name: string;
+ url: string;
+ locale: string;
+ multiTurn: boolean;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ await dismissCreateQnAModal({ projectId });
+ const notification = createNotification(getQnaPendingNotification(url));
addNotificationInternal(callbackHelpers, notification);
- } catch (err) {
- addNotificationInternal(
- callbackHelpers,
- createNotification(getQnaFailedNotification(err.response?.data?.message))
- );
- createQnADialogCancel({ projectId });
- TelemetryClient.track('AddNewKnowledgeBaseError', { error: err.response?.data?.message });
- return;
- } finally {
- deleteNotificationInternal(callbackHelpers, notification.id);
- }
-
- const contentForSourceQnA = `> !# @source.url=${url}
+
+ let response;
+ try {
+ response = await httpClient.get(`/utilities/qna/parse`, {
+ params: { url: encodeURIComponent(url), multiTurn },
+ });
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ const notification = createNotification(
+ getQnaSuccessNotification(() => {
+ navigateTo(
+ rootBotProjectId === projectId
+ ? `/bot/${projectId}/knowledge-base/${getBaseName(id)}`
+ : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${getBaseName(id)}`,
+ );
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }),
+ );
+ addNotificationInternal(callbackHelpers, notification);
+ } catch (err) {
+ addNotificationInternal(
+ callbackHelpers,
+ createNotification(getQnaFailedNotification(err.response?.data?.message)),
+ );
+ createQnADialogCancel({ projectId });
+ TelemetryClient.track('AddNewKnowledgeBaseError', { error: err.response?.data?.message });
+ return;
+ } finally {
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }
+
+ const contentForSourceQnA = `> !# @source.url=${url}
> !# @source.multiTurn=${multiTurn}
${response.data}
`;
- await createKBFileByLocaleState(callbackHelpers, {
- id,
- name,
- content: contentForSourceQnA,
- locale,
- projectId,
- });
+ await createKBFileByLocaleState(callbackHelpers, {
+ id,
+ name,
+ content: contentForSourceQnA,
+ locale,
+ projectId,
+ });
- await createQnADialogSuccess({ projectId });
- }
+ await createQnADialogSuccess({ projectId });
+ },
);
const createQnAKBsFromUrls = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- name,
- urls,
- locales,
- multiTurn,
- projectId,
- }: {
- id: string; // dialogId.locale
- name: string;
- urls: string[];
- locales: string[];
- multiTurn: boolean;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- await dismissCreateQnAModal({ projectId });
- const pairs: { locale: string; content: string }[] = locales.map((locale) => {
- return { locale, content: '' };
- });
- await Promise.all(
- urls.map(async (url, index) => {
- const notification = createNotification(getQnaPendingNotification(url));
- addNotificationInternal(callbackHelpers, notification);
-
- let response;
- try {
- response = await httpClient.get(`/utilities/qna/parse`, {
- params: { url: encodeURIComponent(url), multiTurn },
- });
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- const notification = createNotification(
- getQnaSuccessNotification(() => {
- navigateTo(
- rootBotProjectId === projectId
- ? `/bot/${projectId}/knowledge-base/${getBaseName(id)}`
- : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${getBaseName(id)}`
- );
- deleteNotificationInternal(callbackHelpers, notification.id);
- })
- );
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ name,
+ urls,
+ locales,
+ multiTurn,
+ projectId,
+ }: {
+ id: string; // dialogId.locale
+ name: string;
+ urls: string[];
+ locales: string[];
+ multiTurn: boolean;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ await dismissCreateQnAModal({ projectId });
+ const pairs: { locale: string; content: string }[] = locales.map((locale) => {
+ return { locale, content: '' };
+ });
+ await Promise.all(
+ urls.map(async (url, index) => {
+ const notification = createNotification(getQnaPendingNotification(url));
addNotificationInternal(callbackHelpers, notification);
- } catch (err) {
- addNotificationInternal(
- callbackHelpers,
- createNotification(getQnaFailedNotification(err.response?.data?.message))
- );
- createQnADialogCancel({ projectId });
- TelemetryClient.track('AddNewKnowledgeBaseError', { error: err.response?.data?.message });
- return;
- } finally {
- deleteNotificationInternal(callbackHelpers, notification.id);
- }
+ let response;
+ try {
+ response = await httpClient.get(`/utilities/qna/parse`, {
+ params: { url: encodeURIComponent(url), multiTurn },
+ });
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ const notification = createNotification(
+ getQnaSuccessNotification(() => {
+ navigateTo(
+ rootBotProjectId === projectId
+ ? `/bot/${projectId}/knowledge-base/${getBaseName(id)}`
+ : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${getBaseName(id)}`,
+ );
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }),
+ );
+ addNotificationInternal(callbackHelpers, notification);
+ } catch (err) {
+ addNotificationInternal(
+ callbackHelpers,
+ createNotification(getQnaFailedNotification(err.response?.data?.message)),
+ );
+ createQnADialogCancel({ projectId });
+ TelemetryClient.track('AddNewKnowledgeBaseError', { error: err.response?.data?.message });
+
+ return;
+ } finally {
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }
- const contentForSourceQnA = `> !# @source.url=${url}
+ const contentForSourceQnA = `> !# @source.url=${url}
> !# @source.multiTurn=${multiTurn}
${response.data}
`;
- pairs[index].content = contentForSourceQnA;
- })
- );
+ pairs[index].content = contentForSourceQnA;
+ }),
+ );
- const { languages } = await snapshot.getPromise(settingsState(projectId));
+ const { languages } = await snapshot.getPromise(settingsState(projectId));
- const toBeCopiedLocales = languages.filter((l) => {
- return !locales.includes(l);
- });
- toBeCopiedLocales.forEach((locale) => {
- pairs.push({ locale, content: pairs[0].content });
- });
+ const toBeCopiedLocales = languages.filter((l) => {
+ return !locales.includes(l);
+ });
+ toBeCopiedLocales.forEach((locale) => {
+ pairs.push({ locale, content: pairs[0].content });
+ });
+
+ await createKBFileOnLocalesState(callbackHelpers, {
+ id,
+ name,
+ data: pairs,
+ projectId,
+ });
+ await createQnADialogSuccess({ projectId });
+ },
+ );
- await createKBFileOnLocalesState(callbackHelpers, {
+ const createQnAKBFromQnAMaker = useRecoilCallback(
+ (callbackHelpers: CallbackInterface) =>
+ async ({
id,
name,
- data: pairs,
+ endpoint,
+ locales,
+ kbId,
+ kbName,
+ subscriptionKey,
projectId,
- });
- await createQnADialogSuccess({ projectId });
- }
- );
+ }: {
+ id: string; // dialogId.locale
+ name: string;
+ endpoint: string;
+ locales: string[];
+ kbId: string;
+ kbName: string;
+ subscriptionKey: string;
+ projectId: string;
+ }) => {
+ const { snapshot, set } = callbackHelpers;
+ await dismissCreateQnAModal({ projectId });
+ const notification = createNotification(getQnaImportPendingNotification(kbName));
+ addNotificationInternal(callbackHelpers, notification);
- const createQnAKBFromQnAMaker = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- name,
- endpoint,
- locales,
- kbId,
- kbName,
- subscriptionKey,
- projectId,
- }: {
- id: string; // dialogId.locale
- name: string;
- endpoint: string;
- locales: string[];
- kbId: string;
- kbName: string;
- subscriptionKey: string;
- projectId: string;
- }) => {
- const { snapshot, set } = callbackHelpers;
- await dismissCreateQnAModal({ projectId });
- const notification = createNotification(getQnaImportPendingNotification(kbName));
- addNotificationInternal(callbackHelpers, notification);
-
- let response;
- try {
- response = await httpClient.post(`/utilities/qna/import`, {
- endpoint: encodeURIComponent(endpoint),
- kbId,
- subscriptionKey,
- });
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- const currentLocale = await snapshot.getPromise(localeState(projectId));
- const notification = createNotification(
- getQnaSuccessNotification(() => {
- // if created locale is not current authoring locale, switch to target locale.
- if (currentLocale !== locales[0]) {
- set(localeState(projectId), locales[0]);
- }
+ let response;
+ try {
+ response = await httpClient.post(`/utilities/qna/import`, {
+ endpoint: encodeURIComponent(endpoint),
+ kbId,
+ subscriptionKey,
+ });
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ const currentLocale = await snapshot.getPromise(localeState(projectId));
+ const notification = createNotification(
+ getQnaSuccessNotification(() => {
+ // if created locale is not current authoring locale, switch to target locale.
+ if (currentLocale !== locales[0]) {
+ set(localeState(projectId), locales[0]);
+ }
+
+ navigateTo(
+ rootBotProjectId === projectId
+ ? `/bot/${projectId}/knowledge-base/${getBaseName(id)}`
+ : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${getBaseName(id)}`,
+ );
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }),
+ );
+ addNotificationInternal(callbackHelpers, notification);
+ } catch (err) {
+ addNotificationInternal(
+ callbackHelpers,
+ createNotification(getQnaFailedNotification(err.response?.data?.message)),
+ );
+ createQnADialogCancel({ projectId });
+ TelemetryClient.track('AddNewKnowledgeBaseError', { error: err.response?.data?.message });
+ return;
+ } finally {
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }
- navigateTo(
- rootBotProjectId === projectId
- ? `/bot/${projectId}/knowledge-base/${getBaseName(id)}`
- : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${getBaseName(id)}`
- );
- deleteNotificationInternal(callbackHelpers, notification.id);
- })
- );
- addNotificationInternal(callbackHelpers, notification);
- } catch (err) {
- addNotificationInternal(
- callbackHelpers,
- createNotification(getQnaFailedNotification(err.response?.data?.message))
- );
- createQnADialogCancel({ projectId });
- TelemetryClient.track('AddNewKnowledgeBaseError', { error: err.response?.data?.message });
- return;
- } finally {
- deleteNotificationInternal(callbackHelpers, notification.id);
- }
-
- const contentForSourceQnA = `> !# @source.endpoint=${endpoint}
+ const contentForSourceQnA = `> !# @source.endpoint=${endpoint}
> !# @source.kbId=${kbId}
${response.data}
`;
- for (const locale of locales) {
- await createKBFileByLocaleState(callbackHelpers, {
- id,
- name,
- content: contentForSourceQnA,
- locale,
- projectId,
- });
- }
+ for (const locale of locales) {
+ await createKBFileByLocaleState(callbackHelpers, {
+ id,
+ name,
+ content: contentForSourceQnA,
+ locale,
+ projectId,
+ });
+ }
- await createQnADialogSuccess({ projectId });
- }
+ await createQnADialogSuccess({ projectId });
+ },
);
const importQnAFromQnAMaker = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- containerId,
- dialogId,
- projectId,
- endpoint,
- subscriptionKey,
- kbId,
- kbName,
- }: {
- containerId: string; // qna container file id: {name}.source.{locale}
- dialogId: string;
- projectId: string;
- endpoint: string;
- subscriptionKey: string;
- kbId: string;
- kbName: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const notification = createNotification(getQnaImportPendingNotification(kbName));
- addNotificationInternal(callbackHelpers, notification);
- let response;
- try {
- response = await httpClient.post(`/utilities/qna/import`, {
- endpoint: encodeURIComponent(endpoint),
- subscriptionKey,
- kbId,
- });
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- const notification = createNotification(
- getQnaSuccessNotification(() => {
- navigateTo(
- rootBotProjectId === projectId
- ? `/bot/${projectId}/knowledge-base/${dialogId}`
- : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${dialogId}`
- );
- deleteNotificationInternal(callbackHelpers, notification.id);
- })
- );
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ containerId,
+ dialogId,
+ projectId,
+ endpoint,
+ subscriptionKey,
+ kbId,
+ kbName,
+ }: {
+ containerId: string; // qna container file id: {name}.source.{locale}
+ dialogId: string;
+ projectId: string;
+ endpoint: string;
+ subscriptionKey: string;
+ kbId: string;
+ kbName: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ const notification = createNotification(getQnaImportPendingNotification(kbName));
addNotificationInternal(callbackHelpers, notification);
- } catch (err) {
- addNotificationInternal(
- callbackHelpers,
- createNotification(getQnaFailedNotification(err.response?.data?.message))
- );
- TelemetryClient.track('UpdateKnowledgeBaseError', { error: err.response?.data?.message });
- return;
- } finally {
- deleteNotificationInternal(callbackHelpers, notification.id);
- }
+ let response;
+ try {
+ response = await httpClient.post(`/utilities/qna/import`, {
+ endpoint: encodeURIComponent(endpoint),
+ subscriptionKey,
+ kbId,
+ });
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ const notification = createNotification(
+ getQnaSuccessNotification(() => {
+ navigateTo(
+ rootBotProjectId === projectId
+ ? `/bot/${projectId}/knowledge-base/${dialogId}`
+ : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${dialogId}`,
+ );
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }),
+ );
+ addNotificationInternal(callbackHelpers, notification);
+ } catch (err) {
+ addNotificationInternal(
+ callbackHelpers,
+ createNotification(getQnaFailedNotification(err.response?.data?.message)),
+ );
+ TelemetryClient.track('UpdateKnowledgeBaseError', { error: err.response?.data?.message });
+ return;
+ } finally {
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }
- const contentForSourceQnA = `> !# @source.endpoint=${endpoint}
+ const contentForSourceQnA = `> !# @source.endpoint=${endpoint}
> !# @source.kbId=${kbId}
${response.data}
`;
- await updateContainerQnAFile({ id: containerId, content: contentForSourceQnA, projectId });
- }
+ await updateContainerQnAFile({ id: containerId, content: contentForSourceQnA, projectId });
+ },
);
const createKBFileOnLocalesState = async (
@@ -744,7 +742,7 @@ ${response.data}
name,
data,
projectId,
- }: { id: string; name: string; data: { content: string; locale: string }[]; projectId: string }
+ }: { id: string; name: string; data: { content: string; locale: string }[]; projectId: string },
) => {
const { snapshot } = callbackHelpers;
const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
@@ -762,272 +760,245 @@ ${response.data}
}
const createdQnaFile = (await qnaWorker.parse(createdSourceQnAId, d.content)) as QnAFile;
changes.push(createdQnaFile);
- })
+ }),
);
updateQnaFiles(callbackHelpers, projectId, { adds: changes });
};
const createQnAKBFromScratch = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- name,
- projectId,
- content = '',
- }: {
- id: string;
- name: string;
- content?: string;
- projectId: string;
- }) => {
- await dismissCreateQnAModal({ projectId });
-
- await createKBFileState(callbackHelpers, { id, name, content, projectId });
- const rootBotProjectId = await callbackHelpers.snapshot.getPromise(rootBotProjectIdSelector);
- const notification = createNotification(
- getQnaSuccessNotification(() => {
- navigateTo(
- rootBotProjectId === projectId
- ? `/bot/${projectId}/knowledge-base/${getBaseName(id)}`
- : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${getBaseName(id)}`
- );
- deleteNotificationInternal(callbackHelpers, notification.id);
- })
- );
- addNotificationInternal(callbackHelpers, notification);
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ name,
+ projectId,
+ content = '',
+ }: {
+ id: string;
+ name: string;
+ content?: string;
+ projectId: string;
+ }) => {
+ await dismissCreateQnAModal({ projectId });
+
+ await createKBFileState(callbackHelpers, { id, name, content, projectId });
+ const rootBotProjectId = await callbackHelpers.snapshot.getPromise(rootBotProjectIdSelector);
+ const notification = createNotification(
+ getQnaSuccessNotification(() => {
+ navigateTo(
+ rootBotProjectId === projectId
+ ? `/bot/${projectId}/knowledge-base/${getBaseName(id)}`
+ : `/bot/${rootBotProjectId}/skill/${projectId}/knowledge-base/${getBaseName(id)}`,
+ );
+ deleteNotificationInternal(callbackHelpers, notification.id);
+ }),
+ );
+ addNotificationInternal(callbackHelpers, notification);
+ },
);
const updateQnAQuestion = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- sectionId,
- questionId,
- content,
- projectId,
- }: {
- id: string;
- sectionId: string;
- questionId: string;
- content: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const qnaFile = qnaFiles.find((temp) => temp.id === id);
- if (!qnaFile) return qnaFiles;
-
- const updatedFile = qnaUtil.updateQnAQuestion(qnaFile, sectionId, questionId, content);
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ sectionId,
+ questionId,
+ content,
+ projectId,
+ }: {
+ id: string;
+ sectionId: string;
+ questionId: string;
+ content: string;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const qnaFile = qnaFiles.find((temp) => temp.id === id);
+ if (!qnaFile) return qnaFiles;
+
+ const updatedFile = qnaUtil.updateQnAQuestion(qnaFile, sectionId, questionId, content);
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ },
);
const updateQnAAnswer = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- sectionId,
- content,
- projectId,
- }: {
- id: string;
- sectionId: string;
- content: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const qnaFile = qnaFiles.find((temp) => temp.id === id);
- if (!qnaFile) return qnaFiles;
-
- const updatedFile = qnaUtil.updateQnAAnswer(qnaFile, sectionId, content);
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ sectionId,
+ content,
+ projectId,
+ }: {
+ id: string;
+ sectionId: string;
+ content: string;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const qnaFile = qnaFiles.find((temp) => temp.id === id);
+ if (!qnaFile) return qnaFiles;
+
+ const updatedFile = qnaUtil.updateQnAAnswer(qnaFile, sectionId, content);
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ },
);
const createQnAQuestion = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- sectionId,
- content,
- projectId,
- }: {
- id: string;
- sectionId: string;
- content: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const qnaFile = qnaFiles.find((temp) => temp.id === id);
- if (!qnaFile) return qnaFiles;
-
- const updatedFile = qnaUtil.createQnAQuestion(qnaFile, sectionId, content);
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ sectionId,
+ content,
+ projectId,
+ }: {
+ id: string;
+ sectionId: string;
+ content: string;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const qnaFile = qnaFiles.find((temp) => temp.id === id);
+ if (!qnaFile) return qnaFiles;
+
+ const updatedFile = qnaUtil.createQnAQuestion(qnaFile, sectionId, content);
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ },
);
const removeQnAQuestion = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- sectionId,
- questionId,
- projectId,
- }: {
- id: string;
- sectionId: string;
- questionId: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const qnaFile = qnaFiles.find((temp) => temp.id === id);
- if (!qnaFile) return qnaFiles;
-
- const updatedFile = qnaUtil.removeQnAQuestion(qnaFile, sectionId, questionId);
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ sectionId,
+ questionId,
+ projectId,
+ }: {
+ id: string;
+ sectionId: string;
+ questionId: string;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const qnaFile = qnaFiles.find((temp) => temp.id === id);
+ if (!qnaFile) return qnaFiles;
+
+ const updatedFile = qnaUtil.removeQnAQuestion(qnaFile, sectionId, questionId);
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ },
);
const createQnAPairs = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- content,
- projectId,
- }: {
- id: string;
- content: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const qnaFile = qnaFiles.find((temp) => temp.id === id);
- if (!qnaFile) return qnaFiles;
-
- // insert into head, need investigate
- const updatedFile = qnaUtil.insertSection(qnaFile, 0, content);
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, content, projectId }: { id: string; content: string; projectId: string }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const qnaFile = qnaFiles.find((temp) => temp.id === id);
+ if (!qnaFile) return qnaFiles;
+
+ // insert into head, need investigate
+ const updatedFile = qnaUtil.insertSection(qnaFile, 0, content);
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ },
);
const removeQnAPairs = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- sectionId,
- projectId,
- }: {
- id: string;
- sectionId: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const qnaFile = qnaFiles.find((temp) => temp.id === id);
- if (!qnaFile) return qnaFiles;
-
- const updatedFile = qnaUtil.removeSection(qnaFile, sectionId);
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, sectionId, projectId }: { id: string; sectionId: string; projectId: string }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const qnaFile = qnaFiles.find((temp) => temp.id === id);
+ if (!qnaFile) return qnaFiles;
+
+ const updatedFile = qnaUtil.removeSection(qnaFile, sectionId);
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ },
);
const createQnAImport = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- sourceId,
- projectId,
- }: {
- id: string;
- sourceId: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const qnaFile = qnaFiles.find((temp) => temp.id === id);
- if (!qnaFile) return qnaFiles;
-
- const updatedFile = qnaUtil.addImport(qnaFile, `${sourceId}.qna`);
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, sourceId, projectId }: { id: string; sourceId: string; projectId: string }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const qnaFile = qnaFiles.find((temp) => temp.id === id);
+ if (!qnaFile) return qnaFiles;
+
+ const updatedFile = qnaUtil.addImport(qnaFile, `${sourceId}.qna`);
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ },
);
const removeQnAImport = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- sourceId,
- projectId,
- }: {
- id: string;
- sourceId: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const qnaFile = qnaFiles.find((temp) => temp.id === id);
- if (!qnaFile) return qnaFiles;
-
- const updatedFile = qnaUtil.removeImport(qnaFile, `${sourceId}.qna`);
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, sourceId, projectId }: { id: string; sourceId: string; projectId: string }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const qnaFile = qnaFiles.find((temp) => temp.id === id);
+ if (!qnaFile) return qnaFiles;
+
+ const updatedFile = qnaUtil.removeImport(qnaFile, `${sourceId}.qna`);
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ },
);
const removeQnAImportOnAllLocales = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id, //dialogName
- sourceId,
- projectId,
- }: {
- id: string;
- sourceId: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const targetQnaFiles = qnaFiles.filter((f) => getBaseName(f.id) === id);
- if (!targetQnaFiles || targetQnaFiles.length === 0) return targetQnaFiles;
-
- const updatedFiles = targetQnaFiles.map((f) => {
- return qnaUtil.removeImport(f, `${sourceId}.qna`);
- });
- updateQnaFiles(callbackHelpers, projectId, { updates: [...updatedFiles] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id, //dialogName
+ sourceId,
+ projectId,
+ }: {
+ id: string;
+ sourceId: string;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const targetQnaFiles = qnaFiles.filter((f) => getBaseName(f.id) === id);
+ if (!targetQnaFiles || targetQnaFiles.length === 0) return targetQnaFiles;
+
+ const updatedFiles = targetQnaFiles.map((f) => {
+ return qnaUtil.removeImport(f, `${sourceId}.qna`);
+ });
+ updateQnaFiles(callbackHelpers, projectId, { updates: [...updatedFiles] });
+ },
);
const updateQnAImport = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- sourceId,
- newSourceId,
- projectId,
- }: {
- id: string;
- sourceId: string;
- newSourceId: string;
- projectId: string;
- }) => {
- const { snapshot } = callbackHelpers;
- const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
- const qnaFile = qnaFiles.find((temp) => temp.id === id);
- if (!qnaFile) return qnaFiles;
-
- let updatedFile = qnaUtil.removeImport(qnaFile, `${sourceId}.qna`);
- updatedFile = qnaUtil.addImport(updatedFile, `${newSourceId}.qna`);
- updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({
+ id,
+ sourceId,
+ newSourceId,
+ projectId,
+ }: {
+ id: string;
+ sourceId: string;
+ newSourceId: string;
+ projectId: string;
+ }) => {
+ const { snapshot } = callbackHelpers;
+ const qnaFiles = await snapshot.getPromise(qnaFilesSelectorFamily(projectId));
+ const qnaFile = qnaFiles.find((temp) => temp.id === id);
+ if (!qnaFile) return qnaFiles;
+
+ let updatedFile = qnaUtil.removeImport(qnaFile, `${sourceId}.qna`);
+ updatedFile = qnaUtil.addImport(updatedFile, `${newSourceId}.qna`);
+ updateQnaFiles(callbackHelpers, projectId, { updates: [updatedFile] });
+ },
);
const removeQnAKB = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ id, projectId }: { id: string; projectId: string }) => {
- await removeKBFileState(callbackHelpers, { id, projectId });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, projectId }: { id: string; projectId: string }) => {
+ await removeKBFileState(callbackHelpers, { id, projectId });
+ },
);
const renameQnAKB = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({
- id,
- name,
- projectId,
- }: {
- id: string;
- name: string;
- projectId: string;
- }) => {
- await renameKBFileState(callbackHelpers, { id, name, projectId });
- }
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, name, projectId }: { id: string; name: string; projectId: string }) => {
+ await renameKBFileState(callbackHelpers, { id, name, projectId });
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/recognizers.ts b/Composer/packages/client/src/recoilModel/dispatchers/recognizers.ts
index 611436fc4d..a83f878f26 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/recognizers.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/recognizers.ts
@@ -19,34 +19,35 @@ const templates = {
export const recognizerDispatcher = () => {
const updateRecognizer = useRecoilCallback(
- ({ set, snapshot }: CallbackInterface) => async (projectId: string, dialogId: string, kind: LuProviderType) => {
- const recognizers = await snapshot.getPromise(recognizersSelectorFamily(projectId));
-
- const updates = recognizers.filter(
- ({ id, content }) =>
- id.split('.')[0] === dialogId && LuProviderRecognizer.includes(content.$kind) && content.$kind !== kind
- );
-
- const mutlilangRecognizer = recognizers.find(
- ({ id, content }) => id.split('.')[0] === dialogId && content.$kind === SDKKinds.MultiLanguageRecognizer
- );
-
- if (mutlilangRecognizer) {
- const { id, content } = mutlilangRecognizer;
- const key = kind === SDKKinds.OrchestratorRecognizer ? 'ORCHESTRATOR' : 'LUIS';
- set(recognizerState({ projectId, id }), {
- content: { ...content, id: `${key}_${id.replace('.lu.dialog', '')}` },
- id,
+ ({ set, snapshot }: CallbackInterface) =>
+ async (projectId: string, dialogId: string, kind: LuProviderType) => {
+ const recognizers = await snapshot.getPromise(recognizersSelectorFamily(projectId));
+
+ const updates = recognizers.filter(
+ ({ id, content }) =>
+ id.split('.')[0] === dialogId && LuProviderRecognizer.includes(content.$kind) && content.$kind !== kind,
+ );
+
+ const mutlilangRecognizer = recognizers.find(
+ ({ id, content }) => id.split('.')[0] === dialogId && content.$kind === SDKKinds.MultiLanguageRecognizer,
+ );
+
+ if (mutlilangRecognizer) {
+ const { id, content } = mutlilangRecognizer;
+ const key = kind === SDKKinds.OrchestratorRecognizer ? 'ORCHESTRATOR' : 'LUIS';
+ set(recognizerState({ projectId, id }), {
+ content: { ...content, id: `${key}_${id.replace('.lu.dialog', '')}` },
+ id,
+ });
+ }
+
+ updates.forEach(({ id }) => {
+ set(recognizerState({ projectId, id }), {
+ id,
+ content: templates[kind](dialogId, id.replace('.lu.dialog', '')),
+ });
});
- }
-
- updates.forEach(({ id }) => {
- set(recognizerState({ projectId, id }), {
- id,
- content: templates[kind](dialogId, id.replace('.lu.dialog', '')),
- });
- });
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/setting.ts b/Composer/packages/client/src/recoilModel/dispatchers/setting.ts
index 7d7ec16e77..c1ee8e4d84 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/setting.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/setting.ts
@@ -27,7 +27,7 @@ import { setError } from './shared';
export const setRootBotSettingState = async (
callbackHelpers: CallbackInterface,
projectId: string,
- settings: DialogSetting
+ settings: DialogSetting,
) => {
const { set: recoilSet, snapshot } = callbackHelpers;
// set value in local storage
@@ -76,7 +76,7 @@ export const setRootBotSettingState = async (
export const setSkillBotSettingState = async (
callbackHelpers: CallbackInterface,
projectId: string,
- settings: DialogSetting
+ settings: DialogSetting,
) => {
const { set: recoilSet, snapshot } = callbackHelpers;
// set value in local storage
@@ -122,134 +122,137 @@ export const settingsDispatcher = () => {
} else {
setSkillBotSettingState(callbackHelpers, projectId, settings);
}
- }
+ },
);
const setPublishTargets = useRecoilCallback(
- ({ set }: CallbackInterface) => async (publishTargets: PublishTarget[], projectId: string) => {
- set(settingsState(projectId), (settings) => ({
- ...settings,
- publishTargets,
- }));
- }
+ ({ set }: CallbackInterface) =>
+ async (publishTargets: PublishTarget[], projectId: string) => {
+ set(settingsState(projectId), (settings) => ({
+ ...settings,
+ publishTargets,
+ }));
+ },
);
const setRuntimeSettings = useRecoilCallback(
- ({ set }: CallbackInterface) => async (
- projectId: string,
- runtime: { path: string; command: string; key: string; name: string }
- ) => {
- set(settingsState(projectId), (currentSettingsState) => ({
- ...currentSettingsState,
- runtime: {
- ...runtime,
- customRuntime: true,
- },
- }));
- }
+ ({ set }: CallbackInterface) =>
+ async (projectId: string, runtime: { path: string; command: string; key: string; name: string }) => {
+ set(settingsState(projectId), (currentSettingsState) => ({
+ ...currentSettingsState,
+ runtime: {
+ ...runtime,
+ customRuntime: true,
+ },
+ }));
+ },
);
const setImportedLibraries = useRecoilCallback(
- ({ set }: CallbackInterface) => async (projectId: string, importedLibraries: LibraryRef[]) => {
- set(settingsState(projectId), (currentSettingsState) => ({
- ...currentSettingsState,
- importedLibraries,
- }));
- }
+ ({ set }: CallbackInterface) =>
+ async (projectId: string, importedLibraries: LibraryRef[]) => {
+ set(settingsState(projectId), (currentSettingsState) => ({
+ ...currentSettingsState,
+ importedLibraries,
+ }));
+ },
);
const setRuntimeField = useRecoilCallback(
- ({ set }: CallbackInterface) => async (projectId: string, field: string, newValue: boolean | string) => {
- set(settingsState(projectId), (currentValue) => ({
- ...currentValue,
- runtime: {
- ...currentValue.runtime,
- [field]: newValue,
- },
- }));
- }
+ ({ set }: CallbackInterface) =>
+ async (projectId: string, field: string, newValue: boolean | string) => {
+ set(settingsState(projectId), (currentValue) => ({
+ ...currentValue,
+ runtime: {
+ ...currentValue.runtime,
+ [field]: newValue,
+ },
+ }));
+ },
);
const setMicrosoftAppProperties = useRecoilCallback(
- ({ set }: CallbackInterface) => async (projectId: string, appId: string, password: string) => {
- set(settingsState(projectId), (currentValue) => ({
- ...currentValue,
- MicrosoftAppId: appId,
- MicrosoftAppPassword: password,
- }));
- }
+ ({ set }: CallbackInterface) =>
+ async (projectId: string, appId: string, password: string) => {
+ set(settingsState(projectId), (currentValue) => ({
+ ...currentValue,
+ MicrosoftAppId: appId,
+ MicrosoftAppPassword: password,
+ }));
+ },
);
const setCustomRuntime = useRecoilCallback(() => async (projectId: string, isOn: boolean) => {
setRuntimeField(projectId, 'customRuntime', isOn);
});
const setSkillAndAllowCaller = useRecoilCallback(
- ({ set, snapshot }: CallbackInterface) => async (projectId: string, skillId: string, endpointName: string) => {
- const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
- if (!rootBotProjectId) {
- return;
- }
- const manifestIdentifier = await snapshot.getPromise(botNameIdentifierState(skillId));
- const settings = await snapshot.getPromise(settingsState(rootBotProjectId));
- const skills = await snapshot.getPromise(skillsStateSelector);
- const manifest = skills[manifestIdentifier]?.manifest;
- let msAppId, endpointUrl;
+ ({ set, snapshot }: CallbackInterface) =>
+ async (projectId: string, skillId: string, endpointName: string) => {
+ const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
+ if (!rootBotProjectId) {
+ return;
+ }
+ const manifestIdentifier = await snapshot.getPromise(botNameIdentifierState(skillId));
+ const settings = await snapshot.getPromise(settingsState(rootBotProjectId));
+ const skills = await snapshot.getPromise(skillsStateSelector);
+ const manifest = skills[manifestIdentifier]?.manifest;
+ let msAppId, endpointUrl;
- if (manifest?.endpoints) {
- const matchedEndpoint = manifest.endpoints.find((item) => item.name === endpointName);
- endpointUrl = matchedEndpoint?.endpointUrl || '';
- msAppId = matchedEndpoint?.msAppId || '';
- }
+ if (manifest?.endpoints) {
+ const matchedEndpoint = manifest.endpoints.find((item) => item.name === endpointName);
+ endpointUrl = matchedEndpoint?.endpointUrl || '';
+ msAppId = matchedEndpoint?.msAppId || '';
+ }
- const isAdaptiveRuntime = isUsingAdaptiveRuntime(settings.runtime);
- set(settingsState(projectId), (currentValue) => {
- if (isAdaptiveRuntime) {
- const callers = settings.runtimeSettings?.skills?.allowedCallers
- ? [...settings.runtimeSettings?.skills?.allowedCallers]
- : [];
- if (!callers?.find((item) => item === msAppId)) {
- callers.push(msAppId);
- }
- return {
- ...currentValue,
- skill: {
- ...settings.skill,
- [manifestIdentifier]: {
- endpointUrl,
- msAppId,
+ const isAdaptiveRuntime = isUsingAdaptiveRuntime(settings.runtime);
+ set(settingsState(projectId), (currentValue) => {
+ if (isAdaptiveRuntime) {
+ const callers = settings.runtimeSettings?.skills?.allowedCallers
+ ? [...(settings.runtimeSettings?.skills?.allowedCallers ?? [])]
+ : [];
+ if (!callers?.find((item) => item === msAppId)) {
+ callers.push(msAppId);
+ }
+ return {
+ ...currentValue,
+ skill: {
+ ...settings.skill,
+ [manifestIdentifier]: {
+ endpointUrl,
+ msAppId,
+ },
+ },
+ runtimeSettings: {
+ ...settings.runtimeSettings,
+ skills: {
+ allowedCallers: callers,
+ },
},
- },
- runtimeSettings: {
- ...settings.runtimeSettings,
- skills: {
+ };
+ } else {
+ const callers = settings.skillConfiguration?.allowedCallers
+ ? [...(settings.skillConfiguration?.allowedCallers ?? [])]
+ : [];
+ if (!callers?.find((item) => item === msAppId)) {
+ callers.push(msAppId);
+ }
+ return {
+ ...currentValue,
+ skill: {
+ ...settings.skill,
+ [manifestIdentifier]: {
+ endpointUrl,
+ msAppId,
+ },
+ },
+ skillConfiguration: {
+ ...settings.skillConfiguration,
allowedCallers: callers,
},
- },
- };
- } else {
- const callers = settings.skillConfiguration?.allowedCallers
- ? [...settings.skillConfiguration?.allowedCallers]
- : [];
- if (!callers?.find((item) => item === msAppId)) {
- callers.push(msAppId);
+ };
}
- return {
- ...currentValue,
- skill: {
- ...settings.skill,
- [manifestIdentifier]: {
- endpointUrl,
- msAppId,
- },
- },
- skillConfiguration: {
- ...settings.skillConfiguration,
- allowedCallers: callers,
- },
- };
- }
- });
- }
+ });
+ },
);
const setQnASettings = useRecoilCallback(
@@ -271,7 +274,7 @@ export const settingsDispatcher = () => {
} catch (err) {
setError(callbackHelpers, err);
}
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/shared.ts b/Composer/packages/client/src/recoilModel/dispatchers/shared.ts
index a930d50b10..34df4c8c9f 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/shared.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/shared.ts
@@ -37,7 +37,7 @@ export const setError = (callbackHelpers: CallbackInterface, payload) => {
callbackHelpers.set(applicationErrorState, {
status: 409,
message: formatMessage(
- 'This version of the content is out of date, and your last change was rejected. The content will be automatically refreshed.'
+ 'This version of the content is out of date, and your last change was rejected. The content will be automatically refreshed.',
),
summary: formatMessage('Modification Rejected'),
});
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/skill.ts b/Composer/packages/client/src/recoilModel/dispatchers/skill.ts
index 84487802b7..3ccaae8306 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/skill.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/skill.ts
@@ -72,35 +72,37 @@ export const skillDispatcher = () => {
};
const removeSkillManifest = useRecoilCallback(
- ({ set, snapshot }: CallbackInterface) => async (id: string, projectId: string) => {
- let newCurrentManifestId: string | undefined;
- const dispatcher = await snapshot.getPromise(dispatcherState);
- set(skillManifestsState(projectId), (skillManifests) => {
- const filtered = skillManifests.filter((manifest) => manifest.id !== id);
- if (filtered.length > 0) {
- newCurrentManifestId = filtered[0].id;
- }
- return filtered;
- });
- dispatcher.updateManifestInBotProjectFile(projectId, newCurrentManifestId);
- }
+ ({ set, snapshot }: CallbackInterface) =>
+ async (id: string, projectId: string) => {
+ let newCurrentManifestId: string | undefined;
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+ set(skillManifestsState(projectId), (skillManifests) => {
+ const filtered = skillManifests.filter((manifest) => manifest.id !== id);
+ if (filtered.length > 0) {
+ newCurrentManifestId = filtered[0].id;
+ }
+ return filtered;
+ });
+ dispatcher.updateManifestInBotProjectFile(projectId, newCurrentManifestId);
+ },
);
const updateSkillManifest = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async ({ id, content }: SkillManifestFile, projectId: string) => {
- const { set, snapshot } = callbackHelpers;
- const manifests = await snapshot.getPromise(skillManifestsState(projectId));
- const dispatcher = await snapshot.getPromise(dispatcherState);
+ (callbackHelpers: CallbackInterface) =>
+ async ({ id, content }: SkillManifestFile, projectId: string) => {
+ const { set, snapshot } = callbackHelpers;
+ const manifests = await snapshot.getPromise(skillManifestsState(projectId));
+ const dispatcher = await snapshot.getPromise(dispatcherState);
- if (!manifests.some((manifest) => manifest.id === id)) {
- createSkillManifest(callbackHelpers, { id, content, projectId });
- dispatcher.updateManifestInBotProjectFile(projectId, id);
- }
+ if (!manifests.some((manifest) => manifest.id === id)) {
+ createSkillManifest(callbackHelpers, { id, content, projectId });
+ dispatcher.updateManifestInBotProjectFile(projectId, id);
+ }
- set(skillManifestsState(projectId), (skillManifests) =>
- skillManifests.map((manifest) => (manifest.id === id ? { id, content } : manifest))
- );
- }
+ set(skillManifestsState(projectId), (skillManifests) =>
+ skillManifests.map((manifest) => (manifest.id === id ? { id, content } : manifest)),
+ );
+ },
);
const displayManifestModal = useRecoilCallback(({ set }: CallbackInterface) => (id: string) => {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/storage.ts b/Composer/packages/client/src/recoilModel/dispatchers/storage.ts
index 02bbe65326..c7a38c3d2f 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/storage.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/storage.ts
@@ -55,7 +55,7 @@ export const storageDispatcher = () => {
// TODO: Handle exceptions
logMessage(callbackHelpers, `Error updating current path for storage: ${ex}`);
}
- }
+ },
);
const addNewStorage = useRecoilCallback((callbackHelpers: CallbackInterface) => async (storageData: string) => {
@@ -110,35 +110,37 @@ export const storageDispatcher = () => {
logMessage(callbackHelpers, `Error fetching focussed storage folder: ${ex}`);
setStorageFileLoadingStatus('failure');
}
- }
+ },
);
const createFolder = useRecoilCallback<[string, string], Promise>(
- ({ set }: CallbackInterface) => async (path, name) => {
- const storageId = 'default';
- try {
- await httpClient.post(`/storages/folder`, { path, name, storageId });
- } catch (err) {
- set(applicationErrorState, {
- message: err.message,
- summary: formatMessage('Create Folder Error'),
- });
- }
- }
+ ({ set }: CallbackInterface) =>
+ async (path, name) => {
+ const storageId = 'default';
+ try {
+ await httpClient.post(`/storages/folder`, { path, name, storageId });
+ } catch (err) {
+ set(applicationErrorState, {
+ message: err.message,
+ summary: formatMessage('Create Folder Error'),
+ });
+ }
+ },
);
const updateFolder = useRecoilCallback<[string, string, string], Promise>(
- ({ set }: CallbackInterface) => async (path, oldName, newName) => {
- const storageId = 'default';
- try {
- await httpClient.put(`/storages/folder`, { path, oldName, newName, storageId });
- } catch (err) {
- set(applicationErrorState, {
- message: err.message,
- summary: formatMessage('Update Folder Name Error'),
- });
- }
- }
+ ({ set }: CallbackInterface) =>
+ async (path, oldName, newName) => {
+ const storageId = 'default';
+ try {
+ await httpClient.put(`/storages/folder`, { path, oldName, newName, storageId });
+ } catch (err) {
+ set(applicationErrorState, {
+ message: err.message,
+ summary: formatMessage('Update Folder Name Error'),
+ });
+ }
+ },
);
const fetchTemplates = useRecoilCallback(({ set }: CallbackInterface) => async (feedUrls?: string[]) => {
@@ -176,7 +178,7 @@ export const storageDispatcher = () => {
// TODO: Handle exceptions
logMessage(callbackHelpers, `Error fetching runtime templates: ${ex}`);
}
- }
+ },
);
const fetchFeatureFlags = useRecoilCallback<[], Promise>((callbackHelpers: CallbackInterface) => async () => {
@@ -195,19 +197,20 @@ export const storageDispatcher = () => {
});
const toggleFeatureFlag = useRecoilCallback(
- ({ set }: CallbackInterface) => async (featureName: FeatureFlagKey, enabled: boolean) => {
- let newFeatureFlags: FeatureFlagMap = {} as FeatureFlagMap;
- // update local
- set(featureFlagsState, (featureFlagsState) => {
- newFeatureFlags = { ...featureFlagsState };
- newFeatureFlags[featureName] = { ...featureFlagsState[featureName], enabled: enabled };
- return newFeatureFlags;
- });
- // update server
- await httpClient.post(`/featureFlags`, { featureFlags: newFeatureFlags });
+ ({ set }: CallbackInterface) =>
+ async (featureName: FeatureFlagKey, enabled: boolean) => {
+ let newFeatureFlags: FeatureFlagMap = {} as FeatureFlagMap;
+ // update local
+ set(featureFlagsState, (featureFlagsState) => {
+ newFeatureFlags = { ...featureFlagsState };
+ newFeatureFlags[featureName] = { ...featureFlagsState[featureName], enabled: enabled };
+ return newFeatureFlags;
+ });
+ // update server
+ await httpClient.post(`/featureFlags`, { featureFlags: newFeatureFlags });
- TelemetryClient.track('FeatureFlagChanged', { featureFlag: featureName, enabled });
- }
+ TelemetryClient.track('FeatureFlagChanged', { featureFlag: featureName, enabled });
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/trigger.ts b/Composer/packages/client/src/recoilModel/dispatchers/trigger.ts
index 8dfed17a1b..a52a4572ad 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/trigger.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/trigger.ts
@@ -44,7 +44,7 @@ const getNewDialogWithTrigger = async (
dialogId: string,
formData: TriggerFormData,
createLuIntent,
- createLgTemplates
+ createLgTemplates,
) => {
const { snapshot } = callbackHelpers;
const lgFiles = await snapshot.getPromise(lgFilesSelectorFamily(projectId));
@@ -68,11 +68,11 @@ const getNewDialogWithTrigger = async (
} else if (formData.$kind === qnaMatcherKey) {
const designerId1 = getDesignerIdFromDialogPath(
newDialog,
- `content.triggers[${index}].actions[0].actions[1].prompt`
+ `content.triggers[${index}].actions[0].actions[1].prompt`,
);
const designerId2 = getDesignerIdFromDialogPath(
newDialog,
- `content.triggers[${index}].actions[0].elseActions[0].activity`
+ `content.triggers[${index}].actions[0].elseActions[0].activity`,
);
const lgTemplates: LgTemplate[] = [
LgTemplateSamples.TextInputPromptForQnAMatcher(designerId1) as LgTemplate,
@@ -83,7 +83,7 @@ const getNewDialogWithTrigger = async (
const designerId1 = getDesignerIdFromDialogPath(newDialog, `content.triggers[${index}].actions[2].prompt`);
const designerId2 = getDesignerIdFromDialogPath(
newDialog,
- `content.triggers[${index}].actions[3].elseActions[0].activity`
+ `content.triggers[${index}].actions[3].elseActions[0].activity`,
);
const lgTemplates: LgTemplate[] = [
LgTemplateSamples.textInputPromptForOnChooseIntent(designerId1) as LgTemplate,
@@ -108,33 +108,29 @@ const getNewDialogWithTrigger = async (
export const triggerDispatcher = () => {
const createTrigger = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- projectId: string,
- dialogId: string,
- formData: TriggerFormData,
- autoSelected = true
- ) => {
- try {
- const { snapshot } = callbackHelpers;
- const dispatcher = await snapshot.getPromise(dispatcherState);
- const { createLuIntent, createLgTemplates, updateDialog, selectTo } = dispatcher;
- const dialogPayload = await getNewDialogWithTrigger(
- callbackHelpers,
- projectId,
- dialogId,
- formData,
- createLuIntent,
- createLgTemplates
- );
- await updateDialog(dialogPayload);
- if (autoSelected) {
- const index = get(dialogPayload.content, 'triggers', []).length - 1;
- await selectTo(projectId, dialogPayload.id, `triggers[${index}]`);
+ (callbackHelpers: CallbackInterface) =>
+ async (projectId: string, dialogId: string, formData: TriggerFormData, autoSelected = true) => {
+ try {
+ const { snapshot } = callbackHelpers;
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+ const { createLuIntent, createLgTemplates, updateDialog, selectTo } = dispatcher;
+ const dialogPayload = await getNewDialogWithTrigger(
+ callbackHelpers,
+ projectId,
+ dialogId,
+ formData,
+ createLuIntent,
+ createLgTemplates,
+ );
+ await updateDialog(dialogPayload);
+ if (autoSelected) {
+ const index = get(dialogPayload.content, 'triggers', []).length - 1;
+ await selectTo(projectId, dialogPayload.id, `triggers[${index}]`);
+ }
+ } catch (ex) {
+ setError(callbackHelpers, ex);
}
- } catch (ex) {
- setError(callbackHelpers, ex);
- }
- }
+ },
);
const deleteTrigger = useRecoilCallback(
@@ -162,75 +158,66 @@ export const triggerDispatcher = () => {
actions,
(templateNames: string[]) => removeLgTemplates({ id: `${dialogId}.${locale}`, templateNames, projectId }),
(intentNames: string[]) =>
- Promise.all(intentNames.map((intentName) => removeLuIntent({ id: luFile.id, intentName, projectId })))
+ Promise.all(intentNames.map((intentName) => removeLuIntent({ id: luFile.id, intentName, projectId }))),
);
} catch (ex) {
setError(callbackHelpers, ex);
}
- }
+ },
);
const createQnATrigger = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- projectId: string,
- dialogId: string,
- autoSelectTrigger?: boolean
- ) => {
- try {
- const { snapshot } = callbackHelpers;
- const dispatcher = await snapshot.getPromise(dispatcherState);
- const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
-
- const targetDialog = dialogs.find((item) => item.id === dialogId);
- if (!targetDialog) throw new Error(`dialog ${dialogId} not found`);
- const existedQnATrigger = get(targetDialog, 'content.triggers', []).find(
- (item) => item.$kind === SDKKinds.OnQnAMatch
- );
- if (!existedQnATrigger) {
- await dispatcher.createTrigger(projectId, dialogId, defaultQnATriggerData, autoSelectTrigger);
+ (callbackHelpers: CallbackInterface) =>
+ async (projectId: string, dialogId: string, autoSelectTrigger?: boolean) => {
+ try {
+ const { snapshot } = callbackHelpers;
+ const dispatcher = await snapshot.getPromise(dispatcherState);
+ const dialogs = await snapshot.getPromise(dialogsSelectorFamily(projectId));
+
+ const targetDialog = dialogs.find((item) => item.id === dialogId);
+ if (!targetDialog) throw new Error(`dialog ${dialogId} not found`);
+ const existedQnATrigger = get(targetDialog, 'content.triggers', []).find(
+ (item) => item.$kind === SDKKinds.OnQnAMatch,
+ );
+ if (!existedQnATrigger) {
+ await dispatcher.createTrigger(projectId, dialogId, defaultQnATriggerData, autoSelectTrigger);
+ }
+ } catch (ex) {
+ setError(callbackHelpers, ex);
}
- } catch (ex) {
- setError(callbackHelpers, ex);
- }
- }
+ },
);
const createTriggerForRemoteSkill = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (
- projectId: string,
- dialogId: string,
- formData: TriggerFormData,
- skillId: string,
- autoSelected = true
- ) => {
- try {
- const { snapshot } = callbackHelpers;
- const { createLuIntent, createLgTemplates, updateDialog, selectTo } = await snapshot.getPromise(
- dispatcherState
- );
- const dialogPayload = await getNewDialogWithTrigger(
- callbackHelpers,
- projectId,
- dialogId,
- formData,
- createLuIntent,
- createLgTemplates
- );
- const index = get(dialogPayload.content, 'triggers', []).length - 1;
- const skillsByProjectId = await snapshot.getPromise(skillNameIdentifierByProjectIdSelector);
- const skillIdentifier = skillsByProjectId[skillId];
- const actions: any = [];
- actions.push(createActionFromManifest(skillIdentifier));
- dialogPayload.content.triggers[index].actions = actions;
-
- await updateDialog(dialogPayload);
- if (autoSelected) {
- await selectTo(projectId, dialogPayload.id, `triggers[${index}]`);
+ (callbackHelpers: CallbackInterface) =>
+ async (projectId: string, dialogId: string, formData: TriggerFormData, skillId: string, autoSelected = true) => {
+ try {
+ const { snapshot } = callbackHelpers;
+ const { createLuIntent, createLgTemplates, updateDialog, selectTo } =
+ await snapshot.getPromise(dispatcherState);
+ const dialogPayload = await getNewDialogWithTrigger(
+ callbackHelpers,
+ projectId,
+ dialogId,
+ formData,
+ createLuIntent,
+ createLgTemplates,
+ );
+ const index = get(dialogPayload.content, 'triggers', []).length - 1;
+ const skillsByProjectId = await snapshot.getPromise(skillNameIdentifierByProjectIdSelector);
+ const skillIdentifier = skillsByProjectId[skillId];
+ const actions: any = [];
+ actions.push(createActionFromManifest(skillIdentifier));
+ dialogPayload.content.triggers[index].actions = actions;
+
+ await updateDialog(dialogPayload);
+ if (autoSelected) {
+ await selectTo(projectId, dialogPayload.id, `triggers[${index}]`);
+ }
+ } catch (ex) {
+ setError(callbackHelpers, ex);
}
- } catch (ex) {
- setError(callbackHelpers, ex);
- }
- }
+ },
);
return {
createTrigger,
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/user.ts b/Composer/packages/client/src/recoilModel/dispatchers/user.ts
index 4a64b0b36f..e57b9395ee 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/user.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/user.ts
@@ -16,39 +16,40 @@ import { logMessage } from './shared';
export const userDispatcher = () => {
const updateUserSettings = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => async (settings: Partial = {}) => {
- const { set } = callbackHelpers;
- if (settings.appLocale != null) {
- await loadLocale(settings.appLocale);
- }
- set(userSettingsState, (currentSettings) => {
- const newSettings = {
- ...currentSettings,
- };
- for (const key in settings) {
- if (newSettings[key] != null) {
- if (typeof newSettings[key] === 'object') {
- newSettings[key] = { ...newSettings[key], ...settings[key] };
- } else {
- newSettings[key] = settings[key];
+ (callbackHelpers: CallbackInterface) =>
+ async (settings: Partial = {}) => {
+ const { set } = callbackHelpers;
+ if (settings.appLocale != null) {
+ await loadLocale(settings.appLocale);
+ }
+ set(userSettingsState, (currentSettings) => {
+ const newSettings = {
+ ...currentSettings,
+ };
+ for (const key in settings) {
+ if (newSettings[key] != null) {
+ if (typeof newSettings[key] === 'object') {
+ newSettings[key] = { ...newSettings[key], ...settings[key] };
+ } else {
+ newSettings[key] = settings[key];
+ }
}
}
- }
- storage.set('userSettings', newSettings);
+ storage.set('userSettings', newSettings);
- // push telemetry settings to the server
- httpClient.post('/settings', { settings: pick(newSettings, ['telemetry']) }).catch((error) => {
- logMessage(callbackHelpers, `Error updating server settings: ${error}`);
- });
+ // push telemetry settings to the server
+ httpClient.post('/settings', { settings: pick(newSettings, ['telemetry']) }).catch((error) => {
+ logMessage(callbackHelpers, `Error updating server settings: ${error}`);
+ });
- if (isElectron()) {
- // push the settings to the electron main process
- window.ipcRenderer.send('update-user-settings', newSettings);
- }
+ if (isElectron()) {
+ // push the settings to the electron main process
+ window.ipcRenderer.send('update-user-settings', newSettings);
+ }
- return newSettings;
- });
- }
+ return newSettings;
+ });
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/utils/project.ts b/Composer/packages/client/src/recoilModel/dispatchers/utils/project.ts
index 83ffd46412..af8fddbc5d 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/utils/project.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/utils/project.ts
@@ -103,7 +103,7 @@ import { getPublishProfileFromPayload } from '../../../utils/electronUtil';
import { crossTrainConfigState, projectIndexingState } from './../../atoms/botState';
import { recognizersSelectorFamily } from './../../selectors/recognizers';
-export const resetBotStates = async ({ reset }: CallbackInterface, projectId: string) => {
+export const resetBotStates = ({ reset }: CallbackInterface, projectId: string) => {
const botStates = Object.keys(botstates);
botStates.forEach((state) => {
const currentRecoilAtom: any = botstates[state];
@@ -118,7 +118,7 @@ export const setErrorOnBotProject = async (
callbackHelpers: CallbackInterface,
projectId: string,
botName: string,
- payload: any
+ payload: any,
) => {
const { set } = callbackHelpers;
if (payload?.response?.data?.message) {
@@ -137,13 +137,15 @@ export const flushExistingTasks = async (callbackHelpers: CallbackInterface) =>
reset(botProjectSpaceLoadedState);
reset(botProjectIdsState);
- for (const projectId of projectIds) {
- botRuntimeOperations?.stopBot(projectId);
+ const result = projectIds.map(async (projectId) => {
+ await botRuntimeOperations?.stopBot(projectId);
resetBotStates(callbackHelpers, projectId);
- }
+ });
- const workers = [lgWorker, luWorker, qnaWorker];
- return Promise.all([workers.map((w) => w.flush())]);
+ const workers = [lgWorker, luWorker, qnaWorker].map(async (worker) => {
+ await worker.flush();
+ });
+ await Promise.all([...result, ...workers]);
};
// merge sensitive values in localStorage
@@ -214,7 +216,7 @@ export const navigateToBot = (
callbackHelpers: CallbackInterface,
projectId: string,
mainDialog?: string,
- urlSuffix?: string
+ urlSuffix?: string,
) => {
if (projectId) {
const { set } = callbackHelpers;
@@ -293,7 +295,7 @@ const parseAllAssets = async ({ set }: CallbackInterface, projectId: string, bot
const luFeaturesMap: { [key: string]: ILUFeaturesConfig } = {};
for (const { id } of luFiles) {
const isOrchestartor = recognizers.some(
- (f) => f.id === `${id}.lu.dialog` && f.content.$kind === SDKKinds.OrchestratorRecognizer
+ (f) => f.id === `${id}.lu.dialog` && f.content.$kind === SDKKinds.OrchestratorRecognizer,
);
const luFeatures = { ...mergedSettings.luFeatures, isOrchestartor };
luFeaturesMap[id] = luFeatures;
@@ -367,7 +369,7 @@ export const loadProjectData = async (data) => {
export const fetchProjectDataByPath = async (
path: string,
storageId,
- isRootBot: boolean
+ isRootBot: boolean,
): Promise<{ botFiles: any; projectData: any; error: any }> => {
try {
const response = await httpClient.put(`/projects/open`, { path, storageId, isRootBot });
@@ -444,7 +446,7 @@ export const updateLuFilesStatus = (projectId: string, luFiles: LuFile[]) => {
export const initLuFilesStatus = (projectId: string, luFiles: LuFile[], dialogs: DialogInfo[]) => {
luFileStatusStorage.checkFileStatus(
projectId,
- getReferredLuFiles(luFiles, dialogs).map((file) => file.id)
+ getReferredLuFiles(luFiles, dialogs).map((file) => file.id),
);
return updateLuFilesStatus(projectId, luFiles);
};
@@ -463,7 +465,7 @@ export const updateQnaFilesStatus = (projectId: string, qnaFiles: QnAFile[]) =>
export const initQnaFilesStatus = (projectId: string, qnaFiles: QnAFile[], dialogs: DialogInfo[]) => {
qnaFileStatusStorage.checkFileStatus(
projectId,
- getReferredQnaFiles(qnaFiles, dialogs).map((file) => file.id)
+ getReferredQnaFiles(qnaFiles, dialogs).map((file) => file.id),
);
return updateQnaFilesStatus(projectId, qnaFiles);
};
@@ -527,7 +529,7 @@ export const initBotState = async (callbackHelpers: CallbackInterface, data: any
// Form dialogs
set(
formDialogSchemaIdsState(projectId),
- formDialogSchemas.map((f) => f.id)
+ formDialogSchemas.map((f) => f.id),
);
formDialogSchemas.forEach(({ id, content }) => {
set(formDialogSchemaState({ projectId, schemaId: id }), { id, content });
@@ -575,7 +577,7 @@ export const removeRecentProject = async (callbackHelpers: CallbackInterface, pa
export const openRemoteSkill = async (
callbackHelpers: CallbackInterface,
- { manifestUrl, manifestFromZip = { name: '', content: {} }, rootBotProjectId = '', botNameIdentifier = '' }
+ { manifestUrl, manifestFromZip = { name: '', content: {} }, rootBotProjectId = '', botNameIdentifier = '' },
) => {
const { set } = callbackHelpers;
@@ -594,7 +596,7 @@ export const openRemoteSkill = async (
manifestResponseData = (
await httpClient.get(
- `/projects/${rootBotProjectId}/skill/retrieveSkillManifest?${stringified}&ignoreProjectValidation=true`
+ `/projects/${rootBotProjectId}/skill/retrieveSkillManifest?${stringified}&ignoreProjectValidation=true`,
)
).data;
}
@@ -651,7 +653,7 @@ export const migrateToV2 = async (
description: string,
location: string,
runtimeLanguage: string,
- runtimeType: string
+ runtimeType: string,
) => {
const jobId = await httpClient.post(`projects/migrate`, {
storageId: 'default',
@@ -715,7 +717,7 @@ export const openRootBotAndSkills = async (callbackHelpers: CallbackInterface, d
if (mergedSettings.skill) {
const { botProjectFile, skillSettings } = migrateSkillsForExistingBots(
currentBotProjectFileIndexed.content,
- mergedSettings.skill
+ mergedSettings.skill,
);
if (!isEmpty(skillSettings)) {
setRootBotSettingState(callbackHelpers, rootBotProjectId, {
@@ -797,7 +799,7 @@ export const postRootBotCreation = async (
templateId,
profile,
source,
- projectIdCache
+ projectIdCache,
) => {
if (settingStorage.get(projectId)) {
settingStorage.remove(projectId);
@@ -863,7 +865,7 @@ export const saveProject = async (callbackHelpers, oldProjectData) => {
export const getSkillNameIdentifier = async (
callbackHelpers: CallbackInterface,
- displayName: string
+ displayName: string,
): Promise => {
const { snapshot } = callbackHelpers;
const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
@@ -877,7 +879,7 @@ export const getSkillNameIdentifier = async (
export const checkIfBotExistsInBotProjectFile = async (
callbackHelpers: CallbackInterface,
pathOrManifest: string,
- remote?: boolean
+ remote?: boolean,
) => {
const { snapshot } = callbackHelpers;
const rootBotProjectId = await snapshot.getPromise(rootBotProjectIdSelector);
@@ -910,7 +912,12 @@ export const checkIfBotExistsInBotProjectFile = async (
};
export const getMemoryVariables = async (projectId: string, options?: { signal: AbortSignal }) => {
- const res = await fetch(`${BASEURL}/projects/${projectId}/variables`, { signal: options?.signal });
+ // eslint-disable-next-line no-underscore-dangle
+ const fetchHeaders = { 'X-CSRF-Token': window.__csrf__ };
+ const res = await fetch(`${BASEURL}/projects/${projectId}/variables`, {
+ headers: fetchHeaders,
+ signal: options?.signal,
+ });
const json = (await res.json()) as { variables: string[] };
return json.variables ?? [];
};
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/utils/skills.ts b/Composer/packages/client/src/recoilModel/dispatchers/utils/skills.ts
index 34f86b3560..8b793e1557 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/utils/skills.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/utils/skills.ts
@@ -9,7 +9,7 @@ export const addSkillFiles = async (
projectId: string,
skillName: string,
url: string,
- zipContent: Record
+ zipContent: Record,
): Promise<{ manifest: FileInfo | undefined; error?: any }> => {
try {
const response = await httpClient.post(`/projects/${projectId}/skillFiles`, { url, skillName, zipContent });
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/webchat.ts b/Composer/packages/client/src/recoilModel/dispatchers/webchat.ts
index f62cab07fc..ed97fb40bb 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/webchat.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/webchat.ts
@@ -26,33 +26,31 @@ export const webChatLogDispatcher = () => {
});
const appendWebChatTraffic = useRecoilCallback(
- (callbackHelpers: CallbackInterface) => (
- projectId: string,
- traffic: ConversationTrafficItem | ConversationTrafficItem[]
- ) => {
- const { set } = callbackHelpers;
- set(webChatTrafficState(projectId), (currentTraffic) => {
- if (Array.isArray(traffic)) {
- return [...currentTraffic, ...traffic].sort((t1, t2) => t1.timestamp - t2.timestamp);
- } else {
- return [...currentTraffic, traffic].sort((t1, t2) => t1.timestamp - t2.timestamp);
- }
- });
- }
+ (callbackHelpers: CallbackInterface) =>
+ (projectId: string, traffic: ConversationTrafficItem | ConversationTrafficItem[]) => {
+ const { set } = callbackHelpers;
+ set(webChatTrafficState(projectId), (currentTraffic) => {
+ if (Array.isArray(traffic)) {
+ return [...currentTraffic, ...traffic].sort((t1, t2) => t1.timestamp - t2.timestamp);
+ } else {
+ return [...currentTraffic, traffic].sort((t1, t2) => t1.timestamp - t2.timestamp);
+ }
+ });
+ },
);
const setWebChatInspectionData = useRecoilCallback(
(callbackHelpers: CallbackInterface) => (projectId: string, inspectionData: WebChatInspectionData) => {
const { set } = callbackHelpers;
set(webChatInspectionDataState(projectId), inspectionData);
- }
+ },
);
const setWatchedVariables = useRecoilCallback(
(callbackHelpers: CallbackInterface) => (projectId: string, variables: Record) => {
const { set } = callbackHelpers;
set(watchedVariablesState(projectId), variables);
- }
+ },
);
return {
diff --git a/Composer/packages/client/src/recoilModel/parsers/__test__/lgWorker.test.ts b/Composer/packages/client/src/recoilModel/parsers/__test__/lgWorker.test.ts
index 4b08dca445..505705e629 100644
--- a/Composer/packages/client/src/recoilModel/parsers/__test__/lgWorker.test.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/__test__/lgWorker.test.ts
@@ -10,6 +10,7 @@ jest.mock('./../workers/lgParser.worker.ts', () => {
onmessage = (data) => data;
postMessage = (data) => {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
const payload = require('../workers/lgParser.worker').handleMessage(data);
this.onmessage({ data: { id: data.id, payload } });
};
@@ -18,6 +19,7 @@ jest.mock('./../workers/lgParser.worker.ts', () => {
return Test;
});
+// eslint-disable-next-line @typescript-eslint/no-var-requires
const lgCache = require('../workers/lgParser.worker').cache;
const lgFiles = [
@@ -32,7 +34,7 @@ const getLgTemplate = (name, body): LgTemplate =>
({
name,
body,
- } as LgTemplate);
+ }) as LgTemplate;
describe('test lg worker', () => {
it('cache the new project', async () => {
@@ -65,7 +67,7 @@ describe('test lg worker', () => {
'test',
lgFiles[0],
[getLgTemplate('Test1', '-add1'), getLgTemplate('Test2', '-add2')],
- lgFiles
+ lgFiles,
);
const expected = {
body: '-add2',
@@ -84,7 +86,7 @@ describe('test lg worker', () => {
lgFiles[0],
'Test2',
getLgTemplate('Test2', '-update'),
- lgFiles
+ lgFiles,
);
const expected = {
body: '-update',
diff --git a/Composer/packages/client/src/recoilModel/parsers/__test__/luWorker.test.ts b/Composer/packages/client/src/recoilModel/parsers/__test__/luWorker.test.ts
index ad94307424..6738fb7d35 100644
--- a/Composer/packages/client/src/recoilModel/parsers/__test__/luWorker.test.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/__test__/luWorker.test.ts
@@ -12,6 +12,7 @@ jest.mock('./../workers/luParser.worker.ts', () => {
onmessage = (data) => data;
postMessage = (data) => {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
const payload = require('../workers/luParser.worker').handleMessage(data);
this.onmessage({ data: { id: data.id, payload } });
};
@@ -24,7 +25,7 @@ const getLuIntent = (Name, Body): LuIntentSection =>
({
Name,
Body,
- } as LuIntentSection);
+ }) as LuIntentSection;
let luFile;
describe('test lu worker', () => {
@@ -74,7 +75,7 @@ hi
luFile,
[getLuIntent('New1', '-IntentValue1'), getLuIntent('New2', '-IntentValue2')],
luFeatures,
- []
+ [],
);
const expected = {
Body: '-IntentValue2',
diff --git a/Composer/packages/client/src/recoilModel/parsers/__test__/qnaWorker.test.ts b/Composer/packages/client/src/recoilModel/parsers/__test__/qnaWorker.test.ts
index 0e699905e7..89a326532e 100644
--- a/Composer/packages/client/src/recoilModel/parsers/__test__/qnaWorker.test.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/__test__/qnaWorker.test.ts
@@ -8,6 +8,7 @@ jest.mock('./../workers/qnaParser.worker.ts', () => {
onmessage = (data) => data;
postMessage = (data) => {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
const payload = require('../workers/qnaParser.worker').handleMessage(data);
this.onmessage({ data: { id: data.id, payload } });
};
diff --git a/Composer/packages/client/src/recoilModel/parsers/fileDiffCalculator.ts b/Composer/packages/client/src/recoilModel/parsers/fileDiffCalculator.ts
index e778cfbc7a..6b0a170021 100644
--- a/Composer/packages/client/src/recoilModel/parsers/fileDiffCalculator.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/fileDiffCalculator.ts
@@ -3,6 +3,7 @@
import { FileAsset } from '../persistence/types';
+// @ts-expect-error used for creating worker (adjusted by Webpack)
import Worker from './workers/calculator.worker.ts';
import { BaseWorker } from './baseWorker';
import { FilesDifferencePayload, CalculatorType } from './types';
diff --git a/Composer/packages/client/src/recoilModel/parsers/lgDiagnosticWorker.ts b/Composer/packages/client/src/recoilModel/parsers/lgDiagnosticWorker.ts
index ad50daf7a9..7c8add15b3 100644
--- a/Composer/packages/client/src/recoilModel/parsers/lgDiagnosticWorker.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/lgDiagnosticWorker.ts
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
import { LgFile } from '@bfc/shared';
+// @ts-expect-error used for creating worker (adjusted by Webpack)
import Worker from './workers/lgParserDiagnostic.worker.ts';
import { BaseWorker } from './baseWorker';
import { LgActionType, LgParsePayload } from './types';
diff --git a/Composer/packages/client/src/recoilModel/parsers/lgWorker.ts b/Composer/packages/client/src/recoilModel/parsers/lgWorker.ts
index 83a246df1a..e27d5dc949 100644
--- a/Composer/packages/client/src/recoilModel/parsers/lgWorker.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/lgWorker.ts
@@ -2,10 +2,12 @@
// Licensed under the MIT License.
import { LgFile, LgTemplate, TextFile } from '@bfc/shared';
+// @ts-expect-error used for creating worker (adjusted by Webpack)
import Worker from './workers/lgParser.worker.ts';
import { BaseWorker } from './baseWorker';
import {
LgActionType,
+ LgEventType,
LgParsePayload,
LgUpdateTemplatePayload,
LgCreateTemplatePayload,
@@ -20,6 +22,39 @@ import {
// Wrapper class
class LgWorker extends BaseWorker {
+ private listeners = new Map void)[]>();
+
+ constructor(worker: Worker) {
+ super(worker);
+
+ worker.onmessage = (msg) => {
+ const { type } = msg.data;
+
+ if (type === LgEventType.OnUpdateLgFile) {
+ this.listeners.get(type)?.forEach((cb) => cb(msg));
+ } else {
+ this.handleMsg(msg);
+ }
+ };
+ }
+
+ listen(action: LgEventType, callback: (msg: MessageEvent) => void) {
+ if (this.listeners.has(action)) {
+ this.listeners.get(action)!.push(callback);
+ } else {
+ this.listeners.set(action, [callback]);
+ }
+
+ return {
+ destroy: () => this.listeners.delete(action),
+ };
+ }
+
+ flush(): Promise {
+ this.listeners.clear();
+ return super.flush();
+ }
+
addProject(projectId: string) {
return this.sendMsg(LgActionType.NewCache, { projectId });
}
@@ -49,7 +84,7 @@ class LgWorker extends BaseWorker {
lgFile: LgFile,
templateName: string,
template: { name?: string; parameters?: string[]; body?: string },
- lgFiles: LgFile[]
+ lgFiles: LgFile[],
) {
return this.sendMsg(LgActionType.UpdateTemplate, {
lgFile,
diff --git a/Composer/packages/client/src/recoilModel/parsers/luWorker.ts b/Composer/packages/client/src/recoilModel/parsers/luWorker.ts
index 0a6143fc59..5de43953fe 100644
--- a/Composer/packages/client/src/recoilModel/parsers/luWorker.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/luWorker.ts
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
import { LuIntentSection, LuFile, TextFile, ILUFeaturesConfig } from '@bfc/shared';
+// @ts-expect-error used for creating worker (adjusted by Webpack)
import Worker from './workers/luParser.worker.ts';
import { BaseWorker } from './baseWorker';
import {
@@ -36,7 +37,7 @@ class LuWorker extends BaseWorker {
intentName: string,
intent: { Name?: string; Body?: string },
luFeatures,
- luFiles: LuFile[]
+ luFiles: LuFile[],
) {
const payload = { luFile, intentName, intent, luFeatures, luFiles };
return this.sendMsg(LuActionType.UpdateIntent, payload);
diff --git a/Composer/packages/client/src/recoilModel/parsers/qnaWorker.ts b/Composer/packages/client/src/recoilModel/parsers/qnaWorker.ts
index 134b1b05de..44c6a6c760 100644
--- a/Composer/packages/client/src/recoilModel/parsers/qnaWorker.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/qnaWorker.ts
@@ -3,6 +3,7 @@
import { TextFile } from '@bfc/shared';
+// @ts-expect-error used for creating worker (adjusted by Webpack)
import Worker from './workers/qnaParser.worker.ts';
import { BaseWorker } from './baseWorker';
import { QnAActionType, QnAParseAllPayload, QnAParsePayload } from './types';
diff --git a/Composer/packages/client/src/recoilModel/parsers/types.ts b/Composer/packages/client/src/recoilModel/parsers/types.ts
index 488d9b89e5..1e2e1b243b 100644
--- a/Composer/packages/client/src/recoilModel/parsers/types.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/types.ts
@@ -156,6 +156,10 @@ export enum LgActionType {
ParseAll = 'parse-all',
}
+export enum LgEventType {
+ OnUpdateLgFile = 'on-update-lgfile',
+}
+
export enum IndexerActionType {
Index = 'index',
}
diff --git a/Composer/packages/client/src/recoilModel/parsers/workers/calculator.worker.ts b/Composer/packages/client/src/recoilModel/parsers/workers/calculator.worker.ts
index b724a07bda..e7d998b6ef 100644
--- a/Composer/packages/client/src/recoilModel/parsers/workers/calculator.worker.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/workers/calculator.worker.ts
@@ -40,7 +40,7 @@ export function getDifferenceItems(target: FileAsset[], origin: FileAsset[]) {
return result;
},
- { updated: [], added: [] }
+ { updated: [], added: [] },
);
return { updated, added, deleted };
diff --git a/Composer/packages/client/src/recoilModel/parsers/workers/lgParser.worker.ts b/Composer/packages/client/src/recoilModel/parsers/workers/lgParser.worker.ts
index 9003ec80dd..f313c5939c 100644
--- a/Composer/packages/client/src/recoilModel/parsers/workers/lgParser.worker.ts
+++ b/Composer/packages/client/src/recoilModel/parsers/workers/lgParser.worker.ts
@@ -5,6 +5,7 @@ import { lgImportResolverGenerator, LgFile } from '@bfc/shared';
import {
LgActionType,
+ LgEventType,
LgParsePayload,
LgUpdateTemplatePayload,
LgCreateTemplatePayload,
@@ -16,6 +17,7 @@ import {
LgCleanCachePayload,
LgParseAllPayload,
} from '../types';
+import { MapOptimizer } from '../../utils/mapOptimizer';
const ctx: Worker = self as any;
@@ -153,13 +155,32 @@ const filterParseResult = (lgFile: LgFile) => {
return cloned;
};
-const getTargetFile = (projectId: string, lgFile: LgFile) => {
+const getTargetFile = (projectId: string, lgFile: LgFile, lgFiles: LgFile[]) => {
const cachedFile = cache.get(projectId, lgFile.id);
+ if (cachedFile?.isContentUnparsed) {
+ const lgFile = lgUtil.parse(cachedFile.id, cachedFile.content, lgFiles);
+ lgFile.isContentUnparsed = false;
+ cache.set(projectId, lgFile);
+ return filterParseResult(lgFile);
+ }
+
// Instead of compare content, just use cachedFile as single truth of fact, because all updates are supposed to be happen in worker, and worker will always update cache.
return cachedFile ?? lgFile;
};
+const emptyLgFile = (id: string, content: string): LgFile => {
+ return {
+ id,
+ content,
+ diagnostics: [],
+ templates: [],
+ allTemplates: [],
+ imports: [],
+ isContentUnparsed: true,
+ };
+};
+
export const handleMessage = (msg: LgMessageEvent) => {
let payload: any = null;
switch (msg.type) {
@@ -178,6 +199,11 @@ export const handleMessage = (msg: LgMessageEvent) => {
case LgActionType.Parse: {
const { id, content, lgFiles, projectId } = msg.payload;
+ const cachedFile = cache.get(projectId, id);
+ if (cachedFile?.isContentUnparsed === false && cachedFile?.content === content) {
+ return filterParseResult(cachedFile);
+ }
+
const lgFile = lgUtil.parse(id, content, lgFiles);
cache.set(projectId, lgFile);
payload = filterParseResult(lgFile);
@@ -186,19 +212,27 @@ export const handleMessage = (msg: LgMessageEvent) => {
case LgActionType.ParseAll: {
const { lgResources, projectId } = msg.payload;
-
- payload = lgResources.map(({ id, content }) => {
- const lgFile = lgUtil.parse(id, content, lgResources);
+ // We'll do the parsing when the file is required. Save empty LG instead.
+ payload = lgResources.map(({ id, content }) => [id, emptyLgFile(id, content)]);
+ const resources = new Map(payload);
+ cache.projects.set(projectId, resources);
+
+ const optimizer = new MapOptimizer(10, resources);
+ optimizer.onUpdate((_, value, ctx) => {
+ const refs = value.parseResult?.references?.map(({ name }) => name);
+ ctx.setReferences(refs);
+ });
+ optimizer.onDelete((_, value) => {
+ const lgFile = emptyLgFile(value.id, value.content);
cache.set(projectId, lgFile);
- return filterParseResult(lgFile);
+ ctx.postMessage({ type: LgEventType.OnUpdateLgFile, projectId, payload: lgFile });
});
-
break;
}
case LgActionType.AddTemplate: {
const { lgFile, template, lgFiles, projectId } = msg.payload;
- const result = lgUtil.addTemplate(getTargetFile(projectId, lgFile), template, lgFileResolver(lgFiles));
+ const result = lgUtil.addTemplate(getTargetFile(projectId, lgFile, lgFiles), template, lgFileResolver(lgFiles));
cache.set(projectId, result);
payload = filterParseResult(result);
break;
@@ -206,7 +240,7 @@ export const handleMessage = (msg: LgMessageEvent) => {
case LgActionType.AddTemplates: {
const { lgFile, templates, lgFiles, projectId } = msg.payload;
- const result = lgUtil.addTemplates(getTargetFile(projectId, lgFile), templates, lgFileResolver(lgFiles));
+ const result = lgUtil.addTemplates(getTargetFile(projectId, lgFile, lgFiles), templates, lgFileResolver(lgFiles));
cache.set(projectId, result);
payload = filterParseResult(result);
break;
@@ -215,10 +249,10 @@ export const handleMessage = (msg: LgMessageEvent) => {
case LgActionType.UpdateTemplate: {
const { lgFile, templateName, template, lgFiles, projectId } = msg.payload;
const result = lgUtil.updateTemplate(
- getTargetFile(projectId, lgFile),
+ getTargetFile(projectId, lgFile, lgFiles),
templateName,
template,
- lgFileResolver(lgFiles)
+ lgFileResolver(lgFiles),
);
cache.set(projectId, result);
payload = filterParseResult(result);
@@ -227,7 +261,11 @@ export const handleMessage = (msg: LgMessageEvent) => {
case LgActionType.RemoveTemplate: {
const { lgFile, templateName, lgFiles, projectId } = msg.payload;
- const result = lgUtil.removeTemplate(getTargetFile(projectId, lgFile), templateName, lgFileResolver(lgFiles));
+ const result = lgUtil.removeTemplate(
+ getTargetFile(projectId, lgFile, lgFiles),
+ templateName,
+ lgFileResolver(lgFiles),
+ );
cache.set(projectId, result);
payload = filterParseResult(result);
break;
@@ -235,7 +273,11 @@ export const handleMessage = (msg: LgMessageEvent) => {
case LgActionType.RemoveAllTemplates: {
const { lgFile, templateNames, lgFiles, projectId } = msg.payload;
- const result = lgUtil.removeTemplates(getTargetFile(projectId, lgFile), templateNames, lgFileResolver(lgFiles));
+ const result = lgUtil.removeTemplates(
+ getTargetFile(projectId, lgFile, lgFiles),
+ templateNames,
+ lgFileResolver(lgFiles),
+ );
cache.set(projectId, result);
payload = filterParseResult(result);
break;
@@ -244,10 +286,10 @@ export const handleMessage = (msg: LgMessageEvent) => {
case LgActionType.CopyTemplate: {
const { lgFile, toTemplateName, fromTemplateName, lgFiles, projectId } = msg.payload;
const result = lgUtil.copyTemplate(
- getTargetFile(projectId, lgFile),
+ getTargetFile(projectId, lgFile, lgFiles),
fromTemplateName,
toTemplateName,
- lgFileResolver(lgFiles)
+ lgFileResolver(lgFiles),
);
cache.set(projectId, result);
payload = filterParseResult(result);
diff --git a/Composer/packages/client/src/recoilModel/persistence/FilePersistence.ts b/Composer/packages/client/src/recoilModel/persistence/FilePersistence.ts
index b4a49209a2..35c862bab3 100644
--- a/Composer/packages/client/src/recoilModel/persistence/FilePersistence.ts
+++ b/Composer/packages/client/src/recoilModel/persistence/FilePersistence.ts
@@ -196,19 +196,19 @@ class FilePersistence {
const changes = await Promise.all(
files.map(async (item) => {
return await this.getFilesChanges(item[0], item[1], item[2]);
- })
+ }),
);
const settingChanges = this.getSettingsChanges(currentAssets.setting, previousAssets.setting);
const botProjectFileChanges = this.getBotProjectFileChanges(
currentAssets.botProjectFile,
- previousAssets.botProjectFile
+ previousAssets.botProjectFile,
);
const crossTrainFileChanges = this.getCrossTrainConfigChanges(
currentAssets.crossTrainConfig,
- previousAssets.crossTrainConfig
+ previousAssets.crossTrainConfig,
);
const fileChanges: IFileChange[] = [...settingChanges, ...botProjectFileChanges, ...crossTrainFileChanges];
diff --git a/Composer/packages/client/src/recoilModel/persistence/__test__/FilePersistence.test.ts b/Composer/packages/client/src/recoilModel/persistence/__test__/FilePersistence.test.ts
index be9275dd4b..af8f3be576 100644
--- a/Composer/packages/client/src/recoilModel/persistence/__test__/FilePersistence.test.ts
+++ b/Composer/packages/client/src/recoilModel/persistence/__test__/FilePersistence.test.ts
@@ -7,6 +7,7 @@ const projectId = '2123.2234as';
jest.mock('../../parsers/fileDiffCalculator', () => {
return {
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
difference: require('../../parsers/workers/calculator.worker').getDifferenceItems,
};
});
@@ -29,7 +30,7 @@ describe('test persistence layer', () => {
const current = {
projectId: 'test',
- dialogs: ([{ id: 'a', content: { a: 'create' } }] as unknown) as DialogInfo[],
+ dialogs: [{ id: 'a', content: { a: 'create' } }] as unknown as DialogInfo[],
dialogSchemas: [{ id: 'a', content: { a: 'new schema' } }] as DialogSchemaFile[],
lgFiles: [{ id: 'a.en-us', content: 'a.lg' }] as LgFile[],
luFiles: [{ id: 'a.en-us', content: 'a.lu' }] as LuFile[],
@@ -38,7 +39,7 @@ describe('test persistence layer', () => {
const last = {
projectId: 'test',
- dialogs: ([{ id: 'a', content: { a: 'update' } }] as unknown) as DialogInfo[],
+ dialogs: [{ id: 'a', content: { a: 'update' } }] as unknown as DialogInfo[],
dialogSchemas: [{ id: 'a', content: { a: 'new schema' } }] as DialogSchemaFile[],
lgFiles: [{ id: 'a.en-us', content: 'a.lg' }] as LgFile[],
luFiles: [{ id: 'a.en-us', content: 'a.lu' }] as LuFile[],
@@ -61,7 +62,7 @@ describe('test persistence layer', () => {
it('test notify create', async () => {
const previous = {
projectId: 'test',
- dialogs: ([{ id: 'a', content: { a: 'a' } }] as unknown) as DialogInfo[],
+ dialogs: [{ id: 'a', content: { a: 'a' } }] as unknown as DialogInfo[],
dialogSchemas: [{ id: 'a', content: { a: 'a' } }] as DialogSchemaFile[],
lgFiles: [{ id: 'a.en-us', content: 'a' }] as LgFile[],
luFiles: [{ id: 'a.en-us', content: 'a' }] as LuFile[],
@@ -69,10 +70,10 @@ describe('test persistence layer', () => {
const current = {
projectId: 'test',
- dialogs: ([
+ dialogs: [
{ id: 'a', content: { a: 'a' } },
{ id: 'b', content: { b: 'b' } },
- ] as unknown) as DialogInfo[],
+ ] as unknown as DialogInfo[],
dialogSchemas: [
{ id: 'a', content: { a: 'a' } },
{ id: 'b', content: { b: 'b' } },
@@ -100,10 +101,10 @@ describe('test persistence layer', () => {
it('test notify remove', async () => {
const previous = {
projectId: 'test',
- dialogs: ([
+ dialogs: [
{ id: 'a', content: { a: 'a' } },
{ id: 'b', content: { b: 'b.pre' } },
- ] as unknown) as DialogInfo[],
+ ] as unknown as DialogInfo[],
dialogSchemas: [
{ id: 'a', content: { a: 'a' } },
{ id: 'b', content: { b: 'b.pre' } },
@@ -120,7 +121,7 @@ describe('test persistence layer', () => {
const current = {
projectId: 'test',
- dialogs: ([{ id: 'a', content: { a: 'a' } }] as unknown) as DialogInfo[],
+ dialogs: [{ id: 'a', content: { a: 'a' } }] as unknown as DialogInfo[],
dialogSchemas: [{ id: 'a', content: { a: 'a' } }] as DialogSchemaFile[],
lgFiles: [{ id: 'a.en-us', content: 'a' }] as LgFile[],
luFiles: [{ id: 'a.en-us', content: 'a' }] as LuFile[],
diff --git a/Composer/packages/client/src/recoilModel/selectors/__test__/project.test.ts b/Composer/packages/client/src/recoilModel/selectors/__test__/project.test.ts
index 043c528c31..0484d6ea3f 100644
--- a/Composer/packages/client/src/recoilModel/selectors/__test__/project.test.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/__test__/project.test.ts
@@ -20,20 +20,22 @@ const projectIds = ['123-a', '234-bc', '567-de'];
const projectDataSelector = selectorFamily({
key: 'project-data-selector',
get: () => noop,
- set: (projectId: string) => ({ set }, stateUpdater: any) => {
- const { metadata, botError, displayName } = stateUpdater;
- if (metadata) {
- set(projectMetaDataState(projectId), metadata);
- }
+ set:
+ (projectId: string) =>
+ ({ set }, stateUpdater: any) => {
+ const { metadata, botError, displayName } = stateUpdater;
+ if (metadata) {
+ set(projectMetaDataState(projectId), metadata);
+ }
- if (botError) {
- set(botErrorState(projectId), location);
- }
+ if (botError) {
+ set(botErrorState(projectId), location);
+ }
- if (displayName) {
- set(botDisplayNameState(projectId), displayName);
- }
- },
+ if (displayName) {
+ set(botDisplayNameState(projectId), displayName);
+ }
+ },
});
const useRecoilTestHook = () => {
@@ -69,7 +71,7 @@ beforeEach(() => {
useRecoilTestHook,
{
states: [],
- }
+ },
);
renderedComponent = rendered.result;
});
diff --git a/Composer/packages/client/src/recoilModel/selectors/diagnosticsPageSelector.ts b/Composer/packages/client/src/recoilModel/selectors/diagnosticsPageSelector.ts
index 15f319c239..32c278dc96 100644
--- a/Composer/packages/client/src/recoilModel/selectors/diagnosticsPageSelector.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/diagnosticsPageSelector.ts
@@ -43,65 +43,69 @@ import { qnaFilesSelectorFamily } from './qna';
export const botAssetsSelectFamily = selectorFamily({
key: 'botAssetsSelectFamily',
- get: (projectId: string) => ({ get }) => {
- const projectsMetaData = get(projectMetaDataState(projectId));
- if (!projectsMetaData || projectsMetaData.isRemote) return null;
-
- const dialogs = get(dialogsWithLuProviderSelectorFamily(projectId));
- const luFiles = get(luFilesSelectorFamily(projectId));
- const lgFiles = get(lgFilesSelectorFamily(projectId));
- const setting = get(settingsState(projectId));
- const skillManifests = get(skillManifestsState(projectId));
- const dialogSchemas = get(dialogSchemasState(projectId));
- const qnaFiles = get(qnaFilesSelectorFamily(projectId));
- const formDialogSchemas = get(formDialogSchemasSelectorFamily(projectId));
- const botProjectFile = get(botProjectFileState(projectId));
- const jsonSchemaFiles = get(jsonSchemaFilesState(projectId));
- const recognizers = get(recognizersSelectorFamily(projectId));
- const crossTrainConfig = get(crossTrainConfigState(projectId));
- return {
- projectId,
- dialogs,
- luFiles,
- qnaFiles,
- lgFiles,
- skillManifests,
- setting,
- dialogSchemas,
- formDialogSchemas,
- botProjectFile,
- jsonSchemaFiles,
- recognizers,
- crossTrainConfig,
- };
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const projectsMetaData = get(projectMetaDataState(projectId));
+ if (!projectsMetaData || projectsMetaData.isRemote) return null;
+
+ const dialogs = get(dialogsWithLuProviderSelectorFamily(projectId));
+ const luFiles = get(luFilesSelectorFamily(projectId));
+ const lgFiles = get(lgFilesSelectorFamily(projectId));
+ const setting = get(settingsState(projectId));
+ const skillManifests = get(skillManifestsState(projectId));
+ const dialogSchemas = get(dialogSchemasState(projectId));
+ const qnaFiles = get(qnaFilesSelectorFamily(projectId));
+ const formDialogSchemas = get(formDialogSchemasSelectorFamily(projectId));
+ const botProjectFile = get(botProjectFileState(projectId));
+ const jsonSchemaFiles = get(jsonSchemaFilesState(projectId));
+ const recognizers = get(recognizersSelectorFamily(projectId));
+ const crossTrainConfig = get(crossTrainConfigState(projectId));
+ return {
+ projectId,
+ dialogs,
+ luFiles,
+ qnaFiles,
+ lgFiles,
+ skillManifests,
+ setting,
+ dialogSchemas,
+ formDialogSchemas,
+ botProjectFile,
+ jsonSchemaFiles,
+ recognizers,
+ crossTrainConfig,
+ };
+ },
});
export const botDiagnosticsSelectorFamily = selectorFamily({
key: 'botDiagnosticsSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const botAssets = get(botAssetsSelectFamily(projectId));
- if (botAssets === null) return [];
-
- const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
- const diagnostics = get(botDiagnosticsState(projectId));
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const botAssets = get(botAssetsSelectFamily(projectId));
+ if (botAssets === null) return [];
- const diagnosticList: DiagnosticInfo[] = [];
+ const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
+ const diagnostics = get(botDiagnosticsState(projectId));
- diagnostics.forEach((d) => {
- diagnosticList.push(new BotDiagnostic(rootProjectId, projectId, '', d.source, d));
- });
+ const diagnosticList: DiagnosticInfo[] = [];
- //manifest.json
- //Manifest should exist
- if (rootProjectId !== projectId) {
- BotIndexer.checkManifest(botAssets).forEach((d) => {
+ diagnostics.forEach((d) => {
diagnosticList.push(new BotDiagnostic(rootProjectId, projectId, '', d.source, d));
});
- }
- return diagnosticList;
- },
+ //manifest.json
+ //Manifest should exist
+ if (rootProjectId !== projectId) {
+ BotIndexer.checkManifest(botAssets).forEach((d) => {
+ diagnosticList.push(new BotDiagnostic(rootProjectId, projectId, '', d.source, d));
+ });
+ }
+
+ return diagnosticList;
+ },
});
/**
@@ -111,219 +115,239 @@ export const botDiagnosticsSelectorFamily = selectorFamily({
*/
export const skillSettingDiagnosticsSelectorFamily = selectorFamily({
key: 'skillDiagnosticsSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const botAssets = get(botAssetsSelectFamily(projectId));
- if (botAssets === null) return [];
-
- const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
- const diagnosticList: DiagnosticInfo[] = [];
-
- const skillDiagnostics = BotIndexer.checkSkillSetting(botAssets);
- skillDiagnostics.forEach((item) => {
- diagnosticList.push(new SkillSettingDiagnostic(rootProjectId, projectId, item.source, item.source, item));
- });
- return diagnosticList;
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const botAssets = get(botAssetsSelectFamily(projectId));
+ if (botAssets === null) return [];
+
+ const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
+ const diagnosticList: DiagnosticInfo[] = [];
+
+ const skillDiagnostics = BotIndexer.checkSkillSetting(botAssets);
+ skillDiagnostics.forEach((item) => {
+ diagnosticList.push(new SkillSettingDiagnostic(rootProjectId, projectId, item.source, item.source, item));
+ });
+ return diagnosticList;
+ },
});
export const settingDiagnosticsSelectorFamily = selectorFamily({
key: 'settingDiagnosticsSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const botAssets = get(botAssetsSelectFamily(projectId));
- if (botAssets === null) return [];
-
- const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
- const rootSetting = get(settingsState(rootProjectId));
- const diagnosticList: DiagnosticInfo[] = [];
-
- //1. Missing LUIS key
- //2. Missing QnA Maker subscription key.
- //appsettings.json
- const settingDiagnostic = BotIndexer.checkSetting(botAssets, rootSetting);
- settingDiagnostic.forEach((item) => {
- diagnosticList.push(new SettingDiagnostic(rootProjectId, projectId, item.source, item.source, item));
- });
-
- //Check bot settings & dialog
- //files meet LUIS/QnA requirments.
- //appsettings.json
- const luisLocaleDiagnostics = BotIndexer.checkLUISLocales(botAssets);
- const qnaLocaleDiagnostics = BotIndexer.checkQnALocales(botAssets);
-
- luisLocaleDiagnostics.forEach((item) => {
- diagnosticList.push(new SettingDiagnostic(rootProjectId, projectId, item.source, item.source, item));
- });
-
- qnaLocaleDiagnostics.forEach((item) => {
- diagnosticList.push(new SettingDiagnostic(rootProjectId, projectId, item.source, item.source, item));
- });
-
- return diagnosticList;
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const botAssets = get(botAssetsSelectFamily(projectId));
+ if (botAssets === null) return [];
+
+ const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
+ const rootSetting = get(settingsState(rootProjectId));
+ const diagnosticList: DiagnosticInfo[] = [];
+
+ //1. Missing LUIS key
+ //2. Missing QnA Maker subscription key.
+ //appsettings.json
+ const settingDiagnostic = BotIndexer.checkSetting(botAssets, rootSetting);
+ settingDiagnostic.forEach((item) => {
+ diagnosticList.push(new SettingDiagnostic(rootProjectId, projectId, item.source, item.source, item));
+ });
+
+ //Check bot settings & dialog
+ //files meet LUIS/QnA requirments.
+ //appsettings.json
+ const luisLocaleDiagnostics = BotIndexer.checkLUISLocales(botAssets);
+ const qnaLocaleDiagnostics = BotIndexer.checkQnALocales(botAssets);
+
+ luisLocaleDiagnostics.forEach((item) => {
+ diagnosticList.push(new SettingDiagnostic(rootProjectId, projectId, item.source, item.source, item));
+ });
+
+ qnaLocaleDiagnostics.forEach((item) => {
+ diagnosticList.push(new SettingDiagnostic(rootProjectId, projectId, item.source, item.source, item));
+ });
+
+ return diagnosticList;
+ },
});
export const dialogsDiagnosticsSelectorFamily = selectorFamily({
key: 'dialogsDiagnosticsSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const botAssets = get(botAssetsSelectFamily(projectId));
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const botAssets = get(botAssetsSelectFamily(projectId));
- if (botAssets === null) return [];
- const { dialogs } = botAssets;
+ if (botAssets === null) return [];
+ const { dialogs } = botAssets;
- const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
- const dialogIds = get(dialogIdsState(projectId));
+ const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
+ const dialogIds = get(dialogIdsState(projectId));
- const diagnosticList: DiagnosticInfo[] = [];
+ const diagnosticList: DiagnosticInfo[] = [];
- dialogIds.forEach((dialogId: string) => {
- const diagnostics = get(dialogDiagnosticsSelectorFamily({ projectId, dialogId })) || [];
- diagnostics.forEach((diagnostic) => {
- const location = `${dialogId}.dialog`;
- diagnosticList.push(new DialogDiagnostic(rootProjectId, projectId, dialogId, location, diagnostic, dialogs));
+ dialogIds.forEach((dialogId: string) => {
+ const diagnostics = get(dialogDiagnosticsSelectorFamily({ projectId, dialogId })) || [];
+ diagnostics.forEach((diagnostic) => {
+ const location = `${dialogId}.dialog`;
+ diagnosticList.push(new DialogDiagnostic(rootProjectId, projectId, dialogId, location, diagnostic, dialogs));
+ });
});
- });
- return diagnosticList;
- },
+ return diagnosticList;
+ },
});
export const schemaDiagnosticsSelectorFamily = selectorFamily({
key: 'schemaDiagnosticsSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const botAssets = get(botAssetsSelectFamily(projectId));
- if (botAssets === null) return [];
- const { dialogs } = botAssets;
-
- const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
-
- /**
- * `botAssets.dialogSchema` contains all *.schema files loaded by project indexer. However, it actually messes up sdk.schema and *.dialog.schema.
- * To get the correct sdk.schema content, current workaround is to filter schema by id.
- *
- * TODO: To fix it entirely, we need to differentiate dialog.schema from sdk.schema in indexer.
- */
- const sdkSchemaContent = botAssets.dialogSchemas.find((d) => d.id === '')?.content;
- if (!sdkSchemaContent) return [];
-
- const fullDiagnostics: DiagnosticInfo[] = [];
- botAssets.dialogs.forEach((dialog) => {
- const diagnostics = validateSchema(dialog.id, dialog.content, sdkSchemaContent);
- fullDiagnostics.push(
- ...diagnostics.map((d) => {
- let location = dialog.id;
- if (d.path) {
- const list = d.path.split('.');
- let path = '';
- location = [
- location,
- ...list.map((item) => {
- path = `${path}${path ? '.' : ''}${item}`;
- return getFriendlyName(lodashGet(dialog.content, path)) || '';
- }),
- ].join('>');
- }
- return new SchemaDiagnostic(rootProjectId, projectId, dialog.id, location, d, dialogs);
- })
- );
- });
- return fullDiagnostics;
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const botAssets = get(botAssetsSelectFamily(projectId));
+ if (botAssets === null) return [];
+ const { dialogs } = botAssets;
+
+ const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
+
+ /**
+ * `botAssets.dialogSchema` contains all *.schema files loaded by project indexer. However, it actually messes up sdk.schema and *.dialog.schema.
+ * To get the correct sdk.schema content, current workaround is to filter schema by id.
+ *
+ * TODO: To fix it entirely, we need to differentiate dialog.schema from sdk.schema in indexer.
+ */
+ const sdkSchemaContent = botAssets.dialogSchemas.find((d) => d.id === '')?.content;
+ if (!sdkSchemaContent) return [];
+
+ const fullDiagnostics: DiagnosticInfo[] = [];
+ botAssets.dialogs.forEach((dialog) => {
+ const diagnostics = validateSchema(dialog.id, dialog.content, sdkSchemaContent);
+ fullDiagnostics.push(
+ ...diagnostics.map((d) => {
+ let location = dialog.id;
+ if (d.path) {
+ const list = d.path.split('.');
+ let path = '';
+ location = [
+ location,
+ ...list.map((item) => {
+ path = `${path}${path ? '.' : ''}${item}`;
+ return getFriendlyName(lodashGet(dialog.content, path)) || '';
+ }),
+ ].join('>');
+ }
+ return new SchemaDiagnostic(rootProjectId, projectId, dialog.id, location, d, dialogs);
+ }),
+ );
+ });
+ return fullDiagnostics;
+ },
});
export const luDiagnosticsSelectorFamily = selectorFamily({
key: 'luDiagnosticsSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const botAssets = get(botAssetsSelectFamily(projectId));
-
- if (botAssets === null) return [];
-
- const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
- const diagnosticList: DiagnosticInfo[] = [];
- const { luFiles, dialogs } = botAssets;
-
- getReferredLuFiles(luFiles, dialogs).forEach((lufile) => {
- lufile.diagnostics.forEach((diagnostic) => {
- const location = `${lufile.id}.lu`;
- diagnosticList.push(
- new LuDiagnostic(rootProjectId, projectId, lufile.id, location, diagnostic, lufile, dialogs)
- );
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const botAssets = get(botAssetsSelectFamily(projectId));
+
+ if (botAssets === null) return [];
+
+ const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
+ const diagnosticList: DiagnosticInfo[] = [];
+ const { luFiles, dialogs } = botAssets;
+
+ getReferredLuFiles(luFiles, dialogs).forEach((lufile) => {
+ lufile.diagnostics.forEach((diagnostic) => {
+ const location = `${lufile.id}.lu`;
+ diagnosticList.push(
+ new LuDiagnostic(rootProjectId, projectId, lufile.id, location, diagnostic, lufile, dialogs),
+ );
+ });
});
- });
- return diagnosticList;
- },
+ return diagnosticList;
+ },
});
export const lgDiagnosticsSelectorFamily = selectorFamily({
key: 'lgDiagnosticsSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const botAssets = get(botAssetsSelectFamily(projectId));
- if (botAssets === null) return [];
-
- const { lgFiles, dialogs } = botAssets;
- const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
- const diagnosticList: DiagnosticInfo[] = [];
-
- lgFiles.forEach((lgFile) => {
- lgFile.diagnostics.forEach((diagnostic) => {
- const location = `${lgFile.id}.lg`;
- diagnosticList.push(
- new LgDiagnostic(rootProjectId, projectId, lgFile.id, location, diagnostic, lgFile, dialogs)
- );
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const botAssets = get(botAssetsSelectFamily(projectId));
+ if (botAssets === null) return [];
+
+ const { lgFiles, dialogs } = botAssets;
+ const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
+ const diagnosticList: DiagnosticInfo[] = [];
+
+ lgFiles.forEach((lgFile) => {
+ lgFile.diagnostics.forEach((diagnostic) => {
+ const location = `${lgFile.id}.lg`;
+ diagnosticList.push(
+ new LgDiagnostic(rootProjectId, projectId, lgFile.id, location, diagnostic, lgFile, dialogs),
+ );
+ });
});
- });
- return diagnosticList;
- },
+ return diagnosticList;
+ },
});
export const qnaDiagnosticsSelectorFamily = selectorFamily({
key: 'qnaDiagnosticsSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const botAssets = get(botAssetsSelectFamily(projectId));
- if (botAssets === null) return [];
-
- const { qnaFiles } = botAssets;
- const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
- const diagnosticList: DiagnosticInfo[] = [];
-
- qnaFiles.forEach((qnaFile) => {
- lodashGet(qnaFile, 'diagnostics', []).forEach((diagnostic) => {
- const location = `${qnaFile.id}.qna`;
- diagnosticList.push(new QnADiagnostic(rootProjectId, projectId, qnaFile.id, location, diagnostic));
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const botAssets = get(botAssetsSelectFamily(projectId));
+ if (botAssets === null) return [];
+
+ const { qnaFiles } = botAssets;
+ const rootProjectId = get(rootBotProjectIdSelector) ?? projectId;
+ const diagnosticList: DiagnosticInfo[] = [];
+
+ qnaFiles.forEach((qnaFile) => {
+ lodashGet(qnaFile, 'diagnostics', []).forEach((diagnostic) => {
+ const location = `${qnaFile.id}.qna`;
+ diagnosticList.push(new QnADiagnostic(rootProjectId, projectId, qnaFile.id, location, diagnostic));
+ });
});
- });
- return diagnosticList;
- },
+ return diagnosticList;
+ },
});
export const diagnosticsSelectorFamily = selectorFamily({
key: 'diagnosticsSelector',
- get: (projectId: string) => ({ get }) => [
- ...get(dialogsDiagnosticsSelectorFamily(projectId)),
- ...get(botDiagnosticsSelectorFamily(projectId)),
- ...get(skillSettingDiagnosticsSelectorFamily(projectId)),
- ...get(settingDiagnosticsSelectorFamily(projectId)),
- ...get(luDiagnosticsSelectorFamily(projectId)),
- ...get(lgDiagnosticsSelectorFamily(projectId)),
- ...get(qnaDiagnosticsSelectorFamily(projectId)),
- ...get(schemaDiagnosticsSelectorFamily(projectId)),
- ],
+ get:
+ (projectId: string) =>
+ ({ get }) => [
+ ...get(dialogsDiagnosticsSelectorFamily(projectId)),
+ ...get(botDiagnosticsSelectorFamily(projectId)),
+ ...get(skillSettingDiagnosticsSelectorFamily(projectId)),
+ ...get(settingDiagnosticsSelectorFamily(projectId)),
+ ...get(luDiagnosticsSelectorFamily(projectId)),
+ ...get(lgDiagnosticsSelectorFamily(projectId)),
+ ...get(qnaDiagnosticsSelectorFamily(projectId)),
+ ...get(schemaDiagnosticsSelectorFamily(projectId)),
+ ],
});
export const allDiagnosticsSelectorFamily = selectorFamily({
key: 'allDiagnosticsSelector',
- get: (severitiesToFilter: DiagnosticSeverity[]) => ({ get }) => {
- const ids = get(botProjectIdsState);
- const result = ids.reduce((result: DiagnosticInfo[], id: string) => {
- return [
- ...result,
- ...get(diagnosticsSelectorFamily(id)).filter((diagnostic) => severitiesToFilter.includes(diagnostic.severity)),
- ];
- }, []);
- return result;
- },
+ get:
+ (severitiesToFilter: DiagnosticSeverity[]) =>
+ ({ get }) => {
+ const ids = get(botProjectIdsState);
+ const result = ids.reduce((result: DiagnosticInfo[], id: string) => {
+ return [
+ ...result,
+ ...get(diagnosticsSelectorFamily(id)).filter((diagnostic) =>
+ severitiesToFilter.includes(diagnostic.severity),
+ ),
+ ];
+ }, []);
+ return result;
+ },
});
export const diagnosticNavLinksSelector = selector({
diff --git a/Composer/packages/client/src/recoilModel/selectors/dialogImports.ts b/Composer/packages/client/src/recoilModel/selectors/dialogImports.ts
index a487d90f05..72044d46d5 100644
--- a/Composer/packages/client/src/recoilModel/selectors/dialogImports.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/dialogImports.ts
@@ -14,7 +14,7 @@ import { luFilesSelectorFamily } from './lu';
// Finds all the file imports starting from a given dialog file.
export const getLanguageFileImports = (
rootDialogId: string,
- getFile: (fileId: string) => T
+ getFile: (fileId: string) => T,
): LanguageFileImport[] => {
const imports: LanguageFileImport[] = [];
@@ -31,7 +31,7 @@ export const getLanguageFileImports = (
const file = getFile(currentId);
// If file is not found or file content is empty, then continue.
- if (!file || !file.content) {
+ if (!file?.content) {
// eslint-disable-next-line no-console
console.warn(`Could not find language import file ${currentId}`);
continue;
@@ -58,26 +58,30 @@ export const getLanguageFileImports = (
// Returns all the lg imports referenced by a dialog file and its referenced lg files.
export const lgImportsSelectorFamily = selectorFamily({
key: 'lgImports',
- get: ({ projectId, dialogId }) => ({ get }) => {
- const locale = get(localeState(projectId));
+ get:
+ ({ projectId, dialogId }) =>
+ ({ get }) => {
+ const locale = get(localeState(projectId));
- const getFile = (fileId: string) =>
- get(lgFilesSelectorFamily(projectId)).find((f) => f.id === fileId || f.id === `${fileId}.${locale}`) as LgFile;
+ const getFile = (fileId: string) =>
+ get(lgFilesSelectorFamily(projectId)).find((f) => f.id === fileId || f.id === `${fileId}.${locale}`) as LgFile;
- // Have to exclude common as a special case
- return getLanguageFileImports(dialogId, getFile).filter((i) => getBaseName(i.id) !== 'common');
- },
+ // Have to exclude common as a special case
+ return getLanguageFileImports(dialogId, getFile).filter((i) => getBaseName(i.id) !== 'common');
+ },
});
// Returns all the lu imports referenced by a dialog file and its referenced lu files.
export const luImportsSelectorFamily = selectorFamily({
key: 'luImports',
- get: ({ projectId, dialogId }) => ({ get }) => {
- const locale = get(localeState(projectId));
+ get:
+ ({ projectId, dialogId }) =>
+ ({ get }) => {
+ const locale = get(localeState(projectId));
- const getFile = (fileId: string) =>
- get(luFilesSelectorFamily(projectId)).find((f) => f.id === fileId || f.id === `${fileId}.${locale}`) as LuFile;
+ const getFile = (fileId: string) =>
+ get(luFilesSelectorFamily(projectId)).find((f) => f.id === fileId || f.id === `${fileId}.${locale}`) as LuFile;
- return getLanguageFileImports(dialogId, getFile);
- },
+ return getLanguageFileImports(dialogId, getFile);
+ },
});
diff --git a/Composer/packages/client/src/recoilModel/selectors/dialogs.ts b/Composer/packages/client/src/recoilModel/selectors/dialogs.ts
index d29def42ae..c8c15c8533 100644
--- a/Composer/packages/client/src/recoilModel/selectors/dialogs.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/dialogs.ts
@@ -10,66 +10,76 @@ import { dialogsWithLuProviderSelectorFamily } from './validatedDialogs';
export const dialogsSelectorFamily = selectorFamily({
key: 'dialogs',
- get: (projectId: string) => ({ get }) => {
- const dialogIds = get(dialogIdsState(projectId));
- return dialogIds
- .map((dialogId) => {
- const result = get(dialogState({ projectId, dialogId }));
- return result;
- })
- .filter((d) => !d.isTopic);
- },
- set: (projectId: string) => ({ set }, newDialogs) => {
- const newDialogArray = newDialogs as DialogInfo[];
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const dialogIds = get(dialogIdsState(projectId));
+ return dialogIds
+ .map((dialogId) => {
+ const result = get(dialogState({ projectId, dialogId }));
+ return result;
+ })
+ .filter((d) => !d.isTopic);
+ },
+ set:
+ (projectId: string) =>
+ ({ set }, newDialogs) => {
+ const newDialogArray = newDialogs as DialogInfo[];
- set(
- dialogIdsState(projectId),
- newDialogArray.map((dialog) => dialog.id)
- );
- newDialogArray.forEach((dialog) => set(dialogState({ projectId, dialogId: dialog.id }), dialog));
- },
+ set(
+ dialogIdsState(projectId),
+ newDialogArray.map((dialog) => dialog.id),
+ );
+ newDialogArray.forEach((dialog) => set(dialogState({ projectId, dialogId: dialog.id }), dialog));
+ },
});
export const topicsSelectorFamily = selectorFamily({
key: 'topics',
- get: (projectId: string) => ({ get }) => {
- const dialogIds = get(dialogIdsState(projectId));
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const dialogIds = get(dialogIdsState(projectId));
- return dialogIds
- .map((dialogId) => {
- return get(dialogState({ projectId, dialogId }));
- })
- .filter((d) => d.isTopic)
- .sort((a, b) => {
- // sort system topics at the end of the list
- if (a.content?.isSystemTopic) {
- return 1;
- } else if (b.content?.isSystemTopic) {
- return -1;
- } else {
- return 0;
- }
- });
- },
+ return dialogIds
+ .map((dialogId) => {
+ return get(dialogState({ projectId, dialogId }));
+ })
+ .filter((d) => d.isTopic)
+ .sort((a, b) => {
+ // sort system topics at the end of the list
+ if (a.content?.isSystemTopic) {
+ return 1;
+ } else if (b.content?.isSystemTopic) {
+ return -1;
+ } else {
+ return 0;
+ }
+ });
+ },
});
export const currentDialogState = selectorFamily({
key: 'currentDialog',
- get: ({ projectId, dialogId }) => ({ get }) => {
- const dialogIds = get(dialogIdsState(projectId));
- if (dialogId && dialogIds.includes(dialogId)) {
- return get(dialogState({ projectId, dialogId }));
- }
+ get:
+ ({ projectId, dialogId }) =>
+ ({ get }) => {
+ const dialogIds = get(dialogIdsState(projectId));
+ if (dialogId && dialogIds.includes(dialogId)) {
+ return get(dialogState({ projectId, dialogId }));
+ }
- return get(dialogsSelectorFamily(projectId))?.[0];
- },
+ return get(dialogsSelectorFamily(projectId))?.[0];
+ },
});
export const rootDialogSelector = selectorFamily({
key: 'luFiles',
- get: (projectId: string) => ({ get }) => {
- const dialogs = get(dialogsWithLuProviderSelectorFamily(projectId));
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const dialogs = get(dialogsWithLuProviderSelectorFamily(projectId));
- return dialogs.find((d) => d.isRoot);
- },
+ return dialogs.find((d) => d.isRoot);
+ },
});
diff --git a/Composer/packages/client/src/recoilModel/selectors/lg.ts b/Composer/packages/client/src/recoilModel/selectors/lg.ts
index c4a45d7694..9389b257dc 100644
--- a/Composer/packages/client/src/recoilModel/selectors/lg.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/lg.ts
@@ -8,21 +8,25 @@ import { lgFileIdsState, lgFileState, settingsState } from '../atoms';
export const lgFilesSelectorFamily = selectorFamily({
key: 'lgFiles',
- get: (projectId: string) => ({ get }) => {
- const lgFileIds = get(lgFileIdsState(projectId));
- const settings = get(settingsState(projectId));
- return lgFileIds.map((lgFileId) => {
- const lgFile = get(lgFileState({ projectId, lgFileId }));
- const diagnostics = filterCustomFunctionError(lgFile.diagnostics, settings?.customFunctions ?? []);
- return { ...lgFile, diagnostics };
- });
- },
- set: (projectId: string) => ({ set }, newLgFiles) => {
- const newLgFileArray = newLgFiles as LgFile[];
- set(
- lgFileIdsState(projectId),
- newLgFileArray.map((lgFile) => lgFile.id)
- );
- newLgFileArray.forEach((lgFile) => set(lgFileState({ projectId, lgFileId: lgFile.id }), lgFile));
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const lgFileIds = get(lgFileIdsState(projectId));
+ const settings = get(settingsState(projectId));
+ return lgFileIds.map((lgFileId) => {
+ const lgFile = get(lgFileState({ projectId, lgFileId }));
+ const diagnostics = filterCustomFunctionError(lgFile.diagnostics, settings?.customFunctions ?? []);
+ return { ...lgFile, diagnostics };
+ });
+ },
+ set:
+ (projectId: string) =>
+ ({ set }, newLgFiles) => {
+ const newLgFileArray = newLgFiles as LgFile[];
+ set(
+ lgFileIdsState(projectId),
+ newLgFileArray.map((lgFile) => lgFile.id),
+ );
+ newLgFileArray.forEach((lgFile) => set(lgFileState({ projectId, lgFileId: lgFile.id }), lgFile));
+ },
});
diff --git a/Composer/packages/client/src/recoilModel/selectors/localRuntimeBuilder.ts b/Composer/packages/client/src/recoilModel/selectors/localRuntimeBuilder.ts
index 8c060d7881..8d4bd1f875 100644
--- a/Composer/packages/client/src/recoilModel/selectors/localRuntimeBuilder.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/localRuntimeBuilder.ts
@@ -19,49 +19,55 @@ import { qnaFilesSelectorFamily } from './qna';
export const trackBotStatusesSelector = selectorFamily({
key: 'trackBotStatusesSelector',
- get: (trackedProjectIds: string[]) => ({ get }) => {
- if (trackedProjectIds.length === 0) {
- return false;
- }
- const areBotsRunning = trackedProjectIds.find((projectId: string) => {
- const currentStatus = get(botStatusState(projectId));
- return currentStatus !== BotStatus.connected && currentStatus !== BotStatus.failed;
- });
- return areBotsRunning;
- },
+ get:
+ (trackedProjectIds: string[]) =>
+ ({ get }) => {
+ if (trackedProjectIds.length === 0) {
+ return false;
+ }
+ const areBotsRunning = trackedProjectIds.find((projectId: string) => {
+ const currentStatus = get(botStatusState(projectId));
+ return currentStatus !== BotStatus.connected && currentStatus !== BotStatus.failed;
+ });
+ return areBotsRunning;
+ },
});
export const botBuildRequiredSelector = selectorFamily({
key: 'botBuildRequiredSelector',
- get: (projectId: string) => ({ get }) => {
- const dialogs = get(dialogsSelectorFamily(projectId));
- return !isAbsHosted() && needsBuild(dialogs);
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const dialogs = get(dialogsSelectorFamily(projectId));
+ return !isAbsHosted() && needsBuild(dialogs);
+ },
});
export const buildEssentialsSelector = selectorFamily({
key: 'buildEssentialsSelector',
- get: (projectId: string) => ({ get }) => {
- const settings = get(settingsState(projectId));
- const configuration = {
- luis: settings.luis,
- qna: settings.qna,
- orchestrator: settings.orchestrator,
- };
- const dialogs = get(dialogsSelectorFamily(projectId));
- const luFiles = get(luFilesSelectorFamily(projectId));
- const qnaFiles = get(qnaFilesSelectorFamily(projectId));
- const buildRequired = get(botBuildRequiredSelector(projectId));
- const status = get(botStatusState(projectId));
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const settings = get(settingsState(projectId));
+ const configuration = {
+ luis: settings.luis,
+ qna: settings.qna,
+ orchestrator: settings.orchestrator,
+ };
+ const dialogs = get(dialogsSelectorFamily(projectId));
+ const luFiles = get(luFilesSelectorFamily(projectId));
+ const qnaFiles = get(qnaFilesSelectorFamily(projectId));
+ const buildRequired = get(botBuildRequiredSelector(projectId));
+ const status = get(botStatusState(projectId));
- return {
- isConfigurationComplete: isBuildConfigurationComplete(configuration, dialogs, luFiles, qnaFiles),
- configuration,
- buildRequired,
- projectId,
- status,
- };
- },
+ return {
+ isConfigurationComplete: isBuildConfigurationComplete(configuration, dialogs, luFiles, qnaFiles),
+ configuration,
+ buildRequired,
+ projectId,
+ status,
+ };
+ },
});
export const buildConfigurationSelector = selector({
diff --git a/Composer/packages/client/src/recoilModel/selectors/lu.ts b/Composer/packages/client/src/recoilModel/selectors/lu.ts
index 555118b23e..b3ddfd372e 100644
--- a/Composer/packages/client/src/recoilModel/selectors/lu.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/lu.ts
@@ -8,19 +8,23 @@ import { luFileIdsState, luFileState } from '../atoms';
export const luFilesSelectorFamily = selectorFamily({
key: 'luFiles',
- get: (projectId: string) => ({ get }) => {
- const luFileIds = get(luFileIdsState(projectId));
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const luFileIds = get(luFileIdsState(projectId));
- return luFileIds.map((luFileId) => {
- return get(luFileState({ projectId, luFileId }));
- });
- },
- set: (projectId: string) => ({ set }, newLuFiles: LuFile[] | DefaultValue) => {
- if (newLuFiles instanceof DefaultValue) return;
- set(
- luFileIdsState(projectId),
- newLuFiles.map((luFile) => luFile.id)
- );
- newLuFiles.forEach((luFile) => set(luFileState({ projectId, luFileId: luFile.id }), luFile));
- },
+ return luFileIds.map((luFileId) => {
+ return get(luFileState({ projectId, luFileId }));
+ });
+ },
+ set:
+ (projectId: string) =>
+ ({ set }, newLuFiles: LuFile[] | DefaultValue) => {
+ if (newLuFiles instanceof DefaultValue) return;
+ set(
+ luFileIdsState(projectId),
+ newLuFiles.map((luFile) => luFile.id),
+ );
+ newLuFiles.forEach((luFile) => set(luFileState({ projectId, luFileId: luFile.id }), luFile));
+ },
});
diff --git a/Composer/packages/client/src/recoilModel/selectors/project.ts b/Composer/packages/client/src/recoilModel/selectors/project.ts
index d2d566c9fe..36dda3add1 100644
--- a/Composer/packages/client/src/recoilModel/selectors/project.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/project.ts
@@ -132,19 +132,23 @@ export const localBotsSettingDataSelector = selector({
export const formDialogSchemasSelectorFamily = selectorFamily({
key: 'formDialogSchemasSelector',
- get: (projectId: string) => ({ get }) => {
- const formDialogSchemaIds = get(formDialogSchemaIdsState(projectId));
- return formDialogSchemaIds.map((schemaId) => get(formDialogSchemaState({ projectId, schemaId })));
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const formDialogSchemaIds = get(formDialogSchemaIdsState(projectId));
+ return formDialogSchemaIds.map((schemaId) => get(formDialogSchemaState({ projectId, schemaId })));
+ },
});
// Given a form dialog schema, indicates if the dialog exist for it (aka is generated)
export const formDialogSchemaDialogExistsSelector = selectorFamily({
key: 'formDialogSchemasSelector',
- get: ({ projectId, schemaId }) => ({ get }) => {
- const dialogs = get(dialogsSelectorFamily(projectId));
- return !!dialogs.find((d) => d.id === schemaId);
- },
+ get:
+ ({ projectId, schemaId }) =>
+ ({ get }) => {
+ const dialogs = get(dialogsSelectorFamily(projectId));
+ return !!dialogs.find((d) => d.id === schemaId);
+ },
});
// TODO: This selector would be modified and leveraged by the project tree
@@ -239,37 +243,39 @@ export const jsonSchemaFilesByProjectIdSelector = selector({
export const perProjectDiagnosticsSelectorFamily = selectorFamily({
key: 'perProjectDiagnosticsSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const { isRemote, isRootBot } = get(projectMetaDataState(projectId));
- const rootBotId = get(rootBotProjectIdSelector) || projectId;
- const rootSetting = get(settingsState(rootBotId));
- const dialogs = get(dialogsWithLuProviderSelectorFamily(projectId));
- const formDialogSchemas = get(formDialogSchemasSelectorFamily(projectId));
- const luFiles = get(luFilesSelectorFamily(projectId));
- const lgFiles = get(lgFilesSelectorFamily(projectId));
- const setting = get(settingsState(projectId));
- const skillManifests = get(skillManifestsState(projectId));
- const dialogSchemas = get(dialogSchemasState(projectId));
- const qnaFiles = get(qnaFilesSelectorFamily(projectId));
- const botProjectFile = get(botProjectFileState(projectId));
- const jsonSchemaFiles = get(jsonSchemaFilesState(projectId));
- const botAssets: BotAssets = {
- projectId,
- dialogs,
- luFiles,
- qnaFiles,
- lgFiles,
- skillManifests,
- setting,
- dialogSchemas,
- formDialogSchemas,
- botProjectFile,
- jsonSchemaFiles,
- recognizers: [],
- crossTrainConfig: {},
- };
- return BotIndexer.validate({ ...botAssets, isRemote, isRootBot }, rootSetting);
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const { isRemote, isRootBot } = get(projectMetaDataState(projectId));
+ const rootBotId = get(rootBotProjectIdSelector) || projectId;
+ const rootSetting = get(settingsState(rootBotId));
+ const dialogs = get(dialogsWithLuProviderSelectorFamily(projectId));
+ const formDialogSchemas = get(formDialogSchemasSelectorFamily(projectId));
+ const luFiles = get(luFilesSelectorFamily(projectId));
+ const lgFiles = get(lgFilesSelectorFamily(projectId));
+ const setting = get(settingsState(projectId));
+ const skillManifests = get(skillManifestsState(projectId));
+ const dialogSchemas = get(dialogSchemasState(projectId));
+ const qnaFiles = get(qnaFilesSelectorFamily(projectId));
+ const botProjectFile = get(botProjectFileState(projectId));
+ const jsonSchemaFiles = get(jsonSchemaFilesState(projectId));
+ const botAssets: BotAssets = {
+ projectId,
+ dialogs,
+ luFiles,
+ qnaFiles,
+ lgFiles,
+ skillManifests,
+ setting,
+ dialogSchemas,
+ formDialogSchemas,
+ botProjectFile,
+ jsonSchemaFiles,
+ recognizers: [],
+ crossTrainConfig: {},
+ };
+ return BotIndexer.validate({ ...botAssets, isRemote, isRootBot }, rootSetting);
+ },
});
export const botProjectDiagnosticsSelector = selector({
@@ -369,27 +375,29 @@ export const projectTreeSelectorFamily = selector({
export const webChatEssentialsSelector = selectorFamily({
key: 'webChatEssentialsSelector',
- get: (projectId: string) => ({ get }) => {
- const settings = get(settingsState(projectId));
- const secret = {
- msAppId: settings.MicrosoftAppId || '',
- msPassword: settings.MicrosoftAppPassword || '',
- };
- const botEndpoints = get(botEndpointsState);
- const botUrl = botEndpoints[projectId]?.url;
- const botName = get(botDisplayNameState(projectId));
- const activeLocale = get(localeState(projectId));
- const botStatus = get(botStatusState(projectId));
-
- return {
- projectId,
- botName,
- secret: secret,
- botUrl,
- activeLocale,
- botStatus,
- };
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const settings = get(settingsState(projectId));
+ const secret = {
+ msAppId: settings.MicrosoftAppId || '',
+ msPassword: settings.MicrosoftAppPassword || '',
+ };
+ const botEndpoints = get(botEndpointsState);
+ const botUrl = botEndpoints[projectId]?.url;
+ const botName = get(botDisplayNameState(projectId));
+ const activeLocale = get(localeState(projectId));
+ const botStatus = get(botStatusState(projectId));
+
+ return {
+ projectId,
+ botName,
+ secret: secret,
+ botUrl,
+ activeLocale,
+ botStatus,
+ };
+ },
});
function getBaseName(filename: string, sep?: string): string {
@@ -420,7 +428,7 @@ export const allRequiredRecognizersSelector = selector({
if (botAssets) {
const { dialogs, luFiles, qnaFiles } = botAssets;
const requiresLUIS = dialogs.some(
- (dialog) => dialog.luProvider === SDKKinds.LuisRecognizer && !isEmptyFile(luFiles, dialog.luFile)
+ (dialog) => dialog.luProvider === SDKKinds.LuisRecognizer && !isEmptyFile(luFiles, dialog.luFile),
);
const requiresQNA = qnaFiles.some((file) => file.content.trim().replace(/^>.*$/g, '').trim() !== '');
result.push({ projectId: id, requiresLUIS, requiresQNA });
@@ -448,14 +456,16 @@ export const outputsDebugPanelSelector = selector({
export const luFileLuFeatureSelector = selectorFamily({
key: 'luFileLuFeatureSelector',
- get: ({ projectId, id }) => ({ get }) => {
- const recognizers = get(recognizersSelectorFamily(projectId));
- const { luFeatures } = get(settingsState(projectId));
-
- const isOrchestartor = recognizers.some(
- (f) => f.id === `${id}.lu.dialog` && f.content.$kind === SDKKinds.OrchestratorRecognizer
- );
-
- return { ...luFeatures, isOrchestartor };
- },
+ get:
+ ({ projectId, id }) =>
+ ({ get }) => {
+ const recognizers = get(recognizersSelectorFamily(projectId));
+ const { luFeatures } = get(settingsState(projectId));
+
+ const isOrchestartor = recognizers.some(
+ (f) => f.id === `${id}.lu.dialog` && f.content.$kind === SDKKinds.OrchestratorRecognizer,
+ );
+
+ return { ...luFeatures, isOrchestartor };
+ },
});
diff --git a/Composer/packages/client/src/recoilModel/selectors/qna.ts b/Composer/packages/client/src/recoilModel/selectors/qna.ts
index 6b2be2148a..101e3e08da 100644
--- a/Composer/packages/client/src/recoilModel/selectors/qna.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/qna.ts
@@ -8,20 +8,24 @@ import { qnaFileIdsState, qnaFileState } from '../atoms';
export const qnaFilesSelectorFamily = selectorFamily({
key: 'qnaFiles',
- get: (projectId: string) => ({ get }) => {
- const qnaFileIds = get(qnaFileIdsState(projectId));
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const qnaFileIds = get(qnaFileIdsState(projectId));
- return qnaFileIds.map((qnaFileId) => {
- return get(qnaFileState({ projectId, qnaFileId }));
- });
- },
- set: (projectId: string) => ({ set }, newQnaFiles: QnAFile[] | DefaultValue) => {
- if (newQnaFiles instanceof DefaultValue) return;
+ return qnaFileIds.map((qnaFileId) => {
+ return get(qnaFileState({ projectId, qnaFileId }));
+ });
+ },
+ set:
+ (projectId: string) =>
+ ({ set }, newQnaFiles: QnAFile[] | DefaultValue) => {
+ if (newQnaFiles instanceof DefaultValue) return;
- set(
- qnaFileIdsState(projectId),
- newQnaFiles.map((qnaFile) => qnaFile.id)
- );
- newQnaFiles.forEach((qnaFile) => set(qnaFileState({ projectId, qnaFileId: qnaFile.id }), qnaFile));
- },
+ set(
+ qnaFileIdsState(projectId),
+ newQnaFiles.map((qnaFile) => qnaFile.id),
+ );
+ newQnaFiles.forEach((qnaFile) => set(qnaFileState({ projectId, qnaFileId: qnaFile.id }), qnaFile));
+ },
});
diff --git a/Composer/packages/client/src/recoilModel/selectors/recognizers.ts b/Composer/packages/client/src/recoilModel/selectors/recognizers.ts
index 8e772bdbdb..356d51b023 100644
--- a/Composer/packages/client/src/recoilModel/selectors/recognizers.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/recognizers.ts
@@ -7,19 +7,23 @@ import { recognizerIdsState, recognizerState } from '../atoms';
export const recognizersSelectorFamily = selectorFamily({
key: 'recognizers',
- get: (projectId: string) => ({ get }) => {
- const recognizerIds = get(recognizerIdsState(projectId));
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const recognizerIds = get(recognizerIdsState(projectId));
- return recognizerIds.map((id) => {
- return get(recognizerState({ projectId, id }));
- });
- },
- set: (projectId: string) => ({ set }, newRecognizers) => {
- const newRecognizerArray = newRecognizers as RecognizerFile[];
- set(
- recognizerIdsState(projectId),
- newRecognizerArray.map((file) => file.id)
- );
- newRecognizerArray.forEach((file) => set(recognizerState({ projectId, id: file.id }), file));
- },
+ return recognizerIds.map((id) => {
+ return get(recognizerState({ projectId, id }));
+ });
+ },
+ set:
+ (projectId: string) =>
+ ({ set }, newRecognizers) => {
+ const newRecognizerArray = newRecognizers as RecognizerFile[];
+ set(
+ recognizerIdsState(projectId),
+ newRecognizerArray.map((file) => file.id),
+ );
+ newRecognizerArray.forEach((file) => set(recognizerState({ projectId, id: file.id }), file));
+ },
});
diff --git a/Composer/packages/client/src/recoilModel/selectors/skills.ts b/Composer/packages/client/src/recoilModel/selectors/skills.ts
index 87e2f4b1b3..58c5e73467 100644
--- a/Composer/packages/client/src/recoilModel/selectors/skills.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/skills.ts
@@ -110,7 +110,7 @@ export const skillUsedInBotsSelector = selector({
result[skillId] = usedInBots;
return result;
},
- {}
+ {},
);
return skillInBots;
},
diff --git a/Composer/packages/client/src/recoilModel/selectors/undo.ts b/Composer/packages/client/src/recoilModel/selectors/undo.ts
index f031ca1c3e..65f867dd63 100644
--- a/Composer/packages/client/src/recoilModel/selectors/undo.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/undo.ts
@@ -6,9 +6,11 @@ import { canRedoState, canUndoState } from '../atoms/botState';
export const undoStatusSelectorFamily = selectorFamily<[boolean, boolean], string>({
key: 'undoStatus',
- get: (projectId: string) => ({ get }) => {
- const canUndo = get(canUndoState(projectId));
- const canRedo = get(canRedoState(projectId));
- return [canUndo, canRedo];
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const canUndo = get(canUndoState(projectId));
+ const canRedo = get(canRedoState(projectId));
+ return [canUndo, canRedo];
+ },
});
diff --git a/Composer/packages/client/src/recoilModel/selectors/validatedDialogs.ts b/Composer/packages/client/src/recoilModel/selectors/validatedDialogs.ts
index 39d0475f64..769fb6d9dc 100644
--- a/Composer/packages/client/src/recoilModel/selectors/validatedDialogs.ts
+++ b/Composer/packages/client/src/recoilModel/selectors/validatedDialogs.ts
@@ -16,40 +16,44 @@ const dialogCache = new ClientStorage(window.sessionStorage, 'dialogCache');
type validateDialogSelectorFamilyParams = { projectId: string; dialogId: string };
export const dialogsWithLuProviderSelectorFamily = selectorFamily({
key: 'dialogLuProviderSelectorFamily',
- get: (projectId: string) => ({ get }) => {
- const dialogs = get(dialogsSelectorFamily(projectId));
- const recognizers: RecognizerFile[] = get(recognizersSelectorFamily(projectId));
- return dialogs.map((dialog) => {
- return {
- ...dialog,
- luProvider: getLuProvider(dialog.id, recognizers),
- };
- });
- },
+ get:
+ (projectId: string) =>
+ ({ get }) => {
+ const dialogs = get(dialogsSelectorFamily(projectId));
+ const recognizers: RecognizerFile[] = get(recognizersSelectorFamily(projectId));
+ return dialogs.map((dialog) => {
+ return {
+ ...dialog,
+ luProvider: getLuProvider(dialog.id, recognizers),
+ };
+ });
+ },
});
export const dialogDiagnosticsSelectorFamily = selectorFamily({
key: 'dialogDiagnosticsSelectorFamily',
- get: ({ projectId, dialogId }: validateDialogSelectorFamilyParams) => ({ get }) => {
- if (get(projectMetaDataState(projectId)).isRemote) return [];
-
- const dialog: DialogInfo = get(dialogState({ projectId, dialogId }));
- const schemas: BotSchemas = get(schemasState(projectId));
- const locale = get(localeState(projectId));
- const lgFile: LgFile = get(lgFileState({ projectId, lgFileId: `${dialogId}.${locale}` }));
- const settings: DialogSetting = get(settingsState(projectId));
- const cacheId = `${projectId}-${dialogId}`;
-
- const { diagnostics, cache } = validateDialog(
- dialog,
- schemas.sdk.content,
- settings,
- [lgFile],
- [],
- dialogCache.get(cacheId)
- );
- dialogCache.set(cacheId, cache);
-
- return diagnostics;
- },
+ get:
+ ({ projectId, dialogId }: validateDialogSelectorFamilyParams) =>
+ ({ get }) => {
+ if (get(projectMetaDataState(projectId)).isRemote) return [];
+
+ const dialog: DialogInfo = get(dialogState({ projectId, dialogId }));
+ const schemas: BotSchemas = get(schemasState(projectId));
+ const locale = get(localeState(projectId));
+ const lgFile: LgFile = get(lgFileState({ projectId, lgFileId: `${dialogId}.${locale}` }));
+ const settings: DialogSetting = get(settingsState(projectId));
+ const cacheId = `${projectId}-${dialogId}`;
+
+ const { diagnostics, cache } = validateDialog(
+ dialog,
+ schemas.sdk.content,
+ settings,
+ [lgFile],
+ [],
+ dialogCache.get(cacheId),
+ );
+ dialogCache.set(cacheId, cache);
+
+ return diagnostics;
+ },
});
diff --git a/Composer/packages/client/src/recoilModel/undo/history.ts b/Composer/packages/client/src/recoilModel/undo/history.ts
index c08d74e738..fdfe1e925f 100644
--- a/Composer/packages/client/src/recoilModel/undo/history.ts
+++ b/Composer/packages/client/src/recoilModel/undo/history.ts
@@ -72,7 +72,7 @@ function mapTrackedAtomsOntoSnapshot(
target: Snapshot,
currentAssets: AtomAssetsMap,
nextAssets: AtomAssetsMap,
- projectId: string
+ projectId: string,
): Snapshot {
trackedAtoms(projectId).forEach((atom) => {
const current = currentAssets.get(atom);
@@ -157,7 +157,7 @@ export const UndoRoot = React.memo((props: UndoRootProps) => {
current: AtomAssetsMap,
next: AtomAssetsMap,
gotoSnapshot: (snapshot: Snapshot) => void,
- projectId: string
+ projectId: string,
) => {
target = mapTrackedAtomsOntoSnapshot(target, current, next, projectId);
gotoSnapshot(target);
diff --git a/Composer/packages/client/src/recoilModel/utils/fontUtil.ts b/Composer/packages/client/src/recoilModel/utils/fontUtil.ts
index 8effec4e4e..ac4d26f782 100644
--- a/Composer/packages/client/src/recoilModel/utils/fontUtil.ts
+++ b/Composer/packages/client/src/recoilModel/utils/fontUtil.ts
@@ -15,8 +15,8 @@ export const getDefaultFontSettings = () => {
platformName === OS.MacOS
? DEFAULT_MAC_FONT_FAMILY
: platformName === OS.Linux
- ? DEFAULT_LINUX_FONT_FAMILY
- : DEFAULT_WINDOWS_FONT_FAMILY,
+ ? DEFAULT_LINUX_FONT_FAMILY
+ : DEFAULT_WINDOWS_FONT_FAMILY,
fontWeight: 'normal',
fontSize: '14px',
lineHeight: 0,
diff --git a/Composer/packages/client/src/recoilModel/utils/mapOptimizer.ts b/Composer/packages/client/src/recoilModel/utils/mapOptimizer.ts
new file mode 100644
index 0000000000..a4cd0ae9e1
--- /dev/null
+++ b/Composer/packages/client/src/recoilModel/utils/mapOptimizer.ts
@@ -0,0 +1,144 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/**
+ * Internal tree structure to track the oldest elements and their references.
+ */
+interface MapOptimizerTree {
+ timestamp: number;
+ references: Key[];
+}
+
+/**
+ * Context for the MapOptimizer.onUpdate event.
+ */
+interface OnUpdateMapOptimizerContext {
+ /**
+ * Sets the related Map keys references of an element, these references are taken into account on the delete event.
+ * @param references The Map keys of a related element.
+ */
+ setReferences(references: Key[]): void;
+}
+
+/**
+ * Class to optimize a Map object by deleting the oldest elements of the collection based on a capacity limit.
+ */
+export class MapOptimizer {
+ public tree = new Map>();
+ private skipOptimize = new Set();
+
+ onUpdateCallback?: (key: Key, value: Value, ctx: OnUpdateMapOptimizerContext) => void;
+ onDeleteCallback?: (key: Key, value: Value) => void;
+
+ /**
+ * Initializes a new instance of the MapOptimizer class.
+ * @param capacity The capacity limit to trigger the optimization steps.
+ * @param list The Map object to optimize.
+ */
+ constructor(
+ private capacity: number,
+ public list: Map,
+ ) {
+ this.attach();
+ }
+
+ /**
+ * Event triggered when an element is added or updated in the Map object.
+ * @param callback Exposes the element's Key, Value and Context to perform operations.
+ */
+ onUpdate(callback: (key: Key, value: Value, ctx: OnUpdateMapOptimizerContext) => void) {
+ this.onUpdateCallback = callback;
+ }
+
+ /**
+ * Event triggered when an element is marked for deletion.
+ * @param callback Exposes the element's Key, Value.
+ */
+ onDelete(callback: (key: Key, value: Value) => void) {
+ this.onDeleteCallback = callback;
+ }
+
+ /**
+ * @private
+ * Attaches the "set" method to the Map object to listen and trigger the optimization.
+ */
+ private attach() {
+ const set = this.list.set;
+ this.list.set = (key, value) => {
+ if (!this.skipOptimize.has(key)) {
+ this.optimize(key, value);
+ }
+ const result = set.apply(this.list, [key, value]);
+ return result;
+ };
+ }
+
+ /**
+ * @private
+ * Optimizes the Map object by performing the onDelete event callback on the oldest element in the collection.
+ */
+ private optimize(keyToAdd: Key, valueToAdd: Value) {
+ const exists = this.tree.has(keyToAdd);
+ const context: MapOptimizerTree = { timestamp: Date.now(), references: [] };
+ this.onUpdateCallback?.(keyToAdd, valueToAdd, {
+ setReferences: (references) => (context.references = references || []),
+ });
+ this.tree.set(keyToAdd, context);
+
+ if (exists) {
+ return;
+ }
+
+ let processed: [Key, MapOptimizerTree][] = [];
+ const itemsToRemove = Array.from(this.tree.entries())
+ .filter(([key]) => key !== keyToAdd)
+ .sort(([, v1], [, v2]) => v2.timestamp - v1.timestamp);
+
+ while (this.capacity < this.tree.size) {
+ const itemToRemove = itemsToRemove.pop();
+ if (!itemToRemove) {
+ break;
+ }
+
+ const [key, { references }] = itemToRemove;
+ const ids = this.identify([key, ...references]);
+
+ // Re-process previous items if an item gets deleted.
+ processed.push(itemToRemove);
+ if (ids.length > 0) {
+ itemsToRemove.push(...processed);
+ processed = [];
+ }
+
+ for (const id of ids) {
+ this.tree.delete(id);
+ const listItem = this.list.get(id)!;
+ this.skipOptimize.add(id);
+ this.onDeleteCallback ? this.onDeleteCallback(id, listItem) : this.list.delete(id);
+ this.skipOptimize.delete(id);
+ }
+ }
+ }
+
+ /**
+ * @private
+ * Identifies all the keys that are available to delete.
+ */
+ private identify(references: Key[], memo: Key[] = []) {
+ for (const reference of references) {
+ const found = this.tree.get(reference);
+ const existsOnMemo = () => memo.some((e) => found!.references.includes(e));
+ const existsOnReferences = () =>
+ Array.from(this.tree.values()).some(({ references }) => references.includes(reference));
+
+ if (!found || existsOnMemo() || existsOnReferences()) {
+ continue;
+ }
+
+ memo.push(reference);
+ this.identify(found.references, memo);
+ }
+
+ return memo;
+ }
+}
diff --git a/Composer/packages/client/src/recoilModel/utils/skill.ts b/Composer/packages/client/src/recoilModel/utils/skill.ts
index 266e42a6a0..231048996e 100644
--- a/Composer/packages/client/src/recoilModel/utils/skill.ts
+++ b/Composer/packages/client/src/recoilModel/utils/skill.ts
@@ -24,7 +24,7 @@ export const getManifestJsonFromZip = (zipContent) => {
try {
const manifestUrl = Object.keys(zipContent).find((key) => zipContent[key] && isManifestJson(zipContent[key]));
return manifestUrl
- ? { name: `skills/${manifestUrl}`, content: JSON.parse(zipContent[manifestUrl]) }
+ ? { name: manifestUrl, content: JSON.parse(zipContent[manifestUrl]) }
: { name: '', content: null };
} catch (e) {
return { name: '', content: null };
diff --git a/Composer/packages/client/src/shell/actionApi.ts b/Composer/packages/client/src/shell/actionApi.ts
index e4e3741848..e7a35b53ca 100644
--- a/Composer/packages/client/src/shell/actionApi.ts
+++ b/Composer/packages/client/src/shell/actionApi.ts
@@ -39,7 +39,7 @@ export const useActionApi = (projectId: string) => {
toId: string,
lgText: string,
hostActionData: MicrosoftIDialog,
- hostFieldName: string
+ hostFieldName: string,
): Promise => {
if (!lgText) return '';
return await deserializeLgTemplate(lgFileId, toId, lgText, hostActionData, hostFieldName, addLgTemplate);
@@ -63,7 +63,7 @@ export const useActionApi = (projectId: string) => {
luFileId: string,
intent: LuIntentSection | undefined,
hostResourceId: string,
- hostResourceData: MicrosoftIDialog
+ hostResourceData: MicrosoftIDialog,
) => {
if (!intent) return;
@@ -132,7 +132,7 @@ export const useActionApi = (projectId: string) => {
return destructActions(
actions,
(templates: string[]) => removeLgTemplates(dialogId, templates),
- (luIntents: string[]) => Promise.all(luIntents.map((intent) => removeLuIntent(dialogId, intent)))
+ (luIntents: string[]) => Promise.all(luIntents.map((intent) => removeLuIntent(dialogId, intent))),
);
}
diff --git a/Composer/packages/client/src/shell/lgApi.ts b/Composer/packages/client/src/shell/lgApi.ts
index 23d6aec7a9..d46842ae64 100644
--- a/Composer/packages/client/src/shell/lgApi.ts
+++ b/Composer/packages/client/src/shell/lgApi.ts
@@ -33,7 +33,7 @@ const memoizedDebounce = (func, wait, options = {}) => {
function createLgApi(
state: { dialogId: string; projectId: string },
actions: Dispatcher,
- lgFileResolver: (id: string) => LgFile | undefined
+ lgFileResolver: (id: string) => LgFile | undefined,
): LgContextApi {
const getLgTemplates = (id) => {
if (id === undefined) throw new Error('must have a file id');
diff --git a/Composer/packages/client/src/shell/luApi.ts b/Composer/packages/client/src/shell/luApi.ts
index 244c0d481d..1bd3f2c091 100644
--- a/Composer/packages/client/src/shell/luApi.ts
+++ b/Composer/packages/client/src/shell/luApi.ts
@@ -17,7 +17,7 @@ const INTENT_ERROR = formatMessage('intentName is missing or empty');
function createLuApi(
state: { dialogId: string; projectId: string },
dispatchers: Dispatcher,
- luFileResolver: (id: string) => LuFile | undefined
+ luFileResolver: (id: string) => LuFile | undefined,
): LuContextApi {
const updateLuFile = async (id: string, content: string) => {
const file = luFileResolver(id);
@@ -83,7 +83,6 @@ function createLuApi(
getLuIntents,
getLuIntent,
updateLuIntent,
- // @ts-expect-error debounce is typed in a way that allows returning undefined which conflicts with debouncedUpdateLuIntent type
debouncedUpdateLuIntent: debounce(updateLuIntent, 250),
renameLuIntent,
removeLuIntent,
diff --git a/Composer/packages/client/src/shell/useShell.ts b/Composer/packages/client/src/shell/useShell.ts
index f20caa7245..a475e39392 100644
--- a/Composer/packages/client/src/shell/useShell.ts
+++ b/Composer/packages/client/src/shell/useShell.ts
@@ -267,7 +267,7 @@ export function useShell(source: EventSource, projectId: string): Shell {
(newDialog: string | null) => {
resolve(newDialog);
},
- projectId
+ projectId,
);
});
},
diff --git a/Composer/packages/client/src/shell/utils.ts b/Composer/packages/client/src/shell/utils.ts
index 6ecf068bd4..b559b2984c 100644
--- a/Composer/packages/client/src/shell/utils.ts
+++ b/Composer/packages/client/src/shell/utils.ts
@@ -22,7 +22,7 @@ export const serializeLgTemplate = (
templateName: string,
fromId: string,
lgText: string,
- lgTemplates: LgTemplate[]
+ lgTemplates: LgTemplate[],
) => {
const lgTemplate = lgTemplates.find((x) => x.name === templateName);
@@ -77,7 +77,7 @@ export const deserializeLgTemplate = async (
lgText: string,
hostActionData: MicrosoftIDialog,
hostFieldName: string,
- addLgTemplate: ShellApi['addLgTemplate']
+ addLgTemplate: ShellApi['addLgTemplate'],
) => {
const newLgType = new LgType(hostActionData.$kind, hostFieldName).toString();
const newLgTemplateName = new LgMetaData(newLgType, toId).toString();
diff --git a/Composer/packages/client/src/telemetry/TelemetryClient.ts b/Composer/packages/client/src/telemetry/TelemetryClient.ts
index d4e9359b5f..e4d466bfc2 100644
--- a/Composer/packages/client/src/telemetry/TelemetryClient.ts
+++ b/Composer/packages/client/src/telemetry/TelemetryClient.ts
@@ -26,7 +26,7 @@ export default class TelemetryClient {
public static track(
eventName: TN,
- properties?: TelemetryEvents[TN] extends undefined ? never : TelemetryEvents[TN]
+ properties?: TelemetryEvents[TN] extends undefined ? never : TelemetryEvents[TN],
) {
this.client?.trackEvent(eventName, { ...this.sharedProperties, ...properties });
}
@@ -34,7 +34,7 @@ export default class TelemetryClient {
public static pageView(
eventName: TN,
url: string,
- properties?: TelemetryEvents[TN] extends undefined ? never : TelemetryEvents[TN]
+ properties?: TelemetryEvents[TN] extends undefined ? never : TelemetryEvents[TN],
) {
this.client?.logPageView(eventName, url, { ...this.sharedProperties, ...properties });
}
diff --git a/Composer/packages/client/src/telemetry/__tests__/AppInsightsClient.test.ts b/Composer/packages/client/src/telemetry/__tests__/AppInsightsClient.test.ts
index 8db823825a..1d6dbb1104 100644
--- a/Composer/packages/client/src/telemetry/__tests__/AppInsightsClient.test.ts
+++ b/Composer/packages/client/src/telemetry/__tests__/AppInsightsClient.test.ts
@@ -31,7 +31,7 @@ describe('Application Insights Logger', () => {
},
}),
]),
- })
+ }),
);
});
@@ -65,7 +65,7 @@ describe('Application Insights Logger', () => {
},
}),
]),
- })
+ }),
);
});
diff --git a/Composer/packages/client/src/telemetry/__tests__/TelemetryClient.test.ts b/Composer/packages/client/src/telemetry/__tests__/TelemetryClient.test.ts
index 33f358455b..9411a37026 100644
--- a/Composer/packages/client/src/telemetry/__tests__/TelemetryClient.test.ts
+++ b/Composer/packages/client/src/telemetry/__tests__/TelemetryClient.test.ts
@@ -21,7 +21,7 @@ describe('TelemetryClient', () => {
expect.objectContaining({
prop1: 'prop1',
name: 'test',
- })
+ }),
);
});
@@ -35,7 +35,7 @@ describe('TelemetryClient', () => {
expect.objectContaining({
prop1: 'prop1',
name: 'test',
- })
+ }),
);
});
});
diff --git a/Composer/packages/client/src/telemetry/useInitializeLogger.ts b/Composer/packages/client/src/telemetry/useInitializeLogger.ts
index f80b776f83..e3dac22ebd 100644
--- a/Composer/packages/client/src/telemetry/useInitializeLogger.ts
+++ b/Composer/packages/client/src/telemetry/useInitializeLogger.ts
@@ -24,7 +24,7 @@ export const useInitializeLogger = () => {
...acc,
[camelCase(key)]: enabled,
}),
- {}
+ {},
);
const {
diff --git a/Composer/packages/client/src/utils/__tests__/auth.test.ts b/Composer/packages/client/src/utils/__tests__/auth.test.ts
index dbb24ba9e8..e5a33d368e 100644
--- a/Composer/packages/client/src/utils/__tests__/auth.test.ts
+++ b/Composer/packages/client/src/utils/__tests__/auth.test.ts
@@ -9,7 +9,7 @@ const jwtToken =
describe('isTokenExpired', () => {
it('is false when token is valid', () => {
- // @ts-ignore
+ // @ts-expect-error: test
Date.now = jest.spyOn(Date, 'now').mockImplementation(() => 1567630800000); // 2019-09-04 14:00 PDT
expect(isTokenExpired(jwtToken)).toBe(false);
});
@@ -19,11 +19,11 @@ describe('isTokenExpired', () => {
});
it('is true when token is expired', () => {
- // @ts-ignore
+ // @ts-expect-error: test
Date.now = jest.spyOn(Date, 'now').mockImplementation(() => 1567717200000); // 2019-09-05 14:00 PDT
expect(isTokenExpired(jwtToken)).toBe(true);
- // @ts-ignore
+ // @ts-expect-error: test
Date.now = jest.spyOn(Date, 'now').mockImplementation(() => 1567803600000); // 2019-09-06 14:00 PDT
expect(isTokenExpired(jwtToken)).toBe(true);
});
diff --git a/Composer/packages/client/src/utils/__tests__/dialogUtil.test.ts b/Composer/packages/client/src/utils/__tests__/dialogUtil.test.ts
index 562cafe4ac..a6a0c28bf3 100644
--- a/Composer/packages/client/src/utils/__tests__/dialogUtil.test.ts
+++ b/Composer/packages/client/src/utils/__tests__/dialogUtil.test.ts
@@ -38,7 +38,7 @@ const dialogsMap = {
},
};
-const dialogs = ([
+const dialogs = [
{
content: {
$kind: 'kind1',
@@ -57,7 +57,7 @@ const dialogs = ([
displayName: 'toBeCleaned',
id: 'id3',
},
-] as unknown) as DialogInfo[];
+] as unknown as DialogInfo[];
describe('getDialogData', () => {
it('return empty string if no dialogId', () => {
diff --git a/Composer/packages/client/src/utils/__tests__/lgUtil.test.ts b/Composer/packages/client/src/utils/__tests__/lgUtil.test.ts
index 2bbcd7986b..f237c6a6f6 100644
--- a/Composer/packages/client/src/utils/__tests__/lgUtil.test.ts
+++ b/Composer/packages/client/src/utils/__tests__/lgUtil.test.ts
@@ -8,6 +8,7 @@ import { createMissingLgTemplatesForDialogs } from '../lgUtil';
jest.mock('../../recoilModel/parsers/lgWorker', () => {
return {
addTemplates: (projectId, lgFile, templatesToAdd, lgFiles) =>
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
require('@bfc/indexers/lib/utils/lgUtil').addTemplates(lgFile, templatesToAdd),
};
});
diff --git a/Composer/packages/client/src/utils/__tests__/navigation.test.ts b/Composer/packages/client/src/utils/__tests__/navigation.test.ts
index a08005f9c5..ab4fdcf80d 100644
--- a/Composer/packages/client/src/utils/__tests__/navigation.test.ts
+++ b/Composer/packages/client/src/utils/__tests__/navigation.test.ts
@@ -35,7 +35,7 @@ describe('composer url util', () => {
selected: 'triggers[0]',
focused: 'triggers[0].actions[0]',
promptTab: PromptTab.BOT_ASKS,
- }
+ },
);
expect(result1).toEqual(true);
const result2 = checkUrl(`test`, projectId, skillId, {
@@ -57,7 +57,7 @@ describe('composer url util', () => {
selected: 'triggers[0]',
focused: 'triggers[0].actions[0]',
promptTab: PromptTab.BOT_ASKS,
- }
+ },
);
expect(result1).toEqual(true);
const result2 = checkUrl(`test`, projectId, skillId, {
@@ -74,16 +74,16 @@ describe('composer url util', () => {
expect(result1).toEqual(`/bot/${projectId}/skill/${skillId}/dialogs/main`);
const result2 = convertPathToUrl(projectId, skillId, 'main', 'main.triggers[0].actions[0]');
expect(result2).toEqual(
- `/bot/${projectId}/skill/${skillId}/dialogs/main?selected=triggers[0]&focused=triggers[0].actions[0]`
+ `/bot/${projectId}/skill/${skillId}/dialogs/main?selected=triggers[0]&focused=triggers[0].actions[0]`,
);
const result3 = convertPathToUrl(
projectId,
skillId,
'main',
- 'main.triggers[0].actions[0]#Microsoft.TextInput#prompt'
+ 'main.triggers[0].actions[0]#Microsoft.TextInput#prompt',
);
expect(result3).toEqual(
- `/bot/${projectId}/skill/${skillId}/dialogs/main?selected=triggers[0]&focused=triggers[0].actions[0]#botAsks`
+ `/bot/${projectId}/skill/${skillId}/dialogs/main?selected=triggers[0]&focused=triggers[0].actions[0]#botAsks`,
);
const result4 = convertPathToUrl(projectId, null, 'main');
expect(result4).toEqual(`/bot/${projectId}/dialogs/main`);
diff --git a/Composer/packages/client/src/utils/auth.ts b/Composer/packages/client/src/utils/auth.ts
index 738bb2c19f..91ae4c7629 100644
--- a/Composer/packages/client/src/utils/auth.ts
+++ b/Composer/packages/client/src/utils/auth.ts
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-/* eslint-disable @typescript-eslint/camelcase */
import { randomBytes } from 'crypto';
import querystring from 'query-string';
@@ -14,8 +13,7 @@ import { authConfig, authUrl } from '../constants';
import storage from './storage';
import httpClient from './httpUtil';
-import { isElectron } from './electronUtil';
-import { platform, OS } from './os';
+import { isOneAuthEnabled } from './oneAuthUtil';
export function decodeToken(token: string) {
try {
@@ -102,7 +100,7 @@ export function prepareAxios() {
}
return Promise.reject(err);
- }
+ },
);
}
}
@@ -212,7 +210,7 @@ export function createPopupWindow(loginUrl: string): Window | null {
const popup = window.open(
loginUrl,
formatMessage('Login to Azure'),
- `width=483, height=600, top=${top}, left=${left}`
+ `width=483, height=600, top=${top}, left=${left}`,
);
// if popups are blocked, use a redirect flow
@@ -237,7 +235,7 @@ export function createHiddenIframe(url: string): HTMLIFrameElement {
export async function monitorWindowForQueryParam(
popup: Window,
queryParam: string,
- redirectUrl: string
+ redirectUrl: string,
): Promise {
return new Promise((resolve) => {
const startTime = Date.now();
@@ -340,9 +338,8 @@ export function getAccessTokenUrl(options: { clientId: string; redirectUrl: stri
}
export function userShouldProvideTokens(): boolean {
- // If it's electron build and not running on Linux use oneAuth, otherwise ask user to manually enter tokens.
- const os = platform();
- if (isElectron() && os !== OS.Linux) {
+ // If it is enabled use OneAuth, otherwise ask user to manually enter tokens.
+ if (isOneAuthEnabled()) {
return false;
} else return !(authConfig.clientId && authConfig.redirectUrl && authConfig.tenantId);
}
diff --git a/Composer/packages/client/src/utils/authClient.ts b/Composer/packages/client/src/utils/authClient.ts
index c3106a9ad5..83194b19da 100644
--- a/Composer/packages/client/src/utils/authClient.ts
+++ b/Composer/packages/client/src/utils/authClient.ts
@@ -50,7 +50,7 @@ async function getAccessToken(options: AuthParameters): Promise {
if (!idToken) {
// pop up window if token not exist
const popup = createPopupWindow(
- getIdTokenUrl({ clientId: authConfig.clientId, redirectUrl: authConfig.redirectUrl })
+ getIdTokenUrl({ clientId: authConfig.clientId, redirectUrl: authConfig.redirectUrl }),
);
if (popup) {
idToken = await monitorWindowForQueryParam(popup, 'id_token', authConfig.redirectUrl);
@@ -59,7 +59,7 @@ async function getAccessToken(options: AuthParameters): Promise {
} else if (isTokenExpired(idToken)) {
// refresh idToken
const notDisplayFrame = createHiddenIframe(
- getIdTokenUrl({ clientId: authConfig.clientId, redirectUrl: authConfig.redirectUrl })
+ getIdTokenUrl({ clientId: authConfig.clientId, redirectUrl: authConfig.redirectUrl }),
);
idToken =
notDisplayFrame.contentWindow &&
@@ -70,7 +70,7 @@ async function getAccessToken(options: AuthParameters): Promise {
// use id token to get access token
if (typeof idToken === 'string') {
const notDisplayFrame = createHiddenIframe(
- getAccessTokenUrl({ clientId: authConfig.clientId, redirectUrl: authConfig.redirectUrl, scopes: scopes })
+ getAccessTokenUrl({ clientId: authConfig.clientId, redirectUrl: authConfig.redirectUrl, scopes: scopes }),
);
token =
notDisplayFrame.contentWindow &&
diff --git a/Composer/packages/client/src/utils/buildUtil.ts b/Composer/packages/client/src/utils/buildUtil.ts
index c9d1c07841..85bcc1ebc5 100644
--- a/Composer/packages/client/src/utils/buildUtil.ts
+++ b/Composer/packages/client/src/utils/buildUtil.ts
@@ -20,7 +20,7 @@ export function createCrossTrainConfig(dialogs: DialogInfo[], luFiles: LuFile[],
if (!luFile) return result;
const filtered = intentTriggers.filter((intentTrigger) =>
- luFile.intents.find((intent) => intent.Name === intentTrigger.intent || intentTrigger.intent === '')
+ luFile.intents.find((intent) => intent.Name === intentTrigger.intent || intentTrigger.intent === ''),
);
if (!filtered.length) return result;
diff --git a/Composer/packages/client/src/utils/convertUtils/__tests__/designerPathEncoder.test.ts b/Composer/packages/client/src/utils/convertUtils/__tests__/designerPathEncoder.test.ts
index e37d75b939..31277021d8 100644
--- a/Composer/packages/client/src/utils/convertUtils/__tests__/designerPathEncoder.test.ts
+++ b/Composer/packages/client/src/utils/convertUtils/__tests__/designerPathEncoder.test.ts
@@ -59,13 +59,13 @@ describe('decodeDesignerPathToArrayPath()', () => {
it('can handle invalid designer path.', () => {
expect(decodeDesignerPathToArrayPath(dialog, `triggers["1234"].actions["9999"]`)).toEqual(
- `triggers["1234"].actions["9999"]`
+ `triggers["1234"].actions["9999"]`,
);
expect(decodeDesignerPathToArrayPath(dialog, `triggers["5678"].actions["1234"]`)).toEqual(
- `triggers["5678"].actions["1234"]`
+ `triggers["5678"].actions["1234"]`,
);
expect(decodeDesignerPathToArrayPath(dialog, `dialogs["1234"].actions["5678"]`)).toEqual(
- `dialogs["1234"].actions["5678"]`
+ `dialogs["1234"].actions["5678"]`,
);
});
diff --git a/Composer/packages/client/src/utils/convertUtils/__tests__/parsePathToFocused.test.ts b/Composer/packages/client/src/utils/convertUtils/__tests__/parsePathToFocused.test.ts
index 77ab4e3027..91ea541637 100644
--- a/Composer/packages/client/src/utils/convertUtils/__tests__/parsePathToFocused.test.ts
+++ b/Composer/packages/client/src/utils/convertUtils/__tests__/parsePathToFocused.test.ts
@@ -9,7 +9,7 @@ describe('parsePathToFocused', () => {
expect(parsePathToFocused('main.triggers[0].actions[0]')).toBe('triggers[0].actions[0]');
expect(parsePathToFocused('main.triggers[0].actions[0].actions[1]')).toBe('triggers[0].actions[0].actions[1]');
expect(parsePathToFocused('main.triggers[0].actions[0].elseActions[1]')).toBe(
- 'triggers[0].actions[0].elseActions[1]'
+ 'triggers[0].actions[0].elseActions[1]',
);
});
});
diff --git a/Composer/packages/client/src/utils/dialogUtil.ts b/Composer/packages/client/src/utils/dialogUtil.ts
index 15c8bcda27..7effaf04e0 100644
--- a/Composer/packages/client/src/utils/dialogUtil.ts
+++ b/Composer/packages/client/src/utils/dialogUtil.ts
@@ -151,7 +151,7 @@ export function generateNewDialog(
dialogs: DialogInfo[],
dialogId: string,
data: TriggerFormData,
- schema: any
+ schema: any,
): DialogInfo {
//add new trigger
const dialog = dialogs.find((dialog) => dialog.id === dialogId);
@@ -173,7 +173,7 @@ export function deleteTrigger(
dialogs: DialogInfo[],
dialogId: string,
index: number,
- callbackOnDeletedTrigger?: (trigger: ITriggerCondition) => any
+ callbackOnDeletedTrigger?: (trigger: ITriggerCondition) => any,
) {
let dialogCopy = getDialog(dialogs, dialogId);
if (!dialogCopy) return null;
@@ -191,7 +191,7 @@ export function deleteTrigger(
}
function getDialogsMap(dialogs: DialogInfo[]): DialogsMap {
- return dialogs.reduce((result: { [key: string]: {} }, dialog: DialogInfo) => {
+ return dialogs.reduce((result: { [key: string]: Record }, dialog: DialogInfo) => {
result[dialog.id] = dialog.content;
return result;
}, {});
diff --git a/Composer/packages/client/src/utils/electronUtil.ts b/Composer/packages/client/src/utils/electronUtil.ts
index 8202004574..70bc6e8086 100644
--- a/Composer/packages/client/src/utils/electronUtil.ts
+++ b/Composer/packages/client/src/utils/electronUtil.ts
@@ -28,7 +28,7 @@ export type Profile = ABSProfile; // can include PVAProfile or other type of pro
*/
export async function getPublishProfileFromPayload(
profile: Profile,
- source: string
+ source: string,
): Promise {
try {
const result = await httpClient.post(`/import/${source}/generateProfile`, profile);
diff --git a/Composer/packages/client/src/utils/hooks.ts b/Composer/packages/client/src/utils/hooks.ts
index 1701bf53e8..45d4796f32 100644
--- a/Composer/packages/client/src/utils/hooks.ts
+++ b/Composer/packages/client/src/utils/hooks.ts
@@ -109,8 +109,8 @@ export const useProjectIdCache = () => {
return projectId;
};
-export function useInterval(callback: Function, delay: number | null) {
- const savedCallback: MutableRefObject = useRef();
+export function useInterval(callback: () => void, delay: number | null) {
+ const savedCallback: MutableRefObject<(() => void) | undefined> = useRef();
// Remember the latest callback.
useEffect(() => {
@@ -133,9 +133,9 @@ export function useInterval(callback: Function, delay: number | null) {
export function useClickOutsideOutsideTarget(
targetRefs: MutableRefObject[] | null,
- callback: Function
+ callback: (...args: any[]) => void,
) {
- const savedCallback: MutableRefObject = useRef();
+ const savedCallback: MutableRefObject<((...args: any[]) => void) | undefined> = useRef();
const isClickInsideTargets = (currentClickTarget: Node) => {
const isClickedInside = targetRefs?.find((ref) => {
diff --git a/Composer/packages/client/src/utils/lgUtil.ts b/Composer/packages/client/src/utils/lgUtil.ts
index 95c0d8627b..644b24c608 100644
--- a/Composer/packages/client/src/utils/lgUtil.ts
+++ b/Composer/packages/client/src/utils/lgUtil.ts
@@ -15,7 +15,7 @@ import { getBaseName } from './fileUtil';
export const createMissingLgTemplatesForDialogs = async (
projectId: string,
dialogs: DialogInfo[],
- lgFiles: LgFile[]
+ lgFiles: LgFile[],
): Promise => {
const updatedLgFiles: LgFile[] = [];
diff --git a/Composer/packages/client/src/utils/luUtil.ts b/Composer/packages/client/src/utils/luUtil.ts
index 06f4ceb2b9..47f93af51c 100644
--- a/Composer/packages/client/src/utils/luUtil.ts
+++ b/Composer/packages/client/src/utils/luUtil.ts
@@ -30,7 +30,7 @@ export function getLuisBuildLuFiles(luFiles: LuFile[], dialogs: DialogInfo[]) {
const idWithoutLocale = getBaseName(file.id);
return dialogs.some(
(dialog) =>
- dialog.luFile === idWithoutLocale && dialog.luProvider !== SDKKinds.OrchestratorRecognizer && !file.empty
+ dialog.luFile === idWithoutLocale && dialog.luProvider !== SDKKinds.OrchestratorRecognizer && !file.empty,
);
});
}
@@ -47,7 +47,7 @@ function generateErrorMessage(invalidLuFile: LuFile[]) {
export function checkLuisBuild(luFiles: LuFile[], dialogs: DialogInfo[]) {
const referred = getReferredLuFiles(luFiles, dialogs, false);
const invalidLuFile = referred.filter(
- (file) => file.diagnostics.filter((n) => n.severity === DiagnosticSeverity.Error).length !== 0
+ (file) => file.diagnostics.filter((n) => n.severity === DiagnosticSeverity.Error).length !== 0,
);
if (invalidLuFile.length !== 0) {
const msg = generateErrorMessage(invalidLuFile);
diff --git a/Composer/packages/client/src/utils/navigation.ts b/Composer/packages/client/src/utils/navigation.ts
index 764938c358..e9d101b346 100644
--- a/Composer/packages/client/src/utils/navigation.ts
+++ b/Composer/packages/client/src/utils/navigation.ts
@@ -42,7 +42,7 @@ export function checkUrl(
currentUri: string,
projectId: string,
skillId: string | null,
- { dialogId, selected, focused, promptTab }: DesignPageLocation
+ { dialogId, selected, focused, promptTab }: DesignPageLocation,
) {
let lastUri =
skillId == null
@@ -62,7 +62,7 @@ export function convertPathToUrl(
projectId: string,
skillId: string | null,
dialogId: string | null,
- path?: string
+ path?: string,
): string {
//path is like main.triggers[0].actions[0]
//uri = id?selected=triggers[0]&focused=triggers[0].actions[0]
diff --git a/Composer/packages/client/src/utils/oneAuthUtil.ts b/Composer/packages/client/src/utils/oneAuthUtil.ts
new file mode 100644
index 0000000000..9c61db36b5
--- /dev/null
+++ b/Composer/packages/client/src/utils/oneAuthUtil.ts
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { isElectron } from './electronUtil';
+
+let isEnabled = false;
+
+export const isOneAuthEnabled = () => isElectron() && isEnabled;
+
+export const setOneAuthEnabled = (enabled: boolean) => (isEnabled = enabled);
diff --git a/Composer/packages/client/src/utils/pageLinks.ts b/Composer/packages/client/src/utils/pageLinks.ts
index 48ebaacbdc..67ae9570e3 100644
--- a/Composer/packages/client/src/utils/pageLinks.ts
+++ b/Composer/packages/client/src/utils/pageLinks.ts
@@ -22,7 +22,7 @@ export const topLinks = (
showFormDialog: boolean,
schema: any,
skillIsRemote: boolean,
- rootProjectId?: string
+ rootProjectId?: string,
) => {
const isPVASchema = checkForPVASchema(schema);
const botLoaded = !!projectId;
diff --git a/Composer/packages/client/src/utils/publishStatusPollingUpdater.ts b/Composer/packages/client/src/utils/publishStatusPollingUpdater.ts
index 413b724810..ac4ae1ea7c 100644
--- a/Composer/packages/client/src/utils/publishStatusPollingUpdater.ts
+++ b/Composer/packages/client/src/utils/publishStatusPollingUpdater.ts
@@ -79,7 +79,7 @@ export class PublishStatusPollingUpdater {
this.fetchPublishStatusData(this.botProjectId, this.publishTargetName, onData);
this.timerId = window.setInterval(
async () => this.fetchPublishStatusData(this.botProjectId, this.publishTargetName, onData),
- this.pollingInterval
+ this.pollingInterval,
);
}
diff --git a/Composer/packages/client/src/utils/qnaUtil.ts b/Composer/packages/client/src/utils/qnaUtil.ts
index fb40dd89f1..e56822a8f9 100644
--- a/Composer/packages/client/src/utils/qnaUtil.ts
+++ b/Composer/packages/client/src/utils/qnaUtil.ts
@@ -94,7 +94,7 @@ export const copyQnAFilesOnOtherLocales = (
projectId: string,
dialogIds: string[],
qnaFiles: QnAFile[],
- locales: string[]
+ locales: string[],
): QnAFile[] => {
const originalSourceQnAFiles = qnaFiles.filter((f) => f.id.endsWith('.source'));
const containerQnAFileIds = dialogIds.map((d) => `${d}.en-us`);
@@ -136,7 +136,7 @@ export const migrateQnAFiles = (
projectId: string,
dialogIds: string[],
qnaFiles: QnAFile[],
- locales: string[]
+ locales: string[],
): QnAFile[] => {
// migrate script move qna pairs in *.qna to *-manual.source.qna.
const updateQnAFiles1 = reformQnAToContainerKB(projectId, qnaFiles, locales);
diff --git a/Composer/packages/client/src/utils/runtimeErrors.ts b/Composer/packages/client/src/utils/runtimeErrors.ts
index 7d458bea33..148fc18126 100644
--- a/Composer/packages/client/src/utils/runtimeErrors.ts
+++ b/Composer/packages/client/src/utils/runtimeErrors.ts
@@ -19,8 +19,7 @@ export const missingFunctionsError = {
message: formatMessage('To run this bot, Composer needs Azure Functions Core Tools.'),
linkAfterMessage: {
text: formatMessage('Learn more'),
- url:
- 'https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#install-the-azure-functions-core-tools',
+ url: 'https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#install-the-azure-functions-core-tools',
},
link: {
text: formatMessage('Install Azure Functions'),
diff --git a/Composer/packages/client/src/utils/urlUtil.ts b/Composer/packages/client/src/utils/urlUtil.ts
new file mode 100644
index 0000000000..456ae20068
--- /dev/null
+++ b/Composer/packages/client/src/utils/urlUtil.ts
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/* Returns true if the url is different than the local domain. */
+export const isExternalLink = (url: string): boolean => {
+ const { origin } = location;
+ const parsedUrl = new URL(url, origin);
+ return parsedUrl.origin !== origin;
+};
diff --git a/Composer/packages/electron-server/AUTH.md b/Composer/packages/electron-server/AUTH.md
index 05c048201f..9e43d302df 100644
--- a/Composer/packages/electron-server/AUTH.md
+++ b/Composer/packages/electron-server/AUTH.md
@@ -6,6 +6,8 @@ Authentication in Composer is done using the OneAuth native node library.
This library leverages APIs within the user's OS to store and retrieve credentials in a compliant fashion, and allows Composer to get access tokens on behalf of the user once the user signs in.
+Note: in some cases you might want to disable OneAuth and provide required tokens directly. To do so set the `COMPOSER_ENABLE_ONEAUTH` to `false`.
+
We disable this authentication flow by default in the development environment. To use the flow in a dev environment, please follow the steps below to leverage the OneAuth library.
## Requirements
diff --git a/Composer/packages/electron-server/__tests__/auth/oneAuthService.test.ts b/Composer/packages/electron-server/__tests__/auth/oneAuthService.test.ts
index 401cc15bc7..a91f89a0f6 100644
--- a/Composer/packages/electron-server/__tests__/auth/oneAuthService.test.ts
+++ b/Composer/packages/electron-server/__tests__/auth/oneAuthService.test.ts
@@ -153,8 +153,7 @@ describe('OneAuth Serivce', () => {
it('should return the shim on Linux', async () => {
Object.assign(process.env, { ...process.env, COMPOSER_ENABLE_ONEAUTH: 'true', TEST_IS_LINUX: 'true' });
- // eslint-disable-next-line @typescript-eslint/no-var-requires
- const { OneAuthService: service } = require('../../src/auth/oneAuthService');
+ const { OneAuthService: service } = require('../../src/auth/oneAuthService');
const result = await service.getAccessToken({});
expect(result).toEqual({ accessToken: '', acquiredAt: 0, expiryTime: 99999999999 });
@@ -167,8 +166,7 @@ describe('OneAuth Serivce', () => {
NODE_ENV: 'development',
TEST_IS_LINUX: 'false',
});
- // eslint-disable-next-line @typescript-eslint/no-var-requires
- const { OneAuthService: service } = require('../../src/auth/oneAuthService');
+ const { OneAuthService: service } = require('../../src/auth/oneAuthService');
const result = await service.getAccessToken({});
expect(result).toEqual({ accessToken: '', acquiredAt: 0, expiryTime: 99999999999 });
diff --git a/Composer/packages/electron-server/package.json b/Composer/packages/electron-server/package.json
index d0f5a9961a..97b6b0668e 100644
--- a/Composer/packages/electron-server/package.json
+++ b/Composer/packages/electron-server/package.json
@@ -2,7 +2,7 @@
"name": "@bfc/electron-server",
"license": "MIT",
"author": "Microsoft Corporation",
- "version": "2.1.2",
+ "version": "2.1.3",
"description": "Electron wrapper around Composer that launches Composer as a desktop application.",
"main": "./build/main.js",
"engines": {
@@ -10,7 +10,7 @@
},
"scripts": {
"build": "tsc -b tsconfig.build.json && ncp src/preload.js build/preload.js",
- "clean": "rimraf build && rimraf dist && rimraf l10ntemp",
+ "clean": "rimraf build dist l10ntemp .swc",
"copy-artifacts": "node scripts/copy-artifacts.js",
"dist": "node scripts/electronBuilderDist.js",
"dist:full": "yarn clean && yarn build && yarn run pack && yarn copy-artifacts && yarn dist",
@@ -28,7 +28,7 @@
},
"devDependencies": {
"@babel/plugin-proposal-class-properties": "7.18.6",
- "@babel/plugin-transform-runtime": "7.18.6",
+ "@babel/plugin-transform-runtime": "7.24.0",
"@botframework-composer/test-utils": "0.0.1",
"@types/archiver": "^3.1.0",
"@types/body-parser": "^1.17.0",
@@ -49,7 +49,7 @@
"@types/rimraf": "^2.0.2",
"cross-env": "7.0.3",
"electron": "14.2.6",
- "electron-builder": "^22.6.0",
+ "electron-builder": "23.6.0",
"globby": "^11.0.1",
"js-yaml": "^3.13.1",
"mock-fs": "^4.10.1",
@@ -73,7 +73,7 @@
"lodash": "^4.17.19",
"node-fetch": "2.6.7",
"semver": "7.3.2",
- "tslib": "2.4.0",
+ "tslib": "2.6.2",
"uuid": "7.0.0"
},
"peerDependencies": {
diff --git a/Composer/packages/electron-server/src/auth/isOneAuthEnabled.ts b/Composer/packages/electron-server/src/auth/isOneAuthEnabled.ts
new file mode 100644
index 0000000000..3b74dc3a49
--- /dev/null
+++ b/Composer/packages/electron-server/src/auth/isOneAuthEnabled.ts
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// dev: allow force enable OneAuth, use shim by default
+// prod: allow to force enable the shim, use OneAuth by default
+// fallback to the shim if OS is not supported in any case
+export const isOneAuthEnabled =
+ ['darwin', 'win32'].includes(process.platform) &&
+ ((process.env.COMPOSER_ENABLE_ONEAUTH !== 'false' && process.env.NODE_ENV !== 'development') ||
+ (process.env.COMPOSER_ENABLE_ONEAUTH === 'true' && process.env.NODE_ENV === 'development'));
diff --git a/Composer/packages/electron-server/src/auth/oneAuthBase.ts b/Composer/packages/electron-server/src/auth/oneAuthBase.ts
index 86dd760ffb..e8167cdf80 100644
--- a/Composer/packages/electron-server/src/auth/oneAuthBase.ts
+++ b/Composer/packages/electron-server/src/auth/oneAuthBase.ts
@@ -4,8 +4,8 @@
import { ElectronAuthParameters } from '@botframework-composer/types';
export abstract class OneAuthBase {
- abstract async getAccessToken(
- params: ElectronAuthParameters
+ abstract getAccessToken(
+ params: ElectronAuthParameters,
): Promise<{ accessToken: string; acquiredAt: number; expiryTime: number }>;
abstract shutdown();
abstract signOut();
diff --git a/Composer/packages/electron-server/src/auth/oneAuthService.ts b/Composer/packages/electron-server/src/auth/oneAuthService.ts
index 60c55f6411..bcff4cd507 100644
--- a/Composer/packages/electron-server/src/auth/oneAuthService.ts
+++ b/Composer/packages/electron-server/src/auth/oneAuthService.ts
@@ -7,7 +7,7 @@ import { app } from 'electron';
import fetch from '../utility/fetch';
import ElectronWindow from '../electronWindow';
-import { isLinux, isMac } from '../utility/platform';
+import { isMac } from '../utility/platform';
import logger from '../utility/logger';
import { getUnpackedAsarPath } from '../utility/getUnpackedAsarPath';
import { isDevelopment } from '../utility/env';
@@ -15,6 +15,7 @@ import { isDevelopment } from '../utility/env';
import { OneAuth } from './oneauth';
import { OneAuthShim } from './oneAuthShim';
import { OneAuthBase } from './oneAuthBase';
+import { isOneAuthEnabled } from './isOneAuthEnabled';
const log = logger.extend('one-auth');
@@ -90,19 +91,19 @@ export class OneAuthInstance extends OneAuthBase {
COMPOSER_APP_VERSION,
DEFAULT_LOCALE,
'Please login',
- window.getNativeWindowHandle()
+ window.getNativeWindowHandle(),
);
const msaConfig = new this.oneAuth.MsaConfiguration(
COMPOSER_CLIENT_ID,
COMPOSER_REDIRECT_URI,
GRAPH_RESOURCE + '/Application.ReadWrite.All',
- undefined
+ undefined,
);
const aadConfig = new this.oneAuth.AadConfiguration(
COMPOSER_CLIENT_ID,
COMPOSER_REDIRECT_URI,
GRAPH_RESOURCE,
- false // prefer broker
+ false, // prefer broker
);
this.oneAuth.setFlights([Flight.UseMsalforMsa]);
this.oneAuth.initialize(appConfig, msaConfig, aadConfig, undefined);
@@ -114,7 +115,7 @@ export class OneAuthInstance extends OneAuthBase {
}
public async getAccessToken(
- params: ElectronAuthParameters
+ params: ElectronAuthParameters,
): Promise<{ accessToken: string; acquiredAt: number; expiryTime: number }> {
try {
if (!this.initialized) {
@@ -149,10 +150,10 @@ export class OneAuthInstance extends OneAuthBase {
params.authority || DEFAULT_AUTH_AUTHORITY,
params.targetResource,
this.signedInAccount.realm,
- ''
+ '',
);
const result = await this.oneAuth.acquireCredentialSilently(this.signedInAccount?.id, reqParams, '');
- if (result.credential && result.credential.value) {
+ if (result.credential?.value) {
log('Acquired access token. %s', result.credential.value);
return {
accessToken: result.credential.value,
@@ -171,10 +172,10 @@ export class OneAuthInstance extends OneAuthBase {
params.authority || DEFAULT_AUTH_AUTHORITY,
params.targetResource,
this.signedInAccount.realm,
- ''
+ '',
);
const result = await this.oneAuth.acquireCredentialInteractively(this.signedInAccount?.id, reqParams, '');
- if (result.credential && result.credential.value) {
+ if (result.credential?.value) {
log('Acquired access token interactively. %s', result.credential.value);
return {
accessToken: result.credential.value,
@@ -245,10 +246,10 @@ export class OneAuthInstance extends OneAuthBase {
`https://login.microsoftonline.com/${tenantId}`,
ARM_RESOURCE,
'',
- ''
+ '',
);
const result = await this.oneAuth.acquireCredentialSilently(this.signedInARMAccount.id, tokenParams, '');
- if (result.credential && result.credential.value && Date.now() <= result.credential.expiresOn) {
+ if (result.credential?.value && Date.now() <= result.credential.expiresOn) {
log('Acquired ARM token for tenant: %s', result.credential.value);
return result.credential.value;
}
@@ -257,7 +258,7 @@ export class OneAuthInstance extends OneAuthBase {
log(
'There was an error trying to silently get an ARM token for tenant %s: %O. Trying again interactively to get access token.',
tenantId,
- e
+ e,
);
// use the signed in account to acquire a token
@@ -266,10 +267,10 @@ export class OneAuthInstance extends OneAuthBase {
`https://login.microsoftonline.com/${tenantId}`,
ARM_RESOURCE,
'',
- ''
+ '',
);
const result = await this.oneAuth.acquireCredentialInteractively(this.signedInARMAccount?.id, reqParams, '');
- if (result.credential && result.credential.value && Date.now() <= result.credential.expiresOn) {
+ if (result.credential?.value && Date.now() <= result.credential.expiresOn) {
log('Acquired ARM token interactively. %s', result.credential.value);
return result.credential.value;
}
@@ -285,7 +286,7 @@ export class OneAuthInstance extends OneAuthBase {
`https://login.microsoftonline.com/${tenantId}`,
ARM_RESOURCE,
'',
- ''
+ '',
);
const result = await this.oneAuth.acquireCredentialInteractively(this.signedInARMAccount.id, tokenParams, '');
if (!result.credential.value) {
@@ -335,7 +336,7 @@ export class OneAuthInstance extends OneAuthBase {
/** Temporary workaround on Mac until we figure out how to enable keychain access on a dev build. */
// eslint-disable-next-line
private async TEMPORARY_getAccessTokenOnMacDev(
- params: ElectronAuthParameters
+ params: ElectronAuthParameters,
): Promise<{ accessToken: string; acquiredAt: number; expiryTime: number }> {
try {
// sign-in every time with auth parameters to get a token
@@ -344,7 +345,7 @@ export class OneAuthInstance extends OneAuthBase {
params.authority || DEFAULT_AUTH_AUTHORITY,
params.targetResource,
'',
- ''
+ '',
);
const result = await this.oneAuth.signInInteractively(undefined, reqParams, '');
if (result?.credential?.value) {
@@ -366,7 +367,7 @@ export class OneAuthInstance extends OneAuthBase {
if (!this._oneAuth) {
log('Attempting to load oneauth module from %s.', this.oneauthPath);
try {
- // eslint-disable-next-line security/detect-non-literal-require
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, security/detect-non-literal-require
this._oneAuth = require(this.oneauthPath) as typeof OneAuth;
} catch (e) {
log('Error loading oneauth module. %O', e);
@@ -390,7 +391,6 @@ export class OneAuthInstance extends OneAuthBase {
}
}
-// only use the shim in Linux, or dev environment without flag enabled
-const useShim = (isDevelopment && process.env.COMPOSER_ENABLE_ONEAUTH !== 'true') || isLinux();
+const useShim = !isOneAuthEnabled;
export const OneAuthService = useShim ? new OneAuthShim() : new OneAuthInstance();
diff --git a/Composer/packages/electron-server/src/auth/oneauth.d.ts b/Composer/packages/electron-server/src/auth/oneauth.d.ts
index 5fd78ec6e0..c13a1be2f5 100644
--- a/Composer/packages/electron-server/src/auth/oneauth.d.ts
+++ b/Composer/packages/electron-server/src/auth/oneauth.d.ts
@@ -192,7 +192,7 @@ export namespace OneAuth {
appVersion: string,
languageCode: string,
signInWindowTitle: string | undefined,
- parentWindow: any | undefined
+ parentWindow: any | undefined,
);
readonly appId: string;
readonly appName: string;
@@ -212,7 +212,7 @@ export namespace OneAuth {
clientId: string,
redirectUri: string,
defaultSignInScope: string,
- useMsalFlight: boolean | undefined // deprecated
+ useMsalFlight: boolean | undefined, // deprecated
);
readonly clientId: string;
readonly redirectUri: string;
@@ -237,7 +237,7 @@ export namespace OneAuth {
appConfiguration: AppConfiguration,
msaConfiguration: MsaConfiguration | undefined,
aadConfiguration: AadConfiguration | undefined,
- telemetryConfiguration: TelemetryConfiguration | undefined
+ telemetryConfiguration: TelemetryConfiguration | undefined,
): boolean;
/// Cancels all outstanding tasks, closes the authentication UI if any, and shuts down the OneAuth authenticator.
@@ -313,7 +313,7 @@ export namespace OneAuth {
export function signInInteractively(
accountHint: string | undefined,
authParameters: AuthParameters | undefined,
- correlationId: string
+ correlationId: string,
): Promise;
/// Sign in a user to the app silently with an account inferred from the underlying OS infrastructure, if such
@@ -350,7 +350,7 @@ export namespace OneAuth {
/// @see {@link AuthResult}
export function signInSilently(
authParameters: AuthParameters | undefined,
- correlationId: string
+ correlationId: string,
): Promise;
/// Show a prompt for the given account and parameters.
@@ -388,7 +388,7 @@ export namespace OneAuth {
export function acquireCredentialInteractively(
accountId: string,
authParameters: AuthParameters,
- correlationId: string
+ correlationId: string,
): Promise;
/// Acquire a credential silently for the given account and parameters.
@@ -424,7 +424,7 @@ export namespace OneAuth {
export function acquireCredentialSilently(
accountId: string,
authParameters: AuthParameters,
- correlationId: string
+ correlationId: string,
): Promise;
/// Cancels all ongoing tasks and dismisses the UI (if any).
@@ -542,7 +542,7 @@ export namespace OneAuth {
audienceType: AudienceType,
sessionId: string,
dispatcher: TelemetryDispatcher | undefined,
- allowedResources: string[]
+ allowedResources: string[],
): TelemetryConfiguration;
}
diff --git a/Composer/packages/electron-server/src/auth/oneauthShim/index.ts b/Composer/packages/electron-server/src/auth/oneauthShim/index.ts
index 57d5839dcf..a0315ca0ef 100644
--- a/Composer/packages/electron-server/src/auth/oneauthShim/index.ts
+++ b/Composer/packages/electron-server/src/auth/oneauthShim/index.ts
@@ -3,7 +3,7 @@
import { OneAuth } from '../oneauth';
-export const oneauthShim = ({
+export const oneauthShim = {
initialize() {},
shutdown() {},
setLogPiiEnabled() {},
@@ -15,5 +15,5 @@ export const oneauthShim = ({
AuthParameters() {},
AuthResult() {},
Account() {},
-} as unknown) as typeof OneAuth;
+} as unknown as typeof OneAuth;
export default oneauthShim;
diff --git a/Composer/packages/electron-server/src/main.ts b/Composer/packages/electron-server/src/main.ts
index a3338f5b8a..dca9cb8be2 100644
--- a/Composer/packages/electron-server/src/main.ts
+++ b/Composer/packages/electron-server/src/main.ts
@@ -25,6 +25,7 @@ import { isLinux, isMac, isWindows } from './utility/platform';
import { parseDeepLinkUrl } from './utility/url';
import { getMachineId } from './utility/machineId';
import { getSessionId } from './utility/sessionId';
+import { isOneAuthEnabled } from './auth/isOneAuthEnabled';
const env = log.extend('env');
env('%O', process.env);
@@ -205,13 +206,9 @@ async function main(show = false) {
}
})
.catch((e) =>
- console.error('[Windows] Error while waiting for main window to show before processing deep link: ', e)
+ console.error('[Windows] Error while waiting for main window to show before processing deep link: ', e),
);
}
-
- mainWindow.on('closed', () => {
- ElectronWindow.destroy();
- });
log('Rendered application.');
}
}
@@ -268,13 +265,55 @@ async function run() {
app.quit();
}
+ const getMainWindow = () => ElectronWindow.getInstance().browserWindow;
+
+ const initApp = async () => {
+ let mainWindow = getMainWindow();
+ if (!mainWindow) return;
+
+ mainWindow.webContents.send('session-update', 'session-started');
+
+ if (process.env.COMPOSER_DEV_TOOLS) {
+ mainWindow.webContents.openDevTools();
+ }
+
+ mainWindow.on('close', (event) => {
+ // when the window is not visible, it means that window.close
+ // has been called by the handler, so it is time to proceed
+ if (!mainWindow?.isVisible) {
+ return;
+ }
+
+ event.preventDefault();
+ mainWindow.hide();
+ mainWindow.webContents.send('session-update', 'session-ended');
+
+ // Give 30 seconds to close app gracefully, then proceed
+ Promise.race([
+ new Promise((resolve) => setTimeout(resolve, 30000)),
+ new Promise((resolve) => ipcMain.once('closed', () => resolve())),
+ ]).then(() => {
+ mainWindow?.close();
+ mainWindow = undefined;
+ ElectronWindow.destroy();
+
+ // preserve app icon in the dock on MacOS
+ if (isMac()) return;
+
+ process.emit('beforeExit', 0);
+ app.quit();
+ });
+
+ mainWindow.webContents.send('closing');
+ });
+ };
+
app.on('ready', async () => {
log('App ready');
log('Loading latest known locale');
loadLocale(currentAppLocale);
- const getMainWindow = () => ElectronWindow.getInstance().browserWindow;
const { startApp, updateStatus } = await initSplashScreen({
getMainWindow,
icon: join(__dirname, '../resources/composerIcon_1024x1024.png'),
@@ -292,42 +331,29 @@ async function run() {
await loadServer();
initSettingsListeners();
- await main();
-
- setTimeout(() => startApp(signalThatMainWindowIsShowing), 500);
- const mainWindow = getMainWindow();
const machineId = await getMachineId();
+ ipcMain.handle('app-init', () => {
+ return {
+ machineInfo: {
+ id: machineId,
+ os: os.platform(),
+ },
+ isOneAuthEnabled,
+ };
+ });
- mainWindow?.webContents.send('session-update', 'session-started');
-
- if (process.env.COMPOSER_DEV_TOOLS) {
- mainWindow?.webContents.openDevTools();
- }
-
- mainWindow?.webContents.send('machine-info', { id: machineId, os: os.platform() });
- });
-
- // Quit when all windows are closed.
- app.on('window-all-closed', () => {
- // On OS X it is common for applications and their menu bar
- // to stay active until the user quits explicitly with Cmd + Q
- if (!isMac()) {
- app.quit();
- }
- });
-
- app.on('before-quit', () => {
- const mainWindow = ElectronWindow.getInstance().browserWindow;
- mainWindow?.webContents.send('session-update', 'session-ended');
- mainWindow?.webContents.send('cleanup');
+ await main();
+ setTimeout(() => startApp(signalThatMainWindowIsShowing), 500);
+ await initApp();
});
- app.on('activate', () => {
+ app.on('activate', async () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (!ElectronWindow.isBrowserWindowCreated) {
- main(true);
+ await main(true);
+ initApp();
}
});
@@ -343,7 +369,7 @@ async function run() {
mainWindow?.loadURL(getBaseUrl() + deeplinkUrl);
})
.catch((e) =>
- console.error('[Mac] Error while waiting for main window to show before processing deep link: ', e)
+ console.error('[Mac] Error while waiting for main window to show before processing deep link: ', e),
);
});
}
diff --git a/Composer/packages/electron-server/src/preload.js b/Composer/packages/electron-server/src/preload.js
index 93f83baca9..e3473876d5 100644
--- a/Composer/packages/electron-server/src/preload.js
+++ b/Composer/packages/electron-server/src/preload.js
@@ -5,6 +5,7 @@ const { ipcRenderer, contextBridge } = require('electron'); // eslint-disable-li
// expose ipcRenderer to the browser
contextBridge.exposeInMainWorld('ipcRenderer', {
+ invoke: (...args) => ipcRenderer.invoke(...args),
send: (...args) => ipcRenderer.send(...args),
on: (...args) => ipcRenderer.on(...args),
});
diff --git a/Composer/packages/electron-server/src/splash/splashScreen.ts b/Composer/packages/electron-server/src/splash/splashScreen.ts
index 237d60f8fe..1d06683922 100644
--- a/Composer/packages/electron-server/src/splash/splashScreen.ts
+++ b/Composer/packages/electron-server/src/splash/splashScreen.ts
@@ -89,7 +89,7 @@ export const initSplashScreen = async ({
*/
const updateStatus = async (status: string) => {
await splashScreenWindow.webContents.executeJavaScript(
- `document.querySelector('#${statusElmId}').textContent = '${status}';`
+ `document.querySelector('#${statusElmId}').textContent = '${status}';`,
);
};
diff --git a/Composer/packages/electron-server/src/utility/fs.ts b/Composer/packages/electron-server/src/utility/fs.ts
index f64650da38..aeccfb53f1 100644
--- a/Composer/packages/electron-server/src/utility/fs.ts
+++ b/Composer/packages/electron-server/src/utility/fs.ts
@@ -7,7 +7,7 @@ import { existsSync, mkdirp, mkdirpSync, readFileSync, writeFile, writeFileSync
export const ensureDirectory = async (dirPath: string) => await mkdirp(dirPath);
-export const ensureJsonFileSync = (filePath: string, defaultContent: { [key: string]: {} }) => {
+export const ensureJsonFileSync = (filePath: string, defaultContent: { [key: string]: unknown }) => {
if (!existsSync(filePath)) {
mkdirpSync(path.dirname(filePath));
writeFileSync(filePath, JSON.stringify(defaultContent, null, 4), { encoding: 'utf8' });
diff --git a/Composer/packages/extension-client/package.json b/Composer/packages/extension-client/package.json
index a8b7d1d99c..9907d04465 100644
--- a/Composer/packages/extension-client/package.json
+++ b/Composer/packages/extension-client/package.json
@@ -8,7 +8,7 @@
"scripts": {
"build": "yarn clean && yarn build:ts",
"build:ts": "tsc --build tsconfig.build.json",
- "clean": "rimraf lib"
+ "clean": "rimraf lib .swc"
},
"peerDependencies": {
"@botframework-composer/types": "*",
@@ -22,11 +22,11 @@
"react": "16.13.1",
"react-dom": "16.13.1",
"rimraf": "3.0.2",
- "typescript": "3.9.2"
+ "typescript": "5.4.2"
},
"dependencies": {
"debug": "^4.1.1",
"lodash": "^4.17.19",
- "tslib": "2.4.0"
+ "tslib": "2.6.2"
}
}
diff --git a/Composer/packages/extension-client/src/hooks/useFormConfig.ts b/Composer/packages/extension-client/src/hooks/useFormConfig.ts
index d456948f92..1146862575 100644
--- a/Composer/packages/extension-client/src/hooks/useFormConfig.ts
+++ b/Composer/packages/extension-client/src/hooks/useFormConfig.ts
@@ -29,6 +29,9 @@ export function useFormConfig() {
Object.entries(result)
.filter(([$kind, options]) => options && isTrigger($kind))
.forEach(([, options]) => {
+ if (!options) {
+ return;
+ }
if (!options.hidden) {
options.hidden = ['actions'];
} else if (Array.isArray(options.hidden) && !options.hidden.some((x) => x === 'actions')) {
diff --git a/Composer/packages/extension/package.json b/Composer/packages/extension/package.json
index be59676e3c..b8ef53afb4 100644
--- a/Composer/packages/extension/package.json
+++ b/Composer/packages/extension/package.json
@@ -20,7 +20,7 @@
"@types/tar": "^4.0.3",
"json-schema": "0.4.0",
"rimraf": "3.0.2",
- "typescript": "^3.8.3"
+ "typescript": "5.4.2"
},
"dependencies": {
"@botframework-composer/types": "*",
@@ -34,6 +34,6 @@
"passport": "^0.4.1",
"path-to-regexp": "^6.1.0",
"tar": "^6.1.6",
- "tslib": "2.4.0"
+ "tslib": "2.6.2"
}
}
diff --git a/Composer/packages/extension/src/extensionRegistration.ts b/Composer/packages/extension/src/extensionRegistration.ts
index ba39a77829..f90c3a58c3 100644
--- a/Composer/packages/extension/src/extensionRegistration.ts
+++ b/Composer/packages/extension/src/extensionRegistration.ts
@@ -32,7 +32,7 @@ export class ExtensionRegistration implements IExtensionRegistration {
public context: IExtensionContext,
metadata: ExtensionMetadata,
private _getSettings: () => ExtensionSettings,
- private _dataDir: string
+ private _dataDir: string,
) {
this._name = metadata.id;
this._description = metadata.description;
diff --git a/Composer/packages/extension/src/storage/store.ts b/Composer/packages/extension/src/storage/store.ts
index 63d8b409df..ce51c713b6 100644
--- a/Composer/packages/extension/src/storage/store.ts
+++ b/Composer/packages/extension/src/storage/store.ts
@@ -10,7 +10,11 @@ export class Store {
private path: string;
private data: Partial;
- public constructor(storePath: string, private defaultValue: T, private _log?: debug.Debugger) {
+ public constructor(
+ storePath: string,
+ private defaultValue: T,
+ private _log?: debug.Debugger,
+ ) {
this.path = storePath;
this.data = { ...defaultValue };
diff --git a/Composer/packages/form-dialogs/package.json b/Composer/packages/form-dialogs/package.json
index 9c8c2d2066..8f027d3267 100644
--- a/Composer/packages/form-dialogs/package.json
+++ b/Composer/packages/form-dialogs/package.json
@@ -11,7 +11,7 @@
"lib/FormDialogSchemaEditor.d.ts"
],
"scripts": {
- "clean": "rimraf lib dist",
+ "clean": "rimraf lib dist .swc",
"start": "node tools/devServer.js",
"build": "yarn clean && yarn build:ts",
"build:ts": "tsc --build ./tsconfig.lib.json",
@@ -23,7 +23,7 @@
"@bfc/shared": "*",
"@bfc/ui-shared": "*",
"react-beautiful-dnd": "^13.0.0",
- "tslib": "2.4.0"
+ "tslib": "2.6.2"
},
"peerDependencies": {
"@emotion/react": "^11.1.3",
diff --git a/Composer/packages/form-dialogs/src/FormDialogSchemaEditor.tsx b/Composer/packages/form-dialogs/src/FormDialogSchemaEditor.tsx
index a474e6ea19..455821fba5 100644
--- a/Composer/packages/form-dialogs/src/FormDialogSchemaEditor.tsx
+++ b/Composer/packages/form-dialogs/src/FormDialogSchemaEditor.tsx
@@ -3,7 +3,6 @@
import { FormDialogSchemaTemplate } from '@bfc/shared';
import * as React from 'react';
-// eslint-disable-next-line @typescript-eslint/camelcase
import { RecoilRoot, useRecoilTransactionObserver_UNSTABLE, useRecoilValue } from 'recoil';
import { formDialogSchemaJsonSelector, trackedAtomsSelector } from './atoms/appState';
diff --git a/Composer/packages/form-dialogs/src/atoms/appState.ts b/Composer/packages/form-dialogs/src/atoms/appState.ts
index bd46dfec08..4c925cc0b1 100644
--- a/Composer/packages/form-dialogs/src/atoms/appState.ts
+++ b/Composer/packages/form-dialogs/src/atoms/appState.ts
@@ -83,10 +83,12 @@ export const formDialogSchemaPropertyNamesSelector = selector({
*/
export const formDialogPropertyJsonSelector = selectorFamily({
key: 'FormDialogPropertyJsonSelector',
- get: (id) => ({ get }) => {
- const cardData = get(propertyCardDataAtom(id));
- return spreadCardData(cardData);
- },
+ get:
+ (id) =>
+ ({ get }) => {
+ const cardData = get(propertyCardDataAtom(id));
+ return spreadCardData(cardData);
+ },
});
/**
@@ -94,11 +96,13 @@ export const formDialogPropertyJsonSelector = selectorFamily({
*/
export const formDialogPropertyValidSelector = selectorFamily({
key: 'FormDialogPropertyValidSelector',
- get: (id) => ({ get }) => {
- const templates = get(formDialogTemplatesAtom);
- const cardData = get(propertyCardDataAtom(id));
- return validateSchemaPropertyStore(cardData, templates);
- },
+ get:
+ (id) =>
+ ({ get }) => {
+ const templates = get(formDialogTemplatesAtom);
+ const cardData = get(propertyCardDataAtom(id));
+ return validateSchemaPropertyStore(cardData, templates);
+ },
});
/**
@@ -129,11 +133,14 @@ export const formDialogSchemaJsonSelector = selector({
if (propertyCards.length) {
jsonObject = {
...jsonObject,
- properties: propertyIds.reduce>((acc, propId, idx) => {
- const property = propertyCards[idx];
- acc[property.name] = get(formDialogPropertyJsonSelector(propId));
- return acc;
- }, >{}),
+ properties: propertyIds.reduce>(
+ (acc, propId, idx) => {
+ const property = propertyCards[idx];
+ acc[property.name] = get(formDialogPropertyJsonSelector(propId));
+ return acc;
+ },
+ >{},
+ ),
};
}
diff --git a/Composer/packages/form-dialogs/src/atoms/handlers.ts b/Composer/packages/form-dialogs/src/atoms/handlers.ts
index 19ee429834..84246c5d41 100644
--- a/Composer/packages/form-dialogs/src/atoms/handlers.ts
+++ b/Composer/packages/form-dialogs/src/atoms/handlers.ts
@@ -29,25 +29,18 @@ import { createSchemaStoreFromJson, getDuplicateName } from './utils';
const getHandlers = () => {
const importSchemaString = useRecoilCallback(
- ({ set }) => async ({
- id,
- content,
- templates,
- }: {
- id: string;
- content: string;
- templates: FormDialogSchemaTemplate[];
- }) => {
- const schema = createSchemaStoreFromJson(id, content, templates);
-
- set(formDialogSchemaAtom, {
- id: schema.name,
- name: schema.name,
- requiredPropertyIds: schema.properties.filter((p) => p.isRequired).map((p) => p.id),
- optionalPropertyIds: schema.properties.filter((p) => !p.isRequired).map((p) => p.id),
- });
- schema.properties.forEach((property) => set(propertyCardDataAtom(property.id), property));
- }
+ ({ set }) =>
+ async ({ id, content, templates }: { id: string; content: string; templates: FormDialogSchemaTemplate[] }) => {
+ const schema = createSchemaStoreFromJson(id, content, templates);
+
+ set(formDialogSchemaAtom, {
+ id: schema.name,
+ name: schema.name,
+ requiredPropertyIds: schema.properties.filter((p) => p.isRequired).map((p) => p.id),
+ optionalPropertyIds: schema.properties.filter((p) => !p.isRequired).map((p) => p.id),
+ });
+ schema.properties.forEach((property) => set(propertyCardDataAtom(property.id), property));
+ },
);
const importSchema = useRecoilCallback(({ snapshot }) => async ({ id, file }: { id: string; file: File }) => {
@@ -77,80 +70,84 @@ const getHandlers = () => {
});
const changePropertyType = useRecoilCallback(
- ({ set }) => ({ id, propertyType }: { id: string; propertyType: string }) => {
- set(propertyCardDataAtom(id), (currentPropertyCardData) => {
- const basicCardData = pick(currentPropertyCardData, ['id', 'name', 'isRequired', 'isArray']);
- return { ...basicCardData, propertyType };
- });
- }
+ ({ set }) =>
+ ({ id, propertyType }: { id: string; propertyType: string }) => {
+ set(propertyCardDataAtom(id), (currentPropertyCardData) => {
+ const basicCardData = pick(currentPropertyCardData, ['id', 'name', 'isRequired', 'isArray']);
+ return { ...basicCardData, propertyType };
+ });
+ },
);
const changePropertyRequired = useRecoilCallback(
- ({ set }) => ({ id, isRequired }: { id: string; isRequired: boolean }) => {
- set(propertyCardDataAtom(id), (currentPropertyCardData) => {
- return { ...currentPropertyCardData, isRequired };
- });
- }
+ ({ set }) =>
+ ({ id, isRequired }: { id: string; isRequired: boolean }) => {
+ set(propertyCardDataAtom(id), (currentPropertyCardData) => {
+ return { ...currentPropertyCardData, isRequired };
+ });
+ },
);
const changePropertyName = useRecoilCallback(
- ({ set, snapshot }) => async ({ id, name }: { id: string; name: string }) => {
- const locale = await snapshot.getPromise(formDialogLocale);
- set(propertyCardDataAtom(id), (currentPropertyCardData) => {
- const currentName = currentPropertyCardData.name;
- const cardData = { ...currentPropertyCardData, name } as PropertyCardData;
-
- // Change the name of the entity for examples if the type is enum
- if (cardData.propertyType === 'enum' && cardData.$examples?.[locale]?.[`${currentName}Value`]) {
- const examples = cloneDeep(cardData.$examples);
- examples[locale][`${name}Value`] = { ...examples[locale][`${currentName}Value`] };
- delete examples[locale][`${currentName}Value`];
-
- cardData.$examples = examples;
- }
+ ({ set, snapshot }) =>
+ async ({ id, name }: { id: string; name: string }) => {
+ const locale = await snapshot.getPromise(formDialogLocale);
+ set(propertyCardDataAtom(id), (currentPropertyCardData) => {
+ const currentName = currentPropertyCardData.name;
+ const cardData = { ...currentPropertyCardData, name } as PropertyCardData;
+
+ // Change the name of the entity for examples if the type is enum
+ if (cardData.propertyType === 'enum' && cardData.$examples?.[locale]?.[`${currentName}Value`]) {
+ const examples = cloneDeep(cardData.$examples);
+ examples[locale][`${name}Value`] = { ...examples[locale][`${currentName}Value`] };
+ delete examples[locale][`${currentName}Value`];
+
+ cardData.$examples = examples;
+ }
- return cardData;
- });
- }
+ return cardData;
+ });
+ },
);
const changePropertyCardData = useRecoilCallback(
- ({ set, snapshot }) => async ({ id, data }: { id: string; data: Record }) => {
- const locale = await snapshot.getPromise(formDialogLocale);
- set(propertyCardDataAtom(id), (currentPropertyCardData) => {
- const hadEnum = !!currentPropertyCardData.enum?.length;
- const cardData = { ...currentPropertyCardData, ...data } as PropertyCardData;
-
- if (cardData.propertyType === 'enum') {
- // If $examples is empty, deleted current locale examples
- if (hadEnum && !cardData.$examples?.[locale]) {
+ ({ set, snapshot }) =>
+ async ({ id, data }: { id: string; data: Record }) => {
+ const locale = await snapshot.getPromise(formDialogLocale);
+ set(propertyCardDataAtom(id), (currentPropertyCardData) => {
+ const hadEnum = !!currentPropertyCardData.enum?.length;
+ const cardData = { ...currentPropertyCardData, ...data } as PropertyCardData;
+
+ if (cardData.propertyType === 'enum') {
+ // If $examples is empty, deleted current locale examples
+ if (hadEnum && !cardData.$examples?.[locale]) {
+ return cardData;
+ }
+
+ const defaultExamples = {
+ [locale]: {
+ [`${cardData.name}Value`]: (cardData?.enum ?? []).reduce((acc, e) => {
+ acc[e] = [];
+ return acc;
+ }, {}),
+ },
+ };
+
+ const newExamples = data?.$examples?.[locale]?.[`${cardData.name}Value`] ? data.$examples : defaultExamples;
+
+ // Merge default, old and new and only keep the examples for current enum values
+ const mergedExamples = pick(
+ merge(defaultExamples, newExamples),
+ cardData.enum.map((e: string) => `${locale}.${cardData.name}Value.${e}`),
+ );
+ cardData.$examples = mergedExamples;
+
return cardData;
}
- const defaultExamples = {
- [locale]: {
- [`${cardData.name}Value`]: (cardData?.enum ?? []).reduce((acc, e) => {
- acc[e] = [];
- return acc;
- }, {}),
- },
- };
-
- const newExamples = data?.$examples?.[locale]?.[`${cardData.name}Value`] ? data.$examples : defaultExamples;
-
- // Merge default, old and new and only keep the examples for current enum values
- const mergedExamples = pick(
- merge(defaultExamples, newExamples),
- cardData.enum.map((e: string) => `${locale}.${cardData.name}Value.${e}`)
- );
- cardData.$examples = mergedExamples;
-
return cardData;
- }
-
- return cardData;
- });
- }
+ });
+ },
);
const changePropertyArray = useRecoilCallback(({ set }) => ({ id, isArray }: { id: string; isArray: boolean }) => {
@@ -160,56 +157,56 @@ const getHandlers = () => {
});
const moveProperty = useRecoilCallback(
- ({ set }) => ({
- id,
- source,
- destination,
- fromIndex,
- toIndex,
- }: {
- id: string;
- source: PropertyRequiredKind;
- destination: PropertyRequiredKind;
- fromIndex: number;
- toIndex: number;
- }) => {
- const toggleRequired = source !== destination;
-
- if (toggleRequired) {
- changePropertyRequired({ id, isRequired: source === 'optional' });
- }
+ ({ set }) =>
+ ({
+ id,
+ source,
+ destination,
+ fromIndex,
+ toIndex,
+ }: {
+ id: string;
+ source: PropertyRequiredKind;
+ destination: PropertyRequiredKind;
+ fromIndex: number;
+ toIndex: number;
+ }) => {
+ const toggleRequired = source !== destination;
- set(formDialogSchemaAtom, (currentSchema) => {
if (toggleRequired) {
- //Move between two lists
- const requiredPropertyIds = currentSchema.requiredPropertyIds.slice();
- const optionalPropertyIds = currentSchema.optionalPropertyIds.slice();
+ changePropertyRequired({ id, isRequired: source === 'optional' });
+ }
- if (source === 'required') {
- requiredPropertyIds.splice(fromIndex, 1);
- optionalPropertyIds.splice(toIndex, 0, id);
+ set(formDialogSchemaAtom, (currentSchema) => {
+ if (toggleRequired) {
+ //Move between two lists
+ const requiredPropertyIds = currentSchema.requiredPropertyIds.slice();
+ const optionalPropertyIds = currentSchema.optionalPropertyIds.slice();
+
+ if (source === 'required') {
+ requiredPropertyIds.splice(fromIndex, 1);
+ optionalPropertyIds.splice(toIndex, 0, id);
+ } else {
+ optionalPropertyIds.splice(fromIndex, 1);
+ requiredPropertyIds.splice(toIndex, 0, id);
+ }
+
+ return { ...currentSchema, requiredPropertyIds, optionalPropertyIds };
} else {
- optionalPropertyIds.splice(fromIndex, 1);
- requiredPropertyIds.splice(toIndex, 0, id);
- }
-
- return { ...currentSchema, requiredPropertyIds, optionalPropertyIds };
- } else {
- // Move within a list
- const propertyIds = (source === 'required'
- ? currentSchema.requiredPropertyIds
- : currentSchema.optionalPropertyIds
- ).slice();
+ // Move within a list
+ const propertyIds = (
+ source === 'required' ? currentSchema.requiredPropertyIds : currentSchema.optionalPropertyIds
+ ).slice();
- propertyIds.splice(fromIndex, 1);
- propertyIds.splice(toIndex, 0, id);
+ propertyIds.splice(fromIndex, 1);
+ propertyIds.splice(toIndex, 0, id);
- return source === 'required'
- ? { ...currentSchema, requiredPropertyIds: propertyIds }
- : { ...currentSchema, optionalPropertyIds: propertyIds };
- }
- });
- }
+ return source === 'required'
+ ? { ...currentSchema, requiredPropertyIds: propertyIds }
+ : { ...currentSchema, optionalPropertyIds: propertyIds };
+ }
+ });
+ },
);
const removeProperty = useRecoilCallback(({ set, reset, snapshot }) => async ({ id }: { id: string }) => {
@@ -242,9 +239,8 @@ const getHandlers = () => {
const name = getDuplicateName(propertyCardData.name, propertyNames);
set(formDialogSchemaAtom, (currentSchema) => {
- const propertyIds = (propertyCardData.isRequired
- ? currentSchema.requiredPropertyIds
- : currentSchema.optionalPropertyIds
+ const propertyIds = (
+ propertyCardData.isRequired ? currentSchema.requiredPropertyIds : currentSchema.optionalPropertyIds
).slice();
if (propertyCardData.isRequired) {
diff --git a/Composer/packages/form-dialogs/src/atoms/types.ts b/Composer/packages/form-dialogs/src/atoms/types.ts
index c95e0c3b1e..e91add6451 100644
--- a/Composer/packages/form-dialogs/src/atoms/types.ts
+++ b/Composer/packages/form-dialogs/src/atoms/types.ts
@@ -19,7 +19,7 @@ export type TypedPropertyPayload = {
const builtInFormats = ['date-time', 'date', 'time', 'email', 'uri', 'iri'] as const;
-export type BuiltInStringFormat = typeof builtInFormats[number];
+export type BuiltInStringFormat = (typeof builtInFormats)[number];
export type StringFormatItem = { displayName: string; value: BuiltInStringFormat };
diff --git a/Composer/packages/form-dialogs/src/atoms/utils.ts b/Composer/packages/form-dialogs/src/atoms/utils.ts
index a3fd8306bd..ee1335e3ff 100644
--- a/Composer/packages/form-dialogs/src/atoms/utils.ts
+++ b/Composer/packages/form-dialogs/src/atoms/utils.ts
@@ -36,7 +36,7 @@ const $refToRef = ($ref: string) => {
export const jsonSchemaTypeToTemplateType = (
propertyJson: any,
- templates: FormDialogSchemaTemplate[]
+ templates: FormDialogSchemaTemplate[],
): { propertyType: string; isArray?: boolean } => {
const jsonType = propertyJson.type ?? 'ref';
@@ -55,7 +55,7 @@ export const jsonSchemaTypeToTemplateType = (
if (propertyJson.format) {
const template = templates.find(
- (template) => template.format === propertyJson.format && template.type === jsonType
+ (template) => template.format === propertyJson.format && template.type === jsonType,
);
return { propertyType: template.id };
}
@@ -77,7 +77,7 @@ export const jsonSchemaTypeToTemplateType = (
export const createSchemaStoreFromJson = (
name: string,
jsonString: string,
- templates: FormDialogSchemaTemplate[]
+ templates: FormDialogSchemaTemplate[],
): { name: string; properties: PropertyCardData[] } => {
const json = JSON.parse(jsonString);
diff --git a/Composer/packages/form-dialogs/src/components/FormDialogPropertiesEditor.tsx b/Composer/packages/form-dialogs/src/components/FormDialogPropertiesEditor.tsx
index 698cc7af23..44ebeaee9e 100644
--- a/Composer/packages/form-dialogs/src/components/FormDialogPropertiesEditor.tsx
+++ b/Composer/packages/form-dialogs/src/components/FormDialogPropertiesEditor.tsx
@@ -170,7 +170,7 @@ export const FormDialogPropertiesEditor = React.memo((props: Props) => {
onClick: async () => {
const result = await OpenConfirmModal(
formatMessage('Start over?'),
- formatMessage('Are you sure you want to start over? Your progress will be lost.')
+ formatMessage('Are you sure you want to start over? Your progress will be lost.'),
);
if (result) {
diff --git a/Composer/packages/form-dialogs/src/components/property/FormDialogPropertyCard.tsx b/Composer/packages/form-dialogs/src/components/property/FormDialogPropertyCard.tsx
index c67fd43202..6f27562e10 100644
--- a/Composer/packages/form-dialogs/src/components/property/FormDialogPropertyCard.tsx
+++ b/Composer/packages/form-dialogs/src/components/property/FormDialogPropertyCard.tsx
@@ -86,10 +86,10 @@ export const FormDialogPropertyCard = React.memo((props: FormDialogPropertyCardP
} = props;
const templates = useRecoilValue(formDialogTemplatesAtom);
- const selectedTemplate = React.useMemo(() => templates.find((t) => t.id === propertyCardData.propertyType), [
- propertyCardData,
- templates,
- ]);
+ const selectedTemplate = React.useMemo(
+ () => templates.find((t) => t.id === propertyCardData.propertyType),
+ [propertyCardData, templates],
+ );
// Indicates if the form in the card has been touched by the user.
const touchedRef = React.useRef(!!propertyCardData.name);
@@ -103,7 +103,7 @@ export const FormDialogPropertyCard = React.memo((props: FormDialogPropertyCardP
(_: React.FormEvent, checked: boolean) => {
onChangeArray(checked);
},
- [onChangeArray]
+ [onChangeArray],
);
const changeName = React.useCallback(
@@ -111,7 +111,7 @@ export const FormDialogPropertyCard = React.memo((props: FormDialogPropertyCardP
onChangeName(value);
touchedRef.current = true;
},
- [onChangeName]
+ [onChangeName],
);
const deactivateItem = React.useCallback(() => {
@@ -124,12 +124,12 @@ export const FormDialogPropertyCard = React.memo((props: FormDialogPropertyCardP
(props: any, defaultRender?: (props: any) => JSX.Element | null) => (