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/src/Contracts/DataModels.ts b/src/Contracts/DataModels.ts index 0a51d721a..39006ab76 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 { 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 f445caefd..6e0990849 100644 --- a/src/Explorer/Controls/Settings/SettingsUtils.tsx +++ b/src/Explorer/Controls/Settings/SettingsUtils.tsx @@ -1,7 +1,7 @@ +import { Keys, t } from "Localization"; import * as Constants from "../../../Common/Constants"; import * as DataModels from "../../../Contracts/DataModels"; import * as ViewModels from "../../../Contracts/ViewModels"; -import { Keys, t } from "Localization"; import { isFabricNative } from "../../../Platform/Fabric/FabricUtil"; import { userContext } from "../../../UserContext"; import { isCapabilityEnabled } from "../../../Utils/CapabilityUtils"; @@ -15,6 +15,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 daa26da90..819858641 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/Panes/DeleteCollectionConfirmationPane/DeleteCollectionConfirmationPane.test.tsx b/src/Explorer/Panes/DeleteCollectionConfirmationPane/DeleteCollectionConfirmationPane.test.tsx index 569017247..ed2e6f1ab 100644 --- a/src/Explorer/Panes/DeleteCollectionConfirmationPane/DeleteCollectionConfirmationPane.test.tsx +++ b/src/Explorer/Panes/DeleteCollectionConfirmationPane/DeleteCollectionConfirmationPane.test.tsx @@ -112,6 +112,9 @@ describe("Delete Collection Confirmation Pane", () => { 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" >