mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-23 10:51:30 +00:00
Compare commits
2 Commits
eslint/Not
...
add-eslint
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27d129e689 | ||
|
|
fb9f97b43a |
@@ -81,9 +81,17 @@ src/Explorer/Tables/DataTable/DataTableBindingManager.ts
|
|||||||
src/Explorer/Tables/DataTable/DataTableBuilder.ts
|
src/Explorer/Tables/DataTable/DataTableBuilder.ts
|
||||||
src/Explorer/Tables/DataTable/DataTableContextMenu.ts
|
src/Explorer/Tables/DataTable/DataTableContextMenu.ts
|
||||||
src/Explorer/Tables/DataTable/DataTableOperationManager.ts
|
src/Explorer/Tables/DataTable/DataTableOperationManager.ts
|
||||||
|
src/Explorer/Tables/DataTable/DataTableOperations.ts
|
||||||
src/Explorer/Tables/DataTable/DataTableViewModel.ts
|
src/Explorer/Tables/DataTable/DataTableViewModel.ts
|
||||||
|
src/Explorer/Tables/DataTable/TableCommands.ts
|
||||||
|
src/Explorer/Tables/DataTable/TableEntityCache.ts
|
||||||
src/Explorer/Tables/DataTable/TableEntityListViewModel.ts
|
src/Explorer/Tables/DataTable/TableEntityListViewModel.ts
|
||||||
|
src/Explorer/Tables/Entities.ts
|
||||||
|
src/Explorer/Tables/QueryBuilder/ClauseGroup.ts
|
||||||
|
src/Explorer/Tables/QueryBuilder/ClauseGroupViewModel.ts
|
||||||
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
|
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
|
||||||
|
src/Explorer/Tables/QueryBuilder/QueryBuilderViewModel.ts
|
||||||
|
src/Explorer/Tables/QueryBuilder/QueryClauseViewModel.ts
|
||||||
src/Explorer/Tables/TableDataClient.ts
|
src/Explorer/Tables/TableDataClient.ts
|
||||||
src/Explorer/Tables/TableEntityProcessor.ts
|
src/Explorer/Tables/TableEntityProcessor.ts
|
||||||
src/Explorer/Tables/Utilities.ts
|
src/Explorer/Tables/Utilities.ts
|
||||||
@@ -93,7 +101,11 @@ src/Explorer/Tabs/DocumentsTab.test.ts
|
|||||||
src/Explorer/Tabs/DocumentsTab.ts
|
src/Explorer/Tabs/DocumentsTab.ts
|
||||||
src/Explorer/Tabs/GraphTab.ts
|
src/Explorer/Tabs/GraphTab.ts
|
||||||
src/Explorer/Tabs/MongoDocumentsTab.ts
|
src/Explorer/Tabs/MongoDocumentsTab.ts
|
||||||
|
src/Explorer/Tabs/NotebookV2Tab.ts
|
||||||
|
src/Explorer/Tabs/ScriptTabBase.ts
|
||||||
|
src/Explorer/Tabs/TabComponents.ts
|
||||||
src/Explorer/Tabs/TabsBase.ts
|
src/Explorer/Tabs/TabsBase.ts
|
||||||
|
src/Explorer/Tabs/TriggerTab.ts
|
||||||
src/Explorer/Tabs/UserDefinedFunctionTab.ts
|
src/Explorer/Tabs/UserDefinedFunctionTab.ts
|
||||||
src/Explorer/Tree/AccessibleVerticalList.ts
|
src/Explorer/Tree/AccessibleVerticalList.ts
|
||||||
src/Explorer/Tree/Collection.ts
|
src/Explorer/Tree/Collection.ts
|
||||||
@@ -103,10 +115,15 @@ src/Explorer/Tree/ObjectId.ts
|
|||||||
src/Explorer/Tree/ResourceTokenCollection.ts
|
src/Explorer/Tree/ResourceTokenCollection.ts
|
||||||
src/Explorer/Tree/StoredProcedure.ts
|
src/Explorer/Tree/StoredProcedure.ts
|
||||||
src/Explorer/Tree/TreeComponents.ts
|
src/Explorer/Tree/TreeComponents.ts
|
||||||
|
src/Explorer/Tree/Trigger.ts
|
||||||
src/Explorer/WaitsForTemplateViewModel.ts
|
src/Explorer/WaitsForTemplateViewModel.ts
|
||||||
src/GitHub/GitHubClient.test.ts
|
src/GitHub/GitHubClient.test.ts
|
||||||
src/GitHub/GitHubClient.ts
|
src/GitHub/GitHubClient.ts
|
||||||
|
src/GitHub/GitHubConnector.ts
|
||||||
|
src/GitHub/GitHubOAuthService.ts
|
||||||
src/Index.ts
|
src/Index.ts
|
||||||
|
src/Juno/JunoClient.test.ts
|
||||||
|
src/Juno/JunoClient.ts
|
||||||
src/Platform/Hosted/Authorization.ts
|
src/Platform/Hosted/Authorization.ts
|
||||||
src/ReactDevTools.ts
|
src/ReactDevTools.ts
|
||||||
src/Shared/Constants.ts
|
src/Shared/Constants.ts
|
||||||
@@ -126,13 +143,20 @@ src/Explorer/Controls/Notebook/NotebookTerminalComponent.tsx
|
|||||||
src/Explorer/Controls/NotebookViewer/NotebookViewerComponent.tsx
|
src/Explorer/Controls/NotebookViewer/NotebookViewerComponent.tsx
|
||||||
src/Explorer/Controls/TreeComponent/TreeComponent.tsx
|
src/Explorer/Controls/TreeComponent/TreeComponent.tsx
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx
|
src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx
|
||||||
|
src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx
|
||||||
|
src/Explorer/Graph/GraphExplorerComponent/GraphVizComponent.tsx
|
||||||
|
src/Explorer/Graph/GraphExplorerComponent/LeftPaneComponent.tsx
|
||||||
|
src/Explorer/Graph/GraphExplorerComponent/MiddlePaneComponent.tsx
|
||||||
|
src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.test.tsx
|
||||||
src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx
|
src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx
|
||||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.test.tsx
|
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.test.tsx
|
||||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.tsx
|
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.tsx
|
||||||
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
|
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
|
||||||
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
|
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
|
||||||
|
src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
|
||||||
src/Explorer/Notebook/NotebookComponent/VirtualCommandBarComponent.tsx
|
src/Explorer/Notebook/NotebookComponent/VirtualCommandBarComponent.tsx
|
||||||
src/Explorer/Notebook/NotebookComponent/contents/index.tsx
|
src/Explorer/Notebook/NotebookComponent/contents/index.tsx
|
||||||
|
src/Explorer/Notebook/NotebookRenderer/NotebookReadOnlyRenderer.tsx
|
||||||
src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx
|
src/Explorer/Notebook/NotebookRenderer/NotebookRenderer.tsx
|
||||||
src/Explorer/Notebook/NotebookRenderer/decorators/draggable/index.tsx
|
src/Explorer/Notebook/NotebookRenderer/decorators/draggable/index.tsx
|
||||||
src/Explorer/Notebook/NotebookRenderer/decorators/hijack-scroll/index.tsx
|
src/Explorer/Notebook/NotebookRenderer/decorators/hijack-scroll/index.tsx
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ module.exports = {
|
|||||||
browser: true,
|
browser: true,
|
||||||
es6: true,
|
es6: true,
|
||||||
},
|
},
|
||||||
plugins: ["@typescript-eslint", "no-null", "prefer-arrow", "react-hooks"],
|
plugins: ["@typescript-eslint", "no-null", "prefer-arrow", "react-hooks", "jsx-a11y"],
|
||||||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:jsx-a11y/recommended"],
|
||||||
globals: {
|
globals: {
|
||||||
Atomics: "readonly",
|
Atomics: "readonly",
|
||||||
SharedArrayBuffer: "readonly",
|
SharedArrayBuffer: "readonly",
|
||||||
@@ -39,6 +39,7 @@ module.exports = {
|
|||||||
"@typescript-eslint/switch-exhaustiveness-check": "error",
|
"@typescript-eslint/switch-exhaustiveness-check": "error",
|
||||||
"@typescript-eslint/no-unused-vars": "error",
|
"@typescript-eslint/no-unused-vars": "error",
|
||||||
"@typescript-eslint/no-extraneous-class": "error",
|
"@typescript-eslint/no-extraneous-class": "error",
|
||||||
|
"no-null/no-null": "error",
|
||||||
"@typescript-eslint/no-explicit-any": "error",
|
"@typescript-eslint/no-explicit-any": "error",
|
||||||
"prefer-arrow/prefer-arrow-functions": ["error", { allowStandaloneDeclarations: true }],
|
"prefer-arrow/prefer-arrow-functions": ["error", { allowStandaloneDeclarations: true }],
|
||||||
eqeqeq: "error",
|
eqeqeq: "error",
|
||||||
|
|||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -22,6 +22,5 @@
|
|||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": true,
|
"source.fixAll.eslint": true,
|
||||||
"source.organizeImports": true
|
"source.organizeImports": true
|
||||||
},
|
}
|
||||||
"typescript.preferences.importModuleSpecifier": "non-relative"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ module.exports = {
|
|||||||
global: {
|
global: {
|
||||||
branches: 25,
|
branches: 25,
|
||||||
functions: 25,
|
functions: 25,
|
||||||
lines: 29,
|
lines: 29.5,
|
||||||
statements: 29,
|
statements: 29.5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -129,8 +129,6 @@ module.exports = {
|
|||||||
// The test environment that will be used for testing
|
// The test environment that will be used for testing
|
||||||
// testEnvironment: "jest-environment-jsdom",
|
// testEnvironment: "jest-environment-jsdom",
|
||||||
|
|
||||||
modulePaths: ["node_modules", "<rootDir>/src"],
|
|
||||||
|
|
||||||
// Options that will be passed to the testEnvironment
|
// Options that will be passed to the testEnvironment
|
||||||
// testEnvironmentOptions: {},
|
// testEnvironmentOptions: {},
|
||||||
|
|
||||||
|
|||||||
@@ -3079,3 +3079,6 @@ settings-pane {
|
|||||||
background: white;
|
background: white;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
.moreOption {
|
||||||
|
color: #337ab7;
|
||||||
|
}
|
||||||
91
package-lock.json
generated
91
package-lock.json
generated
@@ -6809,6 +6809,11 @@
|
|||||||
"integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=",
|
"integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ast-types-flow": {
|
||||||
|
"version": "0.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
|
||||||
|
"integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0="
|
||||||
|
},
|
||||||
"astral-regex": {
|
"astral-regex": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
|
||||||
@@ -6876,6 +6881,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
|
||||||
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
|
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
|
||||||
},
|
},
|
||||||
|
"axe-core": {
|
||||||
|
"version": "4.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz",
|
||||||
|
"integrity": "sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA=="
|
||||||
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "0.21.1",
|
"version": "0.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz",
|
||||||
@@ -6891,6 +6901,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"axobject-query": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA=="
|
||||||
|
},
|
||||||
"babel-code-frame": {
|
"babel-code-frame": {
|
||||||
"version": "6.26.0",
|
"version": "6.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||||
@@ -8878,6 +8893,11 @@
|
|||||||
"d3-transition": "2"
|
"d3-transition": "2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"damerau-levenshtein": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz",
|
||||||
|
"integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw=="
|
||||||
|
},
|
||||||
"dashdash": {
|
"dashdash": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||||
@@ -10171,6 +10191,64 @@
|
|||||||
"@typescript-eslint/experimental-utils": "^2.5.0"
|
"@typescript-eslint/experimental-utils": "^2.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"eslint-plugin-jsx-a11y": {
|
||||||
|
"version": "6.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz",
|
||||||
|
"integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.11.2",
|
||||||
|
"aria-query": "^4.2.2",
|
||||||
|
"array-includes": "^3.1.1",
|
||||||
|
"ast-types-flow": "^0.0.7",
|
||||||
|
"axe-core": "^4.0.2",
|
||||||
|
"axobject-query": "^2.2.0",
|
||||||
|
"damerau-levenshtein": "^1.0.6",
|
||||||
|
"emoji-regex": "^9.0.0",
|
||||||
|
"has": "^1.0.3",
|
||||||
|
"jsx-ast-utils": "^3.1.0",
|
||||||
|
"language-tags": "^1.0.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"emoji-regex": {
|
||||||
|
"version": "9.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
|
||||||
|
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
|
||||||
|
},
|
||||||
|
"get-intrinsic": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
|
||||||
|
"requires": {
|
||||||
|
"function-bind": "^1.1.1",
|
||||||
|
"has": "^1.0.3",
|
||||||
|
"has-symbols": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"jsx-ast-utils": {
|
||||||
|
"version": "3.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz",
|
||||||
|
"integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==",
|
||||||
|
"requires": {
|
||||||
|
"array-includes": "^3.1.3",
|
||||||
|
"object.assign": "^4.1.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"array-includes": {
|
||||||
|
"version": "3.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz",
|
||||||
|
"integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==",
|
||||||
|
"requires": {
|
||||||
|
"call-bind": "^1.0.2",
|
||||||
|
"define-properties": "^1.1.3",
|
||||||
|
"es-abstract": "^1.18.0-next.2",
|
||||||
|
"get-intrinsic": "^1.1.1",
|
||||||
|
"is-string": "^1.0.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"eslint-plugin-no-null": {
|
"eslint-plugin-no-null": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-no-null/-/eslint-plugin-no-null-1.0.2.tgz",
|
||||||
@@ -18065,6 +18143,19 @@
|
|||||||
"resolved": "https://registry.npmjs.org/labella/-/labella-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/labella/-/labella-1.1.4.tgz",
|
||||||
"integrity": "sha1-xsxaNA6N80DrM1YzaD6lm4KMMi0="
|
"integrity": "sha1-xsxaNA6N80DrM1YzaD6lm4KMMi0="
|
||||||
},
|
},
|
||||||
|
"language-subtag-registry": {
|
||||||
|
"version": "0.3.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
||||||
|
"integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg=="
|
||||||
|
},
|
||||||
|
"language-tags": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
|
||||||
|
"integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=",
|
||||||
|
"requires": {
|
||||||
|
"language-subtag-registry": "~0.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"lcid": {
|
"lcid": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
"dom-to-image": "2.6.0",
|
"dom-to-image": "2.6.0",
|
||||||
"dotenv": "8.2.0",
|
"dotenv": "8.2.0",
|
||||||
"eslint-plugin-jest": "23.13.2",
|
"eslint-plugin-jest": "23.13.2",
|
||||||
|
"eslint-plugin-jsx-a11y": "6.4.1",
|
||||||
"eslint-plugin-react": "7.20.0",
|
"eslint-plugin-react": "7.20.0",
|
||||||
"hasher": "1.2.0",
|
"hasher": "1.2.0",
|
||||||
"html2canvas": "1.0.0-rc.5",
|
"html2canvas": "1.0.0-rc.5",
|
||||||
|
|||||||
@@ -31,17 +31,15 @@ export const CollapsedResourceTree: FunctionComponent<CollapsedResourceTreeProps
|
|||||||
<div id="mini" className={!isLeftPaneExpanded ? "mini toggle-mini" : "hiddenMain"}>
|
<div id="mini" className={!isLeftPaneExpanded ? "mini toggle-mini" : "hiddenMain"}>
|
||||||
<div className="main-nav nav">
|
<div className="main-nav nav">
|
||||||
<ul className="nav">
|
<ul className="nav">
|
||||||
<li
|
<li className="resourceTreeCollapse" id="collapseToggleLeftPaneButton" aria-label="Expand Tree">
|
||||||
className="resourceTreeCollapse"
|
<span
|
||||||
id="collapseToggleLeftPaneButton"
|
className="leftarrowCollapsed"
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
aria-label="Expand Tree"
|
onClick={toggleLeftPaneExpanded}
|
||||||
onClick={toggleLeftPaneExpanded}
|
onKeyPress={onKeyPressToggleLeftPaneExpanded}
|
||||||
onKeyPress={onKeyPressToggleLeftPaneExpanded}
|
ref={focusButton}
|
||||||
ref={focusButton}
|
>
|
||||||
>
|
|
||||||
<span className="leftarrowCollapsed">
|
|
||||||
<img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" />
|
<img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" />
|
||||||
</span>
|
</span>
|
||||||
<span className="collectionCollapsed">
|
<span className="collectionCollapsed">
|
||||||
|
|||||||
@@ -339,11 +339,9 @@ export enum ConflictOperationType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum ConnectionStatusType {
|
export enum ConnectionStatusType {
|
||||||
Connect = "Connect",
|
|
||||||
Connecting = "Connecting",
|
Connecting = "Connecting",
|
||||||
Connected = "Connected",
|
Connected = "Connected",
|
||||||
Failed = "Connection Failed",
|
Failed = "Connection Failed",
|
||||||
ReConnect = "Reconnect",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EmulatorMasterKey =
|
export const EmulatorMasterKey =
|
||||||
@@ -355,32 +353,15 @@ export const StyleConstants = require("less-vars-loader!../../less/Common/Consta
|
|||||||
|
|
||||||
export class Notebook {
|
export class Notebook {
|
||||||
public static readonly defaultBasePath = "./notebooks";
|
public static readonly defaultBasePath = "./notebooks";
|
||||||
public static readonly heartbeatDelayMs = 60000;
|
public static readonly heartbeatDelayMs = 5000;
|
||||||
public static readonly kernelRestartInitialDelayMs = 1000;
|
public static readonly kernelRestartInitialDelayMs = 1000;
|
||||||
public static readonly kernelRestartMaxDelayMs = 20000;
|
public static readonly kernelRestartMaxDelayMs = 20000;
|
||||||
public static readonly autoSaveIntervalMs = 120000;
|
public static readonly autoSaveIntervalMs = 120000;
|
||||||
public static readonly memoryGuageToGB = 1048576;
|
|
||||||
public static readonly temporarilyDownMsg = "Notebooks is currently not available. We are working on it.";
|
public static readonly temporarilyDownMsg = "Notebooks is currently not available. We are working on it.";
|
||||||
public static readonly mongoShellTemporarilyDownMsg =
|
public static readonly mongoShellTemporarilyDownMsg =
|
||||||
"We have identified an issue with the Mongo Shell and it is unavailable right now. We are actively working on the mitigation.";
|
"We have identified an issue with the Mongo Shell and it is unavailable right now. We are actively working on the mitigation.";
|
||||||
public static readonly cassandraShellTemporarilyDownMsg =
|
public static readonly cassandraShellTemporarilyDownMsg =
|
||||||
"We have identified an issue with the Cassandra Shell and it is unavailable right now. We are actively working on the mitigation.";
|
"We have identified an issue with the Cassandra Shell and it is unavailable right now. We are actively working on the mitigation.";
|
||||||
public static saveNotebookModalTitle = "Save Notebook in temporary workspace";
|
|
||||||
public static saveNotebookModalContent =
|
|
||||||
"This notebook will be saved in the temporary workspace and will be removed when the session expires. To save your work permanently, save your notebooks to a GitHub repository or download the notebooks to your local machine before the session ends.";
|
|
||||||
public static newNotebookModalTitle = "Create Notebook in temporary workspace";
|
|
||||||
public static newNotebookUploadModalTitle = "Upload Notebook in temporary workspace";
|
|
||||||
public static newNotebookModalContent1 =
|
|
||||||
"A temporary workspace will be created to enable you to work with notebooks. When the session expires, any notebooks in the workspace will be removed.";
|
|
||||||
public static newNotebookModalContent2 =
|
|
||||||
"To save your work permanently, save your notebooks to a GitHub repository or download the notebooks to your local machine before the session ends. ";
|
|
||||||
public static galleryNotebookDownloadContent1 =
|
|
||||||
"To download, run, and make changes to this sample notebook, a temporary workspace will be created. When the session expires, any notebooks in the workspace will be removed.";
|
|
||||||
public static galleryNotebookDownloadContent2 =
|
|
||||||
"To save your work permanently, save your notebooks to a GitHub repository or download the Notebooks to your local machine before the session ends. ";
|
|
||||||
public static cosmosNotebookHomePageUrl = "https://aka.ms/cosmos-notebooks-limits";
|
|
||||||
public static cosmosNotebookGitDocumentationUrl = "https://aka.ms/cosmos-notebooks-github";
|
|
||||||
public static learnMore = "Learn more.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SparkLibrary {
|
export class SparkLibrary {
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label={entityValueLabel && entityValueLabel}
|
label={entityValueLabel && entityValueLabel}
|
||||||
id="entityTimeId"
|
id="entityTimeId"
|
||||||
autoFocus
|
|
||||||
type="time"
|
type="time"
|
||||||
value={entityTimeValue}
|
value={entityTimeValue}
|
||||||
onChange={onEntityTimeValueChange}
|
onChange={onEntityTimeValueChange}
|
||||||
@@ -55,7 +54,6 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|||||||
label={entityValueLabel && entityValueLabel}
|
label={entityValueLabel && entityValueLabel}
|
||||||
className="addEntityTextField"
|
className="addEntityTextField"
|
||||||
id="entityValueId"
|
id="entityValueId"
|
||||||
autoFocus
|
|
||||||
disabled={isEntityValueDisable}
|
disabled={isEntityValueDisable}
|
||||||
type={entityValueType}
|
type={entityValueType}
|
||||||
placeholder={entityValuePlaceholder}
|
placeholder={entityValuePlaceholder}
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
|||||||
<TextField
|
<TextField
|
||||||
label={entityPropertyLabel && entityPropertyLabel}
|
label={entityPropertyLabel && entityPropertyLabel}
|
||||||
id="entityPropertyId"
|
id="entityPropertyId"
|
||||||
autoFocus
|
|
||||||
disabled={isPropertyTypeDisable}
|
disabled={isPropertyTypeDisable}
|
||||||
placeholder={entityPropertyPlaceHolder}
|
placeholder={entityPropertyPlaceHolder}
|
||||||
value={entityProperty}
|
value={entityProperty}
|
||||||
|
|||||||
@@ -66,9 +66,15 @@ export const Upload: FunctionComponent<UploadProps> = ({
|
|||||||
onChange={onUpload}
|
onChange={onUpload}
|
||||||
role="button"
|
role="button"
|
||||||
/>
|
/>
|
||||||
<a href="#" id="fileImportLinkNotebook" onClick={onImportLinkClick} onKeyPress={onImportLinkKeyPress}>
|
<span
|
||||||
|
id="fileImportLinkNotebook"
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onClick={onImportLinkClick}
|
||||||
|
onKeyPress={onImportLinkKeyPress}
|
||||||
|
>
|
||||||
<Image className="fileImportImg" src={FolderIcon} alt={title} title={title} />
|
<Image className="fileImportImg" src={FolderIcon} alt={title} title={title} />
|
||||||
</a>
|
</span>
|
||||||
</Stack>
|
</Stack>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -55,7 +55,13 @@ export class AccordionItemComponent extends React.Component<AccordionItemCompone
|
|||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="accordionItemContainer">
|
<div className="accordionItemContainer">
|
||||||
<div className="accordionItemHeader" onClick={this.onHeaderClick} onKeyPress={this.onHeaderKeyPress}>
|
<div
|
||||||
|
className="accordionItemHeader"
|
||||||
|
onClick={this.onHeaderClick}
|
||||||
|
onKeyPress={this.onHeaderKeyPress}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
{this.renderCollapseExpandIcon()}
|
{this.renderCollapseExpandIcon()}
|
||||||
{this.props.title}
|
{this.props.title}
|
||||||
</div>
|
</div>
|
||||||
@@ -74,8 +80,6 @@ export class AccordionItemComponent extends React.Component<AccordionItemCompone
|
|||||||
className="expandCollapseIcon"
|
className="expandCollapseIcon"
|
||||||
src={this.state.isExpanded ? TriangleDownIcon : TriangleRightIcon}
|
src={this.state.isExpanded ? TriangleDownIcon : TriangleRightIcon}
|
||||||
alt="Hide"
|
alt="Hide"
|
||||||
tabIndex={0}
|
|
||||||
role="button"
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
|
|||||||
onClick={this.toggleCollapsed}
|
onClick={this.toggleCollapsed}
|
||||||
onKeyPress={this.onKeyPress}
|
onKeyPress={this.onKeyPress}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
aria-name="Advanced"
|
aria-label="Advanced"
|
||||||
role="button"
|
role="button"
|
||||||
aria-expanded={this.state.isExpanded}
|
aria-expanded={this.state.isExpanded}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ exports[`CollapsibleSectionComponent renders 1`] = `
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
<Stack
|
<Stack
|
||||||
aria-expanded={true}
|
aria-expanded={true}
|
||||||
aria-name="Advanced"
|
aria-label="Advanced"
|
||||||
className="collapsibleSection"
|
className="collapsibleSection"
|
||||||
horizontal={true}
|
horizontal={true}
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
|
|||||||
@@ -188,12 +188,13 @@ export class CommandButtonComponent extends React.Component<CommandButtonCompone
|
|||||||
ref={(ref: HTMLElement) => {
|
ref={(ref: HTMLElement) => {
|
||||||
this.expandButtonElt = ref;
|
this.expandButtonElt = ref;
|
||||||
}}
|
}}
|
||||||
|
role="button"
|
||||||
onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => this.onLauncherKeyDown(e)}
|
onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => this.onLauncherKeyDown(e)}
|
||||||
>
|
>
|
||||||
<div className="commandDropdownLauncher">
|
<div className="commandDropdownLauncher">
|
||||||
<span className="partialSplitter" />
|
<span className="partialSplitter" />
|
||||||
<span className="expandDropdown">
|
<span className="expandDropdown">
|
||||||
<img src={CollapseChevronDownIcon} />
|
<img src={CollapseChevronDownIcon} alt="Collapse down icon" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import {
|
|||||||
Link,
|
Link,
|
||||||
PrimaryButton,
|
PrimaryButton,
|
||||||
ProgressIndicator,
|
ProgressIndicator,
|
||||||
Text,
|
|
||||||
TextField,
|
TextField,
|
||||||
} from "@fluentui/react";
|
} from "@fluentui/react";
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
@@ -31,7 +30,6 @@ export interface DialogState {
|
|||||||
onOk: () => void,
|
onOk: () => void,
|
||||||
cancelLabel: string,
|
cancelLabel: string,
|
||||||
onCancel: () => void,
|
onCancel: () => void,
|
||||||
contentHtml?: JSX.Element,
|
|
||||||
choiceGroupProps?: IChoiceGroupProps,
|
choiceGroupProps?: IChoiceGroupProps,
|
||||||
textFieldProps?: TextFieldProps,
|
textFieldProps?: TextFieldProps,
|
||||||
primaryButtonDisabled?: boolean
|
primaryButtonDisabled?: boolean
|
||||||
@@ -60,7 +58,6 @@ export const useDialog: UseStore<DialogState> = create((set, get) => ({
|
|||||||
onOk: () => void,
|
onOk: () => void,
|
||||||
cancelLabel: string,
|
cancelLabel: string,
|
||||||
onCancel: () => void,
|
onCancel: () => void,
|
||||||
contentHtml?: JSX.Element,
|
|
||||||
choiceGroupProps?: IChoiceGroupProps,
|
choiceGroupProps?: IChoiceGroupProps,
|
||||||
textFieldProps?: TextFieldProps,
|
textFieldProps?: TextFieldProps,
|
||||||
primaryButtonDisabled?: boolean
|
primaryButtonDisabled?: boolean
|
||||||
@@ -79,7 +76,6 @@ export const useDialog: UseStore<DialogState> = create((set, get) => ({
|
|||||||
get().closeDialog();
|
get().closeDialog();
|
||||||
onCancel && onCancel();
|
onCancel && onCancel();
|
||||||
},
|
},
|
||||||
contentHtml,
|
|
||||||
choiceGroupProps,
|
choiceGroupProps,
|
||||||
textFieldProps,
|
textFieldProps,
|
||||||
primaryButtonDisabled,
|
primaryButtonDisabled,
|
||||||
@@ -128,7 +124,6 @@ export interface DialogProps {
|
|||||||
type?: DialogType;
|
type?: DialogType;
|
||||||
showCloseButton?: boolean;
|
showCloseButton?: boolean;
|
||||||
onDismiss?: () => void;
|
onDismiss?: () => void;
|
||||||
contentHtml?: JSX.Element;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DIALOG_MIN_WIDTH = "400px";
|
const DIALOG_MIN_WIDTH = "400px";
|
||||||
@@ -155,7 +150,6 @@ export const Dialog: FC = () => {
|
|||||||
type,
|
type,
|
||||||
showCloseButton,
|
showCloseButton,
|
||||||
onDismiss,
|
onDismiss,
|
||||||
contentHtml,
|
|
||||||
} = props || {};
|
} = props || {};
|
||||||
|
|
||||||
const dialogProps: IDialogProps = {
|
const dialogProps: IDialogProps = {
|
||||||
@@ -197,7 +191,6 @@ export const Dialog: FC = () => {
|
|||||||
{linkProps.linkText} <FontIcon iconName="NavigateExternalInline" />
|
{linkProps.linkText} <FontIcon iconName="NavigateExternalInline" />
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
{contentHtml && <Text>{contentHtml}</Text>}
|
|
||||||
{progressIndicatorProps && <ProgressIndicator {...progressIndicatorProps} />}
|
{progressIndicatorProps && <ProgressIndicator {...progressIndicatorProps} />}
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<PrimaryButton {...primaryButtonProps} />
|
<PrimaryButton {...primaryButtonProps} />
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ import Explorer from "../../Explorer";
|
|||||||
import { NotebookClientV2 } from "../../Notebook/NotebookClientV2";
|
import { NotebookClientV2 } from "../../Notebook/NotebookClientV2";
|
||||||
import { NotebookComponentBootstrapper } from "../../Notebook/NotebookComponent/NotebookComponentBootstrapper";
|
import { NotebookComponentBootstrapper } from "../../Notebook/NotebookComponent/NotebookComponentBootstrapper";
|
||||||
import NotebookReadOnlyRenderer from "../../Notebook/NotebookRenderer/NotebookReadOnlyRenderer";
|
import NotebookReadOnlyRenderer from "../../Notebook/NotebookRenderer/NotebookReadOnlyRenderer";
|
||||||
import { NotebookUtil } from "../../Notebook/NotebookUtil";
|
|
||||||
import { useNotebook } from "../../Notebook/useNotebook";
|
|
||||||
import { Dialog, TextFieldProps, useDialog } from "../Dialog";
|
import { Dialog, TextFieldProps, useDialog } from "../Dialog";
|
||||||
import { NotebookMetadataComponent } from "./NotebookMetadataComponent";
|
import { NotebookMetadataComponent } from "./NotebookMetadataComponent";
|
||||||
import "./NotebookViewerComponent.less";
|
import "./NotebookViewerComponent.less";
|
||||||
@@ -148,9 +146,7 @@ export class NotebookViewerComponent
|
|||||||
<NotebookMetadataComponent
|
<NotebookMetadataComponent
|
||||||
data={this.state.galleryItem}
|
data={this.state.galleryItem}
|
||||||
isFavorite={this.state.isFavorite}
|
isFavorite={this.state.isFavorite}
|
||||||
downloadButtonText={
|
downloadButtonText={this.props.container && "Download to my notebooks"}
|
||||||
this.props.container && NotebookUtil.getNotebookBtnTitle(useNotebook.getState().notebookFolderName)
|
|
||||||
}
|
|
||||||
onTagClick={this.props.onTagClick}
|
onTagClick={this.props.onTagClick}
|
||||||
onFavoriteClick={this.favoriteItem}
|
onFavoriteClick={this.favoriteItem}
|
||||||
onUnfavoriteClick={this.unfavoriteItem}
|
onUnfavoriteClick={this.unfavoriteItem}
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ export class QueriesGridComponent extends React.Component<QueriesGridComponentPr
|
|||||||
To write a new query, open a new query tab and enter the desired query. Once ready to save, click on Save
|
To write a new query, open a new query tab and enter the desired query. Once ready to save, click on Save
|
||||||
Query and follow the prompt in order to save the query.
|
Query and follow the prompt in order to save the query.
|
||||||
</div>
|
</div>
|
||||||
<img {...bannerProps} />
|
<img {...bannerProps} alt="Save query helper banner" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export class IndexingPolicyComponent extends React.Component<
|
|||||||
{isDirty(this.props.indexingPolicyContent, this.props.indexingPolicyContentBaseline) && (
|
{isDirty(this.props.indexingPolicyContent, this.props.indexingPolicyContentBaseline) && (
|
||||||
<MessageBar messageBarType={MessageBarType.warning}>{indexingPolicynUnsavedWarningMessage}</MessageBar>
|
<MessageBar messageBarType={MessageBarType.warning}>{indexingPolicynUnsavedWarningMessage}</MessageBar>
|
||||||
)}
|
)}
|
||||||
<div className="settingsV2IndexingPolicyEditor" tabIndex={0} ref={this.indexingPolicyDiv}></div>
|
<div className="settingsV2IndexingPolicyEditor" ref={this.indexingPolicyDiv}></div>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ exports[`IndexingPolicyComponent renders 1`] = `
|
|||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className="settingsV2IndexingPolicyEditor"
|
className="settingsV2IndexingPolicyEditor"
|
||||||
tabIndex={0}
|
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -118,10 +118,8 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
<input
|
<input
|
||||||
className="throughputInputRadioBtn"
|
className="throughputInputRadioBtn"
|
||||||
aria-label="Autoscale mode"
|
aria-label="Autoscale mode"
|
||||||
aria-required={true}
|
|
||||||
checked={isAutoscaleSelected}
|
checked={isAutoscaleSelected}
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={(e) => handleOnChangeMode(e, "Autoscale")}
|
onChange={(e) => handleOnChangeMode(e, "Autoscale")}
|
||||||
/>
|
/>
|
||||||
@@ -132,8 +130,6 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
aria-label="Manual mode"
|
aria-label="Manual mode"
|
||||||
checked={!isAutoscaleSelected}
|
checked={!isAutoscaleSelected}
|
||||||
type="radio"
|
type="radio"
|
||||||
aria-required={true}
|
|
||||||
role="radio"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={(e) => handleOnChangeMode(e, "Manual")}
|
onChange={(e) => handleOnChangeMode(e, "Manual")}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -654,12 +654,10 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
|
|||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
aria-label="Autoscale mode"
|
aria-label="Autoscale mode"
|
||||||
aria-required={true}
|
|
||||||
checked={true}
|
checked={true}
|
||||||
className="throughputInputRadioBtn"
|
className="throughputInputRadioBtn"
|
||||||
key=".0:$.0"
|
key=".0:$.0"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
role="radio"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
type="radio"
|
type="radio"
|
||||||
/>
|
/>
|
||||||
@@ -671,12 +669,10 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
<input
|
<input
|
||||||
aria-label="Manual mode"
|
aria-label="Manual mode"
|
||||||
aria-required={true}
|
|
||||||
checked={false}
|
checked={false}
|
||||||
className="throughputInputRadioBtn"
|
className="throughputInputRadioBtn"
|
||||||
key=".0:$.2"
|
key=".0:$.2"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
role="radio"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
type="radio"
|
type="radio"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import { Link } from "@fluentui/react/lib/Link";
|
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
||||||
import * as Constants from "../Common/Constants";
|
import * as Constants from "../Common/Constants";
|
||||||
import { ConnectionStatusType, HttpStatusCodes, Notebook } from "../Common/Constants";
|
|
||||||
import { readCollection } from "../Common/dataAccess/readCollection";
|
import { readCollection } from "../Common/dataAccess/readCollection";
|
||||||
import { readDatabases } from "../Common/dataAccess/readDatabases";
|
import { readDatabases } from "../Common/dataAccess/readDatabases";
|
||||||
import { isPublicInternetAccessAllowed } from "../Common/DatabaseAccountUtility";
|
import { isPublicInternetAccessAllowed } from "../Common/DatabaseAccountUtility";
|
||||||
@@ -13,7 +11,6 @@ import { getErrorMessage, getErrorStack, handleError } from "../Common/ErrorHand
|
|||||||
import * as Logger from "../Common/Logger";
|
import * as Logger from "../Common/Logger";
|
||||||
import { QueriesClient } from "../Common/QueriesClient";
|
import { QueriesClient } from "../Common/QueriesClient";
|
||||||
import * as DataModels from "../Contracts/DataModels";
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
import { ContainerConnectionInfo } from "../Contracts/DataModels";
|
|
||||||
import * as ViewModels from "../Contracts/ViewModels";
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
||||||
import { useSidePanel } from "../hooks/useSidePanel";
|
import { useSidePanel } from "../hooks/useSidePanel";
|
||||||
@@ -166,10 +163,23 @@ export default class Explorer {
|
|||||||
|
|
||||||
useNotebook.subscribe(
|
useNotebook.subscribe(
|
||||||
async () => {
|
async () => {
|
||||||
this.initiateAndRefreshNotebookList();
|
if (!this.notebookManager) {
|
||||||
useNotebook.getState().setIsRefreshed(false);
|
const NotebookManager = await (
|
||||||
|
await import(/* webpackChunkName: "NotebookManager" */ "./Notebook/NotebookManager")
|
||||||
|
).default;
|
||||||
|
this.notebookManager = new NotebookManager();
|
||||||
|
this.notebookManager.initialize({
|
||||||
|
container: this,
|
||||||
|
resourceTree: this.resourceTree,
|
||||||
|
refreshCommandBarButtons: () => this.refreshCommandBarButtons(),
|
||||||
|
refreshNotebookList: () => this.refreshNotebookList(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refreshCommandBarButtons();
|
||||||
|
this.refreshNotebookList();
|
||||||
},
|
},
|
||||||
(state) => state.isNotebookEnabled || state.isRefreshed
|
(state) => state.isNotebookEnabled
|
||||||
);
|
);
|
||||||
|
|
||||||
this.resourceTree = new ResourceTreeAdapter(this);
|
this.resourceTree = new ResourceTreeAdapter(this);
|
||||||
@@ -202,23 +212,6 @@ export default class Explorer {
|
|||||||
this.refreshExplorer();
|
this.refreshExplorer();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async initiateAndRefreshNotebookList(): Promise<void> {
|
|
||||||
if (!this.notebookManager) {
|
|
||||||
const NotebookManager = (await import(/* webpackChunkName: "NotebookManager" */ "./Notebook/NotebookManager"))
|
|
||||||
.default;
|
|
||||||
this.notebookManager = new NotebookManager();
|
|
||||||
this.notebookManager.initialize({
|
|
||||||
container: this,
|
|
||||||
resourceTree: this.resourceTree,
|
|
||||||
refreshCommandBarButtons: () => this.refreshCommandBarButtons(),
|
|
||||||
refreshNotebookList: () => this.refreshNotebookList(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.refreshCommandBarButtons();
|
|
||||||
this.refreshNotebookList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public openEnableSynapseLinkDialog(): void {
|
public openEnableSynapseLinkDialog(): void {
|
||||||
const addSynapseLinkDialogProps: DialogProps = {
|
const addSynapseLinkDialogProps: DialogProps = {
|
||||||
linkProps: {
|
linkProps: {
|
||||||
@@ -352,7 +345,23 @@ export default class Explorer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._isInitializingNotebooks = true;
|
this._isInitializingNotebooks = true;
|
||||||
if (userContext.features.phoenix === false) {
|
if (userContext.features.phoenix) {
|
||||||
|
const provisionData = {
|
||||||
|
cosmosEndpoint: userContext.databaseAccount.properties.documentEndpoint,
|
||||||
|
resourceId: userContext.databaseAccount.id,
|
||||||
|
dbAccountName: userContext.databaseAccount.name,
|
||||||
|
aadToken: userContext.authorizationToken,
|
||||||
|
resourceGroup: userContext.resourceGroup,
|
||||||
|
subscriptionId: userContext.subscriptionId,
|
||||||
|
};
|
||||||
|
const connectionInfo = await this.phoenixClient.containerConnectionInfo(provisionData);
|
||||||
|
if (connectionInfo.data && connectionInfo.data.notebookServerUrl) {
|
||||||
|
useNotebook.getState().setNotebookServerInfo({
|
||||||
|
notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.data.notebookServerUrl,
|
||||||
|
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
await this.ensureNotebookWorkspaceRunning();
|
await this.ensureNotebookWorkspaceRunning();
|
||||||
const connectionInfo = await listConnectionInfo(
|
const connectionInfo = await listConnectionInfo(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
@@ -367,59 +376,13 @@ export default class Explorer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useNotebook.getState().initializeNotebooksTree(this.notebookManager);
|
||||||
|
|
||||||
this.refreshNotebookList();
|
this.refreshNotebookList();
|
||||||
|
|
||||||
this._isInitializingNotebooks = false;
|
this._isInitializingNotebooks = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async allocateContainer(): Promise<void> {
|
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
|
||||||
const isAllocating = useNotebook.getState().isAllocating;
|
|
||||||
if (isAllocating === false && notebookServerInfo && notebookServerInfo.notebookServerEndpoint === undefined) {
|
|
||||||
const provisionData = {
|
|
||||||
aadToken: userContext.authorizationToken,
|
|
||||||
subscriptionId: userContext.subscriptionId,
|
|
||||||
resourceGroup: userContext.resourceGroup,
|
|
||||||
dbAccountName: userContext.databaseAccount.name,
|
|
||||||
cosmosEndpoint: userContext.databaseAccount.properties.documentEndpoint,
|
|
||||||
};
|
|
||||||
const connectionStatus: ContainerConnectionInfo = {
|
|
||||||
status: ConnectionStatusType.Connecting,
|
|
||||||
};
|
|
||||||
useNotebook.getState().setConnectionInfo(connectionStatus);
|
|
||||||
try {
|
|
||||||
useNotebook.getState().setIsAllocating(true);
|
|
||||||
const connectionInfo = await this.phoenixClient.containerConnectionInfo(provisionData);
|
|
||||||
if (
|
|
||||||
connectionInfo.status === HttpStatusCodes.OK &&
|
|
||||||
connectionInfo.data &&
|
|
||||||
connectionInfo.data.notebookServerUrl
|
|
||||||
) {
|
|
||||||
connectionStatus.status = ConnectionStatusType.Connected;
|
|
||||||
useNotebook.getState().setConnectionInfo(connectionStatus);
|
|
||||||
useNotebook.getState().setNotebookServerInfo({
|
|
||||||
notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.data.notebookServerUrl,
|
|
||||||
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
|
|
||||||
});
|
|
||||||
this.notebookManager?.notebookClient
|
|
||||||
.getMemoryUsage()
|
|
||||||
.then((memoryUsageInfo) => useNotebook.getState().setMemoryUsageInfo(memoryUsageInfo));
|
|
||||||
useNotebook.getState().setIsAllocating(false);
|
|
||||||
} else {
|
|
||||||
connectionStatus.status = ConnectionStatusType.Failed;
|
|
||||||
useNotebook.getState().resetConatinerConnection(connectionStatus);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
connectionStatus.status = ConnectionStatusType.Failed;
|
|
||||||
useNotebook.getState().resetConatinerConnection(connectionStatus);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
this.refreshNotebookList();
|
|
||||||
|
|
||||||
this._isInitializingNotebooks = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public resetNotebookWorkspace(): void {
|
public resetNotebookWorkspace(): void {
|
||||||
if (!useNotebook.getState().isNotebookEnabled || !this.notebookManager?.notebookClient) {
|
if (!useNotebook.getState().isNotebookEnabled || !this.notebookManager?.notebookClient) {
|
||||||
handleError(
|
handleError(
|
||||||
@@ -691,9 +654,6 @@ export default class Explorer {
|
|||||||
if (!notebookContentItem || !notebookContentItem.path) {
|
if (!notebookContentItem || !notebookContentItem.path) {
|
||||||
throw new Error(`Invalid notebookContentItem: ${notebookContentItem}`);
|
throw new Error(`Invalid notebookContentItem: ${notebookContentItem}`);
|
||||||
}
|
}
|
||||||
if (notebookContentItem.type === NotebookContentItemType.Notebook && NotebookUtil.isPhoenixEnabled()) {
|
|
||||||
this.allocateContainer();
|
|
||||||
}
|
|
||||||
|
|
||||||
const notebookTabs = useTabs
|
const notebookTabs = useTabs
|
||||||
.getState()
|
.getState()
|
||||||
@@ -915,51 +875,9 @@ export default class Explorer {
|
|||||||
handleError(error, "Explorer/onNewNotebookClicked");
|
handleError(error, "Explorer/onNewNotebookClicked");
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
const isPhoenixEnabled = NotebookUtil.isPhoenixEnabled();
|
|
||||||
if (isPhoenixEnabled) {
|
|
||||||
if (isGithubTree) {
|
|
||||||
async () => {
|
|
||||||
await this.allocateContainer();
|
|
||||||
parent = parent || this.resourceTree.myNotebooksContentRoot;
|
|
||||||
this.createNewNoteBook(parent, isGithubTree);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
useDialog.getState().showOkCancelModalDialog(
|
|
||||||
Notebook.newNotebookModalTitle,
|
|
||||||
undefined,
|
|
||||||
"Create",
|
|
||||||
async () => {
|
|
||||||
await this.allocateContainer();
|
|
||||||
parent = parent || this.resourceTree.myNotebooksContentRoot;
|
|
||||||
this.createNewNoteBook(parent, isGithubTree);
|
|
||||||
},
|
|
||||||
"Cancel",
|
|
||||||
undefined,
|
|
||||||
this.getNewNoteWarningText()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
parent = parent || this.resourceTree.myNotebooksContentRoot;
|
|
||||||
this.createNewNoteBook(parent, isGithubTree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getNewNoteWarningText(): JSX.Element {
|
parent = parent || this.resourceTree.myNotebooksContentRoot;
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<p>{Notebook.newNotebookModalContent1}</p>
|
|
||||||
<br />
|
|
||||||
<p>
|
|
||||||
{Notebook.newNotebookModalContent2}
|
|
||||||
<Link href={Notebook.cosmosNotebookHomePageUrl} target="_blank">
|
|
||||||
{Notebook.learnMore}
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private createNewNoteBook(parent?: NotebookContentItem, isGithubTree?: boolean): void {
|
|
||||||
const clearInProgressMessage = logConsoleProgress(`Creating new notebook in ${parent.path}`);
|
const clearInProgressMessage = logConsoleProgress(`Creating new notebook in ${parent.path}`);
|
||||||
const startKey: number = TelemetryProcessor.traceStart(Action.CreateNewNotebook, {
|
const startKey: number = TelemetryProcessor.traceStart(Action.CreateNewNotebook, {
|
||||||
dataExplorerArea: Constants.Areas.Notebook,
|
dataExplorerArea: Constants.Areas.Notebook,
|
||||||
@@ -1006,26 +924,7 @@ export default class Explorer {
|
|||||||
await this.notebookManager?.notebookContentClient.updateItemChildrenInPlace(item);
|
await this.notebookManager?.notebookContentClient.updateItemChildrenInPlace(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async openNotebookTerminal(kind: ViewModels.TerminalKind): Promise<void> {
|
public openNotebookTerminal(kind: ViewModels.TerminalKind): void {
|
||||||
if (NotebookUtil.isPhoenixEnabled()) {
|
|
||||||
await this.allocateContainer();
|
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
|
||||||
if (notebookServerInfo && notebookServerInfo.notebookServerEndpoint !== undefined) {
|
|
||||||
this.connectToNotebookTerminal(kind);
|
|
||||||
} else {
|
|
||||||
useDialog
|
|
||||||
.getState()
|
|
||||||
.showOkModalDialog(
|
|
||||||
"Failed to Connect",
|
|
||||||
"Failed to connect temporary workspace, this could happen because of network issue please refresh and try again."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.connectToNotebookTerminal(kind);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private connectToNotebookTerminal(kind: ViewModels.TerminalKind): void {
|
|
||||||
let title: string;
|
let title: string;
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
@@ -1076,7 +975,7 @@ export default class Explorer {
|
|||||||
notebookUrl?: string,
|
notebookUrl?: string,
|
||||||
galleryItem?: IGalleryItem,
|
galleryItem?: IGalleryItem,
|
||||||
isFavorite?: boolean
|
isFavorite?: boolean
|
||||||
): Promise<void> {
|
) {
|
||||||
const title = "Gallery";
|
const title = "Gallery";
|
||||||
const GalleryTab = await (await import(/* webpackChunkName: "GalleryTab" */ "./Tabs/GalleryTab")).default;
|
const GalleryTab = await (await import(/* webpackChunkName: "GalleryTab" */ "./Tabs/GalleryTab")).default;
|
||||||
const galleryTab = useTabs
|
const galleryTab = useTabs
|
||||||
@@ -1180,27 +1079,7 @@ export default class Explorer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public openUploadFilePanel(parent?: NotebookContentItem): void {
|
public openUploadFilePanel(parent?: NotebookContentItem): void {
|
||||||
if (NotebookUtil.isPhoenixEnabled()) {
|
parent = parent || this.resourceTree.myNotebooksContentRoot;
|
||||||
useDialog.getState().showOkCancelModalDialog(
|
|
||||||
Notebook.newNotebookUploadModalTitle,
|
|
||||||
undefined,
|
|
||||||
"Upload",
|
|
||||||
async () => {
|
|
||||||
await this.allocateContainer();
|
|
||||||
parent = parent || this.resourceTree.myNotebooksContentRoot;
|
|
||||||
this.uploadFilePanel(parent);
|
|
||||||
},
|
|
||||||
"Cancel",
|
|
||||||
undefined,
|
|
||||||
this.getNewNoteWarningText()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
parent = parent || this.resourceTree.myNotebooksContentRoot;
|
|
||||||
this.uploadFilePanel(parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private uploadFilePanel(parent?: NotebookContentItem): void {
|
|
||||||
useSidePanel
|
useSidePanel
|
||||||
.getState()
|
.getState()
|
||||||
.openSidePanel(
|
.openSidePanel(
|
||||||
@@ -1209,24 +1088,6 @@ export default class Explorer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDownloadModalConent(fileName: string): JSX.Element {
|
|
||||||
if (NotebookUtil.isPhoenixEnabled()) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<p>{Notebook.galleryNotebookDownloadContent1}</p>
|
|
||||||
<br />
|
|
||||||
<p>
|
|
||||||
{Notebook.galleryNotebookDownloadContent2}
|
|
||||||
<Link href={Notebook.cosmosNotebookGitDocumentationUrl} target="_blank">
|
|
||||||
{Notebook.learnMore}
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <p> Download {fileName} from gallery as a copy to your notebooks to run and/or edit the notebook. </p>;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async refreshExplorer(): Promise<void> {
|
public async refreshExplorer(): Promise<void> {
|
||||||
userContext.authType === AuthType.ResourceToken
|
userContext.authType === AuthType.ResourceToken
|
||||||
? this.refreshDatabaseForResourceToken()
|
? this.refreshDatabaseForResourceToken()
|
||||||
|
|||||||
@@ -214,8 +214,14 @@ export class EditorNeighborsComponent extends React.Component<EditorNeighborsCom
|
|||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td className="actionCol">
|
<td className="actionCol">
|
||||||
<span className="rightPaneTrashIcon rightPaneBtns">
|
<span
|
||||||
<img src={DeleteIcon} alt="Delete" onClick={() => this.removeAddedEdgeToNeighbor(index)} />
|
className="rightPaneTrashIcon rightPaneBtns"
|
||||||
|
role="button"
|
||||||
|
onKeyPress={() => this.removeAddedEdgeToNeighbor(index)}
|
||||||
|
onClick={() => this.removeAddedEdgeToNeighbor(index)}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
|
<img src={DeleteIcon} alt="Delete" />
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ export class EditorNodePropertiesComponent extends React.Component<EditorNodePro
|
|||||||
<select
|
<select
|
||||||
className="typeSelect"
|
className="typeSelect"
|
||||||
value={singleValue.type}
|
value={singleValue.type}
|
||||||
onChange={(e) => {
|
onBlur={(e) => {
|
||||||
singleValue.type = e.target.value as ViewModels.InputPropertyValueTypeString;
|
singleValue.type = e.target.value as ViewModels.InputPropertyValueTypeString;
|
||||||
if (singleValue.type === "null") {
|
if (singleValue.type === "null") {
|
||||||
singleValue.value = undefined;
|
singleValue.value = undefined;
|
||||||
@@ -217,7 +217,7 @@ export class EditorNodePropertiesComponent extends React.Component<EditorNodePro
|
|||||||
<select
|
<select
|
||||||
className="typeSelect"
|
className="typeSelect"
|
||||||
value={firstValue.type}
|
value={firstValue.type}
|
||||||
onChange={(e) => {
|
onBlur={(e) => {
|
||||||
firstValue.type = e.target.value as ViewModels.InputPropertyValueTypeString;
|
firstValue.type = e.target.value as ViewModels.InputPropertyValueTypeString;
|
||||||
this.props.onUpdateProperties(this.props.editedProperties);
|
this.props.onUpdateProperties(this.props.editedProperties);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
|
||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
import { FeedOptions, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
import { FeedOptions, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
||||||
import * as Q from "q";
|
import * as Q from "q";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
@@ -296,6 +294,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
this.setGremlinParams();
|
this.setGremlinParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const selectedNode = this.state.highlightedNode;
|
||||||
|
|
||||||
props.onGraphAccessorCreated({
|
props.onGraphAccessorCreated({
|
||||||
applyFilter: this.submitQuery.bind(this),
|
applyFilter: this.submitQuery.bind(this),
|
||||||
addVertex: this.addVertex.bind(this),
|
addVertex: this.addVertex.bind(this),
|
||||||
@@ -303,7 +303,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
});
|
});
|
||||||
} // constructor
|
} // constructor
|
||||||
|
|
||||||
public shareIGraphConfig(igraphConfig: IGraphConfig): void {
|
public shareIGraphConfig(igraphConfig: IGraphConfig) {
|
||||||
this.setState({
|
this.setState({
|
||||||
igraphConfig: { ...igraphConfig },
|
igraphConfig: { ...igraphConfig },
|
||||||
});
|
});
|
||||||
@@ -330,10 +330,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
const partitionKeyProperty = this.props.collectionPartitionKeyProperty;
|
const partitionKeyProperty = this.props.collectionPartitionKeyProperty;
|
||||||
|
|
||||||
// aggregate all the properties, remove dropped ones
|
// aggregate all the properties, remove dropped ones
|
||||||
const finalProperties = editedProperties.existingProperties.concat(editedProperties.addedProperties);
|
let finalProperties = editedProperties.existingProperties.concat(editedProperties.addedProperties);
|
||||||
|
|
||||||
// Compose the query
|
// Compose the query
|
||||||
const pkId = editedProperties.pkId;
|
let pkId = editedProperties.pkId;
|
||||||
let updateQueryFragment = "";
|
let updateQueryFragment = "";
|
||||||
|
|
||||||
finalProperties.forEach((p) => {
|
finalProperties.forEach((p) => {
|
||||||
@@ -422,7 +422,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
* Called from ko binding
|
* Called from ko binding
|
||||||
* @param id
|
* @param id
|
||||||
*/
|
*/
|
||||||
public selectNode(id: string): void {
|
public selectNode(id: string) {
|
||||||
if (!this.d3ForceGraph) {
|
if (!this.d3ForceGraph) {
|
||||||
console.warn("Attempting to select node, but d3ForceGraph not initialized, yet.");
|
console.warn("Attempting to select node, but d3ForceGraph not initialized, yet.");
|
||||||
return;
|
return;
|
||||||
@@ -431,7 +431,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
this.d3ForceGraph.selectNode(id);
|
this.d3ForceGraph.selectNode(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public deleteHighlightedNode(): void {
|
public deleteHighlightedNode() {
|
||||||
if (!this.state.highlightedNode) {
|
if (!this.state.highlightedNode) {
|
||||||
GraphExplorer.reportToConsole(ConsoleDataType.Error, "No highlighted node to remove.");
|
GraphExplorer.reportToConsole(ConsoleDataType.Error, "No highlighted node to remove.");
|
||||||
return;
|
return;
|
||||||
@@ -467,23 +467,23 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
* Is of type: {e: GremlinEdge, v: GremlinVertex}[]
|
* Is of type: {e: GremlinEdge, v: GremlinVertex}[]
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
public static isEdgeVertexPairArray(data: any): boolean {
|
public static isEdgeVertexPairArray(data: any) {
|
||||||
if (!(data instanceof Array)) {
|
if (!(data instanceof Array)) {
|
||||||
GraphExplorer.reportToConsole(ConsoleDataType.Info, "Query result not an array", data);
|
GraphExplorer.reportToConsole(ConsoleDataType.Info, "Query result not an array", data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pairs: any[] = data;
|
let pairs: any[] = data;
|
||||||
for (let i = 0; i < pairs.length; i++) {
|
for (let i = 0; i < pairs.length; i++) {
|
||||||
const item = pairs[i];
|
const item = pairs[i];
|
||||||
if (
|
if (
|
||||||
!Object.prototype.hasOwnProperty.call(item, "e") ||
|
!item.hasOwnProperty("e") ||
|
||||||
!Object.prototype.hasOwnProperty.call(item, "v") ||
|
!item.hasOwnProperty("v") ||
|
||||||
!Object.prototype.hasOwnProperty.call(item["e"], "id") ||
|
!item["e"].hasOwnProperty("id") ||
|
||||||
!Object.prototype.hasOwnProperty.call(item["e"], "type") ||
|
!item["e"].hasOwnProperty("type") ||
|
||||||
item["e"].type !== "edge" ||
|
item["e"].type !== "edge" ||
|
||||||
!Object.prototype.hasOwnProperty.call(item["v"], "id") ||
|
!item["v"].hasOwnProperty("id") ||
|
||||||
!Object.prototype.hasOwnProperty.call(item["e"], "type") ||
|
!item["v"].hasOwnProperty("type") ||
|
||||||
item["v"].type !== "vertex"
|
item["v"].type !== "vertex"
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
@@ -514,7 +514,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
// Try hitting cache first
|
// Try hitting cache first
|
||||||
const cache = outE ? this.outECache : this.inECache;
|
const cache = outE ? this.outECache : this.inECache;
|
||||||
const pairs = cache.retrieve(vertex.id, startIndex, pageSize);
|
const pairs = cache.retrieve(vertex.id, startIndex, pageSize);
|
||||||
if (pairs !== null && pairs.length === pageSize) {
|
if (pairs != null && pairs.length === pageSize) {
|
||||||
const msg = `Retrieved ${pairs.length} ${outE ? "outE" : "inE"} edges from cache for vertex id: ${vertex.id}`;
|
const msg = `Retrieved ${pairs.length} ${outE ? "outE" : "inE"} edges from cache for vertex id: ${vertex.id}`;
|
||||||
GraphExplorer.reportToConsole(ConsoleDataType.Info, msg);
|
GraphExplorer.reportToConsole(ConsoleDataType.Info, msg);
|
||||||
return Q.resolve(pairs);
|
return Q.resolve(pairs);
|
||||||
@@ -588,6 +588,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
vertex._outEAllLoaded &&
|
vertex._outEAllLoaded &&
|
||||||
vertex._inEAllLoaded
|
vertex._inEAllLoaded
|
||||||
) {
|
) {
|
||||||
|
console.info("No more edges to load for vertex " + vertex.id);
|
||||||
updateGraphData();
|
updateGraphData();
|
||||||
return Q.resolve(graphData);
|
return Q.resolve(graphData);
|
||||||
}
|
}
|
||||||
@@ -667,7 +668,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return promise.then(() => {
|
return promise.then((nbPairsFetched: number) => {
|
||||||
if (offsetIndex >= GraphExplorer.LOAD_PAGE_SIZE || !vertex._outEAllLoaded || !vertex._inEAllLoaded) {
|
if (offsetIndex >= GraphExplorer.LOAD_PAGE_SIZE || !vertex._outEAllLoaded || !vertex._inEAllLoaded) {
|
||||||
vertex._pagination = {
|
vertex._pagination = {
|
||||||
total:
|
total:
|
||||||
@@ -753,7 +754,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
* Create a new edge in docdb and update graph
|
* Create a new edge in docdb and update graph
|
||||||
* @param e
|
* @param e
|
||||||
*/
|
*/
|
||||||
public createNewEdge(e: GraphNewEdgeData): Q.Promise<unknown> {
|
public createNewEdge(e: GraphNewEdgeData): Q.Promise<any> {
|
||||||
const q = `g.V('${GraphUtil.escapeSingleQuotes(e.inputOutV)}').addE('${GraphUtil.escapeSingleQuotes(
|
const q = `g.V('${GraphUtil.escapeSingleQuotes(e.inputOutV)}').addE('${GraphUtil.escapeSingleQuotes(
|
||||||
e.label
|
e.label
|
||||||
)}').To(g.V('${GraphUtil.escapeSingleQuotes(e.inputInV)}'))`;
|
)}').To(g.V('${GraphUtil.escapeSingleQuotes(e.inputInV)}'))`;
|
||||||
@@ -771,8 +772,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const edge = edges[0];
|
let edge = edges[0];
|
||||||
const graphData = this.originalGraphData;
|
let graphData = this.originalGraphData;
|
||||||
graphData.addEdge(edge);
|
graphData.addEdge(edge);
|
||||||
|
|
||||||
// Allow loadNeighbors to load list new edge
|
// Allow loadNeighbors to load list new edge
|
||||||
@@ -799,10 +800,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
* Manually update in-memory graph.
|
* Manually update in-memory graph.
|
||||||
* @param edgeId
|
* @param edgeId
|
||||||
*/
|
*/
|
||||||
public removeEdge(edgeId: string): Q.Promise<unknown> {
|
public removeEdge(edgeId: string): Q.Promise<any> {
|
||||||
return this.submitToBackend(`g.E('${GraphUtil.escapeSingleQuotes(edgeId)}').drop()`).then(
|
return this.submitToBackend(`g.E('${GraphUtil.escapeSingleQuotes(edgeId)}').drop()`).then(
|
||||||
() => {
|
() => {
|
||||||
const graphData = this.originalGraphData;
|
let graphData = this.originalGraphData;
|
||||||
graphData.removeEdge(edgeId, false);
|
graphData.removeEdge(edgeId, false);
|
||||||
this.updateGraphData(graphData, this.state.igraphConfig);
|
this.updateGraphData(graphData, this.state.igraphConfig);
|
||||||
},
|
},
|
||||||
@@ -825,14 +826,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const vertices: any[] = data;
|
let vertices: any[] = data;
|
||||||
if (vertices.length > 0) {
|
if (vertices.length > 0) {
|
||||||
const v0 = vertices[0];
|
let v0 = vertices[0];
|
||||||
if (
|
if (!v0.hasOwnProperty("id") || !v0.hasOwnProperty("type") || v0.type !== "vertex") {
|
||||||
!Object.prototype.hasOwnProperty.call(v0, "id") ||
|
|
||||||
!Object.prototype.hasOwnProperty.call(v0, "type") ||
|
|
||||||
v0.type !== "vertex"
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -840,7 +837,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
public processGremlinQueryResults(result: GremlinClient.GremlinRequestResult): void {
|
public processGremlinQueryResults(result: GremlinClient.GremlinRequestResult): void {
|
||||||
const data = result.data as GraphData.GremlinVertex[];
|
const data = result.data as any;
|
||||||
this.setFilterQueryStatus(FilterQueryStatus.GraphEmptyResult);
|
this.setFilterQueryStatus(FilterQueryStatus.GraphEmptyResult);
|
||||||
|
|
||||||
if (data === null) {
|
if (data === null) {
|
||||||
@@ -930,13 +927,13 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
throw { title: err };
|
throw { title: err };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertices === null || vertices.length < 1) {
|
if (vertices == null || vertices.length < 1) {
|
||||||
const err = "Failed to create vertex (no vertex in response)";
|
const err = "Failed to create vertex (no vertex in response)";
|
||||||
GraphExplorer.reportToConsole(ConsoleDataType.Error, err, vertices);
|
GraphExplorer.reportToConsole(ConsoleDataType.Error, err, vertices);
|
||||||
throw { title: err };
|
throw { title: err };
|
||||||
}
|
}
|
||||||
|
|
||||||
const vertex = vertices[0];
|
let vertex = vertices[0];
|
||||||
const graphData = this.originalGraphData;
|
const graphData = this.originalGraphData;
|
||||||
graphData.addVertex(vertex);
|
graphData.addVertex(vertex);
|
||||||
this.updateGraphData(graphData, this.state.igraphConfig);
|
this.updateGraphData(graphData, this.state.igraphConfig);
|
||||||
@@ -1025,7 +1022,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
this.gremlinClient.destroy();
|
this.gremlinClient.destroy();
|
||||||
}
|
}
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
if (this.props.onLoadStartKey !== null && this.props.onLoadStartKey !== undefined) {
|
if (this.props.onLoadStartKey != null && this.props.onLoadStartKey != undefined) {
|
||||||
TelemetryProcessor.traceSuccess(
|
TelemetryProcessor.traceSuccess(
|
||||||
Action.Tab,
|
Action.Tab,
|
||||||
{
|
{
|
||||||
@@ -1085,7 +1082,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
public static reportToConsole(type: ConsoleDataType.Info, msg: string, ...errorData: any[]): void;
|
public static reportToConsole(type: ConsoleDataType.Info, msg: string, ...errorData: any[]): void;
|
||||||
public static reportToConsole(type: ConsoleDataType.Error, msg: string, ...errorData: any[]): void;
|
public static reportToConsole(type: ConsoleDataType.Error, msg: string, ...errorData: any[]): void;
|
||||||
public static reportToConsole(type: ConsoleDataType, msg: string, ...errorData: any[]): void | (() => void) {
|
public static reportToConsole(type: ConsoleDataType, msg: string, ...errorData: any[]): void | (() => void) {
|
||||||
let errorDataStr = "";
|
let errorDataStr: string = "";
|
||||||
if (errorData && errorData.length > 0) {
|
if (errorData && errorData.length > 0) {
|
||||||
console.error(msg, errorData);
|
console.error(msg, errorData);
|
||||||
errorDataStr = ": " + JSON.stringify(errorData);
|
errorDataStr = ": " + JSON.stringify(errorData);
|
||||||
@@ -1164,15 +1161,12 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
)}"`
|
)}"`
|
||||||
).then(
|
).then(
|
||||||
(documents: DataModels.DocumentId[]) => {
|
(documents: DataModels.DocumentId[]) => {
|
||||||
$.each(
|
$.each(documents, (index: number, doc: any) => {
|
||||||
documents,
|
newIconsMap[doc["_graph_icon_property_value"]] = {
|
||||||
(index: number, doc: { _graph_icon_property_value: string; icon: string; format: string }) => {
|
data: doc["icon"],
|
||||||
newIconsMap[doc["_graph_icon_property_value"]] = {
|
format: doc["format"],
|
||||||
data: doc["icon"],
|
};
|
||||||
format: doc["format"],
|
});
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update graph configuration
|
// Update graph configuration
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -1229,8 +1223,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
const key = this.state.igraphConfig.nodeCaption;
|
const key = this.state.igraphConfig.nodeCaption;
|
||||||
return $.map(
|
return $.map(
|
||||||
this.state.rootMap,
|
this.state.rootMap,
|
||||||
(value: any): LeftPane.CaptionId => {
|
(value: any, index: number): LeftPane.CaptionId => {
|
||||||
const result = GraphData.GraphData.getNodePropValue(value, key);
|
let result = GraphData.GraphData.getNodePropValue(value, key);
|
||||||
return {
|
return {
|
||||||
caption: result !== undefined ? result : value.id,
|
caption: result !== undefined ? result : value.id,
|
||||||
id: value.id,
|
id: value.id,
|
||||||
@@ -1243,7 +1237,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
* Selecting a root node means
|
* Selecting a root node means
|
||||||
* @param node
|
* @param node
|
||||||
*/
|
*/
|
||||||
private selectRootNode(id: string): Q.Promise<unknown> {
|
private selectRootNode(id: string): Q.Promise<any> {
|
||||||
if (!this.d3ForceGraph) {
|
if (!this.d3ForceGraph) {
|
||||||
console.warn("Attempting to reset zoom, but d3ForceGraph not initialized, yet.");
|
console.warn("Attempting to reset zoom, but d3ForceGraph not initialized, yet.");
|
||||||
} else {
|
} else {
|
||||||
@@ -1288,7 +1282,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
this.collectNodeProperties(this.originalGraphData.vertices);
|
this.collectNodeProperties(this.originalGraphData.vertices);
|
||||||
this.updatePropertiesPane(id);
|
this.updatePropertiesPane(id);
|
||||||
},
|
},
|
||||||
(reason: string) => {
|
(reason: any) => {
|
||||||
GraphExplorer.reportToConsole(ConsoleDataType.Error, `Failed to select root node. Reason:${reason}`);
|
GraphExplorer.reportToConsole(ConsoleDataType.Error, `Failed to select root node. Reason:${reason}`);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -1355,10 +1349,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
private getPkIdFromVertex(v: GraphData.GremlinVertex): string {
|
private getPkIdFromVertex(v: GraphData.GremlinVertex): string {
|
||||||
if (
|
if (
|
||||||
this.props.collectionPartitionKeyProperty &&
|
this.props.collectionPartitionKeyProperty &&
|
||||||
Object.prototype.hasOwnProperty.call(v, "properties") &&
|
v.hasOwnProperty("properties") &&
|
||||||
Object.prototype.hasOwnProperty.call(v.properties, this.props.collectionPartitionKeyProperty) &&
|
v.properties.hasOwnProperty(this.props.collectionPartitionKeyProperty) &&
|
||||||
v.properties[this.props.collectionPartitionKeyProperty].length > 0 &&
|
v.properties[this.props.collectionPartitionKeyProperty].length > 0 &&
|
||||||
Object.prototype.hasOwnProperty.call(v.properties[this.props.collectionPartitionKeyProperty][0], "value")
|
v.properties[this.props.collectionPartitionKeyProperty][0].hasOwnProperty("value")
|
||||||
) {
|
) {
|
||||||
const pk = v.properties[this.props.collectionPartitionKeyProperty][0].value;
|
const pk = v.properties[this.props.collectionPartitionKeyProperty][0].value;
|
||||||
return GraphExplorer.generatePkIdPair(pk, v.id);
|
return GraphExplorer.generatePkIdPair(pk, v.id);
|
||||||
@@ -1376,8 +1370,8 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
private getPkIdFromNodeData(v: GraphHighlightedNodeData): string {
|
private getPkIdFromNodeData(v: GraphHighlightedNodeData): string {
|
||||||
if (
|
if (
|
||||||
this.props.collectionPartitionKeyProperty &&
|
this.props.collectionPartitionKeyProperty &&
|
||||||
Object.prototype.hasOwnProperty.call(v, "properties") &&
|
v.hasOwnProperty("properties") &&
|
||||||
Object.prototype.hasOwnProperty.call(v.properties, this.props.collectionPartitionKeyProperty)
|
v.properties.hasOwnProperty(this.props.collectionPartitionKeyProperty)
|
||||||
) {
|
) {
|
||||||
const pk = v.properties[this.props.collectionPartitionKeyProperty];
|
const pk = v.properties[this.props.collectionPartitionKeyProperty];
|
||||||
return GraphExplorer.generatePkIdPair(pk[0] as PartitionKeyValueType, v.id);
|
return GraphExplorer.generatePkIdPair(pk[0] as PartitionKeyValueType, v.id);
|
||||||
@@ -1394,14 +1388,14 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
* @return id
|
* @return id
|
||||||
*/
|
*/
|
||||||
public static getPkIdFromDocumentId(d: DataModels.DocumentId, collectionPartitionKeyProperty: string): string {
|
public static getPkIdFromDocumentId(d: DataModels.DocumentId, collectionPartitionKeyProperty: string): string {
|
||||||
const { id } = d;
|
let { id } = d;
|
||||||
if (typeof id !== "string") {
|
if (typeof id !== "string") {
|
||||||
const error = `Vertex id is not a string: ${JSON.stringify(id)}.`;
|
const error = `Vertex id is not a string: ${JSON.stringify(id)}.`;
|
||||||
logConsoleError(error);
|
logConsoleError(error);
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionPartitionKeyProperty && Object.prototype.hasOwnProperty.call(d, collectionPartitionKeyProperty)) {
|
if (collectionPartitionKeyProperty && d.hasOwnProperty(collectionPartitionKeyProperty)) {
|
||||||
let pk = (d as any)[collectionPartitionKeyProperty];
|
let pk = (d as any)[collectionPartitionKeyProperty];
|
||||||
if (typeof pk !== "string" && typeof pk !== "number" && typeof pk !== "boolean") {
|
if (typeof pk !== "string" && typeof pk !== "number" && typeof pk !== "boolean") {
|
||||||
if (Array.isArray(pk) && pk.length > 0) {
|
if (Array.isArray(pk) && pk.length > 0) {
|
||||||
@@ -1431,7 +1425,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
}"] AS p FROM c WHERE NOT IS_DEFINED(c._isEdge)`;
|
}"] AS p FROM c WHERE NOT IS_DEFINED(c._isEdge)`;
|
||||||
return this.executeNonPagedDocDbQuery(q).then(
|
return this.executeNonPagedDocDbQuery(q).then(
|
||||||
(documents: DataModels.DocumentId[]) => {
|
(documents: DataModels.DocumentId[]) => {
|
||||||
const possibleVertices = [] as PossibleVertex[];
|
let possibleVertices = [] as PossibleVertex[];
|
||||||
$.each(documents, (index: number, item: any) => {
|
$.each(documents, (index: number, item: any) => {
|
||||||
if (highlightedNodeId && item.id === highlightedNodeId) {
|
if (highlightedNodeId && item.id === highlightedNodeId) {
|
||||||
// Exclude highlighed node in the list
|
// Exclude highlighed node in the list
|
||||||
@@ -1445,7 +1439,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
caption: item.p,
|
caption: item.p,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (Object.prototype.hasOwnProperty.call(item, "p")) {
|
if (item.hasOwnProperty("p")) {
|
||||||
possibleVertices.push({
|
possibleVertices.push({
|
||||||
value: item.id,
|
value: item.id,
|
||||||
caption: item.p[0]["_value"],
|
caption: item.p[0]["_value"],
|
||||||
@@ -1468,17 +1462,17 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
* @param addedEdges
|
* @param addedEdges
|
||||||
* @return promise when done
|
* @return promise when done
|
||||||
*/
|
*/
|
||||||
private editGraphEdges(editedEdges: EditedEdges): Q.Promise<unknown> {
|
private editGraphEdges(editedEdges: EditedEdges): Q.Promise<any> {
|
||||||
const promises = [];
|
let promises = [];
|
||||||
// Drop edges
|
// Drop edges
|
||||||
for (let i = 0; i < editedEdges.droppedIds.length; i++) {
|
for (let i = 0; i < editedEdges.droppedIds.length; i++) {
|
||||||
const id = editedEdges.droppedIds[i];
|
let id = editedEdges.droppedIds[i];
|
||||||
promises.push(this.removeEdge(id));
|
promises.push(this.removeEdge(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add edges
|
// Add edges
|
||||||
for (let i = 0; i < editedEdges.addedEdges.length; i++) {
|
for (let i = 0; i < editedEdges.addedEdges.length; i++) {
|
||||||
const e = editedEdges.addedEdges[i];
|
let e = editedEdges.addedEdges[i];
|
||||||
promises.push(
|
promises.push(
|
||||||
this.createNewEdge(e).then(() => {
|
this.createNewEdge(e).then(() => {
|
||||||
// Reload neighbors in case we linked to a vertex that isn't loaded in the graph
|
// Reload neighbors in case we linked to a vertex that isn't loaded in the graph
|
||||||
@@ -1531,9 +1525,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
/**
|
/**
|
||||||
* For unit testing purposes
|
* For unit testing purposes
|
||||||
*/
|
*/
|
||||||
|
public onGraphUpdated(timestamp: number): void {}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
public onGraphUpdated(_timestamp: number): void {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get node properties for styling purposes. Result is the union of all properties of all nodes.
|
* Get node properties for styling purposes. Result is the union of all properties of all nodes.
|
||||||
@@ -1541,17 +1533,17 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
private collectNodeProperties(vertices: GraphData.GremlinVertex[]) {
|
private collectNodeProperties(vertices: GraphData.GremlinVertex[]) {
|
||||||
const props = {} as any; // Hashset
|
const props = {} as any; // Hashset
|
||||||
$.each(vertices, (index: number, item: GraphData.GremlinVertex) => {
|
$.each(vertices, (index: number, item: GraphData.GremlinVertex) => {
|
||||||
for (const p in item) {
|
for (var p in item) {
|
||||||
// DocDB: Exclude type because it's always 'vertex'
|
// DocDB: Exclude type because it's always 'vertex'
|
||||||
if (p !== "type" && typeof (item as any)[p] === "string") {
|
if (p !== "type" && typeof (item as any)[p] === "string") {
|
||||||
props[p] = true;
|
props[p] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Inspect properties
|
// Inspect properties
|
||||||
if (Object.prototype.hasOwnProperty.call(item, "properties")) {
|
if (item.hasOwnProperty("properties")) {
|
||||||
// TODO This is DocDB-graph specific
|
// TODO This is DocDB-graph specific
|
||||||
// Assume each property value is [{value:... }]
|
// Assume each property value is [{value:... }]
|
||||||
for (const f in item.properties) {
|
for (var f in item.properties) {
|
||||||
props[f] = true;
|
props[f] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1578,21 +1570,21 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = this.originalGraphData.getVertexById(id);
|
let data = this.originalGraphData.getVertexById(id);
|
||||||
|
|
||||||
// A bit of translation to make it easier to display
|
// A bit of translation to make it easier to display
|
||||||
const props: { [id: string]: ViewModels.GremlinPropertyValueType[] } = {};
|
let props: { [id: string]: ViewModels.GremlinPropertyValueType[] } = {};
|
||||||
for (const p in data.properties) {
|
for (let p in data.properties) {
|
||||||
props[p] = data.properties[p].map((gremlinProperty) => gremlinProperty.value);
|
props[p] = data.properties[p].map((gremlinProperty) => gremlinProperty.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update neighbors
|
// update neighbors
|
||||||
const sources: NeighborVertexBasicInfo[] = [];
|
let sources: NeighborVertexBasicInfo[] = [];
|
||||||
const targets: NeighborVertexBasicInfo[] = [];
|
let targets: NeighborVertexBasicInfo[] = [];
|
||||||
this.props.onResetDefaultGraphConfigValues();
|
this.props.onResetDefaultGraphConfigValues();
|
||||||
const nodeCaption = this.state.igraphConfigUiData.nodeCaptionChoice;
|
let nodeCaption = this.state.igraphConfigUiData.nodeCaptionChoice;
|
||||||
this.updateSelectedNodeNeighbors(data.id, nodeCaption, sources, targets);
|
this.updateSelectedNodeNeighbors(data.id, nodeCaption, sources, targets);
|
||||||
const sData: GraphHighlightedNodeData = {
|
let sData: GraphHighlightedNodeData = {
|
||||||
id: data.id,
|
id: data.id,
|
||||||
label: data.label,
|
label: data.label,
|
||||||
properties: props,
|
properties: props,
|
||||||
@@ -1619,16 +1611,16 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
targets: NeighborVertexBasicInfo[]
|
targets: NeighborVertexBasicInfo[]
|
||||||
): void {
|
): void {
|
||||||
// update neighbors
|
// update neighbors
|
||||||
const gd = this.originalGraphData;
|
let gd = this.originalGraphData;
|
||||||
const v = gd.getVertexById(id);
|
let v = gd.getVertexById(id);
|
||||||
|
|
||||||
// Clear the array while keeping the references
|
// Clear the array while keeping the references
|
||||||
sources.length = 0;
|
sources.length = 0;
|
||||||
targets.length = 0;
|
targets.length = 0;
|
||||||
|
|
||||||
const possibleEdgeLabels = {} as any; // Collect all edge labels in a hashset
|
let possibleEdgeLabels = {} as any; // Collect all edge labels in a hashset
|
||||||
|
|
||||||
for (const p in v.inE) {
|
for (let p in v.inE) {
|
||||||
possibleEdgeLabels[p] = true;
|
possibleEdgeLabels[p] = true;
|
||||||
const edges = v.inE[p];
|
const edges = v.inE[p];
|
||||||
$.each(edges, (index: number, edge: GraphData.GremlinShortInEdge) => {
|
$.each(edges, (index: number, edge: GraphData.GremlinShortInEdge) => {
|
||||||
@@ -1637,7 +1629,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
// If id not known, it must be an edge node whose neighbor hasn't been loaded into the graph, yet
|
// If id not known, it must be an edge node whose neighbor hasn't been loaded into the graph, yet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
|
let caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
|
||||||
sources.push({
|
sources.push({
|
||||||
name: caption,
|
name: caption,
|
||||||
id: neighborId,
|
id: neighborId,
|
||||||
@@ -1647,7 +1639,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const p in v.outE) {
|
for (let p in v.outE) {
|
||||||
possibleEdgeLabels[p] = true;
|
possibleEdgeLabels[p] = true;
|
||||||
const edges = v.outE[p];
|
const edges = v.outE[p];
|
||||||
$.each(edges, (index: number, edge: GraphData.GremlinShortOutEdge) => {
|
$.each(edges, (index: number, edge: GraphData.GremlinShortOutEdge) => {
|
||||||
@@ -1656,7 +1648,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
// If id not known, it must be an edge node whose neighbor hasn't been loaded into the graph, yet
|
// If id not known, it must be an edge node whose neighbor hasn't been loaded into the graph, yet
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
|
let caption = GraphData.GraphData.getNodePropValue(gd.getVertexById(neighborId), nodeCaption) as string;
|
||||||
targets.push({
|
targets.push({
|
||||||
name: caption,
|
name: caption,
|
||||||
id: neighborId,
|
id: neighborId,
|
||||||
@@ -1668,7 +1660,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
possibleEdgeLabels: Object.keys(possibleEdgeLabels).map(
|
possibleEdgeLabels: Object.keys(possibleEdgeLabels).map(
|
||||||
(value: string): InputTypeaheadComponent.Item => {
|
(value: string, index: number, array: string[]): InputTypeaheadComponent.Item => {
|
||||||
return { caption: value, value: value };
|
return { caption: value, value: value };
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
@@ -1689,20 +1681,20 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedVertex = vertices[0];
|
let updatedVertex = vertices[0];
|
||||||
if (this.originalGraphData.hasVertexId(updatedVertex.id)) {
|
if (this.originalGraphData.hasVertexId(updatedVertex.id)) {
|
||||||
const currentVertex = this.originalGraphData.getVertexById(updatedVertex.id);
|
let currentVertex = this.originalGraphData.getVertexById(updatedVertex.id);
|
||||||
// Copy updated properties
|
// Copy updated properties
|
||||||
if (Object.prototype.hasOwnProperty.call(currentVertex, "properties")) {
|
if (currentVertex.hasOwnProperty("properties")) {
|
||||||
delete currentVertex["properties"];
|
delete currentVertex["properties"];
|
||||||
}
|
}
|
||||||
for (const p in updatedVertex) {
|
for (var p in updatedVertex) {
|
||||||
(currentVertex as any)[p] = updatedVertex[p];
|
(currentVertex as any)[p] = updatedVertex[p];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO This kind of assumes saveVertexProperty is done from property panes.
|
// TODO This kind of assumes saveVertexProperty is done from property panes.
|
||||||
const hn = this.state.highlightedNode;
|
let hn = this.state.highlightedNode;
|
||||||
if (hn && hn.id === updatedVertex.id) {
|
if (hn && hn.id === updatedVertex.id) {
|
||||||
this.updatePropertiesPane(hn.id);
|
this.updatePropertiesPane(hn.id);
|
||||||
}
|
}
|
||||||
@@ -1716,7 +1708,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
igraphConfig?: IGraphConfig
|
igraphConfig?: IGraphConfig
|
||||||
) {
|
) {
|
||||||
this.originalGraphData = graphData;
|
this.originalGraphData = graphData;
|
||||||
const gd = JSON.parse(JSON.stringify(this.originalGraphData));
|
let gd = JSON.parse(JSON.stringify(this.originalGraphData));
|
||||||
if (!this.d3ForceGraph) {
|
if (!this.d3ForceGraph) {
|
||||||
console.warn("Attempting to update graph, but d3ForceGraph not initialized, yet.");
|
console.warn("Attempting to update graph, but d3ForceGraph not initialized, yet.");
|
||||||
return;
|
return;
|
||||||
@@ -1881,7 +1873,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
|
|
||||||
promise
|
promise
|
||||||
.then((result: GremlinClient.GremlinRequestResult) => this.processGremlinQueryResults(result))
|
.then((result: GremlinClient.GremlinRequestResult) => this.processGremlinQueryResults(result))
|
||||||
.catch((error: Error) => {
|
.catch((error: any) => {
|
||||||
const errorMsg = `Failed to process query result: ${getErrorMessage(error)}`;
|
const errorMsg = `Failed to process query result: ${getErrorMessage(error)}`;
|
||||||
GraphExplorer.reportToConsole(ConsoleDataType.Error, errorMsg);
|
GraphExplorer.reportToConsole(ConsoleDataType.Error, errorMsg);
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export class LeftPaneComponent extends React.Component<LeftPaneComponentProps> {
|
|||||||
className={className}
|
className={className}
|
||||||
as="tr"
|
as="tr"
|
||||||
aria-label={node.caption}
|
aria-label={node.caption}
|
||||||
onActivated={() => this.props.onRootNodeSelected(node.id)}
|
onActivated={(e) => this.props.onRootNodeSelected(node.id)}
|
||||||
key={node.id}
|
key={node.id}
|
||||||
>
|
>
|
||||||
<td className="resultItem">
|
<td className="resultItem">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import React from "react";
|
||||||
import { mount, ReactWrapper } from "enzyme";
|
import { mount, ReactWrapper } from "enzyme";
|
||||||
import * as Q from "q";
|
import * as Q from "q";
|
||||||
import React from "react";
|
import { NodePropertiesComponent, NodePropertiesComponentProps, Mode } from "./NodePropertiesComponent";
|
||||||
import { GraphHighlightedNodeData, PossibleVertex } from "./GraphExplorer";
|
import { GraphHighlightedNodeData, EditedProperties, EditedEdges, PossibleVertex } from "./GraphExplorer";
|
||||||
import { Mode, NodePropertiesComponent, NodePropertiesComponentProps } from "./NodePropertiesComponent";
|
|
||||||
|
|
||||||
describe("Property pane", () => {
|
describe("Property pane", () => {
|
||||||
const title = "My Title";
|
const title = "My Title";
|
||||||
@@ -37,18 +37,17 @@ describe("Property pane", () => {
|
|||||||
return {
|
return {
|
||||||
expandedTitle: title,
|
expandedTitle: title,
|
||||||
isCollapsed: false,
|
isCollapsed: false,
|
||||||
onCollapsedChanged: jest.fn(),
|
onCollapsedChanged: (newValue: boolean): void => {},
|
||||||
node: highlightedNode,
|
node: highlightedNode,
|
||||||
getPkIdFromNodeData: (): string => undefined,
|
getPkIdFromNodeData: (v: GraphHighlightedNodeData): string => null,
|
||||||
collectionPartitionKeyProperty: undefined,
|
collectionPartitionKeyProperty: null,
|
||||||
updateVertexProperties: (): Q.Promise<void> => Q.resolve(),
|
updateVertexProperties: (editedProperties: EditedProperties): Q.Promise<void> => Q.resolve(),
|
||||||
selectNode: jest.fn(),
|
selectNode: (id: string): void => {},
|
||||||
updatePossibleVertices: (): Q.Promise<PossibleVertex[]> => Q.resolve(undefined),
|
updatePossibleVertices: (): Q.Promise<PossibleVertex[]> => Q.resolve(null),
|
||||||
possibleEdgeLabels: undefined,
|
possibleEdgeLabels: null,
|
||||||
//eslint-disable-next-line
|
editGraphEdges: (editedEdges: EditedEdges): Q.Promise<any> => Q.resolve(),
|
||||||
editGraphEdges: (): Q.Promise<any> => Q.resolve(),
|
deleteHighlightedNode: (): void => {},
|
||||||
deleteHighlightedNode: jest.fn(),
|
onModeChanged: (newMode: Mode): void => {},
|
||||||
onModeChanged: jest.fn(),
|
|
||||||
viewMode: Mode.READONLY_PROP,
|
viewMode: Mode.READONLY_PROP,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export class NodePropertiesComponent extends React.Component<
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
editedProperties: {
|
editedProperties: {
|
||||||
pkId: undefined,
|
pkId: null,
|
||||||
readOnlyProperties: [],
|
readOnlyProperties: [],
|
||||||
existingProperties: [],
|
existingProperties: [],
|
||||||
addedProperties: [],
|
addedProperties: [],
|
||||||
@@ -98,12 +98,15 @@ export class NodePropertiesComponent extends React.Component<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getDerivedStateFromProps(props: NodePropertiesComponentProps): Partial<NodePropertiesComponentState> {
|
public static getDerivedStateFromProps(
|
||||||
|
props: NodePropertiesComponentProps,
|
||||||
|
state: NodePropertiesComponentState
|
||||||
|
): Partial<NodePropertiesComponentState> {
|
||||||
if (props.viewMode !== Mode.READONLY_PROP) {
|
if (props.viewMode !== Mode.READONLY_PROP) {
|
||||||
return { isDeleteConfirm: false };
|
return { isDeleteConfirm: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
@@ -135,10 +138,10 @@ export class NodePropertiesComponent extends React.Component<
|
|||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
private static getTypeOption(value: any): ViewModels.InputPropertyValueTypeString {
|
private static getTypeOption(value: any): ViewModels.InputPropertyValueTypeString {
|
||||||
if (value === undefined) {
|
if (value == null) {
|
||||||
return "null";
|
return "null";
|
||||||
}
|
}
|
||||||
const type = typeof value;
|
let type = typeof value;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "number":
|
case "number":
|
||||||
case "boolean":
|
case "boolean":
|
||||||
@@ -169,9 +172,10 @@ export class NodePropertiesComponent extends React.Component<
|
|||||||
];
|
];
|
||||||
|
|
||||||
const existingProps: ViewModels.InputProperty[] = [];
|
const existingProps: ViewModels.InputProperty[] = [];
|
||||||
|
|
||||||
if (this.props.node.hasOwnProperty("properties")) {
|
if (this.props.node.hasOwnProperty("properties")) {
|
||||||
const hProps = this.props.node["properties"];
|
const hProps = this.props.node["properties"];
|
||||||
for (const p in hProps) {
|
for (let p in hProps) {
|
||||||
const propValues = hProps[p];
|
const propValues = hProps[p];
|
||||||
(p === partitionKeyProperty ? readOnlyProps : existingProps).push({
|
(p === partitionKeyProperty ? readOnlyProps : existingProps).push({
|
||||||
key: p,
|
key: p,
|
||||||
@@ -433,7 +437,7 @@ export class NodePropertiesComponent extends React.Component<
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
|
|||||||
<td>
|
<td>
|
||||||
<select
|
<select
|
||||||
className="typeSelect"
|
className="typeSelect"
|
||||||
onChange={[Function]}
|
onBlur={[Function]}
|
||||||
required={true}
|
required={true}
|
||||||
value="string"
|
value="string"
|
||||||
>
|
>
|
||||||
@@ -282,7 +282,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
|
|||||||
<td>
|
<td>
|
||||||
<select
|
<select
|
||||||
className="typeSelect"
|
className="typeSelect"
|
||||||
onChange={[Function]}
|
onBlur={[Function]}
|
||||||
required={true}
|
required={true}
|
||||||
value="string"
|
value="string"
|
||||||
>
|
>
|
||||||
@@ -344,7 +344,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
|
|||||||
<td>
|
<td>
|
||||||
<select
|
<select
|
||||||
className="typeSelect"
|
className="typeSelect"
|
||||||
onChange={[Function]}
|
onBlur={[Function]}
|
||||||
required={true}
|
required={true}
|
||||||
value="string"
|
value="string"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -132,7 +132,6 @@ export const NewVertexComponent: FunctionComponent<INewVertexComponentProps> = (
|
|||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
onLabelChange(event);
|
onLabelChange(event);
|
||||||
}}
|
}}
|
||||||
autoFocus
|
|
||||||
/>
|
/>
|
||||||
<div className="actionCol"></div>
|
<div className="actionCol"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { useTabs } from "../../../hooks/useTabs";
|
|||||||
import { userContext } from "../../../UserContext";
|
import { userContext } from "../../../UserContext";
|
||||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import { NotebookUtil } from "../../Notebook/NotebookUtil";
|
|
||||||
import { useSelectedNode } from "../../useSelectedNode";
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import * as CommandBarComponentButtonFactory from "./CommandBarComponentButtonFactory";
|
import * as CommandBarComponentButtonFactory from "./CommandBarComponentButtonFactory";
|
||||||
import * as CommandBarUtil from "./CommandBarUtil";
|
import * as CommandBarUtil from "./CommandBarUtil";
|
||||||
@@ -56,15 +55,15 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
|||||||
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
|
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
|
||||||
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
||||||
|
|
||||||
if (NotebookUtil.isPhoenixEnabled()) {
|
|
||||||
uiFabricControlButtons.unshift(CommandBarUtil.createConnectionStatus(container, "connectionStatus"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
userContext.features.phoenix === false &&
|
|
||||||
userContext.features.notebooksTemporarilyDown === false &&
|
userContext.features.notebooksTemporarilyDown === false &&
|
||||||
|
userContext.features.phoenix === true &&
|
||||||
useTabs.getState().activeTab?.tabKind === ViewModels.CollectionTabKind.NotebookV2
|
useTabs.getState().activeTab?.tabKind === ViewModels.CollectionTabKind.NotebookV2
|
||||||
) {
|
) {
|
||||||
|
uiFabricControlButtons.unshift(CommandBarUtil.createConnectionStatus("connectionStatus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useTabs.getState().activeTab?.tabKind === ViewModels.CollectionTabKind.NotebookV2) {
|
||||||
uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker"));
|
uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -307,18 +307,11 @@ function createOpenSynapseLinkDialogButton(container: Explorer): CommandButtonCo
|
|||||||
|
|
||||||
function createNewDatabase(container: Explorer): CommandButtonComponentProps {
|
function createNewDatabase(container: Explorer): CommandButtonComponentProps {
|
||||||
const label = "New " + getDatabaseName();
|
const label = "New " + getDatabaseName();
|
||||||
const newDatabaseButton = document.activeElement as HTMLElement;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
iconSrc: AddDatabaseIcon,
|
iconSrc: AddDatabaseIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () =>
|
onCommandClick: () =>
|
||||||
useSidePanel
|
useSidePanel.getState().openSidePanel("New " + getDatabaseName(), <AddDatabasePanel explorer={container} />),
|
||||||
.getState()
|
|
||||||
.openSidePanel(
|
|
||||||
"New " + getDatabaseName(),
|
|
||||||
<AddDatabasePanel explorer={container} buttonElement={newDatabaseButton} />
|
|
||||||
),
|
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
@@ -603,7 +596,7 @@ function createManageGitHubAccountButton(container: Explorer): CommandButtonComp
|
|||||||
return {
|
return {
|
||||||
iconSrc: GitHubIcon,
|
iconSrc: GitHubIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () =>
|
||||||
useSidePanel
|
useSidePanel
|
||||||
.getState()
|
.getState()
|
||||||
.openSidePanel(
|
.openSidePanel(
|
||||||
@@ -613,8 +606,7 @@ function createManageGitHubAccountButton(container: Explorer): CommandButtonComp
|
|||||||
gitHubClientProp={container.notebookManager.gitHubClient}
|
gitHubClientProp={container.notebookManager.gitHubClient}
|
||||||
junoClientProp={junoClient}
|
junoClientProp={junoClient}
|
||||||
/>
|
/>
|
||||||
);
|
),
|
||||||
},
|
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
hasPopup: false,
|
hasPopup: false,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { StyleConstants } from "../../../Common/Constants";
|
|||||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||||
import Explorer from "../../Explorer";
|
|
||||||
import { ConnectionStatus } from "./ConnectionStatusComponent";
|
import { ConnectionStatus } from "./ConnectionStatusComponent";
|
||||||
import { MemoryTracker } from "./MemoryTrackerComponent";
|
import { MemoryTracker } from "./MemoryTrackerComponent";
|
||||||
|
|
||||||
@@ -204,9 +203,9 @@ export const createMemoryTracker = (key: string): ICommandBarItemProps => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createConnectionStatus = (container: Explorer, key: string): ICommandBarItemProps => {
|
export const createConnectionStatus = (key: string): ICommandBarItemProps => {
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
onRender: () => <ConnectionStatus container={container} />,
|
onRender: () => <ConnectionStatus />,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,182 +3,77 @@
|
|||||||
.connectionStatusContainer {
|
.connectionStatusContainer {
|
||||||
cursor: default;
|
cursor: default;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin: 0 9px;
|
||||||
border: 1px;
|
border: 1px;
|
||||||
min-height: 44px;
|
min-height: 44px;
|
||||||
|
|
||||||
> span {
|
> span {
|
||||||
padding-right: 12px;
|
padding-right: 12px;
|
||||||
font-size: 12px;
|
font-size: 13px;
|
||||||
font-family: @DataExplorerFont;
|
font-family: @DataExplorerFont;
|
||||||
color: @DefaultFontColor;
|
color: @DefaultFontColor;
|
||||||
}
|
}
|
||||||
&:focus{
|
|
||||||
outline: 0px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.commandReactBtn {
|
.connectionStatusFailed{
|
||||||
&:hover {
|
color: #bd1919;
|
||||||
background-color: rgb(238, 247, 255);
|
|
||||||
color: rgb(32, 31, 30);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
&:focus{
|
|
||||||
outline: 1px dashed #605e5c;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.connectedReactBtn {
|
.ring-container {
|
||||||
&:hover {
|
|
||||||
background-color: rgb(238, 247, 255);
|
|
||||||
color: rgb(32, 31, 30);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
&:focus{
|
|
||||||
outline: 0px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.connectIcon{
|
|
||||||
margin: 0px 4px;
|
|
||||||
height: 18px;
|
|
||||||
width: 18px;
|
|
||||||
color: rgb(0, 120, 212);
|
|
||||||
}
|
|
||||||
.status {
|
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
}
|
||||||
margin-right: 8px;
|
|
||||||
width: 1em;
|
.ringringGreen {
|
||||||
height: 1em;
|
border: 3px solid green;
|
||||||
font-size: 9px!important;
|
border-radius: 30px;
|
||||||
padding: 0px!important;
|
height: 18px;
|
||||||
border-radius: 0.5em;
|
width: 18px;
|
||||||
}
|
|
||||||
|
|
||||||
.status::before,
|
|
||||||
.status::after {
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
content: "";
|
margin: .4285em 0em 0em 0.07477em;
|
||||||
}
|
animation: pulsate 3s ease-out;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
.status::before {
|
opacity: 0.0
|
||||||
top: 0;
|
}
|
||||||
left: 0;
|
.ringringYellow{
|
||||||
width: 1em;
|
border: 3px solid #ffbf00;
|
||||||
height: 1em;
|
border-radius: 30px;
|
||||||
background-color: rgba(#fff, 0.1);
|
height: 18px;
|
||||||
border-radius: 100%;
|
width: 18px;
|
||||||
opacity: 1;
|
position: absolute;
|
||||||
transform: translate3d(0, 0, 0) scale(0);
|
margin: .4285em 0em 0em 0.07477em;
|
||||||
}
|
animation: pulsate 3s ease-out;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
.connected{
|
opacity: 0.0
|
||||||
background-color: green;
|
}
|
||||||
box-shadow:
|
.ringringRed{
|
||||||
0 0 0 0em rgba(green, 0),
|
border: 3px solid #bd1919;
|
||||||
0em 0.05em 0.1em rgba(#000000, 0.2);
|
border-radius: 30px;
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
height: 18px;
|
||||||
}
|
width: 18px;
|
||||||
.connecting{
|
position: absolute;
|
||||||
background-color:#ffbf00;
|
margin: .4285em 0em 0em 0.07477em;
|
||||||
box-shadow:
|
animation: pulsate 3s ease-out;
|
||||||
0 0 0 0em rgba(#ffbf00, 0),
|
animation-iteration-count: infinite;
|
||||||
0em 0.05em 0.1em rgba(#000000, 0.2);
|
opacity: 0.0
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
}
|
||||||
}
|
@keyframes pulsate {
|
||||||
.failed{
|
0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}
|
||||||
background-color:#bd1919;
|
15% {opacity: 0.8;}
|
||||||
box-shadow:
|
25% {opacity: 0.6;}
|
||||||
0 0 0 0em rgba(#bd1919, 0),
|
45% {opacity: 0.4;}
|
||||||
0em 0.05em 0.1em rgba(#000000, 0.2);
|
70% {opacity: 0.3;}
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
100% {-webkit-transform: scale(.7, .7); opacity: 0.1;}
|
||||||
}
|
}
|
||||||
|
.locationGreenDot{
|
||||||
.status.connecting.is-animating {
|
font-size: 20px;
|
||||||
animation: status-outer-connecting 3000ms infinite;
|
margin-right: 0.07em;
|
||||||
}
|
color: green;
|
||||||
.status.failed.is-animating {
|
}
|
||||||
animation: status-outer-failed 3000ms infinite;
|
.locationYellowDot{
|
||||||
}
|
font-size: 20px;
|
||||||
.status.connected.is-animating {
|
margin-right: 0.07em;
|
||||||
animation: status-outer-connected 3000ms infinite;
|
color: #ffbf00;
|
||||||
}
|
}
|
||||||
@keyframes status-outer-connected {
|
.locationRedDot{
|
||||||
|
font-size: 20px;
|
||||||
0% {
|
margin-right: 0.07em;
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
color: #bd1919;
|
||||||
box-shadow: 0 0 0 0em #008000, 0em 0.05em 0.1em rgba(0, 0, 0, 0.2);
|
}
|
||||||
}
|
|
||||||
20% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0.6), 0em 0.05em 0.1em rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0.5), 0em 0.05em 0.1em rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
60% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0.3), 0em 0.05em 0.1em rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
80% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0.5em rgba(0, 128, 0, 0.1), 0em 0.05em 0.1em rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
85% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0), 0em 0.05em 0.1em rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes status-outer-failed {
|
|
||||||
|
|
||||||
0% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em #bd1919, 0em 0.05em 0.1em rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
20% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em #c52d2d, 0em 0.05em 0.1em rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em #b47b7b, 0em 0.05em 0.1em rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
60% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0.3), 0em 0.05em 0.1em rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
80% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0.5em rgba(0, 128, 0, 0.1), 0em 0.05em 0.1em rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
85% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0), 0em 0.05em 0.1em rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes status-outer-connecting {
|
|
||||||
|
|
||||||
0% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em #ffbf00, 0em 0.05em 0.1em rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
20% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em #f0dfad, 0em 0.05em 0.1em rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em rgba(198, 243, 198, 0.5), 0em 0.05em 0.1em rgba(0, 0, 0, 0.4);
|
|
||||||
}
|
|
||||||
60% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em rgba(213, 241, 213, 0.3), 0em 0.05em 0.1em rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
80% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0.5em rgba(0, 128, 0, 0.1), 0em 0.05em 0.1em rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
85% {
|
|
||||||
transform: translate3d(0, 0, 0) scale(1);
|
|
||||||
box-shadow: 0 0 0 0em rgba(0, 128, 0, 0), 0em 0.05em 0.1em rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,17 @@
|
|||||||
import { Icon, ProgressIndicator, Stack, TooltipHost } from "@fluentui/react";
|
import { Icon, ProgressIndicator, Stack, TooltipHost } from "@fluentui/react";
|
||||||
import { ActionButton } from "@fluentui/react/lib/Button";
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import "../../../../less/hostedexplorer.less";
|
import { ConnectionStatusType } from "../../../Common/Constants";
|
||||||
import { ConnectionStatusType, Notebook } from "../../../Common/Constants";
|
|
||||||
import Explorer from "../../Explorer";
|
|
||||||
import { useNotebook } from "../../Notebook/useNotebook";
|
import { useNotebook } from "../../Notebook/useNotebook";
|
||||||
import "../CommandBar/ConnectionStatusComponent.less";
|
import "../CommandBar/ConnectionStatusComponent.less";
|
||||||
interface Props {
|
|
||||||
container: Explorer;
|
export const ConnectionStatus: React.FC = (): JSX.Element => {
|
||||||
}
|
|
||||||
export const ConnectionStatus: React.FC<Props> = ({ container }: Props): JSX.Element => {
|
|
||||||
const [second, setSecond] = React.useState("00");
|
const [second, setSecond] = React.useState("00");
|
||||||
const [minute, setMinute] = React.useState("00");
|
const [minute, setMinute] = React.useState("00");
|
||||||
const [isActive, setIsActive] = React.useState(false);
|
const [isActive, setIsActive] = React.useState(false);
|
||||||
const [counter, setCounter] = React.useState(0);
|
const [counter, setCounter] = React.useState(0);
|
||||||
const [statusColor, setStatusColor] = React.useState("");
|
const [statusColor, setStatusColor] = React.useState("locationYellowDot");
|
||||||
const [toolTipContent, setToolTipContent] = React.useState("Connect to temporary workspace.");
|
const [statusColorAnimation, setStatusColorAnimation] = React.useState("ringringYellow");
|
||||||
|
const toolTipContent = "Hosted runtime status.";
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
let intervalId: NodeJS.Timeout;
|
let intervalId: NodeJS.Timeout;
|
||||||
|
|
||||||
@@ -43,65 +39,34 @@ export const ConnectionStatus: React.FC<Props> = ({ container }: Props): JSX.Ele
|
|||||||
};
|
};
|
||||||
|
|
||||||
const connectionInfo = useNotebook((state) => state.connectionInfo);
|
const connectionInfo = useNotebook((state) => state.connectionInfo);
|
||||||
const memoryUsageInfo = useNotebook((state) => state.memoryUsageInfo);
|
if (!connectionInfo) {
|
||||||
|
return <></>;
|
||||||
const totalGB = memoryUsageInfo ? memoryUsageInfo.totalKB / Notebook.memoryGuageToGB : 0;
|
|
||||||
const usedGB = totalGB > 0 ? totalGB - memoryUsageInfo.freeKB / Notebook.memoryGuageToGB : 0;
|
|
||||||
|
|
||||||
if (
|
|
||||||
connectionInfo &&
|
|
||||||
(connectionInfo.status === ConnectionStatusType.Connect || connectionInfo.status === ConnectionStatusType.ReConnect)
|
|
||||||
) {
|
|
||||||
return (
|
|
||||||
<ActionButton className="commandReactBtn" onClick={() => container.allocateContainer()}>
|
|
||||||
<TooltipHost content={toolTipContent}>
|
|
||||||
<Stack className="connectionStatusContainer" horizontal>
|
|
||||||
<Icon iconName="ConnectVirtualMachine" className="connectIcon" />
|
|
||||||
<span>{connectionInfo.status}</span>
|
|
||||||
</Stack>
|
|
||||||
</TooltipHost>
|
|
||||||
</ActionButton>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionInfo && connectionInfo.status === ConnectionStatusType.Connecting && isActive === false) {
|
if (connectionInfo && connectionInfo.status === ConnectionStatusType.Connecting && isActive === false) {
|
||||||
setIsActive(true);
|
setIsActive(true);
|
||||||
setStatusColor("status connecting is-animating");
|
|
||||||
setToolTipContent("Connecting to temporary workspace.");
|
|
||||||
} else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Connected && isActive === true) {
|
} else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Connected && isActive === true) {
|
||||||
stopTimer();
|
stopTimer();
|
||||||
setStatusColor("status connected is-animating");
|
setStatusColor("locationGreenDot");
|
||||||
setToolTipContent("Connected to temporary workspace.");
|
setStatusColorAnimation("ringringGreen");
|
||||||
} else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Failed && isActive === true) {
|
} else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Failed && isActive === true) {
|
||||||
stopTimer();
|
stopTimer();
|
||||||
setStatusColor("status failed is-animating");
|
setStatusColor("locationRedDot");
|
||||||
setToolTipContent("Click here to Reconnect to temporary workspace.");
|
setStatusColorAnimation("ringringRed");
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ActionButton
|
<TooltipHost content={toolTipContent}>
|
||||||
className={connectionInfo.status === ConnectionStatusType.Failed ? "commandReactBtn" : "connectedReactBtn"}
|
<Stack className="connectionStatusContainer" horizontal>
|
||||||
onClick={(e: React.MouseEvent<HTMLSpanElement>) =>
|
<div className="ring-container">
|
||||||
connectionInfo.status === ConnectionStatusType.Failed ? container.allocateContainer() : e.preventDefault()
|
<div className={statusColorAnimation}></div>
|
||||||
}
|
<Icon iconName="LocationDot" className={statusColor} />
|
||||||
>
|
</div>
|
||||||
<TooltipHost content={toolTipContent}>
|
<span className={connectionInfo.status === ConnectionStatusType.Failed ? "connectionStatusFailed" : ""}>
|
||||||
<Stack className="connectionStatusContainer" horizontal>
|
{connectionInfo.status}
|
||||||
<i className={statusColor}></i>
|
</span>
|
||||||
<span className={connectionInfo.status === ConnectionStatusType.Failed ? "connectionStatusFailed" : ""}>
|
{connectionInfo.status === ConnectionStatusType.Connecting && isActive && (
|
||||||
{connectionInfo.status}
|
<ProgressIndicator description={minute + ":" + second} />
|
||||||
</span>
|
)}
|
||||||
{connectionInfo.status === ConnectionStatusType.Connecting && isActive && (
|
</Stack>
|
||||||
<ProgressIndicator description={minute + ":" + second} />
|
</TooltipHost>
|
||||||
)}
|
|
||||||
{connectionInfo.status === ConnectionStatusType.Connected && !isActive && (
|
|
||||||
<ProgressIndicator
|
|
||||||
className={usedGB / totalGB > 0.8 ? "lowMemory" : ""}
|
|
||||||
description={usedGB.toFixed(1) + " of " + totalGB.toFixed(1) + " GB"}
|
|
||||||
percentComplete={usedGB / totalGB}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</TooltipHost>
|
|
||||||
</ActionButton>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ export class NotificationConsoleComponent extends React.Component<
|
|||||||
onClick={() => this.expandCollapseConsole()}
|
onClick={() => this.expandCollapseConsole()}
|
||||||
onKeyDown={(event: React.KeyboardEvent<HTMLDivElement>) => this.onExpandCollapseKeyPress(event)}
|
onKeyDown={(event: React.KeyboardEvent<HTMLDivElement>) => this.onExpandCollapseKeyPress(event)}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
|
role="button"
|
||||||
>
|
>
|
||||||
<div className="statusBar">
|
<div className="statusBar">
|
||||||
<span className="dataTypeIcons">
|
<span className="dataTypeIcons">
|
||||||
@@ -162,7 +163,7 @@ export class NotificationConsoleComponent extends React.Component<
|
|||||||
onKeyDown={(event: React.KeyboardEvent<HTMLSpanElement>) => this.onClearNotificationsKeyPress(event)}
|
onKeyDown={(event: React.KeyboardEvent<HTMLSpanElement>) => this.onClearNotificationsKeyPress(event)}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<img src={ClearIcon} alt="clear notifications image" />
|
<img src={ClearIcon} alt="clear notifications icon" />
|
||||||
Clear Notifications
|
Clear Notifications
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
|
|||||||
id="notificationConsoleHeader"
|
id="notificationConsoleHeader"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -150,7 +151,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="clear notifications image"
|
alt="clear notifications icon"
|
||||||
src=""
|
src=""
|
||||||
/>
|
/>
|
||||||
Clear Notifications
|
Clear Notifications
|
||||||
@@ -173,6 +174,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
|
|||||||
id="notificationConsoleHeader"
|
id="notificationConsoleHeader"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyDown={[Function]}
|
onKeyDown={[Function]}
|
||||||
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -316,7 +318,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="clear notifications image"
|
alt="clear notifications icon"
|
||||||
src=""
|
src=""
|
||||||
/>
|
/>
|
||||||
Clear Notifications
|
Clear Notifications
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
||||||
import { CellId, CellType, ImmutableNotebook } from "@nteract/commutable";
|
import { CellId, CellType, ImmutableNotebook } from "@nteract/commutable";
|
||||||
// Vendor modules
|
// Vendor modules
|
||||||
import {
|
import {
|
||||||
@@ -31,19 +30,6 @@ export interface NotebookComponentBootstrapperOptions {
|
|||||||
contentRef: ContentRef;
|
contentRef: ContentRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IWrapModel {
|
|
||||||
name: string;
|
|
||||||
path: string;
|
|
||||||
last_modified: Date;
|
|
||||||
created: string;
|
|
||||||
content: unknown;
|
|
||||||
format: string;
|
|
||||||
mimetype: unknown;
|
|
||||||
size: number;
|
|
||||||
writeable: boolean;
|
|
||||||
type: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NotebookComponentBootstrapper {
|
export class NotebookComponentBootstrapper {
|
||||||
public contentRef: ContentRef;
|
public contentRef: ContentRef;
|
||||||
protected renderExtraComponent: () => JSX.Element;
|
protected renderExtraComponent: () => JSX.Element;
|
||||||
@@ -55,7 +41,7 @@ export class NotebookComponentBootstrapper {
|
|||||||
this.contentRef = options.contentRef;
|
this.contentRef = options.contentRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static wrapModelIntoContent(name: string, path: string, content: unknown): IWrapModel {
|
protected static wrapModelIntoContent(name: string, path: string, content: any) {
|
||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
path,
|
path,
|
||||||
@@ -63,7 +49,7 @@ export class NotebookComponentBootstrapper {
|
|||||||
created: "",
|
created: "",
|
||||||
content,
|
content,
|
||||||
format: "json",
|
format: "json",
|
||||||
mimetype: undefined,
|
mimetype: null as any,
|
||||||
size: 0,
|
size: 0,
|
||||||
writeable: false,
|
writeable: false,
|
||||||
type: "notebook",
|
type: "notebook",
|
||||||
@@ -99,7 +85,7 @@ export class NotebookComponentBootstrapper {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public setContent(name: string, content: unknown): void {
|
public setContent(name: string, content: any): void {
|
||||||
this.getStore().dispatch(
|
this.getStore().dispatch(
|
||||||
actions.fetchContentFulfilled({
|
actions.fetchContentFulfilled({
|
||||||
filepath: undefined,
|
filepath: undefined,
|
||||||
@@ -284,6 +270,7 @@ export class NotebookComponentBootstrapper {
|
|||||||
public isContentDirty(): boolean {
|
public isContentDirty(): boolean {
|
||||||
const content = selectors.content(this.getStore().getState(), { contentRef: this.contentRef });
|
const content = selectors.content(this.getStore().getState(), { contentRef: this.contentRef });
|
||||||
if (!content) {
|
if (!content) {
|
||||||
|
console.log("No error");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,12 @@
|
|||||||
* Notebook container related stuff
|
* Notebook container related stuff
|
||||||
*/
|
*/
|
||||||
import * as Constants from "../../Common/Constants";
|
import * as Constants from "../../Common/Constants";
|
||||||
import { ConnectionStatusType } from "../../Common/Constants";
|
|
||||||
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
||||||
import * as Logger from "../../Common/Logger";
|
import * as Logger from "../../Common/Logger";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { ContainerConnectionInfo } from "../../Contracts/DataModels";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { createOrUpdate, destroy } from "../../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces";
|
import { createOrUpdate, destroy } from "../../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { NotebookUtil } from "./NotebookUtil";
|
|
||||||
import { useNotebook } from "./useNotebook";
|
import { useNotebook } from "./useNotebook";
|
||||||
|
|
||||||
export class NotebookContainerClient {
|
export class NotebookContainerClient {
|
||||||
@@ -45,7 +42,7 @@ export class NotebookContainerClient {
|
|||||||
}, delayMs);
|
}, delayMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
|
private async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
||||||
if (!notebookServerInfo || !notebookServerInfo.notebookServerEndpoint) {
|
if (!notebookServerInfo || !notebookServerInfo.notebookServerEndpoint) {
|
||||||
const error = "No server endpoint detected";
|
const error = "No server endpoint detected";
|
||||||
@@ -78,12 +75,6 @@ export class NotebookContainerClient {
|
|||||||
freeKB: memoryUsageInfo.free,
|
freeKB: memoryUsageInfo.free,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if (NotebookUtil.isPhoenixEnabled()) {
|
|
||||||
const connectionStatus: ContainerConnectionInfo = {
|
|
||||||
status: ConnectionStatusType.ReConnect,
|
|
||||||
};
|
|
||||||
useNotebook.getState().resetConatinerConnection(connectionStatus);
|
|
||||||
useNotebook.getState().setIsRefreshed(true);
|
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -93,13 +84,6 @@ export class NotebookContainerClient {
|
|||||||
"Connection lost with Notebook server. Attempting to reconnect..."
|
"Connection lost with Notebook server. Attempting to reconnect..."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (NotebookUtil.isPhoenixEnabled()) {
|
|
||||||
const connectionStatus: ContainerConnectionInfo = {
|
|
||||||
status: ConnectionStatusType.Failed,
|
|
||||||
};
|
|
||||||
useNotebook.getState().resetConatinerConnection(connectionStatus);
|
|
||||||
useNotebook.getState().setIsRefreshed(true);
|
|
||||||
}
|
|
||||||
this.onConnectionLost();
|
this.onConnectionLost();
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,7 +212,6 @@ export default class NotebookManager {
|
|||||||
"Cancel",
|
"Cancel",
|
||||||
() => reject(new Error("Commit dialog canceled")),
|
() => reject(new Error("Commit dialog canceled")),
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
|
||||||
{
|
{
|
||||||
label: "Commit message",
|
label: "Commit message",
|
||||||
autoAdjustHeight: true,
|
autoAdjustHeight: true,
|
||||||
|
|||||||
@@ -16,10 +16,9 @@ import "./NotebookReadOnlyRenderer.less";
|
|||||||
import SandboxOutputs from "./outputs/SandboxOutputs";
|
import SandboxOutputs from "./outputs/SandboxOutputs";
|
||||||
|
|
||||||
export interface NotebookRendererProps {
|
export interface NotebookRendererProps {
|
||||||
contentRef: ContentRef;
|
contentRef: any;
|
||||||
hideInputs?: boolean;
|
hideInputs?: boolean;
|
||||||
hidePrompts?: boolean;
|
hidePrompts?: boolean;
|
||||||
addTransform: (component: React.ComponentType & { MIMETYPE: string }) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -28,7 +27,7 @@ export interface NotebookRendererProps {
|
|||||||
class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (!userContext.features.sandboxNotebookOutputs) {
|
if (!userContext.features.sandboxNotebookOutputs) {
|
||||||
loadTransform(this.props as NotebookRendererProps);
|
loadTransform(this.props as any);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +59,7 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
|||||||
<div className="NotebookReadOnlyRender">
|
<div className="NotebookReadOnlyRender">
|
||||||
<Cells contentRef={this.props.contentRef}>
|
<Cells contentRef={this.props.contentRef}>
|
||||||
{{
|
{{
|
||||||
code: ({ id, contentRef }: { id: string; contentRef: ContentRef }) => (
|
code: ({ id, contentRef }: { id: any; contentRef: ContentRef }) => (
|
||||||
<CodeCell id={id} contentRef={contentRef}>
|
<CodeCell id={id} contentRef={contentRef}>
|
||||||
{{
|
{{
|
||||||
prompt: (props: { id: string; contentRef: string }) => this.renderPrompt(props.id, props.contentRef),
|
prompt: (props: { id: string; contentRef: string }) => this.renderPrompt(props.id, props.contentRef),
|
||||||
@@ -74,14 +73,14 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
|||||||
}}
|
}}
|
||||||
</CodeCell>
|
</CodeCell>
|
||||||
),
|
),
|
||||||
markdown: ({ id, contentRef }: { id: string; contentRef: ContentRef }) => (
|
markdown: ({ id, contentRef }: { id: any; contentRef: ContentRef }) => (
|
||||||
<MarkdownCell id={id} contentRef={contentRef} cell_type="markdown">
|
<MarkdownCell id={id} contentRef={contentRef} cell_type="markdown">
|
||||||
{{
|
{{
|
||||||
editor: {},
|
editor: {},
|
||||||
}}
|
}}
|
||||||
</MarkdownCell>
|
</MarkdownCell>
|
||||||
),
|
),
|
||||||
raw: ({ id, contentRef }: { id: string; contentRef: ContentRef }) => (
|
raw: ({ id, contentRef }: { id: any; contentRef: ContentRef }) => (
|
||||||
<RawCell id={id} contentRef={contentRef} cell_type="raw">
|
<RawCell id={id} contentRef={contentRef} cell_type="raw">
|
||||||
{{
|
{{
|
||||||
editor: {
|
editor: {
|
||||||
@@ -99,7 +98,6 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const makeMapDispatchToProps = (initialDispatch: Dispatch, initialProps: NotebookRendererProps) => {
|
const makeMapDispatchToProps = (initialDispatch: Dispatch, initialProps: NotebookRendererProps) => {
|
||||||
const mapDispatchToProps = (dispatch: Dispatch) => {
|
const mapDispatchToProps = (dispatch: Dispatch) => {
|
||||||
return {
|
return {
|
||||||
@@ -116,4 +114,4 @@ const makeMapDispatchToProps = (initialDispatch: Dispatch, initialProps: Noteboo
|
|||||||
return mapDispatchToProps;
|
return mapDispatchToProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(undefined, makeMapDispatchToProps)(NotebookReadOnlyRenderer);
|
export default connect(null, makeMapDispatchToProps)(NotebookReadOnlyRenderer);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { AppState, selectors } from "@nteract/core";
|
|||||||
import domtoimage from "dom-to-image";
|
import domtoimage from "dom-to-image";
|
||||||
import Html2Canvas from "html2canvas";
|
import Html2Canvas from "html2canvas";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
||||||
import * as StringUtils from "../../Utils/StringUtils";
|
import * as StringUtils from "../../Utils/StringUtils";
|
||||||
import { SnapshotFragment } from "./NotebookComponent/types";
|
import { SnapshotFragment } from "./NotebookComponent/types";
|
||||||
@@ -329,16 +328,4 @@ export class NotebookUtil {
|
|||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
document.body.removeChild(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getNotebookBtnTitle(fileName: string): string {
|
|
||||||
if (this.isPhoenixEnabled()) {
|
|
||||||
return `Download to ${fileName}`;
|
|
||||||
} else {
|
|
||||||
return `Download to my notebooks`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static isPhoenixEnabled(): boolean {
|
|
||||||
return userContext.features.notebooksTemporarilyDown === false && userContext.features.phoenix === true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,10 @@ import { cloneDeep } from "lodash";
|
|||||||
import create, { UseStore } from "zustand";
|
import create, { UseStore } from "zustand";
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import * as Constants from "../../Common/Constants";
|
import * as Constants from "../../Common/Constants";
|
||||||
import { ConnectionStatusType } from "../../Common/Constants";
|
|
||||||
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
||||||
import * as Logger from "../../Common/Logger";
|
import * as Logger from "../../Common/Logger";
|
||||||
import { configContext } from "../../ConfigContext";
|
import { configContext } from "../../ConfigContext";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { ContainerConnectionInfo } from "../../Contracts/DataModels";
|
|
||||||
import { IPinnedRepo } from "../../Juno/JunoClient";
|
import { IPinnedRepo } from "../../Juno/JunoClient";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
@@ -16,7 +14,6 @@ import { getAuthorizationHeader } from "../../Utils/AuthorizationUtils";
|
|||||||
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
||||||
import { NotebookContentItem, NotebookContentItemType } from "./NotebookContentItem";
|
import { NotebookContentItem, NotebookContentItemType } from "./NotebookContentItem";
|
||||||
import NotebookManager from "./NotebookManager";
|
import NotebookManager from "./NotebookManager";
|
||||||
import { NotebookUtil } from "./NotebookUtil";
|
|
||||||
|
|
||||||
interface NotebookState {
|
interface NotebookState {
|
||||||
isNotebookEnabled: boolean;
|
isNotebookEnabled: boolean;
|
||||||
@@ -31,10 +28,8 @@ interface NotebookState {
|
|||||||
myNotebooksContentRoot: NotebookContentItem;
|
myNotebooksContentRoot: NotebookContentItem;
|
||||||
gitHubNotebooksContentRoot: NotebookContentItem;
|
gitHubNotebooksContentRoot: NotebookContentItem;
|
||||||
galleryContentRoot: NotebookContentItem;
|
galleryContentRoot: NotebookContentItem;
|
||||||
connectionInfo: ContainerConnectionInfo;
|
connectionInfo: DataModels.ContainerConnectionInfo;
|
||||||
notebookFolderName: string;
|
notebookFolderName: string;
|
||||||
isAllocating: boolean;
|
|
||||||
isRefreshed: boolean;
|
|
||||||
setIsNotebookEnabled: (isNotebookEnabled: boolean) => void;
|
setIsNotebookEnabled: (isNotebookEnabled: boolean) => void;
|
||||||
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => void;
|
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => void;
|
||||||
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => void;
|
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => void;
|
||||||
@@ -51,10 +46,7 @@ interface NotebookState {
|
|||||||
deleteNotebookItem: (item: NotebookContentItem, isGithubTree?: boolean) => void;
|
deleteNotebookItem: (item: NotebookContentItem, isGithubTree?: boolean) => void;
|
||||||
initializeNotebooksTree: (notebookManager: NotebookManager) => Promise<void>;
|
initializeNotebooksTree: (notebookManager: NotebookManager) => Promise<void>;
|
||||||
initializeGitHubRepos: (pinnedRepos: IPinnedRepo[]) => void;
|
initializeGitHubRepos: (pinnedRepos: IPinnedRepo[]) => void;
|
||||||
setConnectionInfo: (connectionInfo: ContainerConnectionInfo) => void;
|
setConnectionInfo: (connectionInfo: DataModels.ContainerConnectionInfo) => void;
|
||||||
setIsAllocating: (isAllocating: boolean) => void;
|
|
||||||
resetConatinerConnection: (connectionStatus: ContainerConnectionInfo) => void;
|
|
||||||
setIsRefreshed: (isAllocating: boolean) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
||||||
@@ -77,12 +69,8 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
|||||||
myNotebooksContentRoot: undefined,
|
myNotebooksContentRoot: undefined,
|
||||||
gitHubNotebooksContentRoot: undefined,
|
gitHubNotebooksContentRoot: undefined,
|
||||||
galleryContentRoot: undefined,
|
galleryContentRoot: undefined,
|
||||||
connectionInfo: {
|
connectionInfo: undefined,
|
||||||
status: ConnectionStatusType.Connect,
|
|
||||||
},
|
|
||||||
notebookFolderName: undefined,
|
notebookFolderName: undefined,
|
||||||
isAllocating: false,
|
|
||||||
isRefreshed: false,
|
|
||||||
setIsNotebookEnabled: (isNotebookEnabled: boolean) => set({ isNotebookEnabled }),
|
setIsNotebookEnabled: (isNotebookEnabled: boolean) => set({ isNotebookEnabled }),
|
||||||
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => set({ isNotebooksEnabledForAccount }),
|
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => set({ isNotebooksEnabledForAccount }),
|
||||||
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) =>
|
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) =>
|
||||||
@@ -187,7 +175,7 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
|||||||
isGithubTree ? set({ gitHubNotebooksContentRoot: root }) : set({ myNotebooksContentRoot: root });
|
isGithubTree ? set({ gitHubNotebooksContentRoot: root }) : set({ myNotebooksContentRoot: root });
|
||||||
},
|
},
|
||||||
initializeNotebooksTree: async (notebookManager: NotebookManager): Promise<void> => {
|
initializeNotebooksTree: async (notebookManager: NotebookManager): Promise<void> => {
|
||||||
const notebookFolderName = NotebookUtil.isPhoenixEnabled() === true ? "Temporary Notebooks" : "My Notebooks";
|
const notebookFolderName = userContext.features.phoenix === true ? "Temporary Notebooks" : "My Notebooks";
|
||||||
set({ notebookFolderName });
|
set({ notebookFolderName });
|
||||||
const myNotebooksContentRoot = {
|
const myNotebooksContentRoot = {
|
||||||
name: get().notebookFolderName,
|
name: get().notebookFolderName,
|
||||||
@@ -268,15 +256,5 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
|||||||
set({ gitHubNotebooksContentRoot });
|
set({ gitHubNotebooksContentRoot });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setConnectionInfo: (connectionInfo: ContainerConnectionInfo) => set({ connectionInfo }),
|
setConnectionInfo: (connectionInfo: DataModels.ContainerConnectionInfo) => set({ connectionInfo }),
|
||||||
setIsAllocating: (isAllocating: boolean) => set({ isAllocating }),
|
|
||||||
resetConatinerConnection: (connectionStatus: ContainerConnectionInfo): void => {
|
|
||||||
useNotebook.getState().setConnectionInfo(connectionStatus);
|
|
||||||
useNotebook.getState().setNotebookServerInfo({
|
|
||||||
notebookServerEndpoint: undefined,
|
|
||||||
authToken: undefined,
|
|
||||||
});
|
|
||||||
useNotebook.getState().setIsAllocating(false);
|
|
||||||
},
|
|
||||||
setIsRefreshed: (isRefreshed: boolean) => set({ isRefreshed }),
|
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import * as React from "react";
|
|||||||
import { useFullScreenURLs } from "../hooks/useFullScreenURLs";
|
import { useFullScreenURLs } from "../hooks/useFullScreenURLs";
|
||||||
|
|
||||||
export const OpenFullScreen: React.FunctionComponent = () => {
|
export const OpenFullScreen: React.FunctionComponent = () => {
|
||||||
const [isReadUrlCopy, setIsReadUrlCopy] = React.useState<boolean>(false);
|
|
||||||
const [isReadWriteUrlCopy, setIsReadWriteUrlCopy] = React.useState<boolean>(false);
|
|
||||||
const result = useFullScreenURLs();
|
const result = useFullScreenURLs();
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return <Spinner label="Generating URLs..." ariaLive="assertive" labelPosition="right" />;
|
return <Spinner label="Generating URLs..." ariaLive="assertive" labelPosition="right" />;
|
||||||
@@ -27,9 +25,8 @@ export const OpenFullScreen: React.FunctionComponent = () => {
|
|||||||
<DefaultButton
|
<DefaultButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
copyToClipboard(readWriteUrl);
|
copyToClipboard(readWriteUrl);
|
||||||
setIsReadWriteUrlCopy(true);
|
|
||||||
}}
|
}}
|
||||||
text={isReadWriteUrlCopy ? "Copied" : "Copy"}
|
text="Copy"
|
||||||
iconProps={{ iconName: "Copy" }}
|
iconProps={{ iconName: "Copy" }}
|
||||||
/>
|
/>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
@@ -44,10 +41,9 @@ export const OpenFullScreen: React.FunctionComponent = () => {
|
|||||||
<Stack horizontal tokens={{ childrenGap: 10 }}>
|
<Stack horizontal tokens={{ childrenGap: 10 }}>
|
||||||
<DefaultButton
|
<DefaultButton
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsReadUrlCopy(true);
|
|
||||||
copyToClipboard(readUrl);
|
copyToClipboard(readUrl);
|
||||||
}}
|
}}
|
||||||
text={isReadUrlCopy ? "Copied" : "Copy"}
|
text="Copy"
|
||||||
iconProps={{ iconName: "Copy" }}
|
iconProps={{ iconName: "Copy" }}
|
||||||
/>
|
/>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
|
|||||||
@@ -13,21 +13,21 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
TooltipHost,
|
TooltipHost,
|
||||||
} from "@fluentui/react";
|
} from "@fluentui/react";
|
||||||
import * as Constants from "Common/Constants";
|
|
||||||
import { createCollection } from "Common/dataAccess/createCollection";
|
|
||||||
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
|
|
||||||
import { configContext, Platform } from "ConfigContext";
|
|
||||||
import * as DataModels from "Contracts/DataModels";
|
|
||||||
import { SubscriptionType } from "Contracts/SubscriptionType";
|
|
||||||
import { useSidePanel } from "hooks/useSidePanel";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CollectionCreation } from "Shared/Constants";
|
import * as Constants from "../../Common/Constants";
|
||||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
import { createCollection } from "../../Common/dataAccess/createCollection";
|
||||||
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
|
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
|
||||||
import { userContext } from "UserContext";
|
import { configContext, Platform } from "../../ConfigContext";
|
||||||
import { getCollectionName } from "Utils/APITypeUtils";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { isCapabilityEnabled, isServerlessAccount } from "Utils/CapabilityUtils";
|
import { SubscriptionType } from "../../Contracts/SubscriptionType";
|
||||||
import { getUpsellMessage } from "Utils/PricingUtils";
|
import { useSidePanel } from "../../hooks/useSidePanel";
|
||||||
|
import { CollectionCreation } from "../../Shared/Constants";
|
||||||
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { getCollectionName } from "../../Utils/APITypeUtils";
|
||||||
|
import { isCapabilityEnabled, isServerlessAccount } from "../../Utils/CapabilityUtils";
|
||||||
|
import { getUpsellMessage } from "../../Utils/PricingUtils";
|
||||||
import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent";
|
import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent";
|
||||||
import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput";
|
import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
@@ -173,7 +173,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
aria-checked={this.state.createNewDatabase}
|
aria-checked={this.state.createNewDatabase}
|
||||||
name="databaseType"
|
name="databaseType"
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
id="databaseCreateNew"
|
id="databaseCreateNew"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)}
|
onChange={this.onCreateNewDatabaseRadioBtnChange.bind(this)}
|
||||||
@@ -187,7 +186,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
aria-checked={!this.state.createNewDatabase}
|
aria-checked={!this.state.createNewDatabase}
|
||||||
name="databaseType"
|
name="databaseType"
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)}
|
onChange={this.onUseExistingDatabaseRadioBtnChange.bind(this)}
|
||||||
/>
|
/>
|
||||||
@@ -209,7 +207,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
size={40}
|
size={40}
|
||||||
className="panelTextField"
|
className="panelTextField"
|
||||||
aria-label="New database id"
|
aria-label="New database id"
|
||||||
autoFocus
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
value={this.state.newDatabaseId}
|
value={this.state.newDatabaseId}
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
@@ -320,7 +317,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
aria-label="Turn on indexing"
|
aria-label="Turn on indexing"
|
||||||
aria-checked={this.state.enableIndexing}
|
aria-checked={this.state.enableIndexing}
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onTurnOnIndexing.bind(this)}
|
onChange={this.onTurnOnIndexing.bind(this)}
|
||||||
/>
|
/>
|
||||||
@@ -332,7 +328,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
aria-label="Turn off indexing"
|
aria-label="Turn off indexing"
|
||||||
aria-checked={!this.state.enableIndexing}
|
aria-checked={!this.state.enableIndexing}
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onTurnOffIndexing.bind(this)}
|
onChange={this.onTurnOffIndexing.bind(this)}
|
||||||
/>
|
/>
|
||||||
@@ -375,7 +370,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
aria-checked={!this.state.isSharded}
|
aria-checked={!this.state.isSharded}
|
||||||
name="unsharded"
|
name="unsharded"
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
id="unshardedOption"
|
id="unshardedOption"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onUnshardedRadioBtnChange.bind(this)}
|
onChange={this.onUnshardedRadioBtnChange.bind(this)}
|
||||||
@@ -389,7 +383,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
aria-checked={this.state.isSharded}
|
aria-checked={this.state.isSharded}
|
||||||
name="sharded"
|
name="sharded"
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
id="shardedOption"
|
id="shardedOption"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onShardedRadioBtnChange.bind(this)}
|
onChange={this.onShardedRadioBtnChange.bind(this)}
|
||||||
@@ -515,7 +508,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
: "Comma separated paths e.g. /firstName,/address/zipCode"
|
: "Comma separated paths e.g. /firstName,/address/zipCode"
|
||||||
}
|
}
|
||||||
className="panelTextField"
|
className="panelTextField"
|
||||||
autoFocus
|
|
||||||
value={uniqueKey}
|
value={uniqueKey}
|
||||||
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const uniqueKeys = this.state.uniqueKeys.map((uniqueKey: string, j: number) => {
|
const uniqueKeys = this.state.uniqueKeys.map((uniqueKey: string, j: number) => {
|
||||||
@@ -574,7 +566,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
aria-checked={this.state.enableAnalyticalStore}
|
aria-checked={this.state.enableAnalyticalStore}
|
||||||
name="analyticalStore"
|
name="analyticalStore"
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
id="enableAnalyticalStoreBtn"
|
id="enableAnalyticalStoreBtn"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onEnableAnalyticalStoreRadioBtnChange.bind(this)}
|
onChange={this.onEnableAnalyticalStoreRadioBtnChange.bind(this)}
|
||||||
@@ -589,7 +580,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
aria-checked={!this.state.enableAnalyticalStore}
|
aria-checked={!this.state.enableAnalyticalStore}
|
||||||
name="analyticalStore"
|
name="analyticalStore"
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
id="disableAnalyticalStoreBtn"
|
id="disableAnalyticalStoreBtn"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={this.onDisableAnalyticalStoreRadioBtnChange.bind(this)}
|
onChange={this.onDisableAnalyticalStoreRadioBtnChange.bind(this)}
|
||||||
@@ -999,7 +989,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
|
|
||||||
const collectionId: string = this.state.collectionId.trim();
|
const collectionId: string = this.state.collectionId.trim();
|
||||||
let databaseId = this.state.createNewDatabase ? this.state.newDatabaseId.trim() : this.state.selectedDatabaseId;
|
let databaseId = this.state.createNewDatabase ? this.state.newDatabaseId.trim() : this.state.selectedDatabaseId;
|
||||||
let partitionKeyString = this.state.isSharded ? this.state.partitionKey.trim() : undefined;
|
let partitionKeyString = this.state.partitionKey.trim();
|
||||||
|
|
||||||
if (userContext.apiType === "Tables") {
|
if (userContext.apiType === "Tables") {
|
||||||
// Table require fixed Database: TablesDB, and fixed Partition Key: /'$pk'
|
// Table require fixed Database: TablesDB, and fixed Partition Key: /'$pk'
|
||||||
|
|||||||
@@ -210,7 +210,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
|
|||||||
placeholder={databaseIdPlaceHolder}
|
placeholder={databaseIdPlaceHolder}
|
||||||
value={databaseId}
|
value={databaseId}
|
||||||
onChange={handleonChangeDBId}
|
onChange={handleonChangeDBId}
|
||||||
autoFocus
|
|
||||||
styles={getTextFieldStyles()}
|
styles={getTextFieldStyles()}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ exports[`AddDatabasePane Pane should render Default properly 1`] = `
|
|||||||
aria-label="Database id"
|
aria-label="Database id"
|
||||||
aria-required="true"
|
aria-required="true"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
autoFocus={true}
|
|
||||||
id="database-id"
|
id="database-id"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
pattern="[^/?#\\\\\\\\]*[^/?# \\\\\\\\]"
|
pattern="[^/?#\\\\\\\\]*[^/?# \\\\\\\\]"
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import { Checkbox, Dropdown, IDropdownOption, Link, Stack, Text, TextField } from "@fluentui/react";
|
import { Checkbox, Dropdown, IDropdownOption, Link, Stack, Text, TextField } from "@fluentui/react";
|
||||||
import * as Constants from "Common/Constants";
|
|
||||||
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
|
|
||||||
import { InfoTooltip } from "Common/Tooltip/InfoTooltip";
|
|
||||||
import { useSidePanel } from "hooks/useSidePanel";
|
|
||||||
import React, { FunctionComponent, useState } from "react";
|
import React, { FunctionComponent, useState } from "react";
|
||||||
import * as SharedConstants from "Shared/Constants";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
||||||
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
|
import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
|
||||||
import { userContext } from "UserContext";
|
import { useSidePanel } from "../../../hooks/useSidePanel";
|
||||||
import { isServerlessAccount } from "Utils/CapabilityUtils";
|
import * as SharedConstants from "../../../Shared/Constants";
|
||||||
|
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
|
import { isServerlessAccount } from "../../../Utils/CapabilityUtils";
|
||||||
import { ThroughputInput } from "../../Controls/ThroughputInput/ThroughputInput";
|
import { ThroughputInput } from "../../Controls/ThroughputInput/ThroughputInput";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import { CassandraAPIDataClient } from "../../Tables/TableDataClient";
|
import { CassandraAPIDataClient } from "../../Tables/TableDataClient";
|
||||||
@@ -169,7 +169,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
|
|||||||
aria-label="Create new keyspace"
|
aria-label="Create new keyspace"
|
||||||
checked={keyspaceCreateNew}
|
checked={keyspaceCreateNew}
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setKeyspaceCreateNew(true);
|
setKeyspaceCreateNew(true);
|
||||||
@@ -184,7 +183,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
|
|||||||
aria-label="Use existing keyspace"
|
aria-label="Use existing keyspace"
|
||||||
checked={!keyspaceCreateNew}
|
checked={!keyspaceCreateNew}
|
||||||
type="radio"
|
type="radio"
|
||||||
role="radio"
|
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setKeyspaceCreateNew(false);
|
setKeyspaceCreateNew(false);
|
||||||
@@ -208,7 +206,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
|
|||||||
value={newKeyspaceId}
|
value={newKeyspaceId}
|
||||||
onChange={(e, newValue) => setNewKeyspaceId(newValue)}
|
onChange={(e, newValue) => setNewKeyspaceId(newValue)}
|
||||||
ariaLabel="Keyspace id"
|
ariaLabel="Keyspace id"
|
||||||
autoFocus
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{!isServerlessAccount() && (
|
{!isServerlessAccount() && (
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
|
|||||||
selectedLocation.repo
|
selectedLocation.repo
|
||||||
)} - ${selectedLocation.branch}`;
|
)} - ${selectedLocation.branch}`;
|
||||||
} else if (selectedLocation.type === "MyNotebooks" && userContext.features.phoenix) {
|
} else if (selectedLocation.type === "MyNotebooks" && userContext.features.phoenix) {
|
||||||
destination = useNotebook.getState().notebookFolderName;
|
destination = "My Notebooks Scratch";
|
||||||
}
|
}
|
||||||
|
|
||||||
clearMessage = NotificationConsoleUtils.logConsoleProgress(`Copying ${name} to ${destination}`);
|
clearMessage = NotificationConsoleUtils.logConsoleProgress(`Copying ${name} to ${destination}`);
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { Text, TextField } from "@fluentui/react";
|
import { Text, TextField } from "@fluentui/react";
|
||||||
import { Areas } from "Common/Constants";
|
|
||||||
import { deleteCollection } from "Common/dataAccess/deleteCollection";
|
|
||||||
import DeleteFeedback from "Common/DeleteFeedback";
|
|
||||||
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
|
|
||||||
import { Collection } from "Contracts/ViewModels";
|
|
||||||
import { useSidePanel } from "hooks/useSidePanel";
|
|
||||||
import { useTabs } from "hooks/useTabs";
|
|
||||||
import React, { FunctionComponent, useState } from "react";
|
import React, { FunctionComponent, useState } from "react";
|
||||||
import { DefaultExperienceUtility } from "Shared/DefaultExperienceUtility";
|
import { Areas } from "../../../Common/Constants";
|
||||||
import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants";
|
import { deleteCollection } from "../../../Common/dataAccess/deleteCollection";
|
||||||
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
|
import DeleteFeedback from "../../../Common/DeleteFeedback";
|
||||||
import { userContext } from "UserContext";
|
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
||||||
import { getCollectionName } from "Utils/APITypeUtils";
|
import { Collection } from "../../../Contracts/ViewModels";
|
||||||
import * as NotificationConsoleUtils from "Utils/NotificationConsoleUtils";
|
import { useSidePanel } from "../../../hooks/useSidePanel";
|
||||||
|
import { useTabs } from "../../../hooks/useTabs";
|
||||||
|
import { DefaultExperienceUtility } from "../../../Shared/DefaultExperienceUtility";
|
||||||
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
|
import { getCollectionName } from "../../../Utils/APITypeUtils";
|
||||||
|
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
||||||
import { useDatabases } from "../../useDatabases";
|
import { useDatabases } from "../../useDatabases";
|
||||||
import { useSelectedNode } from "../../useSelectedNode";
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||||
@@ -119,7 +119,6 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
|
|||||||
<Text variant="small">Confirm by typing the {collectionName.toLowerCase()} id</Text>
|
<Text variant="small">Confirm by typing the {collectionName.toLowerCase()} id</Text>
|
||||||
<TextField
|
<TextField
|
||||||
id="confirmCollectionId"
|
id="confirmCollectionId"
|
||||||
autoFocus
|
|
||||||
value={inputCollectionName}
|
value={inputCollectionName}
|
||||||
styles={{ fieldGroup: { width: 300 } }}
|
styles={{ fieldGroup: { width: 300 } }}
|
||||||
onChange={(event, newInput?: string) => {
|
onChange={(event, newInput?: string) => {
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
</Text>
|
</Text>
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
ariaLabel="Confirm by typing the container id"
|
ariaLabel="Confirm by typing the container id"
|
||||||
autoFocus={true}
|
|
||||||
id="confirmCollectionId"
|
id="confirmCollectionId"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
styles={
|
styles={
|
||||||
@@ -55,7 +54,6 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
>
|
>
|
||||||
<TextFieldBase
|
<TextFieldBase
|
||||||
ariaLabel="Confirm by typing the container id"
|
ariaLabel="Confirm by typing the container id"
|
||||||
autoFocus={true}
|
|
||||||
deferredValidationTime={200}
|
deferredValidationTime={200}
|
||||||
id="confirmCollectionId"
|
id="confirmCollectionId"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
@@ -349,7 +347,6 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
<input
|
<input
|
||||||
aria-invalid={false}
|
aria-invalid={false}
|
||||||
aria-label="Confirm by typing the container id"
|
aria-label="Confirm by typing the container id"
|
||||||
autoFocus={true}
|
|
||||||
className="ms-TextField-field field-57"
|
className="ms-TextField-field field-57"
|
||||||
id="confirmCollectionId"
|
id="confirmCollectionId"
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { Text, TextField } from "@fluentui/react";
|
import { Text, TextField } from "@fluentui/react";
|
||||||
import { useBoolean } from "@fluentui/react-hooks";
|
import { useBoolean } from "@fluentui/react-hooks";
|
||||||
import { Areas } from "Common/Constants";
|
|
||||||
import { deleteDatabase } from "Common/dataAccess/deleteDatabase";
|
|
||||||
import DeleteFeedback from "Common/DeleteFeedback";
|
|
||||||
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
|
|
||||||
import { Collection, Database } from "Contracts/ViewModels";
|
|
||||||
import { useSidePanel } from "hooks/useSidePanel";
|
|
||||||
import { useTabs } from "hooks/useTabs";
|
|
||||||
import React, { FunctionComponent, useState } from "react";
|
import React, { FunctionComponent, useState } from "react";
|
||||||
import { DefaultExperienceUtility } from "Shared/DefaultExperienceUtility";
|
import { Areas } from "../../Common/Constants";
|
||||||
import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants";
|
import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
|
||||||
import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor";
|
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||||
import { userContext } from "UserContext";
|
import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
|
||||||
import { logConsoleError } from "Utils/NotificationConsoleUtils";
|
import { Collection, Database } from "../../Contracts/ViewModels";
|
||||||
|
import { useSidePanel } from "../../hooks/useSidePanel";
|
||||||
|
import { useTabs } from "../../hooks/useTabs";
|
||||||
|
import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility";
|
||||||
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { useDatabases } from "../useDatabases";
|
import { useDatabases } from "../useDatabases";
|
||||||
import { useSelectedNode } from "../useSelectedNode";
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
import { PanelInfoErrorComponent, PanelInfoErrorProps } from "./PanelInfoErrorComponent";
|
import { PanelInfoErrorComponent, PanelInfoErrorProps } from "./PanelInfoErrorComponent";
|
||||||
@@ -129,7 +129,6 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
|
|||||||
<Text variant="small">Confirm by typing the database id</Text>
|
<Text variant="small">Confirm by typing the database id</Text>
|
||||||
<TextField
|
<TextField
|
||||||
id="confirmDatabaseId"
|
id="confirmDatabaseId"
|
||||||
autoFocus
|
|
||||||
styles={{ fieldGroup: { width: 300 } }}
|
styles={{ fieldGroup: { width: 300 } }}
|
||||||
onChange={(event, newInput?: string) => {
|
onChange={(event, newInput?: string) => {
|
||||||
setDatabaseInput(newInput);
|
setDatabaseInput(newInput);
|
||||||
|
|||||||
@@ -69,25 +69,11 @@ export const InputParameter: FunctionComponent<InputParameterProps> = ({
|
|||||||
/>
|
/>
|
||||||
{isAddRemoveVisible && (
|
{isAddRemoveVisible && (
|
||||||
<>
|
<>
|
||||||
<div tabIndex={0}>
|
<div tabIndex={0} onClick={onDeleteParamKeyPress} role="button" onKeyPress={onDeleteParamKeyPress}>
|
||||||
<Image
|
<Image {...imageProps} src={EntityCancelIcon} alt="Delete param" id="deleteparam" />
|
||||||
{...imageProps}
|
|
||||||
src={EntityCancelIcon}
|
|
||||||
alt="Delete param"
|
|
||||||
id="deleteparam"
|
|
||||||
role="button"
|
|
||||||
onClick={onDeleteParamKeyPress}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div tabIndex={0}>
|
<div tabIndex={0} onClick={onAddNewParamKeyPress} role="button" onKeyPress={onAddNewParamKeyPress}>
|
||||||
<Image
|
<Image {...imageProps} src={AddPropertyIcon} alt="Add param" id="addparam" />
|
||||||
{...imageProps}
|
|
||||||
src={AddPropertyIcon}
|
|
||||||
alt="Add param"
|
|
||||||
id="addparam"
|
|
||||||
role="button"
|
|
||||||
onClick={onAddNewParamKeyPress}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -4328,6 +4328,9 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
|||||||
</TextFieldBase>
|
</TextFieldBase>
|
||||||
</StyledTextFieldBase>
|
</StyledTextFieldBase>
|
||||||
<div
|
<div
|
||||||
|
onClick={[Function]}
|
||||||
|
onKeyPress={[Function]}
|
||||||
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<StyledImageBase
|
<StyledImageBase
|
||||||
@@ -4335,8 +4338,6 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
|||||||
className="addRemoveIconLabel"
|
className="addRemoveIconLabel"
|
||||||
height={30}
|
height={30}
|
||||||
id="deleteparam"
|
id="deleteparam"
|
||||||
onClick={[Function]}
|
|
||||||
role="button"
|
|
||||||
src=""
|
src=""
|
||||||
width={20}
|
width={20}
|
||||||
>
|
>
|
||||||
@@ -4345,8 +4346,6 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
|||||||
className="addRemoveIconLabel"
|
className="addRemoveIconLabel"
|
||||||
height={30}
|
height={30}
|
||||||
id="deleteparam"
|
id="deleteparam"
|
||||||
onClick={[Function]}
|
|
||||||
role="button"
|
|
||||||
src=""
|
src=""
|
||||||
styles={[Function]}
|
styles={[Function]}
|
||||||
theme={
|
theme={
|
||||||
@@ -4638,10 +4637,8 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
|||||||
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
|
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
|
||||||
id="deleteparam"
|
id="deleteparam"
|
||||||
key="fabricImage"
|
key="fabricImage"
|
||||||
onClick={[Function]}
|
|
||||||
onError={[Function]}
|
onError={[Function]}
|
||||||
onLoad={[Function]}
|
onLoad={[Function]}
|
||||||
role="button"
|
|
||||||
src=""
|
src=""
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -4649,6 +4646,9 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
|||||||
</StyledImageBase>
|
</StyledImageBase>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
onClick={[Function]}
|
||||||
|
onKeyPress={[Function]}
|
||||||
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
<StyledImageBase
|
<StyledImageBase
|
||||||
@@ -4656,8 +4656,6 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
|||||||
className="addRemoveIconLabel"
|
className="addRemoveIconLabel"
|
||||||
height={30}
|
height={30}
|
||||||
id="addparam"
|
id="addparam"
|
||||||
onClick={[Function]}
|
|
||||||
role="button"
|
|
||||||
src=""
|
src=""
|
||||||
width={20}
|
width={20}
|
||||||
>
|
>
|
||||||
@@ -4666,8 +4664,6 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
|||||||
className="addRemoveIconLabel"
|
className="addRemoveIconLabel"
|
||||||
height={30}
|
height={30}
|
||||||
id="addparam"
|
id="addparam"
|
||||||
onClick={[Function]}
|
|
||||||
role="button"
|
|
||||||
src=""
|
src=""
|
||||||
styles={[Function]}
|
styles={[Function]}
|
||||||
theme={
|
theme={
|
||||||
@@ -4959,10 +4955,8 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
|
|||||||
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
|
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
|
||||||
id="addparam"
|
id="addparam"
|
||||||
key="fabricImage"
|
key="fabricImage"
|
||||||
onClick={[Function]}
|
|
||||||
onError={[Function]}
|
onError={[Function]}
|
||||||
onLoad={[Function]}
|
onLoad={[Function]}
|
||||||
role="button"
|
|
||||||
src=""
|
src=""
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ export const LoadQueryPane: FunctionComponent = (): JSX.Element => {
|
|||||||
id="confirmCollectionId"
|
id="confirmCollectionId"
|
||||||
label="Select a query document"
|
label="Select a query document"
|
||||||
value={selectedFileName}
|
value={selectedFileName}
|
||||||
autoFocus
|
|
||||||
readOnly
|
readOnly
|
||||||
styles={{ fieldGroup: { width: 300 } }}
|
styles={{ fieldGroup: { width: 300 } }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ exports[`Load Query Pane should render Default properly 1`] = `
|
|||||||
horizontal={true}
|
horizontal={true}
|
||||||
>
|
>
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
autoFocus={true}
|
|
||||||
id="confirmCollectionId"
|
id="confirmCollectionId"
|
||||||
label="Select a query document"
|
label="Select a query document"
|
||||||
readOnly={true}
|
readOnly={true}
|
||||||
|
|||||||
@@ -48,9 +48,15 @@ export const PanelInfoErrorComponent: React.FunctionComponent<PanelInfoErrorProp
|
|||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
{showErrorDetails && (
|
{showErrorDetails && (
|
||||||
<a className="paneErrorLink" role="link" onClick={expandConsole}>
|
<span
|
||||||
|
className="paneErrorLink moreOption"
|
||||||
|
role="link"
|
||||||
|
onClick={expandConsole}
|
||||||
|
onKeyPress={expandConsole}
|
||||||
|
tabIndex={0}
|
||||||
|
>
|
||||||
More details
|
More details
|
||||||
</a>
|
</span>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ import LoadingIndicator_3Squares from "../../../images/LoadingIndicator_3Squares
|
|||||||
|
|
||||||
export const PanelLoadingScreen: React.FunctionComponent = () => (
|
export const PanelLoadingScreen: React.FunctionComponent = () => (
|
||||||
<div className="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer">
|
<div className="dataExplorerLoaderContainer dataExplorerPaneLoaderContainer">
|
||||||
<img className="dataExplorerLoader" src={LoadingIndicator_3Squares} />
|
<img className="dataExplorerLoader" src={LoadingIndicator_3Squares} alt="loading indicator" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -146,7 +146,6 @@ export const SaveQueryPane: FunctionComponent<SaveQueryPaneProps> = ({ explorer
|
|||||||
<TextField
|
<TextField
|
||||||
id="saveQueryInput"
|
id="saveQueryInput"
|
||||||
label="Name"
|
label="Name"
|
||||||
autoFocus
|
|
||||||
styles={{ fieldGroup: { width: 300 } }}
|
styles={{ fieldGroup: { width: 300 } }}
|
||||||
onChange={(event, newInput?: string) => {
|
onChange={(event, newInput?: string) => {
|
||||||
setQueryName(newInput);
|
setQueryName(newInput);
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { Checkbox, ChoiceGroup, IChoiceGroupOption, SpinButton } from "@fluentui/react";
|
import { Checkbox, ChoiceGroup, IChoiceGroupOption, SpinButton } from "@fluentui/react";
|
||||||
import * as Constants from "Common/Constants";
|
|
||||||
import { InfoTooltip } from "Common/Tooltip/InfoTooltip";
|
|
||||||
import { configContext } from "ConfigContext";
|
|
||||||
import { useSidePanel } from "hooks/useSidePanel";
|
|
||||||
import React, { FunctionComponent, MouseEvent, useState } from "react";
|
import React, { FunctionComponent, MouseEvent, useState } from "react";
|
||||||
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import * as StringUtility from "Shared/StringUtility";
|
import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
|
||||||
import { userContext } from "UserContext";
|
import { configContext } from "../../../ConfigContext";
|
||||||
import { logConsoleInfo } from "Utils/NotificationConsoleUtils";
|
import { useSidePanel } from "../../../hooks/useSidePanel";
|
||||||
|
import { LocalStorageUtility, StorageKey } from "../../../Shared/StorageUtility";
|
||||||
|
import * as StringUtility from "../../../Shared/StringUtility";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
|
import { logConsoleInfo } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||||
|
|
||||||
export const SettingsPane: FunctionComponent = () => {
|
export const SettingsPane: FunctionComponent = () => {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { TextField } from "@fluentui/react";
|
import { TextField } from "@fluentui/react";
|
||||||
import * as ViewModels from "Contracts/ViewModels";
|
|
||||||
import { useTabs } from "hooks/useTabs";
|
|
||||||
import React, { FormEvent, FunctionComponent, useState } from "react";
|
import React, { FormEvent, FunctionComponent, useState } from "react";
|
||||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "Utils/NotificationConsoleUtils";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
|
import { useTabs } from "../../../hooks/useTabs";
|
||||||
|
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import * as FileSystemUtil from "../../Notebook/FileSystemUtil";
|
import * as FileSystemUtil from "../../Notebook/FileSystemUtil";
|
||||||
import { NotebookContentItem } from "../../Notebook/NotebookContentItem";
|
import { NotebookContentItem } from "../../Notebook/NotebookContentItem";
|
||||||
import NotebookV2Tab from "../../Tabs/NotebookV2Tab";
|
import NotebookV2Tab from "../../Tabs/NotebookV2Tab";
|
||||||
@@ -97,7 +97,6 @@ export const StringInputPane: FunctionComponent<StringInputPanelProps> = ({
|
|||||||
label={inputLabel}
|
label={inputLabel}
|
||||||
name="collectionIdConfirmation"
|
name="collectionIdConfirmation"
|
||||||
value={stringInput}
|
value={stringInput}
|
||||||
autoFocus
|
|
||||||
required
|
required
|
||||||
onChange={(event: FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) =>
|
onChange={(event: FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) =>
|
||||||
setStringInput(newValue)
|
setStringInput(newValue)
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
|||||||
>
|
>
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
aria-label="Enter new directory name"
|
aria-label="Enter new directory name"
|
||||||
autoFocus={true}
|
|
||||||
label="Enter new directory name"
|
label="Enter new directory name"
|
||||||
name="collectionIdConfirmation"
|
name="collectionIdConfirmation"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
@@ -65,7 +64,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
|||||||
>
|
>
|
||||||
<TextFieldBase
|
<TextFieldBase
|
||||||
aria-label="Enter new directory name"
|
aria-label="Enter new directory name"
|
||||||
autoFocus={true}
|
|
||||||
deferredValidationTime={200}
|
deferredValidationTime={200}
|
||||||
label="Enter new directory name"
|
label="Enter new directory name"
|
||||||
name="collectionIdConfirmation"
|
name="collectionIdConfirmation"
|
||||||
@@ -655,7 +653,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
|||||||
<input
|
<input
|
||||||
aria-invalid={false}
|
aria-invalid={false}
|
||||||
aria-labelledby="TextFieldLabel2"
|
aria-labelledby="TextFieldLabel2"
|
||||||
autoFocus={true}
|
|
||||||
className="ms-TextField-field field-56"
|
className="ms-TextField-field field-56"
|
||||||
id="TextField0"
|
id="TextField0"
|
||||||
name="collectionIdConfirmation"
|
name="collectionIdConfirmation"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Upload } from "Common/Upload/Upload";
|
|
||||||
import { useSidePanel } from "hooks/useSidePanel";
|
|
||||||
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
||||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "Utils/NotificationConsoleUtils";
|
import { Upload } from "../../../Common/Upload/Upload";
|
||||||
|
import { useSidePanel } from "../../../hooks/useSidePanel";
|
||||||
|
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import { NotebookContentItem } from "../../Notebook/NotebookContentItem";
|
import { NotebookContentItem } from "../../Notebook/NotebookContentItem";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "@fluentui/react";
|
import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "@fluentui/react";
|
||||||
import { Upload } from "Common/Upload/Upload";
|
|
||||||
import { UploadDetailsRecord } from "Contracts/ViewModels";
|
|
||||||
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
||||||
import { logConsoleError } from "Utils/NotificationConsoleUtils";
|
import { Upload } from "../../../Common/Upload/Upload";
|
||||||
|
import { UploadDetailsRecord } from "../../../Contracts/ViewModels";
|
||||||
|
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import { getErrorMessage } from "../../Tables/Utilities";
|
import { getErrorMessage } from "../../Tables/Utilities";
|
||||||
import { useSelectedNode } from "../../useSelectedNode";
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||||
|
|||||||
@@ -368,7 +368,6 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
|
|||||||
</Text>
|
</Text>
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
ariaLabel="Confirm by typing the database id"
|
ariaLabel="Confirm by typing the database id"
|
||||||
autoFocus={true}
|
|
||||||
id="confirmDatabaseId"
|
id="confirmDatabaseId"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
styles={
|
styles={
|
||||||
@@ -381,7 +380,6 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
|
|||||||
>
|
>
|
||||||
<TextFieldBase
|
<TextFieldBase
|
||||||
ariaLabel="Confirm by typing the database id"
|
ariaLabel="Confirm by typing the database id"
|
||||||
autoFocus={true}
|
|
||||||
deferredValidationTime={200}
|
deferredValidationTime={200}
|
||||||
id="confirmDatabaseId"
|
id="confirmDatabaseId"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
@@ -674,7 +672,6 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
|
|||||||
<input
|
<input
|
||||||
aria-invalid={false}
|
aria-invalid={false}
|
||||||
aria-label="Confirm by typing the database id"
|
aria-label="Confirm by typing the database id"
|
||||||
autoFocus={true}
|
|
||||||
className="ms-TextField-field field-60"
|
className="ms-TextField-field field-60"
|
||||||
id="confirmDatabaseId"
|
id="confirmDatabaseId"
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
|
|||||||
@@ -108,7 +108,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.oneLineContent {
|
.oneLineContent {
|
||||||
margin-top: 4px;
|
margin-top: 6px;
|
||||||
|
margin-left: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.twoLineContent {
|
.twoLineContent {
|
||||||
@@ -133,18 +134,18 @@
|
|||||||
.flex-display();
|
.flex-display();
|
||||||
.flex-direction();
|
.flex-direction();
|
||||||
|
|
||||||
>.title {
|
.title {
|
||||||
color: @BaseDark;
|
color: @BaseDark;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
>.description {
|
.description {
|
||||||
color: @BaseDark;
|
color: @BaseDark;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(:hover):not(:focus) {
|
&:not(:hover):not(:focus) {
|
||||||
background-color: @BaseLow;
|
background-color: @BaseLow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.commonTasks {
|
&.commonTasks {
|
||||||
|
|||||||
@@ -128,18 +128,18 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
|||||||
<div className="title">Common Tasks</div>
|
<div className="title">Common Tasks</div>
|
||||||
<ul>
|
<ul>
|
||||||
{commonTaskItems.map((item) => (
|
{commonTaskItems.map((item) => (
|
||||||
<li
|
<li className="focusable" key={`${item.title}${item.description}`}>
|
||||||
className="focusable"
|
<div
|
||||||
key={`${item.title}${item.description}`}
|
onClick={item.onClick}
|
||||||
onClick={item.onClick}
|
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
|
||||||
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
|
tabIndex={0}
|
||||||
tabIndex={0}
|
role="button"
|
||||||
role="button"
|
>
|
||||||
>
|
<img src={item.iconSrc} alt="" />
|
||||||
<img src={item.iconSrc} alt="" />
|
<span className="oneLineContent" title={item.info}>
|
||||||
<span className="oneLineContent" title={item.info}>
|
{item.title}
|
||||||
{item.title}
|
</span>
|
||||||
</span>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
@@ -165,22 +165,23 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
|||||||
<div className="title">Tips</div>
|
<div className="title">Tips</div>
|
||||||
<ul>
|
<ul>
|
||||||
{tipsItems.map((item) => (
|
{tipsItems.map((item) => (
|
||||||
<li
|
<li className="tipContainer focusable" key={`${item.title}${item.description}`}>
|
||||||
className="tipContainer focusable"
|
<div
|
||||||
key={`${item.title}${item.description}`}
|
onClick={item.onClick}
|
||||||
onClick={item.onClick}
|
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
|
||||||
onKeyPress={(event: React.KeyboardEvent) => this.onSplashScreenItemKeyPress(event, item.onClick)}
|
tabIndex={0}
|
||||||
tabIndex={0}
|
role="button"
|
||||||
role="link"
|
className="tipsWrapper"
|
||||||
>
|
>
|
||||||
<div className="title" title={item.info}>
|
<div className="title" title={item.info}>
|
||||||
{item.title}
|
{item.title}
|
||||||
|
</div>
|
||||||
|
<div className="description">{item.description}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="description">{item.description}</div>
|
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
<li>
|
<li>
|
||||||
<a role="link" href={SplashScreen.seeMoreItemUrl} rel="noreferrer" target="_blank" tabIndex={0}>
|
<a href={SplashScreen.seeMoreItemUrl} rel="noreferrer" target="_blank" tabIndex={0}>
|
||||||
{SplashScreen.seeMoreItemTitle}
|
{SplashScreen.seeMoreItemTitle}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import Q from "q";
|
|
||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
import * as QueryBuilderConstants from "../Constants";
|
import Q from "q";
|
||||||
|
|
||||||
import * as Entities from "../Entities";
|
import * as Entities from "../Entities";
|
||||||
|
import * as QueryBuilderConstants from "../Constants";
|
||||||
import * as Utilities from "../Utilities";
|
import * as Utilities from "../Utilities";
|
||||||
|
|
||||||
export function getRowSelector(selectorSchema: Entities.IProperty[]): string {
|
export function getRowSelector(selectorSchema: Entities.IProperty[]): string {
|
||||||
let selector = "";
|
var selector: string = "";
|
||||||
selectorSchema &&
|
selectorSchema &&
|
||||||
selectorSchema.forEach((p: Entities.IProperty) => {
|
selectorSchema.forEach((p: Entities.IProperty) => {
|
||||||
selector += "[" + p.key + '="' + Utilities.jQuerySelectorEscape(p.value) + '"]';
|
selector += "[" + p.key + '="' + Utilities.jQuerySelectorEscape(p.value) + '"]';
|
||||||
@@ -14,10 +15,10 @@ export function getRowSelector(selectorSchema: Entities.IProperty[]): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function isRowVisible(dataTableScrollBodyQuery: JQuery, element: HTMLElement): boolean {
|
export function isRowVisible(dataTableScrollBodyQuery: JQuery, element: HTMLElement): boolean {
|
||||||
let isVisible = false;
|
var isVisible = false;
|
||||||
|
|
||||||
if (dataTableScrollBodyQuery.length && element) {
|
if (dataTableScrollBodyQuery.length && element) {
|
||||||
const elementRect: ClientRect = element.getBoundingClientRect(),
|
var elementRect: ClientRect = element.getBoundingClientRect(),
|
||||||
dataTableScrollBodyRect: ClientRect = dataTableScrollBodyQuery.get(0).getBoundingClientRect();
|
dataTableScrollBodyRect: ClientRect = dataTableScrollBodyQuery.get(0).getBoundingClientRect();
|
||||||
|
|
||||||
isVisible = elementRect.bottom <= dataTableScrollBodyRect.bottom && dataTableScrollBodyRect.top <= elementRect.top;
|
isVisible = elementRect.bottom <= dataTableScrollBodyRect.bottom && dataTableScrollBodyRect.top <= elementRect.top;
|
||||||
@@ -28,17 +29,17 @@ export function isRowVisible(dataTableScrollBodyQuery: JQuery, element: HTMLElem
|
|||||||
|
|
||||||
export function scrollToRowIfNeeded(dataTableRows: JQuery, currentIndex: number, isScrollUp: boolean): void {
|
export function scrollToRowIfNeeded(dataTableRows: JQuery, currentIndex: number, isScrollUp: boolean): void {
|
||||||
if (dataTableRows.length) {
|
if (dataTableRows.length) {
|
||||||
const dataTableScrollBodyQuery: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableScrollBodySelector),
|
var dataTableScrollBodyQuery: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableScrollBodySelector),
|
||||||
selectedRowElement: HTMLElement = dataTableRows.get(currentIndex);
|
selectedRowElement: HTMLElement = dataTableRows.get(currentIndex);
|
||||||
|
|
||||||
if (dataTableScrollBodyQuery.length && selectedRowElement) {
|
if (dataTableScrollBodyQuery.length && selectedRowElement) {
|
||||||
const isVisible: boolean = isRowVisible(dataTableScrollBodyQuery, selectedRowElement);
|
var isVisible: boolean = isRowVisible(dataTableScrollBodyQuery, selectedRowElement);
|
||||||
|
|
||||||
if (!isVisible) {
|
if (!isVisible) {
|
||||||
const selectedRowQuery: JQuery = $(selectedRowElement),
|
var selectedRowQuery: JQuery = $(selectedRowElement),
|
||||||
scrollPosition: number = dataTableScrollBodyQuery.scrollTop(),
|
scrollPosition: number = dataTableScrollBodyQuery.scrollTop(),
|
||||||
selectedElementPosition: number = selectedRowQuery.position().top;
|
selectedElementPosition: number = selectedRowQuery.position().top,
|
||||||
let newScrollPosition = 0;
|
newScrollPosition: number = 0;
|
||||||
|
|
||||||
if (isScrollUp) {
|
if (isScrollUp) {
|
||||||
newScrollPosition = scrollPosition + selectedElementPosition;
|
newScrollPosition = scrollPosition + selectedElementPosition;
|
||||||
@@ -54,7 +55,7 @@ export function scrollToRowIfNeeded(dataTableRows: JQuery, currentIndex: number,
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function scrollToTopIfNeeded(): void {
|
export function scrollToTopIfNeeded(): void {
|
||||||
const $dataTableRows: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableAllRowsSelector),
|
var $dataTableRows: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableAllRowsSelector),
|
||||||
$dataTableScrollBody: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableScrollBodySelector);
|
$dataTableScrollBody: JQuery = $(QueryBuilderConstants.htmlSelectors.dataTableScrollBodySelector);
|
||||||
|
|
||||||
if ($dataTableRows.length && $dataTableScrollBody.length) {
|
if ($dataTableRows.length && $dataTableScrollBody.length) {
|
||||||
@@ -87,14 +88,13 @@ export function reorderColumns(
|
|||||||
table: DataTables.DataTable,
|
table: DataTables.DataTable,
|
||||||
targetOrder: number[],
|
targetOrder: number[],
|
||||||
currentOrder?: number[]
|
currentOrder?: number[]
|
||||||
//eslint-disable-next-line
|
|
||||||
): Q.Promise<any> {
|
): Q.Promise<any> {
|
||||||
const columnsCount: number = targetOrder.length;
|
var columnsCount: number = targetOrder.length;
|
||||||
const isCurrentOrderPassedIn = !!currentOrder;
|
var isCurrentOrderPassedIn: boolean = !!currentOrder;
|
||||||
if (!isCurrentOrderPassedIn) {
|
if (!isCurrentOrderPassedIn) {
|
||||||
currentOrder = getInitialOrder(columnsCount);
|
currentOrder = getInitialOrder(columnsCount);
|
||||||
}
|
}
|
||||||
const isSameOrder: boolean = Utilities.isEqual(currentOrder, targetOrder);
|
var isSameOrder: boolean = Utilities.isEqual(currentOrder, targetOrder);
|
||||||
|
|
||||||
// if the targetOrder is the same as current order, do nothing.
|
// if the targetOrder is the same as current order, do nothing.
|
||||||
if (!isSameOrder) {
|
if (!isSameOrder) {
|
||||||
@@ -104,7 +104,7 @@ export function reorderColumns(
|
|||||||
// Then the transformation order will be the same as target order.
|
// Then the transformation order will be the same as target order.
|
||||||
// If current order is specified, then a transformation order is calculated.
|
// If current order is specified, then a transformation order is calculated.
|
||||||
// Refer to calculateTransformationOrder for details about transformation order.
|
// Refer to calculateTransformationOrder for details about transformation order.
|
||||||
const transformationOrder: number[] = isCurrentOrderPassedIn
|
var transformationOrder: number[] = isCurrentOrderPassedIn
|
||||||
? calculateTransformationOrder(currentOrder, targetOrder)
|
? calculateTransformationOrder(currentOrder, targetOrder)
|
||||||
: targetOrder;
|
: targetOrder;
|
||||||
try {
|
try {
|
||||||
@@ -143,7 +143,7 @@ export function getCurrentOrder(table: DataTables.DataTable): number[] {
|
|||||||
* Result: [0, 1, 2, 5, 6, 7, 3, 4, 8]
|
* Result: [0, 1, 2, 5, 6, 7, 3, 4, 8]
|
||||||
*/
|
*/
|
||||||
export function invertIndexValues(inputArray: number[]): number[] {
|
export function invertIndexValues(inputArray: number[]): number[] {
|
||||||
const invertedArray: number[] = [];
|
var invertedArray: number[] = [];
|
||||||
if (inputArray) {
|
if (inputArray) {
|
||||||
inputArray.forEach((value: number, index: number) => {
|
inputArray.forEach((value: number, index: number) => {
|
||||||
invertedArray[inputArray[index]] = index;
|
invertedArray[inputArray[index]] = index;
|
||||||
@@ -170,21 +170,20 @@ export function invertIndexValues(inputArray: number[]): number[] {
|
|||||||
* transformation order: Trans = [0, 1, 2, 7, 3, 4, 8, 5, 6]
|
* transformation order: Trans = [0, 1, 2, 7, 3, 4, 8, 5, 6]
|
||||||
*/
|
*/
|
||||||
export function calculateTransformationOrder(currentOrder: number[], targetOrder: number[]): number[] {
|
export function calculateTransformationOrder(currentOrder: number[], targetOrder: number[]): number[] {
|
||||||
let transformationOrder: number[] = [];
|
var transformationOrder: number[] = [];
|
||||||
if (currentOrder && targetOrder && currentOrder.length === targetOrder.length) {
|
if (currentOrder && targetOrder && currentOrder.length === targetOrder.length) {
|
||||||
const invertedCurrentOrder: number[] = invertIndexValues(currentOrder);
|
var invertedCurrentOrder: number[] = invertIndexValues(currentOrder);
|
||||||
transformationOrder = targetOrder.map((value: number) => invertedCurrentOrder[value]);
|
transformationOrder = targetOrder.map((value: number) => invertedCurrentOrder[value]);
|
||||||
}
|
}
|
||||||
return transformationOrder;
|
return transformationOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDataTableHeaders(table: DataTables.DataTable): string[] {
|
export function getDataTableHeaders(table: DataTables.DataTable): string[] {
|
||||||
const columns: DataTables.ColumnsMethods = table.columns();
|
var columns: DataTables.ColumnsMethods = table.columns();
|
||||||
let headers: string[] = [];
|
var headers: string[] = [];
|
||||||
if (columns) {
|
if (columns) {
|
||||||
// table.columns() return ColumnsMethods which is an array of arrays
|
// table.columns() return ColumnsMethods which is an array of arrays
|
||||||
//eslint-disable-next-line
|
var columnIndexes: number[] = (<any>columns)[0];
|
||||||
const columnIndexes: number[] = (<any>columns)[0];
|
|
||||||
if (columnIndexes) {
|
if (columnIndexes) {
|
||||||
headers = columnIndexes.map((value: number) => $(table.columns(value).header()).html());
|
headers = columnIndexes.map((value: number) => $(table.columns(value).header()).html());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import TableEntityListViewModel from "./TableEntityListViewModel";
|
|||||||
|
|
||||||
export default class TableCommands {
|
export default class TableCommands {
|
||||||
// Command Ids
|
// Command Ids
|
||||||
public static editEntityCommand = "edit";
|
public static editEntityCommand: string = "edit";
|
||||||
public static deleteEntitiesCommand = "delete";
|
public static deleteEntitiesCommand: string = "delete";
|
||||||
public static reorderColumnsCommand = "reorder";
|
public static reorderColumnsCommand: string = "reorder";
|
||||||
public static resetColumnsCommand = "reset";
|
public static resetColumnsCommand: string = "reset";
|
||||||
public static customizeColumnsCommand = "customizeColumns";
|
public static customizeColumnsCommand: string = "customizeColumns";
|
||||||
|
|
||||||
private _container: Explorer;
|
private _container: Explorer;
|
||||||
|
|
||||||
@@ -21,8 +21,8 @@ export default class TableCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isEnabled(commandName: string, selectedEntites: Entities.ITableEntity[]): boolean {
|
public isEnabled(commandName: string, selectedEntites: Entities.ITableEntity[]): boolean {
|
||||||
const singleItemSelected = DataTableUtilities.containSingleItem(selectedEntites);
|
var singleItemSelected: boolean = DataTableUtilities.containSingleItem(selectedEntites);
|
||||||
const atLeastOneItemSelected = DataTableUtilities.containItems(selectedEntites);
|
var atLeastOneItemSelected: boolean = DataTableUtilities.containItems(selectedEntites);
|
||||||
switch (commandName) {
|
switch (commandName) {
|
||||||
case TableCommands.editEntityCommand:
|
case TableCommands.editEntityCommand:
|
||||||
return singleItemSelected;
|
return singleItemSelected;
|
||||||
@@ -47,7 +47,6 @@ export default class TableCommands {
|
|||||||
/**
|
/**
|
||||||
* Edit entity
|
* Edit entity
|
||||||
*/
|
*/
|
||||||
//eslint-disable-next-line
|
|
||||||
public editEntityCommand(viewModel: TableEntityListViewModel): Q.Promise<any> {
|
public editEntityCommand(viewModel: TableEntityListViewModel): Q.Promise<any> {
|
||||||
if (!viewModel) {
|
if (!viewModel) {
|
||||||
return null; // Error
|
return null; // Error
|
||||||
@@ -57,9 +56,12 @@ export default class TableCommands {
|
|||||||
return null; // Erorr
|
return null; // Erorr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var entityToUpdate: Entities.ITableEntity = viewModel.selected()[0];
|
||||||
|
var originalNumberOfProperties = entityToUpdate ? 0 : Object.keys(entityToUpdate).length - 1; // .metadata is always a property for etag
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
//eslint-disable-next-line
|
|
||||||
public deleteEntitiesCommand(viewModel: TableEntityListViewModel): Q.Promise<any> {
|
public deleteEntitiesCommand(viewModel: TableEntityListViewModel): Q.Promise<any> {
|
||||||
if (!viewModel) {
|
if (!viewModel) {
|
||||||
return null; // Error
|
return null; // Error
|
||||||
@@ -67,7 +69,7 @@ export default class TableCommands {
|
|||||||
if (!DataTableUtilities.containItems(viewModel.selected())) {
|
if (!DataTableUtilities.containItems(viewModel.selected())) {
|
||||||
return null; // Error
|
return null; // Error
|
||||||
}
|
}
|
||||||
const entitiesToDelete: Entities.ITableEntity[] = viewModel.selected();
|
var entitiesToDelete: Entities.ITableEntity[] = viewModel.selected();
|
||||||
const deleteMessage: string =
|
const deleteMessage: string =
|
||||||
userContext.apiType === "Cassandra"
|
userContext.apiType === "Cassandra"
|
||||||
? "Are you sure you want to delete the selected rows?"
|
? "Are you sure you want to delete the selected rows?"
|
||||||
@@ -80,7 +82,7 @@ export default class TableCommands {
|
|||||||
() => {
|
() => {
|
||||||
viewModel.queryTablesTab.container.tableDataClient
|
viewModel.queryTablesTab.container.tableDataClient
|
||||||
.deleteDocuments(viewModel.queryTablesTab.collection, entitiesToDelete)
|
.deleteDocuments(viewModel.queryTablesTab.collection, entitiesToDelete)
|
||||||
.then(() => {
|
.then((results: any) => {
|
||||||
return viewModel.removeEntitiesFromCache(entitiesToDelete).then(() => {
|
return viewModel.removeEntitiesFromCache(entitiesToDelete).then(() => {
|
||||||
viewModel.redrawTableThrottled();
|
viewModel.redrawTableThrottled();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import * as Entities from "../Entities";
|
|
||||||
import * as Utilities from "../Utilities";
|
import * as Utilities from "../Utilities";
|
||||||
|
import * as Entities from "../Entities";
|
||||||
import CacheBase from "./CacheBase";
|
import CacheBase from "./CacheBase";
|
||||||
|
|
||||||
export default class TableEntityCache extends CacheBase<Entities.ITableEntity> {
|
export default class TableEntityCache extends CacheBase<Entities.ITableEntity> {
|
||||||
@@ -21,7 +21,7 @@ export default class TableEntityCache extends CacheBase<Entities.ITableEntity> {
|
|||||||
this._tableQuery = Utilities.copyTableQuery(tableQuery);
|
this._tableQuery = Utilities.copyTableQuery(tableQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
public preClear(): void {
|
public preClear() {
|
||||||
this.tableQuery = null;
|
this.tableQuery = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
|
import { QueryIterator, ItemDefinition, Resource } from "@azure/cosmos";
|
||||||
|
|
||||||
export interface ITableEntity {
|
export interface ITableEntity {
|
||||||
[property: string]: ITableEntityAttribute;
|
[property: string]: ITableEntityAttribute;
|
||||||
@@ -17,7 +17,6 @@ export interface ITableEntityAttribute {
|
|||||||
|
|
||||||
export interface IListTableEntitiesResult {
|
export interface IListTableEntitiesResult {
|
||||||
Results: ITableEntity[];
|
Results: ITableEntity[];
|
||||||
//eslint-disable-next-line
|
|
||||||
ContinuationToken: any;
|
ContinuationToken: any;
|
||||||
iterator?: QueryIterator<ItemDefinition & Resource>;
|
iterator?: QueryIterator<ItemDefinition & Resource>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import * as Utilities from "../Utilities";
|
|
||||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||||
|
import * as Utilities from "../Utilities";
|
||||||
|
|
||||||
export default class ClauseGroup {
|
export default class ClauseGroup {
|
||||||
public isRootGroup: boolean;
|
public isRootGroup: boolean;
|
||||||
//eslint-disable-next-line
|
|
||||||
public children = new Array();
|
public children = new Array();
|
||||||
public parentGroup: ClauseGroup;
|
public parentGroup: ClauseGroup;
|
||||||
private _id: string;
|
private _id: string;
|
||||||
@@ -18,7 +17,7 @@ export default class ClauseGroup {
|
|||||||
* Flattens the clause tree into an array, depth-first, left to right.
|
* Flattens the clause tree into an array, depth-first, left to right.
|
||||||
*/
|
*/
|
||||||
public flattenClauses(targetArray: ko.ObservableArray<QueryClauseViewModel>): void {
|
public flattenClauses(targetArray: ko.ObservableArray<QueryClauseViewModel>): void {
|
||||||
const tempArray = new Array<QueryClauseViewModel>();
|
var tempArray = new Array<QueryClauseViewModel>();
|
||||||
|
|
||||||
this.flattenClausesImpl(this, tempArray);
|
this.flattenClausesImpl(this, tempArray);
|
||||||
targetArray.removeAll();
|
targetArray.removeAll();
|
||||||
@@ -32,10 +31,10 @@ export default class ClauseGroup {
|
|||||||
newClause.clauseGroup = this;
|
newClause.clauseGroup = this;
|
||||||
this.children.push(newClause);
|
this.children.push(newClause);
|
||||||
} else {
|
} else {
|
||||||
const targetGroup = insertBefore.clauseGroup;
|
var targetGroup = insertBefore.clauseGroup;
|
||||||
|
|
||||||
if (targetGroup) {
|
if (targetGroup) {
|
||||||
const insertBeforeIndex = targetGroup.children.indexOf(insertBefore);
|
var insertBeforeIndex = targetGroup.children.indexOf(insertBefore);
|
||||||
newClause.clauseGroup = targetGroup;
|
newClause.clauseGroup = targetGroup;
|
||||||
targetGroup.children.splice(insertBeforeIndex, 0, newClause);
|
targetGroup.children.splice(insertBeforeIndex, 0, newClause);
|
||||||
}
|
}
|
||||||
@@ -43,19 +42,19 @@ export default class ClauseGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public deleteClause(clause: QueryClauseViewModel): void {
|
public deleteClause(clause: QueryClauseViewModel): void {
|
||||||
const targetGroup = clause.clauseGroup;
|
var targetGroup = clause.clauseGroup;
|
||||||
|
|
||||||
if (targetGroup) {
|
if (targetGroup) {
|
||||||
const index = targetGroup.children.indexOf(clause);
|
var index = targetGroup.children.indexOf(clause);
|
||||||
targetGroup.children.splice(index, 1);
|
targetGroup.children.splice(index, 1);
|
||||||
clause.dispose();
|
clause.dispose();
|
||||||
|
|
||||||
if (targetGroup.children.length <= 1 && !targetGroup.isRootGroup) {
|
if (targetGroup.children.length <= 1 && !targetGroup.isRootGroup) {
|
||||||
const parent = targetGroup.parentGroup;
|
var parent = targetGroup.parentGroup;
|
||||||
const targetGroupIndex = parent.children.indexOf(targetGroup);
|
var targetGroupIndex = parent.children.indexOf(targetGroup);
|
||||||
|
|
||||||
if (targetGroup.children.length === 1) {
|
if (targetGroup.children.length === 1) {
|
||||||
const orphan = targetGroup.children.shift();
|
var orphan = targetGroup.children.shift();
|
||||||
|
|
||||||
if (orphan instanceof QueryClauseViewModel) {
|
if (orphan instanceof QueryClauseViewModel) {
|
||||||
(<QueryClauseViewModel>orphan).clauseGroup = parent;
|
(<QueryClauseViewModel>orphan).clauseGroup = parent;
|
||||||
@@ -72,14 +71,14 @@ export default class ClauseGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public removeAll(): void {
|
public removeAll(): void {
|
||||||
const allClauses: QueryClauseViewModel[] = new Array<QueryClauseViewModel>();
|
var allClauses: QueryClauseViewModel[] = new Array<QueryClauseViewModel>();
|
||||||
|
|
||||||
this.flattenClausesImpl(this, allClauses);
|
this.flattenClausesImpl(this, allClauses);
|
||||||
|
|
||||||
while (allClauses.length > 0) {
|
while (allClauses.length > 0) {
|
||||||
allClauses.shift().dispose();
|
allClauses.shift().dispose();
|
||||||
}
|
}
|
||||||
//eslint-disable-next-line
|
|
||||||
this.children = new Array<any>();
|
this.children = new Array<any>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,12 +87,12 @@ export default class ClauseGroup {
|
|||||||
*/
|
*/
|
||||||
public groupSelectedItems(): boolean {
|
public groupSelectedItems(): boolean {
|
||||||
// Find the selection start & end, also check for gaps between selected items (if found, cannot proceed).
|
// Find the selection start & end, also check for gaps between selected items (if found, cannot proceed).
|
||||||
const selection = this.getCheckedItemsInfo();
|
var selection = this.getCheckedItemsInfo();
|
||||||
|
|
||||||
if (selection.canGroup) {
|
if (selection.canGroup) {
|
||||||
const newGroup = new ClauseGroup(false, this);
|
var newGroup = new ClauseGroup(false, this);
|
||||||
// Replace the selected items with the new group, and then move the selected items into the new group.
|
// Replace the selected items with the new group, and then move the selected items into the new group.
|
||||||
const groupedItems = this.children.splice(selection.begin, selection.end - selection.begin + 1, newGroup);
|
var groupedItems = this.children.splice(selection.begin, selection.end - selection.begin + 1, newGroup);
|
||||||
|
|
||||||
groupedItems &&
|
groupedItems &&
|
||||||
groupedItems.forEach((element) => {
|
groupedItems.forEach((element) => {
|
||||||
@@ -119,13 +118,13 @@ export default class ClauseGroup {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentGroup = this.parentGroup;
|
var parentGroup = this.parentGroup;
|
||||||
let index = parentGroup.children.indexOf(this);
|
var index = parentGroup.children.indexOf(this);
|
||||||
|
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
parentGroup.children.splice(index, 1);
|
parentGroup.children.splice(index, 1);
|
||||||
|
|
||||||
const toPromote = this.children.splice(0, this.children.length);
|
var toPromote = this.children.splice(0, this.children.length);
|
||||||
|
|
||||||
// Move all children one level up.
|
// Move all children one level up.
|
||||||
toPromote &&
|
toPromote &&
|
||||||
@@ -147,16 +146,16 @@ export default class ClauseGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public findDeepestGroupInChildren(skipIndex?: number): ClauseGroup {
|
public findDeepestGroupInChildren(skipIndex?: number): ClauseGroup {
|
||||||
let deepest = <ClauseGroup>this;
|
var deepest: ClauseGroup = this;
|
||||||
let level = 0;
|
var level: number = 0;
|
||||||
const func = (currentGroup: ClauseGroup): void => {
|
var func = (currentGroup: ClauseGroup): void => {
|
||||||
level++;
|
level++;
|
||||||
if (currentGroup.getCurrentGroupDepth() > deepest.getCurrentGroupDepth()) {
|
if (currentGroup.getCurrentGroupDepth() > deepest.getCurrentGroupDepth()) {
|
||||||
deepest = currentGroup;
|
deepest = currentGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < currentGroup.children.length; i++) {
|
for (var i = 0; i < currentGroup.children.length; i++) {
|
||||||
const currentItem = currentGroup.children[i];
|
var currentItem = currentGroup.children[i];
|
||||||
|
|
||||||
if ((i !== skipIndex || level > 1) && currentItem instanceof ClauseGroup) {
|
if ((i !== skipIndex || level > 1) && currentItem instanceof ClauseGroup) {
|
||||||
func(currentItem);
|
func(currentItem);
|
||||||
@@ -171,16 +170,16 @@ export default class ClauseGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getCheckedItemsInfo(): { canGroup: boolean; begin: number; end: number } {
|
private getCheckedItemsInfo(): { canGroup: boolean; begin: number; end: number } {
|
||||||
let beginIndex = -1;
|
var beginIndex = -1;
|
||||||
let endIndex = -1;
|
var endIndex = -1;
|
||||||
// In order to perform group, all selected items must be next to each other.
|
// In order to perform group, all selected items must be next to each other.
|
||||||
// If one or more items are not selected between the first and the last selected item, the gapFlag will be set to True, meaning cannot perform group.
|
// If one or more items are not selected between the first and the last selected item, the gapFlag will be set to True, meaning cannot perform group.
|
||||||
let gapFlag = false;
|
var gapFlag = false;
|
||||||
let count = 0;
|
var count = 0;
|
||||||
|
|
||||||
for (let i = 0; i < this.children.length; i++) {
|
for (var i = 0; i < this.children.length; i++) {
|
||||||
const currentItem = this.children[i];
|
var currentItem = this.children[i];
|
||||||
let subGroupSelectionState: { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean };
|
var subGroupSelectionState: { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean };
|
||||||
|
|
||||||
if (currentItem instanceof ClauseGroup) {
|
if (currentItem instanceof ClauseGroup) {
|
||||||
subGroupSelectionState = (<ClauseGroup>currentItem).getSelectionState();
|
subGroupSelectionState = (<ClauseGroup>currentItem).getSelectionState();
|
||||||
@@ -236,10 +235,10 @@ export default class ClauseGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getSelectionState(): { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean } {
|
private getSelectionState(): { allSelected: boolean; partiallySelected: boolean; nonSelected: boolean } {
|
||||||
let selectedCount = 0;
|
var selectedCount = 0;
|
||||||
|
|
||||||
for (let i = 0; i < this.children.length; i++) {
|
for (var i = 0; i < this.children.length; i++) {
|
||||||
const currentItem = this.children[i];
|
var currentItem = this.children[i];
|
||||||
|
|
||||||
if (currentItem instanceof ClauseGroup && (<ClauseGroup>currentItem).getSelectionState().allSelected) {
|
if (currentItem instanceof ClauseGroup && (<ClauseGroup>currentItem).getSelectionState().allSelected) {
|
||||||
selectedCount++;
|
selectedCount++;
|
||||||
@@ -261,8 +260,8 @@ export default class ClauseGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private unselectAll(): void {
|
private unselectAll(): void {
|
||||||
for (let i = 0; i < this.children.length; i++) {
|
for (var i = 0; i < this.children.length; i++) {
|
||||||
const currentItem = this.children[i];
|
var currentItem = this.children[i];
|
||||||
|
|
||||||
if (currentItem instanceof ClauseGroup) {
|
if (currentItem instanceof ClauseGroup) {
|
||||||
(<ClauseGroup>currentItem).unselectAll();
|
(<ClauseGroup>currentItem).unselectAll();
|
||||||
@@ -279,8 +278,8 @@ export default class ClauseGroup {
|
|||||||
targetArray.splice(0, targetArray.length);
|
targetArray.splice(0, targetArray.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < queryGroup.children.length; i++) {
|
for (var i = 0; i < queryGroup.children.length; i++) {
|
||||||
const currentItem = queryGroup.children[i];
|
var currentItem = queryGroup.children[i];
|
||||||
|
|
||||||
if (currentItem instanceof ClauseGroup) {
|
if (currentItem instanceof ClauseGroup) {
|
||||||
this.flattenClausesImpl(currentItem, targetArray);
|
this.flattenClausesImpl(currentItem, targetArray);
|
||||||
@@ -293,13 +292,13 @@ export default class ClauseGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getTreeDepth(): number {
|
public getTreeDepth(): number {
|
||||||
let currentDepth = this.getCurrentGroupDepth();
|
var currentDepth = this.getCurrentGroupDepth();
|
||||||
|
|
||||||
for (let i = 0; i < this.children.length; i++) {
|
for (var i = 0; i < this.children.length; i++) {
|
||||||
const currentItem = this.children[i];
|
var currentItem = this.children[i];
|
||||||
|
|
||||||
if (currentItem instanceof ClauseGroup) {
|
if (currentItem instanceof ClauseGroup) {
|
||||||
const newDepth = (<ClauseGroup>currentItem).getTreeDepth();
|
var newDepth = (<ClauseGroup>currentItem).getTreeDepth();
|
||||||
|
|
||||||
if (newDepth > currentDepth) {
|
if (newDepth > currentDepth) {
|
||||||
currentDepth = newDepth;
|
currentDepth = newDepth;
|
||||||
@@ -311,8 +310,8 @@ export default class ClauseGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getCurrentGroupDepth(): number {
|
public getCurrentGroupDepth(): number {
|
||||||
let group = <ClauseGroup>this;
|
var group = <ClauseGroup>this;
|
||||||
let depth = 0;
|
var depth = 0;
|
||||||
|
|
||||||
while (!group.isRootGroup) {
|
while (!group.isRootGroup) {
|
||||||
depth++;
|
depth++;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import * as Constants from "../Constants";
|
|
||||||
import ClauseGroup from "./ClauseGroup";
|
import ClauseGroup from "./ClauseGroup";
|
||||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||||
|
import * as Constants from "../Constants";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View model for showing group indicators on UI, contains information such as group color and border styles.
|
* View model for showing group indicators on UI, contains information such as group color and border styles.
|
||||||
@@ -38,7 +38,7 @@ export default class ClauseGroupViewModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private getGroupBackgroundColor(group: ClauseGroup): string {
|
private getGroupBackgroundColor(group: ClauseGroup): string {
|
||||||
const colorCount = Constants.clauseGroupColors.length;
|
var colorCount = Constants.clauseGroupColors.length;
|
||||||
|
|
||||||
if (group.isRootGroup) {
|
if (group.isRootGroup) {
|
||||||
return Constants.transparentColor;
|
return Constants.transparentColor;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export default class QueryBuilderViewModel {
|
|||||||
public removeThisFilterLine = "Remove this filter line"; // localize
|
public removeThisFilterLine = "Remove this filter line"; // localize
|
||||||
public groupSelectedClauses = "Group selected clauses"; // localize
|
public groupSelectedClauses = "Group selected clauses"; // localize
|
||||||
public clauseArray = ko.observableArray<QueryClauseViewModel>(); // This is for storing the clauses in flattened form queryClauses for easier UI data binding.
|
public clauseArray = ko.observableArray<QueryClauseViewModel>(); // This is for storing the clauses in flattened form queryClauses for easier UI data binding.
|
||||||
public queryClauses = new ClauseGroup(true, undefined); // The actual data structure containing the clause information.
|
public queryClauses = new ClauseGroup(true, null); // The actual data structure containing the clause information.
|
||||||
public columnOptions: ko.ObservableArray<string>;
|
public columnOptions: ko.ObservableArray<string>;
|
||||||
public canGroupClauses = ko.observable<boolean>(false);
|
public canGroupClauses = ko.observable<boolean>(false);
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ export default class QueryBuilderViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setExample() {
|
public setExample() {
|
||||||
const example1 = new QueryClauseViewModel(
|
var example1 = new QueryClauseViewModel(
|
||||||
this,
|
this,
|
||||||
"",
|
"",
|
||||||
"PartitionKey",
|
"PartitionKey",
|
||||||
@@ -121,7 +121,7 @@ export default class QueryBuilderViewModel {
|
|||||||
//null,
|
//null,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
const example2 = new QueryClauseViewModel(
|
var example2 = new QueryClauseViewModel(
|
||||||
this,
|
this,
|
||||||
"And",
|
"And",
|
||||||
"RowKey",
|
"RowKey",
|
||||||
@@ -140,13 +140,13 @@ export default class QueryBuilderViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getODataFilterFromClauses = (): string => {
|
public getODataFilterFromClauses = (): string => {
|
||||||
let filterString = "";
|
var filterString: string = "";
|
||||||
const treeTraversal = (group: ClauseGroup): void => {
|
var treeTraversal = (group: ClauseGroup): void => {
|
||||||
for (let i = 0; i < group.children.length; i++) {
|
for (var i = 0; i < group.children.length; i++) {
|
||||||
const currentItem = group.children[i];
|
var currentItem = group.children[i];
|
||||||
|
|
||||||
if (currentItem instanceof QueryClauseViewModel) {
|
if (currentItem instanceof QueryClauseViewModel) {
|
||||||
const clause = <QueryClauseViewModel>currentItem;
|
var clause = <QueryClauseViewModel>currentItem;
|
||||||
this.timestampToValue(clause);
|
this.timestampToValue(clause);
|
||||||
filterString = filterString.concat(
|
filterString = filterString.concat(
|
||||||
this.constructODataClause(
|
this.constructODataClause(
|
||||||
@@ -173,7 +173,7 @@ export default class QueryBuilderViewModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public getSqlFilterFromClauses = (): string => {
|
public getSqlFilterFromClauses = (): string => {
|
||||||
let filterString = "SELECT * FROM c";
|
var filterString: string = "SELECT * FROM c";
|
||||||
if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) {
|
if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) {
|
||||||
filterString = "SELECT";
|
filterString = "SELECT";
|
||||||
const selectText = this._queryViewModel && this._queryViewModel.selectText && this._queryViewModel.selectText();
|
const selectText = this._queryViewModel && this._queryViewModel.selectText && this._queryViewModel.selectText();
|
||||||
@@ -199,15 +199,15 @@ export default class QueryBuilderViewModel {
|
|||||||
return filterString;
|
return filterString;
|
||||||
}
|
}
|
||||||
filterString = filterString.concat(" WHERE");
|
filterString = filterString.concat(" WHERE");
|
||||||
let first = true;
|
var first = true;
|
||||||
const treeTraversal = (group: ClauseGroup): void => {
|
var treeTraversal = (group: ClauseGroup): void => {
|
||||||
for (let i = 0; i < group.children.length; i++) {
|
for (var i = 0; i < group.children.length; i++) {
|
||||||
const currentItem = group.children[i];
|
var currentItem = group.children[i];
|
||||||
|
|
||||||
if (currentItem instanceof QueryClauseViewModel) {
|
if (currentItem instanceof QueryClauseViewModel) {
|
||||||
const clause = <QueryClauseViewModel>currentItem;
|
var clause = <QueryClauseViewModel>currentItem;
|
||||||
const timeStampValue: string = this.timestampToSqlValue(clause);
|
let timeStampValue: string = this.timestampToSqlValue(clause);
|
||||||
let value = clause.value();
|
var value = clause.value();
|
||||||
if (!clause.isValue()) {
|
if (!clause.isValue()) {
|
||||||
value = timeStampValue;
|
value = timeStampValue;
|
||||||
}
|
}
|
||||||
@@ -240,7 +240,7 @@ export default class QueryBuilderViewModel {
|
|||||||
const databaseId = this._queryViewModel.queryTablesTab.collection.databaseId;
|
const databaseId = this._queryViewModel.queryTablesTab.collection.databaseId;
|
||||||
const collectionId = this._queryViewModel.queryTablesTab.collection.id();
|
const collectionId = this._queryViewModel.queryTablesTab.collection.id();
|
||||||
const tableToQuery = `${getQuotedCqlIdentifier(databaseId)}.${getQuotedCqlIdentifier(collectionId)}`;
|
const tableToQuery = `${getQuotedCqlIdentifier(databaseId)}.${getQuotedCqlIdentifier(collectionId)}`;
|
||||||
let filterString = `SELECT * FROM ${tableToQuery}`;
|
var filterString: string = `SELECT * FROM ${tableToQuery}`;
|
||||||
if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) {
|
if (this._queryViewModel.selectText() && this._queryViewModel.selectText().length > 0) {
|
||||||
filterString = "SELECT";
|
filterString = "SELECT";
|
||||||
const selectText = this._queryViewModel && this._queryViewModel.selectText && this._queryViewModel.selectText();
|
const selectText = this._queryViewModel && this._queryViewModel.selectText && this._queryViewModel.selectText();
|
||||||
@@ -255,15 +255,15 @@ export default class QueryBuilderViewModel {
|
|||||||
return filterString;
|
return filterString;
|
||||||
}
|
}
|
||||||
filterString = filterString.concat(" WHERE");
|
filterString = filterString.concat(" WHERE");
|
||||||
let first = true;
|
var first = true;
|
||||||
const treeTraversal = (group: ClauseGroup): void => {
|
var treeTraversal = (group: ClauseGroup): void => {
|
||||||
for (let i = 0; i < group.children.length; i++) {
|
for (var i = 0; i < group.children.length; i++) {
|
||||||
const currentItem = group.children[i];
|
var currentItem = group.children[i];
|
||||||
|
|
||||||
if (currentItem instanceof QueryClauseViewModel) {
|
if (currentItem instanceof QueryClauseViewModel) {
|
||||||
const clause = <QueryClauseViewModel>currentItem;
|
var clause = <QueryClauseViewModel>currentItem;
|
||||||
const timeStampValue = this.timestampToSqlValue(clause);
|
let timeStampValue: string = this.timestampToSqlValue(clause);
|
||||||
let value = clause.value();
|
var value = clause.value();
|
||||||
if (!clause.isValue()) {
|
if (!clause.isValue()) {
|
||||||
value = timeStampValue;
|
value = timeStampValue;
|
||||||
}
|
}
|
||||||
@@ -293,13 +293,13 @@ export default class QueryBuilderViewModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public updateColumnOptions = (): void => {
|
public updateColumnOptions = (): void => {
|
||||||
// let originalHeaders = this.columnOptions();
|
let originalHeaders = this.columnOptions();
|
||||||
const newHeaders = this.tableEntityListViewModel.headers;
|
let newHeaders = this.tableEntityListViewModel.headers;
|
||||||
this.columnOptions(newHeaders.sort(DataTableUtilities.compareTableColumns));
|
this.columnOptions(newHeaders.sort(DataTableUtilities.compareTableColumns));
|
||||||
};
|
};
|
||||||
|
|
||||||
private generateLeftParentheses(clause: QueryClauseViewModel): string {
|
private generateLeftParentheses(clause: QueryClauseViewModel): string {
|
||||||
let result = "";
|
var result = "";
|
||||||
|
|
||||||
if (clause.clauseGroup.isRootGroup || clause.clauseGroup.children.indexOf(clause) !== 0) {
|
if (clause.clauseGroup.isRootGroup || clause.clauseGroup.children.indexOf(clause) !== 0) {
|
||||||
return result;
|
return result;
|
||||||
@@ -307,7 +307,7 @@ export default class QueryBuilderViewModel {
|
|||||||
result = result.concat("(");
|
result = result.concat("(");
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentGroup: ClauseGroup = clause.clauseGroup;
|
var currentGroup: ClauseGroup = clause.clauseGroup;
|
||||||
|
|
||||||
while (
|
while (
|
||||||
!currentGroup.isRootGroup &&
|
!currentGroup.isRootGroup &&
|
||||||
@@ -322,7 +322,7 @@ export default class QueryBuilderViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private generateRightParentheses(clause: QueryClauseViewModel): string {
|
private generateRightParentheses(clause: QueryClauseViewModel): string {
|
||||||
let result = "";
|
var result = "";
|
||||||
|
|
||||||
if (
|
if (
|
||||||
clause.clauseGroup.isRootGroup ||
|
clause.clauseGroup.isRootGroup ||
|
||||||
@@ -333,7 +333,7 @@ export default class QueryBuilderViewModel {
|
|||||||
result = result.concat(")");
|
result = result.concat(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentGroup: ClauseGroup = clause.clauseGroup;
|
var currentGroup: ClauseGroup = clause.clauseGroup;
|
||||||
|
|
||||||
while (
|
while (
|
||||||
!currentGroup.isRootGroup &&
|
!currentGroup.isRootGroup &&
|
||||||
@@ -364,17 +364,14 @@ export default class QueryBuilderViewModel {
|
|||||||
case Constants.TableType.String:
|
case Constants.TableType.String:
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
||||||
operator
|
operator
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
)} \'${value}\'${rightParentheses}`;
|
)} \'${value}\'${rightParentheses}`;
|
||||||
case Constants.TableType.Guid:
|
case Constants.TableType.Guid:
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
||||||
operator
|
operator
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
)} guid\'${value}\'${rightParentheses}`;
|
)} guid\'${value}\'${rightParentheses}`;
|
||||||
case Constants.TableType.Binary:
|
case Constants.TableType.Binary:
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
||||||
operator
|
operator
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
)} binary\'${value}\'${rightParentheses}`;
|
)} binary\'${value}\'${rightParentheses}`;
|
||||||
default:
|
default:
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}${propertyName} ${this.operatorConverter(
|
||||||
@@ -394,11 +391,9 @@ export default class QueryBuilderViewModel {
|
|||||||
): string => {
|
): string => {
|
||||||
if (propertyName === Constants.EntityKeyNames.PartitionKey) {
|
if (propertyName === Constants.EntityKeyNames.PartitionKey) {
|
||||||
propertyName = TableEntityProcessor.keyProperties.PartitionKey;
|
propertyName = TableEntityProcessor.keyProperties.PartitionKey;
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c["${propertyName}"] ${operator} \'${value}\'${rightParentheses}`;
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c["${propertyName}"] ${operator} \'${value}\'${rightParentheses}`;
|
||||||
} else if (propertyName === Constants.EntityKeyNames.RowKey) {
|
} else if (propertyName === Constants.EntityKeyNames.RowKey) {
|
||||||
propertyName = TableEntityProcessor.keyProperties.Id;
|
propertyName = TableEntityProcessor.keyProperties.Id;
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName} ${operator} \'${value}\'${rightParentheses}`;
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName} ${operator} \'${value}\'${rightParentheses}`;
|
||||||
} else if (propertyName === Constants.EntityKeyNames.Timestamp) {
|
} else if (propertyName === Constants.EntityKeyNames.Timestamp) {
|
||||||
propertyName = TableEntityProcessor.keyProperties.Timestamp;
|
propertyName = TableEntityProcessor.keyProperties.Timestamp;
|
||||||
@@ -408,21 +403,16 @@ export default class QueryBuilderViewModel {
|
|||||||
}
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Constants.TableType.DateTime:
|
case Constants.TableType.DateTime:
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${DateTimeUtilities.convertJSDateToTicksWithPadding(
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${DateTimeUtilities.convertJSDateToTicksWithPadding(
|
||||||
value
|
value
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
)}\'${rightParentheses}`;
|
)}\'${rightParentheses}`;
|
||||||
case Constants.TableType.Int64:
|
case Constants.TableType.Int64:
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${Utilities.padLongWithZeros(
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${Utilities.padLongWithZeros(
|
||||||
value
|
value
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
)}\'${rightParentheses}`;
|
)}\'${rightParentheses}`;
|
||||||
case Constants.TableType.String:
|
case Constants.TableType.String:
|
||||||
case Constants.TableType.Guid:
|
case Constants.TableType.Guid:
|
||||||
case Constants.TableType.Binary:
|
case Constants.TableType.Binary:
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${value}\'${rightParentheses}`;
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} \'${value}\'${rightParentheses}`;
|
||||||
default:
|
default:
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} ${value}${rightParentheses}`;
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses}c.${propertyName}["$v"] ${operator} ${value}${rightParentheses}`;
|
||||||
@@ -444,7 +434,6 @@ export default class QueryBuilderViewModel {
|
|||||||
type === Constants.CassandraType.Ascii ||
|
type === Constants.CassandraType.Ascii ||
|
||||||
type === Constants.CassandraType.Varchar
|
type === Constants.CassandraType.Varchar
|
||||||
) {
|
) {
|
||||||
// eslint-disable-next-line no-useless-escape
|
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses} ${propertyName} ${operator} \'${value}\'${rightParentheses}`;
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses} ${propertyName} ${operator} \'${value}\'${rightParentheses}`;
|
||||||
}
|
}
|
||||||
return ` ${clauseRule.toLowerCase()} ${leftParentheses} ${propertyName} ${operator} ${value}${rightParentheses}`;
|
return ` ${clauseRule.toLowerCase()} ${leftParentheses} ${propertyName} ${operator} ${value}${rightParentheses}`;
|
||||||
@@ -465,7 +454,7 @@ export default class QueryBuilderViewModel {
|
|||||||
case Constants.Operator.NotEqualTo:
|
case Constants.Operator.NotEqualTo:
|
||||||
return Constants.ODataOperator.NotEqualTo;
|
return Constants.ODataOperator.NotEqualTo;
|
||||||
}
|
}
|
||||||
return undefined;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
public groupClauses = (): void => {
|
public groupClauses = (): void => {
|
||||||
@@ -474,11 +463,11 @@ export default class QueryBuilderViewModel {
|
|||||||
this.updateCanGroupClauses();
|
this.updateCanGroupClauses();
|
||||||
};
|
};
|
||||||
|
|
||||||
public addClauseIndex = (index: number): void => {
|
public addClauseIndex = (index: number, data: any): void => {
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
const newClause = new QueryClauseViewModel(
|
var newClause = new QueryClauseViewModel(
|
||||||
this,
|
this,
|
||||||
"And",
|
"And",
|
||||||
"",
|
"",
|
||||||
@@ -503,28 +492,28 @@ export default class QueryBuilderViewModel {
|
|||||||
|
|
||||||
// adds a new clause to the end of the array
|
// adds a new clause to the end of the array
|
||||||
public addNewClause = (): void => {
|
public addNewClause = (): void => {
|
||||||
this.addClauseIndex(this.clauseArray().length);
|
this.addClauseIndex(this.clauseArray().length, null);
|
||||||
};
|
};
|
||||||
|
|
||||||
public onAddClauseKeyDown = (index: number, event: KeyboardEvent): boolean => {
|
public onAddClauseKeyDown = (index: number, data: any, event: KeyboardEvent, source: any): boolean => {
|
||||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||||
this.addClauseIndex(index);
|
this.addClauseIndex(index, data);
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
public onAddNewClauseKeyDown = (event: KeyboardEvent): boolean => {
|
public onAddNewClauseKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||||
this.addClauseIndex(this.clauseArray().length - 1);
|
this.addClauseIndex(this.clauseArray().length - 1, null);
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
public deleteClause = (index: number): void => {
|
public deleteClause = (index: number, data: any): void => {
|
||||||
this.deleteClauseImpl(index);
|
this.deleteClauseImpl(index);
|
||||||
if (this.clauseArray().length !== 0) {
|
if (this.clauseArray().length !== 0) {
|
||||||
this.clauseArray()[0].and_or("");
|
this.clauseArray()[0].and_or("");
|
||||||
@@ -534,9 +523,9 @@ export default class QueryBuilderViewModel {
|
|||||||
$(window).resize();
|
$(window).resize();
|
||||||
};
|
};
|
||||||
|
|
||||||
public onDeleteClauseKeyDown = (index: number, event: KeyboardEvent): boolean => {
|
public onDeleteClauseKeyDown = (index: number, data: any, event: KeyboardEvent, source: any): boolean => {
|
||||||
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||||
this.deleteClause(index);
|
this.deleteClause(index, data);
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -550,26 +539,25 @@ export default class QueryBuilderViewModel {
|
|||||||
* (transparent) or its parent group view models.
|
* (transparent) or its parent group view models.
|
||||||
*/
|
*/
|
||||||
public getClauseGroupViewModels = (clause: QueryClauseViewModel): ClauseGroupViewModel[] => {
|
public getClauseGroupViewModels = (clause: QueryClauseViewModel): ClauseGroupViewModel[] => {
|
||||||
const placeHolderGroupViewModel = new ClauseGroupViewModel(this.queryClauses, false, this);
|
var placeHolderGroupViewModel = new ClauseGroupViewModel(this.queryClauses, false, this);
|
||||||
const treeDepth = this.queryClauses.getTreeDepth();
|
var treeDepth = this.queryClauses.getTreeDepth();
|
||||||
const groupViewModels = new Array<ClauseGroupViewModel>(treeDepth);
|
var groupViewModels = new Array<ClauseGroupViewModel>(treeDepth);
|
||||||
|
|
||||||
// Prefill the arry with placeholders.
|
// Prefill the arry with placeholders.
|
||||||
for (let i = 0; i < groupViewModels.length; i++) {
|
for (var i = 0; i < groupViewModels.length; i++) {
|
||||||
groupViewModels[i] = placeHolderGroupViewModel;
|
groupViewModels[i] = placeHolderGroupViewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
let currentGroup = clause.clauseGroup;
|
var currentGroup = clause.clauseGroup;
|
||||||
|
|
||||||
// This function determines whether the path from clause to the current group is on the left most.
|
// This function determines whether the path from clause to the current group is on the left most.
|
||||||
const isLeftMostPath = (): boolean => {
|
var isLeftMostPath = (): boolean => {
|
||||||
let group = clause.clauseGroup;
|
var group = clause.clauseGroup;
|
||||||
|
|
||||||
if (group.children.indexOf(clause) !== 0) {
|
if (group.children.indexOf(clause) !== 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (group.getId() === currentGroup.getId()) {
|
if (group.getId() === currentGroup.getId()) {
|
||||||
break;
|
break;
|
||||||
@@ -585,14 +573,13 @@ export default class QueryBuilderViewModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// This function determines whether the path from clause to the current group is on the right most.
|
// This function determines whether the path from clause to the current group is on the right most.
|
||||||
const isRightMostPath = (): boolean => {
|
var isRightMostPath = (): boolean => {
|
||||||
let group = clause.clauseGroup;
|
var group = clause.clauseGroup;
|
||||||
|
|
||||||
if (group.children.indexOf(clause) !== group.children.length - 1) {
|
if (group.children.indexOf(clause) !== group.children.length - 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (group.getId() === currentGroup.getId()) {
|
if (group.getId() === currentGroup.getId()) {
|
||||||
break;
|
break;
|
||||||
@@ -607,26 +594,26 @@ export default class QueryBuilderViewModel {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
let vmIndex = groupViewModels.length - 1;
|
var vmIndex = groupViewModels.length - 1;
|
||||||
let skipIndex = -1;
|
var skipIndex = -1;
|
||||||
let lastDepth = clause.groupDepth;
|
var lastDepth = clause.groupDepth;
|
||||||
|
|
||||||
while (!currentGroup.isRootGroup) {
|
while (!currentGroup.isRootGroup) {
|
||||||
// The current group will be rendered at least once, and if there are any sibling groups deeper
|
// The current group will be rendered at least once, and if there are any sibling groups deeper
|
||||||
// than the current group, we will repeat rendering the current group to fill up the gap between
|
// than the current group, we will repeat rendering the current group to fill up the gap between
|
||||||
// current & deepest sibling.
|
// current & deepest sibling.
|
||||||
const deepestInSiblings = currentGroup.findDeepestGroupInChildren(skipIndex).getCurrentGroupDepth();
|
var deepestInSiblings = currentGroup.findDeepestGroupInChildren(skipIndex).getCurrentGroupDepth();
|
||||||
// Find out the depth difference between the deepest group under the siblings of currentGroup and
|
// Find out the depth difference between the deepest group under the siblings of currentGroup and
|
||||||
// the deepest group under currentGroup. If the result n is a positive number, it means there are
|
// the deepest group under currentGroup. If the result n is a positive number, it means there are
|
||||||
// deeper groups in siblings and we need to draw n + 1 group blocks on UI to fill up the depth
|
// deeper groups in siblings and we need to draw n + 1 group blocks on UI to fill up the depth
|
||||||
// differences. If the result n is a negative number, it means current group contains the deepest
|
// differences. If the result n is a negative number, it means current group contains the deepest
|
||||||
// sub-group, we only need to draw the group block once.
|
// sub-group, we only need to draw the group block once.
|
||||||
const repeatCount = Math.max(deepestInSiblings - lastDepth, 0);
|
var repeatCount = Math.max(deepestInSiblings - lastDepth, 0);
|
||||||
|
|
||||||
for (let i = 0; i <= repeatCount; i++) {
|
for (var i = 0; i <= repeatCount; i++) {
|
||||||
const isLeftMost = isLeftMostPath();
|
var isLeftMost = isLeftMostPath();
|
||||||
const isRightMost = isRightMostPath();
|
var isRightMost = isRightMostPath();
|
||||||
const groupViewModel = new ClauseGroupViewModel(currentGroup, i === 0 && isLeftMost, this);
|
var groupViewModel = new ClauseGroupViewModel(currentGroup, i === 0 && isLeftMost, this);
|
||||||
|
|
||||||
groupViewModel.showTopBorder(isLeftMost);
|
groupViewModel.showTopBorder(isLeftMost);
|
||||||
groupViewModel.showBottomBorder(isRightMost);
|
groupViewModel.showBottomBorder(isRightMost);
|
||||||
@@ -648,9 +635,9 @@ export default class QueryBuilderViewModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public addCustomRange(timestamp: CustomTimestampHelper.ITimestampQuery, clauseToAdd: QueryClauseViewModel): void {
|
public addCustomRange(timestamp: CustomTimestampHelper.ITimestampQuery, clauseToAdd: QueryClauseViewModel): void {
|
||||||
const index = this.clauseArray.peek().indexOf(clauseToAdd);
|
var index = this.clauseArray.peek().indexOf(clauseToAdd);
|
||||||
|
|
||||||
const newClause = new QueryClauseViewModel(
|
var newClause = new QueryClauseViewModel(
|
||||||
this,
|
this,
|
||||||
//this._tableEntityListViewModel.tableExplorerContext.hostProxy,
|
//this._tableEntityListViewModel.tableExplorerContext.hostProxy,
|
||||||
"And",
|
"And",
|
||||||
@@ -675,10 +662,10 @@ export default class QueryBuilderViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private scrollToBottom(): void {
|
private scrollToBottom(): void {
|
||||||
const scrollBox = document.getElementById("scroll");
|
var scrollBox = document.getElementById("scroll");
|
||||||
if (!this.scrollEventListener) {
|
if (!this.scrollEventListener) {
|
||||||
scrollBox.addEventListener("scroll", function () {
|
scrollBox.addEventListener("scroll", function () {
|
||||||
const translate = "translate(0," + this.scrollTop + "px)";
|
var translate = "translate(0," + this.scrollTop + "px)";
|
||||||
const allTh = <NodeListOf<HTMLElement>>this.querySelectorAll("thead td");
|
const allTh = <NodeListOf<HTMLElement>>this.querySelectorAll("thead td");
|
||||||
for (let i = 0; i < allTh.length; i++) {
|
for (let i = 0; i < allTh.length; i++) {
|
||||||
allTh[i].style.transform = translate;
|
allTh[i].style.transform = translate;
|
||||||
@@ -686,7 +673,7 @@ export default class QueryBuilderViewModel {
|
|||||||
});
|
});
|
||||||
this.scrollEventListener = true;
|
this.scrollEventListener = true;
|
||||||
}
|
}
|
||||||
const isScrolledToBottom = scrollBox.scrollHeight - scrollBox.clientHeight <= scrollBox.scrollHeight + 1;
|
var isScrolledToBottom = scrollBox.scrollHeight - scrollBox.clientHeight <= scrollBox.scrollHeight + 1;
|
||||||
if (isScrolledToBottom) {
|
if (isScrolledToBottom) {
|
||||||
scrollBox.scrollTop = scrollBox.scrollHeight - scrollBox.clientHeight;
|
scrollBox.scrollTop = scrollBox.scrollHeight - scrollBox.clientHeight;
|
||||||
}
|
}
|
||||||
@@ -698,8 +685,8 @@ export default class QueryBuilderViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private deleteClauseImpl(index: number): void {
|
private deleteClauseImpl(index: number): void {
|
||||||
const clause = this.clauseArray()[index];
|
var clause = this.clauseArray()[index];
|
||||||
const previousClause = index === 0 ? 0 : index - 1;
|
var previousClause = index === 0 ? 0 : index - 1;
|
||||||
this.queryClauses.deleteClause(clause);
|
this.queryClauses.deleteClause(clause);
|
||||||
this.updateClauseArray();
|
this.updateClauseArray();
|
||||||
if (this.clauseArray()[previousClause]) {
|
if (this.clauseArray()[previousClause]) {
|
||||||
@@ -744,7 +731,7 @@ export default class QueryBuilderViewModel {
|
|||||||
|
|
||||||
private timestampToSqlValue(clause: QueryClauseViewModel): string {
|
private timestampToSqlValue(clause: QueryClauseViewModel): string {
|
||||||
if (clause.isValue()) {
|
if (clause.isValue()) {
|
||||||
return undefined;
|
return null;
|
||||||
} else if (clause.isTimestamp()) {
|
} else if (clause.isTimestamp()) {
|
||||||
return this.getTimeStampToSqlQuery(clause);
|
return this.getTimeStampToSqlQuery(clause);
|
||||||
// } else if (clause.isCustomLastTimestamp()) {
|
// } else if (clause.isCustomLastTimestamp()) {
|
||||||
@@ -756,7 +743,7 @@ export default class QueryBuilderViewModel {
|
|||||||
return clause.customTimeValue();
|
return clause.customTimeValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getTimeStampToQuery(clause: QueryClauseViewModel): void {
|
private getTimeStampToQuery(clause: QueryClauseViewModel): void {
|
||||||
@@ -802,7 +789,7 @@ export default class QueryBuilderViewModel {
|
|||||||
case Constants.timeOptions.currentYear:
|
case Constants.timeOptions.currentYear:
|
||||||
return CustomTimestampHelper._queryCurrentYearLocal();
|
return CustomTimestampHelper._queryCurrentYearLocal();
|
||||||
}
|
}
|
||||||
return undefined;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public checkIfClauseChanged(): void {
|
public checkIfClauseChanged(): void {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default class QueryClauseViewModel {
|
|||||||
public field: ko.Observable<string>;
|
public field: ko.Observable<string>;
|
||||||
public type: ko.Observable<string>;
|
public type: ko.Observable<string>;
|
||||||
public operator: ko.Observable<string>;
|
public operator: ko.Observable<string>;
|
||||||
public value: ko.Observable<string>;
|
public value: ko.Observable<any>;
|
||||||
public timeValue: ko.Observable<string>;
|
public timeValue: ko.Observable<string>;
|
||||||
public customTimeValue: ko.Observable<string>;
|
public customTimeValue: ko.Observable<string>;
|
||||||
public canAnd: ko.Observable<boolean>;
|
public canAnd: ko.Observable<boolean>;
|
||||||
@@ -39,7 +39,7 @@ export default class QueryClauseViewModel {
|
|||||||
field: string,
|
field: string,
|
||||||
type: string,
|
type: string,
|
||||||
operator: string,
|
operator: string,
|
||||||
value: string,
|
value: any,
|
||||||
canAnd: boolean,
|
canAnd: boolean,
|
||||||
timeValue: string,
|
timeValue: string,
|
||||||
customTimeValue: string,
|
customTimeValue: string,
|
||||||
@@ -88,30 +88,30 @@ export default class QueryClauseViewModel {
|
|||||||
userContext.apiType !== "Cassandra"
|
userContext.apiType !== "Cassandra"
|
||||||
);
|
);
|
||||||
|
|
||||||
this.and_or.subscribe(() => {
|
this.and_or.subscribe((value) => {
|
||||||
this._queryBuilderViewModel.checkIfClauseChanged();
|
this._queryBuilderViewModel.checkIfClauseChanged();
|
||||||
});
|
});
|
||||||
this.field.subscribe(() => {
|
this.field.subscribe((value) => {
|
||||||
this.changeField();
|
this.changeField();
|
||||||
});
|
});
|
||||||
this.type.subscribe(() => {
|
this.type.subscribe((value) => {
|
||||||
this.changeType();
|
this.changeType();
|
||||||
});
|
});
|
||||||
this.timeValue.subscribe(() => {
|
this.timeValue.subscribe((value) => {
|
||||||
// if (this.timeValue() === QueryBuilderConstants.timeOptions.custom) {
|
// if (this.timeValue() === QueryBuilderConstants.timeOptions.custom) {
|
||||||
// this.customTimestampDialog();
|
// this.customTimestampDialog();
|
||||||
// }
|
// }
|
||||||
});
|
});
|
||||||
this.customTimeValue.subscribe(() => {
|
this.customTimeValue.subscribe((value) => {
|
||||||
this._queryBuilderViewModel.checkIfClauseChanged();
|
this._queryBuilderViewModel.checkIfClauseChanged();
|
||||||
});
|
});
|
||||||
this.value.subscribe(() => {
|
this.value.subscribe((value) => {
|
||||||
this._queryBuilderViewModel.checkIfClauseChanged();
|
this._queryBuilderViewModel.checkIfClauseChanged();
|
||||||
});
|
});
|
||||||
this.operator.subscribe(() => {
|
this.operator.subscribe((value) => {
|
||||||
this._queryBuilderViewModel.checkIfClauseChanged();
|
this._queryBuilderViewModel.checkIfClauseChanged();
|
||||||
});
|
});
|
||||||
this._groupCheckSubscription = this.checkedForGrouping.subscribe(() => {
|
this._groupCheckSubscription = this.checkedForGrouping.subscribe((value) => {
|
||||||
this._queryBuilderViewModel.updateCanGroupClauses();
|
this._queryBuilderViewModel.updateCanGroupClauses();
|
||||||
});
|
});
|
||||||
this.isAndOrFocused = ko.observable<boolean>(false);
|
this.isAndOrFocused = ko.observable<boolean>(false);
|
||||||
@@ -280,7 +280,7 @@ export default class QueryClauseViewModel {
|
|||||||
this._groupCheckSubscription.dispose();
|
this._groupCheckSubscription.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clauseGroup = undefined;
|
this.clauseGroup = null;
|
||||||
this._queryBuilderViewModel = undefined;
|
this._queryBuilderViewModel = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export default class NotebookTabV2 extends NotebookTabBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public onCloseTabButtonClick(): Q.Promise<void> {
|
public onCloseTabButtonClick(): Q.Promise<any> {
|
||||||
const cleanup = () => {
|
const cleanup = () => {
|
||||||
this.notebookComponentAdapter.notebookShutdown();
|
this.notebookComponentAdapter.notebookShutdown();
|
||||||
super.onCloseTabButtonClick();
|
super.onCloseTabButtonClick();
|
||||||
@@ -78,7 +78,7 @@ export default class NotebookTabV2 extends NotebookTabBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async reconfigureServiceEndpoints(): Promise<void> {
|
public async reconfigureServiceEndpoints() {
|
||||||
if (!this.notebookComponentAdapter) {
|
if (!this.notebookComponentAdapter) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ export default class NotebookTabV2 extends NotebookTabBase {
|
|||||||
const saveButtonChildren = [];
|
const saveButtonChildren = [];
|
||||||
if (this.container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
if (this.container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
||||||
saveButtonChildren.push({
|
saveButtonChildren.push({
|
||||||
iconName: copyToLabel,
|
iconName: "Copy",
|
||||||
onCommandClick: () => this.copyNotebook(),
|
onCommandClick: () => this.copyNotebook(),
|
||||||
commandButtonLabel: copyToLabel,
|
commandButtonLabel: copyToLabel,
|
||||||
hasPopup: false,
|
hasPopup: false,
|
||||||
@@ -136,7 +136,7 @@ export default class NotebookTabV2 extends NotebookTabBase {
|
|||||||
ariaLabel: publishLabel,
|
ariaLabel: publishLabel,
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttons: CommandButtonComponentProps[] = [
|
let buttons: CommandButtonComponentProps[] = [
|
||||||
{
|
{
|
||||||
iconSrc: SaveIcon,
|
iconSrc: SaveIcon,
|
||||||
iconAlt: saveLabel,
|
iconAlt: saveLabel,
|
||||||
@@ -160,7 +160,7 @@ export default class NotebookTabV2 extends NotebookTabBase {
|
|||||||
{
|
{
|
||||||
iconSrc: null,
|
iconSrc: null,
|
||||||
iconAlt: kernelLabel,
|
iconAlt: kernelLabel,
|
||||||
onCommandClick: () => undefined,
|
onCommandClick: () => {},
|
||||||
commandButtonLabel: null,
|
commandButtonLabel: null,
|
||||||
hasPopup: false,
|
hasPopup: false,
|
||||||
disabled: availableKernels.length < 1,
|
disabled: availableKernels.length < 1,
|
||||||
@@ -271,7 +271,7 @@ export default class NotebookTabV2 extends NotebookTabBase {
|
|||||||
{
|
{
|
||||||
iconSrc: null,
|
iconSrc: null,
|
||||||
iconAlt: null,
|
iconAlt: null,
|
||||||
onCommandClick: () => undefined,
|
onCommandClick: () => {},
|
||||||
commandButtonLabel: null,
|
commandButtonLabel: null,
|
||||||
ariaLabel: cellTypeLabel,
|
ariaLabel: cellTypeLabel,
|
||||||
hasPopup: false,
|
hasPopup: false,
|
||||||
@@ -361,7 +361,7 @@ export default class NotebookTabV2 extends NotebookTabBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onKernelUpdate = async () => {
|
private onKernelUpdate = async () => {
|
||||||
await this.configureServiceEndpoints(this.notebookComponentAdapter.getCurrentKernelName()).catch(() => {
|
await this.configureServiceEndpoints(this.notebookComponentAdapter.getCurrentKernelName()).catch((reason) => {
|
||||||
/* Erroring is ok here */
|
/* Erroring is ok here */
|
||||||
});
|
});
|
||||||
this.updateNavbarWithTabsButtons();
|
this.updateNavbarWithTabsButtons();
|
||||||
|
|||||||
@@ -966,10 +966,15 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
|||||||
<>
|
<>
|
||||||
<span className="queryResultDivider">|</span>
|
<span className="queryResultDivider">|</span>
|
||||||
<span className="queryResultNextEnable">
|
<span className="queryResultNextEnable">
|
||||||
<a onClick={this.onFetchNextPageClick.bind(this)}>
|
<div
|
||||||
<span>Load more</span>
|
onClick={this.onFetchNextPageClick.bind(this)}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onKeyPress={this.onFetchNextPageClick.bind(this)}
|
||||||
|
>
|
||||||
|
<span className="moreOption">Load more</span>
|
||||||
<img className="queryResultnextImg" src={QueryEditorNext} alt="Fetch next page" />
|
<img className="queryResultnextImg" src={QueryEditorNext} alt="Fetch next page" />
|
||||||
</a>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -1015,7 +1020,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
|||||||
</div>
|
</div>
|
||||||
{this.state.isQueryMetricsEnabled && (
|
{this.state.isQueryMetricsEnabled && (
|
||||||
<div className="downloadMetricsLinkContainer">
|
<div className="downloadMetricsLinkContainer">
|
||||||
<a
|
<span
|
||||||
id="downloadMetricsLink"
|
id="downloadMetricsLink"
|
||||||
role="button"
|
role="button"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
@@ -1030,7 +1035,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
|||||||
alt="download query metrics csv"
|
alt="download query metrics csv"
|
||||||
/>
|
/>
|
||||||
<span>Per-partition query metrics (CSV)</span>
|
<span>Per-partition query metrics (CSV)</span>
|
||||||
</a>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -1044,7 +1049,7 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
|||||||
<div className="errorContent">
|
<div className="errorContent">
|
||||||
<span className="errorMessage">{this.state.error}</span>
|
<span className="errorMessage">{this.state.error}</span>
|
||||||
<span className="errorDetailsLink">
|
<span className="errorDetailsLink">
|
||||||
<a
|
<span
|
||||||
onClick={() => this.onErrorDetailsClick()}
|
onClick={() => this.onErrorDetailsClick()}
|
||||||
onKeyPress={(event: React.KeyboardEvent<HTMLAnchorElement>) =>
|
onKeyPress={(event: React.KeyboardEvent<HTMLAnchorElement>) =>
|
||||||
this.onErrorDetailsKeyPress(event)
|
this.onErrorDetailsKeyPress(event)
|
||||||
@@ -1052,9 +1057,11 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
|||||||
id="error-display"
|
id="error-display"
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
aria-label="Error details link"
|
aria-label="Error details link"
|
||||||
|
role="button"
|
||||||
|
className="moreOption"
|
||||||
>
|
>
|
||||||
More details
|
More details
|
||||||
</a>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,12 +25,11 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode
|
|||||||
public errors: ko.ObservableArray<ViewModels.QueryError>;
|
public errors: ko.ObservableArray<ViewModels.QueryError>;
|
||||||
public statusMessge: ko.Observable<string>;
|
public statusMessge: ko.Observable<string>;
|
||||||
public statusIcon: ko.Observable<string>;
|
public statusIcon: ko.Observable<string>;
|
||||||
public formFields: ko.ObservableArray<ViewModels.Editable<unknown>>;
|
public formFields: ko.ObservableArray<ViewModels.Editable<any>>;
|
||||||
public formIsValid: ko.Computed<boolean>;
|
public formIsValid: ko.Computed<boolean>;
|
||||||
public formIsDirty: ko.Computed<boolean>;
|
public formIsDirty: ko.Computed<boolean>;
|
||||||
public isNew: ko.Observable<boolean>;
|
public isNew: ko.Observable<boolean>;
|
||||||
// TODO: Remove any. The SDK types for all the script.body are slightly incorrect which makes this REALLY hard to type correct.
|
// TODO: Remove any. The SDK types for all the script.body are slightly incorrect which makes this REALLY hard to type correct.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
public resource: ko.Observable<any>;
|
public resource: ko.Observable<any>;
|
||||||
public isTemplateReady: ko.Observable<boolean>;
|
public isTemplateReady: ko.Observable<boolean>;
|
||||||
protected _partitionKey: DataModels.PartitionKey;
|
protected _partitionKey: DataModels.PartitionKey;
|
||||||
@@ -86,6 +85,7 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode
|
|||||||
this.editorState(ViewModels.ScriptEditorState.exisitingDirtyInvalid);
|
this.editorState(ViewModels.ScriptEditorState.exisitingDirtyInvalid);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ViewModels.ScriptEditorState.exisitingDirtyValid:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode
|
|||||||
this.editorContent.setBaseline(resource.body);
|
this.editorContent.setBaseline(resource.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setBaselines(): void {
|
public setBaselines() {
|
||||||
this._setBaselines();
|
this._setBaselines();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,9 +194,9 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract onSaveClick: () => void;
|
public abstract onSaveClick: () => void;
|
||||||
public abstract onUpdateClick: () => Promise<void>;
|
public abstract onUpdateClick: () => Promise<any>;
|
||||||
|
|
||||||
public onDiscard = (): Q.Promise<void> => {
|
public onDiscard = (): Q.Promise<any> => {
|
||||||
this.setBaselines();
|
this.setBaselines();
|
||||||
const original = this.editorContent.getEditableOriginalValue();
|
const original = this.editorContent.getEditableOriginalValue();
|
||||||
const editorModel = this.editor() && this.editor().getModel();
|
const editorModel = this.editor() && this.editor().getModel();
|
||||||
@@ -289,7 +289,7 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode
|
|||||||
return !!value;
|
return !!value;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async _createBodyEditor(): Promise<void> {
|
protected async _createBodyEditor() {
|
||||||
const id = this.editorId;
|
const id = this.editorId;
|
||||||
const container = document.getElementById(id);
|
const container = document.getElementById(id);
|
||||||
const options = {
|
const options = {
|
||||||
@@ -308,7 +308,7 @@ export default abstract class ScriptTabBase extends TabsBase implements ViewMode
|
|||||||
editorModel.onDidChangeContent(this._onBodyContentChange.bind(this));
|
editorModel.onDidChangeContent(this._onBodyContentChange.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _onBodyContentChange() {
|
private _onBodyContentChange(e: monaco.editor.IModelContentChangedEvent) {
|
||||||
const editorModel = this.editor().getModel();
|
const editorModel = this.editor().getModel();
|
||||||
this.editorContent(editorModel.getValue());
|
this.editorContent(editorModel.getValue());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -579,13 +579,16 @@ export default class StoredProcedureTabComponent extends React.Component<
|
|||||||
<div className="errorContent">
|
<div className="errorContent">
|
||||||
<span className="errorMessage">{this.state.error}</span>
|
<span className="errorMessage">{this.state.error}</span>
|
||||||
<span className="errorDetailsLink">
|
<span className="errorDetailsLink">
|
||||||
<a
|
<span
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
className="moreOption"
|
||||||
aria-label="Error details link"
|
aria-label="Error details link"
|
||||||
onClick={() => this.onErrorDetailsClick()}
|
onClick={() => this.onErrorDetailsClick()}
|
||||||
onKeyPress={(event: React.KeyboardEvent<HTMLAnchorElement>) => this.onErrorDetailsKeyPress(event)}
|
onKeyPress={(event: React.KeyboardEvent<HTMLAnchorElement>) => this.onErrorDetailsKeyPress(event)}
|
||||||
>
|
>
|
||||||
More details
|
More details
|
||||||
</a>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
role="tab"
|
role="tab"
|
||||||
ref={focusTab}
|
ref={focusTab}
|
||||||
|
onFocus={() => setHovering(true)}
|
||||||
>
|
>
|
||||||
<span className="tabNavContentContainer">
|
<span className="tabNavContentContainer">
|
||||||
<a data-toggle="tab" href={"#" + tab.tabId} tabIndex={-1}>
|
<a data-toggle="tab" href={"#" + tab.tabId} tabIndex={-1}>
|
||||||
|
|||||||
@@ -295,8 +295,6 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
|
|||||||
className="trigger-field"
|
className="trigger-field"
|
||||||
label="Trigger Id"
|
label="Trigger Id"
|
||||||
id="entityTimeId"
|
id="entityTimeId"
|
||||||
autoFocus
|
|
||||||
required
|
|
||||||
type="text"
|
type="text"
|
||||||
pattern="[^/?#\\]*[^/?# \\]"
|
pattern="[^/?#\\]*[^/?# \\]"
|
||||||
placeholder="Enter the new trigger id"
|
placeholder="Enter the new trigger id"
|
||||||
|
|||||||
@@ -276,7 +276,6 @@ export default class UserDefinedFunctionTabContent extends Component<
|
|||||||
className="trigger-field"
|
className="trigger-field"
|
||||||
label="User Defined Function Id"
|
label="User Defined Function Id"
|
||||||
id="entityTimeId"
|
id="entityTimeId"
|
||||||
autoFocus
|
|
||||||
required
|
required
|
||||||
readOnly={!isUdfIdEditable}
|
readOnly={!isUdfIdEditable}
|
||||||
type="text"
|
type="text"
|
||||||
|
|||||||
@@ -128,12 +128,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
notebooksTree.children.push(buildGalleryNotebooksTree());
|
notebooksTree.children.push(buildGalleryNotebooksTree());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (myNotebooksContentRoot && useNotebook.getState().connectionInfo.status == ConnectionStatusType.Connected) {
|
||||||
myNotebooksContentRoot &&
|
|
||||||
((NotebookUtil.isPhoenixEnabled() &&
|
|
||||||
useNotebook.getState().connectionInfo.status === ConnectionStatusType.Connected) ||
|
|
||||||
userContext.features.phoenix === false)
|
|
||||||
) {
|
|
||||||
notebooksTree.children.push(buildMyNotebooksTree());
|
notebooksTree.children.push(buildMyNotebooksTree());
|
||||||
}
|
}
|
||||||
if (container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
if (container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
||||||
@@ -167,11 +162,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
myNotebooksContentRoot,
|
myNotebooksContentRoot,
|
||||||
(item: NotebookContentItem) => {
|
(item: NotebookContentItem) => {
|
||||||
container.openNotebook(item).then((hasOpened) => {
|
container.openNotebook(item).then((hasOpened) => {
|
||||||
if (
|
if (hasOpened) {
|
||||||
hasOpened &&
|
|
||||||
userContext.features.notebooksTemporarilyDown === false &&
|
|
||||||
userContext.features.phoenix === false
|
|
||||||
) {
|
|
||||||
mostRecentActivity.notebookWasItemOpened(userContext.databaseAccount?.id, item);
|
mostRecentActivity.notebookWasItemOpened(userContext.databaseAccount?.id, item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -190,11 +181,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
gitHubNotebooksContentRoot,
|
gitHubNotebooksContentRoot,
|
||||||
(item: NotebookContentItem) => {
|
(item: NotebookContentItem) => {
|
||||||
container.openNotebook(item).then((hasOpened) => {
|
container.openNotebook(item).then((hasOpened) => {
|
||||||
if (
|
if (hasOpened) {
|
||||||
hasOpened &&
|
|
||||||
userContext.features.notebooksTemporarilyDown === false &&
|
|
||||||
userContext.features.phoenix === false
|
|
||||||
) {
|
|
||||||
mostRecentActivity.notebookWasItemOpened(userContext.databaseAccount?.id, item);
|
mostRecentActivity.notebookWasItemOpened(userContext.databaseAccount?.id, item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -226,7 +213,23 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
gitHubNotebooksTree.contextMenu = manageGitContextMenu;
|
const connectGitContextMenu: TreeNodeMenuItem[] = [
|
||||||
|
{
|
||||||
|
label: "Connect to GitHub",
|
||||||
|
onClick: () =>
|
||||||
|
useSidePanel
|
||||||
|
.getState()
|
||||||
|
.openSidePanel(
|
||||||
|
"Connect to GitHub",
|
||||||
|
<GitHubReposPanel
|
||||||
|
explorer={container}
|
||||||
|
gitHubClientProp={container.notebookManager.gitHubClient}
|
||||||
|
junoClientProp={container.notebookManager.junoClient}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
gitHubNotebooksTree.contextMenu = isConnected ? manageGitContextMenu : connectGitContextMenu;
|
||||||
gitHubNotebooksTree.isExpanded = true;
|
gitHubNotebooksTree.isExpanded = true;
|
||||||
gitHubNotebooksTree.isAlphaSorted = true;
|
gitHubNotebooksTree.isAlphaSorted = true;
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import UserDefinedFunction from "./UserDefinedFunction";
|
|||||||
|
|
||||||
export class ResourceTreeAdapter implements ReactAdapter {
|
export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
public static readonly MyNotebooksTitle = "My Notebooks";
|
public static readonly MyNotebooksTitle = "My Notebooks";
|
||||||
|
public static readonly MyNotebooksScratchTitle = "My Notebooks Scratch";
|
||||||
public static readonly GitHubReposTitle = "GitHub repos";
|
public static readonly GitHubReposTitle = "GitHub repos";
|
||||||
|
|
||||||
private static readonly DataTitle = "DATA";
|
private static readonly DataTitle = "DATA";
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ export default class Trigger {
|
|||||||
public triggerType: ko.Observable<string>;
|
public triggerType: ko.Observable<string>;
|
||||||
public triggerOperation: ko.Observable<string>;
|
public triggerOperation: ko.Observable<string>;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
constructor(container: Explorer, collection: ViewModels.Collection, data: any) {
|
constructor(container: Explorer, collection: ViewModels.Collection, data: any) {
|
||||||
this.nodeKind = "Trigger";
|
this.nodeKind = "Trigger";
|
||||||
this.container = container;
|
this.container = container;
|
||||||
@@ -35,7 +34,7 @@ export default class Trigger {
|
|||||||
this.triggerType = ko.observable(data.triggerType);
|
this.triggerType = ko.observable(data.triggerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public select(): void {
|
public select() {
|
||||||
useSelectedNode.getState().setSelectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Trigger node",
|
description: "Trigger node",
|
||||||
@@ -44,8 +43,7 @@ export default class Trigger {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
public static create(source: ViewModels.Collection, event: MouseEvent) {
|
||||||
public static create(source: ViewModels.Collection, _event: MouseEvent): void {
|
|
||||||
const id = useTabs.getState().getTabs(ViewModels.CollectionTabKind.Triggers).length + 1;
|
const id = useTabs.getState().getTabs(ViewModels.CollectionTabKind.Triggers).length + 1;
|
||||||
const trigger = <StoredProcedureDefinition>{
|
const trigger = <StoredProcedureDefinition>{
|
||||||
id: "",
|
id: "",
|
||||||
@@ -101,7 +99,7 @@ export default class Trigger {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public delete(): void {
|
public delete() {
|
||||||
useDialog.getState().showOkCancelModalDialog(
|
useDialog.getState().showOkCancelModalDialog(
|
||||||
"Confirm delete",
|
"Confirm delete",
|
||||||
"Are you sure you want to delete the trigger?",
|
"Are you sure you want to delete the trigger?",
|
||||||
@@ -112,8 +110,7 @@ export default class Trigger {
|
|||||||
useTabs.getState().closeTabsByComparator((tab) => tab.node && tab.node.rid === this.rid);
|
useTabs.getState().closeTabsByComparator((tab) => tab.node && tab.node.rid === this.rid);
|
||||||
this.collection.children.remove(this);
|
this.collection.children.remove(this);
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
(reason) => {}
|
||||||
() => {}
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
"Cancel",
|
"Cancel",
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export class GitHubOAuthService {
|
|||||||
return params.state;
|
return params.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async finishOAuth(params: IGitHubConnectorParams): Promise<void> {
|
public async finishOAuth(params: IGitHubConnectorParams) {
|
||||||
try {
|
try {
|
||||||
this.validateState(params.state);
|
this.validateState(params.state);
|
||||||
const response = await this.junoClient.getGitHubToken(params.code);
|
const response = await this.junoClient.getGitHubToken(params.code);
|
||||||
@@ -113,7 +113,7 @@ export class GitHubOAuthService {
|
|||||||
return this.state;
|
return this.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public resetToken(): void {
|
public resetToken() {
|
||||||
this.token(undefined);
|
this.token(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ const App: React.FunctionComponent = () => {
|
|||||||
onClick={() => window.open("https://portal.azure.com", "_blank")}
|
onClick={() => window.open("https://portal.azure.com", "_blank")}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
title="Go to Azure Portal"
|
title="Go to Azure Portal"
|
||||||
|
role="button"
|
||||||
|
onKeyDown={() => window.open("https://portal.azure.com", "_blank")}
|
||||||
>
|
>
|
||||||
Microsoft Azure
|
Microsoft Azure
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -33,13 +33,23 @@ const Index = (): JSX.Element => {
|
|||||||
<div
|
<div
|
||||||
id="Quickstart"
|
id="Quickstart"
|
||||||
onClick={quickstart_click}
|
onClick={quickstart_click}
|
||||||
|
onKeyPress={quickstart_click}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
className={navigationSelection === "quickstart" ? "topSelected" : ""}
|
className={navigationSelection === "quickstart" ? "topSelected" : ""}
|
||||||
>
|
>
|
||||||
<img id="imgiconwidth1" src={Quickstart} alt="Open Quick Start" />
|
<img id="imgiconwidth1" src={Quickstart} alt="Open Quick Start" />
|
||||||
<span className="menuQuickStart">Quickstart</span>
|
<span className="menuQuickStart">Quickstart</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="Explorer" onClick={explorer_click} className={navigationSelection === "explorer" ? "topSelected" : ""}>
|
<div
|
||||||
|
id="Explorer"
|
||||||
|
onClick={explorer_click}
|
||||||
|
className={navigationSelection === "explorer" ? "topSelected" : ""}
|
||||||
|
role="button"
|
||||||
|
tabIndex={0}
|
||||||
|
onKeyPress={explorer_click}
|
||||||
|
>
|
||||||
<img id="imgiconwidth1" src={Explorer} alt="Open Data Explorer" />
|
<img id="imgiconwidth1" src={Explorer} alt="Open Data Explorer" />
|
||||||
<span className="menuExplorer">Explorer</span>
|
<span className="menuExplorer">Explorer</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,11 +63,11 @@ const Index = (): JSX.Element => {
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
{navigationSelection === "quickstart" && (
|
{navigationSelection === "quickstart" && (
|
||||||
<iframe name="quickstart" className="iframe" src="quickstart.html"></iframe>
|
<iframe name="quickstart" className="iframe" src="quickstart.html" title="Quick Start"></iframe>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{navigationSelection === "explorer" && (
|
{navigationSelection === "explorer" && (
|
||||||
<iframe name="explorer" className="iframe" src="explorer.html?platform=Emulator"></iframe>
|
<iframe name="explorer" className="iframe" src="explorer.html?platform=Emulator" title="Explorer"></iframe>
|
||||||
)}
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ describe("Pinned repos", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("updatePinnedRepos invokes pinned repos subscribers", async () => {
|
it("updatePinnedRepos invokes pinned repos subscribers", async () => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
const callback = jest.fn().mockImplementation((pinnedRepos: IPinnedRepo[]) => {});
|
||||||
const callback = jest.fn().mockImplementation(() => {});
|
|
||||||
|
|
||||||
junoClient.subscribeToPinnedRepos(callback);
|
junoClient.subscribeToPinnedRepos(callback);
|
||||||
const response = await junoClient.updatePinnedRepos(samplePinnedRepos);
|
const response = await junoClient.updatePinnedRepos(samplePinnedRepos);
|
||||||
@@ -61,8 +60,7 @@ describe("Pinned repos", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("getPinnedRepos invokes pinned repos subscribers", async () => {
|
it("getPinnedRepos invokes pinned repos subscribers", async () => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
const callback = jest.fn().mockImplementation((pinnedRepos: IPinnedRepo[]) => {});
|
||||||
const callback = jest.fn().mockImplementation(() => {});
|
|
||||||
|
|
||||||
junoClient.subscribeToPinnedRepos(callback);
|
junoClient.subscribeToPinnedRepos(callback);
|
||||||
const response = await junoClient.getPinnedRepos("scope");
|
const response = await junoClient.getPinnedRepos("scope");
|
||||||
@@ -155,7 +153,7 @@ describe("Gallery", () => {
|
|||||||
it("getSampleNotebooks", async () => {
|
it("getSampleNotebooks", async () => {
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.getSampleNotebooks();
|
const response = await junoClient.getSampleNotebooks();
|
||||||
@@ -167,7 +165,7 @@ describe("Gallery", () => {
|
|||||||
it("getPublicNotebooks", async () => {
|
it("getPublicNotebooks", async () => {
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.getPublicNotebooks();
|
const response = await junoClient.getPublicNotebooks();
|
||||||
@@ -180,7 +178,7 @@ describe("Gallery", () => {
|
|||||||
const id = "id";
|
const id = "id";
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.getNotebookInfo(id);
|
const response = await junoClient.getNotebookInfo(id);
|
||||||
@@ -193,7 +191,7 @@ describe("Gallery", () => {
|
|||||||
const id = "id";
|
const id = "id";
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
text: () => undefined as undefined,
|
text: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.getNotebookContent(id);
|
const response = await junoClient.getNotebookContent(id);
|
||||||
@@ -206,7 +204,7 @@ describe("Gallery", () => {
|
|||||||
const id = "id";
|
const id = "id";
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
const response = await junoClient.increaseNotebookViews(id);
|
const response = await junoClient.increaseNotebookViews(id);
|
||||||
|
|
||||||
@@ -220,7 +218,7 @@ describe("Gallery", () => {
|
|||||||
const id = "id";
|
const id = "id";
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.increaseNotebookDownloadCount(id);
|
const response = await junoClient.increaseNotebookDownloadCount(id);
|
||||||
@@ -245,7 +243,7 @@ describe("Gallery", () => {
|
|||||||
const id = "id";
|
const id = "id";
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.favoriteNotebook(id);
|
const response = await junoClient.favoriteNotebook(id);
|
||||||
@@ -270,7 +268,7 @@ describe("Gallery", () => {
|
|||||||
const id = "id";
|
const id = "id";
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.unfavoriteNotebook(id);
|
const response = await junoClient.unfavoriteNotebook(id);
|
||||||
@@ -294,7 +292,7 @@ describe("Gallery", () => {
|
|||||||
it("getFavoriteNotebooks", async () => {
|
it("getFavoriteNotebooks", async () => {
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.getFavoriteNotebooks();
|
const response = await junoClient.getFavoriteNotebooks();
|
||||||
@@ -317,7 +315,7 @@ describe("Gallery", () => {
|
|||||||
it("getPublishedNotebooks", async () => {
|
it("getPublishedNotebooks", async () => {
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.getPublishedNotebooks();
|
const response = await junoClient.getPublishedNotebooks();
|
||||||
@@ -341,7 +339,7 @@ describe("Gallery", () => {
|
|||||||
const id = "id";
|
const id = "id";
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.deleteNotebook(id);
|
const response = await junoClient.deleteNotebook(id);
|
||||||
@@ -371,7 +369,7 @@ describe("Gallery", () => {
|
|||||||
const addLinkToNotebookViewer = true;
|
const addLinkToNotebookViewer = true;
|
||||||
window.fetch = jest.fn().mockReturnValue({
|
window.fetch = jest.fn().mockReturnValue({
|
||||||
status: HttpStatusCodes.OK,
|
status: HttpStatusCodes.OK,
|
||||||
json: () => undefined as undefined,
|
json: () => undefined as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await junoClient.publishNotebook(name, description, tags, thumbnailUrl, content);
|
const response = await junoClient.publishNotebook(name, description, tags, thumbnailUrl, content);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export interface IPublishNotebookRequest {
|
|||||||
description: string;
|
description: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
thumbnailUrl: string;
|
thumbnailUrl: string;
|
||||||
content: unknown;
|
content: any;
|
||||||
addLinkToNotebookViewer: boolean;
|
addLinkToNotebookViewer: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { HttpHeaders, HttpStatusCodes } from "../Common/Constants";
|
import { ConnectionStatusType, HttpHeaders, HttpStatusCodes } from "../Common/Constants";
|
||||||
import { configContext } from "../ConfigContext";
|
import { configContext } from "../ConfigContext";
|
||||||
|
import { ContainerConnectionInfo } from "../Contracts/DataModels";
|
||||||
|
import { useNotebook } from "../Explorer/Notebook/useNotebook";
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
||||||
|
|
||||||
@@ -13,6 +15,7 @@ export interface IPhoenixConnectionInfoResult {
|
|||||||
}
|
}
|
||||||
export interface IProvosionData {
|
export interface IProvosionData {
|
||||||
cosmosEndpoint: string;
|
cosmosEndpoint: string;
|
||||||
|
resourceId: string;
|
||||||
dbAccountName: string;
|
dbAccountName: string;
|
||||||
aadToken: string;
|
aadToken: string;
|
||||||
resourceGroup: string;
|
resourceGroup: string;
|
||||||
@@ -23,7 +26,11 @@ export class PhoenixClient {
|
|||||||
provisionData: IProvosionData
|
provisionData: IProvosionData
|
||||||
): Promise<IPhoenixResponse<IPhoenixConnectionInfoResult>> {
|
): Promise<IPhoenixResponse<IPhoenixConnectionInfoResult>> {
|
||||||
try {
|
try {
|
||||||
const response = await window.fetch(`${this.getPhoenixContainerPoolingEndPoint()}/allocate`, {
|
const connectionStatus: ContainerConnectionInfo = {
|
||||||
|
status: ConnectionStatusType.Connecting,
|
||||||
|
};
|
||||||
|
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||||
|
const response = await window.fetch(`${this.getPhoenixContainerPoolingEndPoint()}/provision`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: PhoenixClient.getHeaders(),
|
headers: PhoenixClient.getHeaders(),
|
||||||
body: JSON.stringify(provisionData),
|
body: JSON.stringify(provisionData),
|
||||||
@@ -31,20 +38,31 @@ export class PhoenixClient {
|
|||||||
let data: IPhoenixConnectionInfoResult;
|
let data: IPhoenixConnectionInfoResult;
|
||||||
if (response.status === HttpStatusCodes.OK) {
|
if (response.status === HttpStatusCodes.OK) {
|
||||||
data = await response.json();
|
data = await response.json();
|
||||||
|
if (data && data.notebookServerUrl) {
|
||||||
|
connectionStatus.status = ConnectionStatusType.Connected;
|
||||||
|
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
connectionStatus.status = ConnectionStatusType.Failed;
|
||||||
|
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: response.status,
|
status: response.status,
|
||||||
data,
|
data,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const connectionStatus: ContainerConnectionInfo = {
|
||||||
|
status: ConnectionStatusType.Failed,
|
||||||
|
};
|
||||||
|
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getPhoenixEndpoint(): string {
|
public static getPhoenixEndpoint(): string {
|
||||||
const phoenixEndpoint =
|
const phoenixEndpoint = userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
||||||
userContext.features.phoenixEndpoint ?? userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
|
||||||
if (configContext.allowedJunoOrigins.indexOf(new URL(phoenixEndpoint).origin) === -1) {
|
if (configContext.allowedJunoOrigins.indexOf(new URL(phoenixEndpoint).origin) === -1) {
|
||||||
const error = `${phoenixEndpoint} not allowed as juno endpoint`;
|
const error = `${phoenixEndpoint} not allowed as juno endpoint`;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
@@ -55,7 +73,7 @@ export class PhoenixClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getPhoenixContainerPoolingEndPoint(): string {
|
public getPhoenixContainerPoolingEndPoint(): string {
|
||||||
return `${PhoenixClient.getPhoenixEndpoint()}/api/controlplane/toolscontainer`;
|
return `${PhoenixClient.getPhoenixEndpoint()}/api/containerpooling`;
|
||||||
}
|
}
|
||||||
private static getHeaders(): HeadersInit {
|
private static getHeaders(): HeadersInit {
|
||||||
const authorizationHeader = getAuthorizationHeader();
|
const authorizationHeader = getAuthorizationHeader();
|
||||||
|
|||||||
@@ -77,16 +77,16 @@ export const ConnectExplorer: React.FunctionComponent<Props> = ({
|
|||||||
<p className="connectExplorerContent">
|
<p className="connectExplorerContent">
|
||||||
<input className="filterbtnstyle" type="submit" value="Connect" />
|
<input className="filterbtnstyle" type="submit" value="Connect" />
|
||||||
</p>
|
</p>
|
||||||
<p className="switchConnectTypeText" onClick={login}>
|
<div className="switchConnectTypeText" onClick={login} onKeyDown={login} role="button" tabIndex={0}>
|
||||||
Sign In with Azure Account
|
Sign In with Azure Account
|
||||||
</p>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
) : (
|
) : (
|
||||||
<div id="connectWithAad">
|
<div id="connectWithAad">
|
||||||
<input className="filterbtnstyle" type="button" value="Sign In" onClick={login} />
|
<input className="filterbtnstyle" type="button" value="Sign In" onClick={login} />
|
||||||
<p className="switchConnectTypeText" onClick={showForm}>
|
<div className="switchConnectTypeText" onClick={showForm} onKeyDown={showForm} role="button" tabIndex={0}>
|
||||||
Connect to your account with connection string
|
Connect to your account with connection string
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ export type Features = {
|
|||||||
readonly enableKoResourceTree: boolean;
|
readonly enableKoResourceTree: boolean;
|
||||||
readonly hostedDataExplorer: boolean;
|
readonly hostedDataExplorer: boolean;
|
||||||
readonly junoEndpoint?: string;
|
readonly junoEndpoint?: string;
|
||||||
readonly phoenixEndpoint?: string;
|
|
||||||
readonly livyEndpoint?: string;
|
readonly livyEndpoint?: string;
|
||||||
readonly notebookBasePath?: string;
|
readonly notebookBasePath?: string;
|
||||||
readonly notebookServerToken?: string;
|
readonly notebookServerToken?: string;
|
||||||
@@ -69,7 +68,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
|||||||
mongoProxyEndpoint: get("mongoproxyendpoint"),
|
mongoProxyEndpoint: get("mongoproxyendpoint"),
|
||||||
mongoProxyAPIs: get("mongoproxyapis"),
|
mongoProxyAPIs: get("mongoproxyapis"),
|
||||||
junoEndpoint: get("junoendpoint"),
|
junoEndpoint: get("junoendpoint"),
|
||||||
phoenixEndpoint: get("phoenixendpoint"),
|
|
||||||
livyEndpoint: get("livyendpoint"),
|
livyEndpoint: get("livyendpoint"),
|
||||||
notebookBasePath: get("notebookbasepath"),
|
notebookBasePath: get("notebookbasepath"),
|
||||||
notebookServerToken: get("notebookservertoken"),
|
notebookServerToken: get("notebookservertoken"),
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe("GalleryUtils", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("downloadItem shows dialog in data explorer", () => {
|
it("downloadItem shows dialog in data explorer", () => {
|
||||||
const container = new Explorer();
|
const container = {} as Explorer;
|
||||||
GalleryUtils.downloadItem(container, undefined, galleryItem, undefined);
|
GalleryUtils.downloadItem(container, undefined, galleryItem, undefined);
|
||||||
|
|
||||||
expect(useDialog.getState().visible).toBe(true);
|
expect(useDialog.getState().visible).toBe(true);
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
SortBy,
|
SortBy,
|
||||||
} from "../Explorer/Controls/NotebookGallery/GalleryViewerComponent";
|
} from "../Explorer/Controls/NotebookGallery/GalleryViewerComponent";
|
||||||
import Explorer from "../Explorer/Explorer";
|
import Explorer from "../Explorer/Explorer";
|
||||||
import { NotebookUtil } from "../Explorer/Notebook/NotebookUtil";
|
|
||||||
import { useNotebook } from "../Explorer/Notebook/useNotebook";
|
import { useNotebook } from "../Explorer/Notebook/useNotebook";
|
||||||
import { IGalleryItem, JunoClient } from "../Juno/JunoClient";
|
import { IGalleryItem, JunoClient } from "../Juno/JunoClient";
|
||||||
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
||||||
@@ -226,89 +225,67 @@ export function downloadItem(
|
|||||||
const name = data.name;
|
const name = data.name;
|
||||||
useDialog.getState().showOkCancelModalDialog(
|
useDialog.getState().showOkCancelModalDialog(
|
||||||
`Download to ${useNotebook.getState().notebookFolderName}`,
|
`Download to ${useNotebook.getState().notebookFolderName}`,
|
||||||
undefined,
|
`Download ${name} from gallery as a copy to your notebooks to run and/or edit the notebook.`,
|
||||||
"Download",
|
"Download",
|
||||||
async () => {
|
async () => {
|
||||||
if (NotebookUtil.isPhoenixEnabled()) {
|
const clearInProgressMessage = logConsoleProgress(
|
||||||
await container.allocateContainer();
|
`Downloading ${name} to ${useNotebook.getState().notebookFolderName}`
|
||||||
}
|
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
|
||||||
if (notebookServerInfo && notebookServerInfo.notebookServerEndpoint !== undefined) {
|
|
||||||
downloadNotebookItem(name, data, junoClient, container, onComplete);
|
|
||||||
} else {
|
|
||||||
useDialog
|
|
||||||
.getState()
|
|
||||||
.showOkModalDialog(
|
|
||||||
"Failed to Connect",
|
|
||||||
"Failed to connect to temporary workspace. Please refresh the page and try again."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Cancel",
|
|
||||||
undefined,
|
|
||||||
container.getDownloadModalConent(name)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export async function downloadNotebookItem(
|
|
||||||
fileName: string,
|
|
||||||
data: IGalleryItem,
|
|
||||||
junoClient: JunoClient,
|
|
||||||
container: Explorer,
|
|
||||||
onComplete: (item: IGalleryItem) => void
|
|
||||||
) {
|
|
||||||
const clearInProgressMessage = logConsoleProgress(
|
|
||||||
`Downloading ${fileName} to ${useNotebook.getState().notebookFolderName}`
|
|
||||||
);
|
|
||||||
const startKey = traceStart(Action.NotebooksGalleryDownload, {
|
|
||||||
notebookId: data.id,
|
|
||||||
downloadCount: data.downloads,
|
|
||||||
isSample: data.isSample,
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await junoClient.getNotebookContent(data.id);
|
|
||||||
if (!response.data) {
|
|
||||||
throw new Error(`Received HTTP ${response.status} when fetching ${data.name}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const notebook = JSON.parse(response.data) as Notebook;
|
|
||||||
removeNotebookViewerLink(notebook, data.newCellId);
|
|
||||||
|
|
||||||
if (!data.isSample) {
|
|
||||||
const metadata = notebook.metadata as { [name: string]: unknown };
|
|
||||||
metadata.untrusted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
await container.importAndOpenContent(data.name, JSON.stringify(notebook));
|
|
||||||
logConsoleInfo(`Successfully downloaded ${data.name} to ${useNotebook.getState().notebookFolderName}`);
|
|
||||||
|
|
||||||
const increaseDownloadResponse = await junoClient.increaseNotebookDownloadCount(data.id);
|
|
||||||
if (increaseDownloadResponse.data) {
|
|
||||||
traceSuccess(
|
|
||||||
Action.NotebooksGalleryDownload,
|
|
||||||
{ notebookId: data.id, downloadCount: increaseDownloadResponse.data.downloads, isSample: data.isSample },
|
|
||||||
startKey
|
|
||||||
);
|
);
|
||||||
onComplete(increaseDownloadResponse.data);
|
const startKey = traceStart(Action.NotebooksGalleryDownload, {
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
traceFailure(
|
|
||||||
Action.NotebooksGalleryDownload,
|
|
||||||
{
|
|
||||||
notebookId: data.id,
|
notebookId: data.id,
|
||||||
downloadCount: data.downloads,
|
downloadCount: data.downloads,
|
||||||
isSample: data.isSample,
|
isSample: data.isSample,
|
||||||
error: getErrorMessage(error),
|
});
|
||||||
errorStack: getErrorStack(error),
|
|
||||||
},
|
|
||||||
startKey
|
|
||||||
);
|
|
||||||
|
|
||||||
handleError(error, "GalleryUtils/downloadItem", `Failed to download ${data.name}`);
|
try {
|
||||||
}
|
const response = await junoClient.getNotebookContent(data.id);
|
||||||
|
if (!response.data) {
|
||||||
|
throw new Error(`Received HTTP ${response.status} when fetching ${data.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
clearInProgressMessage();
|
const notebook = JSON.parse(response.data) as Notebook;
|
||||||
|
removeNotebookViewerLink(notebook, data.newCellId);
|
||||||
|
|
||||||
|
if (!data.isSample) {
|
||||||
|
const metadata = notebook.metadata as { [name: string]: unknown };
|
||||||
|
metadata.untrusted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
await container.importAndOpenContent(data.name, JSON.stringify(notebook));
|
||||||
|
logConsoleInfo(`Successfully downloaded ${name} to My Notebooks`);
|
||||||
|
|
||||||
|
const increaseDownloadResponse = await junoClient.increaseNotebookDownloadCount(data.id);
|
||||||
|
if (increaseDownloadResponse.data) {
|
||||||
|
traceSuccess(
|
||||||
|
Action.NotebooksGalleryDownload,
|
||||||
|
{ notebookId: data.id, downloadCount: increaseDownloadResponse.data.downloads, isSample: data.isSample },
|
||||||
|
startKey
|
||||||
|
);
|
||||||
|
onComplete(increaseDownloadResponse.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
traceFailure(
|
||||||
|
Action.NotebooksGalleryDownload,
|
||||||
|
{
|
||||||
|
notebookId: data.id,
|
||||||
|
downloadCount: data.downloads,
|
||||||
|
isSample: data.isSample,
|
||||||
|
error: getErrorMessage(error),
|
||||||
|
errorStack: getErrorStack(error),
|
||||||
|
},
|
||||||
|
startKey
|
||||||
|
);
|
||||||
|
|
||||||
|
handleError(error, "GalleryUtils/downloadItem", `Failed to download ${data.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearInProgressMessage();
|
||||||
|
},
|
||||||
|
"Cancel",
|
||||||
|
undefined
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const removeNotebookViewerLink = (notebook: Notebook, newCellId: string): void => {
|
export const removeNotebookViewerLink = (notebook: Notebook, newCellId: string): void => {
|
||||||
if (!newCellId) {
|
if (!newCellId) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -69,11 +69,7 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
|||||||
if (tab.tabId === activeTab.tabId && tabIndex !== -1) {
|
if (tab.tabId === activeTab.tabId && tabIndex !== -1) {
|
||||||
const tabToTheRight = updatedTabs[tabIndex];
|
const tabToTheRight = updatedTabs[tabIndex];
|
||||||
const lastOpenTab = updatedTabs[updatedTabs.length - 1];
|
const lastOpenTab = updatedTabs[updatedTabs.length - 1];
|
||||||
const newActiveTab = tabToTheRight ?? lastOpenTab;
|
set({ activeTab: tabToTheRight || lastOpenTab });
|
||||||
set({ activeTab: newActiveTab });
|
|
||||||
if (newActiveTab) {
|
|
||||||
newActiveTab.onActivate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
set({ openedTabs: updatedTabs });
|
set({ openedTabs: updatedTabs });
|
||||||
|
|||||||
@@ -15,13 +15,18 @@
|
|||||||
"target": "es2017",
|
"target": "es2017",
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"lib": ["es5", "es6", "dom"],
|
"lib": [
|
||||||
|
"es5",
|
||||||
|
"es6",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"types": ["jest"],
|
"types": [
|
||||||
"baseUrl": "src"
|
"jest"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"typedocOptions": {
|
"typedocOptions": {
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
@@ -37,6 +42,11 @@
|
|||||||
"includes": "./src/SelfServe/Documentation",
|
"includes": "./src/SelfServe/Documentation",
|
||||||
"disableSources": true
|
"disableSources": true
|
||||||
},
|
},
|
||||||
"include": ["src", "./src/**/*", "./utils/**/*"],
|
"include": [
|
||||||
"exclude": ["./src/**/__mocks__/**/*"]
|
"./src/**/*",
|
||||||
}
|
"./utils/**/*"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"./src/**/__mocks__/**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
"noUnusedParameters": true
|
"noUnusedParameters": true
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
|
"./src/SelfServe/GraphAPICompute/GraphAPICompute.types.ts",
|
||||||
"./src/AuthType.ts",
|
"./src/AuthType.ts",
|
||||||
"./src/Bindings/ReactBindingHandler.ts",
|
"./src/Bindings/ReactBindingHandler.ts",
|
||||||
"./src/Common/ArrayHashMap.ts",
|
"./src/Common/ArrayHashMap.ts",
|
||||||
@@ -165,4 +166,4 @@
|
|||||||
"src/Terminal/**/*",
|
"src/Terminal/**/*",
|
||||||
"src/Utils/arm/**/*"
|
"src/Utils/arm/**/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user