diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 70d097a31..d3e99849e 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -109,6 +109,8 @@ const title = t("splashScreen.title.default"); ``` The `ResourceKey` type (derived from `Resources.json`) ensures compile-time safety — invalid keys will cause a type error. When adding new strings, add the English entry to `Resources.json` first, then reference it with `t()`. +**Important:** Only modify the English resource file (`src/Localization/en/Resources.json`). Do not modify non-English locale files (`src/Localization//Resources.json`) — translations are managed by a separate localization process. + ### Imports TypeScript `baseUrl` is set to `src/`, so imports from `src/` are written without a leading `./src/` prefix: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8d98b7ad..21180bb36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -188,9 +188,89 @@ jobs: with: azcliversion: latest inlineScript: | - NOSQL_TESTACCOUNT_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql.documents.azure.com/.default" -o tsv --query accessToken) - echo "::add-mask::$NOSQL_TESTACCOUNT_TOKEN" - echo NOSQL_TESTACCOUNT_TOKEN=$NOSQL_TESTACCOUNT_TOKEN >> $GITHUB_ENV + SHARD_INDEX=${{ matrix.shardIndex }} + echo PLAYWRIGHT_SHARD_INDEX=$SHARD_INDEX >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_1_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-1.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_1_TOKEN" + echo NOSQL_TESTACCOUNT_1_TOKEN=$NOSQL_TESTACCOUNT_1_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_2_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-2.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_2_TOKEN" + echo NOSQL_TESTACCOUNT_2_TOKEN=$NOSQL_TESTACCOUNT_2_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_3_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-3.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_3_TOKEN" + echo NOSQL_TESTACCOUNT_3_TOKEN=$NOSQL_TESTACCOUNT_3_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_4_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-4.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_4_TOKEN" + echo NOSQL_TESTACCOUNT_4_TOKEN=$NOSQL_TESTACCOUNT_4_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_5_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-5.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_5_TOKEN" + echo NOSQL_TESTACCOUNT_5_TOKEN=$NOSQL_TESTACCOUNT_5_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_6_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-6.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_6_TOKEN" + echo NOSQL_TESTACCOUNT_6_TOKEN=$NOSQL_TESTACCOUNT_6_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_7_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-7.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_7_TOKEN" + echo NOSQL_TESTACCOUNT_7_TOKEN=$NOSQL_TESTACCOUNT_7_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_8_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-8.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_8_TOKEN" + echo NOSQL_TESTACCOUNT_8_TOKEN=$NOSQL_TESTACCOUNT_8_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_9_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-9.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_9_TOKEN" + echo NOSQL_TESTACCOUNT_9_TOKEN=$NOSQL_TESTACCOUNT_9_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_10_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-10.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_10_TOKEN" + echo NOSQL_TESTACCOUNT_10_TOKEN=$NOSQL_TESTACCOUNT_10_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_11_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-11.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_11_TOKEN" + echo NOSQL_TESTACCOUNT_11_TOKEN=$NOSQL_TESTACCOUNT_11_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_12_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-12.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_12_TOKEN" + echo NOSQL_TESTACCOUNT_12_TOKEN=$NOSQL_TESTACCOUNT_12_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_13_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-13.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_13_TOKEN" + echo NOSQL_TESTACCOUNT_13_TOKEN=$NOSQL_TESTACCOUNT_13_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_14_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-14.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_14_TOKEN" + echo NOSQL_TESTACCOUNT_14_TOKEN=$NOSQL_TESTACCOUNT_14_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_15_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-15.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_15_TOKEN" + echo NOSQL_TESTACCOUNT_15_TOKEN=$NOSQL_TESTACCOUNT_15_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_16_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-16.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_16_TOKEN" + echo NOSQL_TESTACCOUNT_16_TOKEN=$NOSQL_TESTACCOUNT_16_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_17_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-17.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_17_TOKEN" + echo NOSQL_TESTACCOUNT_17_TOKEN=$NOSQL_TESTACCOUNT_17_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_18_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-18.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_18_TOKEN" + echo NOSQL_TESTACCOUNT_18_TOKEN=$NOSQL_TESTACCOUNT_18_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_19_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-19.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_19_TOKEN" + echo NOSQL_TESTACCOUNT_19_TOKEN=$NOSQL_TESTACCOUNT_19_TOKEN >> $GITHUB_ENV + + NOSQL_TESTACCOUNT_20_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-20.documents.azure.com/.default" -o tsv --query accessToken) + echo "::add-mask::$NOSQL_TESTACCOUNT_20_TOKEN" + echo NOSQL_TESTACCOUNT_20_TOKEN=$NOSQL_TESTACCOUNT_20_TOKEN >> $GITHUB_ENV + NOSQL_READONLY_TESTACCOUNT_TOKEN=$(az account get-access-token --scope "https://github-e2etests-sql-readonly.documents.azure.com/.default" -o tsv --query accessToken) echo "::add-mask::$NOSQL_READONLY_TESTACCOUNT_TOKEN" echo NOSQL_READONLY_TESTACCOUNT_TOKEN=$NOSQL_READONLY_TESTACCOUNT_TOKEN >> $GITHUB_ENV @@ -257,4 +337,4 @@ jobs: with: name: html-report--attempt-${{ github.run_attempt }} path: playwright-report - retention-days: 14 \ No newline at end of file + retention-days: 14 diff --git a/package-lock.json b/package-lock.json index 4bc29029c..e9cef16a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,7 +51,7 @@ "@types/lodash": "4.14.171", "@types/mkdirp": "1.0.1", "@types/node-fetch": "2.6.13", - "@xmldom/xmldom": "0.8.12", + "@xmldom/xmldom": "0.8.13", "@xterm/addon-fit": "0.10.0", "@xterm/xterm": "5.5.0", "allotment": "1.20.2", @@ -10453,9 +10453,9 @@ } }, "node_modules/@xmldom/xmldom": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.12.tgz", - "integrity": "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==", + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz", + "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -22925,7 +22925,9 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "3.1.2", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -25352,25 +25354,16 @@ } }, "node_modules/recursive-readdir": { - "version": "2.2.2", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", "dev": true, "license": "MIT", "dependencies": { - "minimatch": "3.0.4" + "minimatch": "^3.0.5" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/recursive-readdir/node_modules/minimatch": { - "version": "3.0.4", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "node": ">=6.0.0" } }, "node_modules/redent": { @@ -27498,21 +27491,23 @@ } }, "node_modules/typedoc/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", + "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" diff --git a/package.json b/package.json index 2ae4972af..e8614111f 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@types/lodash": "4.14.171", "@types/mkdirp": "1.0.1", "@types/node-fetch": "2.6.13", - "@xmldom/xmldom": "0.8.12", + "@xmldom/xmldom": "0.8.13", "@xterm/addon-fit": "0.10.0", "@xterm/xterm": "5.5.0", "allotment": "1.20.2", diff --git a/preview/package-lock.json b/preview/package-lock.json index 3052162db..fd98a4bfe 100644 --- a/preview/package-lock.json +++ b/preview/package-lock.json @@ -14,7 +14,7 @@ "http-proxy-middleware": "^3.0.5", "node": "^20.19.5", "node-fetch": "^2.6.1", - "path-to-regexp": "^0.1.12" + "path-to-regexp": "^0.1.13" } }, "node_modules/@types/http-proxy": { @@ -660,7 +660,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "license": "MIT" }, "node_modules/picomatch": { @@ -746,9 +748,10 @@ } }, "node_modules/router/node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/express" diff --git a/preview/package.json b/preview/package.json index 73637a0a7..c50f57a1e 100644 --- a/preview/package.json +++ b/preview/package.json @@ -17,6 +17,6 @@ "http-proxy-middleware": "^3.0.5", "node": "^20.19.5", "node-fetch": "^2.6.1", - "path-to-regexp": "^0.1.12" + "path-to-regexp": "^0.1.13" } } diff --git a/src/Common/DatabaseUtility.ts b/src/Common/DatabaseUtility.ts deleted file mode 100644 index c5b8538ff..000000000 --- a/src/Common/DatabaseUtility.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function getNewDatabaseSharedThroughputDefault(): boolean { - return false; -} diff --git a/src/Contracts/DataModels.ts b/src/Contracts/DataModels.ts index 0a51d721a..a72ac434e 100644 --- a/src/Contracts/DataModels.ts +++ b/src/Contracts/DataModels.ts @@ -255,6 +255,7 @@ export interface VectorIndex { vectorIndexShardKey?: string[]; indexingSearchListSize?: number; quantizationByteSize?: number; + quantizerType?: "product" | "spherical"; } export interface FullTextIndex { @@ -599,12 +600,6 @@ export interface IContainerData { forwardingId: string; } -export interface IDbAccountAllow { - status: number; - message?: string; - type?: string; -} - export interface IResponse { status: number; data: T; diff --git a/src/Explorer/Controls/Settings/SettingsComponent.tsx b/src/Explorer/Controls/Settings/SettingsComponent.tsx index bc269cb4b..4aca3ce6b 100644 --- a/src/Explorer/Controls/Settings/SettingsComponent.tsx +++ b/src/Explorer/Controls/Settings/SettingsComponent.tsx @@ -15,6 +15,7 @@ import { } from "Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent"; import { useIndexingPolicyStore } from "Explorer/Tabs/QueryTab/ResultsView"; import { useDatabases } from "Explorer/useDatabases"; +import { Keys, t } from "Localization"; import { isFabricNative } from "Platform/Fabric/FabricUtil"; import { isVectorSearchEnabled } from "Utils/CapabilityUtils"; import { isRunningOnPublicCloud } from "Utils/CloudUtils"; @@ -44,7 +45,6 @@ import { useCommandBar } from "../../Menus/CommandBar/CommandBarComponentAdapter import { SettingsTabV2 } from "../../Tabs/SettingsTabV2"; import "./SettingsComponent.less"; import { mongoIndexingPolicyAADError } from "./SettingsRenderUtils"; -import { Keys, t } from "Localization"; import { ConflictResolutionComponent, ConflictResolutionComponentProps, @@ -555,6 +555,19 @@ export class SettingsComponent extends React.Component this.setState({ vectorEmbeddingPolicy: newVectorEmbeddingPolicy }); + private onVectorIndexesChange = (newVectorIndexes: DataModels.VectorIndex[]): void => { + const currentIndexingPolicy: DataModels.IndexingPolicy = + this.state.indexingPolicyContent || ({} as DataModels.IndexingPolicy); + const newIndexingPolicy: DataModels.IndexingPolicy = { + ...currentIndexingPolicy, + vectorIndexes: newVectorIndexes, + }; + this.setState({ + indexingPolicyContent: newIndexingPolicy, + isIndexingPolicyDirty: true, + }); + }; + private onFullTextPolicyChange = (newFullTextPolicy: DataModels.FullTextPolicy): void => this.setState({ fullTextPolicy: newFullTextPolicy }); @@ -1332,6 +1345,9 @@ export class SettingsComponent extends React.Component void; onVectorEmbeddingPolicyDirtyChange: (isVectorEmbeddingPolicyDirty: boolean) => void; onVectorEmbeddingPolicyValidationChange: (isValid: boolean) => void; + vectorIndexes: VectorIndex[]; + vectorIndexesBaseline: VectorIndex[]; + onVectorIndexesChange: (newVectorIndexes: VectorIndex[]) => void; isVectorSearchEnabled: boolean; fullTextPolicy: FullTextPolicy; fullTextPolicyBaseline: FullTextPolicy; @@ -33,6 +36,9 @@ export const ContainerPolicyComponent: React.FC = onVectorEmbeddingPolicyChange, onVectorEmbeddingPolicyDirtyChange, onVectorEmbeddingPolicyValidationChange, + vectorIndexes, + vectorIndexesBaseline, + onVectorIndexesChange, isVectorSearchEnabled, fullTextPolicy, fullTextPolicyBaseline, @@ -78,6 +84,7 @@ export const ContainerPolicyComponent: React.FC = const checkAndSendVectorEmbeddingPoliciesToSettings = ( newVectorEmbeddings: VectorEmbedding[], + newVectorIndexes: VectorIndex[], validationPassed: boolean, ): void => { onVectorEmbeddingPolicyValidationChange(validationPassed); @@ -86,6 +93,9 @@ export const ContainerPolicyComponent: React.FC = if (isVectorDirty) { onVectorEmbeddingPolicyChange({ vectorEmbeddings: newVectorEmbeddings }); } + if (isDirty(newVectorIndexes ?? [], vectorIndexesBaseline ?? [])) { + onVectorIndexesChange(newVectorIndexes); + } }; const checkAndSendFullTextPolicyToSettings = (newFullTextPolicy: FullTextPolicy): void => { @@ -169,12 +179,14 @@ export const ContainerPolicyComponent: React.FC = checkAndSendVectorEmbeddingPoliciesToSettings(vectorEmbeddings, validationPassed)} + ) => + checkAndSendVectorEmbeddingPoliciesToSettings(newVectorEmbeddings, newVectorIndexes, validationPassed) + } discardChanges={discardVectorChanges} onChangesDiscarded={onVectorChangesDiscarded} /> diff --git a/src/Explorer/Controls/Settings/SettingsUtils.tsx b/src/Explorer/Controls/Settings/SettingsUtils.tsx index 5bb49fa95..5d8e2766c 100644 --- a/src/Explorer/Controls/Settings/SettingsUtils.tsx +++ b/src/Explorer/Controls/Settings/SettingsUtils.tsx @@ -14,6 +14,7 @@ export type isDirtyTypes = | DataModels.IndexingPolicy | DataModels.ComputedProperties | DataModels.VectorEmbedding[] + | DataModels.VectorIndex[] | DataModels.FullTextPolicy | DataModels.ThroughputBucket[] | DataModels.DataMaskingPolicy; diff --git a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap index 9abb900b5..876f42ada 100644 --- a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap +++ b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap @@ -359,10 +359,13 @@ exports[`SettingsComponent renders 1`] = ` onVectorEmbeddingPolicyChange={[Function]} onVectorEmbeddingPolicyDirtyChange={[Function]} onVectorEmbeddingPolicyValidationChange={[Function]} + onVectorIndexesChange={[Function]} resetShouldDiscardContainerPolicyChange={[Function]} shouldDiscardContainerPolicies={false} vectorEmbeddingPolicy={{}} vectorEmbeddingPolicyBaseline={{}} + vectorIndexes={[]} + vectorIndexesBaseline={[]} /> diff --git a/src/Explorer/Controls/VectorSearch/VectorEmbeddingPoliciesComponent.tsx b/src/Explorer/Controls/VectorSearch/VectorEmbeddingPoliciesComponent.tsx index ba2610fb4..88a6f021b 100644 --- a/src/Explorer/Controls/VectorSearch/VectorEmbeddingPoliciesComponent.tsx +++ b/src/Explorer/Controls/VectorSearch/VectorEmbeddingPoliciesComponent.tsx @@ -16,7 +16,10 @@ import { getDataTypeOptions, getDistanceFunctionOptions, getIndexTypeOptions, + getQuantizerTypeOptions, + supportsQuantization, } from "Explorer/Controls/VectorSearch/VectorSearchUtils"; +import { Keys, t } from "Localization"; import React, { FunctionComponent, useState } from "react"; export interface IVectorEmbeddingPoliciesComponentProps { @@ -46,6 +49,7 @@ export interface VectorEmbeddingPolicyData { indexingSearchListSizeError?: string; quantizationByteSize?: number; quantizationByteSizeError?: string; + quantizerType?: VectorIndex["quantizerType"]; } type VectorEmbeddingPolicyProperty = "dataType" | "distanceFunction" | "indexType"; @@ -110,7 +114,7 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent { let error = ""; if (!path) { - error = "Path should not be empty"; + error = t(Keys.controls.vectorEmbeddingPolicies.pathEmptyError); } if ( index >= 0 && @@ -119,7 +123,7 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent { let error = ""; if (dimension <= 0 || dimension > 4096) { - error = "Dimension must be greater than 0 and less than or equal 4096"; + error = t(Keys.controls.vectorEmbeddingPolicies.dimensionRangeError); } if (indexType === "flat" && dimension > 505) { - error = "Maximum allowed dimension for flat index is 505"; + error = t(Keys.controls.vectorEmbeddingPolicies.dimensionFlatIndexError); } return error; }; @@ -138,7 +142,7 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent { let error = ""; if (size < 1 || size > 512) { - error = "Quantization byte size must be greater than 0 and less than or equal to 512"; + error = t(Keys.controls.vectorEmbeddingPolicies.quantizationByteSizeRangeError); } return error; }; @@ -146,7 +150,7 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent { let error = ""; if (size < 25 || size > 500) { - error = "Indexing search list size must be greater than or equal to 25 and less than or equal to 500"; + error = t(Keys.controls.vectorEmbeddingPolicies.indexingSearchListSizeRangeError); } return error; }; @@ -155,11 +159,14 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent { const matchingIndex = displayIndexes ? vectorIndexes.find((index) => index.path === embedding.path) : undefined; + const matchingType = matchingIndex?.type; + const supportsQuantizer = supportsQuantization(matchingType); mergedData.push({ ...embedding, - indexType: matchingIndex?.type || "none", + indexType: matchingType || "none", indexingSearchListSize: matchingIndex?.indexingSearchListSize || undefined, quantizationByteSize: matchingIndex?.quantizationByteSize || undefined, + quantizerType: supportsQuantizer ? matchingIndex?.quantizerType || "product" : undefined, vectorIndexShardKey: matchingIndex?.vectorIndexShardKey || undefined, pathError: onVectorEmbeddingPathError(embedding.path), dimensionsError: onVectorEmbeddingDimensionError(embedding.dimensions, matchingIndex?.type || "none"), @@ -202,6 +209,9 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent { + const vectorEmbeddings = [...vectorEmbeddingPolicyData]; + vectorEmbeddings[index].quantizerType = option.key as VectorIndex["quantizerType"]; setVectorEmbeddingPolicyData(vectorEmbeddings); }; @@ -306,8 +327,10 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent { - const containerName: string = isGlobalSecondaryIndex ? "global secondary index" : "container"; - return `This is dynamically set by the ${containerName} if left blank, or it can be set to a fixed number`; + const containerName = isGlobalSecondaryIndex + ? t(Keys.controls.vectorEmbeddingPolicies.quantizationByteSizeTooltipGlobalSecondaryIndexName) + : t(Keys.controls.vectorEmbeddingPolicies.quantizationByteSizeTooltipContainerName); + return t(Keys.controls.vectorEmbeddingPolicies.quantizationByteSizeTooltip, { containerName }); }; return ( @@ -319,7 +342,7 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent onDelete(index)} disableDelete={false} @@ -337,7 +360,7 @@ export const VectorEmbeddingPoliciesComponent: FunctionComponent - Quantization byte size + {t(Keys.controls.vectorEmbeddingPolicies.quantizationByteSize)} {getQuantizationByteSizeTooltipContent()} + + + , option: IDropdownOption) => + onQuantizerTypeChange(index, option) + } + /> + - Vector index shard key + {t(Keys.controls.vectorEmbeddingPolicies.vectorIndexShardKey)} ))} - Add vector embedding + {t(Keys.controls.vectorEmbeddingPolicies.addVectorEmbedding)} ); diff --git a/src/Explorer/Controls/VectorSearch/VectorSearchUtils.ts b/src/Explorer/Controls/VectorSearch/VectorSearchUtils.ts index 745a6cce0..7e90053fc 100644 --- a/src/Explorer/Controls/VectorSearch/VectorSearchUtils.ts +++ b/src/Explorer/Controls/VectorSearch/VectorSearchUtils.ts @@ -1,4 +1,6 @@ import { IDropdownOption } from "@fluentui/react"; +import { VectorIndex } from "Contracts/DataModels"; +import { Keys, t } from "Localization"; const dataTypes = ["float32", "uint8", "int8", "float16"]; const distanceFunctions = ["euclidean", "cosine", "dotproduct"]; @@ -7,6 +9,13 @@ const indexTypes = ["none", "flat", "diskANN", "quantizedFlat"]; export const getDataTypeOptions = (): IDropdownOption[] => createDropdownOptionsFromLiterals(dataTypes); export const getDistanceFunctionOptions = (): IDropdownOption[] => createDropdownOptionsFromLiterals(distanceFunctions); export const getIndexTypeOptions = (): IDropdownOption[] => createDropdownOptionsFromLiterals(indexTypes); +export const getQuantizerTypeOptions = (): IDropdownOption[] => [ + { key: "product", text: "Product" }, + { key: "spherical", text: `Spherical (${t(Keys.common.preview)})` }, +]; + +export const supportsQuantization = (indexType: VectorIndex["type"] | "none" | undefined): boolean => + indexType === "quantizedFlat" || indexType === "diskANN"; function createDropdownOptionsFromLiterals(literals: T[]): IDropdownOption[] { return literals.map((value) => ({ diff --git a/src/Explorer/Notebook/useNotebook.ts b/src/Explorer/Notebook/useNotebook.ts index 1ab4171fd..88b39aab8 100644 --- a/src/Explorer/Notebook/useNotebook.ts +++ b/src/Explorer/Notebook/useNotebook.ts @@ -1,15 +1,13 @@ -import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility"; -import { PhoenixClient } from "Phoenix/PhoenixClient"; import { cloneDeep } from "lodash"; import create, { UseStore } from "zustand"; import { AuthType } from "../../AuthType"; import * as Constants from "../../Common/Constants"; -import { ConnectionStatusType, HttpStatusCodes } from "../../Common/Constants"; +import { ConnectionStatusType } from "../../Common/Constants"; import { getErrorMessage } from "../../Common/ErrorHandlingUtils"; import * as Logger from "../../Common/Logger"; import { configContext } from "../../ConfigContext"; import * as DataModels from "../../Contracts/DataModels"; -import { ContainerConnectionInfo, ContainerInfo, PhoenixErrorType } from "../../Contracts/DataModels"; +import { ContainerConnectionInfo, ContainerInfo } from "../../Contracts/DataModels"; import { IPinnedRepo } from "../../Juno/JunoClient"; import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants"; import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; @@ -309,34 +307,9 @@ export const useNotebook: UseStore = create((set, get) => ({ setContainerStatus: (containerStatus: ContainerInfo) => set({ containerStatus }), getPhoenixStatus: async () => { if (get().isPhoenixNotebooks === undefined || get().isPhoenixFeatures === undefined) { - const startKey = TelemetryProcessor.traceStart(Action.CheckPhoenixStatus, { - dataExplorerArea: "Notebook", - }); - let isPhoenixNotebooks = false; - let isPhoenixFeatures = false; - - const isPublicInternetAllowed = isPublicInternetAccessAllowed(); - const phoenixClient = new PhoenixClient(userContext?.databaseAccount?.id); - const dbAccountAllowedInfo = await phoenixClient.getDbAccountAllowedStatus(); - - if (dbAccountAllowedInfo.status === HttpStatusCodes.OK) { - if (dbAccountAllowedInfo?.type === PhoenixErrorType.PhoenixFlightFallback) { - isPhoenixNotebooks = isPublicInternetAllowed && userContext.features.phoenixNotebooks === true; - isPhoenixFeatures = - isPublicInternetAllowed && - // phoenix needs to be enabled for Postgres and VCoreMongo accounts since the PSQL and mongo shell requires phoenix containers - (userContext.features.phoenixFeatures === true || - userContext.apiType === "Postgres" || - userContext.apiType === "VCoreMongo"); - } else { - isPhoenixNotebooks = isPhoenixFeatures = isPublicInternetAllowed; - } - } else { - isPhoenixNotebooks = isPhoenixFeatures = false; - } - set({ isPhoenixNotebooks: isPhoenixNotebooks }); - set({ isPhoenixFeatures: isPhoenixFeatures }); - TelemetryProcessor.traceSuccess(Action.CheckPhoenixStatus, { isPhoenixNotebooks, isPhoenixFeatures }, startKey); + // getDbAccountAllowedStatus has been deprecated; Phoenix features are no longer available. + set({ isPhoenixNotebooks: false }); + set({ isPhoenixFeatures: false }); } }, setIsPhoenixNotebooks: (isPhoenixNotebooks: boolean) => set({ isPhoenixNotebooks: isPhoenixNotebooks }), diff --git a/src/Explorer/Panes/AddCollectionPanel/AddCollectionPanel.tsx b/src/Explorer/Panes/AddCollectionPanel/AddCollectionPanel.tsx index d598a3eb0..bb8fd7f24 100644 --- a/src/Explorer/Panes/AddCollectionPanel/AddCollectionPanel.tsx +++ b/src/Explorer/Panes/AddCollectionPanel/AddCollectionPanel.tsx @@ -17,7 +17,6 @@ import { } from "@fluentui/react"; import * as Constants from "Common/Constants"; import { createCollection } from "Common/dataAccess/createCollection"; -import { getNewDatabaseSharedThroughputDefault } from "Common/DatabaseUtility"; import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils"; import { configContext, Platform } from "ConfigContext"; import * as DataModels from "Contracts/DataModels"; @@ -77,7 +76,6 @@ export const DefaultVectorEmbeddingPolicy: DataModels.VectorEmbeddingPolicy = { export interface AddCollectionPanelState { createNewDatabase: boolean; newDatabaseId: string; - isSharedThroughputChecked: boolean; selectedDatabaseId: string; collectionId: string; enableIndexing: boolean; @@ -103,8 +101,6 @@ export interface AddCollectionPanelState { } export class AddCollectionPanel extends React.Component { - private newDatabaseThroughput: number; - private isNewDatabaseAutoscale: boolean; private collectionThroughput: number; private isCollectionAutoscale: boolean; private isCostAcknowledged: boolean; @@ -117,7 +113,6 @@ export class AddCollectionPanel extends React.Component - - {!isServerlessAccount() && ( - - , isChecked: boolean) => - this.setState({ isSharedThroughputChecked: isChecked }) - } - /> - - - - - )} - - {!isServerlessAccount() && this.state.isSharedThroughputChecked && ( - (this.newDatabaseThroughput = throughput)} - setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)} - setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) => - this.setState({ isThroughputCapExceeded }) - } - onCostAcknowledgeChange={(isAcknowledge: boolean) => (this.isCostAcknowledged = isAcknowledge)} - /> - )} )} {!this.state.createNewDatabase && ( @@ -515,59 +455,57 @@ export class AddCollectionPanel extends React.Component )} - {userContext.apiType === "Mongo" && - (!this.state.isSharedThroughputChecked || - this.props.explorer.isFixedCollectionWithSharedThroughputSupported()) && ( - - - - - {t(Keys.panes.addCollection.sharding)} - - - - - - - - + + + + {t(Keys.panes.addCollection.sharding)} + + + - {t(Keys.panes.addCollection.unshardedLabel)} - - - {t(Keys.panes.addCollection.sharded)} - + - )} + + + + {t(Keys.panes.addCollection.unshardedLabel)} + + + {t(Keys.panes.addCollection.sharded)} + + + )} {this.state.isSharded && ( @@ -1191,7 +1129,7 @@ export class AddCollectionPanel extends React.Component CollectionCreation.DefaultCollectionRUs100K && !this.isCostAcknowledged) { - const errorMessage = this.isNewDatabaseAutoscale + const errorMessage = this.isCollectionAutoscale ? t(Keys.panes.addCollection.acknowledgeSpendErrorMonthly) : t(Keys.panes.addCollection.acknowledgeSpendErrorDaily); this.setState({ errorMessage }); @@ -1379,9 +1315,7 @@ export class AddCollectionPanel extends React.Component - - - - - - = ({ buttonElement, }: AddDatabasePaneProps) => { const closeSidePanel = useSidePanel((state) => state.closeSidePanel); - let throughput: number; - let isAutoscaleSelected: boolean; - let isCostAcknowledged: boolean; const { subscriptionType } = userContext; const isCassandraAccount: boolean = userContext.apiType === "Cassandra"; const databaseLabel: string = isCassandraAccount ? "keyspace" : "database"; @@ -49,23 +41,15 @@ export const AddDatabasePanel: FunctionComponent = ({ const [databaseId, setDatabaseId] = useState(""); const databaseIdTooltipText = t(Keys.panes.addDatabase.databaseTooltip, { databaseLabel, collectionsLabel }); - const databaseLevelThroughputTooltipText = t(Keys.panes.addDatabase.shareThroughputTooltip, { - databaseLabel, - collectionsLabel, - }); - const [databaseCreateNewShared, setDatabaseCreateNewShared] = useState( - getNewDatabaseSharedThroughputDefault(), - ); const [formErrors, setFormErrors] = useState(""); const [isExecuting, setIsExecuting] = useState(false); - const [isThroughputCapExceeded, setIsThroughputCapExceeded] = useState(false); const isFreeTierAccount: boolean = userContext.databaseAccount?.properties?.enableFreeTier; const addDatabasePaneMessage = { database: { id: databaseId, - shared: databaseCreateNewShared, + shared: false, }, subscriptionType: SubscriptionType[subscriptionType], subscriptionQuotaId: userContext.quotaId, @@ -76,9 +60,7 @@ export const AddDatabasePanel: FunctionComponent = ({ const addDatabasePaneOpenMessage = { subscriptionType: SubscriptionType[subscriptionType], subscriptionQuotaId: userContext.quotaId, - defaultsCheck: { - throughput, - }, + defaultsCheck: {}, dataExplorerArea: Constants.Areas.ContextualPane, }; TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage); @@ -88,13 +70,8 @@ export const AddDatabasePanel: FunctionComponent = ({ }, []); const onSubmit = () => { - if (!_isValid()) { - return; - } - const addDatabasePaneStartMessage = { ...addDatabasePaneMessage, - throughput, }; const startKey: number = TelemetryProcessor.traceStart(Action.CreateDatabase, addDatabasePaneStartMessage); setFormErrors(""); @@ -102,69 +79,41 @@ export const AddDatabasePanel: FunctionComponent = ({ const createDatabaseParams: DataModels.CreateDatabaseParams = { databaseId: addDatabasePaneStartMessage.database.id, - databaseLevelThroughput: addDatabasePaneStartMessage.database.shared, + databaseLevelThroughput: false, }; - if (isAutoscaleSelected) { - createDatabaseParams.autoPilotMaxThroughput = addDatabasePaneStartMessage.throughput; - } else { - createDatabaseParams.offerThroughput = addDatabasePaneStartMessage.throughput; - } createDatabase(createDatabaseParams).then( () => { - _onCreateDatabaseSuccess(throughput, startKey); + _onCreateDatabaseSuccess(startKey); }, (error: string) => { - _onCreateDatabaseFailure(error, throughput, startKey); + _onCreateDatabaseFailure(error, startKey); }, ); }; - const _onCreateDatabaseSuccess = (offerThroughput: number, startKey: number): void => { + const _onCreateDatabaseSuccess = (startKey: number): void => { setIsExecuting(false); closeSidePanel(); container.refreshAllDatabases(); const addDatabasePaneSuccessMessage = { ...addDatabasePaneMessage, - offerThroughput, }; TelemetryProcessor.traceSuccess(Action.CreateDatabase, addDatabasePaneSuccessMessage, startKey); }; - const _onCreateDatabaseFailure = (error: string, offerThroughput: number, startKey: number): void => { + const _onCreateDatabaseFailure = (error: string, startKey: number): void => { setIsExecuting(false); const errorMessage = getErrorMessage(error); setFormErrors(errorMessage); const addDatabasePaneFailedMessage = { ...addDatabasePaneMessage, - offerThroughput, error: errorMessage, errorStack: getErrorStack(error), }; TelemetryProcessor.traceFailure(Action.CreateDatabase, addDatabasePaneFailedMessage, startKey); }; - const _isValid = (): boolean => { - // TODO add feature flag that disables validation for customers with custom accounts - if (isAutoscaleSelected) { - if (!AutoPilotUtils.isValidAutoPilotThroughput(throughput)) { - setFormErrors(t(Keys.panes.addDatabase.greaterThanError, { minValue: AutoPilotUtils.autoPilotThroughput1K })); - return false; - } - } - - if (throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && !isCostAcknowledged) { - setFormErrors( - isAutoscaleSelected - ? t(Keys.panes.addDatabase.acknowledgeSpendErrorMonthly) - : t(Keys.panes.addDatabase.acknowledgeSpendErrorDaily), - ); - return false; - } - - return true; - }; - const handleonChangeDBId = React.useCallback( (event: React.FormEvent, newValue?: string) => { setDatabaseId(newValue || ""); @@ -176,7 +125,6 @@ export const AddDatabasePanel: FunctionComponent = ({ formError: formErrors, isExecuting, submitButtonText: t(Keys.common.ok), - isSubmitButtonDisabled: isThroughputCapExceeded, onSubmit, }; @@ -224,42 +172,7 @@ export const AddDatabasePanel: FunctionComponent = ({ data-lpignore={true} data-1p-ignore={true} /> - - {!isServerlessAccount() && ( - - setDatabaseCreateNewShared(!databaseCreateNewShared)} - /> - {databaseLevelThroughputTooltipText} - - )} - - {!isServerlessAccount() && databaseCreateNewShared && ( - (throughput = newThroughput)} - setIsAutoscale={(isAutoscale: boolean) => (isAutoscaleSelected = isAutoscale)} - setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)} - onCostAcknowledgeChange={(isAcknowledged: boolean) => (isCostAcknowledged = isAcknowledged)} - /> - )} ); diff --git a/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap b/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap index 6d53644ab..c9ab614a6 100644 --- a/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap +++ b/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap @@ -4,7 +4,6 @@ exports[`AddDatabasePane Pane should render Default properly 1`] = ` @@ -61,42 +60,6 @@ exports[`AddDatabasePane Pane should render Default properly 1`] = ` type="text" value="" /> - - - - Provisioned throughput at the database level will be shared across all collections within the database. - - diff --git a/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.test.tsx b/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.test.tsx index 67944d7ab..4391be995 100644 --- a/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.test.tsx +++ b/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.test.tsx @@ -15,7 +15,7 @@ describe("Cassandra add collection pane test", () => { it("should render default properly", () => { expect(screen.getByRole("radio", { name: "Create new keyspace", checked: true })).toBeDefined(); - expect(screen.getByRole("checkbox", { name: "Provision shared throughput", checked: false })).toBeDefined(); + expect(screen.queryByRole("checkbox", { name: "Provision shared throughput" })).toBeNull(); }); it("click on use existing", () => { diff --git a/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.tsx b/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.tsx index 525373d64..dcbcdf379 100644 --- a/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.tsx +++ b/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.tsx @@ -1,4 +1,4 @@ -import { Checkbox, Dropdown, IDropdownOption, Link, Stack, Text, TextField } from "@fluentui/react"; +import { Dropdown, IDropdownOption, Link, Stack, Text, TextField } from "@fluentui/react"; import * as Constants from "Common/Constants"; import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils"; import { InfoTooltip } from "Common/Tooltip/InfoTooltip"; @@ -27,8 +27,6 @@ export const CassandraAddCollectionPane: FunctionComponent { - let newKeySpaceThroughput: number; - let isNewKeySpaceAutoscale: boolean; let tableThroughput: number; let isTableAutoscale: boolean; let isCostAcknowledged: boolean; @@ -52,7 +50,7 @@ export const CassandraAddCollectionPane: FunctionComponent { - const throughput = keyspaceCreateNew ? newKeySpaceThroughput : tableThroughput; + const throughput = tableThroughput; const keyspaceId = keyspaceCreateNew ? newKeyspaceId : existingKeyspaceId; if (throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && !isCostAcknowledged) { - const errorMessage = - isNewKeySpaceAutoscale || isTableAutoscale - ? t(Keys.panes.addCollection.acknowledgeSpendErrorMonthly) - : t(Keys.panes.addCollection.acknowledgeSpendErrorDaily); + const errorMessage = isTableAutoscale + ? t(Keys.panes.addCollection.acknowledgeSpendErrorMonthly) + : t(Keys.panes.addCollection.acknowledgeSpendErrorDaily); setFormError(errorMessage); return; } setIsExecuting(true); - const autoPilotCommand = `cosmosdb_autoscale_max_throughput`; const createKeyspaceQueryPrefix = `CREATE KEYSPACE ${keyspaceId.trim()} WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 3 }`; - const createKeyspaceQuery: string = isKeyspaceShared - ? isNewKeySpaceAutoscale - ? `${createKeyspaceQueryPrefix} AND ${autoPilotCommand}=${newKeySpaceThroughput};` - : `${createKeyspaceQueryPrefix} AND cosmosdb_provisioned_throughput=${newKeySpaceThroughput};` - : `${createKeyspaceQueryPrefix};`; + const createKeyspaceQuery = `${createKeyspaceQueryPrefix};`; let tableQuery: string; + const autoPilotCommand = `cosmosdb_autoscale_max_throughput`; const createTableQueryPrefix = `CREATE TABLE ${keyspaceId}.${tableId.trim()} ${userTableQuery}`; if (tableThroughput) { @@ -177,7 +170,6 @@ export const CassandraAddCollectionPane: FunctionComponent { setKeyspaceCreateNew(true); - setIsKeyspaceShared(false); setExistingKeyspaceId(""); }} /> @@ -192,7 +184,6 @@ export const CassandraAddCollectionPane: FunctionComponent { setKeyspaceCreateNew(false); - setIsKeyspaceShared(false); }} /> {t(Keys.panes.addCollection.useExisting)} @@ -214,25 +205,6 @@ export const CassandraAddCollectionPane: FunctionComponent - - {!isServerlessAccount() && ( - - , isChecked: boolean) => setIsKeyspaceShared(isChecked)} - /> - - Provisioned throughput at the keyspace level will be shared across unlimited number of tables within - the keyspace - - - )} )} @@ -256,21 +228,6 @@ export const CassandraAddCollectionPane: FunctionComponent )} - - {!isServerlessAccount() && keyspaceCreateNew && isKeyspaceShared && ( - (newKeySpaceThroughput = throughput)} - setIsAutoscale={(isAutoscale: boolean) => (isNewKeySpaceAutoscale = isAutoscale)} - setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)} - onCostAcknowledgeChange={(isAcknowledged: boolean) => (isCostAcknowledged = isAcknowledged)} - /> - )} @@ -328,7 +285,7 @@ export const CassandraAddCollectionPane: FunctionComponent{t(Keys.panes.cassandraAddCollection.provisionDedicatedThroughputTooltip)} )} - {!isServerlessAccount() && (!isKeyspaceShared || dedicateTableThroughput) && ( + {!isServerlessAccount() && (keyspaceCreateNew || !isKeyspaceShared || dedicateTableThroughput) && ( { const wrapper = mount( undefined} />); expect(wrapper).toMatchSnapshot(); + expect(wrapper.exists("#copyableCollectionId")).toBe(true); + expect(wrapper.find("#copyableCollectionId").hostNodes().prop("value")).toBe(selectedCollectionId); + expect(wrapper.exists("#confirmCollectionId")).toBe(true); wrapper .find("#confirmCollectionId") diff --git a/src/Explorer/Panes/DeleteCollectionConfirmationPane/DeleteCollectionConfirmationPane.tsx b/src/Explorer/Panes/DeleteCollectionConfirmationPane/DeleteCollectionConfirmationPane.tsx index 3f3fae58d..0e7bd63c2 100644 --- a/src/Explorer/Panes/DeleteCollectionConfirmationPane/DeleteCollectionConfirmationPane.tsx +++ b/src/Explorer/Panes/DeleteCollectionConfirmationPane/DeleteCollectionConfirmationPane.tsx @@ -1,4 +1,4 @@ -import { Text, TextField } from "@fluentui/react"; +import { IconButton, Text, TextField } from "@fluentui/react"; import { Areas } from "Common/Constants"; import DeleteFeedback from "Common/DeleteFeedback"; import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils"; @@ -17,6 +17,7 @@ import React, { FunctionComponent, useState } from "react"; import { useDatabases } from "../../useDatabases"; import { useSelectedNode } from "../../useSelectedNode"; import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm"; +import { PanelInfoErrorComponent, PanelInfoErrorProps } from "../PanelInfoErrorComponent"; const themedTextFieldStyles = { fieldGroup: { @@ -54,6 +55,10 @@ export const DeleteCollectionConfirmationPane: FunctionComponent => { const collection = useSelectedNode.getState().findSelectedCollection(); @@ -131,6 +136,14 @@ export const DeleteCollectionConfirmationPane: FunctionComponent + {!formError && }
+ + {copyableIdLabel} + + ( + navigator.clipboard.writeText(selectedCollectionId)} + styles={{ root: { height: "100%" } }} + /> + )} + ariaLabel={copyableIdLabel} + /> * {confirmContainer} diff --git a/src/Explorer/Panes/DeleteCollectionConfirmationPane/__snapshots__/DeleteCollectionConfirmationPane.test.tsx.snap b/src/Explorer/Panes/DeleteCollectionConfirmationPane/__snapshots__/DeleteCollectionConfirmationPane.test.tsx.snap index f7f77d195..abf7e2091 100644 --- a/src/Explorer/Panes/DeleteCollectionConfirmationPane/__snapshots__/DeleteCollectionConfirmationPane.test.tsx.snap +++ b/src/Explorer/Panes/DeleteCollectionConfirmationPane/__snapshots__/DeleteCollectionConfirmationPane.test.tsx.snap @@ -14,6 +14,336 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect className="panelFormWrapper" onSubmit={[Function]} > + + +
+ + + +  + + + + + + + Warning! The action you are about to take cannot be undone. Continuing will permanently delete this resource and all of its children resources. + + + +
+
+
@@ -23,6 +353,1527 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
+ + + Container Id: + + + + +
+
+
+ +
+ + + + span": { + "left": 0, + "position": "relative", + "top": 0, + }, + "border": "1px solid #8a8886", + "borderRadius": "2px", + "boxSizing": "border-box", + "cursor": "pointer", + "display": "inline-block", + "padding": "0 16px", + "textAlign": "center", + "textDecoration": "none", + "userSelect": "none", + }, + { + "backgroundColor": "transparent", + "border": "none", + "color": "#0078d4", + "height": "32px", + "padding": "0 4px", + "width": "32px", + }, + { + "height": "100%", + }, + ], + "rootChecked": { + "backgroundColor": "#edebe9", + "color": "#005a9e", + }, + "rootCheckedHovered": { + "backgroundColor": "#e1dfdd", + "color": "#005a9e", + }, + "rootDisabled": [ + { + "outline": "transparent", + "position": "relative", + "selectors": { + ".ms-Fabric--isFocusVisible &:focus:after, :host(.ms-Fabric--isFocusVisible) &:focus:after": { + "border": "1px solid transparent", + "borderRadius": undefined, + "bottom": 2, + "content": """", + "left": 2, + "outline": "1px solid #605e5c", + "pointerEvents": undefined, + "position": "absolute", + "right": 2, + "selectors": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "bottom": -2, + "left": -2, + "outlineColor": "ButtonText", + "right": -2, + "top": -2, + }, + }, + "top": 2, + "zIndex": 1, + }, + "::-moz-focus-inner": { + "border": "0", + }, + }, + }, + { + ":focus": { + "outline": 0, + }, + ":hover": { + "outline": 0, + }, + "backgroundColor": "#f3f2f1", + "borderColor": "#f3f2f1", + "color": "#a19f9d", + "cursor": "default", + }, + { + "color": "#c8c6c4", + }, + ], + "rootExpanded": { + "backgroundColor": "#edebe9", + "color": "#005a9e", + }, + "rootHasMenu": { + "width": "auto", + }, + "rootHovered": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "borderColor": "Highlight", + "color": "Highlight", + }, + "backgroundColor": "#f3f2f1", + "color": "#106ebe", + }, + "rootPressed": { + "backgroundColor": "#edebe9", + "color": "#005a9e", + }, + "screenReaderText": { + "border": 0, + "height": 1, + "margin": -1, + "overflow": "hidden", + "padding": 0, + "position": "absolute", + "whiteSpace": "nowrap", + "width": 1, + }, + "splitButtonContainer": [ + { + "outline": "transparent", + "position": "relative", + "selectors": { + ".ms-Fabric--isFocusVisible &:focus:after, :host(.ms-Fabric--isFocusVisible) &:focus:after": { + "border": "1px solid #ffffff", + "borderRadius": undefined, + "bottom": 3, + "content": """", + "left": 3, + "outline": "1px solid #605e5c", + "pointerEvents": "none", + "position": "absolute", + "right": 3, + "selectors": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "border": "none", + "bottom": -2, + "left": -2, + "right": -2, + "top": -2, + }, + }, + "top": 3, + "zIndex": 1, + }, + "::-moz-focus-inner": { + "border": "0", + }, + }, + }, + { + ".ms-Button--default": { + "borderBottomRightRadius": "0", + "borderRight": "none", + "borderTopRightRadius": "0", + "flexGrow": "1", + }, + ".ms-Button--default + .ms-Button": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + ":hover": { + ".ms-Button-menuIcon": { + "MsHighContrastAdjust": "none", + "backgroundColor": "HighlightText", + "color": "Highlight", + "forcedColorAdjust": "none", + }, + "backgroundColor": "HighlightText", + "borderColor": "Highlight", + "color": "Highlight", + }, + "border": "1px solid WindowText", + "borderLeftWidth": "0", + }, + }, + ".ms-Button--default + .ms-Button[aria-expanded="true"]": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + ".ms-Button-menuIcon": { + "MsHighContrastAdjust": "none", + "backgroundColor": "HighlightText", + "color": "Highlight", + "forcedColorAdjust": "none", + }, + "backgroundColor": "HighlightText", + "borderColor": "Highlight", + "color": "Highlight", + }, + }, + ".ms-Button--primary": { + ":active": { + "border": "none", + }, + ":hover": { + "border": "none", + }, + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + ":active": { + "border": "1px solid Highlight", + }, + ":hover": { + "backgroundColor": "Highlight", + "border": "1px solid Highlight", + "borderRightWidth": "0", + "color": "HighlightText", + }, + "MsHighContrastAdjust": "none", + "backgroundColor": "Window", + "border": "1px solid WindowText", + "borderRightWidth": "0", + "color": "WindowText", + "forcedColorAdjust": "none", + }, + "border": "none", + "borderBottomRightRadius": "0", + "borderTopRightRadius": "0", + "flexGrow": "1", + }, + ".ms-Button--primary + .ms-Button": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + ":hover": { + ".ms-Button-menuIcon": { + "MsHighContrastAdjust": "none", + "color": "HighlightText", + "forcedColorAdjust": "none", + }, + "backgroundColor": "Highlight", + "borderColor": "Highlight", + "borderLeftWidth": "0", + "color": "HighlightText", + }, + "border": "1px solid WindowText", + "borderLeftWidth": "0", + }, + "border": "none", + }, + ".ms-Button--primary + .ms-Button[aria-expanded="true"]": { + ".ms-Button-menuIcon": { + "color": "HighlightText", + }, + "MsHighContrastAdjust": "none", + "backgroundColor": "Highlight", + "borderColor": "Highlight", + "color": "HighlightText", + "forcedColorAdjust": "none", + }, + ".ms-Button.is-disabled": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + }, + }, + "display": "inline-flex", + }, + ], + "splitButtonContainerChecked": { + ".ms-Button--primary": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "MsHighContrastAdjust": "none", + "backgroundColor": "WindowText", + "color": "Window", + "forcedColorAdjust": "none", + }, + }, + }, + "splitButtonContainerCheckedHovered": { + ".ms-Button--primary": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "MsHighContrastAdjust": "none", + "backgroundColor": "WindowText", + "color": "Window", + "forcedColorAdjust": "none", + }, + }, + }, + "splitButtonContainerDisabled": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "MsHighContrastAdjust": "none", + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + "forcedColorAdjust": "none", + }, + "border": "none", + "outline": "none", + }, + "splitButtonContainerFocused": { + "outline": "none!important", + }, + "splitButtonContainerHovered": { + ".ms-Button--default.is-disabled": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + }, + "backgroundColor": "#f3f2f1", + "color": "#a19f9d", + }, + ".ms-Button--primary.is-disabled": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + }, + "backgroundColor": "#f3f2f1", + "color": "#d2d0ce", + }, + }, + "splitButtonDivider": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "backgroundColor": "WindowText", + }, + "bottom": 8, + "position": "absolute", + "right": 31, + "top": 8, + "width": 1, + }, + "splitButtonDividerDisabled": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "backgroundColor": "GrayText", + }, + "bottom": 8, + "position": "absolute", + "right": 31, + "top": 8, + "width": 1, + }, + "splitButtonFlexContainer": { + "alignItems": "center", + "display": "flex", + "flexWrap": "nowrap", + "height": "100%", + "justifyContent": "center", + }, + "splitButtonMenuButton": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + ".ms-Button-menuIcon": { + "color": "WindowText", + }, + }, + "border": "1px solid #8a8886", + "borderBottomRightRadius": "2px", + "borderLeft": "none", + "borderRadius": 0, + "borderTopRightRadius": "2px", + "boxSizing": "border-box", + "cursor": "pointer", + "display": "inline-block", + "height": "auto", + "marginBottom": 0, + "marginLeft": -1, + "marginRight": 0, + "marginTop": 0, + "outline": "transparent", + "padding": 6, + "textAlign": "center", + "textDecoration": "none", + "userSelect": "none", + "verticalAlign": "top", + "width": 32, + }, + "splitButtonMenuButtonDisabled": { + ".ms-Button--primary": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "backgroundColor": "Window", + "borderColor": "GrayText", + "color": "GrayText", + }, + }, + ".ms-Button-menuIcon": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "color": "GrayText", + }, + }, + ":hover": { + "cursor": "default", + }, + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "backgroundColor": "Window", + "border": "1px solid GrayText", + "color": "GrayText", + }, + "border": "none", + "pointerEvents": "none", + }, + "splitButtonMenuFocused": { + "outline": "transparent", + "position": "relative", + "selectors": { + ".ms-Fabric--isFocusVisible &:focus:after, :host(.ms-Fabric--isFocusVisible) &:focus:after": { + "border": "1px solid #ffffff", + "borderRadius": undefined, + "bottom": 3, + "content": """", + "left": 3, + "outline": "1px solid #605e5c", + "pointerEvents": undefined, + "position": "absolute", + "right": 3, + "selectors": { + "@media screen and (-ms-high-contrast: active), screen and (forced-colors: active)": { + "border": "none", + "bottom": -2, + "left": -2, + "right": -2, + "top": -2, + }, + }, + "top": 3, + "zIndex": 1, + }, + "::-moz-focus-inner": { + "border": "0", + }, + }, + }, + "textContainer": { + "display": "block", + "flexGrow": 1, + }, + } + } + theme={ + { + "disableGlobalClassNames": false, + "effects": { + "elevation16": "0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132), 0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108)", + "elevation4": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)", + "elevation64": "0 25.6px 57.6px 0 rgba(0, 0, 0, 0.22), 0 4.8px 14.4px 0 rgba(0, 0, 0, 0.18)", + "elevation8": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)", + "roundedCorner2": "2px", + "roundedCorner4": "4px", + "roundedCorner6": "6px", + }, + "fonts": { + "large": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "18px", + "fontWeight": 400, + }, + "medium": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "14px", + "fontWeight": 400, + }, + "mediumPlus": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "16px", + "fontWeight": 400, + }, + "mega": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "68px", + "fontWeight": 600, + }, + "small": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "12px", + "fontWeight": 400, + }, + "smallPlus": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "12px", + "fontWeight": 400, + }, + "superLarge": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "42px", + "fontWeight": 600, + }, + "tiny": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "10px", + "fontWeight": 400, + }, + "xLarge": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "20px", + "fontWeight": 600, + }, + "xLargePlus": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "24px", + "fontWeight": 600, + }, + "xSmall": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "10px", + "fontWeight": 400, + }, + "xxLarge": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "28px", + "fontWeight": 600, + }, + "xxLargePlus": { + "MozOsxFontSmoothing": "grayscale", + "WebkitFontSmoothing": "antialiased", + "fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", + "fontSize": "32px", + "fontWeight": 600, + }, + }, + "isInverted": false, + "palette": { + "accent": "#0078d4", + "black": "#000000", + "blackTranslucent40": "rgba(0,0,0,.4)", + "blue": "#0078d4", + "blueDark": "#002050", + "blueLight": "#00bcf2", + "blueMid": "#00188f", + "green": "#107c10", + "greenDark": "#004b1c", + "greenLight": "#bad80a", + "magenta": "#b4009e", + "magentaDark": "#5c005c", + "magentaLight": "#e3008c", + "neutralDark": "#201f1e", + "neutralLight": "#edebe9", + "neutralLighter": "#f3f2f1", + "neutralLighterAlt": "#faf9f8", + "neutralPrimary": "#323130", + "neutralPrimaryAlt": "#3b3a39", + "neutralQuaternary": "#d2d0ce", + "neutralQuaternaryAlt": "#e1dfdd", + "neutralSecondary": "#605e5c", + "neutralSecondaryAlt": "#8a8886", + "neutralTertiary": "#a19f9d", + "neutralTertiaryAlt": "#c8c6c4", + "orange": "#d83b01", + "orangeLight": "#ea4300", + "orangeLighter": "#ff8c00", + "purple": "#5c2d91", + "purpleDark": "#32145a", + "purpleLight": "#b4a0ff", + "red": "#e81123", + "redDark": "#a4262c", + "teal": "#008272", + "tealDark": "#004b50", + "tealLight": "#00b294", + "themeDark": "#005a9e", + "themeDarkAlt": "#106ebe", + "themeDarker": "#004578", + "themeLight": "#c7e0f4", + "themeLighter": "#deecf9", + "themeLighterAlt": "#eff6fc", + "themePrimary": "#0078d4", + "themeSecondary": "#2b88d8", + "themeTertiary": "#71afe5", + "white": "#ffffff", + "whiteTranslucent40": "rgba(255,255,255,.4)", + "yellow": "#ffb900", + "yellowDark": "#d29200", + "yellowLight": "#fff100", + }, + "rtl": undefined, + "semanticColors": { + "accentButtonBackground": "#0078d4", + "accentButtonText": "#ffffff", + "actionLink": "#323130", + "actionLinkHovered": "#201f1e", + "blockingBackground": "#FDE7E9", + "blockingIcon": "#FDE7E9", + "bodyBackground": "#ffffff", + "bodyBackgroundChecked": "#edebe9", + "bodyBackgroundHovered": "#f3f2f1", + "bodyDivider": "#edebe9", + "bodyFrameBackground": "#ffffff", + "bodyFrameDivider": "#edebe9", + "bodyStandoutBackground": "#faf9f8", + "bodySubtext": "#605e5c", + "bodyText": "#323130", + "bodyTextChecked": "#000000", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#c8c6c4", + "buttonBackgroundCheckedHovered": "#edebe9", + "buttonBackgroundDisabled": "#f3f2f1", + "buttonBackgroundHovered": "#f3f2f1", + "buttonBackgroundPressed": "#edebe9", + "buttonBorder": "#8a8886", + "buttonBorderDisabled": "#f3f2f1", + "buttonText": "#323130", + "buttonTextChecked": "#201f1e", + "buttonTextCheckedHovered": "#000000", + "buttonTextDisabled": "#a19f9d", + "buttonTextHovered": "#201f1e", + "buttonTextPressed": "#201f1e", + "cardShadow": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)", + "cardShadowHovered": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)", + "cardStandoutBackground": "#ffffff", + "defaultStateBackground": "#faf9f8", + "disabledBackground": "#f3f2f1", + "disabledBodySubtext": "#c8c6c4", + "disabledBodyText": "#a19f9d", + "disabledBorder": "#c8c6c4", + "disabledSubtext": "#d2d0ce", + "disabledText": "#a19f9d", + "errorBackground": "#FDE7E9", + "errorIcon": "#A80000", + "errorText": "#a4262c", + "focusBorder": "#605e5c", + "infoBackground": "#f3f2f1", + "infoIcon": "#605e5c", + "inputBackground": "#ffffff", + "inputBackgroundChecked": "#0078d4", + "inputBackgroundCheckedHovered": "#005a9e", + "inputBorder": "#605e5c", + "inputBorderHovered": "#323130", + "inputFocusBorderAlt": "#0078d4", + "inputForegroundChecked": "#ffffff", + "inputIcon": "#0078d4", + "inputIconDisabled": "#a19f9d", + "inputIconHovered": "#005a9e", + "inputPlaceholderBackgroundChecked": "#deecf9", + "inputPlaceholderText": "#605e5c", + "inputText": "#323130", + "inputTextHovered": "#201f1e", + "link": "#0078d4", + "linkHovered": "#004578", + "listBackground": "#ffffff", + "listHeaderBackgroundHovered": "#f3f2f1", + "listHeaderBackgroundPressed": "#edebe9", + "listItemBackgroundChecked": "#edebe9", + "listItemBackgroundCheckedHovered": "#e1dfdd", + "listItemBackgroundHovered": "#f3f2f1", + "listText": "#323130", + "listTextColor": "#323130", + "menuBackground": "#ffffff", + "menuDivider": "#c8c6c4", + "menuHeader": "#0078d4", + "menuIcon": "#0078d4", + "menuItemBackgroundChecked": "#edebe9", + "menuItemBackgroundHovered": "#f3f2f1", + "menuItemBackgroundPressed": "#edebe9", + "menuItemText": "#323130", + "menuItemTextHovered": "#201f1e", + "messageLink": "#005A9E", + "messageLinkHovered": "#004578", + "messageText": "#323130", + "primaryButtonBackground": "#0078d4", + "primaryButtonBackgroundDisabled": "#f3f2f1", + "primaryButtonBackgroundHovered": "#106ebe", + "primaryButtonBackgroundPressed": "#005a9e", + "primaryButtonBorder": "transparent", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#d2d0ce", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "severeWarningBackground": "#FED9CC", + "severeWarningIcon": "#D83B01", + "smallInputBorder": "#605e5c", + "successBackground": "#DFF6DD", + "successIcon": "#107C10", + "successText": "#107C10", + "variantBorder": "#edebe9", + "variantBorderHovered": "#a19f9d", + "warningBackground": "#FFF4CE", + "warningHighlight": "#ffb900", + "warningIcon": "#797775", + "warningText": "#323130", + }, + "spacing": { + "l1": "20px", + "l2": "32px", + "m": "16px", + "s1": "8px", + "s2": "4px", + }, + } + } + title="Copy" + variantClassName="ms-Button--icon" + > + + + + + + +
+
+
+
+
+
@@ -37,7 +1888,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect variant="small" >
+ + + + + +
+
+
+
+ + @@ -699,7 +2220,7 @@ exports[`Delete Database Confirmation Pane Should call delete database 1`] = ` className="ms-TextField-wrapper" >