Add Sample Data to Resource Tree (#1499)
* Add Sample Data to Resource Tree * Format * Fix strict build * Fix lint * Fixed implementation to show Sample data container * Udated logic based on TokenCollection * Re-configure copilot flag --------- Co-authored-by: Predrag Klepic <v-prklepic@microsoft.com>
This commit is contained in:
parent
f3c96b91bd
commit
ceed162491
|
@ -0,0 +1,26 @@
|
||||||
|
import * as Cosmos from "@azure/cosmos";
|
||||||
|
import { userContext } from "UserContext";
|
||||||
|
|
||||||
|
let _sampleDataclient: Cosmos.CosmosClient;
|
||||||
|
|
||||||
|
export function sampleDataClient(): Cosmos.CosmosClient {
|
||||||
|
if (_sampleDataclient) {
|
||||||
|
return _sampleDataclient;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sampleDataConnectionInfo = userContext.sampleDataConnectionInfo;
|
||||||
|
const options: Cosmos.CosmosClientOptions = {
|
||||||
|
endpoint: sampleDataConnectionInfo.accountEndpoint,
|
||||||
|
tokenProvider: async () => {
|
||||||
|
const sampleDataConnectionInfo = userContext.sampleDataConnectionInfo;
|
||||||
|
return Promise.resolve(sampleDataConnectionInfo.resourceToken);
|
||||||
|
},
|
||||||
|
connectionPolicy: {
|
||||||
|
enableEndpointDiscovery: false,
|
||||||
|
},
|
||||||
|
userAgentSuffix: "Azure Portal",
|
||||||
|
};
|
||||||
|
|
||||||
|
_sampleDataclient = new Cosmos.CosmosClient(options);
|
||||||
|
return _sampleDataclient;
|
||||||
|
}
|
|
@ -1,13 +1,39 @@
|
||||||
|
import { CosmosClient } from "@azure/cosmos";
|
||||||
|
import { sampleDataClient } from "Common/SampleDataClient";
|
||||||
|
import { userContext } from "UserContext";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { client } from "../CosmosClient";
|
import { client } from "../CosmosClient";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
|
|
||||||
export async function readCollection(databaseId: string, collectionId: string): Promise<DataModels.Collection> {
|
export async function readCollection(databaseId: string, collectionId: string): Promise<DataModels.Collection> {
|
||||||
|
const cosmosClient = client();
|
||||||
|
return await readCollectionInternal(cosmosClient, databaseId, collectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function readSampleCollection(): Promise<DataModels.Collection> {
|
||||||
|
const cosmosClient = sampleDataClient();
|
||||||
|
|
||||||
|
const sampleDataConnectionInfo = userContext.sampleDataConnectionInfo;
|
||||||
|
const databaseId = sampleDataConnectionInfo?.databaseId;
|
||||||
|
const collectionId = sampleDataConnectionInfo?.collectionId;
|
||||||
|
|
||||||
|
if (!databaseId || !collectionId) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await readCollectionInternal(cosmosClient, databaseId, collectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function readCollectionInternal(
|
||||||
|
cosmosClient: CosmosClient,
|
||||||
|
databaseId: string,
|
||||||
|
collectionId: string
|
||||||
|
): Promise<DataModels.Collection> {
|
||||||
let collection: DataModels.Collection;
|
let collection: DataModels.Collection;
|
||||||
const clearMessage = logConsoleProgress(`Querying container ${collectionId}`);
|
const clearMessage = logConsoleProgress(`Querying container ${collectionId}`);
|
||||||
try {
|
try {
|
||||||
const response = await client().database(databaseId).container(collectionId).read();
|
const response = await cosmosClient.database(databaseId).container(collectionId).read();
|
||||||
collection = response.resource as DataModels.Collection;
|
collection = response.resource as DataModels.Collection;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, "ReadCollection", `Error while querying container ${collectionId}`);
|
handleError(error, "ReadCollection", `Error while querying container ${collectionId}`);
|
||||||
|
|
|
@ -1,39 +1,39 @@
|
||||||
import { Link } from "@fluentui/react/lib/Link";
|
import { Link } from "@fluentui/react/lib/Link";
|
||||||
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
|
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
|
||||||
import { IGalleryItem } from "Juno/JunoClient";
|
import { IGalleryItem } from "Juno/JunoClient";
|
||||||
|
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointValidation";
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointValidation";
|
|
||||||
import shallow from "zustand/shallow";
|
import shallow from "zustand/shallow";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
||||||
import * as Constants from "../Common/Constants";
|
import * as Constants from "../Common/Constants";
|
||||||
import { Areas, ConnectionStatusType, HttpStatusCodes, Notebook, PoolIdType } from "../Common/Constants";
|
import { Areas, ConnectionStatusType, HttpStatusCodes, Notebook, PoolIdType } from "../Common/Constants";
|
||||||
import { readCollection } from "../Common/dataAccess/readCollection";
|
|
||||||
import { readDatabases } from "../Common/dataAccess/readDatabases";
|
|
||||||
import { getErrorMessage, getErrorStack, handleError } from "../Common/ErrorHandlingUtils";
|
import { getErrorMessage, getErrorStack, handleError } from "../Common/ErrorHandlingUtils";
|
||||||
import * as Logger from "../Common/Logger";
|
import * as Logger from "../Common/Logger";
|
||||||
import { QueriesClient } from "../Common/QueriesClient";
|
import { QueriesClient } from "../Common/QueriesClient";
|
||||||
|
import { readCollection, readSampleCollection } from "../Common/dataAccess/readCollection";
|
||||||
|
import { readDatabases } from "../Common/dataAccess/readDatabases";
|
||||||
import * as DataModels from "../Contracts/DataModels";
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
import { ContainerConnectionInfo, IPhoenixServiceInfo, IProvisionData, IResponse } from "../Contracts/DataModels";
|
import { ContainerConnectionInfo, IPhoenixServiceInfo, IProvisionData, IResponse } from "../Contracts/DataModels";
|
||||||
import * as ViewModels from "../Contracts/ViewModels";
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
||||||
import { useSidePanel } from "../hooks/useSidePanel";
|
|
||||||
import { useTabs } from "../hooks/useTabs";
|
|
||||||
import { PhoenixClient } from "../Phoenix/PhoenixClient";
|
import { PhoenixClient } from "../Phoenix/PhoenixClient";
|
||||||
import * as ExplorerSettings from "../Shared/ExplorerSettings";
|
import * as ExplorerSettings from "../Shared/ExplorerSettings";
|
||||||
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "../UserContext";
|
import { userContext } from "../UserContext";
|
||||||
import { getCollectionName, getUploadName } from "../Utils/APITypeUtils";
|
import { getCollectionName, getUploadName } from "../Utils/APITypeUtils";
|
||||||
import { update } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
|
||||||
import { listByDatabaseAccount } from "../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces";
|
|
||||||
import { stringToBlob } from "../Utils/BlobUtils";
|
import { stringToBlob } from "../Utils/BlobUtils";
|
||||||
import { isCapabilityEnabled } from "../Utils/CapabilityUtils";
|
import { isCapabilityEnabled } from "../Utils/CapabilityUtils";
|
||||||
import { fromContentUri, toRawContentUri } from "../Utils/GitHubUtils";
|
import { fromContentUri, toRawContentUri } from "../Utils/GitHubUtils";
|
||||||
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../Utils/NotificationConsoleUtils";
|
||||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../Utils/NotificationConsoleUtils";
|
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../Utils/NotificationConsoleUtils";
|
||||||
|
import { update } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||||
|
import { listByDatabaseAccount } from "../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces";
|
||||||
|
import { useSidePanel } from "../hooks/useSidePanel";
|
||||||
|
import { useTabs } from "../hooks/useTabs";
|
||||||
import "./ComponentRegisterer";
|
import "./ComponentRegisterer";
|
||||||
import { DialogProps, useDialog } from "./Controls/Dialog";
|
import { DialogProps, useDialog } from "./Controls/Dialog";
|
||||||
import { GalleryTab as GalleryTabKind } from "./Controls/NotebookGallery/GalleryViewerComponent";
|
import { GalleryTab as GalleryTabKind } from "./Controls/NotebookGallery/GalleryViewerComponent";
|
||||||
|
@ -1272,5 +1272,26 @@ export default class Explorer {
|
||||||
if (useNotebook.getState().isPhoenixNotebooks) {
|
if (useNotebook.getState().isPhoenixNotebooks) {
|
||||||
await this.initNotebooks(userContext.databaseAccount);
|
await this.initNotebooks(userContext.databaseAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await this.refreshSampleData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async refreshSampleData(): Promise<void> {
|
||||||
|
if (!userContext.sampleDataConnectionInfo) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const collection: DataModels.Collection = await readSampleCollection();
|
||||||
|
if (!collection) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const databaseId = userContext.sampleDataConnectionInfo?.databaseId;
|
||||||
|
if (!databaseId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sampleDataResourceTokenCollection = new ResourceTokenCollection(this, databaseId, collection);
|
||||||
|
useDatabases.setState({ sampleDataResourceTokenCollection });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import { Callout, DirectionalHint, ICalloutProps, ILinkProps, Link, Stack, Text } from "@fluentui/react";
|
import { Callout, DirectionalHint, ICalloutProps, ILinkProps, Link, Stack, Text } from "@fluentui/react";
|
||||||
import * as React from "react";
|
import { SampleDataTree } from "Explorer/Tree/SampleDataTree";
|
||||||
import { getItemName } from "Utils/APITypeUtils";
|
import { getItemName } from "Utils/APITypeUtils";
|
||||||
|
import * as React from "react";
|
||||||
import shallow from "zustand/shallow";
|
import shallow from "zustand/shallow";
|
||||||
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
|
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
|
||||||
import DeleteIcon from "../../../images/delete.svg";
|
|
||||||
import GalleryIcon from "../../../images/GalleryIcon.svg";
|
import GalleryIcon from "../../../images/GalleryIcon.svg";
|
||||||
import FileIcon from "../../../images/notebook/file-cosmos.svg";
|
import DeleteIcon from "../../../images/delete.svg";
|
||||||
import CopyIcon from "../../../images/notebook/Notebook-copy.svg";
|
import CopyIcon from "../../../images/notebook/Notebook-copy.svg";
|
||||||
import NewNotebookIcon from "../../../images/notebook/Notebook-new.svg";
|
import NewNotebookIcon from "../../../images/notebook/Notebook-new.svg";
|
||||||
import NotebookIcon from "../../../images/notebook/Notebook-resource.svg";
|
import NotebookIcon from "../../../images/notebook/Notebook-resource.svg";
|
||||||
|
import FileIcon from "../../../images/notebook/file-cosmos.svg";
|
||||||
import PublishIcon from "../../../images/notebook/publish_content.svg";
|
import PublishIcon from "../../../images/notebook/publish_content.svg";
|
||||||
import RefreshIcon from "../../../images/refresh-cosmos.svg";
|
import RefreshIcon from "../../../images/refresh-cosmos.svg";
|
||||||
import CollectionIcon from "../../../images/tree-collection.svg";
|
import CollectionIcon from "../../../images/tree-collection.svg";
|
||||||
|
@ -16,14 +17,14 @@ import { Areas, ConnectionStatusType, Notebook } from "../../Common/Constants";
|
||||||
import { isPublicInternetAccessAllowed } from "../../Common/DatabaseAccountUtility";
|
import { isPublicInternetAccessAllowed } from "../../Common/DatabaseAccountUtility";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import { useSidePanel } from "../../hooks/useSidePanel";
|
|
||||||
import { useTabs } from "../../hooks/useTabs";
|
|
||||||
import { LocalStorageUtility, StorageKey } from "../../Shared/StorageUtility";
|
import { LocalStorageUtility, StorageKey } from "../../Shared/StorageUtility";
|
||||||
import { Action, ActionModifiers, Source } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers, Source } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { isServerlessAccount } from "../../Utils/CapabilityUtils";
|
import { isServerlessAccount } from "../../Utils/CapabilityUtils";
|
||||||
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../Utils/GitHubUtils";
|
||||||
|
import { useSidePanel } from "../../hooks/useSidePanel";
|
||||||
|
import { useTabs } from "../../hooks/useTabs";
|
||||||
import * as ResourceTreeContextMenuButtonFactory from "../ContextMenuButtonFactory";
|
import * as ResourceTreeContextMenuButtonFactory from "../ContextMenuButtonFactory";
|
||||||
import { AccordionComponent, AccordionItemComponent } from "../Controls/Accordion/AccordionComponent";
|
import { AccordionComponent, AccordionItemComponent } from "../Controls/Accordion/AccordionComponent";
|
||||||
import { useDialog } from "../Controls/Dialog";
|
import { useDialog } from "../Controls/Dialog";
|
||||||
|
@ -764,23 +765,59 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
||||||
};
|
};
|
||||||
|
|
||||||
const dataRootNode = buildDataTree();
|
const dataRootNode = buildDataTree();
|
||||||
|
const isSampleDataEnabled = userContext.sampleDataConnectionInfo && userContext.apiType === "SQL";
|
||||||
|
const sampleDataResourceTokenCollection = useDatabases((state) => state.sampleDataResourceTokenCollection);
|
||||||
|
|
||||||
if (isNotebookEnabled) {
|
return (
|
||||||
return (
|
<>
|
||||||
<>
|
{!isNotebookEnabled && !isSampleDataEnabled && (
|
||||||
<AccordionComponent>
|
<TreeComponent className="dataResourceTree" rootNode={dataRootNode} />
|
||||||
<AccordionItemComponent title={"DATA"} isExpanded={!gitHubNotebooksContentRoot}>
|
)}
|
||||||
<TreeComponent className="dataResourceTree" rootNode={dataRootNode} />
|
{isNotebookEnabled && !isSampleDataEnabled && (
|
||||||
</AccordionItemComponent>
|
<>
|
||||||
<AccordionItemComponent title={"NOTEBOOKS"}>
|
<AccordionComponent>
|
||||||
<TreeComponent className="notebookResourceTree" rootNode={buildNotebooksTree()} />
|
<AccordionItemComponent title={"DATA"} isExpanded={!gitHubNotebooksContentRoot}>
|
||||||
</AccordionItemComponent>
|
<TreeComponent className="dataResourceTree" rootNode={dataRootNode} />
|
||||||
</AccordionComponent>
|
</AccordionItemComponent>
|
||||||
|
<AccordionItemComponent title={"NOTEBOOKS"}>
|
||||||
|
<TreeComponent className="notebookResourceTree" rootNode={buildNotebooksTree()} />
|
||||||
|
</AccordionItemComponent>
|
||||||
|
</AccordionComponent>
|
||||||
|
|
||||||
{buildGalleryCallout()}
|
{buildGalleryCallout()}
|
||||||
</>
|
</>
|
||||||
);
|
)}
|
||||||
}
|
{!isNotebookEnabled && isSampleDataEnabled && (
|
||||||
|
<>
|
||||||
|
<AccordionComponent>
|
||||||
|
<AccordionItemComponent title={"MY DATA"} isExpanded={!gitHubNotebooksContentRoot}>
|
||||||
|
<TreeComponent className="dataResourceTree" rootNode={dataRootNode} />
|
||||||
|
</AccordionItemComponent>
|
||||||
|
<AccordionItemComponent title={"SAMPLE DATA"}>
|
||||||
|
<SampleDataTree sampleDataResourceTokenCollection={sampleDataResourceTokenCollection} />
|
||||||
|
</AccordionItemComponent>
|
||||||
|
</AccordionComponent>
|
||||||
|
|
||||||
return <TreeComponent className="dataResourceTree" rootNode={dataRootNode} />;
|
{buildGalleryCallout()}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{isNotebookEnabled && isSampleDataEnabled && (
|
||||||
|
<>
|
||||||
|
<AccordionComponent>
|
||||||
|
<AccordionItemComponent title={"MY DATA"} isExpanded={!gitHubNotebooksContentRoot}>
|
||||||
|
<TreeComponent className="dataResourceTree" rootNode={dataRootNode} />
|
||||||
|
</AccordionItemComponent>
|
||||||
|
<AccordionItemComponent title={"SAMPLE DATA"}>
|
||||||
|
<SampleDataTree sampleDataResourceTokenCollection={sampleDataResourceTokenCollection} />
|
||||||
|
</AccordionItemComponent>
|
||||||
|
<AccordionItemComponent title={"NOTEBOOKS"}>
|
||||||
|
<TreeComponent className="notebookResourceTree" rootNode={buildNotebooksTree()} />
|
||||||
|
</AccordionItemComponent>
|
||||||
|
</AccordionComponent>
|
||||||
|
|
||||||
|
{buildGalleryCallout()}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
|
||||||
|
import CollectionIcon from "../../../images/tree-collection.svg";
|
||||||
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
|
import { TreeComponent, TreeNode } from "../Controls/TreeComponent/TreeComponent";
|
||||||
|
|
||||||
|
export const SampleDataTree = ({
|
||||||
|
sampleDataResourceTokenCollection,
|
||||||
|
}: {
|
||||||
|
sampleDataResourceTokenCollection: ViewModels.CollectionBase;
|
||||||
|
}): JSX.Element => {
|
||||||
|
const [root, setRoot] = useState<TreeNode | undefined>(undefined);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (sampleDataResourceTokenCollection) {
|
||||||
|
const updatedSampleTree: TreeNode = {
|
||||||
|
label: sampleDataResourceTokenCollection.databaseId,
|
||||||
|
isExpanded: true,
|
||||||
|
iconSrc: CosmosDBIcon,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: sampleDataResourceTokenCollection.id(),
|
||||||
|
iconSrc: CollectionIcon,
|
||||||
|
isExpanded: true,
|
||||||
|
className: "collectionHeader",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "Items",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
setRoot(updatedSampleTree);
|
||||||
|
}
|
||||||
|
}, [sampleDataResourceTokenCollection]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TreeComponent className="sampleDataResourceTree" rootNode={root || { label: "Sample data not initialized." }} />
|
||||||
|
);
|
||||||
|
};
|
|
@ -8,6 +8,7 @@ import { useSelectedNode } from "./useSelectedNode";
|
||||||
interface DatabasesState {
|
interface DatabasesState {
|
||||||
databases: ViewModels.Database[];
|
databases: ViewModels.Database[];
|
||||||
resourceTokenCollection: ViewModels.CollectionBase;
|
resourceTokenCollection: ViewModels.CollectionBase;
|
||||||
|
sampleDataResourceTokenCollection: ViewModels.CollectionBase;
|
||||||
updateDatabase: (database: ViewModels.Database) => void;
|
updateDatabase: (database: ViewModels.Database) => void;
|
||||||
addDatabases: (databases: ViewModels.Database[]) => void;
|
addDatabases: (databases: ViewModels.Database[]) => void;
|
||||||
deleteDatabase: (database: ViewModels.Database) => void;
|
deleteDatabase: (database: ViewModels.Database) => void;
|
||||||
|
@ -28,6 +29,7 @@ interface DatabasesState {
|
||||||
export const useDatabases: UseStore<DatabasesState> = create((set, get) => ({
|
export const useDatabases: UseStore<DatabasesState> = create((set, get) => ({
|
||||||
databases: [],
|
databases: [],
|
||||||
resourceTokenCollection: undefined,
|
resourceTokenCollection: undefined,
|
||||||
|
sampleDataResourceTokenCollection: undefined,
|
||||||
updateDatabase: (updatedDatabase: ViewModels.Database) =>
|
updateDatabase: (updatedDatabase: ViewModels.Database) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const updatedDatabases = state.databases.map((database: ViewModels.Database) => {
|
const updatedDatabases = state.databases.map((database: ViewModels.Database) => {
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
export interface ParsedResourceTokenConnectionString {
|
export interface ParsedResourceTokenConnectionString {
|
||||||
accountEndpoint: string;
|
accountEndpoint?: string;
|
||||||
collectionId: string;
|
collectionId?: string;
|
||||||
databaseId: string;
|
databaseId?: string;
|
||||||
partitionKey?: string;
|
partitionKey?: string;
|
||||||
resourceToken: string;
|
resourceToken?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseResourceTokenConnectionString(connectionString: string): ParsedResourceTokenConnectionString {
|
export function parseResourceTokenConnectionString(connectionString: string): ParsedResourceTokenConnectionString {
|
||||||
let accountEndpoint: string;
|
let accountEndpoint: string | undefined;
|
||||||
let collectionId: string;
|
let collectionId: string | undefined;
|
||||||
let databaseId: string;
|
let databaseId: string | undefined;
|
||||||
let partitionKey: string;
|
let partitionKey: string | undefined;
|
||||||
let resourceToken: string;
|
let resourceToken: string | undefined;
|
||||||
|
|
||||||
const connectionStringParts = connectionString.split(";");
|
const connectionStringParts = connectionString.split(";");
|
||||||
connectionStringParts.forEach((part: string) => {
|
connectionStringParts.forEach((part: string) => {
|
||||||
if (part.startsWith("type=resource")) {
|
if (part.startsWith("type=resource")) {
|
||||||
|
@ -39,5 +40,5 @@ export function parseResourceTokenConnectionString(connectionString: string): Pa
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isResourceTokenConnectionString(connectionString: string): boolean {
|
export function isResourceTokenConnectionString(connectionString: string): boolean {
|
||||||
return connectionString && connectionString.includes("type=resource");
|
return !!connectionString && connectionString.includes("type=resource");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { useCarousel } from "hooks/useCarousel";
|
import { useCarousel } from "hooks/useCarousel";
|
||||||
import { usePostgres } from "hooks/usePostgres";
|
import { usePostgres } from "hooks/usePostgres";
|
||||||
|
import { ParsedResourceTokenConnectionString } from "Platform/Hosted/Helpers/ResourceTokenUtils";
|
||||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||||
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
|
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
|
||||||
import { AuthType } from "./AuthType";
|
import { AuthType } from "./AuthType";
|
||||||
|
@ -69,6 +70,7 @@ interface UserContext {
|
||||||
readonly postgresConnectionStrParams?: PostgresConnectionStrParams;
|
readonly postgresConnectionStrParams?: PostgresConnectionStrParams;
|
||||||
readonly isReplica?: boolean;
|
readonly isReplica?: boolean;
|
||||||
collectionCreationDefaults: CollectionCreationDefaults;
|
collectionCreationDefaults: CollectionCreationDefaults;
|
||||||
|
sampleDataConnectionInfo?: ParsedResourceTokenConnectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres";
|
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres";
|
||||||
|
@ -157,4 +159,4 @@ function apiType(account: DatabaseAccount | undefined): ApiType {
|
||||||
return "SQL";
|
return "SQL";
|
||||||
}
|
}
|
||||||
|
|
||||||
export { userContext, updateUserContext };
|
export { updateUserContext, userContext };
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
|
import { createUri } from "Common/UrlUtility";
|
||||||
import Explorer from "Explorer/Explorer";
|
import Explorer from "Explorer/Explorer";
|
||||||
|
import { getNetworkSettingsWarningMessage } from "Utils/NetworkUtility";
|
||||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { getNetworkSettingsWarningMessage } from "Utils/NetworkUtility";
|
|
||||||
import { applyExplorerBindings } from "../applyExplorerBindings";
|
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { AccountKind, Flights } from "../Common/Constants";
|
import { AccountKind, Flights } from "../Common/Constants";
|
||||||
import { normalizeArmEndpoint } from "../Common/EnvironmentUtility";
|
import { normalizeArmEndpoint } from "../Common/EnvironmentUtility";
|
||||||
import { sendMessage, sendReadyMessage } from "../Common/MessageHandler";
|
import { sendMessage, sendReadyMessage } from "../Common/MessageHandler";
|
||||||
import { configContext, Platform, updateConfigContext } from "../ConfigContext";
|
import { Platform, configContext, updateConfigContext } from "../ConfigContext";
|
||||||
import { ActionType, DataExplorerAction } from "../Contracts/ActionContracts";
|
import { ActionType, DataExplorerAction } from "../Contracts/ActionContracts";
|
||||||
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
||||||
import { DataExplorerInputsFrame } from "../Contracts/ViewModels";
|
import { DataExplorerInputsFrame } from "../Contracts/ViewModels";
|
||||||
|
@ -21,19 +21,20 @@ import {
|
||||||
ResourceToken,
|
ResourceToken,
|
||||||
} from "../HostedExplorerChildFrame";
|
} from "../HostedExplorerChildFrame";
|
||||||
import { emulatorAccount } from "../Platform/Emulator/emulatorAccount";
|
import { emulatorAccount } from "../Platform/Emulator/emulatorAccount";
|
||||||
import { extractFeatures } from "../Platform/Hosted/extractFeatures";
|
|
||||||
import { parseResourceTokenConnectionString } from "../Platform/Hosted/Helpers/ResourceTokenUtils";
|
import { parseResourceTokenConnectionString } from "../Platform/Hosted/Helpers/ResourceTokenUtils";
|
||||||
import {
|
import {
|
||||||
getDatabaseAccountKindFromExperience,
|
getDatabaseAccountKindFromExperience,
|
||||||
getDatabaseAccountPropertiesFromMetadata,
|
getDatabaseAccountPropertiesFromMetadata,
|
||||||
} from "../Platform/Hosted/HostedUtils";
|
} from "../Platform/Hosted/HostedUtils";
|
||||||
|
import { extractFeatures } from "../Platform/Hosted/extractFeatures";
|
||||||
import { CollectionCreation } from "../Shared/Constants";
|
import { CollectionCreation } from "../Shared/Constants";
|
||||||
import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility";
|
import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility";
|
||||||
import { Node, PortalEnv, updateUserContext, userContext } from "../UserContext";
|
import { Node, PortalEnv, updateUserContext, userContext } from "../UserContext";
|
||||||
|
import { getAuthorizationHeader, getMsalInstance } from "../Utils/AuthorizationUtils";
|
||||||
|
import { isInvalidParentFrameOrigin, shouldProcessMessage } from "../Utils/MessageValidation";
|
||||||
import { listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
import { listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||||
import { DatabaseAccountListKeysResult } from "../Utils/arm/generatedClients/cosmos/types";
|
import { DatabaseAccountListKeysResult } from "../Utils/arm/generatedClients/cosmos/types";
|
||||||
import { getMsalInstance } from "../Utils/AuthorizationUtils";
|
import { applyExplorerBindings } from "../applyExplorerBindings";
|
||||||
import { isInvalidParentFrameOrigin, shouldProcessMessage } from "../Utils/MessageValidation";
|
|
||||||
|
|
||||||
// This hook will create a new instance of Explorer.ts and bind it to the DOM
|
// 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
|
// This hook has a LOT of magic, but ideally we can delete it once we have removed KO and switched entirely to React
|
||||||
|
@ -61,6 +62,10 @@ export function useKnockoutExplorer(platform: Platform): Explorer {
|
||||||
setExplorer(explorer);
|
setExplorer(explorer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (userContext.features.enableCopilot) {
|
||||||
|
await updateContextForSampleData();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
effect();
|
effect();
|
||||||
}, [platform]);
|
}, [platform]);
|
||||||
|
@ -409,3 +414,29 @@ interface PortalMessage {
|
||||||
type?: MessageTypes;
|
type?: MessageTypes;
|
||||||
inputs?: DataExplorerInputsFrame;
|
inputs?: DataExplorerInputsFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateContextForSampleData(): Promise<void> {
|
||||||
|
if (!userContext.features.enableCopilot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = createUri(`${configContext.BACKEND_ENDPOINT}`, `/api/tokens/sampledataconnection`);
|
||||||
|
const authorizationHeader = getAuthorizationHeader();
|
||||||
|
const headers = { [authorizationHeader.header]: authorizationHeader.token };
|
||||||
|
|
||||||
|
const response = await window.fetch(url, {
|
||||||
|
headers,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: SampledataconnectionResponse = await response.json();
|
||||||
|
const sampleDataConnectionInfo = parseResourceTokenConnectionString(data.connectionString);
|
||||||
|
updateUserContext({ sampleDataConnectionInfo });
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SampledataconnectionResponse {
|
||||||
|
connectionString: string;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue