, checked?: boolean): void => {
setRUThresholdEnabled(checked);
};
@@ -383,6 +452,54 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
)}
+ {userContext.apiType === "SQL" && userContext.authType === AuthType.AAD && (
+ <>
+
+
+
+
+
+ >
+ )}
{userContext.apiType === "SQL" && (
<>
diff --git a/src/Shared/StorageUtility.ts b/src/Shared/StorageUtility.ts
index 652451e57..f2ca1f20b 100644
--- a/src/Shared/StorageUtility.ts
+++ b/src/Shared/StorageUtility.ts
@@ -6,6 +6,7 @@ import * as StringUtility from "./StringUtility";
export { LocalStorageUtility, SessionStorageUtility };
export enum StorageKey {
ActualItemPerPage,
+ DataPlaneRbacEnabled,
RUThresholdEnabled,
RUThreshold,
QueryTimeoutEnabled,
diff --git a/src/UserContext.ts b/src/UserContext.ts
index 30a0236dc..4718e3915 100644
--- a/src/UserContext.ts
+++ b/src/UserContext.ts
@@ -101,6 +101,7 @@ export interface UserContext {
sampleDataConnectionInfo?: ParsedResourceTokenConnectionString;
readonly vcoreMongoConnectionParams?: VCoreMongoConnectionParams;
readonly feedbackPolicies?: AdminFeedbackPolicySettings;
+ readonly dataPlaneRbacEnabled?: boolean;
}
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres" | "VCoreMongo";
diff --git a/src/hooks/useKnockoutExplorer.ts b/src/hooks/useKnockoutExplorer.ts
index 3a6061acd..3ee6a04a4 100644
--- a/src/hooks/useKnockoutExplorer.ts
+++ b/src/hooks/useKnockoutExplorer.ts
@@ -1,3 +1,4 @@
+import * as Constants from "Common/Constants";
import { createUri } from "Common/UrlUtility";
import { DATA_EXPLORER_RPC_VERSION } from "Contracts/DataExplorerMessagesContract";
import { FabricMessageTypes } from "Contracts/FabricMessageTypes";
@@ -5,6 +6,7 @@ import { FABRIC_RPC_VERSION, FabricMessageV2 } from "Contracts/FabricMessagesCon
import Explorer from "Explorer/Explorer";
import { useSelectedNode } from "Explorer/useSelectedNode";
import { scheduleRefreshDatabaseResourceToken } from "Platform/Fabric/FabricUtil";
+import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
import { getNetworkSettingsWarningMessage } from "Utils/NetworkUtility";
import { logConsoleError } from "Utils/NotificationConsoleUtils";
import { useQueryCopilot } from "hooks/useQueryCopilot";
@@ -41,6 +43,7 @@ import { isInvalidParentFrameOrigin, shouldProcessMessage } from "../Utils/Messa
import { listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
import { DatabaseAccountListKeysResult } from "../Utils/arm/generatedClients/cosmos/types";
import { applyExplorerBindings } from "../applyExplorerBindings";
+import { useDataPlaneRbac } from "Explorer/Panes/SettingsPane/SettingsPane";
// This hook will create a new instance of Explorer.ts and bind it to the DOM
// This hook has a LOT of magic, but ideally we can delete it once we have removed KO and switched entirely to React
@@ -253,7 +256,6 @@ async function configureHostedWithAAD(config: AAD): Promise {
const subscriptionId = accountResourceId && accountResourceId.split("subscriptions/")[1].split("/")[0];
const resourceGroup = accountResourceId && accountResourceId.split("resourceGroups/")[1].split("/")[0];
let aadToken;
- let keys: DatabaseAccountListKeysResult = {};
if (account.properties?.documentEndpoint) {
const hrefEndpoint = new URL(account.properties.documentEndpoint).href.replace(/\/$/, "/.default");
const msalInstance = await getMsalInstance();
@@ -271,8 +273,30 @@ async function configureHostedWithAAD(config: AAD): Promise {
}
}
try {
- if (!account.properties.disableLocalAuth) {
- keys = await listKeys(subscriptionId, resourceGroup, account.name);
+ updateUserContext({
+ databaseAccount: config.databaseAccount,
+ });
+
+ if (!userContext.features.enableAadDataPlane) {
+ if (userContext.apiType === "SQL") {
+ if (LocalStorageUtility.hasItem(StorageKey.DataPlaneRbacEnabled)) {
+ const isDataPlaneRbacSetting = LocalStorageUtility.getEntryString(StorageKey.DataPlaneRbacEnabled);
+
+ let dataPlaneRbacEnabled;
+ if (isDataPlaneRbacSetting === Constants.RBACOptions.setAutomaticRBACOption) {
+ dataPlaneRbacEnabled = account.properties.disableLocalAuth;
+ } else {
+ dataPlaneRbacEnabled = isDataPlaneRbacSetting === Constants.RBACOptions.setTrueRBACOption;
+ }
+
+ updateUserContext({ dataPlaneRbacEnabled });
+ }
+ } else {
+ const keys: DatabaseAccountListKeysResult = await listKeys(subscriptionId, resourceGroup, account.name);
+ updateUserContext({
+ masterKey: keys.primaryMasterKey,
+ });
+ }
}
} catch (e) {
if (userContext.features.enableAadDataPlane) {
@@ -285,8 +309,6 @@ async function configureHostedWithAAD(config: AAD): Promise {
subscriptionId,
resourceGroup,
aadToken,
- databaseAccount: config.databaseAccount,
- masterKey: keys.primaryMasterKey,
});
const explorer = new Explorer();
return explorer;
@@ -420,7 +442,7 @@ async function configurePortal(): Promise {
// In the Portal, configuration of Explorer happens via iframe message
window.addEventListener(
"message",
- (event) => {
+ async (event) => {
if (isInvalidParentFrameOrigin(event)) {
return;
}
@@ -450,6 +472,29 @@ async function configurePortal(): Promise {
setTimeout(() => explorer.openNPSSurveyDialog(), 3000);
}
+ const { databaseAccount: account, subscriptionId, resourceGroup } = userContext;
+
+ if (userContext.apiType === "SQL") {
+ if (LocalStorageUtility.hasItem(StorageKey.DataPlaneRbacEnabled)) {
+ const isDataPlaneRbacSetting = LocalStorageUtility.getEntryString(StorageKey.DataPlaneRbacEnabled);
+
+ let dataPlaneRbacEnabled;
+ if (isDataPlaneRbacSetting === Constants.RBACOptions.setAutomaticRBACOption) {
+ dataPlaneRbacEnabled = account.properties.disableLocalAuth;
+ } else {
+ dataPlaneRbacEnabled = isDataPlaneRbacSetting === Constants.RBACOptions.setTrueRBACOption;
+ }
+
+ updateUserContext({ dataPlaneRbacEnabled });
+ useDataPlaneRbac.setState({ dataPlaneRbacEnabled: dataPlaneRbacEnabled });
+ }
+ } else {
+ const keys: DatabaseAccountListKeysResult = await listKeys(subscriptionId, resourceGroup, account.name);
+ updateUserContext({
+ masterKey: keys.primaryMasterKey,
+ });
+ }
+
if (openAction) {
handleOpenAction(openAction, useDatabases.getState().databases, explorer);
}
@@ -490,7 +535,6 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
}
const authorizationToken = inputs.authorizationToken || "";
- const masterKey = inputs.masterKey || "";
const databaseAccount = inputs.databaseAccount;
updateConfigContext({
@@ -503,7 +547,6 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
updateUserContext({
authorizationToken,
- masterKey,
databaseAccount,
resourceGroup: inputs.resourceGroup,
subscriptionId: inputs.subscriptionId,
diff --git a/test/tables/container.spec.ts b/test/tables/container.spec.ts
index fb4a2bbae..e30fe7fae 100644
--- a/test/tables/container.spec.ts
+++ b/test/tables/container.spec.ts
@@ -14,6 +14,9 @@ test("Tables CRUD", async ({ page }) => {
await okButton.click();
});
+ const databaseNode = explorer.treeNode("DATA/TablesDB");
+ await databaseNode.expand();
+
const tableNode = explorer.treeNode(`DATA/TablesDB/${tableId}`);
await expect(tableNode.element).toBeAttached();