mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-24 19:31:36 +00:00
Compare commits
6 Commits
genericRig
...
sqlxEdits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b0a98dce7 | ||
|
|
67ebce444f | ||
|
|
a09bcc7197 | ||
|
|
b2390e23e7 | ||
|
|
f922103e5c | ||
|
|
faa98de9e9 |
@@ -4,8 +4,6 @@ PORTAL_RUNNER_SUBSCRIPTION=
|
|||||||
PORTAL_RUNNER_RESOURCE_GROUP=
|
PORTAL_RUNNER_RESOURCE_GROUP=
|
||||||
PORTAL_RUNNER_DATABASE_ACCOUNT=
|
PORTAL_RUNNER_DATABASE_ACCOUNT=
|
||||||
PORTAL_RUNNER_DATABASE_ACCOUNT_KEY=
|
PORTAL_RUNNER_DATABASE_ACCOUNT_KEY=
|
||||||
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT=
|
|
||||||
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT_KEY=
|
|
||||||
PORTAL_RUNNER_CONNECTION_STRING=
|
PORTAL_RUNNER_CONNECTION_STRING=
|
||||||
NOTEBOOKS_TEST_RUNNER_TENANT_ID=
|
NOTEBOOKS_TEST_RUNNER_TENANT_ID=
|
||||||
NOTEBOOKS_TEST_RUNNER_CLIENT_ID=
|
NOTEBOOKS_TEST_RUNNER_CLIENT_ID=
|
||||||
|
|||||||
@@ -1,26 +1,37 @@
|
|||||||
**/node_modules/
|
**/node_modules/
|
||||||
src/**/__mocks__/**/*
|
|
||||||
dist/
|
dist/
|
||||||
Contracts/
|
Contracts/
|
||||||
src/Api/Apis.ts
|
src/Api/Apis.ts
|
||||||
src/AuthType.ts
|
src/AuthType.ts
|
||||||
src/Bindings/BindingHandlersRegisterer.ts
|
src/Bindings/BindingHandlersRegisterer.ts
|
||||||
src/Bindings/ReactBindingHandler.ts
|
src/Bindings/ReactBindingHandler.ts
|
||||||
|
src/Common/ArrayHashMap.ts
|
||||||
src/Common/Constants.ts
|
src/Common/Constants.ts
|
||||||
src/Common/CosmosClient.test.ts
|
src/Common/CosmosClient.test.ts
|
||||||
src/Common/CosmosClient.ts
|
src/Common/CosmosClient.ts
|
||||||
src/Common/DataAccessUtilityBase.test.ts
|
src/Common/DataAccessUtilityBase.test.ts
|
||||||
src/Common/DataAccessUtilityBase.ts
|
src/Common/DataAccessUtilityBase.ts
|
||||||
|
src/Common/DeleteFeedback.ts
|
||||||
|
src/Common/DocumentClientUtilityBase.ts
|
||||||
src/Common/EditableUtility.ts
|
src/Common/EditableUtility.ts
|
||||||
src/Common/HashMap.test.ts
|
src/Common/HashMap.test.ts
|
||||||
|
src/Common/HashMap.ts
|
||||||
|
src/Common/HeadersUtility.test.ts
|
||||||
|
src/Common/HeadersUtility.ts
|
||||||
|
src/Common/IteratorUtilities.test.ts
|
||||||
|
src/Common/IteratorUtilities.ts
|
||||||
src/Common/Logger.test.ts
|
src/Common/Logger.test.ts
|
||||||
src/Common/MessageHandler.test.ts
|
src/Common/MessageHandler.test.ts
|
||||||
src/Common/MessageHandler.ts
|
src/Common/MessageHandler.ts
|
||||||
src/Common/MongoProxyClient.test.ts
|
src/Common/MongoProxyClient.test.ts
|
||||||
src/Common/MongoUtility.ts
|
src/Common/MongoUtility.ts
|
||||||
src/Common/NotificationsClientBase.ts
|
src/Common/NotificationsClientBase.ts
|
||||||
|
src/Common/ObjectCache.test.ts
|
||||||
|
src/Common/ObjectCache.ts
|
||||||
src/Common/QueriesClient.ts
|
src/Common/QueriesClient.ts
|
||||||
src/Common/Splitter.ts
|
src/Common/Splitter.ts
|
||||||
|
src/Common/ThemeUtility.ts
|
||||||
|
src/Common/UrlUtility.ts
|
||||||
src/Config.ts
|
src/Config.ts
|
||||||
src/Contracts/ActionContracts.ts
|
src/Contracts/ActionContracts.ts
|
||||||
src/Contracts/DataModels.ts
|
src/Contracts/DataModels.ts
|
||||||
@@ -42,10 +53,13 @@ src/Definitions/jquery.d.ts
|
|||||||
src/Definitions/plotly.js-cartesian-dist.d-min.ts
|
src/Definitions/plotly.js-cartesian-dist.d-min.ts
|
||||||
src/Definitions/png.d.ts
|
src/Definitions/png.d.ts
|
||||||
src/Definitions/svg.d.ts
|
src/Definitions/svg.d.ts
|
||||||
|
src/Definitions/worker.d.ts
|
||||||
src/Explorer/ComponentRegisterer.test.ts
|
src/Explorer/ComponentRegisterer.test.ts
|
||||||
src/Explorer/ComponentRegisterer.ts
|
src/Explorer/ComponentRegisterer.ts
|
||||||
src/Explorer/ContextMenuButtonFactory.ts
|
src/Explorer/ContextMenuButtonFactory.ts
|
||||||
src/Explorer/Controls/CollapsiblePanel/CollapsiblePanelComponent.ts
|
src/Explorer/Controls/CollapsiblePanel/CollapsiblePanelComponent.ts
|
||||||
|
src/Explorer/Controls/CommandButton/CommandButton.test.ts
|
||||||
|
src/Explorer/Controls/CommandButton/CommandButton.ts
|
||||||
src/Explorer/Controls/DiffEditor/DiffEditorComponent.ts
|
src/Explorer/Controls/DiffEditor/DiffEditorComponent.ts
|
||||||
src/Explorer/Controls/DynamicList/DynamicList.test.ts
|
src/Explorer/Controls/DynamicList/DynamicList.test.ts
|
||||||
src/Explorer/Controls/DynamicList/DynamicListComponent.ts
|
src/Explorer/Controls/DynamicList/DynamicListComponent.ts
|
||||||
@@ -54,6 +68,7 @@ src/Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.ts
|
|||||||
src/Explorer/Controls/InputTypeahead/InputTypeahead.ts
|
src/Explorer/Controls/InputTypeahead/InputTypeahead.ts
|
||||||
src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts
|
src/Explorer/Controls/JsonEditor/JsonEditorComponent.ts
|
||||||
src/Explorer/Controls/Notebook/NotebookAppMessageHandler.ts
|
src/Explorer/Controls/Notebook/NotebookAppMessageHandler.ts
|
||||||
|
src/Explorer/Controls/ThroughputInput/ThroughputInput.test.ts
|
||||||
src/Explorer/Controls/ThroughputInput/ThroughputInputComponent.ts
|
src/Explorer/Controls/ThroughputInput/ThroughputInputComponent.ts
|
||||||
src/Explorer/Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3.ts
|
src/Explorer/Controls/ThroughputInput/ThroughputInputComponentAutoPilotV3.ts
|
||||||
src/Explorer/Controls/Toolbar/IToolbarAction.ts
|
src/Explorer/Controls/Toolbar/IToolbarAction.ts
|
||||||
@@ -80,17 +95,22 @@ src/Explorer/Graph/GraphExplorerComponent/D3ForceGraph.ts
|
|||||||
src/Explorer/Graph/GraphExplorerComponent/EdgeInfoCache.ts
|
src/Explorer/Graph/GraphExplorerComponent/EdgeInfoCache.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GraphData.test.ts
|
src/Explorer/Graph/GraphExplorerComponent/GraphData.test.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GraphData.ts
|
src/Explorer/Graph/GraphExplorerComponent/GraphData.ts
|
||||||
|
src/Explorer/Graph/GraphExplorerComponent/GraphUtil.test.ts
|
||||||
|
src/Explorer/Graph/GraphExplorerComponent/GraphUtil.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.test.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.test.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinClient.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.test.ts
|
||||||
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts
|
src/Explorer/Graph/GraphExplorerComponent/GremlinSimpleClient.ts
|
||||||
# src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts
|
src/Explorer/Graph/GraphStyleComponent/GraphStyle.test.ts
|
||||||
# src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts
|
src/Explorer/Graph/GraphStyleComponent/GraphStyleComponent.ts
|
||||||
|
src/Explorer/Graph/NewVertexComponent/NewVertex.test.ts
|
||||||
|
src/Explorer/Graph/NewVertexComponent/NewVertexComponent.ts
|
||||||
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.test.ts
|
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.test.ts
|
||||||
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.ts
|
src/Explorer/Menus/CommandBar/CommandBarComponentButtonFactory.ts
|
||||||
src/Explorer/Menus/ContextMenu.ts
|
src/Explorer/Menus/ContextMenu.ts
|
||||||
src/Explorer/MostRecentActivity/MostRecentActivity.ts
|
src/Explorer/MostRecentActivity/MostRecentActivity.ts
|
||||||
|
src/Explorer/Notebook/FileSystemUtil.ts
|
||||||
|
src/Explorer/Notebook/NTeractUtil.ts
|
||||||
src/Explorer/Notebook/NotebookClientV2.ts
|
src/Explorer/Notebook/NotebookClientV2.ts
|
||||||
src/Explorer/Notebook/NotebookComponent/NotebookContentProvider.ts
|
src/Explorer/Notebook/NotebookComponent/NotebookContentProvider.ts
|
||||||
src/Explorer/Notebook/NotebookComponent/__mocks__/rx-jupyter.ts
|
src/Explorer/Notebook/NotebookComponent/__mocks__/rx-jupyter.ts
|
||||||
@@ -108,23 +128,41 @@ src/Explorer/Notebook/NotebookUtil.ts
|
|||||||
src/Explorer/OpenActions.test.ts
|
src/Explorer/OpenActions.test.ts
|
||||||
src/Explorer/OpenActions.ts
|
src/Explorer/OpenActions.ts
|
||||||
src/Explorer/OpenActionsStubs.ts
|
src/Explorer/OpenActionsStubs.ts
|
||||||
src/Explorer/Panes/AddDatabasePane.ts
|
src/Explorer/Panes/AddCollectionPane.test.ts
|
||||||
|
src/Explorer/Panes/AddCollectionPane.ts
|
||||||
src/Explorer/Panes/AddDatabasePane.test.ts
|
src/Explorer/Panes/AddDatabasePane.test.ts
|
||||||
|
src/Explorer/Panes/AddDatabasePane.ts
|
||||||
src/Explorer/Panes/BrowseQueriesPane.ts
|
src/Explorer/Panes/BrowseQueriesPane.ts
|
||||||
src/Explorer/Panes/CassandraAddCollectionPane.ts
|
src/Explorer/Panes/CassandraAddCollectionPane.ts
|
||||||
src/Explorer/Panes/ContextualPaneBase.ts
|
src/Explorer/Panes/ContextualPaneBase.ts
|
||||||
|
src/Explorer/Panes/DeleteCollectionConfirmationPane.test.ts
|
||||||
|
src/Explorer/Panes/DeleteCollectionConfirmationPane.ts
|
||||||
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
|
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
|
||||||
src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts
|
src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts
|
||||||
# src/Explorer/Panes/GraphStylingPane.ts
|
src/Explorer/Panes/ExecuteSprocParamsPane.ts
|
||||||
# src/Explorer/Panes/NewVertexPane.ts
|
src/Explorer/Panes/GraphStylingPane.ts
|
||||||
|
src/Explorer/Panes/LoadQueryPane.ts
|
||||||
|
src/Explorer/Panes/NewVertexPane.ts
|
||||||
src/Explorer/Panes/PaneComponents.ts
|
src/Explorer/Panes/PaneComponents.ts
|
||||||
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
||||||
|
src/Explorer/Panes/SaveQueryPane.ts
|
||||||
|
src/Explorer/Panes/SettingsPane.test.ts
|
||||||
|
src/Explorer/Panes/SettingsPane.ts
|
||||||
src/Explorer/Panes/SetupNotebooksPane.ts
|
src/Explorer/Panes/SetupNotebooksPane.ts
|
||||||
|
src/Explorer/Panes/StringInputPane.ts
|
||||||
src/Explorer/Panes/SwitchDirectoryPane.ts
|
src/Explorer/Panes/SwitchDirectoryPane.ts
|
||||||
|
src/Explorer/Panes/Tables/AddTableEntityPane.ts
|
||||||
|
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
||||||
|
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
||||||
|
src/Explorer/Panes/Tables/QuerySelectPane.ts
|
||||||
|
src/Explorer/Panes/Tables/TableColumnOptionsPane.ts
|
||||||
|
src/Explorer/Panes/Tables/TableEntityPane.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
|
||||||
src/Explorer/SplashScreen/SplashScreen.test.ts
|
src/Explorer/Panes/UploadFilePane.ts
|
||||||
|
src/Explorer/Panes/UploadItemsPane.ts
|
||||||
|
src/Explorer/SplashScreen/SplashScreenComponentAdapter.test.ts
|
||||||
src/Explorer/Tables/Constants.ts
|
src/Explorer/Tables/Constants.ts
|
||||||
src/Explorer/Tables/DataTable/CacheBase.ts
|
src/Explorer/Tables/DataTable/CacheBase.ts
|
||||||
src/Explorer/Tables/DataTable/DataTableBindingManager.ts
|
src/Explorer/Tables/DataTable/DataTableBindingManager.ts
|
||||||
@@ -132,6 +170,7 @@ 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/DataTableOperations.ts
|
||||||
|
src/Explorer/Tables/DataTable/DataTableUtilities.ts
|
||||||
src/Explorer/Tables/DataTable/DataTableViewModel.ts
|
src/Explorer/Tables/DataTable/DataTableViewModel.ts
|
||||||
src/Explorer/Tables/DataTable/TableCommands.ts
|
src/Explorer/Tables/DataTable/TableCommands.ts
|
||||||
src/Explorer/Tables/DataTable/TableEntityCache.ts
|
src/Explorer/Tables/DataTable/TableEntityCache.ts
|
||||||
@@ -140,6 +179,8 @@ src/Explorer/Tables/Entities.ts
|
|||||||
src/Explorer/Tables/QueryBuilder/ClauseGroup.ts
|
src/Explorer/Tables/QueryBuilder/ClauseGroup.ts
|
||||||
src/Explorer/Tables/QueryBuilder/ClauseGroupViewModel.ts
|
src/Explorer/Tables/QueryBuilder/ClauseGroupViewModel.ts
|
||||||
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
|
src/Explorer/Tables/QueryBuilder/CustomTimestampHelper.ts
|
||||||
|
src/Explorer/Tables/QueryBuilder/DateTimeUtilities.test.ts
|
||||||
|
src/Explorer/Tables/QueryBuilder/DateTimeUtilities.ts
|
||||||
src/Explorer/Tables/QueryBuilder/QueryBuilderViewModel.ts
|
src/Explorer/Tables/QueryBuilder/QueryBuilderViewModel.ts
|
||||||
src/Explorer/Tables/QueryBuilder/QueryClauseViewModel.ts
|
src/Explorer/Tables/QueryBuilder/QueryClauseViewModel.ts
|
||||||
src/Explorer/Tables/QueryBuilder/QueryViewModel.ts
|
src/Explorer/Tables/QueryBuilder/QueryViewModel.ts
|
||||||
@@ -159,6 +200,7 @@ src/Explorer/Tabs/QueryTab.test.ts
|
|||||||
src/Explorer/Tabs/QueryTab.ts
|
src/Explorer/Tabs/QueryTab.ts
|
||||||
src/Explorer/Tabs/QueryTablesTab.ts
|
src/Explorer/Tabs/QueryTablesTab.ts
|
||||||
src/Explorer/Tabs/ScriptTabBase.ts
|
src/Explorer/Tabs/ScriptTabBase.ts
|
||||||
|
src/Explorer/Tabs/SparkMasterTab.ts
|
||||||
src/Explorer/Tabs/StoredProcedureTab.ts
|
src/Explorer/Tabs/StoredProcedureTab.ts
|
||||||
src/Explorer/Tabs/TabComponents.ts
|
src/Explorer/Tabs/TabComponents.ts
|
||||||
src/Explorer/Tabs/TabsBase.ts
|
src/Explorer/Tabs/TabsBase.ts
|
||||||
@@ -222,6 +264,8 @@ src/Shared/ExplorerSettings.ts
|
|||||||
src/Shared/PriceEstimateCalculator.ts
|
src/Shared/PriceEstimateCalculator.ts
|
||||||
src/Shared/StorageUtility.test.ts
|
src/Shared/StorageUtility.test.ts
|
||||||
src/Shared/StorageUtility.ts
|
src/Shared/StorageUtility.ts
|
||||||
|
src/Shared/StringUtility.test.ts
|
||||||
|
src/Shared/StringUtility.ts
|
||||||
src/Shared/appInsights.ts
|
src/Shared/appInsights.ts
|
||||||
src/SparkClusterManager/ArcadiaResourceManager.ts
|
src/SparkClusterManager/ArcadiaResourceManager.ts
|
||||||
src/SparkClusterManager/SparkClusterManager.ts
|
src/SparkClusterManager/SparkClusterManager.ts
|
||||||
@@ -230,11 +274,26 @@ src/Terminal/NotebookAppContracts.d.ts
|
|||||||
src/Terminal/index.ts
|
src/Terminal/index.ts
|
||||||
src/TokenProviders/PortalTokenProvider.ts
|
src/TokenProviders/PortalTokenProvider.ts
|
||||||
src/TokenProviders/TokenProviderFactory.ts
|
src/TokenProviders/TokenProviderFactory.ts
|
||||||
|
src/Utils/AuthorizationUtils.test.ts
|
||||||
|
src/Utils/AuthorizationUtils.ts
|
||||||
|
src/Utils/AutoPilotUtils.test.ts
|
||||||
|
src/Utils/AutoPilotUtils.ts
|
||||||
|
src/Utils/DatabaseAccountUtils.test.ts
|
||||||
|
src/Utils/DatabaseAccountUtils.ts
|
||||||
|
src/Utils/JunoUtils.ts
|
||||||
|
src/Utils/MessageValidation.ts
|
||||||
|
src/Utils/NotebookConfigurationUtils.ts
|
||||||
src/Utils/PricingUtils.test.ts
|
src/Utils/PricingUtils.test.ts
|
||||||
src/Utils/QueryUtils.test.ts
|
src/Utils/QueryUtils.test.ts
|
||||||
|
src/Utils/QueryUtils.ts
|
||||||
|
src/Utils/StringUtils.test.ts
|
||||||
|
src/Utils/StringUtils.ts
|
||||||
src/applyExplorerBindings.ts
|
src/applyExplorerBindings.ts
|
||||||
src/global.d.ts
|
src/global.d.ts
|
||||||
|
src/quickstart.ts
|
||||||
src/setupTests.ts
|
src/setupTests.ts
|
||||||
|
src/workers/upload/definitions.ts
|
||||||
|
src/workers/upload/index.ts
|
||||||
src/Explorer/Controls/AccessibleElement/AccessibleElement.tsx
|
src/Explorer/Controls/AccessibleElement/AccessibleElement.tsx
|
||||||
src/Explorer/Controls/Accordion/AccordionComponent.tsx
|
src/Explorer/Controls/Accordion/AccordionComponent.tsx
|
||||||
src/Explorer/Controls/AccountSwitch/AccountSwitchComponent.test.tsx
|
src/Explorer/Controls/AccountSwitch/AccountSwitchComponent.test.tsx
|
||||||
@@ -280,8 +339,18 @@ src/Explorer/Graph/GraphExplorerComponent/QueryContainerComponent.tsx
|
|||||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNeighborsComponent.tsx
|
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNeighborsComponent.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/CommandBarComponentAdapter.tsx
|
||||||
|
src/Explorer/Menus/CommandBar/CommandBarUtil.test.tsx
|
||||||
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
|
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
|
||||||
|
src/Explorer/Menus/CommandBar/MemoryTrackerComponent.tsx
|
||||||
|
src/Explorer/Menus/NavBar/ControlBarComponent.tsx
|
||||||
|
src/Explorer/Menus/NavBar/ControlBarComponentAdapter.tsx
|
||||||
|
src/Explorer/Menus/NavBar/MeControlComponent.test.tsx
|
||||||
|
src/Explorer/Menus/NavBar/MeControlComponent.tsx
|
||||||
|
src/Explorer/Menus/NavBar/MeControlComponentAdapter.tsx
|
||||||
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.test.tsx
|
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.test.tsx
|
||||||
|
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.tsx
|
||||||
|
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponentAdapter.tsx
|
||||||
src/Explorer/Notebook/NotebookComponent/NotebookComponent.tsx
|
src/Explorer/Notebook/NotebookComponent/NotebookComponent.tsx
|
||||||
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
|
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
|
||||||
src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
|
src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
|
||||||
@@ -308,7 +377,8 @@ src/Explorer/Notebook/temp/inputs/editor.tsx
|
|||||||
src/Explorer/Notebook/temp/markdown-cell.tsx
|
src/Explorer/Notebook/temp/markdown-cell.tsx
|
||||||
src/Explorer/Notebook/temp/source.tsx
|
src/Explorer/Notebook/temp/source.tsx
|
||||||
src/Explorer/Notebook/temp/syntax-highlighter/index.tsx
|
src/Explorer/Notebook/temp/syntax-highlighter/index.tsx
|
||||||
src/Explorer/SplashScreen/SplashScreen.tsx
|
src/Explorer/SplashScreen/SplashScreenComponent.tsx
|
||||||
|
src/Explorer/SplashScreen/SplashScreenComponentApdapter.tsx
|
||||||
src/Explorer/Tabs/GalleryTab.tsx
|
src/Explorer/Tabs/GalleryTab.tsx
|
||||||
src/Explorer/Tabs/NotebookViewerTab.tsx
|
src/Explorer/Tabs/NotebookViewerTab.tsx
|
||||||
src/Explorer/Tabs/TerminalTab.tsx
|
src/Explorer/Tabs/TerminalTab.tsx
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ 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"],
|
||||||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
||||||
globals: {
|
globals: {
|
||||||
Atomics: "readonly",
|
Atomics: "readonly",
|
||||||
@@ -11,7 +11,6 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
parser: "@typescript-eslint/parser",
|
parser: "@typescript-eslint/parser",
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
project: ["./tsconfig.json", "./tsconfig.test.json"],
|
|
||||||
ecmaFeatures: {
|
ecmaFeatures: {
|
||||||
jsx: true,
|
jsx: true,
|
||||||
},
|
},
|
||||||
@@ -21,7 +20,7 @@ module.exports = {
|
|||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: ["**/*.tsx"],
|
files: ["**/*.tsx"],
|
||||||
extends: ["plugin:react/recommended"],
|
extends: ["plugin:react/recommended"], // TODO: Add react-hooks
|
||||||
plugins: ["react"],
|
plugins: ["react"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -36,7 +35,6 @@ module.exports = {
|
|||||||
rules: {
|
rules: {
|
||||||
"no-console": ["error", { allow: ["error", "warn", "dir"] }],
|
"no-console": ["error", { allow: ["error", "warn", "dir"] }],
|
||||||
curly: "error",
|
curly: "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",
|
"no-null/no-null": "error",
|
||||||
@@ -44,8 +42,6 @@ module.exports = {
|
|||||||
"prefer-arrow/prefer-arrow-functions": ["error", { allowStandaloneDeclarations: true }],
|
"prefer-arrow/prefer-arrow-functions": ["error", { allowStandaloneDeclarations: true }],
|
||||||
eqeqeq: "error",
|
eqeqeq: "error",
|
||||||
"react/display-name": "off",
|
"react/display-name": "off",
|
||||||
"react-hooks/rules-of-hooks": "warn", // TODO: error
|
|
||||||
"react-hooks/exhaustive-deps": "warn", // TODO: error
|
|
||||||
"no-restricted-syntax": [
|
"no-restricted-syntax": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
|
|||||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1 +0,0 @@
|
|||||||
[Preview this branch](https://cosmos-explorer-preview.azurewebsites.net/pull/EDIT_THIS_NUMBER_IN_THE_PR_DESCRIPTION?feature.someFeatureFlagYouMightNeed=true)
|
|
||||||
9
.github/dependabot.yml
vendored
9
.github/dependabot.yml
vendored
@@ -1,9 +0,0 @@
|
|||||||
# Please see the documentation for all configuration options:
|
|
||||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "npm"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
126
.github/workflows/ci.yml
vendored
126
.github/workflows/ci.yml
vendored
@@ -15,10 +15,10 @@ jobs:
|
|||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 14.x
|
- name: Use Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 14.x
|
node-version: 12.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: node utils/codeMetrics.js
|
- run: node utils/codeMetrics.js
|
||||||
env:
|
env:
|
||||||
@@ -28,10 +28,10 @@ jobs:
|
|||||||
name: "Compile TypeScript"
|
name: "Compile TypeScript"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 14.x
|
- name: Use Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 14.x
|
node-version: 12.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run compile
|
- run: npm run compile
|
||||||
- run: npm run compile:strict
|
- run: npm run compile:strict
|
||||||
@@ -40,10 +40,10 @@ jobs:
|
|||||||
name: "Check Format"
|
name: "Check Format"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 14.x
|
- name: Use Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 14.x
|
node-version: 12.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run format:check
|
- run: npm run format:check
|
||||||
lint:
|
lint:
|
||||||
@@ -51,10 +51,10 @@ jobs:
|
|||||||
name: "Lint"
|
name: "Lint"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 14.x
|
- name: Use Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 14.x
|
node-version: 12.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
unittest:
|
unittest:
|
||||||
@@ -62,21 +62,22 @@ jobs:
|
|||||||
name: "Unit Tests"
|
name: "Unit Tests"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 14.x
|
- name: Use Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 14.x
|
node-version: 12.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run test
|
- run: npm run test
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: [lint, format, compile, unittest]
|
||||||
name: "Build"
|
name: "Build"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 14.x
|
- name: Use Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 14.x
|
node-version: 12.x
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: npm run build:contracts
|
- run: npm run build:contracts
|
||||||
- name: Restore Build Cache
|
- name: Restore Build Cache
|
||||||
@@ -91,25 +92,16 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: dist
|
name: dist
|
||||||
path: dist/
|
path: dist/
|
||||||
- name: Upload build to preview blob storage
|
|
||||||
run: az storage blob upload-batch -d '$web' -s 'dist' --account-name cosmosexplorerpreview --subscription cosmosdb-portalteam-generaldemo --destination-path "${{github.event.pull_request.head.sha}}" --account-key="${PREVIEW_STORAGE_KEY}"
|
|
||||||
env:
|
|
||||||
PREVIEW_STORAGE_KEY: ${{ secrets.PREVIEW_STORAGE_KEY }}
|
|
||||||
- name: Upload preview config to blob storage
|
|
||||||
run: az storage blob upload -c '$web' -f ./preview/config.json --account-name cosmosexplorerpreview --subscription cosmosdb-portalteam-generaldemo --name "${{github.event.pull_request.head.sha}}/config.json" --account-key="${PREVIEW_STORAGE_KEY}"
|
|
||||||
env:
|
|
||||||
PREVIEW_STORAGE_KEY: ${{ secrets.PREVIEW_STORAGE_KEY }}
|
|
||||||
endtoendemulator:
|
endtoendemulator:
|
||||||
name: "End To End Emulator Tests"
|
name: "End To End Emulator Tests"
|
||||||
# Temporarily disabled. This test needs to be rewritten in playwright
|
needs: [lint, format, compile, unittest]
|
||||||
if: false
|
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 14.x
|
- name: Use Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 14.x
|
node-version: 12.x
|
||||||
- uses: southpolesteve/cosmos-emulator-github-action@v1
|
- uses: southpolesteve/cosmos-emulator-github-action@v1
|
||||||
- name: End to End Tests
|
- name: End to End Tests
|
||||||
run: |
|
run: |
|
||||||
@@ -127,48 +119,72 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: screenshots
|
name: screenshots
|
||||||
path: failed-*
|
path: failed-*
|
||||||
endtoend:
|
accessibility:
|
||||||
name: "E2E"
|
name: "Accessibility | Hosted"
|
||||||
|
needs: [lint, format, compile, unittest]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
|
||||||
NODE_TLS_REJECT_UNAUTHORIZED: 0
|
|
||||||
NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET }}
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
test-file:
|
|
||||||
- ./test/cassandra/container.spec.ts
|
|
||||||
- ./test/graph/container.spec.ts
|
|
||||||
- ./test/sql/container.spec.ts
|
|
||||||
- ./test/mongo/container.spec.ts
|
|
||||||
- ./test/mongo/container32.spec.ts
|
|
||||||
- ./test/selfServe/selfServeExample.spec.ts
|
|
||||||
- ./test/notebooks/upload.spec.ts
|
|
||||||
- ./test/sql/resourceToken.spec.ts
|
|
||||||
- ./test/tables/container.spec.ts
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Use Node.js 14.x
|
- name: Use Node.js 12.x
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 14.x
|
node-version: 12.x
|
||||||
- run: npm ci
|
- name: Accessibility Check
|
||||||
- run: npm start &
|
|
||||||
- run: npm run wait-for-server
|
|
||||||
- name: ${{ matrix['test-file'] }}
|
|
||||||
run: |
|
run: |
|
||||||
# Run tests up to three times
|
# Ubuntu gets mad when webpack runs too many files watchers
|
||||||
for i in $(seq 1 3); do npx jest -c ./jest.config.playwright.js ${{ matrix['test-file'] }} && s=0 && break || s=$? && sleep 1; done; (exit $s)
|
cat /proc/sys/fs/inotify/max_user_watches
|
||||||
|
sudo sysctl fs.inotify.max_user_watches=524288
|
||||||
|
sudo sysctl -p
|
||||||
|
npm ci
|
||||||
|
npm start &
|
||||||
|
npx wait-on -i 5000 https-get://0.0.0.0:1234/
|
||||||
|
node utils/accesibilityCheck.js
|
||||||
shell: bash
|
shell: bash
|
||||||
|
env:
|
||||||
|
NODE_TLS_REJECT_UNAUTHORIZED: 0
|
||||||
|
endtoendhosted:
|
||||||
|
name: "End to End Hosted Tests"
|
||||||
|
needs: [lint, format, compile, unittest]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use Node.js 12.x
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 12.x
|
||||||
|
- name: End to End Hosted Tests
|
||||||
|
run: |
|
||||||
|
npm ci
|
||||||
|
npm start &
|
||||||
|
node utils/cleanupDBs.js
|
||||||
|
npm run wait-for-server
|
||||||
|
npm run test:e2e
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
NODE_TLS_REJECT_UNAUTHORIZED: 0
|
||||||
|
PORTAL_RUNNER_SUBSCRIPTION: ${{ secrets.PORTAL_RUNNER_SUBSCRIPTION }}
|
||||||
|
PORTAL_RUNNER_RESOURCE_GROUP: ${{ secrets.PORTAL_RUNNER_RESOURCE_GROUP }}
|
||||||
|
PORTAL_RUNNER_DATABASE_ACCOUNT: ${{ secrets.PORTAL_RUNNER_DATABASE_ACCOUNT }}
|
||||||
|
PORTAL_RUNNER_DATABASE_ACCOUNT_KEY: ${{ secrets.PORTAL_RUNNER_DATABASE_ACCOUNT_KEY }}
|
||||||
|
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT: ${{ secrets.PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT }}
|
||||||
|
PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT_KEY: ${{ secrets.PORTAL_RUNNER_MONGO_DATABASE_ACCOUNT_KEY }}
|
||||||
|
NOTEBOOKS_TEST_RUNNER_TENANT_ID: ${{ secrets.NOTEBOOKS_TEST_RUNNER_TENANT_ID }}
|
||||||
|
NOTEBOOKS_TEST_RUNNER_CLIENT_ID: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_ID }}
|
||||||
|
NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET }}
|
||||||
|
PORTAL_RUNNER_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_SQL }}
|
||||||
|
MONGO_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_MONGO }}
|
||||||
|
CASSANDRA_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_CASSANDRA }}
|
||||||
|
TABLES_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_TABLE }}
|
||||||
|
DATA_EXPLORER_ENDPOINT: "https://localhost:1234/hostedExplorer.html"
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
name: screenshots
|
name: screenshots
|
||||||
path: screenshots/
|
path: failed-*
|
||||||
nuget:
|
nuget:
|
||||||
name: Publish Nuget
|
name: Publish Nuget
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
||||||
needs: [build]
|
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted, accessibility]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
||||||
@@ -184,7 +200,7 @@ jobs:
|
|||||||
- run: cp ./configs/prod.json config.json
|
- run: cp ./configs/prod.json config.json
|
||||||
- run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "GitHub" -Password "$AZURE_DEVOPS_PAT"
|
- run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "GitHub" -Password "$AZURE_DEVOPS_PAT"
|
||||||
- run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}"
|
- run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}"
|
||||||
- run: nuget push -SkipDuplicate -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
|
- run: nuget push -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
name: packages
|
name: packages
|
||||||
with:
|
with:
|
||||||
@@ -192,7 +208,7 @@ jobs:
|
|||||||
nugetmpac:
|
nugetmpac:
|
||||||
name: Publish Nuget MPAC
|
name: Publish Nuget MPAC
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
||||||
needs: [build]
|
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted, accessibility]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
||||||
@@ -209,7 +225,7 @@ jobs:
|
|||||||
- run: sed -i 's/Azure.Cosmos.DB.Data.Explorer/Azure.Cosmos.DB.Data.Explorer.MPAC/g' DataExplorer.nuspec
|
- run: sed -i 's/Azure.Cosmos.DB.Data.Explorer/Azure.Cosmos.DB.Data.Explorer.MPAC/g' DataExplorer.nuspec
|
||||||
- run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "GitHub" -Password "$AZURE_DEVOPS_PAT"
|
- run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "GitHub" -Password "$AZURE_DEVOPS_PAT"
|
||||||
- run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}"
|
- run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}"
|
||||||
- run: nuget push -SkipDuplicate -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
|
- run: nuget push -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
name: packages
|
name: packages
|
||||||
with:
|
with:
|
||||||
|
|||||||
28
.github/workflows/cleanup.yml
vendored
28
.github/workflows/cleanup.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
# This is a basic workflow to help you get started with Actions
|
|
||||||
|
|
||||||
name: Cleanup End to End Account Resources
|
|
||||||
|
|
||||||
on:
|
|
||||||
# Allows you to run this workflow manually from the Actions tab
|
|
||||||
workflow_dispatch:
|
|
||||||
schedule:
|
|
||||||
# Once every hour
|
|
||||||
- cron: "0 * * * *"
|
|
||||||
|
|
||||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
|
||||||
jobs:
|
|
||||||
# This workflow contains a single job called "build"
|
|
||||||
cleanupaccounts:
|
|
||||||
name: "Cleanup Test Database Accounts"
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
NOTEBOOKS_TEST_RUNNER_CLIENT_ID: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_ID }}
|
|
||||||
NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET: ${{ secrets.NOTEBOOKS_TEST_RUNNER_CLIENT_SECRET }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- name: Use Node.js 14.x
|
|
||||||
uses: actions/setup-node@v1
|
|
||||||
with:
|
|
||||||
node-version: 14.x
|
|
||||||
- run: npm ci
|
|
||||||
- run: node utils/cleanupDBs.js
|
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -14,6 +14,4 @@ Contracts/*
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
.cache/
|
.cache/
|
||||||
.env
|
.env
|
||||||
failure.png
|
failure.png
|
||||||
screenshots/*
|
|
||||||
GettingStarted-ignore*.ipynb
|
|
||||||
43
.vscode/settings.json
vendored
43
.vscode/settings.json
vendored
@@ -1,26 +1,21 @@
|
|||||||
// Place your settings in this file to overwrite default and user settings.
|
// Place your settings in this file to overwrite default and user settings.
|
||||||
{
|
{
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
".vs": true,
|
".vs": true,
|
||||||
".vscode/**": true,
|
".vscode/**": true,
|
||||||
"*.trx": true,
|
"*.trx": true,
|
||||||
"**/.DS_Store": true,
|
"**/.DS_Store": true,
|
||||||
"**/.git": true,
|
"**/.git": true,
|
||||||
"**/.hg": true,
|
"**/.hg": true,
|
||||||
"**/.svn": true,
|
"**/.svn": true,
|
||||||
"built/**": true,
|
"built/**": true,
|
||||||
"coverage/**": true,
|
"coverage/**": true,
|
||||||
"libs/**": true,
|
"libs/**": true,
|
||||||
"node_modules/**": true,
|
"node_modules/**": true,
|
||||||
"package-lock.json": true,
|
"package-lock.json": true,
|
||||||
"quickstart/**": true,
|
"quickstart/**": true,
|
||||||
"test/out/**": true,
|
"test/out/**": true,
|
||||||
"workers/libs/**": true
|
"workers/libs/**": true
|
||||||
},
|
},
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib"
|
||||||
"editor.formatOnSave": true,
|
}
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
"source.fixAll.eslint": true,
|
|
||||||
"source.organizeImports": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
# Coding Guidelines and Recommendations
|
|
||||||
|
|
||||||
Cosmos Explorer has been under constant development for over 5 years. As a result, there are many different patterns and practices in the codebase. This document serves as a guide to how we write code and helps avoid propagating practices which are no longer preferred. Each requirement in this document is labeled and color-coded to show the relative importance. In order from highest to lowest importance:
|
|
||||||
|
|
||||||
✅ DO this. If you feel you need an exception, engage with the project owners _prior_ to implementation.
|
|
||||||
|
|
||||||
⛔️ DO NOT do this. If you feel you need an exception, engage with the project owners _prior_ to implementation.
|
|
||||||
|
|
||||||
☑️ YOU SHOULD strongly consider this but it is not a requirement. If not following this advice, please comment code with why and proactively begin a discussion as part of the PR process.
|
|
||||||
|
|
||||||
⚠️ YOU SHOULD NOT strongly consider not doing this. If not following this advice, please comment code with why and proactively begin a discussion as part of the PR process.
|
|
||||||
|
|
||||||
💭 YOU MAY consider this advice if appropriate to your situation. Other team members may comment on this as part of PR review, but there is no need to be proactive.
|
|
||||||
|
|
||||||
## Development Environment
|
|
||||||
|
|
||||||
☑️ YOU SHOULD
|
|
||||||
|
|
||||||
- Use VSCode and install the following extensions. This setup will catch most linting/formatting/type errors as you develop:
|
|
||||||
- [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
|
|
||||||
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)
|
|
||||||
|
|
||||||
💭 YOU MAY
|
|
||||||
|
|
||||||
- Use the [GitHub CLI](https://cli.github.com/). It has helpful workflows for submitting PRs as well as for checking out other team member's PRs.
|
|
||||||
- Use Windows, Linux (including WSL), or OSX. We have team members developing on all three environments.
|
|
||||||
|
|
||||||
✅ DO
|
|
||||||
|
|
||||||
- Maintain cross-platform compatibility when modifying any engineering or build systems
|
|
||||||
|
|
||||||
## Code Formatting
|
|
||||||
|
|
||||||
✅ DO
|
|
||||||
|
|
||||||
- Use [Prettier](https://prettier.io/) to format your code
|
|
||||||
- This will occur automatically if using the recommended editor setup
|
|
||||||
- `npm run format` will also format code
|
|
||||||
|
|
||||||
## Linting
|
|
||||||
|
|
||||||
✅ DO
|
|
||||||
|
|
||||||
- Use [ESLint](https://eslint.org/) to check for code errors.
|
|
||||||
- This will occur automatically if using the recommended editor setup
|
|
||||||
- `npm run lint` will also check for linting errors
|
|
||||||
|
|
||||||
💭 YOU MAY
|
|
||||||
|
|
||||||
- Consider adding new lint rules.
|
|
||||||
- If you find yourself performing "nits" as part of PR review, consider adding a lint rule that will automatically catch the error in the future
|
|
||||||
|
|
||||||
⚠️ YOU SHOULD NOT
|
|
||||||
|
|
||||||
- Disable lint rules
|
|
||||||
- Lint rules exist as guidance and to catch common mistakes
|
|
||||||
- You will find places we disable specific lint rules however it should be exceptional.
|
|
||||||
- If a rule does need to be disabled, prefer disabling a specific line instead of the entire file.
|
|
||||||
|
|
||||||
⛔️ DO NOT
|
|
||||||
|
|
||||||
- Add [TSLint](https://palantir.github.io/tslint/) rules
|
|
||||||
- TSLint has been deprecated and is on track to be removed
|
|
||||||
- Always prefer ESLint rules
|
|
||||||
|
|
||||||
## UI Components
|
|
||||||
|
|
||||||
☑️ YOU SHOULD
|
|
||||||
|
|
||||||
- Write new components using [React](https://reactjs.org/). We are actively migrating Cosmos Explorer off of [Knockout](https://knockoutjs.com/).
|
|
||||||
- Use [Fluent](https://developer.microsoft.com/en-us/fluentui#/) components.
|
|
||||||
- Fluent components are designed to be highly accessible and composable
|
|
||||||
- Using Fluent allows us to build upon the work of the Fluent team and leads to a lower total cost of ownership for UI code
|
|
||||||
|
|
||||||
### React
|
|
||||||
|
|
||||||
☑️ YOU SHOULD
|
|
||||||
|
|
||||||
- Use pure functional components when no state is required
|
|
||||||
|
|
||||||
💭 YOU MAY
|
|
||||||
|
|
||||||
- Use functional (hooks) or class components
|
|
||||||
- The project contains examples of both
|
|
||||||
- Neither is strongly preferred at this time
|
|
||||||
|
|
||||||
⛔️ DO NOT
|
|
||||||
|
|
||||||
- Use inheritance for sharing component behavior.
|
|
||||||
- React documentation covers this topic in detail https://reactjs.org/docs/composition-vs-inheritance.html
|
|
||||||
- Suffix your file or component name with "Component"
|
|
||||||
- Even though the code has examples of it, we are ending the practice.
|
|
||||||
|
|
||||||
## Libraries
|
|
||||||
|
|
||||||
⚠️ YOU SHOULD NOT
|
|
||||||
|
|
||||||
- Add new libraries to package.json.
|
|
||||||
- Adding libraries may bring in code that explodes the bundled size or attempts to run NodeJS code in the browser
|
|
||||||
- Consult with project owners for help with library selection if one is needed
|
|
||||||
|
|
||||||
⛔️ DO NOT
|
|
||||||
|
|
||||||
- Use underscore.js
|
|
||||||
- Much of this library is now native to JS and will be automatically transpiled
|
|
||||||
- Use jQuery
|
|
||||||
- Much of this library is not native to the DOM.
|
|
||||||
- We are planning to remove it
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
⛔️ DO NOT
|
|
||||||
|
|
||||||
- Decrease test coverage
|
|
||||||
- Unit/Functional test coverage is checked as part of the CI process
|
|
||||||
|
|
||||||
### Unit Tests
|
|
||||||
|
|
||||||
✅ DO
|
|
||||||
|
|
||||||
- Write unit tests for non-UI and utility code.
|
|
||||||
- Write your tests using [Jest](https://jestjs.io/)
|
|
||||||
|
|
||||||
☑️ YOU SHOULD
|
|
||||||
|
|
||||||
- Abstract non-UI and utility code so it can run either the NodeJS or Browser environment
|
|
||||||
|
|
||||||
### Functional(Component) Tests
|
|
||||||
|
|
||||||
✅ DO
|
|
||||||
|
|
||||||
- Write tests for UI components
|
|
||||||
- Write your tests using [Jest](https://jestjs.io/)
|
|
||||||
- Use either Enzyme or React Testing Library to perform component tests.
|
|
||||||
|
|
||||||
### Mocking
|
|
||||||
|
|
||||||
✅ DO
|
|
||||||
|
|
||||||
- Use Jest's built-in mocking helpers
|
|
||||||
|
|
||||||
☑️ YOU SHOULD
|
|
||||||
|
|
||||||
- Write code that does not require mocking
|
|
||||||
- Build components that do not require mocking extremely large or difficult to mock objects (like Explorer.ts). Pass _only_ what you need.
|
|
||||||
|
|
||||||
⛔️ DO NOT
|
|
||||||
|
|
||||||
- Use sinon.js for mocking
|
|
||||||
- Sinon has been deprecated and planned for removal
|
|
||||||
|
|
||||||
### End to End Tests
|
|
||||||
|
|
||||||
✅ DO
|
|
||||||
|
|
||||||
- Use [Playwright](https://github.com/microsoft/playwright) and [Jest](https://jestjs.io/)
|
|
||||||
- Write or modify an existing E2E test that covers the primary use case of any major feature.
|
|
||||||
- Use caution. Do not try to cover every case. End to End tests can be slow and brittle.
|
|
||||||
|
|
||||||
☑️ YOU SHOULD
|
|
||||||
|
|
||||||
- Write tests that use accessible attributes to perform actions. Role, Title, Label, etc
|
|
||||||
- More information https://testing-library.com/docs/queries/about#priority
|
|
||||||
|
|
||||||
⚠️ YOU SHOULD NOT
|
|
||||||
|
|
||||||
- Add test specfic `data-*` attributes to dom elements
|
|
||||||
- This is a common current practice, but one we would like to avoid in the future
|
|
||||||
- End to end tests need to use semantic HTML and accesible attributes to be truely end to end
|
|
||||||
- No user or screen reader actually navigates an app using `data-*` attributes
|
|
||||||
- Add arbitrary time delays to wait for page to render or element to be ready.
|
|
||||||
- All the time delays add up and slow down testing.
|
|
||||||
- Prefer using the framework's "wait for..." functionality.
|
|
||||||
|
|
||||||
### Migrating Knockout to React
|
|
||||||
|
|
||||||
✅ DO
|
|
||||||
|
|
||||||
- Consult other team members before beginning migration work. There is a significant amount of flux in patterns we are using and it is important we do not propagate incorrect patterns.
|
|
||||||
- Start by converting HTML to JSX: https://magic.reactjs.net/htmltojsx.htm. Add functionality as a second step.
|
|
||||||
|
|
||||||
☑️ YOU SHOULD
|
|
||||||
|
|
||||||
- Write React components that require no dependency on Knockout or observables to trigger rendering.
|
|
||||||
|
|
||||||
## Browser Support
|
|
||||||
|
|
||||||
✅ DO
|
|
||||||
|
|
||||||
- Support all [browsers supported by the Azure Portal](https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-supported-browsers-devices)
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Contribution guidelines to Data Explorer
|
# Contribution guidelines to Data Explorer
|
||||||
|
|
||||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||||
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
||||||
|
|
||||||
@@ -13,7 +13,6 @@ For more information see the [Code of Conduct FAQ](https://opensource.microsoft.
|
|||||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||||
|
|
||||||
## Microsoft Open Source Code of Conduct
|
## Microsoft Open Source Code of Conduct
|
||||||
|
|
||||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||||
|
|
||||||
Resources:
|
Resources:
|
||||||
@@ -21,3 +20,33 @@ Resources:
|
|||||||
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
||||||
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||||
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
||||||
|
|
||||||
|
## Browser support
|
||||||
|
Please make sure to support all modern browsers as well as Internet Explorer 11.
|
||||||
|
For IE support, polyfill is preferred over new usage of lodash or underscore. We already polyfill almost everything by importing babel-polyfill at the top of entry points.
|
||||||
|
|
||||||
|
|
||||||
|
## Coding guidelines, conventions and recommendations
|
||||||
|
### Typescript
|
||||||
|
* Follow this [typescript style guide](https://github.com/excelmicro/typescript) which is based on [airbnb's style guide](https://github.com/airbnb/javascript).
|
||||||
|
* Conventions speficic to this project:
|
||||||
|
- Use double-quotes for string
|
||||||
|
- Don't use `null`, use `undefined`
|
||||||
|
- Pascal case for private static readonly fields
|
||||||
|
- Camel case for classnames in markup
|
||||||
|
* Don't use class unless necessary
|
||||||
|
* Code related to notebooks should be dynamically imported so that it is loaded from a separate bundle only if the account is notebook-enabled. There are already top-level notebook components which are dynamically imported and their dependencies can be statically imported from these files.
|
||||||
|
* Prefer using [Fluent UI controls](https://developer.microsoft.com/en-us/fluentui#/controls/web) over creating your own, in order to maintain consistency and support a11y.
|
||||||
|
|
||||||
|
### React
|
||||||
|
* Prefer using React class components over function components and hooks unless you have a simple component and require no nested functions:
|
||||||
|
* Nested functions may be harder to test independently
|
||||||
|
* Switching from function component to class component later mayb be painful
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
Any PR should not decrease testing coverage.
|
||||||
|
|
||||||
|
## Recommended Tools and VS Code extensions
|
||||||
|
* [Bookmarks](https://github.com/alefragnani/vscode-bookmarks)
|
||||||
|
* [Bracket pair colorizer](https://github.com/CoenraadS/Bracket-Pair-Colorizer-2)
|
||||||
|
* [GitHub Pull Requests and Issues](https://github.com/Microsoft/vscode-pull-request-github)
|
||||||
@@ -18,6 +18,7 @@ Run `npm start` to start the development server and automatically rebuild on cha
|
|||||||
### Hosted Development (https://cosmos.azure.com)
|
### Hosted Development (https://cosmos.azure.com)
|
||||||
|
|
||||||
- Visit: `https://localhost:1234/hostedExplorer.html`
|
- Visit: `https://localhost:1234/hostedExplorer.html`
|
||||||
|
- Local sign in via AAD will NOT work. Connection string only in dev mode. Use the Portal if you need AAD auth.
|
||||||
- The default webpack dev server configuration will proxy requests to the production portal backend: `https://main.documentdb.ext.azure.com`. This will allow you to use production connection strings on your local machine.
|
- The default webpack dev server configuration will proxy requests to the production portal backend: `https://main.documentdb.ext.azure.com`. This will allow you to use production connection strings on your local machine.
|
||||||
|
|
||||||
### Emulator Development
|
### Emulator Development
|
||||||
@@ -68,7 +69,7 @@ Jest and Puppeteer are used for end to end browser based tests and are contained
|
|||||||
|
|
||||||
We generally adhere to the release strategy [documented by the Azure SDK Guidelines](https://azure.github.io/azure-sdk/policies_repobranching.html#release-branches). Most releases should happen from the master branch. If master contains commits that cannot be released, you may create a release from a `release/` or `hotfix/` branch. See linked documentation for more details.
|
We generally adhere to the release strategy [documented by the Azure SDK Guidelines](https://azure.github.io/azure-sdk/policies_repobranching.html#release-branches). Most releases should happen from the master branch. If master contains commits that cannot be released, you may create a release from a `release/` or `hotfix/` branch. See linked documentation for more details.
|
||||||
|
|
||||||
### Architecture
|
### Architechture
|
||||||
|
|
||||||
[](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggTFJcbiAgaG9zdGVkKGh0dHBzOi8vY29zbW9zLmF6dXJlLmNvbSlcbiAgcG9ydGFsKFBvcnRhbClcbiAgZW11bGF0b3IoRW11bGF0b3IpXG4gIGFhZFtBQURdXG4gIHJlc291cmNlVG9rZW5bUmVzb3VyY2UgVG9rZW5dXG4gIGNvbm5lY3Rpb25TdHJpbmdbQ29ubmVjdGlvbiBTdHJpbmddXG4gIHBvcnRhbFRva2VuW0VuY3J5cHRlZCBQb3J0YWwgVG9rZW5dXG4gIG1hc3RlcktleVtNYXN0ZXIgS2V5XVxuICBhcm1bQVJNIFJlc291cmNlIFByb3ZpZGVyXVxuICBkYXRhcGxhbmVbRGF0YSBQbGFuZV1cbiAgcHJveHlbUG9ydGFsIEFQSSBQcm94eV1cbiAgc3FsW1NRTF1cbiAgbW9uZ29bTW9uZ29dXG4gIHRhYmxlc1tUYWJsZXNdXG4gIGNhc3NhbmRyYVtDYXNzYW5kcmFdXG4gIGdyYWZbR3JhcGhdXG5cblxuICBlbXVsYXRvciAtLT4gbWFzdGVyS2V5IC0tLS0-IGRhdGFwbGFuZVxuICBwb3J0YWwgLS0-IGFhZFxuICBob3N0ZWQgLS0-IHBvcnRhbFRva2VuICYgcmVzb3VyY2VUb2tlbiAmIGNvbm5lY3Rpb25TdHJpbmcgJiBhYWRcbiAgYWFkIC0tLT4gYXJtXG4gIGFhZCAtLS0-IGRhdGFwbGFuZVxuICBhYWQgLS0tPiBwcm94eVxuICByZXNvdXJjZVRva2VuIC0tLT4gc3FsIC0tPiBkYXRhcGxhbmVcbiAgcG9ydGFsVG9rZW4gLS0tPiBwcm94eVxuICBwcm94eSAtLT4gZGF0YXBsYW5lXG4gIGNvbm5lY3Rpb25TdHJpbmcgLS0-IHNxbCAmIG1vbmdvICYgY2Fzc2FuZHJhICYgZ3JhZiAmIHRhYmxlc1xuICBzcWwgLS0-IGRhdGFwbGFuZVxuICB0YWJsZXMgLS0-IGRhdGFwbGFuZVxuICBtb25nbyAtLT4gcHJveHlcbiAgY2Fzc2FuZHJhIC0tPiBwcm94eVxuICBncmFmIC0tPiBwcm94eVxuXG5cdFx0IiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifSwidXBkYXRlRWRpdG9yIjpmYWxzZX0)
|
[](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggTFJcbiAgaG9zdGVkKGh0dHBzOi8vY29zbW9zLmF6dXJlLmNvbSlcbiAgcG9ydGFsKFBvcnRhbClcbiAgZW11bGF0b3IoRW11bGF0b3IpXG4gIGFhZFtBQURdXG4gIHJlc291cmNlVG9rZW5bUmVzb3VyY2UgVG9rZW5dXG4gIGNvbm5lY3Rpb25TdHJpbmdbQ29ubmVjdGlvbiBTdHJpbmddXG4gIHBvcnRhbFRva2VuW0VuY3J5cHRlZCBQb3J0YWwgVG9rZW5dXG4gIG1hc3RlcktleVtNYXN0ZXIgS2V5XVxuICBhcm1bQVJNIFJlc291cmNlIFByb3ZpZGVyXVxuICBkYXRhcGxhbmVbRGF0YSBQbGFuZV1cbiAgcHJveHlbUG9ydGFsIEFQSSBQcm94eV1cbiAgc3FsW1NRTF1cbiAgbW9uZ29bTW9uZ29dXG4gIHRhYmxlc1tUYWJsZXNdXG4gIGNhc3NhbmRyYVtDYXNzYW5kcmFdXG4gIGdyYWZbR3JhcGhdXG5cblxuICBlbXVsYXRvciAtLT4gbWFzdGVyS2V5IC0tLS0-IGRhdGFwbGFuZVxuICBwb3J0YWwgLS0-IGFhZFxuICBob3N0ZWQgLS0-IHBvcnRhbFRva2VuICYgcmVzb3VyY2VUb2tlbiAmIGNvbm5lY3Rpb25TdHJpbmcgJiBhYWRcbiAgYWFkIC0tLT4gYXJtXG4gIGFhZCAtLS0-IGRhdGFwbGFuZVxuICBhYWQgLS0tPiBwcm94eVxuICByZXNvdXJjZVRva2VuIC0tLT4gc3FsIC0tPiBkYXRhcGxhbmVcbiAgcG9ydGFsVG9rZW4gLS0tPiBwcm94eVxuICBwcm94eSAtLT4gZGF0YXBsYW5lXG4gIGNvbm5lY3Rpb25TdHJpbmcgLS0-IHNxbCAmIG1vbmdvICYgY2Fzc2FuZHJhICYgZ3JhZiAmIHRhYmxlc1xuICBzcWwgLS0-IGRhdGFwbGFuZVxuICB0YWJsZXMgLS0-IGRhdGFwbGFuZVxuICBtb25nbyAtLT4gcHJveHlcbiAgY2Fzc2FuZHJhIC0tPiBwcm94eVxuICBncmFmIC0tPiBwcm94eVxuXG5cdFx0IiwibWVybWFpZCI6eyJ0aGVtZSI6ImRlZmF1bHQifSwidXBkYXRlRWRpdG9yIjpmYWxzZX0)
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
{
|
{
|
||||||
"JUNO_ENDPOINT": "https://tools-staging.cosmos.azure.com"
|
"JUNO_ENDPOINT": "https://tools-staging.cosmos.azure.com",
|
||||||
|
"ENABLE_GALLERY_PUBLISH": true
|
||||||
}
|
}
|
||||||
|
|||||||
10
externals/iframeResizer.contentWindow.min.js
vendored
10
externals/iframeResizer.contentWindow.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,13 +1,11 @@
|
|||||||
const isCI = require("is-ci");
|
const isCI = require("is-ci");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
exitOnPageError: false,
|
launch: {
|
||||||
launchOptions: {
|
|
||||||
headless: isCI,
|
headless: isCI,
|
||||||
slowMo: 10,
|
slowMo: 55,
|
||||||
timeout: 60000,
|
defaultViewport: null,
|
||||||
},
|
|
||||||
contextOptions: {
|
|
||||||
ignoreHTTPSErrors: true,
|
ignoreHTTPSErrors: true,
|
||||||
|
args: ["--disable-web-security"],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
5
jest.config.e2e.js
Normal file
5
jest.config.e2e.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
preset: "jest-puppeteer",
|
||||||
|
testMatch: ["<rootDir>/test/**/*.spec.[jt]s?(x)"],
|
||||||
|
setupFiles: ["dotenv/config"],
|
||||||
|
};
|
||||||
@@ -21,13 +21,17 @@ module.exports = {
|
|||||||
collectCoverage: true,
|
collectCoverage: true,
|
||||||
|
|
||||||
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
// An array of glob patterns indicating a set of files for which coverage information should be collected
|
||||||
collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}"],
|
// collectCoverageFrom: [
|
||||||
|
// "src/Common/Headers*"
|
||||||
|
// ],
|
||||||
|
|
||||||
// The directory where Jest should output its coverage files
|
// The directory where Jest should output its coverage files
|
||||||
coverageDirectory: "coverage",
|
coverageDirectory: "coverage",
|
||||||
|
|
||||||
// An array of regexp pattern strings used to skip coverage collection
|
// An array of regexp pattern strings used to skip coverage collection
|
||||||
coveragePathIgnorePatterns: ["/node_modules/"],
|
// coveragePathIgnorePatterns: [
|
||||||
|
// "/node_modules/"
|
||||||
|
// ],
|
||||||
|
|
||||||
// A list of reporter names that Jest uses when writing coverage reports
|
// A list of reporter names that Jest uses when writing coverage reports
|
||||||
coverageReporters: ["json", "text", "cobertura"],
|
coverageReporters: ["json", "text", "cobertura"],
|
||||||
@@ -35,10 +39,10 @@ module.exports = {
|
|||||||
// An object that configures minimum threshold enforcement for coverage results
|
// An object that configures minimum threshold enforcement for coverage results
|
||||||
coverageThreshold: {
|
coverageThreshold: {
|
||||||
global: {
|
global: {
|
||||||
branches: 25,
|
branches: 22,
|
||||||
functions: 25,
|
functions: 28,
|
||||||
lines: 30,
|
lines: 33,
|
||||||
statements: 30,
|
statements: 31,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -67,10 +71,9 @@ module.exports = {
|
|||||||
|
|
||||||
// A map from regular expressions to module names that allow to stub out resources with a single module
|
// A map from regular expressions to module names that allow to stub out resources with a single module
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
"^.*[.](svg|png|gif|less|css)$": "<rootDir>/mockModule",
|
"^.*[.](svg|png|gif|less)$": "<rootDir>/mockModule",
|
||||||
"@nteract/stateful-components/(.*)$": "<rootDir>/mockModule",
|
"worker-loader": "<rootDir>/mockModule",
|
||||||
"@fluentui/react/lib/(.*)$": "@fluentui/react/lib-commonjs/$1", // https://github.com/microsoft/fluentui/wiki/Version-8-release-notes
|
"office-ui-fabric-react/lib/(.*)$": "office-ui-fabric-react/lib-commonjs/$1", // https://github.com/OfficeDev/office-ui-fabric-react/wiki/Fabric-6-Release-Notes
|
||||||
"monaco-editor/(.*)$": "<rootDir>/__mocks__/monaco-editor",
|
|
||||||
"^dnd-core$": "dnd-core/dist/cjs",
|
"^dnd-core$": "dnd-core/dist/cjs",
|
||||||
"^react-dnd$": "react-dnd/dist/cjs",
|
"^react-dnd$": "react-dnd/dist/cjs",
|
||||||
"^react-dnd-html5-backend$": "react-dnd-html5-backend/dist/cjs",
|
"^react-dnd-html5-backend$": "react-dnd-html5-backend/dist/cjs",
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
preset: "jest-playwright-preset",
|
|
||||||
testMatch: ["<rootDir>/test/**/*.spec.[jt]s?(x)"],
|
|
||||||
setupFiles: ["dotenv/config"],
|
|
||||||
testEnvironment: "./test/playwrightEnv.js",
|
|
||||||
setupFilesAfterEnv: ["expect-playwright"],
|
|
||||||
};
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: wf_segoe-ui_normal;
|
font-family: wf_segoe-ui_normal;
|
||||||
src: local("Segoe UI"), url("../../fonts/segoe-ui/west-european/normal/latest.woff");
|
src: url("../../fonts/segoe-ui/west-european/normal/latest.woff");
|
||||||
}
|
}
|
||||||
|
|
||||||
@DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
|
@DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
|
||||||
|
|||||||
@@ -718,7 +718,7 @@ execute-sproc-params-pane {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.stored-procedure-tab {
|
stored-procedure-tab {
|
||||||
@ToggleHeight: 30px;
|
@ToggleHeight: 30px;
|
||||||
@ToggleWidth: 180px;
|
@ToggleWidth: 180px;
|
||||||
|
|
||||||
@@ -1757,7 +1757,7 @@ input::-webkit-calendar-picker-indicator {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.paneMainContent {
|
.contextual-pane .paneMainContent {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-left: 34px;
|
padding-left: 34px;
|
||||||
padding-right: 34px;
|
padding-right: 34px;
|
||||||
@@ -2099,7 +2099,7 @@ a:link {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
overflow-y: hidden;
|
overflow-y: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3085,7 +3085,3 @@ settings-pane {
|
|||||||
padding-left: @SmallSpace;
|
padding-left: @SmallSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.hiddenMain {
|
|
||||||
visibility: hidden;
|
|
||||||
height: 0px;
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
.resourceTree {
|
.resourceTree {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 20%;
|
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
.main {
|
.main {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
8339
package-lock.json
generated
8339
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
73
package.json
73
package.json
@@ -5,16 +5,14 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/arm-cosmosdb": "9.1.0",
|
"@azure/arm-cosmosdb": "9.1.0",
|
||||||
"@azure/cosmos": "3.10.5",
|
"@azure/cosmos": "3.9.0",
|
||||||
"@azure/cosmos-language-service": "0.0.5",
|
"@azure/cosmos-language-service": "0.0.5",
|
||||||
"@azure/identity": "1.2.1",
|
"@azure/identity": "1.2.1",
|
||||||
"@azure/ms-rest-nodeauth": "3.0.7",
|
|
||||||
"@babel/plugin-proposal-class-properties": "7.12.1",
|
"@babel/plugin-proposal-class-properties": "7.12.1",
|
||||||
"@babel/plugin-proposal-decorators": "7.12.12",
|
"@babel/plugin-proposal-decorators": "7.12.12",
|
||||||
"@fluentui/react": "8.14.3",
|
|
||||||
"@jupyterlab/services": "6.0.2",
|
"@jupyterlab/services": "6.0.2",
|
||||||
"@jupyterlab/terminal": "3.0.3",
|
"@jupyterlab/terminal": "3.0.3",
|
||||||
"@microsoft/applicationinsights-web": "2.6.1",
|
"@microsoft/applicationinsights-web": "2.5.9",
|
||||||
"@nteract/commutable": "7.4.2",
|
"@nteract/commutable": "7.4.2",
|
||||||
"@nteract/connected-components": "6.8.2",
|
"@nteract/connected-components": "6.8.2",
|
||||||
"@nteract/core": "15.1.0",
|
"@nteract/core": "15.1.0",
|
||||||
@@ -26,7 +24,7 @@
|
|||||||
"@nteract/iron-icons": "1.0.0",
|
"@nteract/iron-icons": "1.0.0",
|
||||||
"@nteract/jupyter-widgets": "2.0.0",
|
"@nteract/jupyter-widgets": "2.0.0",
|
||||||
"@nteract/logos": "1.0.0",
|
"@nteract/logos": "1.0.0",
|
||||||
"@nteract/markdown": "4.6.0",
|
"@nteract/markdown": "4.4.0",
|
||||||
"@nteract/monaco-editor": "3.2.2",
|
"@nteract/monaco-editor": "3.2.2",
|
||||||
"@nteract/octicons": "2.0.0",
|
"@nteract/octicons": "2.0.0",
|
||||||
"@nteract/outputs": "3.0.9",
|
"@nteract/outputs": "3.0.9",
|
||||||
@@ -43,11 +41,14 @@
|
|||||||
"@testing-library/jest-dom": "5.11.9",
|
"@testing-library/jest-dom": "5.11.9",
|
||||||
"@types/mkdirp": "1.0.1",
|
"@types/mkdirp": "1.0.1",
|
||||||
"@types/node-fetch": "2.5.7",
|
"@types/node-fetch": "2.5.7",
|
||||||
|
"@uifabric/react-cards": "0.109.110",
|
||||||
|
"@uifabric/styling": "7.13.7",
|
||||||
|
"abort-controller": "3.0.0",
|
||||||
"applicationinsights": "1.8.0",
|
"applicationinsights": "1.8.0",
|
||||||
|
"babel-polyfill": "6.26.0",
|
||||||
"bootstrap": "3.4.1",
|
"bootstrap": "3.4.1",
|
||||||
"canvas": "file:./canvas",
|
"canvas": "file:./canvas",
|
||||||
"clean-webpack-plugin": "0.1.19",
|
"clean-webpack-plugin": "0.1.19",
|
||||||
"clipboard-copy": "4.0.1",
|
|
||||||
"copy-webpack-plugin": "6.0.2",
|
"copy-webpack-plugin": "6.0.2",
|
||||||
"crossroads": "0.12.2",
|
"crossroads": "0.12.2",
|
||||||
"css-element-queries": "1.1.1",
|
"css-element-queries": "1.1.1",
|
||||||
@@ -56,8 +57,9 @@
|
|||||||
"datatables.net-dt": "1.10.19",
|
"datatables.net-dt": "1.10.19",
|
||||||
"date-fns": "1.29.0",
|
"date-fns": "1.29.0",
|
||||||
"dayjs": "1.8.19",
|
"dayjs": "1.8.19",
|
||||||
"dom-to-image": "2.6.0",
|
|
||||||
"dotenv": "8.2.0",
|
"dotenv": "8.2.0",
|
||||||
|
"es6-object-assign": "1.1.0",
|
||||||
|
"es6-symbol": "3.1.3",
|
||||||
"eslint-plugin-jest": "23.13.2",
|
"eslint-plugin-jest": "23.13.2",
|
||||||
"eslint-plugin-react": "7.20.0",
|
"eslint-plugin-react": "7.20.0",
|
||||||
"hasher": "1.2.0",
|
"hasher": "1.2.0",
|
||||||
@@ -65,7 +67,6 @@
|
|||||||
"i18next": "19.8.4",
|
"i18next": "19.8.4",
|
||||||
"i18next-browser-languagedetector": "6.0.1",
|
"i18next-browser-languagedetector": "6.0.1",
|
||||||
"i18next-http-backend": "1.0.23",
|
"i18next-http-backend": "1.0.23",
|
||||||
"iframe-resizer-react": "1.1.0",
|
|
||||||
"immutable": "4.0.0-rc.12",
|
"immutable": "4.0.0-rc.12",
|
||||||
"is-ci": "2.0.0",
|
"is-ci": "2.0.0",
|
||||||
"jquery": "3.5.1",
|
"jquery": "3.5.1",
|
||||||
@@ -74,11 +75,13 @@
|
|||||||
"knockout": "3.5.1",
|
"knockout": "3.5.1",
|
||||||
"mkdirp": "1.0.4",
|
"mkdirp": "1.0.4",
|
||||||
"monaco-editor": "0.18.1",
|
"monaco-editor": "0.18.1",
|
||||||
"ms": "2.1.3",
|
|
||||||
"msal": "1.4.4",
|
"msal": "1.4.4",
|
||||||
|
"object.entries": "1.1.0",
|
||||||
|
"office-ui-fabric-react": "7.134.1",
|
||||||
"p-retry": "4.2.0",
|
"p-retry": "4.2.0",
|
||||||
"plotly.js-cartesian-dist-min": "1.52.3",
|
"plotly.js-cartesian-dist-min": "1.52.3",
|
||||||
"post-robot": "10.0.42",
|
"promise-polyfill": "8.1.0",
|
||||||
|
"promise.prototype.finally": "3.1.0",
|
||||||
"q": "1.5.1",
|
"q": "1.5.1",
|
||||||
"react": "16.13.1",
|
"react": "16.13.1",
|
||||||
"react-animate-height": "2.0.8",
|
"react-animate-height": "2.0.8",
|
||||||
@@ -93,13 +96,15 @@
|
|||||||
"reflect-metadata": "0.1.13",
|
"reflect-metadata": "0.1.13",
|
||||||
"rx-jupyter": "5.5.12",
|
"rx-jupyter": "5.5.12",
|
||||||
"rxjs": "6.6.3",
|
"rxjs": "6.6.3",
|
||||||
"sanitize-html": "2.3.3",
|
|
||||||
"styled-components": "4.3.2",
|
"styled-components": "4.3.2",
|
||||||
"swr": "0.4.0",
|
"swr": "0.4.0",
|
||||||
"terser-webpack-plugin": "3.1.0",
|
"text-encoding": "0.7.0",
|
||||||
"underscore": "1.9.1",
|
"underscore": "1.9.1",
|
||||||
|
"url-polyfill": "1.1.7",
|
||||||
"utility-types": "3.10.0",
|
"utility-types": "3.10.0",
|
||||||
"zustand": "3.5.0"
|
"webcrypto-liner": "1.1.4",
|
||||||
|
"webfontloader": "1.6.28",
|
||||||
|
"whatwg-fetch": "3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.9.0",
|
"@babel/core": "7.9.0",
|
||||||
@@ -111,26 +116,30 @@
|
|||||||
"@types/codemirror": "0.0.56",
|
"@types/codemirror": "0.0.56",
|
||||||
"@types/crossroads": "0.0.30",
|
"@types/crossroads": "0.0.30",
|
||||||
"@types/d3": "5.9.2",
|
"@types/d3": "5.9.2",
|
||||||
"@types/dom-to-image": "2.6.2",
|
|
||||||
"@types/enzyme": "3.10.7",
|
"@types/enzyme": "3.10.7",
|
||||||
"@types/enzyme-adapter-react-16": "1.0.6",
|
"@types/enzyme-adapter-react-16": "1.0.6",
|
||||||
|
"@types/expect-puppeteer": "4.4.3",
|
||||||
"@types/hasher": "0.0.31",
|
"@types/hasher": "0.0.31",
|
||||||
"@types/jest": "26.0.20",
|
"@types/jest": "26.0.20",
|
||||||
|
"@types/jest-environment-puppeteer": "4.3.2",
|
||||||
"@types/memoize-one": "4.1.1",
|
"@types/memoize-one": "4.1.1",
|
||||||
"@types/node": "12.11.1",
|
"@types/node": "12.11.1",
|
||||||
"@types/post-robot": "10.0.1",
|
|
||||||
"@types/promise.prototype.finally": "2.0.3",
|
"@types/promise.prototype.finally": "2.0.3",
|
||||||
|
"@types/prop-types": "15.5.8",
|
||||||
|
"@types/puppeteer": "3.0.1",
|
||||||
"@types/q": "1.5.1",
|
"@types/q": "1.5.1",
|
||||||
"@types/react": "17.0.3",
|
"@types/react": "17.0.0",
|
||||||
"@types/react-dom": "17.0.3",
|
"@types/react-dom": "17.0.0",
|
||||||
"@types/react-notification-system": "0.2.39",
|
"@types/react-notification-system": "0.2.39",
|
||||||
"@types/react-redux": "7.1.7",
|
"@types/react-redux": "7.1.7",
|
||||||
"@types/sanitize-html": "1.27.2",
|
|
||||||
"@types/sinon": "2.3.3",
|
"@types/sinon": "2.3.3",
|
||||||
"@types/styled-components": "5.1.1",
|
"@types/styled-components": "5.1.1",
|
||||||
|
"@types/text-encoding": "0.0.33",
|
||||||
"@types/underscore": "1.7.36",
|
"@types/underscore": "1.7.36",
|
||||||
"@typescript-eslint/eslint-plugin": "4.22.0",
|
"@types/webfontloader": "1.6.29",
|
||||||
"@typescript-eslint/parser": "4.22.0",
|
"@typescript-eslint/eslint-plugin": "4.0.1",
|
||||||
|
"@typescript-eslint/parser": "4.0.1",
|
||||||
|
"axe-puppeteer": "1.1.0",
|
||||||
"babel-jest": "24.9.0",
|
"babel-jest": "24.9.0",
|
||||||
"babel-loader": "8.1.0",
|
"babel-loader": "8.1.0",
|
||||||
"buffer": "5.1.0",
|
"buffer": "5.1.0",
|
||||||
@@ -145,18 +154,17 @@
|
|||||||
"eslint-plugin-no-null": "1.0.2",
|
"eslint-plugin-no-null": "1.0.2",
|
||||||
"eslint-plugin-prefer-arrow": "1.2.2",
|
"eslint-plugin-prefer-arrow": "1.2.2",
|
||||||
"eslint-plugin-react-hooks": "4.2.0",
|
"eslint-plugin-react-hooks": "4.2.0",
|
||||||
"expect-playwright": "0.3.3",
|
|
||||||
"expose-loader": "0.7.5",
|
"expose-loader": "0.7.5",
|
||||||
"fast-glob": "3.2.5",
|
"fast-glob": "3.2.5",
|
||||||
"file-loader": "2.0.0",
|
"file-loader": "2.0.0",
|
||||||
"fs-extra": "7.0.0",
|
"fs-extra": "7.0.0",
|
||||||
"html-inline-css-webpack-plugin": "1.11.0",
|
|
||||||
"html-loader": "0.5.5",
|
"html-loader": "0.5.5",
|
||||||
"html-loader-jest": "0.2.1",
|
"html-loader-jest": "0.2.1",
|
||||||
"html-webpack-plugin": "4.5.2",
|
"html-webpack-plugin": "3.2.0",
|
||||||
|
"inline-css": "2.2.5",
|
||||||
"jest": "25.5.4",
|
"jest": "25.5.4",
|
||||||
"jest-canvas-mock": "2.1.0",
|
"jest-canvas-mock": "2.1.0",
|
||||||
"jest-playwright-preset": "1.5.1",
|
"jest-puppeteer": "4.4.0",
|
||||||
"jest-trx-results-processor": "0.0.7",
|
"jest-trx-results-processor": "0.0.7",
|
||||||
"less": "3.8.1",
|
"less": "3.8.1",
|
||||||
"less-loader": "4.1.0",
|
"less-loader": "4.1.0",
|
||||||
@@ -164,23 +172,24 @@
|
|||||||
"mini-css-extract-plugin": "0.4.3",
|
"mini-css-extract-plugin": "0.4.3",
|
||||||
"monaco-editor-webpack-plugin": "1.7.0",
|
"monaco-editor-webpack-plugin": "1.7.0",
|
||||||
"node-fetch": "2.6.1",
|
"node-fetch": "2.6.1",
|
||||||
"playwright": "1.10.0",
|
|
||||||
"prettier": "2.2.1",
|
"prettier": "2.2.1",
|
||||||
|
"puppeteer": "4.0.0",
|
||||||
"raw-loader": "0.5.1",
|
"raw-loader": "0.5.1",
|
||||||
"react-dev-utils": "11.0.4",
|
|
||||||
"rimraf": "3.0.0",
|
"rimraf": "3.0.0",
|
||||||
"sinon": "3.2.1",
|
"sinon": "3.2.1",
|
||||||
"style-loader": "0.23.0",
|
"style-loader": "0.23.0",
|
||||||
|
"terser-webpack-plugin": "3.0.5",
|
||||||
"ts-loader": "6.2.2",
|
"ts-loader": "6.2.2",
|
||||||
"tslint": "5.11.0",
|
"tslint": "5.11.0",
|
||||||
"tslint-microsoft-contrib": "6.0.0",
|
"tslint-microsoft-contrib": "6.0.0",
|
||||||
"typescript": "4.2.4",
|
"typescript": "4.0.2",
|
||||||
"url-loader": "1.1.1",
|
"url-loader": "1.1.1",
|
||||||
"wait-on": "4.0.2",
|
"wait-on": "4.0.2",
|
||||||
"webpack": "4.46.0",
|
"webpack": "4.43.0",
|
||||||
"webpack-bundle-analyzer": "3.6.1",
|
"webpack-bundle-analyzer": "3.6.1",
|
||||||
"webpack-cli": "3.3.10",
|
"webpack-cli": "3.3.10",
|
||||||
"webpack-dev-server": "3.11.0"
|
"webpack-dev-server": "3.11.0",
|
||||||
|
"worker-loader": "2.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --max-old-space-size=10196 node_modules/webpack-dev-server/bin/webpack-dev-server.js",
|
"start": "node --max-old-space-size=10196 node_modules/webpack-dev-server/bin/webpack-dev-server.js",
|
||||||
@@ -192,7 +201,7 @@
|
|||||||
"pack:fast": "node --max_old_space_size=10196 ./node_modules/webpack/bin/webpack.js --mode development --progress",
|
"pack:fast": "node --max_old_space_size=10196 ./node_modules/webpack/bin/webpack.js --mode development --progress",
|
||||||
"copyToConsumers": "node copyToConsumers",
|
"copyToConsumers": "node copyToConsumers",
|
||||||
"test": "rimraf coverage && jest",
|
"test": "rimraf coverage && jest",
|
||||||
"test:e2e": "jest -c ./jest.config.playwright.js --detectOpenHandles",
|
"test:e2e": "jest -c ./jest.config.e2e.js --detectOpenHandles",
|
||||||
"watch": "npm run start",
|
"watch": "npm run start",
|
||||||
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",
|
||||||
"build:ase": "gulp build:ase",
|
"build:ase": "gulp build:ase",
|
||||||
@@ -203,8 +212,8 @@
|
|||||||
"format:check": "prettier --check \"{src,test}/**/*.{ts,tsx,html}\" \"*.{js,html}\"",
|
"format:check": "prettier --check \"{src,test}/**/*.{ts,tsx,html}\" \"*.{js,html}\"",
|
||||||
"lint": "tslint --project tsconfig.json && eslint \"**/*.{ts,tsx}\"",
|
"lint": "tslint --project tsconfig.json && eslint \"**/*.{ts,tsx}\"",
|
||||||
"build:contracts": "npm run compile:contracts",
|
"build:contracts": "npm run compile:contracts",
|
||||||
"strict:find": "node ./strict-null-checks/find.js",
|
"strictEligibleFiles": "node ./strict-migration-tools/index.js",
|
||||||
"strict:add": "node ./strict-null-checks/auto-add.js",
|
"autoAddStrictEligibleFiles": "node ./strict-migration-tools/autoAdd.js",
|
||||||
"compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks",
|
"compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks",
|
||||||
"generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts"
|
"generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
[defaults]
|
|
||||||
group = stfaul
|
|
||||||
sku = P1v2
|
|
||||||
appserviceplan = stfaul_asp_Linux_centralus_0
|
|
||||||
location = centralus
|
|
||||||
web = cosmos-explorer-preview
|
|
||||||
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Cosmos Explorer Preview
|
|
||||||
|
|
||||||
Cosmos Explorer Preview makes it possible to try a working version of any commit on master or in a PR. No need to run the app locally or deploy to staging.
|
|
||||||
|
|
||||||
Initial support is for Hosted (Connection string only) or the Azure Portal. Examples:
|
|
||||||
|
|
||||||
Connection string URLs: https://cosmos-explorer-preview.azurewebsites.net/commit/COMMIT_SHA/hostedExplorer.html
|
|
||||||
Portal URLs: https://ms.portal.azure.com/?dataExplorerSource=https://cosmos-explorer-preview.azurewebsites.net/commit/COMMIT_SHA/explorer.html#home
|
|
||||||
|
|
||||||
In both cases replace `COMMIT_SHA` with the commit you want to view. It must have already completed its build on GitHub Actions.
|
|
||||||
|
|
||||||
### Architechture
|
|
||||||
|
|
||||||
- This folder contains a NodeJS app deployed to Azure App Service that powers preview URLs:
|
|
||||||
- Paths starting with `/commit/` are proxied to an Azure Storage account containing build artifacts
|
|
||||||
- Paths starting with `/proxy/` are proxied dynamically to Cosmos account endpoints. Required otherwise CORS would need to be configured for every account accessed.
|
|
||||||
- Paths starting with `/api/` are proxied to Portal APIs that do not support CORS.
|
|
||||||
- On GitHub Actions build completion:
|
|
||||||
- All files in dist are uploaded to an Azure Storage account namespaced by the SHA of the commit
|
|
||||||
- `/preview/config.json` is uploaded to the same folder with preview specific configuration
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"PROXY_PATH": "/proxy"
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
const express = require("express");
|
|
||||||
const { createProxyMiddleware } = require("http-proxy-middleware");
|
|
||||||
const port = process.env.PORT || 3000;
|
|
||||||
const fetch = require("node-fetch");
|
|
||||||
|
|
||||||
const api = createProxyMiddleware("/api", {
|
|
||||||
target: "https://main.documentdb.ext.azure.com",
|
|
||||||
changeOrigin: true,
|
|
||||||
logLevel: "debug",
|
|
||||||
bypass: (req, res) => {
|
|
||||||
if (req.method === "OPTIONS") {
|
|
||||||
res.statusCode = 200;
|
|
||||||
res.send();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const proxy = createProxyMiddleware("/proxy", {
|
|
||||||
target: "https://main.documentdb.ext.azure.com",
|
|
||||||
changeOrigin: true,
|
|
||||||
secure: false,
|
|
||||||
logLevel: "debug",
|
|
||||||
pathRewrite: { "^/proxy": "" },
|
|
||||||
router: (req) => {
|
|
||||||
let newTarget = req.headers["x-ms-proxy-target"];
|
|
||||||
return newTarget;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const commit = createProxyMiddleware("/commit", {
|
|
||||||
target: "https://cosmosexplorerpreview.blob.core.windows.net",
|
|
||||||
changeOrigin: true,
|
|
||||||
secure: false,
|
|
||||||
logLevel: "debug",
|
|
||||||
pathRewrite: { "^/commit": "$web/" },
|
|
||||||
});
|
|
||||||
|
|
||||||
const app = express();
|
|
||||||
|
|
||||||
app.use(api);
|
|
||||||
app.use(proxy);
|
|
||||||
app.use(commit);
|
|
||||||
app.get("/pull/:pr(\\d+)", (req, res) => {
|
|
||||||
const pr = req.params.pr;
|
|
||||||
const [, query] = req.originalUrl.split("?");
|
|
||||||
const search = new URLSearchParams(query);
|
|
||||||
|
|
||||||
fetch("https://api.github.com/repos/Azure/cosmos-explorer/pulls/" + pr)
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then(({ head: { ref, sha } }) => {
|
|
||||||
const prUrl = new URL("https://github.com/Azure/cosmos-explorer/pull/" + pr);
|
|
||||||
prUrl.hash = ref;
|
|
||||||
search.set("feature.pr", prUrl.href);
|
|
||||||
|
|
||||||
const explorer = new URL("https://cosmos-explorer-preview.azurewebsites.net/commit/" + sha + "/explorer.html");
|
|
||||||
explorer.search = search.toString();
|
|
||||||
|
|
||||||
const portal = new URL("https://ms.portal.azure.com/");
|
|
||||||
portal.searchParams.set("dataExplorerSource", explorer.href);
|
|
||||||
|
|
||||||
return res.redirect(portal.href);
|
|
||||||
})
|
|
||||||
.catch(() => res.sendStatus(500));
|
|
||||||
});
|
|
||||||
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log(`Example app listening on port: ${port}`);
|
|
||||||
});
|
|
||||||
1146
preview/package-lock.json
generated
1146
preview/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "cosmos-explorer-preview",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"deploy": "az webapp up -n cosmos-explorer-preview --subscription cosmosdb-portalteam-generaldemo -g stfaul",
|
|
||||||
"start": "node index.js",
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "Microsoft Corporation",
|
|
||||||
"dependencies": {
|
|
||||||
"express": "^4.17.1",
|
|
||||||
"http-proxy-middleware": "^1.1.0",
|
|
||||||
"node-fetch": "^2.6.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
"offerThroughput": 400,
|
"offerThroughput": 400,
|
||||||
"databaseLevelThroughput": false,
|
"databaseLevelThroughput": false,
|
||||||
"collectionId": "Persons",
|
"collectionId": "Persons",
|
||||||
"createNewDatabase": true,
|
|
||||||
"partitionKey": { "kind": "Hash", "paths": ["/name"] },
|
"partitionKey": { "kind": "Hash", "paths": ["/name"] },
|
||||||
"data": [
|
"data": [
|
||||||
"g.addV('person').property(id, '1').property('name', 'Eva').property('age', 44)",
|
"g.addV('person').property(id, '1').property('name', 'Eva').property('age', 44)",
|
||||||
|
|||||||
@@ -22,7 +22,13 @@ export interface ReactAdapter {
|
|||||||
export class Registerer {
|
export class Registerer {
|
||||||
public static register(): void {
|
public static register(): void {
|
||||||
ko.bindingHandlers.react = {
|
ko.bindingHandlers.react = {
|
||||||
init: (element: any, wrappedValueAccessor: () => any) => {
|
init: (
|
||||||
|
element: any,
|
||||||
|
wrappedValueAccessor: () => any,
|
||||||
|
allBindings?: ko.AllBindings,
|
||||||
|
viewModel?: any,
|
||||||
|
bindingContext?: ko.BindingContext
|
||||||
|
) => {
|
||||||
const adapter: ReactAdapter = wrappedValueAccessor();
|
const adapter: ReactAdapter = wrappedValueAccessor();
|
||||||
|
|
||||||
if (adapter.setElement) {
|
if (adapter.setElement) {
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
.schema-analyzer-cell-outputs {
|
|
||||||
padding: 10px 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mimic FluentUI8's DocumentCard style
|
|
||||||
.schema-analyzer-cell-output {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
padding: 14px 20px;
|
|
||||||
border: 1px solid rgb(237, 235, 233);
|
|
||||||
}
|
|
||||||
|
|
||||||
.schema-analyzer-cell-output:hover {
|
|
||||||
border-color: rgb(200, 198, 196);
|
|
||||||
box-shadow: inset 0 0 0 1px rgb(200, 198, 196)
|
|
||||||
}
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
import { createImmutableOutput, JSONObject, OnDiskOutput } from "@nteract/commutable";
|
|
||||||
// import outputs individually to avoid increasing the bundle size
|
|
||||||
import { KernelOutputError } from "@nteract/outputs/lib/components/kernel-output-error";
|
|
||||||
import { Output } from "@nteract/outputs/lib/components/output";
|
|
||||||
import { StreamText } from "@nteract/outputs/lib/components/stream-text";
|
|
||||||
import { ContentRef } from "@nteract/types";
|
|
||||||
import "bootstrap/dist/css/bootstrap.css";
|
|
||||||
import postRobot from "post-robot";
|
|
||||||
import * as React from "react";
|
|
||||||
import * as ReactDOM from "react-dom";
|
|
||||||
import "../../externals/iframeResizer.contentWindow.min.js"; // Required for iFrameResizer to work
|
|
||||||
import { SnapshotRequest } from "../Explorer/Notebook/NotebookComponent/types";
|
|
||||||
import "../Explorer/Notebook/NotebookRenderer/base.css";
|
|
||||||
import "../Explorer/Notebook/NotebookRenderer/default.css";
|
|
||||||
import { NotebookUtil } from "../Explorer/Notebook/NotebookUtil";
|
|
||||||
import "./CellOutputViewer.less";
|
|
||||||
import { TransformMedia } from "./TransformMedia";
|
|
||||||
|
|
||||||
export interface SnapshotResponse {
|
|
||||||
imageSrc: string;
|
|
||||||
requestId: string;
|
|
||||||
}
|
|
||||||
export interface CellOutputViewerProps {
|
|
||||||
id: string;
|
|
||||||
contentRef: ContentRef;
|
|
||||||
outputsContainerClassName: string;
|
|
||||||
outputClassName: string;
|
|
||||||
outputs: OnDiskOutput[];
|
|
||||||
onMetadataChange: (metadata: JSONObject, mediaType: string, index?: number) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onInit = async () => {
|
|
||||||
postRobot.on(
|
|
||||||
"props",
|
|
||||||
{
|
|
||||||
window: window.parent,
|
|
||||||
domain: window.location.origin,
|
|
||||||
},
|
|
||||||
(event) => {
|
|
||||||
// Typescript definition for event is wrong. So read props by casting to <any>
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const props = (event as any).data as CellOutputViewerProps;
|
|
||||||
const outputs = (
|
|
||||||
<div data-iframe-height className={props.outputsContainerClassName}>
|
|
||||||
{props.outputs?.map((output, index) => (
|
|
||||||
<div className={props.outputClassName} key={index}>
|
|
||||||
<Output output={createImmutableOutput(output)} key={index}>
|
|
||||||
<TransformMedia
|
|
||||||
output_type={"display_data"}
|
|
||||||
id={props.id}
|
|
||||||
contentRef={props.contentRef}
|
|
||||||
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
|
|
||||||
/>
|
|
||||||
<TransformMedia
|
|
||||||
output_type={"execute_result"}
|
|
||||||
id={props.id}
|
|
||||||
contentRef={props.contentRef}
|
|
||||||
onMetadataChange={(metadata, mediaType) => props.onMetadataChange(metadata, mediaType, index)}
|
|
||||||
/>
|
|
||||||
<KernelOutputError />
|
|
||||||
<StreamText />
|
|
||||||
</Output>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
ReactDOM.render(outputs, document.getElementById("cellOutput"));
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
postRobot.on(
|
|
||||||
"snapshotRequest",
|
|
||||||
{
|
|
||||||
window: window.parent,
|
|
||||||
domain: window.location.origin,
|
|
||||||
},
|
|
||||||
async (event): Promise<SnapshotResponse> => {
|
|
||||||
const topNode = document.getElementById("cellOutput");
|
|
||||||
if (!topNode) {
|
|
||||||
const errorMsg = "No top node to snapshot";
|
|
||||||
return Promise.reject(new Error(errorMsg));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Typescript definition for event is wrong. So read props by casting to <any>
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const snapshotRequest = (event as any).data as SnapshotRequest;
|
|
||||||
const result = await NotebookUtil.takeScreenshotDomToImage(
|
|
||||||
topNode,
|
|
||||||
snapshotRequest.aspectRatio,
|
|
||||||
undefined,
|
|
||||||
snapshotRequest.downloadFilename
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
imageSrc: result.imageSrc,
|
|
||||||
requestId: snapshotRequest.requestId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Entry point
|
|
||||||
window.addEventListener("load", onInit);
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
import { ImmutableDisplayData, ImmutableExecuteResult, JSONObject } from "@nteract/commutable";
|
|
||||||
// import outputs individually to avoid increasing the bundle size
|
|
||||||
import { HTML } from "@nteract/outputs/lib/components/media/html";
|
|
||||||
import { Image } from "@nteract/outputs/lib/components/media/image";
|
|
||||||
import { JavaScript } from "@nteract/outputs/lib/components/media/javascript";
|
|
||||||
import { Json } from "@nteract/outputs/lib/components/media/json";
|
|
||||||
import { LaTeX } from "@nteract/outputs/lib/components/media/latex";
|
|
||||||
import { Plain } from "@nteract/outputs/lib/components/media/plain";
|
|
||||||
import { SVG } from "@nteract/outputs/lib/components/media/svg";
|
|
||||||
import { ContentRef } from "@nteract/types";
|
|
||||||
import React, { Suspense } from "react";
|
|
||||||
|
|
||||||
const EmptyTransform = (): JSX.Element => <></>;
|
|
||||||
|
|
||||||
const displayOrder = [
|
|
||||||
"application/vnd.jupyter.widget-view+json",
|
|
||||||
"application/vnd.vega.v5+json",
|
|
||||||
"application/vnd.vega.v4+json",
|
|
||||||
"application/vnd.vega.v3+json",
|
|
||||||
"application/vnd.vega.v2+json",
|
|
||||||
"application/vnd.vegalite.v4+json",
|
|
||||||
"application/vnd.vegalite.v3+json",
|
|
||||||
"application/vnd.vegalite.v2+json",
|
|
||||||
"application/vnd.vegalite.v1+json",
|
|
||||||
"application/geo+json",
|
|
||||||
"application/vnd.plotly.v1+json",
|
|
||||||
"text/vnd.plotly.v1+html",
|
|
||||||
"application/x-nteract-model-debug+json",
|
|
||||||
"application/vnd.dataresource+json",
|
|
||||||
"application/vdom.v1+json",
|
|
||||||
"application/json",
|
|
||||||
"application/javascript",
|
|
||||||
"text/html",
|
|
||||||
"text/markdown",
|
|
||||||
"text/latex",
|
|
||||||
"image/svg+xml",
|
|
||||||
"image/gif",
|
|
||||||
"image/png",
|
|
||||||
"image/jpeg",
|
|
||||||
"text/plain",
|
|
||||||
];
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const transformsById = new Map<string, React.ComponentType<any>>([
|
|
||||||
["text/vnd.plotly.v1+html", React.lazy(() => import("@nteract/transform-plotly"))],
|
|
||||||
["application/vnd.plotly.v1+json", React.lazy(() => import("@nteract/transform-plotly"))],
|
|
||||||
["application/geo+json", EmptyTransform], // TODO: The geojson transform will likely need some work because of the basemap URL(s)
|
|
||||||
["application/x-nteract-model-debug+json", React.lazy(() => import("@nteract/transform-model-debug"))],
|
|
||||||
["application/vnd.dataresource+json", React.lazy(() => import("@nteract/data-explorer"))],
|
|
||||||
["application/vnd.jupyter.widget-view+json", React.lazy(() => import("./transforms/WidgetDisplay"))],
|
|
||||||
["application/vnd.vegalite.v1+json", React.lazy(() => import("./transforms/VegaLite1"))],
|
|
||||||
["application/vnd.vegalite.v2+json", React.lazy(() => import("./transforms/VegaLite2"))],
|
|
||||||
["application/vnd.vegalite.v3+json", React.lazy(() => import("./transforms/VegaLite3"))],
|
|
||||||
["application/vnd.vegalite.v4+json", React.lazy(() => import("./transforms/VegaLite4"))],
|
|
||||||
["application/vnd.vega.v2+json", React.lazy(() => import("./transforms/Vega2"))],
|
|
||||||
["application/vnd.vega.v3+json", React.lazy(() => import("./transforms/Vega3"))],
|
|
||||||
["application/vnd.vega.v4+json", React.lazy(() => import("./transforms/Vega4"))],
|
|
||||||
["application/vnd.vega.v5+json", React.lazy(() => import("./transforms/Vega5"))],
|
|
||||||
["application/vdom.v1+json", React.lazy(() => import("@nteract/transform-vdom"))],
|
|
||||||
["application/json", Json],
|
|
||||||
["application/javascript", JavaScript],
|
|
||||||
["text/html", HTML],
|
|
||||||
["text/markdown", React.lazy(() => import("@nteract/outputs/lib/components/media/markdown"))], // Markdown increases the bundle size so lazy load it
|
|
||||||
["text/latex", LaTeX],
|
|
||||||
["image/svg+xml", SVG],
|
|
||||||
["image/gif", Image],
|
|
||||||
["image/png", Image],
|
|
||||||
["image/jpeg", Image],
|
|
||||||
["text/plain", Plain],
|
|
||||||
]);
|
|
||||||
|
|
||||||
interface TransformMediaProps {
|
|
||||||
output_type: string;
|
|
||||||
id: string;
|
|
||||||
contentRef: ContentRef;
|
|
||||||
output?: ImmutableDisplayData | ImmutableExecuteResult;
|
|
||||||
onMetadataChange: (metadata: JSONObject, mediaType: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TransformMedia = (props: TransformMediaProps): JSX.Element => {
|
|
||||||
const { Media, mediaType, data, metadata } = getMediaInfo(props);
|
|
||||||
|
|
||||||
// If we had no valid result, return an empty output
|
|
||||||
if (!mediaType || !data) {
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Suspense fallback={<div>Loading...</div>}>
|
|
||||||
<Media
|
|
||||||
onMetadataChange={props.onMetadataChange}
|
|
||||||
data={data}
|
|
||||||
metadata={metadata}
|
|
||||||
contentRef={props.contentRef}
|
|
||||||
id={props.id}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getMediaInfo = (props: TransformMediaProps) => {
|
|
||||||
const { output, output_type } = props;
|
|
||||||
// This component should only be used with display data and execute result
|
|
||||||
if (!output || !(output_type === "display_data" || output_type === "execute_result")) {
|
|
||||||
console.warn("connected transform media managed to get a non media bundle output");
|
|
||||||
return {
|
|
||||||
Media: EmptyTransform,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the first mediaType in the output data that we support with a handler
|
|
||||||
const mediaType = displayOrder.find(
|
|
||||||
(key) =>
|
|
||||||
Object.prototype.hasOwnProperty.call(output.data, key) &&
|
|
||||||
(Object.prototype.hasOwnProperty.call(transformsById, key) || transformsById.get(key))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (mediaType) {
|
|
||||||
const metadata = output.metadata.get(mediaType);
|
|
||||||
const data = output.data[mediaType];
|
|
||||||
|
|
||||||
const Media = transformsById.get(mediaType);
|
|
||||||
return {
|
|
||||||
Media,
|
|
||||||
mediaType,
|
|
||||||
data,
|
|
||||||
metadata,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
Media: EmptyTransform,
|
|
||||||
mediaType,
|
|
||||||
output,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TransformMedia;
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="height=device-height, width=device-width, initial-scale=1.0" />
|
|
||||||
<title>Cell Output Viewer</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div class="cellOutput" id="cellOutput"></div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { Vega2 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { Vega3 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { Vega4 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { Vega5 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { VegaLite1 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { VegaLite2 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { VegaLite3 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { VegaLite4 as default } from "@nteract/transform-vega";
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export { WidgetDisplay as default } from "@nteract/jupyter-widgets";
|
|
||||||
@@ -1,9 +1,49 @@
|
|||||||
|
import { HashMap } from "./HashMap";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hash map of arrays which allows to:
|
* Hash map of arrays which allows to:
|
||||||
* - push an item by key: add to array and create array if needed
|
* - push an item by key: add to array and create array if needed
|
||||||
* - remove item by key: remove from array and delete array if needed
|
* - remove item by key: remove from array and delete array if needed
|
||||||
*/
|
*/
|
||||||
export class ArrayHashMap<T> extends Map<string, T[]> {
|
|
||||||
|
export class ArrayHashMap<T> {
|
||||||
|
private store: HashMap<T[]>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.store = new HashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public has(key: string): boolean {
|
||||||
|
return this.store.has(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(key: string): T[] {
|
||||||
|
return this.store.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public size(): number {
|
||||||
|
return this.store.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.store.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public keys(): string[] {
|
||||||
|
return this.store.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
public delete(key: string): boolean {
|
||||||
|
return this.store.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public forEach(key: string, iteratorFct: (value: T) => void) {
|
||||||
|
const values = this.store.get(key);
|
||||||
|
if (values) {
|
||||||
|
values.forEach((value) => iteratorFct(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert item into array.
|
* Insert item into array.
|
||||||
* If no array, create one.
|
* If no array, create one.
|
||||||
@@ -12,8 +52,16 @@ export class ArrayHashMap<T> extends Map<string, T[]> {
|
|||||||
* @param item
|
* @param item
|
||||||
*/
|
*/
|
||||||
public push(key: string, item: T): void {
|
public push(key: string, item: T): void {
|
||||||
const array = this.get(key);
|
let itemsArray: T[] = this.store.get(key);
|
||||||
array ? array.includes(item) || array.push(item) : this.set(key, [item]);
|
if (!itemsArray) {
|
||||||
|
itemsArray = [item];
|
||||||
|
this.store.set(key, itemsArray);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemsArray.indexOf(item) === -1) {
|
||||||
|
itemsArray.push(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,11 +70,18 @@ export class ArrayHashMap<T> extends Map<string, T[]> {
|
|||||||
* @param key
|
* @param key
|
||||||
* @param itemToRemove
|
* @param itemToRemove
|
||||||
*/
|
*/
|
||||||
public remove(key: string, itemToRemove: T): void {
|
public remove(key: string, itemToRemove: T) {
|
||||||
const array = this.get(key);
|
if (!this.store.has(key)) {
|
||||||
if (array) {
|
return;
|
||||||
const remaining = array.filter((item) => item !== itemToRemove);
|
}
|
||||||
remaining.length ? this.set(key, remaining) : this.delete(key);
|
|
||||||
|
const itemsArray = this.store.get(key);
|
||||||
|
const index = itemsArray.indexOf(itemToRemove);
|
||||||
|
if (index >= 0) {
|
||||||
|
itemsArray.splice(index, 1);
|
||||||
|
if (itemsArray.length === 0) {
|
||||||
|
this.store.delete(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
|
||||||
import arrowLeftImg from "../../images/imgarrowlefticon.svg";
|
|
||||||
|
|
||||||
export interface CollapsedResourceTreeProps {
|
|
||||||
toggleLeftPaneExpanded: () => void;
|
|
||||||
isLeftPaneExpanded: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CollapsedResourceTree: FunctionComponent<CollapsedResourceTreeProps> = ({
|
|
||||||
toggleLeftPaneExpanded,
|
|
||||||
isLeftPaneExpanded,
|
|
||||||
}: CollapsedResourceTreeProps): JSX.Element => {
|
|
||||||
return (
|
|
||||||
<div id="mini" className={!isLeftPaneExpanded ? "mini toggle-mini" : "hiddenMain"}>
|
|
||||||
<div className="main-nav nav">
|
|
||||||
<ul className="nav">
|
|
||||||
<li
|
|
||||||
className="resourceTreeCollapse"
|
|
||||||
id="collapseToggleLeftPaneButton"
|
|
||||||
role="button"
|
|
||||||
tabIndex={0}
|
|
||||||
aria-label="Expand Tree"
|
|
||||||
>
|
|
||||||
<span className="leftarrowCollapsed" onClick={toggleLeftPaneExpanded}>
|
|
||||||
<img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" />
|
|
||||||
</span>
|
|
||||||
<span className="collectionCollapsed" onClick={toggleLeftPaneExpanded}>
|
|
||||||
<span data-bind="text: collectionTitle" />
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -65,18 +65,28 @@ export class ClientDefaults {
|
|||||||
public static readonly arcadiaTokenRefreshIntervalPaddingMs: number = 2000;
|
public static readonly arcadiaTokenRefreshIntervalPaddingMs: number = 2000;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AccountKind {
|
export class AccountKind {
|
||||||
DocumentDB = "DocumentDB",
|
public static DocumentDB: string = "DocumentDB";
|
||||||
MongoDB = "MongoDB",
|
public static MongoDB: string = "MongoDB";
|
||||||
Parse = "Parse",
|
public static Parse: string = "Parse";
|
||||||
GlobalDocumentDB = "GlobalDocumentDB",
|
public static GlobalDocumentDB: string = "GlobalDocumentDB";
|
||||||
Default = "DocumentDB",
|
public static Default: string = AccountKind.DocumentDB;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CorrelationBackend {
|
export class CorrelationBackend {
|
||||||
public static Url: string = "https://aka.ms/cosmosdbanalytics";
|
public static Url: string = "https://aka.ms/cosmosdbanalytics";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class DefaultAccountExperience {
|
||||||
|
public static DocumentDB: string = "DocumentDB";
|
||||||
|
public static Graph: string = "Graph";
|
||||||
|
public static MongoDB: string = "MongoDB";
|
||||||
|
public static ApiForMongoDB: string = "Azure Cosmos DB for MongoDB API";
|
||||||
|
public static Table: string = "Table";
|
||||||
|
public static Cassandra: string = "Cassandra";
|
||||||
|
public static Default: string = DefaultAccountExperience.DocumentDB;
|
||||||
|
}
|
||||||
|
|
||||||
export class CapabilityNames {
|
export class CapabilityNames {
|
||||||
public static EnableTable: string = "EnableTable";
|
public static EnableTable: string = "EnableTable";
|
||||||
public static EnableGremlin: string = "EnableGremlin";
|
public static EnableGremlin: string = "EnableGremlin";
|
||||||
@@ -88,13 +98,39 @@ export class CapabilityNames {
|
|||||||
public static readonly EnableServerless: string = "EnableServerless";
|
public static readonly EnableServerless: string = "EnableServerless";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Features {
|
||||||
|
public static readonly cosmosdb = "cosmosdb";
|
||||||
|
public static readonly enableChangeFeedPolicy = "enablechangefeedpolicy";
|
||||||
|
public static readonly executeSproc = "dataexplorerexecutesproc";
|
||||||
|
public static readonly hostedDataExplorer = "hosteddataexplorerenabled";
|
||||||
|
public static readonly enableTtl = "enablettl";
|
||||||
|
public static readonly enableNotebooks = "enablenotebooks";
|
||||||
|
public static readonly enableGalleryPublish = "enablegallerypublish";
|
||||||
|
public static readonly enableLinkInjection = "enablelinkinjection";
|
||||||
|
public static readonly enableSpark = "enablespark";
|
||||||
|
public static readonly livyEndpoint = "livyendpoint";
|
||||||
|
public static readonly notebookServerUrl = "notebookserverurl";
|
||||||
|
public static readonly notebookServerToken = "notebookservertoken";
|
||||||
|
public static readonly notebookBasePath = "notebookbasepath";
|
||||||
|
public static readonly canExceedMaximumValue = "canexceedmaximumvalue";
|
||||||
|
public static readonly enableFixedCollectionWithSharedThroughput = "enablefixedcollectionwithsharedthroughput";
|
||||||
|
public static readonly ttl90Days = "ttl90days";
|
||||||
|
public static readonly enableRightPanelV2 = "enablerightpanelv2";
|
||||||
|
public static readonly enableSchema = "enableschema";
|
||||||
|
public static readonly enableSDKoperations = "enablesdkoperations";
|
||||||
|
public static readonly showMinRUSurvey = "showminrusurvey";
|
||||||
|
public static readonly enableDatabaseSettingsTabV1 = "enabledbsettingsv1";
|
||||||
|
public static readonly selfServeType = "selfservetype";
|
||||||
|
public static readonly enableKOPanel = "enablekopanel";
|
||||||
|
}
|
||||||
|
|
||||||
// flight names returned from the portal are always lowercase
|
// flight names returned from the portal are always lowercase
|
||||||
export class Flights {
|
export class Flights {
|
||||||
public static readonly SettingsV2 = "settingsv2";
|
public static readonly SettingsV2 = "settingsv2";
|
||||||
public static readonly MongoIndexEditor = "mongoindexeditor";
|
public static readonly MongoIndexEditor = "mongoindexeditor";
|
||||||
public static readonly MongoIndexing = "mongoindexing";
|
public static readonly MongoIndexing = "mongoindexing";
|
||||||
public static readonly AutoscaleTest = "autoscaletest";
|
public static readonly AutoscaleTest = "autoscaletest";
|
||||||
public static readonly SchemaAnalyzer = "schemaanalyzer";
|
public static readonly GalleryPublish = "gallerypublish";
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AfecFeatures {
|
export class AfecFeatures {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ResourceType } from "@azure/cosmos/dist-esm/common/constants";
|
import { ResourceType } from "@azure/cosmos/dist-esm/common/constants";
|
||||||
import { Platform, resetConfigContext, updateConfigContext } from "../ConfigContext";
|
import { configContext, Platform, updateConfigContext, resetConfigContext } from "../ConfigContext";
|
||||||
import { updateUserContext } from "../UserContext";
|
import { updateUserContext } from "../UserContext";
|
||||||
import { endpoint, getTokenFromAuthService, requestPlugin, tokenProvider } from "./CosmosClient";
|
import { endpoint, getTokenFromAuthService, requestPlugin, tokenProvider } from "./CosmosClient";
|
||||||
|
|
||||||
@@ -91,6 +91,7 @@ describe("endpoint", () => {
|
|||||||
location: "foo",
|
location: "foo",
|
||||||
type: "foo",
|
type: "foo",
|
||||||
kind: "foo",
|
kind: "foo",
|
||||||
|
tags: [],
|
||||||
properties: {
|
properties: {
|
||||||
documentEndpoint: "bar",
|
documentEndpoint: "bar",
|
||||||
gremlinEndpoint: "foo",
|
gremlinEndpoint: "foo",
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import * as Cosmos from "@azure/cosmos";
|
import * as Cosmos from "@azure/cosmos";
|
||||||
import { RequestInfo, setAuthorizationTokenHeaderUsingMasterKey } from "@azure/cosmos";
|
import { RequestInfo, setAuthorizationTokenHeaderUsingMasterKey } from "@azure/cosmos";
|
||||||
import { configContext, Platform } from "../ConfigContext";
|
import { configContext, Platform } from "../ConfigContext";
|
||||||
import { userContext } from "../UserContext";
|
import { getErrorMessage } from "./ErrorHandlingUtils";
|
||||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
||||||
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
|
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
|
||||||
import { getErrorMessage } from "./ErrorHandlingUtils";
|
import { userContext } from "../UserContext";
|
||||||
|
|
||||||
const _global = typeof self === "undefined" ? window : self;
|
const _global = typeof self === "undefined" ? window : self;
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ export const tokenProvider = async (requestInfo: RequestInfo) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const requestPlugin: Cosmos.Plugin<any> = async (requestContext, next) => {
|
export const requestPlugin: Cosmos.Plugin<any> = async (requestContext, next) => {
|
||||||
requestContext.endpoint = new URL(configContext.PROXY_PATH, window.location.href).href;
|
requestContext.endpoint = configContext.PROXY_PATH;
|
||||||
requestContext.headers["x-ms-proxy-target"] = endpoint();
|
requestContext.headers["x-ms-proxy-target"] = endpoint();
|
||||||
return next(requestContext);
|
return next(requestContext);
|
||||||
};
|
};
|
||||||
@@ -43,7 +43,12 @@ export const endpoint = () => {
|
|||||||
const location = _global.parent ? _global.parent.location : _global.location;
|
const location = _global.parent ? _global.parent.location : _global.location;
|
||||||
return configContext.EMULATOR_ENDPOINT || location.origin;
|
return configContext.EMULATOR_ENDPOINT || location.origin;
|
||||||
}
|
}
|
||||||
return userContext.endpoint || userContext?.databaseAccount?.properties?.documentEndpoint;
|
return (
|
||||||
|
userContext.endpoint ||
|
||||||
|
(userContext.databaseAccount &&
|
||||||
|
userContext.databaseAccount.properties &&
|
||||||
|
userContext.databaseAccount.properties.documentEndpoint)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getTokenFromAuthService(verb: string, resourceType: string, resourceId?: string): Promise<any> {
|
export async function getTokenFromAuthService(verb: string, resourceType: string, resourceId?: string): Promise<any> {
|
||||||
@@ -70,10 +75,7 @@ export async function getTokenFromAuthService(verb: string, resourceType: string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _client: Cosmos.CosmosClient;
|
|
||||||
|
|
||||||
export function client(): Cosmos.CosmosClient {
|
export function client(): Cosmos.CosmosClient {
|
||||||
if (_client) return _client;
|
|
||||||
const options: Cosmos.CosmosClientOptions = {
|
const options: Cosmos.CosmosClientOptions = {
|
||||||
endpoint: endpoint() || "https://cosmos.azure.com", // CosmosClient gets upset if we pass a bad URL. This should never actually get called
|
endpoint: endpoint() || "https://cosmos.azure.com", // CosmosClient gets upset if we pass a bad URL. This should never actually get called
|
||||||
key: userContext.masterKey,
|
key: userContext.masterKey,
|
||||||
@@ -87,6 +89,5 @@ export function client(): Cosmos.CosmosClient {
|
|||||||
if (configContext.PROXY_PATH !== undefined) {
|
if (configContext.PROXY_PATH !== undefined) {
|
||||||
(options as any).plugins = [{ on: "request", plugin: requestPlugin }];
|
(options as any).plugins = [{ on: "request", plugin: requestPlugin }];
|
||||||
}
|
}
|
||||||
_client = new Cosmos.CosmosClient(options);
|
return new Cosmos.CosmosClient(options);
|
||||||
return _client;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import { DefaultAccountExperienceType } from "../DefaultAccountExperienceType";
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
|
|
||||||
export const getEntityName = (): string => {
|
export const getEntityName = (): string => {
|
||||||
if (userContext.apiType === "Mongo") {
|
if (userContext.defaultExperience === DefaultAccountExperienceType.MongoDB) {
|
||||||
return "document";
|
return "document";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
import { DatePicker, TextField } from "@fluentui/react";
|
|
||||||
import React, { FunctionComponent } from "react";
|
|
||||||
|
|
||||||
export interface TableEntityProps {
|
|
||||||
entityValueLabel?: string;
|
|
||||||
entityValuePlaceholder: string;
|
|
||||||
entityValue: string | Date;
|
|
||||||
isEntityTypeDate: boolean;
|
|
||||||
isEntityValueDisable?: boolean;
|
|
||||||
entityTimeValue: string;
|
|
||||||
entityValueType: string;
|
|
||||||
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
onSelectDate: (date: Date | null | undefined) => void;
|
|
||||||
onEntityTimeValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const EntityValue: FunctionComponent<TableEntityProps> = ({
|
|
||||||
entityValueLabel,
|
|
||||||
entityValuePlaceholder,
|
|
||||||
entityValue,
|
|
||||||
isEntityTypeDate,
|
|
||||||
entityTimeValue,
|
|
||||||
entityValueType,
|
|
||||||
onEntityValueChange,
|
|
||||||
onSelectDate,
|
|
||||||
isEntityValueDisable,
|
|
||||||
onEntityTimeValueChange,
|
|
||||||
}: TableEntityProps): JSX.Element => {
|
|
||||||
if (isEntityTypeDate) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<DatePicker
|
|
||||||
className="addEntityDatePicker"
|
|
||||||
placeholder={entityValuePlaceholder}
|
|
||||||
value={entityValue && new Date(entityValue)}
|
|
||||||
ariaLabel={entityValuePlaceholder}
|
|
||||||
onSelectDate={onSelectDate}
|
|
||||||
disabled={isEntityValueDisable}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label={entityValueLabel && entityValueLabel}
|
|
||||||
id="entityTimeId"
|
|
||||||
autoFocus
|
|
||||||
type="time"
|
|
||||||
value={entityTimeValue}
|
|
||||||
onChange={onEntityTimeValueChange}
|
|
||||||
disabled={isEntityValueDisable}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TextField
|
|
||||||
label={entityValueLabel && entityValueLabel}
|
|
||||||
className="addEntityTextField"
|
|
||||||
id="entityValueId"
|
|
||||||
autoFocus
|
|
||||||
disabled={isEntityValueDisable}
|
|
||||||
type={entityValueType}
|
|
||||||
placeholder={entityValuePlaceholder}
|
|
||||||
value={typeof entityValue === "string" && entityValue}
|
|
||||||
onChange={onEntityValueChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
|
import { ARMError } from "../Utils/arm/request";
|
||||||
|
import { HttpStatusCodes } from "./Constants";
|
||||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
import { SubscriptionType } from "../Contracts/SubscriptionType";
|
import { SubscriptionType } from "../Contracts/SubscriptionType";
|
||||||
import { userContext } from "../UserContext";
|
|
||||||
import { ARMError } from "../Utils/arm/request";
|
|
||||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
||||||
import { HttpStatusCodes } from "./Constants";
|
|
||||||
import { logError } from "./Logger";
|
import { logError } from "./Logger";
|
||||||
import { sendMessage } from "./MessageHandler";
|
import { sendMessage } from "./MessageHandler";
|
||||||
|
|
||||||
@@ -45,7 +44,7 @@ const sendNotificationForError = (errorMessage: string, errorCode: number | stri
|
|||||||
|
|
||||||
const replaceKnownError = (errorMessage: string): string => {
|
const replaceKnownError = (errorMessage: string): string => {
|
||||||
if (
|
if (
|
||||||
userContext.subscriptionType === SubscriptionType.Internal &&
|
window.dataExplorer?.subscriptionType() === SubscriptionType.Internal &&
|
||||||
errorMessage?.indexOf("SharedOffer is Disabled for your account") >= 0
|
errorMessage?.indexOf("SharedOffer is Disabled for your account") >= 0
|
||||||
) {
|
) {
|
||||||
return "Database throughput is not supported for internal subscriptions.";
|
return "Database throughput is not supported for internal subscriptions.";
|
||||||
|
|||||||
70
src/Common/HashMap.test.ts
Normal file
70
src/Common/HashMap.test.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import { HashMap } from "./HashMap";
|
||||||
|
|
||||||
|
describe("HashMap", () => {
|
||||||
|
it("should test if key/val exists", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 123);
|
||||||
|
|
||||||
|
expect(map.has("a")).toBe(true);
|
||||||
|
expect(map.has("b")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should get object back", () => {
|
||||||
|
const map = new HashMap<string>();
|
||||||
|
map.set("a", "123");
|
||||||
|
map.set("a", "456");
|
||||||
|
|
||||||
|
expect(map.get("a")).toBe("456");
|
||||||
|
expect(map.get("a")).not.toBe("123");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return the right size", () => {
|
||||||
|
const map = new HashMap<string>();
|
||||||
|
map.set("a", "123");
|
||||||
|
map.set("b", "456");
|
||||||
|
|
||||||
|
expect(map.size()).toBe(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be iterable", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 1);
|
||||||
|
map.set("b", 10);
|
||||||
|
map.set("c", 100);
|
||||||
|
map.set("d", 1000);
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
map.forEach((key: string, value: number) => {
|
||||||
|
i += value;
|
||||||
|
});
|
||||||
|
expect(i).toBe(1111);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be deleted", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 1);
|
||||||
|
map.set("b", 10);
|
||||||
|
|
||||||
|
expect(map.delete("a")).toBe(true);
|
||||||
|
expect(map.delete("c")).toBe(false);
|
||||||
|
expect(map.has("a")).toBe(false);
|
||||||
|
expect(map.has("b")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should clear", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 1);
|
||||||
|
map.clear();
|
||||||
|
expect(map.size()).toBe(0);
|
||||||
|
expect(map.has("a")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return all keys", () => {
|
||||||
|
const map = new HashMap<number>();
|
||||||
|
map.set("a", 1);
|
||||||
|
map.set("b", 1);
|
||||||
|
expect(map.keys()).toEqual(["a", "b"]);
|
||||||
|
map.clear();
|
||||||
|
expect(map.keys().length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
45
src/Common/HashMap.ts
Normal file
45
src/Common/HashMap.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Simple hashmap implementation that doesn't rely on ES6 Map nor polyfills
|
||||||
|
*/
|
||||||
|
export class HashMap<T> {
|
||||||
|
constructor(private container: { [key: string]: T } = {}) {}
|
||||||
|
|
||||||
|
public has(key: string): boolean {
|
||||||
|
return this.container.hasOwnProperty(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public set(key: string, value: T): void {
|
||||||
|
this.container[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(key: string): T {
|
||||||
|
return this.container[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
public size(): number {
|
||||||
|
return Object.keys(this.container).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public delete(key: string): boolean {
|
||||||
|
if (this.has(key)) {
|
||||||
|
delete this.container[key];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this.container = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public keys(): string[] {
|
||||||
|
return Object.keys(this.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public forEach(iteratorFct: (key: string, value: T) => void) {
|
||||||
|
for (const k in this.container) {
|
||||||
|
iteratorFct(k, this.container[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,28 @@
|
|||||||
|
import * as Constants from "./Constants";
|
||||||
|
|
||||||
import { LocalStorageUtility, StorageKey } from "../Shared/StorageUtility";
|
import { LocalStorageUtility, StorageKey } from "../Shared/StorageUtility";
|
||||||
|
|
||||||
|
// x-ms-resource-quota: databases = 100; collections = 5000; users = 500000; permissions = 2000000;
|
||||||
|
export function getQuota(responseHeaders: any): any {
|
||||||
|
return responseHeaders && responseHeaders[Constants.HttpHeaders.resourceQuota]
|
||||||
|
? parseStringIntoObject(responseHeaders[Constants.HttpHeaders.resourceQuota])
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
export function shouldEnableCrossPartitionKey(): boolean {
|
export function shouldEnableCrossPartitionKey(): boolean {
|
||||||
return LocalStorageUtility.getEntryString(StorageKey.IsCrossPartitionQueryEnabled) === "true";
|
return LocalStorageUtility.getEntryString(StorageKey.IsCrossPartitionQueryEnabled) === "true";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function parseStringIntoObject(resourceString: string) {
|
||||||
|
var entityObject: any = {};
|
||||||
|
|
||||||
|
if (resourceString) {
|
||||||
|
var entitiesArray: string[] = resourceString.split(";");
|
||||||
|
for (var i: any = 0; i < entitiesArray.length; i++) {
|
||||||
|
var entity: string[] = entitiesArray[i].split("=");
|
||||||
|
entityObject[entity[0]] = entity[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return entityObject;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { QueryResults } from "../Contracts/ViewModels";
|
import { QueryResults } from "../Contracts/ViewModels";
|
||||||
|
|
||||||
interface QueryResponse {
|
interface QueryResponse {
|
||||||
// [Todo] remove any
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
resources: any[];
|
resources: any[];
|
||||||
hasMoreResults: boolean;
|
hasMoreResults: boolean;
|
||||||
activityId: string;
|
activityId: string;
|
||||||
@@ -18,7 +16,6 @@ export interface MinimalQueryIterator {
|
|||||||
export function nextPage(documentsIterator: MinimalQueryIterator, firstItemIndex: number): Promise<QueryResults> {
|
export function nextPage(documentsIterator: MinimalQueryIterator, firstItemIndex: number): Promise<QueryResults> {
|
||||||
return documentsIterator.fetchNext().then((response) => {
|
return documentsIterator.fetchNext().then((response) => {
|
||||||
const documents = response.resources;
|
const documents = response.resources;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const headers = (response as any).headers || {}; // TODO this is a private key. Remove any
|
const headers = (response as any).headers || {}; // TODO this is a private key. Remove any
|
||||||
const itemCount = (documents && documents.length) || 0;
|
const itemCount = (documents && documents.length) || 0;
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { SeverityLevel } from "@microsoft/applicationinsights-web";
|
|
||||||
import { Diagnostics, MessageTypes } from "../Contracts/ExplorerContracts";
|
|
||||||
import { trackTrace } from "../Shared/appInsights";
|
|
||||||
import { sendMessage } from "./MessageHandler";
|
import { sendMessage } from "./MessageHandler";
|
||||||
|
import { Diagnostics, MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
|
import { appInsights } from "../Shared/appInsights";
|
||||||
|
import { SeverityLevel } from "@microsoft/applicationinsights-web";
|
||||||
|
|
||||||
// TODO: Move to a separate Diagnostics folder
|
// TODO: Move to a separate Diagnostics folder
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@@ -46,7 +46,7 @@ function _logEntry(entry: Diagnostics.LogEntry): void {
|
|||||||
return SeverityLevel.Information;
|
return SeverityLevel.Information;
|
||||||
}
|
}
|
||||||
})(entry.level);
|
})(entry.level);
|
||||||
trackTrace({ message: entry.message, severityLevel }, { area: entry.area });
|
appInsights.trackTrace({ message: entry.message, severityLevel }, { area: entry.area });
|
||||||
}
|
}
|
||||||
|
|
||||||
function _generateLogEntry(
|
function _generateLogEntry(
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
import Q from "q";
|
import Q from "q";
|
||||||
import * as _ from "underscore";
|
import * as _ from "underscore";
|
||||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
|
||||||
import { getDataExplorerWindow } from "../Utils/WindowUtils";
|
|
||||||
import * as Constants from "./Constants";
|
import * as Constants from "./Constants";
|
||||||
|
import { getDataExplorerWindow } from "../Utils/WindowUtils";
|
||||||
|
|
||||||
export interface CachedDataPromise<T> {
|
export interface CachedDataPromise<T> {
|
||||||
deferred: Q.Deferred<T>;
|
deferred: Q.Deferred<T>;
|
||||||
@@ -48,18 +48,17 @@ export function sendCachedDataMessage<TResponseDataModel>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function sendMessage(data: any): void {
|
export function sendMessage(data: any): void {
|
||||||
_sendMessage({
|
if (canSendMessage()) {
|
||||||
signature: "pcIframe",
|
// We try to find data explorer window first, then fallback to current window
|
||||||
data: data,
|
const portalChildWindow = getDataExplorerWindow(window) || window;
|
||||||
});
|
portalChildWindow.parent.postMessage(
|
||||||
}
|
{
|
||||||
|
signature: "pcIframe",
|
||||||
export function sendReadyMessage(): void {
|
data: data,
|
||||||
_sendMessage({
|
},
|
||||||
signature: "pcIframe",
|
portalChildWindow.document.referrer
|
||||||
kind: "ready",
|
);
|
||||||
data: "ready",
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function canSendMessage(): boolean {
|
export function canSendMessage(): boolean {
|
||||||
@@ -75,17 +74,3 @@ export function runGarbageCollector() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const _sendMessage = (message: any): void => {
|
|
||||||
if (canSendMessage()) {
|
|
||||||
// Portal window can receive messages from only child windows
|
|
||||||
const portalChildWindow = getDataExplorerWindow(window) || window;
|
|
||||||
if (portalChildWindow === window) {
|
|
||||||
// Current window is a child of portal, send message to portal window
|
|
||||||
portalChildWindow.parent.postMessage(message, portalChildWindow.document.referrer || "*");
|
|
||||||
} else {
|
|
||||||
// Current window is not a child of portal, send message to the child window instead (which is data explorer)
|
|
||||||
portalChildWindow.postMessage(message, portalChildWindow.location.origin || "*");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -220,6 +220,7 @@ describe("MongoProxyClient", () => {
|
|||||||
describe("getEndpoint", () => {
|
describe("getEndpoint", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
resetConfigContext();
|
resetConfigContext();
|
||||||
|
delete window.authType;
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
databaseAccount,
|
databaseAccount,
|
||||||
});
|
});
|
||||||
@@ -240,9 +241,7 @@ describe("MongoProxyClient", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns a guest endpoint", () => {
|
it("returns a guest endpoint", () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.EncryptedToken;
|
||||||
authType: AuthType.EncryptedToken,
|
|
||||||
});
|
|
||||||
const endpoint = getEndpoint();
|
const endpoint = getEndpoint();
|
||||||
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import { configContext } from "../ConfigContext";
|
|||||||
import * as DataModels from "../Contracts/DataModels";
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
import { Collection } from "../Contracts/ViewModels";
|
import { Collection } from "../Contracts/ViewModels";
|
||||||
|
import { ConsoleDataType } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||||
import { userContext } from "../UserContext";
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
|
|
||||||
import { ApiType, HttpHeaders, HttpStatusCodes } from "./Constants";
|
import { ApiType, HttpHeaders, HttpStatusCodes } from "./Constants";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
import { MinimalQueryIterator } from "./IteratorUtilities";
|
import { MinimalQueryIterator } from "./IteratorUtilities";
|
||||||
import { sendMessage } from "./MessageHandler";
|
import { sendMessage } from "./MessageHandler";
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ const defaultHeaders = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function authHeaders() {
|
function authHeaders() {
|
||||||
if (userContext.authType === AuthType.EncryptedToken) {
|
if (window.authType === AuthType.EncryptedToken) {
|
||||||
return { [HttpHeaders.guestAccessToken]: userContext.accessToken };
|
return { [HttpHeaders.guestAccessToken]: userContext.accessToken };
|
||||||
} else {
|
} else {
|
||||||
return { [HttpHeaders.authorization]: userContext.authorizationToken };
|
return { [HttpHeaders.authorization]: userContext.authorizationToken };
|
||||||
@@ -61,7 +62,7 @@ export function queryDocuments(
|
|||||||
query: string,
|
query: string,
|
||||||
continuationToken?: string
|
continuationToken?: string
|
||||||
): Promise<QueryResponse> {
|
): Promise<QueryResponse> {
|
||||||
const { databaseAccount } = userContext;
|
const databaseAccount = userContext.databaseAccount;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const params = {
|
const params = {
|
||||||
db: databaseId,
|
db: databaseId,
|
||||||
@@ -121,7 +122,7 @@ export function readDocument(
|
|||||||
collection: Collection,
|
collection: Collection,
|
||||||
documentId: DocumentId
|
documentId: DocumentId
|
||||||
): Promise<DataModels.DocumentId> {
|
): Promise<DataModels.DocumentId> {
|
||||||
const { databaseAccount } = userContext;
|
const databaseAccount = userContext.databaseAccount;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const idComponents = documentId.self.split("/");
|
const idComponents = documentId.self.split("/");
|
||||||
const path = idComponents.slice(0, 4).join("/");
|
const path = idComponents.slice(0, 4).join("/");
|
||||||
@@ -167,7 +168,7 @@ export function createDocument(
|
|||||||
partitionKeyProperty: string,
|
partitionKeyProperty: string,
|
||||||
documentContent: unknown
|
documentContent: unknown
|
||||||
): Promise<DataModels.DocumentId> {
|
): Promise<DataModels.DocumentId> {
|
||||||
const { databaseAccount } = userContext;
|
const databaseAccount = userContext.databaseAccount;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const params = {
|
const params = {
|
||||||
db: databaseId,
|
db: databaseId,
|
||||||
@@ -206,7 +207,7 @@ export function updateDocument(
|
|||||||
documentId: DocumentId,
|
documentId: DocumentId,
|
||||||
documentContent: string
|
documentContent: string
|
||||||
): Promise<DataModels.DocumentId> {
|
): Promise<DataModels.DocumentId> {
|
||||||
const { databaseAccount } = userContext;
|
const databaseAccount = userContext.databaseAccount;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const idComponents = documentId.self.split("/");
|
const idComponents = documentId.self.split("/");
|
||||||
const path = idComponents.slice(0, 5).join("/");
|
const path = idComponents.slice(0, 5).join("/");
|
||||||
@@ -247,7 +248,7 @@ export function updateDocument(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function deleteDocument(databaseId: string, collection: Collection, documentId: DocumentId): Promise<void> {
|
export function deleteDocument(databaseId: string, collection: Collection, documentId: DocumentId): Promise<void> {
|
||||||
const { databaseAccount } = userContext;
|
const databaseAccount = userContext.databaseAccount;
|
||||||
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
const resourceEndpoint = databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint;
|
||||||
const idComponents = documentId.self.split("/");
|
const idComponents = documentId.self.split("/");
|
||||||
const path = idComponents.slice(0, 5).join("/");
|
const path = idComponents.slice(0, 5).join("/");
|
||||||
@@ -289,7 +290,7 @@ export function deleteDocument(databaseId: string, collection: Collection, docum
|
|||||||
export function createMongoCollectionWithProxy(
|
export function createMongoCollectionWithProxy(
|
||||||
params: DataModels.CreateCollectionParams
|
params: DataModels.CreateCollectionParams
|
||||||
): Promise<DataModels.Collection> {
|
): Promise<DataModels.Collection> {
|
||||||
const { databaseAccount } = userContext;
|
const databaseAccount = userContext.databaseAccount;
|
||||||
const shardKey: string = params.partitionKey?.paths[0];
|
const shardKey: string = params.partitionKey?.paths[0];
|
||||||
const mongoParams: DataModels.MongoParameters = {
|
const mongoParams: DataModels.MongoParameters = {
|
||||||
resourceUrl: databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint,
|
resourceUrl: databaseAccount.properties.mongoEndpoint || databaseAccount.properties.documentEndpoint,
|
||||||
@@ -336,7 +337,7 @@ export function createMongoCollectionWithProxy(
|
|||||||
export function getEndpoint(): string {
|
export function getEndpoint(): string {
|
||||||
let url = (configContext.MONGO_BACKEND_ENDPOINT || configContext.BACKEND_ENDPOINT) + "/api/mongo/explorer";
|
let url = (configContext.MONGO_BACKEND_ENDPOINT || configContext.BACKEND_ENDPOINT) + "/api/mongo/explorer";
|
||||||
|
|
||||||
if (userContext.authType === AuthType.EncryptedToken) {
|
if (window.authType === AuthType.EncryptedToken) {
|
||||||
url = url.replace("api/mongo", "api/guest/mongo");
|
url = url.replace("api/mongo", "api/guest/mongo");
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
@@ -347,7 +348,10 @@ export function getEndpoint(): string {
|
|||||||
async function errorHandling(response: Response, action: string, params: unknown): Promise<void> {
|
async function errorHandling(response: Response, action: string, params: unknown): Promise<void> {
|
||||||
const errorMessage = await response.text();
|
const errorMessage = await response.text();
|
||||||
// Log the error where the user can see it
|
// Log the error where the user can see it
|
||||||
logConsoleError(`Error ${action}: ${errorMessage}, Payload: ${JSON.stringify(params)}`);
|
NotificationConsoleUtils.logConsoleMessage(
|
||||||
|
ConsoleDataType.Error,
|
||||||
|
`Error ${action}: ${errorMessage}, Payload: ${JSON.stringify(params)}`
|
||||||
|
);
|
||||||
if (response.status === HttpStatusCodes.Forbidden) {
|
if (response.status === HttpStatusCodes.Forbidden) {
|
||||||
sendMessage({ type: MessageTypes.ForbiddenError, reason: errorMessage });
|
sendMessage({ type: MessageTypes.ForbiddenError, reason: errorMessage });
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ describe("Object cache", () => {
|
|||||||
cache.set("b", 2);
|
cache.set("b", 2);
|
||||||
cache.set("c", 3);
|
cache.set("c", 3);
|
||||||
cache.set("d", 4);
|
cache.set("d", 4);
|
||||||
expect(cache.size).toBe(2);
|
expect(cache.size()).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should remove first added element to keep size at limit", () => {
|
it("should remove first added element to keep size at limit", () => {
|
||||||
|
|||||||
@@ -1,27 +1,56 @@
|
|||||||
export class ObjectCache<T> extends Map<string, T> {
|
import { HashMap } from "./HashMap";
|
||||||
constructor(private limit: number) {
|
|
||||||
|
export class ObjectCache<T> extends HashMap<T> {
|
||||||
|
private keyQueue: string[]; // Last touched key FIFO to purge cache if too big.
|
||||||
|
private maxNbElements: number;
|
||||||
|
|
||||||
|
public constructor(maxNbElements: number) {
|
||||||
super();
|
super();
|
||||||
|
this.keyQueue = [];
|
||||||
|
this.maxNbElements = maxNbElements;
|
||||||
|
this.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(key: string): T | undefined {
|
public clear(): void {
|
||||||
return this.touch(key);
|
super.clear();
|
||||||
|
this.keyQueue = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public set(key: string, value: T): this {
|
public get(key: string): T {
|
||||||
if (this.size === this.limit) {
|
this.markKeyAsTouched(key);
|
||||||
this.delete(this.keys().next().value);
|
return super.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public set(key: string, value: T): void {
|
||||||
|
super.set(key, value);
|
||||||
|
|
||||||
|
this.markKeyAsTouched(key);
|
||||||
|
|
||||||
|
if (super.size() > this.maxNbElements && key !== this.keyQueue[0]) {
|
||||||
|
this.reduceCacheSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.touch(key, value), this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private touch(key: string, value = super.get(key)) {
|
/**
|
||||||
// Map keeps (re) insertion order according to ES6 spec
|
* Invalidate elements to keep the total number below the limit
|
||||||
if (value) {
|
*/
|
||||||
this.delete(key);
|
private reduceCacheSize(): void {
|
||||||
super.set(key, value);
|
// remove a key
|
||||||
|
const oldKey = this.keyQueue.shift();
|
||||||
|
if (oldKey) {
|
||||||
|
super.delete(oldKey);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
/**
|
||||||
|
* Bubble up this key as new.
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
private markKeyAsTouched(key: string) {
|
||||||
|
const n = this.keyQueue.indexOf(key);
|
||||||
|
if (n > -1) {
|
||||||
|
this.keyQueue.splice(n, 1);
|
||||||
|
}
|
||||||
|
this.keyQueue.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { configContext, Platform } from "../ConfigContext";
|
|
||||||
import * as DataModels from "../Contracts/DataModels";
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
import * as ViewModels from "../Contracts/ViewModels";
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
import { userContext } from "../UserContext";
|
|
||||||
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
|
import { configContext, Platform } from "../ConfigContext";
|
||||||
|
|
||||||
const notificationsPath = () => {
|
const notificationsPath = () => {
|
||||||
switch (configContext.platform) {
|
switch (configContext.platform) {
|
||||||
@@ -20,7 +20,9 @@ export const fetchPortalNotifications = async (): Promise<DataModels.Notificatio
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { databaseAccount, resourceGroup, subscriptionId } = userContext;
|
const databaseAccount = userContext.databaseAccount;
|
||||||
|
const subscriptionId = userContext.subscriptionId;
|
||||||
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const url = `${configContext.BACKEND_ENDPOINT}${notificationsPath()}?accountName=${
|
const url = `${configContext.BACKEND_ENDPOINT}${notificationsPath()}?accountName=${
|
||||||
databaseAccount.name
|
databaseAccount.name
|
||||||
}&subscriptionId=${subscriptionId}&resourceGroup=${resourceGroup}`;
|
}&subscriptionId=${subscriptionId}&resourceGroup=${resourceGroup}`;
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import * as ViewModels from "../Contracts/ViewModels";
|
|||||||
import Explorer from "../Explorer/Explorer";
|
import Explorer from "../Explorer/Explorer";
|
||||||
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
|
import DocumentsTab from "../Explorer/Tabs/DocumentsTab";
|
||||||
import DocumentId from "../Explorer/Tree/DocumentId";
|
import DocumentId from "../Explorer/Tree/DocumentId";
|
||||||
import { userContext } from "../UserContext";
|
|
||||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
import * as QueryUtils from "../Utils/QueryUtils";
|
import { QueryUtils } from "../Utils/QueryUtils";
|
||||||
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
|
import { BackendDefaults, HttpStatusCodes, SavedQueries } from "./Constants";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
|
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
|
||||||
import { createCollection } from "./dataAccess/createCollection";
|
import { createCollection } from "./dataAccess/createCollection";
|
||||||
|
import { handleError } from "./ErrorHandlingUtils";
|
||||||
import { createDocument } from "./dataAccess/createDocument";
|
import { createDocument } from "./dataAccess/createDocument";
|
||||||
import { deleteDocument } from "./dataAccess/deleteDocument";
|
import { deleteDocument } from "./dataAccess/deleteDocument";
|
||||||
import { queryDocuments } from "./dataAccess/queryDocuments";
|
import { queryDocuments } from "./dataAccess/queryDocuments";
|
||||||
import { queryDocumentsPage } from "./dataAccess/queryDocumentsPage";
|
|
||||||
import { handleError } from "./ErrorHandlingUtils";
|
|
||||||
|
|
||||||
export class QueriesClient {
|
export class QueriesClient {
|
||||||
private static readonly PartitionKey: DataModels.PartitionKey = {
|
private static readonly PartitionKey: DataModels.PartitionKey = {
|
||||||
@@ -182,8 +182,11 @@ export class QueriesClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getResourceId(): string {
|
public getResourceId(): string {
|
||||||
const { databaseAccount, subscriptionId = "", resourceGroup = "" } = userContext;
|
const databaseAccount = userContext.databaseAccount;
|
||||||
const databaseAccountName = databaseAccount?.name || "";
|
const databaseAccountName = (databaseAccount && databaseAccount.name) || "";
|
||||||
|
const subscriptionId = userContext.subscriptionId || "";
|
||||||
|
const resourceGroup = userContext.resourceGroup || "";
|
||||||
|
|
||||||
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDb/databaseAccounts/${databaseAccountName}`;
|
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDb/databaseAccounts/${databaseAccountName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +211,7 @@ export class QueriesClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fetchQueriesQuery(): string {
|
private fetchQueriesQuery(): string {
|
||||||
if (userContext.apiType === "Mongo") {
|
if (this.container.isPreferredApiMongoDB()) {
|
||||||
return QueriesClient.FetchMongoQuery;
|
return QueriesClient.FetchMongoQuery;
|
||||||
}
|
}
|
||||||
return QueriesClient.FetchQuery;
|
return QueriesClient.FetchQuery;
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
import React, { FunctionComponent } from "react";
|
|
||||||
import arrowLeftImg from "../../images/imgarrowlefticon.svg";
|
|
||||||
import refreshImg from "../../images/refresh-cosmos.svg";
|
|
||||||
import { AuthType } from "../AuthType";
|
|
||||||
import { userContext } from "../UserContext";
|
|
||||||
|
|
||||||
export interface ResourceTreeProps {
|
|
||||||
toggleLeftPaneExpanded: () => void;
|
|
||||||
isLeftPaneExpanded: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ResourceTree: FunctionComponent<ResourceTreeProps> = ({
|
|
||||||
toggleLeftPaneExpanded,
|
|
||||||
isLeftPaneExpanded,
|
|
||||||
}: ResourceTreeProps): JSX.Element => {
|
|
||||||
return (
|
|
||||||
<div id="main" className={isLeftPaneExpanded ? "main" : "hiddenMain"}>
|
|
||||||
{/* Collections Window - - Start */}
|
|
||||||
<div id="mainslide" className="flexContainer">
|
|
||||||
{/* Collections Window Title/Command Bar - Start */}
|
|
||||||
<div className="collectiontitle">
|
|
||||||
<div className="coltitle">
|
|
||||||
<span className="titlepadcol" data-bind="text: collectionTitle" />
|
|
||||||
<div className="float-right">
|
|
||||||
<span
|
|
||||||
className="padimgcolrefresh"
|
|
||||||
data-test="refreshTree"
|
|
||||||
role="button"
|
|
||||||
data-bind="click: onRefreshResourcesClick, clickBubble: false, event: { keypress: onRefreshDatabasesKeyPress }"
|
|
||||||
tabIndex={0}
|
|
||||||
aria-label="Refresh tree"
|
|
||||||
title="Refresh tree"
|
|
||||||
>
|
|
||||||
<img className="refreshcol" src={refreshImg} alt="Refresh tree" />
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
className="padimgcolrefresh1"
|
|
||||||
id="expandToggleLeftPaneButton"
|
|
||||||
role="button"
|
|
||||||
onClick={toggleLeftPaneExpanded}
|
|
||||||
tabIndex={0}
|
|
||||||
aria-label="Collapse Tree"
|
|
||||||
title="Collapse Tree"
|
|
||||||
>
|
|
||||||
<img className="refreshcol1" src={arrowLeftImg} alt="Hide" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{userContext.authType === AuthType.ResourceToken ? (
|
|
||||||
<div style={{ overflowY: "auto" }} data-bind="react:resourceTreeForResourceToken" />
|
|
||||||
) : (
|
|
||||||
<div style={{ overflowY: "auto" }} data-bind="react:resourceTree" />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{/* Collections Window - End */}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -73,7 +73,7 @@ export class Splitter {
|
|||||||
$(this.leftSide).resizable(splitterOptions);
|
$(this.leftSide).resizable(splitterOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onResizeStart: JQueryUI.ResizableEvent = () => {
|
private onResizeStart: JQueryUI.ResizableEvent = (e: Event, ui: JQueryUI.ResizableUIParams) => {
|
||||||
if (this.direction === SplitterDirection.Vertical) {
|
if (this.direction === SplitterDirection.Vertical) {
|
||||||
$(".ui-resizable-helper").height("100%");
|
$(".ui-resizable-helper").height("100%");
|
||||||
} else {
|
} else {
|
||||||
@@ -82,7 +82,9 @@ export class Splitter {
|
|||||||
$("iframe").css("pointer-events", "none");
|
$("iframe").css("pointer-events", "none");
|
||||||
};
|
};
|
||||||
|
|
||||||
private onResizeStop: JQueryUI.ResizableEvent = () => $("iframe").css("pointer-events", "auto");
|
private onResizeStop: JQueryUI.ResizableEvent = (e: Event, ui: JQueryUI.ResizableUIParams) => {
|
||||||
|
$("iframe").css("pointer-events", "auto");
|
||||||
|
};
|
||||||
|
|
||||||
public collapseLeft() {
|
public collapseLeft() {
|
||||||
this.lastX = $(this.splitter).position().left;
|
this.lastX = $(this.splitter).position().left;
|
||||||
|
|||||||
@@ -1,140 +0,0 @@
|
|||||||
import {
|
|
||||||
Dropdown,
|
|
||||||
IDropdownOption,
|
|
||||||
IDropdownStyles,
|
|
||||||
IImageProps,
|
|
||||||
Image,
|
|
||||||
IStackTokens,
|
|
||||||
Stack,
|
|
||||||
TextField,
|
|
||||||
TooltipHost,
|
|
||||||
} from "@fluentui/react";
|
|
||||||
import React, { FunctionComponent } from "react";
|
|
||||||
import DeleteIcon from "../../images/delete.svg";
|
|
||||||
import EditIcon from "../../images/Edit_entity.svg";
|
|
||||||
import { CassandraType, TableType } from "../Explorer/Tables/Constants";
|
|
||||||
import { userContext } from "../UserContext";
|
|
||||||
import { EntityValue } from "./EntityValue";
|
|
||||||
|
|
||||||
const dropdownStyles: Partial<IDropdownStyles> = { dropdown: { width: 100 } };
|
|
||||||
|
|
||||||
export interface TableEntityProps {
|
|
||||||
entityTypeLabel?: string;
|
|
||||||
entityPropertyLabel?: string;
|
|
||||||
entityValueLabel?: string;
|
|
||||||
isDeleteOptionVisible: boolean;
|
|
||||||
entityProperty: string;
|
|
||||||
entityPropertyPlaceHolder: string;
|
|
||||||
selectedKey: string | number;
|
|
||||||
entityValuePlaceholder: string;
|
|
||||||
entityValue: string | Date;
|
|
||||||
isEntityTypeDate: boolean;
|
|
||||||
options: { key: string; text: string }[];
|
|
||||||
isPropertyTypeDisable: boolean;
|
|
||||||
entityTimeValue: string;
|
|
||||||
isEntityValueDisable?: boolean;
|
|
||||||
onDeleteEntity?: () => void;
|
|
||||||
onEditEntity?: () => void;
|
|
||||||
onEntityPropertyChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
onEntityTypeChange: (event: React.FormEvent<HTMLElement>, selectedParam: IDropdownOption) => void;
|
|
||||||
onEntityValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
onSelectDate: (date: Date | null | undefined) => void;
|
|
||||||
onEntityTimeValueChange: (event: React.FormEvent<HTMLElement>, newInput?: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TableEntity: FunctionComponent<TableEntityProps> = ({
|
|
||||||
entityTypeLabel,
|
|
||||||
entityPropertyLabel,
|
|
||||||
isDeleteOptionVisible,
|
|
||||||
entityProperty,
|
|
||||||
selectedKey,
|
|
||||||
entityPropertyPlaceHolder,
|
|
||||||
entityValueLabel,
|
|
||||||
entityValuePlaceholder,
|
|
||||||
entityValue,
|
|
||||||
options,
|
|
||||||
isPropertyTypeDisable,
|
|
||||||
isEntityTypeDate,
|
|
||||||
entityTimeValue,
|
|
||||||
isEntityValueDisable,
|
|
||||||
onEditEntity,
|
|
||||||
onDeleteEntity,
|
|
||||||
onEntityPropertyChange,
|
|
||||||
onEntityTypeChange,
|
|
||||||
onEntityValueChange,
|
|
||||||
onSelectDate,
|
|
||||||
onEntityTimeValueChange,
|
|
||||||
}: TableEntityProps): JSX.Element => {
|
|
||||||
const imageProps: IImageProps = {
|
|
||||||
width: 16,
|
|
||||||
height: 30,
|
|
||||||
className: entityPropertyLabel ? "addRemoveIconLabel" : "addRemoveIcon",
|
|
||||||
};
|
|
||||||
|
|
||||||
const sectionStackTokens: IStackTokens = { childrenGap: 12 };
|
|
||||||
|
|
||||||
const getEntityValueType = (): string => {
|
|
||||||
const { Int, Smallint, Tinyint } = CassandraType;
|
|
||||||
const { Double, Int32, Int64 } = TableType;
|
|
||||||
|
|
||||||
if (
|
|
||||||
selectedKey === Double ||
|
|
||||||
selectedKey === Int32 ||
|
|
||||||
selectedKey === Int64 ||
|
|
||||||
selectedKey === Int ||
|
|
||||||
selectedKey === Smallint ||
|
|
||||||
selectedKey === Tinyint
|
|
||||||
) {
|
|
||||||
return "number";
|
|
||||||
}
|
|
||||||
return "string";
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Stack horizontal tokens={sectionStackTokens}>
|
|
||||||
<TextField
|
|
||||||
label={entityPropertyLabel && entityPropertyLabel}
|
|
||||||
id="entityPropertyId"
|
|
||||||
autoFocus
|
|
||||||
disabled={isPropertyTypeDisable}
|
|
||||||
placeholder={entityPropertyPlaceHolder}
|
|
||||||
value={entityProperty}
|
|
||||||
onChange={onEntityPropertyChange}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
<Dropdown
|
|
||||||
label={entityTypeLabel && entityTypeLabel}
|
|
||||||
selectedKey={selectedKey}
|
|
||||||
onChange={onEntityTypeChange}
|
|
||||||
options={options}
|
|
||||||
disabled={isPropertyTypeDisable}
|
|
||||||
id="entityTypeId"
|
|
||||||
styles={dropdownStyles}
|
|
||||||
/>
|
|
||||||
<EntityValue
|
|
||||||
entityValueLabel={entityValueLabel}
|
|
||||||
entityValueType={getEntityValueType()}
|
|
||||||
isEntityValueDisable={isEntityValueDisable}
|
|
||||||
entityValuePlaceholder={entityValuePlaceholder}
|
|
||||||
entityValue={entityValue}
|
|
||||||
isEntityTypeDate={isEntityTypeDate}
|
|
||||||
entityTimeValue={entityTimeValue}
|
|
||||||
onEntityValueChange={onEntityValueChange}
|
|
||||||
onSelectDate={onSelectDate}
|
|
||||||
onEntityTimeValueChange={onEntityTimeValueChange}
|
|
||||||
/>
|
|
||||||
{!isEntityValueDisable && (
|
|
||||||
<TooltipHost content="Edit property" id="editTooltip">
|
|
||||||
<Image {...imageProps} src={EditIcon} alt="editEntity" id="editEntity" onClick={onEditEntity} />
|
|
||||||
</TooltipHost>
|
|
||||||
)}
|
|
||||||
{isDeleteOptionVisible && userContext.apiType !== "Cassandra" && (
|
|
||||||
<TooltipHost content="Delete property" id="deleteTooltip">
|
|
||||||
<Image {...imageProps} src={DeleteIcon} alt="delete entity" id="deleteEntity" onClick={onDeleteEntity} />
|
|
||||||
</TooltipHost>
|
|
||||||
)}
|
|
||||||
</Stack>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -2,16 +2,18 @@
|
|||||||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||||
*----------------------------------------------------------*/
|
*----------------------------------------------------------*/
|
||||||
|
|
||||||
export function getMonacoTheme(theme: string): string {
|
export default class ThemeUtility {
|
||||||
switch (theme) {
|
public static getMonacoTheme(theme: string): string {
|
||||||
case "default":
|
switch (theme) {
|
||||||
case "hc-white":
|
case "default":
|
||||||
return "vs";
|
case "hc-white":
|
||||||
case "dark":
|
return "vs";
|
||||||
return "vs-dark";
|
case "dark":
|
||||||
case "hc-black":
|
return "vs-dark";
|
||||||
return "hc-black";
|
case "hc-black":
|
||||||
default:
|
return "hc-black";
|
||||||
return "vs";
|
default:
|
||||||
|
return "vs";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
import { Icon, TooltipHost } from "@fluentui/react";
|
|
||||||
import * as React from "react";
|
|
||||||
|
|
||||||
export interface TooltipProps {
|
|
||||||
children: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const InfoTooltip: React.FunctionComponent<TooltipProps> = ({ children }: TooltipProps) => {
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
<TooltipHost content={children}>
|
|
||||||
<Icon iconName="Info" ariaLabel="Info" className="panelInfoIcon" />
|
|
||||||
</TooltipHost>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
import { Image, Stack, TextField } from "@fluentui/react";
|
|
||||||
import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useRef, useState } from "react";
|
|
||||||
import FolderIcon from "../../../images/folder_16x16.svg";
|
|
||||||
import * as Constants from "../Constants";
|
|
||||||
import { InfoTooltip } from "../Tooltip/InfoTooltip";
|
|
||||||
|
|
||||||
interface UploadProps {
|
|
||||||
label: string;
|
|
||||||
accept?: string;
|
|
||||||
tooltip?: string;
|
|
||||||
multiple?: boolean;
|
|
||||||
tabIndex?: number;
|
|
||||||
onUpload: (event: ChangeEvent<HTMLInputElement>) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Upload: FunctionComponent<UploadProps> = ({
|
|
||||||
label,
|
|
||||||
accept,
|
|
||||||
tooltip,
|
|
||||||
multiple,
|
|
||||||
tabIndex,
|
|
||||||
...props
|
|
||||||
}: UploadProps) => {
|
|
||||||
const [selectedFilesTitle, setSelectedFilesTitle] = useState<string[]>([]);
|
|
||||||
|
|
||||||
const fileRef = useRef<HTMLInputElement>();
|
|
||||||
|
|
||||||
const onImportLinkKeyPress = (event: KeyboardEvent<HTMLAnchorElement>): void => {
|
|
||||||
if (event.keyCode === Constants.KeyCodes.Enter || event.keyCode === Constants.KeyCodes.Space) {
|
|
||||||
onImportLinkClick();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onImportLinkClick = (): void => {
|
|
||||||
fileRef?.current?.click();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onUpload = (event: ChangeEvent<HTMLInputElement>): void => {
|
|
||||||
const { files } = event.target;
|
|
||||||
|
|
||||||
const newFileList = [];
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
|
||||||
newFileList.push(files.item(i).name);
|
|
||||||
}
|
|
||||||
if (newFileList) {
|
|
||||||
setSelectedFilesTitle(newFileList);
|
|
||||||
props.onUpload(event);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const title = label + " to upload";
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<span className="renewUploadItemsHeader">{label}</span>
|
|
||||||
{tooltip && <InfoTooltip>{tooltip}</InfoTooltip>}
|
|
||||||
<Stack horizontal>
|
|
||||||
<TextField styles={{ fieldGroup: { width: 300 } }} readOnly value={selectedFilesTitle.toString()} />
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
id="importFileInput"
|
|
||||||
style={{ display: "none" }}
|
|
||||||
ref={fileRef}
|
|
||||||
accept={accept}
|
|
||||||
tabIndex={tabIndex}
|
|
||||||
multiple={multiple}
|
|
||||||
title="Upload Icon"
|
|
||||||
onChange={onUpload}
|
|
||||||
role="button"
|
|
||||||
/>
|
|
||||||
<a href="#" id="fileImportLinkNotebook" onClick={onImportLinkClick} onKeyPress={onImportLinkKeyPress}>
|
|
||||||
<Image className="fileImportImg" src={FolderIcon} alt={title} title={title} />
|
|
||||||
</a>
|
|
||||||
</Stack>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,61 +1,55 @@
|
|||||||
interface Result {
|
export default class UrlUtility {
|
||||||
type?: string;
|
public static parseDocumentsPath(resourcePath: string): any {
|
||||||
objectBody?: {
|
if (typeof resourcePath !== "string") {
|
||||||
id: string;
|
return {};
|
||||||
self: string;
|
}
|
||||||
};
|
|
||||||
}
|
if (resourcePath.length === 0) {
|
||||||
|
return {};
|
||||||
export function parseDocumentsPath(resourcePath: string): Result {
|
}
|
||||||
if (typeof resourcePath !== "string") {
|
|
||||||
return {};
|
if (resourcePath[resourcePath.length - 1] !== "/") {
|
||||||
}
|
resourcePath = resourcePath + "/";
|
||||||
|
}
|
||||||
if (resourcePath.length === 0) {
|
|
||||||
return {};
|
if (resourcePath[0] !== "/") {
|
||||||
}
|
resourcePath = "/" + resourcePath;
|
||||||
|
}
|
||||||
if (resourcePath[resourcePath.length - 1] !== "/") {
|
|
||||||
resourcePath = resourcePath + "/";
|
var id: string;
|
||||||
}
|
var type: string;
|
||||||
|
var pathParts = resourcePath.split("/");
|
||||||
if (resourcePath[0] !== "/") {
|
|
||||||
resourcePath = "/" + resourcePath;
|
if (pathParts.length % 2 === 0) {
|
||||||
}
|
id = pathParts[pathParts.length - 2];
|
||||||
|
type = pathParts[pathParts.length - 3];
|
||||||
let id: string;
|
} else {
|
||||||
let type: string;
|
id = pathParts[pathParts.length - 3];
|
||||||
const pathParts = resourcePath.split("/");
|
type = pathParts[pathParts.length - 2];
|
||||||
|
}
|
||||||
if (pathParts.length % 2 === 0) {
|
|
||||||
id = pathParts[pathParts.length - 2];
|
var result = {
|
||||||
type = pathParts[pathParts.length - 3];
|
type: type,
|
||||||
} else {
|
objectBody: {
|
||||||
id = pathParts[pathParts.length - 3];
|
id: id,
|
||||||
type = pathParts[pathParts.length - 2];
|
self: resourcePath,
|
||||||
}
|
},
|
||||||
|
};
|
||||||
const result = {
|
|
||||||
type: type,
|
return result;
|
||||||
objectBody: {
|
}
|
||||||
id: id,
|
|
||||||
self: resourcePath,
|
public static createUri(baseUri: string, relativeUri: string): string {
|
||||||
},
|
if (!baseUri) {
|
||||||
};
|
throw new Error("baseUri is null or empty");
|
||||||
|
}
|
||||||
return result;
|
|
||||||
}
|
var slashAtEndOfUriRegex = /\/$/,
|
||||||
|
slashAtStartOfUriRegEx = /^\//;
|
||||||
export function createUri(baseUri: string, relativeUri: string): string {
|
|
||||||
if (!baseUri) {
|
var normalizedBaseUri = baseUri.replace(slashAtEndOfUriRegex, "") + "/",
|
||||||
throw new Error("baseUri is null or empty");
|
normalizedRelativeUri = (relativeUri && relativeUri.replace(slashAtStartOfUriRegEx, "")) || "";
|
||||||
}
|
|
||||||
|
return normalizedBaseUri + normalizedRelativeUri;
|
||||||
const slashAtEndOfUriRegex = /\/$/,
|
}
|
||||||
slashAtStartOfUriRegEx = /^\//;
|
|
||||||
|
|
||||||
const normalizedBaseUri = baseUri.replace(slashAtEndOfUriRegex, "") + "/",
|
|
||||||
normalizedRelativeUri = (relativeUri && relativeUri.replace(slashAtStartOfUriRegEx, "")) || "";
|
|
||||||
|
|
||||||
return normalizedBaseUri + normalizedRelativeUri;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
exports[`requestPlugin Emulator builds a url for emulator proxy via webpack 1`] = `
|
exports[`requestPlugin Emulator builds a url for emulator proxy via webpack 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"endpoint": "http://localhost/proxy",
|
"endpoint": "/proxy",
|
||||||
"headers": Object {
|
"headers": Object {
|
||||||
"x-ms-proxy-target": "http://localhost",
|
"x-ms-proxy-target": "http://localhost",
|
||||||
},
|
},
|
||||||
@@ -12,7 +12,7 @@ Object {
|
|||||||
|
|
||||||
exports[`requestPlugin Hosted builds a proxy URL in development 1`] = `
|
exports[`requestPlugin Hosted builds a proxy URL in development 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"endpoint": "http://localhost/proxy",
|
"endpoint": "/proxy",
|
||||||
"headers": Object {
|
"headers": Object {
|
||||||
"x-ms-proxy-target": "baz",
|
"x-ms-proxy-target": "baz",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
import { JSONObject, OperationResponse } from "@azure/cosmos";
|
|
||||||
import { CollectionBase } from "../../Contracts/ViewModels";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
|
|
||||||
export const bulkCreateDocument = async (
|
|
||||||
collection: CollectionBase,
|
|
||||||
documents: JSONObject[]
|
|
||||||
): Promise<OperationResponse[]> => {
|
|
||||||
const clearMessage = logConsoleProgress(
|
|
||||||
`Executing ${documents.length} bulk operations for container ${collection.id()}`
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await client()
|
|
||||||
.database(collection.databaseId)
|
|
||||||
.container(collection.id())
|
|
||||||
.items.bulk(
|
|
||||||
documents.map((doc) => ({ operationType: "Create", resourceBody: doc })),
|
|
||||||
{ continueOnError: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
const successCount = response.filter((r) => r.statusCode === 201).length;
|
|
||||||
const throttledCount = response.filter((r) => r.statusCode === 429).length;
|
|
||||||
|
|
||||||
logConsoleInfo(
|
|
||||||
`${
|
|
||||||
documents.length
|
|
||||||
} operations completed for container ${collection.id()}. ${successCount} operations succeeded. ${throttledCount} operations throttled`
|
|
||||||
);
|
|
||||||
return response;
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error, "BulkCreateDocument", `Error bulk creating items for container ${collection.id()}`);
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
clearMessage();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -2,10 +2,11 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { CreateCollectionParams, DatabaseAccount } from "../../Contracts/DataModels";
|
import { CreateCollectionParams, DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { updateUserContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { constructRpOptions, createCollection } from "./createCollection";
|
import { createCollection, constructRpOptions } from "./createCollection";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
|
||||||
describe("createCollection", () => {
|
describe("createCollection", () => {
|
||||||
const createCollectionParams: CreateCollectionParams = {
|
const createCollectionParams: CreateCollectionParams = {
|
||||||
@@ -21,22 +22,18 @@ describe("createCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call ARM if logged in with AAD", async () => {
|
it("should call ARM if logged in with AAD", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.AAD;
|
||||||
authType: AuthType.AAD,
|
|
||||||
});
|
|
||||||
await createCollection(createCollectionParams);
|
await createCollection(createCollectionParams);
|
||||||
expect(armRequest).toHaveBeenCalled();
|
expect(armRequest).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call SDK if not logged in with non-AAD method", async () => {
|
it("should call SDK if not logged in with non-AAD method", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.MasterKey;
|
||||||
authType: AuthType.MasterKey,
|
|
||||||
});
|
|
||||||
(client as jest.Mock).mockReturnValue({
|
(client as jest.Mock).mockReturnValue({
|
||||||
databases: {
|
databases: {
|
||||||
createIfNotExists: () => {
|
createIfNotExists: () => {
|
||||||
|
|||||||
@@ -1,32 +1,33 @@
|
|||||||
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
import { ContainerResponse, DatabaseResponse } from "@azure/cosmos";
|
import { ContainerResponse, DatabaseResponse } from "@azure/cosmos";
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
|
||||||
import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/ContainerRequest";
|
import { ContainerRequest } from "@azure/cosmos/dist-esm/client/Container/ContainerRequest";
|
||||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||||
import { AuthType } from "../../AuthType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import { client } from "../CosmosClient";
|
||||||
import { userContext } from "../../UserContext";
|
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
||||||
|
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
getCassandraTable,
|
getCassandraTable,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateGremlinGraph,
|
|
||||||
getGremlinGraph,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateMongoDBCollection,
|
createUpdateMongoDBCollection,
|
||||||
getMongoDBCollection,
|
getMongoDBCollection,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import {
|
||||||
|
createUpdateGremlinGraph,
|
||||||
|
getGremlinGraph,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import * as ARMTypes from "../../Utils/arm/generatedClients/2020-04-01/types";
|
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { userContext } from "../../UserContext";
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { createMongoCollectionWithProxy } from "../MongoProxyClient";
|
|
||||||
import { createDatabase } from "./createDatabase";
|
import { createDatabase } from "./createDatabase";
|
||||||
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export const createCollection = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
export const createCollection = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
||||||
const clearMessage = logConsoleProgress(
|
const clearMessage = logConsoleProgress(
|
||||||
@@ -34,7 +35,7 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
|||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
let collection: DataModels.Collection;
|
let collection: DataModels.Collection;
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
if (window.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||||
if (params.createNewDatabase) {
|
if (params.createNewDatabase) {
|
||||||
const createDatabaseParams: DataModels.CreateDatabaseParams = {
|
const createDatabaseParams: DataModels.CreateDatabaseParams = {
|
||||||
autoPilotMaxThroughput: params.autoPilotMaxThroughput,
|
autoPilotMaxThroughput: params.autoPilotMaxThroughput,
|
||||||
@@ -45,7 +46,7 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
|||||||
await createDatabase(createDatabaseParams);
|
await createDatabase(createDatabaseParams);
|
||||||
}
|
}
|
||||||
collection = await createCollectionWithARM(params);
|
collection = await createCollectionWithARM(params);
|
||||||
} else if (userContext.apiType === "Mongo") {
|
} else if (userContext.defaultExperience === DefaultAccountExperienceType.MongoDB) {
|
||||||
collection = await createMongoCollectionWithProxy(params);
|
collection = await createMongoCollectionWithProxy(params);
|
||||||
} else {
|
} else {
|
||||||
collection = await createCollectionWithSDK(params);
|
collection = await createCollectionWithSDK(params);
|
||||||
@@ -62,20 +63,20 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createCollectionWithARM = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
const createCollectionWithARM = async (params: DataModels.CreateCollectionParams): Promise<DataModels.Collection> => {
|
||||||
const { apiType } = userContext;
|
const defaultExperience = userContext.defaultExperience;
|
||||||
switch (apiType) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
return createSqlContainer(params);
|
return createSqlContainer(params);
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
return createMongoCollection(params);
|
return createMongoCollection(params);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return createCassandraTable(params);
|
return createCassandraTable(params);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
return createGraph(params);
|
return createGraph(params);
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
return createTable(params);
|
return createTable(params);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +1,40 @@
|
|||||||
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseResponse } from "@azure/cosmos";
|
import { DatabaseResponse } from "@azure/cosmos";
|
||||||
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
import { DatabaseRequest } from "@azure/cosmos/dist-esm/client/Database/DatabaseRequest";
|
||||||
import { AuthType } from "../../AuthType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import {
|
||||||
import { userContext } from "../../UserContext";
|
CassandraKeyspaceCreateUpdateParameters,
|
||||||
|
GremlinDatabaseCreateUpdateParameters,
|
||||||
|
MongoDBDatabaseCreateUpdateParameters,
|
||||||
|
SqlDatabaseCreateUpdateParameters,
|
||||||
|
CreateUpdateOptions,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraKeyspace,
|
createUpdateCassandraKeyspace,
|
||||||
getCassandraKeyspace,
|
getCassandraKeyspace,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateGremlinDatabase,
|
|
||||||
getGremlinDatabase,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateMongoDBDatabase,
|
createUpdateMongoDBDatabase,
|
||||||
getMongoDBDatabase,
|
getMongoDBDatabase,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { createUpdateSqlDatabase, getSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
CassandraKeyspaceCreateUpdateParameters,
|
createUpdateGremlinDatabase,
|
||||||
CreateUpdateOptions,
|
getGremlinDatabase,
|
||||||
GremlinDatabaseCreateUpdateParameters,
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
MongoDBDatabaseCreateUpdateParameters,
|
|
||||||
SqlDatabaseCreateUpdateParameters,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress, logConsoleInfo } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function createDatabase(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
export async function createDatabase(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
||||||
const clearMessage = logConsoleProgress(`Creating a new database ${params.databaseId}`);
|
const clearMessage = logConsoleProgress(`Creating a new database ${params.databaseId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.apiType === "Tables") {
|
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
||||||
throw new Error("Creating database resources is not allowed for tables accounts");
|
throw new Error("Creating database resources is not allowed for tables accounts");
|
||||||
}
|
}
|
||||||
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations
|
const database: DataModels.Database = await (window.authType === AuthType.AAD && !userContext.useSDKOperations
|
||||||
? createDatabaseWithARM(params)
|
? createDatabaseWithARM(params)
|
||||||
: createDatabaseWithSDK(params));
|
: createDatabaseWithSDK(params));
|
||||||
|
|
||||||
@@ -48,19 +49,18 @@ export async function createDatabase(params: DataModels.CreateDatabaseParams): P
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function createDatabaseWithARM(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
async function createDatabaseWithARM(params: DataModels.CreateDatabaseParams): Promise<DataModels.Database> {
|
||||||
const { apiType } = userContext;
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
switch (defaultExperience) {
|
||||||
switch (apiType) {
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
case "SQL":
|
|
||||||
return createSqlDatabase(params);
|
return createSqlDatabase(params);
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
return createMongoDatabase(params);
|
return createMongoDatabase(params);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return createCassandraKeyspace(params);
|
return createCassandraKeyspace(params);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
return createGremlineDatabase(params);
|
return createGremlineDatabase(params);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import {
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
createUpdateSqlStoredProcedure,
|
|
||||||
getSqlStoredProcedure,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
SqlStoredProcedureCreateUpdateParameters,
|
SqlStoredProcedureCreateUpdateParameters,
|
||||||
SqlStoredProcedureResource,
|
SqlStoredProcedureResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import {
|
||||||
|
createUpdateSqlStoredProcedure,
|
||||||
|
getSqlStoredProcedure,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function createStoredProcedure(
|
export async function createStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -20,7 +21,11 @@ export async function createStoredProcedure(
|
|||||||
): Promise<StoredProcedureDefinition & Resource> {
|
): Promise<StoredProcedureDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlStoredProcedure(
|
const getResponse = await getSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||||
import {
|
import {
|
||||||
SqlTriggerCreateUpdateParameters,
|
SqlTriggerCreateUpdateParameters,
|
||||||
SqlTriggerResource,
|
SqlTriggerResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { createUpdateSqlTrigger, getSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function createTrigger(
|
export async function createTrigger(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -17,7 +18,11 @@ export async function createTrigger(
|
|||||||
): Promise<TriggerDefinition & Resource> {
|
): Promise<TriggerDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlTrigger(
|
const getResponse = await getSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import {
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
createUpdateSqlUserDefinedFunction,
|
|
||||||
getSqlUserDefinedFunction,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
SqlUserDefinedFunctionCreateUpdateParameters,
|
SqlUserDefinedFunctionCreateUpdateParameters,
|
||||||
SqlUserDefinedFunctionResource,
|
SqlUserDefinedFunctionResource,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import {
|
||||||
|
createUpdateSqlUserDefinedFunction,
|
||||||
|
getSqlUserDefinedFunction,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function createUserDefinedFunction(
|
export async function createUserDefinedFunction(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -20,7 +21,11 @@ export async function createUserDefinedFunction(
|
|||||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||||
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const getResponse = await getSqlUserDefinedFunction(
|
const getResponse = await getSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
jest.mock("../../Utils/arm/request");
|
jest.mock("../../Utils/arm/request");
|
||||||
jest.mock("../MessageHandler");
|
jest.mock("../MessageHandler");
|
||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteCollection } from "./deleteCollection";
|
import { deleteCollection } from "./deleteCollection";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
|
|
||||||
describe("deleteCollection", () => {
|
describe("deleteCollection", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -14,22 +15,18 @@ describe("deleteCollection", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call ARM if logged in with AAD", async () => {
|
it("should call ARM if logged in with AAD", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.AAD;
|
||||||
authType: AuthType.AAD,
|
|
||||||
});
|
|
||||||
await deleteCollection("database", "collection");
|
await deleteCollection("database", "collection");
|
||||||
expect(armRequest).toHaveBeenCalled();
|
expect(armRequest).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call SDK if not logged in with non-AAD method", async () => {
|
it("should call SDK if not logged in with non-AAD method", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.MasterKey;
|
||||||
authType: AuthType.MasterKey,
|
|
||||||
});
|
|
||||||
(client as jest.Mock).mockReturnValue({
|
(client as jest.Mock).mockReturnValue({
|
||||||
database: () => {
|
database: () => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { deleteSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { deleteCassandraTable } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { deleteMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { deleteGremlinGraph } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { deleteTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
|
||||||
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
if (window.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||||
await deleteCollectionWithARM(databaseId, collectionId);
|
await deleteCollectionWithARM(databaseId, collectionId);
|
||||||
} else {
|
} else {
|
||||||
await client().database(databaseId).container(collectionId).delete();
|
await client().database(databaseId).container(collectionId).delete();
|
||||||
@@ -27,21 +28,23 @@ export async function deleteCollection(databaseId: string, collectionId: string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteCollectionWithARM(databaseId: string, collectionId: string): Promise<void> {
|
function deleteCollectionWithARM(databaseId: string, collectionId: string): Promise<void> {
|
||||||
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const accountName = databaseAccount.name;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
|
const accountName = userContext.databaseAccount.name;
|
||||||
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
switch (apiType) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
return deleteMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return deleteCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
return deleteGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
return deleteGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
return deleteTable(subscriptionId, resourceGroup, accountName, collectionId);
|
return deleteTable(subscriptionId, resourceGroup, accountName, collectionId);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
jest.mock("../../Utils/arm/request");
|
jest.mock("../../Utils/arm/request");
|
||||||
jest.mock("../MessageHandler");
|
jest.mock("../MessageHandler");
|
||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
|
||||||
import { updateUserContext } from "../../UserContext";
|
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { deleteDatabase } from "./deleteDatabase";
|
import { deleteDatabase } from "./deleteDatabase";
|
||||||
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
|
|
||||||
describe("deleteDatabase", () => {
|
describe("deleteDatabase", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -14,22 +15,18 @@ describe("deleteDatabase", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call ARM if logged in with AAD", async () => {
|
it("should call ARM if logged in with AAD", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.AAD;
|
||||||
authType: AuthType.AAD,
|
|
||||||
});
|
|
||||||
await deleteDatabase("database");
|
await deleteDatabase("database");
|
||||||
expect(armRequest).toHaveBeenCalled();
|
expect(armRequest).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call SDK if not logged in with non-AAD method", async () => {
|
it("should call SDK if not logged in with non-AAD method", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.MasterKey;
|
||||||
authType: AuthType.MasterKey,
|
|
||||||
});
|
|
||||||
(client as jest.Mock).mockReturnValue({
|
(client as jest.Mock).mockReturnValue({
|
||||||
database: () => {
|
database: () => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
|
||||||
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { deleteSqlDatabase } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { deleteCassandraKeyspace } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { client } from "../CosmosClient";
|
import { deleteMongoDBDatabase } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { deleteGremlinDatabase } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
|
||||||
export async function deleteDatabase(databaseId: string): Promise<void> {
|
export async function deleteDatabase(databaseId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
|
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.apiType === "Tables") {
|
if (userContext.defaultExperience === DefaultAccountExperienceType.Table) {
|
||||||
throw new Error("Deleting database resources is not allowed for tables accounts");
|
throw new Error("Deleting database resources is not allowed for tables accounts");
|
||||||
}
|
}
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
if (window.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||||
await deleteDatabaseWithARM(databaseId);
|
await deleteDatabaseWithARM(databaseId);
|
||||||
} else {
|
} else {
|
||||||
await client().database(databaseId).delete();
|
await client().database(databaseId).delete();
|
||||||
@@ -30,19 +31,21 @@ export async function deleteDatabase(databaseId: string): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteDatabaseWithARM(databaseId: string): Promise<void> {
|
function deleteDatabaseWithARM(databaseId: string): Promise<void> {
|
||||||
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const accountName = databaseAccount.name;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
|
const accountName = userContext.databaseAccount.name;
|
||||||
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
switch (apiType) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteSqlDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
return deleteMongoDBDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteMongoDBDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return deleteCassandraKeyspace(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteCassandraKeyspace(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
return deleteGremlinDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
return deleteGremlinDatabase(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteSqlStoredProcedure } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteSqlStoredProcedure } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function deleteStoredProcedure(
|
export async function deleteStoredProcedure(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -12,7 +13,11 @@ export async function deleteStoredProcedure(
|
|||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
await deleteSqlStoredProcedure(
|
await deleteSqlStoredProcedure(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteSqlTrigger } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
await deleteSqlTrigger(
|
await deleteSqlTrigger(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { deleteSqlUserDefinedFunction } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
|
import { deleteSqlUserDefinedFunction } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
||||||
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
await deleteSqlUserDefinedFunction(
|
await deleteSqlUserDefinedFunction(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { configContext } from "../../ConfigContext";
|
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
|
import { configContext } from "../../ConfigContext";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
interface TimeSeriesData {
|
interface TimeSeriesData {
|
||||||
data: {
|
data: {
|
||||||
@@ -41,13 +41,13 @@ interface MetricsResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getCollectionUsageSizeInKB = async (databaseName: string, containerName: string): Promise<number> => {
|
export const getCollectionUsageSizeInKB = async (databaseName: string, containerName: string): Promise<number> => {
|
||||||
if (userContext.authType !== AuthType.AAD) {
|
if (window.authType !== AuthType.AAD) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const accountName = databaseAccount.name;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
|
const accountName = userContext.databaseAccount.name;
|
||||||
const filter = `DatabaseName eq '${databaseName}' and CollectionName eq '${containerName}'`;
|
const filter = `DatabaseName eq '${databaseName}' and CollectionName eq '${containerName}'`;
|
||||||
const metricNames = "DataUsage,IndexUsage";
|
const metricNames = "DataUsage,IndexUsage";
|
||||||
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/providers/microsoft.insights/metrics`;
|
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/providers/microsoft.insights/metrics`;
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ import { handleError } from "../ErrorHandlingUtils";
|
|||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import * as Constants from "../Constants";
|
import * as Constants from "../Constants";
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
|
||||||
|
|
||||||
export async function getIndexTransformationProgress(databaseId: string, collectionId: string): Promise<number> {
|
export async function getIndexTransformationProgress(databaseId: string, collectionId: string): Promise<number> {
|
||||||
if (userContext.authType !== AuthType.AAD) {
|
if (window.authType !== AuthType.AAD) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
let indexTransformationPercentage: number;
|
let indexTransformationPercentage: number;
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { updateUserContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readCollection } from "./readCollection";
|
import { readCollection } from "./readCollection";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
|
||||||
describe("readCollection", () => {
|
describe("readCollection", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
authType: AuthType.ResourceToken,
|
|
||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call SDK if logged in with resource token", async () => {
|
it("should call SDK if logged in with resource token", async () => {
|
||||||
|
window.authType = AuthType.ResourceToken;
|
||||||
(client as jest.Mock).mockReturnValue({
|
(client as jest.Mock).mockReturnValue({
|
||||||
database: () => {
|
database: () => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { Offer, ReadCollectionOfferParams } from "../../Contracts/DataModels";
|
import { Offer, ReadCollectionOfferParams } from "../../Contracts/DataModels";
|
||||||
import { userContext } from "../../UserContext";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { getSqlContainerThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { getMongoDBCollectionThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { getCassandraTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { getCassandraTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { getGremlinGraphThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { getGremlinGraphThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { getMongoDBCollectionThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { getSqlContainerThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { getTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { getTableThroughput } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { readOfferWithSDK } from "./readOfferWithSDK";
|
import { readOfferWithSDK } from "./readOfferWithSDK";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export const readCollectionOffer = async (params: ReadCollectionOfferParams): Promise<Offer> => {
|
export const readCollectionOffer = async (params: ReadCollectionOfferParams): Promise<Offer> => {
|
||||||
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
|
return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,13 +33,15 @@ export const readCollectionOffer = async (params: ReadCollectionOfferParams): Pr
|
|||||||
};
|
};
|
||||||
|
|
||||||
const readCollectionOfferWithARM = async (databaseId: string, collectionId: string): Promise<Offer> => {
|
const readCollectionOfferWithARM = async (databaseId: string, collectionId: string): Promise<Offer> => {
|
||||||
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const accountName = databaseAccount.name;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
|
const accountName = userContext.databaseAccount.name;
|
||||||
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
try {
|
try {
|
||||||
switch (apiType) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
rpResponse = await getSqlContainerThroughput(
|
rpResponse = await getSqlContainerThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -43,7 +50,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
rpResponse = await getMongoDBCollectionThroughput(
|
rpResponse = await getMongoDBCollectionThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -52,7 +59,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
rpResponse = await getCassandraTableThroughput(
|
rpResponse = await getCassandraTableThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -61,7 +68,7 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
rpResponse = await getGremlinGraphThroughput(
|
rpResponse = await getGremlinGraphThroughput(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
@@ -70,11 +77,11 @@ const readCollectionOfferWithARM = async (databaseId: string, collectionId: stri
|
|||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId);
|
rpResponse = await getTableThroughput(subscriptionId, resourceGroup, accountName, collectionId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "NotFound") {
|
if (error.code !== "NotFound") {
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { updateUserContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readCollections } from "./readCollections";
|
import { readCollections } from "./readCollections";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
|
||||||
describe("readCollections", () => {
|
describe("readCollections", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -13,22 +14,18 @@ describe("readCollections", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call ARM if logged in with AAD", async () => {
|
it("should call ARM if logged in with AAD", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.AAD;
|
||||||
authType: AuthType.AAD,
|
|
||||||
});
|
|
||||||
await readCollections("database");
|
await readCollections("database");
|
||||||
expect(armRequest).toHaveBeenCalled();
|
expect(armRequest).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call SDK if not logged in with non-AAD method", async () => {
|
it("should call SDK if not logged in with non-AAD method", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.MasterKey;
|
||||||
authType: AuthType.MasterKey,
|
|
||||||
});
|
|
||||||
(client as jest.Mock).mockReturnValue({
|
(client as jest.Mock).mockReturnValue({
|
||||||
database: () => {
|
database: () => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,19 +1,25 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { userContext } from "../../UserContext";
|
import { AuthType } from "../../AuthType";
|
||||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.MongoDB &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
return await readCollectionsWithARM(databaseId);
|
return await readCollectionsWithARM(databaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,28 +35,29 @@ export async function readCollections(databaseId: string): Promise<DataModels.Co
|
|||||||
|
|
||||||
async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Collection[]> {
|
async function readCollectionsWithARM(databaseId: string): Promise<DataModels.Collection[]> {
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
|
const subscriptionId = userContext.subscriptionId;
|
||||||
|
const resourceGroup = userContext.resourceGroup;
|
||||||
|
const accountName = userContext.databaseAccount.name;
|
||||||
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
switch (defaultExperience) {
|
||||||
const accountName = databaseAccount.name;
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
|
|
||||||
switch (apiType) {
|
|
||||||
case "SQL":
|
|
||||||
rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listSqlContainers(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
rpResponse = await listMongoDBCollections(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listMongoDBCollections(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
rpResponse = await listCassandraTables(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listCassandraTables(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
rpResponse = await listGremlinGraphs(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await listGremlinGraphs(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
rpResponse = await listTables(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listTables(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rpResponse?.value?.map((collection) => collection.properties?.resource as DataModels.Collection);
|
return rpResponse?.value?.map((collection) => collection.properties?.resource as DataModels.Collection);
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { Offer, ReadDatabaseOfferParams } from "../../Contracts/DataModels";
|
import { Offer, ReadDatabaseOfferParams } from "../../Contracts/DataModels";
|
||||||
import { userContext } from "../../UserContext";
|
import { getSqlDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { getMongoDBDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { getCassandraKeyspaceThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { getCassandraKeyspaceThroughput } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { getGremlinDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { getGremlinDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
import { getMongoDBDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { getSqlDatabaseThroughput } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { readOfferWithSDK } from "./readOfferWithSDK";
|
import { readOfferWithSDK } from "./readOfferWithSDK";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promise<Offer> => {
|
export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promise<Offer> => {
|
||||||
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
|
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
return await readDatabaseOfferWithARM(params.databaseId);
|
return await readDatabaseOfferWithARM(params.databaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,26 +32,28 @@ export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promis
|
|||||||
};
|
};
|
||||||
|
|
||||||
const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
|
const readDatabaseOfferWithARM = async (databaseId: string): Promise<Offer> => {
|
||||||
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const accountName = databaseAccount.name;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
|
const accountName = userContext.databaseAccount.name;
|
||||||
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
try {
|
try {
|
||||||
switch (apiType) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getSqlDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
rpResponse = await getMongoDBDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getMongoDBDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
rpResponse = await getCassandraKeyspaceThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getCassandraKeyspaceThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
rpResponse = await getGremlinDatabaseThroughput(subscriptionId, resourceGroup, accountName, databaseId);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code !== "NotFound") {
|
if (error.code !== "NotFound") {
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ jest.mock("../../Utils/arm/request");
|
|||||||
jest.mock("../CosmosClient");
|
jest.mock("../CosmosClient");
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { DatabaseAccount } from "../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../Contracts/DataModels";
|
||||||
import { updateUserContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { armRequest } from "../../Utils/arm/request";
|
import { armRequest } from "../../Utils/arm/request";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { readDatabases } from "./readDatabases";
|
import { readDatabases } from "./readDatabases";
|
||||||
|
import { updateUserContext } from "../../UserContext";
|
||||||
|
|
||||||
describe("readDatabases", () => {
|
describe("readDatabases", () => {
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
@@ -13,22 +14,18 @@ describe("readDatabases", () => {
|
|||||||
databaseAccount: {
|
databaseAccount: {
|
||||||
name: "test",
|
name: "test",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
apiType: "SQL",
|
defaultExperience: DefaultAccountExperienceType.DocumentDB,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call ARM if logged in with AAD", async () => {
|
it("should call ARM if logged in with AAD", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.AAD;
|
||||||
authType: AuthType.AAD,
|
|
||||||
});
|
|
||||||
await readDatabases();
|
await readDatabases();
|
||||||
expect(armRequest).toHaveBeenCalled();
|
expect(armRequest).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call SDK if not logged in with non-AAD method", async () => {
|
it("should call SDK if not logged in with non-AAD method", async () => {
|
||||||
updateUserContext({
|
window.authType = AuthType.MasterKey;
|
||||||
authType: AuthType.MasterKey,
|
|
||||||
});
|
|
||||||
(client as jest.Mock).mockReturnValue({
|
(client as jest.Mock).mockReturnValue({
|
||||||
databases: {
|
databases: {
|
||||||
readAll: () => {
|
readAll: () => {
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { userContext } from "../../UserContext";
|
import { AuthType } from "../../AuthType";
|
||||||
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { listSqlDatabases } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
|
import { listMongoDBDatabases } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { listGremlinDatabases } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function readDatabases(): Promise<DataModels.Database[]> {
|
export async function readDatabases(): Promise<DataModels.Database[]> {
|
||||||
let databases: DataModels.Database[];
|
let databases: DataModels.Database[];
|
||||||
const clearMessage = logConsoleProgress(`Querying databases`);
|
const clearMessage = logConsoleProgress(`Querying databases`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
databases = await readDatabasesWithARM();
|
databases = await readDatabasesWithARM();
|
||||||
} else {
|
} else {
|
||||||
const sdkResponse = await client().databases.readAll().fetchAll();
|
const sdkResponse = await client().databases.readAll().fetchAll();
|
||||||
@@ -29,24 +34,26 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
|
|||||||
|
|
||||||
async function readDatabasesWithARM(): Promise<DataModels.Database[]> {
|
async function readDatabasesWithARM(): Promise<DataModels.Database[]> {
|
||||||
let rpResponse;
|
let rpResponse;
|
||||||
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const accountName = databaseAccount.name;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
|
const accountName = userContext.databaseAccount.name;
|
||||||
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
switch (apiType) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listSqlDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case "Mongo":
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listMongoDBDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listCassandraKeyspaces(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
|
rpResponse = await listGremlinDatabases(subscriptionId, resourceGroup, accountName);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rpResponse?.value?.map((database) => database.properties?.resource as DataModels.Database);
|
return rpResponse?.value?.map((database) => database.properties?.resource as DataModels.Database);
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import { AuthType } from "../../AuthType";
|
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { getMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
import { getMongoDBCollection } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { MongoDBCollectionResource } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
import { MongoDBCollectionResource } from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { AuthType } from "../../AuthType";
|
||||||
|
|
||||||
export async function readMongoDBCollectionThroughRP(
|
export async function readMongoDBCollectionThroughRP(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
collectionId: string
|
collectionId: string
|
||||||
): Promise<MongoDBCollectionResource> {
|
): Promise<MongoDBCollectionResource> {
|
||||||
if (userContext.authType !== AuthType.AAD) {
|
if (window.authType !== AuthType.AAD) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
let collection: MongoDBCollectionResource;
|
let collection: MongoDBCollectionResource;
|
||||||
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
const accountName = databaseAccount.name;
|
const accountName = userContext.databaseAccount.name;
|
||||||
|
|
||||||
const clearMessage = logConsoleProgress(`Reading container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Reading container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { listSqlStoredProcedures } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { listSqlStoredProcedures } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function readStoredProcedures(
|
export async function readStoredProcedures(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
@@ -12,7 +13,11 @@ export async function readStoredProcedures(
|
|||||||
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
const rpResponse = await listSqlStoredProcedures(
|
const rpResponse = await listSqlStoredProcedures(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
|
import { Resource, TriggerDefinition } from "@azure/cosmos";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
import { listSqlTriggers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { listSqlTriggers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { client } from "../CosmosClient";
|
import { userContext } from "../../UserContext";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function readTriggers(
|
export async function readTriggers(
|
||||||
@@ -12,7 +13,11 @@ export async function readTriggers(
|
|||||||
): Promise<(TriggerDefinition & Resource)[]> {
|
): Promise<(TriggerDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
const rpResponse = await listSqlTriggers(
|
const rpResponse = await listSqlTriggers(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
userContext.resourceGroup,
|
userContext.resourceGroup,
|
||||||
|
|||||||
@@ -1,23 +1,27 @@
|
|||||||
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { userContext } from "../../UserContext";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { listSqlUserDefinedFunctions } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
import { Resource, UserDefinedFunctionDefinition } from "@azure/cosmos";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { listSqlUserDefinedFunctions } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function readUserDefinedFunctions(
|
export async function readUserDefinedFunctions(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
collectionId: string
|
collectionId: string
|
||||||
): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
|
): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
|
||||||
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
|
|
||||||
try {
|
try {
|
||||||
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience === DefaultAccountExperienceType.DocumentDB
|
||||||
|
) {
|
||||||
const rpResponse = await listSqlUserDefinedFunctions(
|
const rpResponse = await listSqlUserDefinedFunctions(
|
||||||
subscriptionId,
|
userContext.subscriptionId,
|
||||||
resourceGroup,
|
userContext.resourceGroup,
|
||||||
databaseAccount.name,
|
userContext.databaseAccount.name,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId
|
collectionId
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,43 +1,51 @@
|
|||||||
import { ContainerDefinition } from "@azure/cosmos";
|
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { Collection } from "../../Contracts/DataModels";
|
import { Collection } from "../../Contracts/DataModels";
|
||||||
import { userContext } from "../../UserContext";
|
import { ContainerDefinition } from "@azure/cosmos";
|
||||||
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
|
import {
|
||||||
|
CreateUpdateOptions,
|
||||||
|
ExtendedResourceProperties,
|
||||||
|
MongoDBCollectionCreateUpdateParameters,
|
||||||
|
MongoDBCollectionResource,
|
||||||
|
SqlContainerCreateUpdateParameters,
|
||||||
|
SqlContainerResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
|
import { client } from "../CosmosClient";
|
||||||
|
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
getCassandraTable,
|
getCassandraTable,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateGremlinGraph,
|
|
||||||
getGremlinGraph,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateMongoDBCollection,
|
createUpdateMongoDBCollection,
|
||||||
getMongoDBCollection,
|
getMongoDBCollection,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
|
||||||
import {
|
import {
|
||||||
ExtendedResourceProperties,
|
createUpdateGremlinGraph,
|
||||||
MongoDBCollectionCreateUpdateParameters,
|
getGremlinGraph,
|
||||||
SqlContainerCreateUpdateParameters,
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
SqlContainerResource,
|
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
|
||||||
export async function updateCollection(
|
export async function updateCollection(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
newCollection: Partial<Collection>,
|
newCollection: Collection,
|
||||||
options: RequestOptions = {}
|
options: RequestOptions = {}
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
let collection: Collection;
|
let collection: Collection;
|
||||||
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
if (
|
||||||
|
window.authType === AuthType.AAD &&
|
||||||
|
!userContext.useSDKOperations &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.MongoDB &&
|
||||||
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
|
) {
|
||||||
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
||||||
} else {
|
} else {
|
||||||
const sdkResponse = await client()
|
const sdkResponse = await client()
|
||||||
@@ -61,31 +69,24 @@ export async function updateCollection(
|
|||||||
async function updateCollectionWithARM(
|
async function updateCollectionWithARM(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
newCollection: Partial<Collection>
|
newCollection: Collection
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const { subscriptionId, resourceGroup, apiType, databaseAccount } = userContext;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const accountName = databaseAccount.name;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
|
const accountName = userContext.databaseAccount.name;
|
||||||
|
const defaultExperience = userContext.defaultExperience;
|
||||||
|
|
||||||
switch (apiType) {
|
switch (defaultExperience) {
|
||||||
case "SQL":
|
case DefaultAccountExperienceType.DocumentDB:
|
||||||
return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateSqlContainer(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case "Cassandra":
|
case DefaultAccountExperienceType.Cassandra:
|
||||||
return updateCassandraTable(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateCassandraTable(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case "Gremlin":
|
case DefaultAccountExperienceType.Graph:
|
||||||
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case "Tables":
|
case DefaultAccountExperienceType.Table:
|
||||||
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case "Mongo":
|
|
||||||
return updateMongoDBCollection(
|
|
||||||
databaseId,
|
|
||||||
collectionId,
|
|
||||||
subscriptionId,
|
|
||||||
resourceGroup,
|
|
||||||
accountName,
|
|
||||||
newCollection
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${apiType}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ async function updateSqlContainer(
|
|||||||
subscriptionId: string,
|
subscriptionId: string,
|
||||||
resourceGroup: string,
|
resourceGroup: string,
|
||||||
accountName: string,
|
accountName: string,
|
||||||
newCollection: Partial<Collection>
|
newCollection: Collection
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const getResponse = await getSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
const getResponse = await getSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
@@ -114,26 +115,35 @@ async function updateSqlContainer(
|
|||||||
throw new Error(`Sql container to update does not exist. Database id: ${databaseId} Collection id: ${collectionId}`);
|
throw new Error(`Sql container to update does not exist. Database id: ${databaseId} Collection id: ${collectionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateMongoDBCollection(
|
export async function updateMongoDBCollectionThroughRP(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
subscriptionId: string,
|
newCollection: MongoDBCollectionResource,
|
||||||
resourceGroup: string,
|
updateOptions?: CreateUpdateOptions
|
||||||
accountName: string,
|
): Promise<MongoDBCollectionResource> {
|
||||||
newCollection: Partial<Collection>
|
const subscriptionId = userContext.subscriptionId;
|
||||||
): Promise<Collection> {
|
const resourceGroup = userContext.resourceGroup;
|
||||||
|
const accountName = userContext.databaseAccount.name;
|
||||||
|
|
||||||
const getResponse = await getMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
const getResponse = await getMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
getResponse.properties.resource = newCollection as SqlContainerResource & ExtendedResourceProperties;
|
const updateParams: MongoDBCollectionCreateUpdateParameters = {
|
||||||
|
properties: {
|
||||||
|
resource: newCollection,
|
||||||
|
options: updateOptions,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const updateResponse = await createUpdateMongoDBCollection(
|
const updateResponse = await createUpdateMongoDBCollection(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
accountName,
|
accountName,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
getResponse as MongoDBCollectionCreateUpdateParameters
|
updateParams
|
||||||
);
|
);
|
||||||
return updateResponse && (updateResponse.properties.resource as Collection);
|
|
||||||
|
return updateResponse && (updateResponse.properties.resource as MongoDBCollectionResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -147,7 +157,7 @@ async function updateCassandraTable(
|
|||||||
subscriptionId: string,
|
subscriptionId: string,
|
||||||
resourceGroup: string,
|
resourceGroup: string,
|
||||||
accountName: string,
|
accountName: string,
|
||||||
newCollection: Partial<Collection>
|
newCollection: Collection
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const getResponse = await getCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
const getResponse = await getCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
@@ -174,7 +184,7 @@ async function updateGremlinGraph(
|
|||||||
subscriptionId: string,
|
subscriptionId: string,
|
||||||
resourceGroup: string,
|
resourceGroup: string,
|
||||||
accountName: string,
|
accountName: string,
|
||||||
newCollection: Partial<Collection>
|
newCollection: Collection
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const getResponse = await getGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
const getResponse = await getGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
@@ -198,7 +208,7 @@ async function updateTable(
|
|||||||
subscriptionId: string,
|
subscriptionId: string,
|
||||||
resourceGroup: string,
|
resourceGroup: string,
|
||||||
accountName: string,
|
accountName: string,
|
||||||
newCollection: Partial<Collection>
|
newCollection: Collection
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const getResponse = await getTable(subscriptionId, resourceGroup, accountName, collectionId);
|
const getResponse = await getTable(subscriptionId, resourceGroup, accountName, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user