From 8cfd951c3179dd65cb2d87c1485503f9dd2c69ee Mon Sep 17 00:00:00 2001 From: Laurent Nguyen Date: Thu, 27 Feb 2025 15:28:26 +0100 Subject: [PATCH] Update to V3 messaging --- src/Common/CosmosClient.ts | 16 +- src/Common/dataAccess/readCollections.ts | 9 +- src/Common/dataAccess/readDatabases.ts | 16 +- src/Contracts/FabricMessagesContract.ts | 70 ++++++-- src/Explorer/Explorer.tsx | 6 +- src/Explorer/Sidebar.tsx | 4 +- src/Explorer/SplashScreen/FabricHome.tsx | 4 +- .../DocumentsTabV2/DocumentsTabV2.test.tsx | 11 +- src/Explorer/Tree/treeNodeUtil.test.ts | 4 +- src/Platform/Fabric/FabricUtil.ts | 19 +- src/UserContext.ts | 24 +-- src/hooks/useKnockoutExplorer.ts | 162 +++++++++++++----- 12 files changed, 248 insertions(+), 97 deletions(-) diff --git a/src/Common/CosmosClient.ts b/src/Common/CosmosClient.ts index f7c80a024..1d27d3c9a 100644 --- a/src/Common/CosmosClient.ts +++ b/src/Common/CosmosClient.ts @@ -1,5 +1,6 @@ import * as Cosmos from "@azure/cosmos"; import { getAuthorizationTokenUsingResourceTokens } from "Common/getAuthorizationTokenUsingResourceTokens"; +import { CosmosDbArtifactType } from "Contracts/FabricMessagesContract"; import { AuthorizationToken } from "Contracts/FabricMessageTypes"; import { checkDatabaseResourceTokensValidity, isFabricMirrored } from "Platform/Fabric/FabricUtil"; import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility"; @@ -8,7 +9,7 @@ import { AuthType } from "../AuthType"; import { BackendApi, PriorityLevel } from "../Common/Constants"; import * as Logger from "../Common/Logger"; import { Platform, configContext } from "../ConfigContext"; -import { updateUserContext, userContext } from "../UserContext"; +import { FabricArtifactInfo, updateUserContext, userContext } from "../UserContext"; import { logConsoleError } from "../Utils/NotificationConsoleUtils"; import * as PriorityBasedExecutionUtils from "../Utils/PriorityBasedExecutionUtils"; import { EmulatorMasterKey, HttpHeaders } from "./Constants"; @@ -54,8 +55,13 @@ export const tokenProvider = async (requestInfo: Cosmos.RequestInfo) => { // User resource tokens // TODO userContext.fabricContext.databaseConnectionInfo can be undefined headers[HttpHeaders.msDate] = new Date().toUTCString(); - const resourceTokens = userContext.fabricContext.mirroredConnectionInfo.resourceTokens; - checkDatabaseResourceTokensValidity(userContext.fabricContext.mirroredConnectionInfo.resourceTokensTimestamp); + const resourceTokens = ( + userContext.fabricContext.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY] + ).resourceTokenInfo.resourceTokens; + checkDatabaseResourceTokensValidity( + (userContext.fabricContext.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY]) + .resourceTokenInfo.resourceTokensTimestamp, + ); return getAuthorizationTokenUsingResourceTokens(resourceTokens, requestInfo.path, requestInfo.resourceId); case Cosmos.ResourceType.none: @@ -66,7 +72,9 @@ export const tokenProvider = async (requestInfo: Cosmos.RequestInfo) => { // For now, these operations aren't used, so fetching the authorization token is commented out. // This provider must return a real token to pass validation by the client, so we return the cached resource token // (which is a valid token, but won't work for these operations). - const resourceTokens2 = userContext.fabricContext.mirroredConnectionInfo.resourceTokens; + const resourceTokens2 = ( + userContext.fabricContext.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY] + ).resourceTokenInfo.resourceTokens; return getAuthorizationTokenUsingResourceTokens(resourceTokens2, requestInfo.path, requestInfo.resourceId); /* ************** TODO: Uncomment this code if we need to support these operations ************** diff --git a/src/Common/dataAccess/readCollections.ts b/src/Common/dataAccess/readCollections.ts index 33f7586bc..bcf3f5c72 100644 --- a/src/Common/dataAccess/readCollections.ts +++ b/src/Common/dataAccess/readCollections.ts @@ -1,9 +1,10 @@ import { ContainerResponse } from "@azure/cosmos"; import { Queries } from "Common/Constants"; +import { CosmosDbArtifactType } from "Contracts/FabricMessagesContract"; import { isFabricMirrored } from "Platform/Fabric/FabricUtil"; import { AuthType } from "../../AuthType"; import * as DataModels from "../../Contracts/DataModels"; -import { userContext } from "../../UserContext"; +import { FabricArtifactInfo, userContext } from "../../UserContext"; import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils"; import { listCassandraTables } from "../../Utils/arm/generatedClients/cosmos/cassandraResources"; import { listGremlinGraphs } from "../../Utils/arm/generatedClients/cosmos/gremlinResources"; @@ -16,11 +17,13 @@ import { handleError } from "../ErrorHandlingUtils"; export async function readCollections(databaseId: string): Promise { const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`); - if (isFabricMirrored() && userContext.fabricContext?.mirroredConnectionInfo.databaseId === databaseId) { + if (isFabricMirrored() && userContext.fabricContext?.databaseName === databaseId) { const collections: DataModels.Collection[] = []; const promises: Promise[] = []; - for (const collectionResourceId in userContext.fabricContext.mirroredConnectionInfo.resourceTokens) { + for (const collectionResourceId in ( + userContext.fabricContext.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY] + ).resourceTokenInfo.resourceTokens) { // Dictionary key looks like this: dbs/SampleDB/colls/Container const resourceIdObj = collectionResourceId.split("/"); const tokenDatabaseId = resourceIdObj[1]; diff --git a/src/Common/dataAccess/readDatabases.ts b/src/Common/dataAccess/readDatabases.ts index 94660e906..d3417b728 100644 --- a/src/Common/dataAccess/readDatabases.ts +++ b/src/Common/dataAccess/readDatabases.ts @@ -1,7 +1,8 @@ +import { CosmosDbArtifactType } from "Contracts/FabricMessagesContract"; import { isFabricMirrored, isFabricNative } from "Platform/Fabric/FabricUtil"; import { AuthType } from "../../AuthType"; import * as DataModels from "../../Contracts/DataModels"; -import { userContext } from "../../UserContext"; +import { FabricArtifactInfo, userContext } from "../../UserContext"; import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils"; import { listCassandraKeyspaces } from "../../Utils/arm/generatedClients/cosmos/cassandraResources"; import { listGremlinDatabases } from "../../Utils/arm/generatedClients/cosmos/gremlinResources"; @@ -14,8 +15,13 @@ export async function readDatabases(): Promise { let databases: DataModels.Database[]; const clearMessage = logConsoleProgress(`Querying databases`); - if (isFabricMirrored() && userContext.fabricContext?.mirroredConnectionInfo.resourceTokens) { - const tokensData = userContext.fabricContext.mirroredConnectionInfo; + if ( + isFabricMirrored() && + (userContext.fabricContext?.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY]).resourceTokenInfo + .resourceTokens + ) { + const tokensData = (userContext.fabricContext.artifactInfo as FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY]) + .resourceTokenInfo; const databaseIdsSet = new Set(); // databaseId @@ -46,8 +52,8 @@ export async function readDatabases(): Promise { })); clearMessage(); return databases; - } else if (isFabricNative() && userContext.fabricContext?.nativeConnectionInfo.databaseName) { - const databaseId = userContext.fabricContext.nativeConnectionInfo.databaseName; + } else if (isFabricNative() && userContext.fabricContext?.databaseName) { + const databaseId = userContext.fabricContext.databaseName; databases = [ { _rid: "", diff --git a/src/Contracts/FabricMessagesContract.ts b/src/Contracts/FabricMessagesContract.ts index 0b8099f39..8155b80f8 100644 --- a/src/Contracts/FabricMessagesContract.ts +++ b/src/Contracts/FabricMessagesContract.ts @@ -1,7 +1,7 @@ import { AuthorizationToken } from "./FabricMessageTypes"; // This is the version of these messages -export const FABRIC_RPC_VERSION = "2"; +export const FABRIC_RPC_VERSION = "FabricMessageV3"; // Fabric to Data Explorer export type FabricMessageV2 = @@ -16,11 +16,6 @@ export type FabricMessageV2 = message: { connectionId: string; isVisible: boolean; - isReadOnly: boolean; - artifactType: CosmosDbArtifactType; - - // For Native artifacts - nativeConnectionInfo?: FabricNativeDatabaseConnectionInfo; }; } | { @@ -36,7 +31,41 @@ export type FabricMessageV2 = message: { id: string; error: string | undefined; - data: FabricMirroredDatabaseConnectionInfo | undefined; + data: ResourceTokenInfo | undefined; + }; + } + | { + type: "explorerVisible"; + message: { + visible: boolean; + }; + }; + +export type FabricMessageV3 = + | { + type: "newContainer"; + databaseName: string; + } + | { + type: "initialize"; + version: string; + id: string; + message: InitializeMessageV3; + } + | { + type: "authorizationToken"; + message: { + id: string; + error: string | undefined; + data: AuthorizationToken | undefined; + }; + } + | { + type: "allResourceTokens_v2"; + message: { + id: string; + error: string | undefined; + data: ResourceTokenInfo | undefined; }; } | { @@ -47,27 +76,38 @@ export type FabricMessageV2 = }; export enum CosmosDbArtifactType { - MIRRORED = "MIRRORED", + MIRRORED_KEY = "MIRRORED_KEY", + MIRRORED_AAD = "MIRRORED_AAD", NATIVE = "NATIVE", } +export interface ArtifactConnectionInfo { + [CosmosDbArtifactType.MIRRORED_KEY]: { connectionId: string }; + [CosmosDbArtifactType.MIRRORED_AAD]: AccessTokenConnectionInfo; + [CosmosDbArtifactType.NATIVE]: AccessTokenConnectionInfo; +} -export interface FabricNativeDatabaseConnectionInfo { +export interface AccessTokenConnectionInfo { accessToken: string; databaseName: string; accountEndpoint: string; } -export interface CosmosDBTokenResponse { - token: string; - date: string; +export interface InitializeMessageV3 { + connectionId: string; + isVisible: boolean; + isReadOnly: boolean; + artifactType: T; + artifactConnectionInfo: ArtifactConnectionInfo[T]; } - export interface CosmosDBConnectionInfoResponse { endpoint: string; databaseId: string; - resourceTokens: Record; + resourceTokens: Record | undefined; + accessToken: string | undefined; + isReadOnly: boolean; + credentialType: "Key" | "OAuth2" | undefined; } -export interface FabricMirroredDatabaseConnectionInfo extends CosmosDBConnectionInfoResponse { +export interface ResourceTokenInfo extends CosmosDBConnectionInfoResponse { resourceTokensTimestamp: number; } diff --git a/src/Explorer/Explorer.tsx b/src/Explorer/Explorer.tsx index e28bfb749..14cfd489a 100644 --- a/src/Explorer/Explorer.tsx +++ b/src/Explorer/Explorer.tsx @@ -43,7 +43,7 @@ import { fromContentUri, toRawContentUri } from "../Utils/GitHubUtils"; import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils"; import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../Utils/NotificationConsoleUtils"; import { useSidePanel } from "../hooks/useSidePanel"; -import { useTabs } from "../hooks/useTabs"; +import { ReactTabKind, useTabs } from "../hooks/useTabs"; import "./ComponentRegisterer"; import { DialogProps, useDialog } from "./Controls/Dialog"; import { GalleryTab as GalleryTabKind } from "./Controls/NotebookGallery/GalleryViewerComponent"; @@ -187,6 +187,10 @@ export default class Explorer { useNotebook.getState().setNotebookBasePath(userContext.features.notebookBasePath); } + if (isFabricMirrored()) { + useTabs.getState().closeReactTab(ReactTabKind.Home); + } + this.refreshExplorer(); } diff --git a/src/Explorer/Sidebar.tsx b/src/Explorer/Sidebar.tsx index ac366aec1..7bdc018d2 100644 --- a/src/Explorer/Sidebar.tsx +++ b/src/Explorer/Sidebar.tsx @@ -133,9 +133,7 @@ const GlobalCommands: React.FC = ({ explorer }) => { label: `New ${getCollectionName()}`, icon: , onClick: () => { - const databaseId = isFabricNative() - ? userContext.fabricContext?.nativeConnectionInfo?.databaseName - : undefined; + const databaseId = isFabricNative() ? userContext.fabricContext?.databaseName : undefined; explorer.onNewCollectionClicked({ databaseId }); }, keyboardAction: KeyboardAction.NEW_COLLECTION, diff --git a/src/Explorer/SplashScreen/FabricHome.tsx b/src/Explorer/SplashScreen/FabricHome.tsx index 72eca2d9f..a923dd928 100644 --- a/src/Explorer/SplashScreen/FabricHome.tsx +++ b/src/Explorer/SplashScreen/FabricHome.tsx @@ -130,9 +130,7 @@ export const FabricHomeScreen: React.FC = (props: SplashScree description: "Create a destination container to store your data", icon: , onClick: () => { - const databaseId = isFabricNative() - ? userContext.fabricContext?.nativeConnectionInfo?.databaseName - : undefined; + const databaseId = isFabricNative() ? userContext.fabricContext?.databaseName : undefined; props.explorer.onNewCollectionClicked({ databaseId }); }, }, diff --git a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.test.tsx b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.test.tsx index 6268ec220..6bb014011 100644 --- a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.test.tsx +++ b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.test.tsx @@ -342,12 +342,15 @@ describe("Documents tab (noSql API)", () => { updateConfigContext({ platform: Platform.Fabric }); updateUserContext({ fabricContext: { - connectionId: "test", - mirroredConnectionInfo: undefined, - nativeConnectionInfo: undefined, - artifactType: CosmosDbArtifactType.MIRRORED, + databaseName: "database", + artifactInfo: { + connectionId: "test", + resourceTokenInfo: undefined, + }, + artifactType: CosmosDbArtifactType.MIRRORED_KEY, isReadOnly: true, isVisible: true, + fabricClientRpcVersion: "rpcVersion", }, }); diff --git a/src/Explorer/Tree/treeNodeUtil.test.ts b/src/Explorer/Tree/treeNodeUtil.test.ts index 034181233..2c7af8021 100644 --- a/src/Explorer/Tree/treeNodeUtil.test.ts +++ b/src/Explorer/Tree/treeNodeUtil.test.ts @@ -557,7 +557,9 @@ describe("createDatabaseTreeNodes", () => { () => { updateConfigContext({ platform: Platform.Fabric }); updateUserContext({ - fabricContext: { artifactType: CosmosDbArtifactType.MIRRORED } as FabricContext, + fabricContext: { + artifactType: CosmosDbArtifactType.MIRRORED_KEY, + } as FabricContext, }); }, ], diff --git a/src/Platform/Fabric/FabricUtil.ts b/src/Platform/Fabric/FabricUtil.ts index f73e4aeb5..684ce52d7 100644 --- a/src/Platform/Fabric/FabricUtil.ts +++ b/src/Platform/Fabric/FabricUtil.ts @@ -1,7 +1,7 @@ import { sendCachedDataMessage } from "Common/MessageHandler"; import { configContext, Platform } from "ConfigContext"; import { FabricMessageTypes } from "Contracts/FabricMessageTypes"; -import { CosmosDbArtifactType, FabricMirroredDatabaseConnectionInfo } from "Contracts/FabricMessagesContract"; +import { CosmosDbArtifactType, ResourceTokenInfo } from "Contracts/FabricMessagesContract"; import { updateUserContext, userContext } from "UserContext"; import { logConsoleError } from "Utils/NotificationConsoleUtils"; @@ -19,21 +19,25 @@ const requestDatabaseResourceTokens = async (): Promise => { lastRequestTimestamp = Date.now(); try { - const fabricDatabaseConnectionInfo = await sendCachedDataMessage( + const resourceTokenInfo = await sendCachedDataMessage( FabricMessageTypes.GetAllResourceTokens, [], - userContext.fabricContext.connectionId, + userContext.fabricContext.artifactInfo.connectionId, ); if (!userContext.databaseAccount.properties.documentEndpoint) { - userContext.databaseAccount.properties.documentEndpoint = fabricDatabaseConnectionInfo.endpoint; + userContext.databaseAccount.properties.documentEndpoint = resourceTokenInfo.endpoint; } updateUserContext({ fabricContext: { ...userContext.fabricContext, - mirroredConnectionInfo: fabricDatabaseConnectionInfo, - isReadOnly: true, + databaseName: resourceTokenInfo.databaseId, + artifactInfo: { + ...userContext.fabricContext.artifactInfo, + resourceTokenInfo, + }, + isReadOnly: resourceTokenInfo.isReadOnly ?? userContext.fabricContext.isReadOnly, }, databaseAccount: { ...userContext.databaseAccount }, }); @@ -75,7 +79,8 @@ export const checkDatabaseResourceTokensValidity = (tokenTimestamp: number): voi export const isFabricMirrored = (): boolean => configContext.platform === Platform.Fabric && - userContext.fabricContext?.artifactType === CosmosDbArtifactType.MIRRORED; + (userContext.fabricContext?.artifactType === CosmosDbArtifactType.MIRRORED_KEY || + userContext.fabricContext?.artifactType === CosmosDbArtifactType.MIRRORED_AAD); export const isFabricNative = (): boolean => configContext.platform === Platform.Fabric && userContext.fabricContext?.artifactType === CosmosDbArtifactType.NATIVE; diff --git a/src/UserContext.ts b/src/UserContext.ts index f522dd2e7..6569d5e18 100644 --- a/src/UserContext.ts +++ b/src/UserContext.ts @@ -1,8 +1,4 @@ -import { - CosmosDbArtifactType, - FabricMirroredDatabaseConnectionInfo, - FabricNativeDatabaseConnectionInfo, -} from "Contracts/FabricMessagesContract"; +import { CosmosDbArtifactType, ResourceTokenInfo } from "Contracts/FabricMessagesContract"; import { ParsedResourceTokenConnectionString } from "Platform/Hosted/Helpers/ResourceTokenUtils"; import { Action } from "Shared/Telemetry/TelemetryConstants"; import { traceOpen } from "Shared/Telemetry/TelemetryProcessor"; @@ -51,13 +47,21 @@ export interface VCoreMongoConnectionParams { connectionString: string; } -export interface FabricContext { - connectionId: string; +export interface FabricArtifactInfo { + [CosmosDbArtifactType.MIRRORED_KEY]: { + connectionId: string; + resourceTokenInfo: ResourceTokenInfo | undefined; + }; + [CosmosDbArtifactType.MIRRORED_AAD]: undefined; + [CosmosDbArtifactType.NATIVE]: undefined; +} +export interface FabricContext { + fabricClientRpcVersion: string; isReadOnly: boolean; isVisible: boolean; + databaseName: string; artifactType: CosmosDbArtifactType; - mirroredConnectionInfo: FabricMirroredDatabaseConnectionInfo | undefined; - nativeConnectionInfo: FabricNativeDatabaseConnectionInfo | undefined; + artifactInfo: FabricArtifactInfo[T]; } export type AdminFeedbackControlPolicy = @@ -76,7 +80,7 @@ export type AdminFeedbackPolicySettings = { }; export interface UserContext { - readonly fabricContext?: FabricContext; + readonly fabricContext?: FabricContext; readonly authType?: AuthType; readonly masterKey?: string; readonly subscriptionId?: string; diff --git a/src/hooks/useKnockoutExplorer.ts b/src/hooks/useKnockoutExplorer.ts index 2ee33bec8..fd3aeb222 100644 --- a/src/hooks/useKnockoutExplorer.ts +++ b/src/hooks/useKnockoutExplorer.ts @@ -3,11 +3,14 @@ import { createUri } from "Common/UrlUtility"; import { DATA_EXPLORER_RPC_VERSION } from "Contracts/DataExplorerMessagesContract"; import { FabricMessageTypes } from "Contracts/FabricMessageTypes"; import { + ArtifactConnectionInfo, CosmosDbArtifactType, FABRIC_RPC_VERSION, FabricMessageV2, - FabricNativeDatabaseConnectionInfo, + FabricMessageV3, + InitializeMessageV3, } from "Contracts/FabricMessagesContract"; +import { useDialog } from "Explorer/Controls/Dialog"; import Explorer from "Explorer/Explorer"; import { useDataPlaneRbac } from "Explorer/Panes/SettingsPane/SettingsPane"; import { useSelectedNode } from "Explorer/useSelectedNode"; @@ -49,7 +52,7 @@ import { } from "../Platform/Hosted/HostedUtils"; import { extractFeatures } from "../Platform/Hosted/extractFeatures"; import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility"; -import { Node, PortalEnv, updateUserContext, userContext } from "../UserContext"; +import { FabricArtifactInfo, Node, PortalEnv, updateUserContext, userContext } from "../UserContext"; import { acquireMsalTokenForAccount, acquireTokenWithMsal, @@ -109,7 +112,7 @@ export function useKnockoutExplorer(platform: Platform): Explorer { async function configureFabric(): Promise { // These are the versions of Fabric that Data Explorer supports. - const SUPPORTED_FABRIC_VERSIONS = [FABRIC_RPC_VERSION]; + const SUPPORTED_FABRIC_VERSIONS = ["2", FABRIC_RPC_VERSION]; let firstContainerOpened = false; let explorer: Explorer; @@ -125,7 +128,7 @@ async function configureFabric(): Promise { return; } - const data: FabricMessageV2 = event.data?.data; + const data: FabricMessageV2 | FabricMessageV3 = event.data?.data; if (!data) { return; } @@ -134,30 +137,51 @@ async function configureFabric(): Promise { case "initialize": { const fabricVersion = data.version; if (!SUPPORTED_FABRIC_VERSIONS.includes(fabricVersion)) { - // TODO Surface error to user + // TODO Surface error to user and log to telemetry + useDialog + .getState() + .showOkModalDialog("Unsupported Fabric version", `Unsupported Fabric version: ${fabricVersion}`); + Logger.logError(`Unsupported Fabric version: ${fabricVersion}`, "Explorer/configureFabric"); console.error(`Unsupported Fabric version: ${fabricVersion}`); return; } - // TODO: Default values points to MIRRORED. This is for old fabric clients to explitly settings these values - data.message.artifactType = data.message.artifactType ?? CosmosDbArtifactType.MIRRORED; - data.message.isReadOnly = data.message.isReadOnly ?? true; + if (fabricVersion === "2") { + // ----------------- TODO: Remove this when FabricMessageV2 is deprecated ----------------- + const initializationMessage = data.message as { + connectionId: string; + isVisible: boolean; + }; - explorer = createExplorerFabric(data.message); - - if (data.message.artifactType === CosmosDbArtifactType.MIRRORED) { - // Do not show Home tab for Mirrored - useTabs.getState().closeReactTab(ReactTabKind.Home); + explorer = createExplorerFabricLegacy(initializationMessage, data.version); await scheduleRefreshDatabaseResourceToken(true); + resolve(explorer); + await explorer.refreshAllDatabases(); + if (userContext.fabricContext.isVisible) { + firstContainerOpened = true; + openFirstContainer(explorer, userContext.fabricContext.databaseName); + } + // ----------------------------------------------------------------------------------------- + } else if (fabricVersion === FABRIC_RPC_VERSION) { + const initializationMessage = data.message as InitializeMessageV3; + explorer = createExplorerFabric(initializationMessage, data.version); + + if (initializationMessage.artifactType === CosmosDbArtifactType.MIRRORED_KEY) { + // Do not show Home tab for Mirrored + useTabs.getState().closeReactTab(ReactTabKind.Home); + await scheduleRefreshDatabaseResourceToken(true); + } + + resolve(explorer); + await explorer.refreshAllDatabases(); + + const { databaseName } = userContext.fabricContext; + if (userContext.fabricContext.isVisible && databaseName) { + firstContainerOpened = true; + openFirstContainer(explorer, databaseName); + } } - resolve(explorer); - await explorer.refreshAllDatabases(); - - if (userContext.fabricContext.isVisible && userContext.fabricContext.mirroredConnectionInfo?.databaseId) { - firstContainerOpened = true; - openFirstContainer(explorer, userContext.fabricContext.mirroredConnectionInfo.databaseId); - } break; } case "newContainer": @@ -170,13 +194,12 @@ async function configureFabric(): Promise { } case "explorerVisible": { userContext.fabricContext.isVisible = data.message.visible; - if ( - userContext.fabricContext.isVisible && - !firstContainerOpened && - userContext?.fabricContext?.mirroredConnectionInfo?.databaseId !== undefined - ) { - firstContainerOpened = true; - openFirstContainer(explorer, userContext.fabricContext.mirroredConnectionInfo.databaseId); + if (userContext.fabricContext.isVisible && !firstContainerOpened) { + const { databaseName } = userContext.fabricContext; + if (databaseName !== undefined) { + firstContainerOpened = true; + openFirstContainer(explorer, databaseName); + } } break; } @@ -431,25 +454,67 @@ function configureHostedWithResourceToken(config: ResourceToken): Explorer { return explorer; } -const createExplorerFabric = (params: { - connectionId: string; - isVisible: boolean; - isReadOnly?: boolean; - artifactType?: CosmosDbArtifactType; - nativeConnectionInfo?: FabricNativeDatabaseConnectionInfo; -}): Explorer => { +/** + * Initialization for FabricMessageV2 + * TODO: delete when FabricMessageV2 is deprecated + * @param params + * @returns + */ +function createExplorerFabricLegacy( + params: { connectionId: string; isVisible: boolean }, + fabricClientRpcVersion: string, +): Explorer { + const artifactInfo: FabricArtifactInfo[CosmosDbArtifactType.MIRRORED_KEY] = { + connectionId: params.connectionId, + resourceTokenInfo: undefined, + }; + updateUserContext({ fabricContext: { - connectionId: params.connectionId, - mirroredConnectionInfo: undefined, // Set with resource token response - isReadOnly: params.isReadOnly, + fabricClientRpcVersion, + isReadOnly: true, + isVisible: params.isVisible ?? true, + databaseName: undefined, + artifactType: CosmosDbArtifactType.MIRRORED_KEY, + artifactInfo, + }, + authType: AuthType.ConnectionString, + databaseAccount: { + id: "", + location: "", + type: "", + name: "Mounted", + kind: AccountKind.Default, + properties: { + documentEndpoint: undefined, + }, + }, + }); + const explorer = new Explorer(); + return explorer; +} + +/** + * Initialization for FabricMessageV3 and above + * @param params + * @returns + */ +const createExplorerFabric = ( + params: InitializeMessageV3, + fabricClientRpcVersion: string, +): Explorer => { + updateUserContext({ + fabricContext: { + fabricClientRpcVersion, + databaseName: undefined, isVisible: params.isVisible, + isReadOnly: params.isReadOnly, artifactType: params.artifactType, - nativeConnectionInfo: params.nativeConnectionInfo, + artifactInfo: undefined, }, }); - if (params.artifactType === CosmosDbArtifactType.MIRRORED) { + if (params.artifactType === CosmosDbArtifactType.MIRRORED_KEY) { updateUserContext({ authType: AuthType.ConnectionString, // TODO: will need its own type and Mirroring could be using AAD databaseAccount: { @@ -462,8 +527,17 @@ const createExplorerFabric = (params: { documentEndpoint: undefined, }, }, + fabricContext: { + ...userContext.fabricContext, + artifactInfo: { + connectionId: (params.artifactConnectionInfo as ArtifactConnectionInfo[CosmosDbArtifactType.MIRRORED_KEY]) + .connectionId, + resourceTokenInfo: undefined, + }, + }, }); } else if (params.artifactType === CosmosDbArtifactType.NATIVE) { + const nativeParams = params as InitializeMessageV3; // Make it behave like Hosted/AAD/RBAC updateUserContext({ databaseAccount: { @@ -473,14 +547,20 @@ const createExplorerFabric = (params: { name: "Native", // TODO: not used? kind: AccountKind.Default, properties: { - documentEndpoint: params.nativeConnectionInfo.accountEndpoint, + documentEndpoint: nativeParams.artifactConnectionInfo.accountEndpoint, }, }, authType: AuthType.AAD, dataPlaneRbacEnabled: true, - aadToken: params.nativeConnectionInfo.accessToken, + aadToken: nativeParams.artifactConnectionInfo.accessToken, masterKey: undefined, + fabricContext: { + ...userContext.fabricContext, + databaseName: nativeParams.artifactConnectionInfo.databaseName, + }, }); + } else if (params.artifactType === CosmosDbArtifactType.MIRRORED_AAD) { + throw new Error("Mirrored AAD is not supported"); } const explorer = new Explorer();