mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-31 23:02:29 +00:00
* First dark theme commits for command bar * Updated theme on sidebar * Updated tabs, sidebar, splash screen * settings theme changes * Dark theme applied to Monaco editor * Dark theme to stored procedures * Fixed sidebar scroll * Updated scroll issue in sidebar * Command bar items fixed * Fixed lint errors * fixed lint errors * settings side panel fixed * Second last iteration for css * Fixed all the issues of css * Updated the theme icon for now on DE to change the theme from portal/DE itself * Formatting issue resolved * Remove CloudShellTerminalComponent changes - revert to master version * Fixed test issue * Fixed formatting issue * Fix tests: update snapshots and revert xterm imports for compatibility * Fix xterm imports in CloudShellTerminalComponent to use @xterm packages * Fix Cloud Shell component imports for compatibility * Update test snapshots * Fix xterm package consistency across all CloudShell components * Fix TypeScript compilation errors in CloudShell components and query Documents - Standardized xterm package imports across CloudShell components to use legacy 'xterm' package - Fixed Terminal type compatibility issues in CommonUtils.tsx - Added type casting for enableQueryControl property in queryDocuments.ts to handle Azure Cosmos SDK interface limitations - Applied code formatting to ensure consistency * Update failing snapshot tests - Updated TreeNodeComponent snapshot tests for loading states - Updated ThroughputInputAutoPilotV3Component snapshots for number formatting changes (10,00,000 -> 1,000,000) - All snapshot tests now pass * Fixed test issue * Fixed test issue * Updated the buttons for theme * Updated the Theme changes based on portal theme changes * Updated review comments * Updated the duplicate code and fixed the fabric react error * Few places styling added and resolving few comments * Fixed errors * Fixed comments * Fixed comments * Fixed comments * Fixed full text policy issue for mongoru accounts * Resolved comments for class Name and few others * Added css for homepage in ru accounts * Final commit with all the feedback issues resolved * Lint error resolved * Updated the review comments and few Ui issues * Resolved review comments and changed header bg and active state color * Moved svg code to different file and imported * css fixed for the hpome page boxed for ru account * Lint errors * Fixed boxes issue in ru accounts * Handled the initial theme from the portal * Updated snap * Update snapshots for TreeNodeComponent and CreateCopyJobScreensProvider tests * Fix duplicate DataExplorerRoot test id causing Playwright strict mode violation * Fix locale-dependent number formatting in ThroughputInputAutoPilotV3Component --------- Co-authored-by: Sakshi Gupta <sakshig+microsoft@microsoft.com> Co-authored-by: Sakshi Gupta <sakshig@microsoft.com>
262 lines
9.2 KiB
TypeScript
262 lines
9.2 KiB
TypeScript
import {
|
|
DefaultButton,
|
|
FontWeights,
|
|
IMessageBarStyles,
|
|
Link,
|
|
MessageBar,
|
|
MessageBarType,
|
|
PrimaryButton,
|
|
ProgressIndicator,
|
|
Stack,
|
|
Text,
|
|
} from "@fluentui/react";
|
|
import * as React from "react";
|
|
import * as ViewModels from "../../../../Contracts/ViewModels";
|
|
|
|
import { handleError } from "Common/ErrorHandlingUtils";
|
|
import { cancelDataTransferJob, pollDataTransferJob } from "Common/dataAccess/dataTransfers";
|
|
import { Platform, configContext } from "ConfigContext";
|
|
import Explorer from "Explorer/Explorer";
|
|
import { ChangePartitionKeyPane } from "Explorer/Panes/ChangePartitionKeyPane/ChangePartitionKeyPane";
|
|
import {
|
|
CosmosSqlDataTransferDataSourceSink,
|
|
DataTransferJobGetResults,
|
|
} from "Utils/arm/generatedClients/dataTransferService/types";
|
|
import { refreshDataTransferJobs, useDataTransferJobs } from "hooks/useDataTransferJobs";
|
|
import { useSidePanel } from "hooks/useSidePanel";
|
|
import { userContext } from "../../../../UserContext";
|
|
|
|
export interface PartitionKeyComponentProps {
|
|
database: ViewModels.Database;
|
|
collection: ViewModels.Collection;
|
|
explorer: Explorer;
|
|
isReadOnly?: boolean; // true: cannot change partition key
|
|
}
|
|
|
|
const darkThemeMessageBarStyles: Partial<IMessageBarStyles> = {
|
|
root: {
|
|
selectors: {
|
|
"&.ms-MessageBar--warning": {
|
|
backgroundColor: "var(--colorStatusWarningBackground1)",
|
|
border: "1px solid var(--colorStatusWarningBorder1)",
|
|
},
|
|
".ms-MessageBar-icon": {
|
|
color: "var(--colorNeutralForeground1)",
|
|
},
|
|
".ms-MessageBar-text": {
|
|
color: "var(--colorNeutralForeground1)",
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
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();
|
|
setPortalDataTransferJob(currentJob);
|
|
startPollingforUpdate(currentJob);
|
|
}, [dataTransferJobs]);
|
|
|
|
const isHierarchicalPartitionedContainer = (): boolean => collection.partitionKey?.kind === "MultiHash";
|
|
|
|
const getPartitionKeyValue = (): string => {
|
|
return (collection.partitionKeyProperties || []).map((property) => "/" + property).join(", ");
|
|
};
|
|
|
|
const partitionKeyName = "Partition key";
|
|
const partitionKeyValue = getPartitionKeyValue();
|
|
|
|
const textHeadingStyle = {
|
|
root: { fontWeight: FontWeights.semibold, fontSize: 16, color: "var(--colorNeutralForeground1)" },
|
|
};
|
|
|
|
const textSubHeadingStyle = {
|
|
root: { fontWeight: FontWeights.semibold, color: "var(--colorNeutralForeground1)" },
|
|
};
|
|
const textSubHeadingStyle1 = {
|
|
root: { color: "var(--colorNeutralForeground1)" },
|
|
};
|
|
const startPollingforUpdate = (currentJob: DataTransferJobGetResults) => {
|
|
if (isCurrentJobInProgress(currentJob)) {
|
|
const jobName = currentJob?.properties?.jobName;
|
|
try {
|
|
pollDataTransferJob(
|
|
jobName,
|
|
userContext.subscriptionId,
|
|
userContext.resourceGroup,
|
|
userContext.databaseAccount.name,
|
|
);
|
|
} catch (error) {
|
|
handleError(error, "ChangePartitionKey", `Failed to complete data transfer job ${jobName}`);
|
|
}
|
|
}
|
|
};
|
|
|
|
const cancelRunningDataTransferJob = async (currentJob: DataTransferJobGetResults) => {
|
|
await cancelDataTransferJob(
|
|
userContext.subscriptionId,
|
|
userContext.resourceGroup,
|
|
userContext.databaseAccount.name,
|
|
currentJob?.properties?.jobName,
|
|
);
|
|
};
|
|
|
|
const isCurrentJobInProgress = (currentJob: DataTransferJobGetResults) => {
|
|
const jobStatus = currentJob?.properties?.status;
|
|
return (
|
|
jobStatus &&
|
|
jobStatus !== "Completed" &&
|
|
jobStatus !== "Cancelled" &&
|
|
jobStatus !== "Failed" &&
|
|
jobStatus !== "Faulted"
|
|
);
|
|
};
|
|
|
|
const refreshDataTransferOperations = async () => {
|
|
await refreshDataTransferJobs(
|
|
userContext.subscriptionId,
|
|
userContext.resourceGroup,
|
|
userContext.databaseAccount.name,
|
|
);
|
|
};
|
|
|
|
const findPortalDataTransferJob = (): DataTransferJobGetResults => {
|
|
return dataTransferJobs.find((feed: DataTransferJobGetResults) => {
|
|
const sourceSink: CosmosSqlDataTransferDataSourceSink = feed?.properties
|
|
?.source as CosmosSqlDataTransferDataSourceSink;
|
|
return sourceSink.databaseName === collection.databaseId && sourceSink.containerName === collection.id();
|
|
});
|
|
};
|
|
|
|
const getProgressDescription = (): string => {
|
|
const processedCount = portalDataTransferJob?.properties?.processedCount;
|
|
const totalCount = portalDataTransferJob?.properties?.totalCount;
|
|
const processedCountString = totalCount > 0 ? `(${processedCount} of ${totalCount} documents processed)` : "";
|
|
return `${portalDataTransferJob?.properties?.status} ${processedCountString}`;
|
|
};
|
|
|
|
const startPartitionkeyChangeWorkflow = () => {
|
|
useSidePanel
|
|
.getState()
|
|
.openSidePanel(
|
|
"Change partition key",
|
|
<ChangePartitionKeyPane
|
|
sourceDatabase={database}
|
|
sourceCollection={collection}
|
|
explorer={explorer}
|
|
onClose={refreshDataTransferOperations}
|
|
/>,
|
|
);
|
|
};
|
|
|
|
const getPercentageComplete = () => {
|
|
const jobStatus = portalDataTransferJob?.properties?.status;
|
|
const isCompleted = jobStatus === "Completed";
|
|
if (isCompleted) {
|
|
return 1;
|
|
}
|
|
const processedCount = portalDataTransferJob?.properties?.processedCount;
|
|
const totalCount = portalDataTransferJob?.properties?.totalCount;
|
|
const isJobInProgress = isCurrentJobInProgress(portalDataTransferJob);
|
|
return isJobInProgress ? (totalCount > 0 ? processedCount / totalCount : null) : 0;
|
|
};
|
|
|
|
return (
|
|
<Stack tokens={{ childrenGap: 20 }} styles={{ root: { maxWidth: 600 } }}>
|
|
<Stack tokens={{ childrenGap: 10 }}>
|
|
{!isReadOnly && <Text styles={textHeadingStyle}>Change {partitionKeyName.toLowerCase()}</Text>}
|
|
<Stack horizontal tokens={{ childrenGap: 20 }}>
|
|
<Stack tokens={{ childrenGap: 5 }}>
|
|
<Text styles={textSubHeadingStyle}>Current {partitionKeyName.toLowerCase()}</Text>
|
|
<Text styles={textSubHeadingStyle}>Partitioning</Text>
|
|
</Stack>
|
|
<Stack tokens={{ childrenGap: 5 }}>
|
|
<Text styles={textSubHeadingStyle1}>{partitionKeyValue}</Text>
|
|
<Text styles={textSubHeadingStyle1}>
|
|
{isHierarchicalPartitionedContainer() ? "Hierarchical" : "Non-hierarchical"}
|
|
</Text>
|
|
</Stack>
|
|
</Stack>
|
|
</Stack>
|
|
|
|
{!isReadOnly && (
|
|
<>
|
|
<MessageBar
|
|
messageBarType={MessageBarType.warning}
|
|
messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}
|
|
styles={darkThemeMessageBarStyles}
|
|
>
|
|
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
|
|
style={{ color: "var(--colorBrandForeground1)" }}
|
|
>
|
|
Learn more
|
|
</Link>
|
|
</MessageBar>
|
|
<Text styles={{ root: { color: "var(--colorNeutralForeground1)" } }}>
|
|
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>
|
|
);
|
|
};
|