Enable original azure resource tree style for Fabric native and turn on Settings tab (#2103)

* Enable original azure resource tree for Fabric native and turn on Settings page

* Fix unit tests
This commit is contained in:
Laurent Nguyen 2025-04-15 17:49:16 +02:00 committed by GitHub
parent afdbefe36c
commit 94b1e729d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 264 additions and 84 deletions

View File

@ -1,3 +1,4 @@
import { isFabric } from "Platform/Fabric/FabricUtil";
import { AuthType } from "../../AuthType";
import { Offer, ReadCollectionOfferParams } from "../../Contracts/DataModels";
import { userContext } from "../../UserContext";
@ -13,6 +14,11 @@ import { readOfferWithSDK } from "./readOfferWithSDK";
export const readCollectionOffer = async (params: ReadCollectionOfferParams): Promise<Offer> => {
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
if (isFabric()) {
// Not exposing offers in Fabric
return undefined;
}
try {
if (
userContext.authType === AuthType.AAD &&

View File

@ -12,6 +12,7 @@ import {
ThroughputBucketsComponentProps,
} from "Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent";
import { useDatabases } from "Explorer/useDatabases";
import { isFabricNative } from "Platform/Fabric/FabricUtil";
import { isFullTextSearchEnabled, isVectorSearchEnabled } from "Utils/CapabilityUtils";
import { isRunningOnPublicCloud } from "Utils/CloudUtils";
import * as React from "react";
@ -1277,6 +1278,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
database: useDatabases.getState().findDatabaseWithId(this.collection.databaseId),
collection: this.collection,
explorer: this.props.settingsTab.getContainer(),
isReadOnly: isFabricNative(),
};
const globalSecondaryIndexComponentProps: GlobalSecondaryIndexComponentProps = {

View File

@ -29,16 +29,26 @@ export interface PartitionKeyComponentProps {
database: ViewModels.Database;
collection: ViewModels.Collection;
explorer: Explorer;
isReadOnly?: boolean; // true: cannot change partition key
}
export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({ database, collection, explorer }) => {
export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({
database,
collection,
explorer,
isReadOnly,
}) => {
const { dataTransferJobs } = useDataTransferJobs();
const [portalDataTransferJob, setPortalDataTransferJob] = React.useState<DataTransferJobGetResults>(null);
React.useEffect(() => {
if (isReadOnly) {
return;
}
const loadDataTransferJobs = refreshDataTransferOperations;
loadDataTransferJobs();
}, []);
}, [isReadOnly]);
React.useEffect(() => {
const currentJob = findPortalDataTransferJob();
@ -163,56 +173,61 @@ export const PartitionKeyComponent: React.FC<PartitionKeyComponentProps> = ({ da
</Stack>
</Stack>
</Stack>
<MessageBar messageBarType={MessageBarType.warning}>
To safeguard the integrity of the data being copied to the new container, ensure that no updates are made to the
source container for the entire duration of the partition key change process.
<Link
href="https://learn.microsoft.com/azure/cosmos-db/container-copy#how-does-container-copy-work"
target="_blank"
underline
>
Learn more
</Link>
</MessageBar>
<Text>
To change the partition key, a new destination container must be created or an existing destination container
selected. Data will then be copied to the destination container.
</Text>
{configContext.platform !== Platform.Emulator && (
<PrimaryButton
styles={{ root: { width: "fit-content" } }}
text="Change"
onClick={startPartitionkeyChangeWorkflow}
disabled={isCurrentJobInProgress(portalDataTransferJob)}
/>
)}
{portalDataTransferJob && (
<Stack>
<Text styles={textHeadingStyle}>{partitionKeyName} change job</Text>
<Stack
horizontal
tokens={{ childrenGap: 20 }}
styles={{
root: {
alignItems: "center",
},
}}
>
<ProgressIndicator
label={portalDataTransferJob?.properties?.jobName}
description={getProgressDescription()}
percentComplete={getPercentageComplete()}
styles={{
root: {
width: "85%",
},
}}
></ProgressIndicator>
{isCurrentJobInProgress(portalDataTransferJob) && (
<DefaultButton text="Cancel" onClick={() => cancelRunningDataTransferJob(portalDataTransferJob)} />
)}
</Stack>
</Stack>
{!isReadOnly && (
<>
<MessageBar messageBarType={MessageBarType.warning}>
To safeguard the integrity of the data being copied to the new container, ensure that no updates are made to
the source container for the entire duration of the partition key change process.
<Link
href="https://learn.microsoft.com/azure/cosmos-db/container-copy#how-does-container-copy-work"
target="_blank"
underline
>
Learn more
</Link>
</MessageBar>
<Text>
To change the partition key, a new destination container must be created or an existing destination
container selected. Data will then be copied to the destination container.
</Text>
{configContext.platform !== Platform.Emulator && (
<PrimaryButton
styles={{ root: { width: "fit-content" } }}
text="Change"
onClick={startPartitionkeyChangeWorkflow}
disabled={isCurrentJobInProgress(portalDataTransferJob)}
/>
)}
{portalDataTransferJob && (
<Stack>
<Text styles={textHeadingStyle}>{partitionKeyName} change job</Text>
<Stack
horizontal
tokens={{ childrenGap: 20 }}
styles={{
root: {
alignItems: "center",
},
}}
>
<ProgressIndicator
label={portalDataTransferJob?.properties?.jobName}
description={getProgressDescription()}
percentComplete={getPercentageComplete()}
styles={{
root: {
width: "85%",
},
}}
></ProgressIndicator>
{isCurrentJobInProgress(portalDataTransferJob) && (
<DefaultButton text="Cancel" onClick={() => cancelRunningDataTransferJob(portalDataTransferJob)} />
)}
</Stack>
</Stack>
)}
</>
)}
</Stack>
);

View File

@ -306,6 +306,7 @@ exports[`SettingsComponent renders 1`] = `
},
}
}
isReadOnly={false}
/>
</PivotItem>
<PivotItem

View File

@ -740,12 +740,38 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the Mo
]
`;
exports[`createDatabaseTreeNodes generates the correct tree structure for the SQL API, on Fabric non read-only 1`] = `
exports[`createDatabaseTreeNodes generates the correct tree structure for the SQL API, on Fabric non read-only (native) 1`] = `
[
{
"children": [
{
"children": undefined,
"children": [
{
"contextMenu": [
{
"iconSrc": {},
"label": "New SQL Query",
"onClick": [Function],
},
{
"iconSrc": {},
"label": "Delete Container",
"onClick": [Function],
"styleClass": "deleteCollectionMenuItem",
},
],
"id": "",
"isSelected": [Function],
"label": "Items",
"onClick": [Function],
},
{
"id": "",
"isSelected": [Function],
"label": "Settings",
"onClick": [Function],
},
],
"className": "collectionNode",
"contextMenu": [
{
@ -772,7 +798,38 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the SQ
"onExpanded": [Function],
},
{
"children": undefined,
"children": [
{
"contextMenu": [
{
"iconSrc": {},
"label": "New SQL Query",
"onClick": [Function],
},
{
"iconSrc": {},
"label": "Delete Container",
"onClick": [Function],
"styleClass": "deleteCollectionMenuItem",
},
],
"id": "",
"isSelected": [Function],
"label": "Items",
"onClick": [Function],
},
{
"id": "",
"isSelected": [Function],
"label": "Settings",
"onClick": [Function],
},
{
"isSelected": [Function],
"label": "Conflicts",
"onClick": [Function],
},
],
"className": "collectionNode",
"contextMenu": [
{
@ -806,12 +863,6 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the SQ
"label": "New Container",
"onClick": [Function],
},
{
"iconSrc": {},
"label": "Delete Database",
"onClick": [Function],
"styleClass": "deleteDatabaseMenuItem",
},
],
"iconSrc": <DatabaseRegular
fontSize={16}
@ -826,7 +877,33 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the SQ
{
"children": [
{
"children": undefined,
"children": [
{
"contextMenu": [
{
"iconSrc": {},
"label": "New SQL Query",
"onClick": [Function],
},
{
"iconSrc": {},
"label": "Delete Container",
"onClick": [Function],
"styleClass": "deleteCollectionMenuItem",
},
],
"id": "sampleItems",
"isSelected": [Function],
"label": "Items",
"onClick": [Function],
},
{
"id": "sampleSettings",
"isSelected": [Function],
"label": "Settings",
"onClick": [Function],
},
],
"className": "collectionNode",
"contextMenu": [
{
@ -860,12 +937,6 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the SQ
"label": "New Container",
"onClick": [Function],
},
{
"iconSrc": {},
"label": "Delete Database",
"onClick": [Function],
"styleClass": "deleteDatabaseMenuItem",
},
],
"iconSrc": <DatabaseRegular
fontSize={16}
@ -880,7 +951,88 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the SQ
{
"children": [
{
"children": undefined,
"children": [
{
"contextMenu": [
{
"iconSrc": {},
"label": "New SQL Query",
"onClick": [Function],
},
{
"iconSrc": {},
"label": "Delete Container",
"onClick": [Function],
"styleClass": "deleteCollectionMenuItem",
},
],
"id": "",
"isSelected": [Function],
"label": "Items",
"onClick": [Function],
},
{
"id": "",
"isSelected": [Function],
"label": "Settings",
"onClick": [Function],
},
{
"children": [
{
"children": [
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "street",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: true",
},
],
"label": "line2",
},
{
"children": [
{
"label": "number",
},
{
"label": "HasNulls: false",
},
],
"label": "zip",
},
],
"label": "address",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "orderId",
},
],
"label": "Schema",
"onClick": [Function],
},
],
"className": "collectionNode",
"contextMenu": [
{
@ -919,12 +1071,6 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the SQ
"label": "New Container",
"onClick": [Function],
},
{
"iconSrc": {},
"label": "Delete Database",
"onClick": [Function],
"styleClass": "deleteDatabaseMenuItem",
},
],
"iconSrc": <DatabaseRegular
fontSize={16}
@ -939,7 +1085,7 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the SQ
]
`;
exports[`createDatabaseTreeNodes generates the correct tree structure for the SQL API, on Fabric read-only 1`] = `
exports[`createDatabaseTreeNodes generates the correct tree structure for the SQL API, on Fabric read-only (mirrored) 1`] = `
[
{
"children": [

View File

@ -373,18 +373,28 @@ describe("createDatabaseTreeNodes", () => {
it.each<[string, Platform, boolean, Partial<DataModels.DatabaseAccountExtendedProperties>, Partial<UserContext>]>([
[
"the SQL API, on Fabric read-only",
"the SQL API, on Fabric read-only (mirrored)",
Platform.Fabric,
false,
{ capabilities: [], enableMultipleWriteLocations: true },
{ fabricContext: { isReadOnly: true } as FabricContext<CosmosDbArtifactType> },
{
fabricContext: {
isReadOnly: true,
artifactType: CosmosDbArtifactType.MIRRORED_KEY,
} as FabricContext<CosmosDbArtifactType>,
},
],
[
"the SQL API, on Fabric non read-only",
"the SQL API, on Fabric non read-only (native)",
Platform.Fabric,
false,
{ capabilities: [], enableMultipleWriteLocations: true },
{ fabricContext: { isReadOnly: false } as FabricContext<CosmosDbArtifactType> },
{
fabricContext: {
isReadOnly: false,
artifactType: CosmosDbArtifactType.NATIVE,
} as FabricContext<CosmosDbArtifactType>,
},
],
[
"the SQL API, on Portal",

View File

@ -6,7 +6,7 @@ import StoredProcedure from "Explorer/Tree/StoredProcedure";
import Trigger from "Explorer/Tree/Trigger";
import UserDefinedFunction from "Explorer/Tree/UserDefinedFunction";
import { useDatabases } from "Explorer/useDatabases";
import { isFabricMirrored } from "Platform/Fabric/FabricUtil";
import { isFabric, isFabricMirrored, isFabricNative } from "Platform/Fabric/FabricUtil";
import { getItemName } from "Utils/APITypeUtils";
import { isServerlessAccount } from "Utils/CapabilityUtils";
import { useTabs } from "hooks/useTabs";
@ -23,7 +23,7 @@ import { useNotebook } from "../Notebook/useNotebook";
import { useSelectedNode } from "../useSelectedNode";
export const shouldShowScriptNodes = (): boolean => {
return !isFabricMirrored() && (userContext.apiType === "SQL" || userContext.apiType === "Gremlin");
return !isFabric() && (userContext.apiType === "SQL" || userContext.apiType === "Gremlin");
};
const TreeDatabaseIcon = <DatabaseRegular fontSize={16} />;
@ -220,7 +220,7 @@ export const buildCollectionNode = (
): TreeNode => {
let children: TreeNode[];
// Flat Tree for Fabric
if (configContext.platform !== Platform.Fabric) {
if (!isFabricMirrored()) {
children = buildCollectionNodeChildren(database, collection, isNotebookEnabled, container, refreshActiveTab);
}
@ -318,7 +318,7 @@ const buildCollectionNodeChildren = (
children.push({
id,
label: database.isDatabaseShared() || isServerlessAccount() ? "Settings" : "Scale & Settings",
label: database.isDatabaseShared() || isServerlessAccount() || isFabricNative() ? "Settings" : "Scale & Settings",
onClick: collection.onSettingsClick.bind(collection),
isSelected: () =>
useSelectedNode