From b83f54e253026d07883c4ac56e2f360f68ab24d8 Mon Sep 17 00:00:00 2001 From: sakshigupta12feb Date: Mon, 2 Feb 2026 11:28:49 +0530 Subject: [PATCH] DDM login issue fixed while logging in via connection string (#2353) * DDM login issue fixed while logging in via connection string * Removed isPolicyEnabled. The includePaths field should be mandatory and, if present, must be an array * updated the included value validation and excluded to be optional --------- Co-authored-by: Sakshi Gupta --- src/Contracts/DataModels.ts | 3 +- .../Settings/SettingsComponent.test.tsx | 9 ---- .../Controls/Settings/SettingsComponent.tsx | 36 ++++--------- .../DataMaskingComponent.test.tsx | 10 ++-- .../DataMaskingComponent.tsx | 16 ++---- .../Controls/Settings/SettingsUtils.tsx | 15 ++++++ src/Explorer/Controls/Settings/TestUtils.tsx | 1 - .../SettingsComponent.test.tsx.snap | 52 +++++++++++++++++++ src/Explorer/Tree/Collection.ts | 1 - 9 files changed, 85 insertions(+), 58 deletions(-) diff --git a/src/Contracts/DataModels.ts b/src/Contracts/DataModels.ts index fef85ab87..0510a7c23 100644 --- a/src/Contracts/DataModels.ts +++ b/src/Contracts/DataModels.ts @@ -275,8 +275,7 @@ export interface DataMaskingPolicy { startPosition: number; length: number; }>; - excludedPaths: string[]; - isPolicyEnabled: boolean; + excludedPaths?: string[]; } export interface MaterializedView { diff --git a/src/Explorer/Controls/Settings/SettingsComponent.test.tsx b/src/Explorer/Controls/Settings/SettingsComponent.test.tsx index 7dfd49b11..ff7485b5e 100644 --- a/src/Explorer/Controls/Settings/SettingsComponent.test.tsx +++ b/src/Explorer/Controls/Settings/SettingsComponent.test.tsx @@ -30,7 +30,6 @@ jest.mock("../../../Common/dataAccess/updateCollection", () => ({ dataMaskingPolicy: { includedPaths: [], excludedPaths: ["/excludedPath"], - isPolicyEnabled: true, }, indexes: [], }), @@ -307,12 +306,10 @@ describe("SettingsComponent", () => { dataMaskingContent: { includedPaths: [], excludedPaths: ["/excludedPath"], - isPolicyEnabled: true, }, dataMaskingContentBaseline: { includedPaths: [], excludedPaths: [], - isPolicyEnabled: false, }, isDataMaskingDirty: true, }); @@ -326,7 +323,6 @@ describe("SettingsComponent", () => { expect(wrapper.state("dataMaskingContentBaseline")).toEqual({ includedPaths: [], excludedPaths: ["/excludedPath"], - isPolicyEnabled: true, }); }); @@ -340,7 +336,6 @@ describe("SettingsComponent", () => { const invalidPolicy: InvalidPolicy = { includedPaths: "invalid", excludedPaths: [], - isPolicyEnabled: false, }; // Use type assertion since we're deliberately testing with invalid data settingsComponentInstance["onDataMaskingContentChange"](invalidPolicy as unknown as DataModels.DataMaskingPolicy); @@ -349,7 +344,6 @@ describe("SettingsComponent", () => { expect(wrapper.state("dataMaskingContent")).toEqual({ includedPaths: "invalid", excludedPaths: [], - isPolicyEnabled: false, }); expect(wrapper.state("dataMaskingValidationErrors")).toEqual(["includedPaths must be an array"]); @@ -364,7 +358,6 @@ describe("SettingsComponent", () => { }, ], excludedPaths: ["/excludedPath"], - isPolicyEnabled: true, }; settingsComponentInstance["onDataMaskingContentChange"](validPolicy); @@ -388,7 +381,6 @@ describe("SettingsComponent", () => { }, ], excludedPaths: ["/excludedPath1"], - isPolicyEnabled: false, }; const modifiedPolicy = { @@ -401,7 +393,6 @@ describe("SettingsComponent", () => { }, ], excludedPaths: ["/excludedPath2"], - isPolicyEnabled: true, }; // Set initial state diff --git a/src/Explorer/Controls/Settings/SettingsComponent.tsx b/src/Explorer/Controls/Settings/SettingsComponent.tsx index 95f7159cc..9f50b53c2 100644 --- a/src/Explorer/Controls/Settings/SettingsComponent.tsx +++ b/src/Explorer/Controls/Settings/SettingsComponent.tsx @@ -16,7 +16,7 @@ import { import { useIndexingPolicyStore } from "Explorer/Tabs/QueryTab/ResultsView"; import { useDatabases } from "Explorer/useDatabases"; import { isFabricNative } from "Platform/Fabric/FabricUtil"; -import { isCapabilityEnabled, isVectorSearchEnabled } from "Utils/CapabilityUtils"; +import { isVectorSearchEnabled } from "Utils/CapabilityUtils"; import { isRunningOnPublicCloud } from "Utils/CloudUtils"; import * as React from "react"; import DiscardIcon from "../../../../images/discard.svg"; @@ -70,6 +70,7 @@ import { getMongoNotification, getTabTitle, hasDatabaseSharedThroughput, + isDataMaskingEnabled, isDirty, parseConflictResolutionMode, parseConflictResolutionProcedure, @@ -686,22 +687,14 @@ export class SettingsComponent extends React.Component { - if (!newDataMasking.excludedPaths) { - newDataMasking.excludedPaths = []; - } - if (!newDataMasking.includedPaths) { - newDataMasking.includedPaths = []; - } - const validationErrors = []; - if (!Array.isArray(newDataMasking.includedPaths)) { + if (newDataMasking.includedPaths === undefined || newDataMasking.includedPaths === null) { + validationErrors.push("includedPaths is required"); + } else if (!Array.isArray(newDataMasking.includedPaths)) { validationErrors.push("includedPaths must be an array"); } - if (!Array.isArray(newDataMasking.excludedPaths)) { - validationErrors.push("excludedPaths must be an array"); - } - if (typeof newDataMasking.isPolicyEnabled !== "boolean") { - validationErrors.push("isPolicyEnabled must be a boolean"); + if (newDataMasking.excludedPaths !== undefined && !Array.isArray(newDataMasking.excludedPaths)) { + validationErrors.push("excludedPaths must be an array if provided"); } this.setState({ @@ -842,7 +835,6 @@ export class SettingsComponent extends React.Component { - const hasDataMaskingCapability = isCapabilityEnabled(Constants.CapabilityNames.EnableDynamicDataMasking); - const isSqlAccount = userContext.apiType === "SQL"; - - return isSqlAccount && hasDataMaskingCapability; // Only show for SQL accounts with DDM capability - }; - - if (shouldEnableDDM()) { + if (isDataMaskingEnabled(this.collection.dataMaskingPolicy?.())) { const dataMaskingComponentProps: DataMaskingComponentProps = { shouldDiscardDataMasking: this.state.shouldDiscardDataMasking, resetShouldDiscardDataMasking: this.resetShouldDiscardDataMasking, diff --git a/src/Explorer/Controls/Settings/SettingsSubComponents/DataMaskingComponent.test.tsx b/src/Explorer/Controls/Settings/SettingsSubComponents/DataMaskingComponent.test.tsx index a51d55a32..4e25c1980 100644 --- a/src/Explorer/Controls/Settings/SettingsSubComponents/DataMaskingComponent.test.tsx +++ b/src/Explorer/Controls/Settings/SettingsSubComponents/DataMaskingComponent.test.tsx @@ -53,7 +53,6 @@ describe("DataMaskingComponent", () => { }, ], excludedPaths: [], - isPolicyEnabled: false, }; let changeContentCallback: () => void; @@ -78,7 +77,7 @@ describe("DataMaskingComponent", () => { , ); @@ -123,7 +122,7 @@ describe("DataMaskingComponent", () => { }); it("resets content when shouldDiscardDataMasking is true", async () => { - const baselinePolicy = { ...samplePolicy, isPolicyEnabled: true }; + const baselinePolicy = { ...samplePolicy, excludedPaths: ["/excluded"] }; const wrapper = mount( { wrapper.update(); // Update baseline to trigger componentDidUpdate - const newBaseline = { ...samplePolicy, isPolicyEnabled: true }; + const newBaseline = { ...samplePolicy, excludedPaths: ["/excluded"] }; wrapper.setProps({ dataMaskingContentBaseline: newBaseline }); expect(mockProps.onDataMaskingDirtyChange).toHaveBeenCalledWith(true); @@ -174,7 +173,6 @@ describe("DataMaskingComponent", () => { const invalidPolicy: Record = { includedPaths: "not an array", excludedPaths: [] as string[], - isPolicyEnabled: "not a boolean", }; mockGetValue.mockReturnValue(JSON.stringify(invalidPolicy)); @@ -197,7 +195,7 @@ describe("DataMaskingComponent", () => { wrapper.update(); // First change - const modifiedPolicy1 = { ...samplePolicy, isPolicyEnabled: true }; + const modifiedPolicy1 = { ...samplePolicy, excludedPaths: ["/path1"] }; mockGetValue.mockReturnValue(JSON.stringify(modifiedPolicy1)); changeContentCallback(); expect(mockProps.onDataMaskingDirtyChange).toHaveBeenCalledWith(true); diff --git a/src/Explorer/Controls/Settings/SettingsSubComponents/DataMaskingComponent.tsx b/src/Explorer/Controls/Settings/SettingsSubComponents/DataMaskingComponent.tsx index 80314fe7c..61ac40931 100644 --- a/src/Explorer/Controls/Settings/SettingsSubComponents/DataMaskingComponent.tsx +++ b/src/Explorer/Controls/Settings/SettingsSubComponents/DataMaskingComponent.tsx @@ -1,12 +1,10 @@ import { MessageBar, MessageBarType, Stack } from "@fluentui/react"; import * as monaco from "monaco-editor"; import * as React from "react"; -import * as Constants from "../../../../Common/Constants"; import * as DataModels from "../../../../Contracts/DataModels"; -import { isCapabilityEnabled } from "../../../../Utils/CapabilityUtils"; import { loadMonaco } from "../../../LazyMonaco"; import { titleAndInputStackProps, unsavedEditorWarningMessage } from "../SettingsRenderUtils"; -import { isDirty as isContentDirty } from "../SettingsUtils"; +import { isDirty as isContentDirty, isDataMaskingEnabled } from "../SettingsUtils"; export interface DataMaskingComponentProps { shouldDiscardDataMasking: boolean; @@ -24,16 +22,8 @@ interface DataMaskingComponentState { } const emptyDataMaskingPolicy: DataModels.DataMaskingPolicy = { - includedPaths: [ - { - path: "/", - strategy: "Default", - startPosition: 0, - length: -1, - }, - ], + includedPaths: [], excludedPaths: [], - isPolicyEnabled: true, }; export class DataMaskingComponent extends React.Component { @@ -140,7 +130,7 @@ export class DataMaskingComponent extends React.Component { + const isSqlAccount = userContext.apiType === "SQL"; + if (!isSqlAccount) { + return false; + } + + const hasDataMaskingCapability = isCapabilityEnabled(Constants.CapabilityNames.EnableDynamicDataMasking); + const hasDataMaskingPolicyFromCollection = + dataMaskingPolicy?.includedPaths?.length > 0 || dataMaskingPolicy?.excludedPaths?.length > 0; + + return hasDataMaskingCapability || hasDataMaskingPolicyFromCollection; +}; + export const parseConflictResolutionMode = (modeFromBackend: string): DataModels.ConflictResolutionMode => { // Backend can contain different casing as it does case-insensitive comparisson if (!modeFromBackend) { diff --git a/src/Explorer/Controls/Settings/TestUtils.tsx b/src/Explorer/Controls/Settings/TestUtils.tsx index f30e84709..c3b3f8b84 100644 --- a/src/Explorer/Controls/Settings/TestUtils.tsx +++ b/src/Explorer/Controls/Settings/TestUtils.tsx @@ -68,7 +68,6 @@ export const collection = { dataMaskingPolicy: ko.observable({ includedPaths: [], excludedPaths: ["/excludedPath"], - isPolicyEnabled: true, }), readSettings: () => { return; diff --git a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap index 569bfd035..7f8452ddf 100644 --- a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap +++ b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap @@ -604,6 +604,58 @@ exports[`SettingsComponent renders 1`] = ` /> + + + + + (), excludedPaths: Array(), - isPolicyEnabled: true, }; const observablePolicy = ko.observable(data.dataMaskingPolicy || defaultDataMaskingPolicy); observablePolicy.subscribe(() => {});