Added logic

This commit is contained in:
Sung-Hyun Kang 2025-01-21 09:28:49 -06:00
parent 07c4ca9c50
commit 152c995ec0
4 changed files with 72 additions and 28 deletions

View File

@ -39,7 +39,10 @@ import {
migrateTableToManualThroughput,
updateTableThroughput,
} from "../../Utils/arm/generatedClients/cosmos/tableResources";
import { ThroughputSettingsUpdateParameters } from "../../Utils/arm/generatedClients/cosmos/types";
import {
ThroughputSettingsGetResults,
ThroughputSettingsUpdateParameters,
} from "../../Utils/arm/generatedClients/cosmos/types";
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
import { HttpHeaders } from "../Constants";
import { client } from "../CosmosClient";
@ -146,23 +149,28 @@ const updateSqlContainerOffer = async (params: UpdateOfferParams): Promise<void>
const { subscriptionId, resourceGroup, databaseAccount } = userContext;
const accountName = databaseAccount.name;
let updatedOffer: ThroughputSettingsGetResults;
if (params.migrateToAutoPilot) {
await migrateSqlContainerToAutoscale(
updatedOffer = (await migrateSqlContainerToAutoscale(
subscriptionId,
resourceGroup,
accountName,
params.databaseId,
params.collectionId,
);
)) as ThroughputSettingsGetResults;
params.autopilotThroughput = updatedOffer.properties?.resource?.autoscaleSettings?.maxThroughput;
} else if (params.migrateToManual) {
await migrateSqlContainerToManualThroughput(
updatedOffer = (await migrateSqlContainerToManualThroughput(
subscriptionId,
resourceGroup,
accountName,
params.databaseId,
params.collectionId,
);
} else {
)) as ThroughputSettingsGetResults;
params.manualThroughput = updatedOffer.properties?.resource?.throughput;
}
if (params.throughputBuckets || !(params.migrateToAutoPilot || params.migrateToManual)) {
const body: ThroughputSettingsUpdateParameters = createUpdateOfferBody(params);
await updateSqlContainerThroughput(
subscriptionId,

View File

@ -106,6 +106,7 @@ export interface SettingsComponentState {
changeFeedPolicyBaseline: ChangeFeedPolicyState;
isSubSettingsSaveable: boolean;
isSubSettingsDiscardable: boolean;
isThroughputBucketsSaveable: boolean;
vectorEmbeddingPolicy: DataModels.VectorEmbeddingPolicy;
vectorEmbeddingPolicyBaseline: DataModels.VectorEmbeddingPolicy;
@ -179,7 +180,9 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
this.changeFeedPolicyVisible = userContext.features.enableChangeFeedPolicy;
this.throughputBucketsEnabled =
userContext.features.enableThroughputBuckets && userContext.authType === AuthType.AAD;
userContext.apiType === "SQL" &&
userContext.features.enableThroughputBuckets &&
userContext.authType === AuthType.AAD;
// Mongo container with system partition key still treat as "Fixed"
this.isFixedContainer =
@ -218,6 +221,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
changeFeedPolicyBaseline: undefined,
isSubSettingsSaveable: false,
isSubSettingsDiscardable: false,
isThroughputBucketsSaveable: false,
vectorEmbeddingPolicy: undefined,
vectorEmbeddingPolicyBaseline: undefined,
@ -450,6 +454,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
isScaleSaveable: false,
isScaleDiscardable: false,
isSubSettingsSaveable: false,
isThroughputBucketsSaveable: false,
isSubSettingsDiscardable: false,
isContainerPolicyDirty: false,
isIndexingPolicyDirty: false,
@ -488,6 +493,10 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
private onIndexingPolicyContentChange = (newIndexingPolicy: DataModels.IndexingPolicy): void =>
this.setState({ indexingPolicyContent: newIndexingPolicy });
private onThroughputBucketsSaveableChange = (isSaveable: boolean): void => {
this.setState({ isThroughputBucketsSaveable: isSaveable });
};
private resetShouldDiscardContainerPolicies = (): void => this.setState({ shouldDiscardContainerPolicies: false });
private resetShouldDiscardIndexingPolicy = (): void => this.setState({ shouldDiscardIndexingPolicy: false });
@ -1053,7 +1062,8 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
currentOffer: this.collection.offer(),
autopilotThroughput: this.state.isAutoPilotSelected ? this.state.autoPilotThroughput : undefined,
manualThroughput: this.state.isAutoPilotSelected ? undefined : this.state.throughput,
...(this.state.throughputBuckets && { throughputBuckets: this.state.throughputBuckets }),
...(this.throughputBucketsEnabled &&
this.state.isThroughputBucketsSaveable && { throughputBuckets: this.state.throughputBuckets }),
};
if (this.hasProvisioningTypeChanged()) {
if (this.state.isAutoPilotSelected) {
@ -1124,6 +1134,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
throughputBuckets: this.state.throughputBuckets,
enableThroughputBuckets: this.isCollectionSettingsTab && this.throughputBucketsEnabled,
onThroughputBucketChange: this.onThroughputBucketChange,
onThroughputBucketsSaveableChange: this.onThroughputBucketsSaveableChange,
throughputError: this.state.throughputError,
};

View File

@ -38,14 +38,15 @@ export interface ScaleComponentProps {
throughputBucketsBaseline: DataModels.ThroughputBucket[];
enableThroughputBuckets: boolean;
onThroughputBucketChange: (throughputBuckets: DataModels.ThroughputBucket[]) => void;
onThroughputBucketsSaveableChange: (isSaveable: boolean) => void;
throughputError?: string;
}
interface ScaleComponentState {
isThroughputSaveable: boolean;
isBucketsSaveable: boolean;
isThroughputBucketsSaveable: boolean;
isThroughputDiscardable: boolean;
isBucketsDiscardable: boolean;
isThroughputBucketsDiscardable: boolean;
}
export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleComponentState> {
@ -62,9 +63,9 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
this.collectionId = this.props.collection?.id();
this.state = {
isThroughputSaveable: false,
isBucketsSaveable: false,
isThroughputBucketsSaveable: false,
isThroughputDiscardable: false,
isBucketsDiscardable: false,
isThroughputBucketsDiscardable: false,
};
}
@ -98,7 +99,6 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
if (userContext.isTryCosmosDBSubscription) {
return SharedConstants.CollectionCreation.DefaultCollectionRUs400;
}
return this.offer?.minimumThroughput || SharedConstants.CollectionCreation.DefaultCollectionRUs400;
};
@ -193,9 +193,12 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
return hasChanges ? { ...prevState, ...updates } : null;
},
() => {
const isSaveable = this.state.isThroughputSaveable || this.state.isBucketsSaveable;
const isDiscardable = this.state.isThroughputDiscardable || this.state.isBucketsDiscardable;
const isSaveable = this.state.isThroughputSaveable
? this.state.isThroughputDiscardable || this.state.isThroughputBucketsSaveable
: this.state.isThroughputBucketsSaveable;
const isDiscardable = this.state.isThroughputDiscardable || this.state.isThroughputBucketsDiscardable;
this.props.onScaleSaveableChange(isSaveable);
this.props.onThroughputBucketsSaveableChange(this.state.isThroughputBucketsSaveable);
this.props.onScaleDiscardableChange(isDiscardable);
},
);
@ -209,12 +212,12 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
this.updateScaleSettingsState({ isThroughputDiscardable: isDiscardable });
};
private handleBucketsSaveableChange = (isSaveable: boolean) => {
this.updateScaleSettingsState({ isBucketsSaveable: isSaveable });
private handleThroughputBucketsSaveableChange = (isSaveable: boolean) => {
this.updateScaleSettingsState({ isThroughputBucketsSaveable: isSaveable });
};
private handleBucketsDiscardableChange = (isDiscardable: boolean) => {
this.updateScaleSettingsState({ isBucketsDiscardable: isDiscardable });
private handleThroughputBucketsDiscardableChange = (isDiscardable: boolean) => {
this.updateScaleSettingsState({ isThroughputBucketsDiscardable: isDiscardable });
};
public render(): JSX.Element {
@ -232,13 +235,13 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
<MessageBar messageBarType={MessageBarType.warning}>{this.getInitialNotificationElement()}</MessageBar>
)}
{!this.isAutoScaleEnabled() && <Stack {...subComponentStackProps}>{this.getThroughputInputComponent()}</Stack>}
{this.props.enableThroughputBuckets && !this.props.isAutoPilotSelected && (
{this.props.enableThroughputBuckets && (
<ThroughputBucketsComponent
currentBuckets={this.props.throughputBuckets}
throughputBucketsBaseline={this.props.throughputBucketsBaseline}
onBucketsChange={this.props.onThroughputBucketChange}
onSaveableChange={this.handleBucketsSaveableChange}
onDiscardableChange={this.handleBucketsDiscardableChange}
onSaveableChange={this.handleThroughputBucketsSaveableChange}
onDiscardableChange={this.handleThroughputBucketsDiscardableChange}
/>
)}

View File

@ -1,4 +1,4 @@
import { Icon, Label, Slider, Stack, TextField } from "@fluentui/react";
import { Label, Slider, Stack, TextField, Toggle } from "@fluentui/react";
import { ThroughputBucket } from "Contracts/DataModels";
import React, { FC, useEffect, useState } from "react";
import { isDirty } from "../../SettingsUtils";
@ -26,7 +26,16 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
onDiscardableChange,
}) => {
const getThroughputBuckets = (buckets: ThroughputBucket[]): ThroughputBucket[] => {
return DEFAULT_BUCKETS.map(
if (!buckets || buckets.length === 0) {
return DEFAULT_BUCKETS;
}
const maxBuckets = Math.max(DEFAULT_BUCKETS.length, buckets.length);
const adjustedDefaultBuckets = Array.from({ length: maxBuckets }, (_, i) => ({
id: i + 1,
maxThroughputPercentage: 100,
}));
return adjustedDefaultBuckets.map(
(defaultBucket) => buckets?.find((bucket) => bucket.id === defaultBucket.id) || defaultBucket,
);
};
@ -54,9 +63,13 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
settingsChanged && onBucketsChange(updatedBuckets);
};
const onToggle = (id: number, checked: boolean) => {
handleBucketChange(id, checked ? 50 : 100);
};
return (
<Stack tokens={{ childrenGap: "m" }} styles={{ root: { width: "70%", maxWidth: 700 } }}>
<Label>Throughput buckets</Label>
<Label>Throughput groups</Label>
<Stack>
{throughputBuckets?.map((bucket) => (
<Stack key={bucket.id} horizontal tokens={{ childrenGap: 8 }} verticalAlign="center">
@ -67,8 +80,9 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
value={bucket.maxThroughputPercentage}
onChange={(newValue) => handleBucketChange(bucket.id, newValue)}
showValue={false}
label={`Bucket ${bucket.id}`}
label={`Group ${bucket.id}${bucket.id === 1 ? " (Data Explorer Query Bucket)" : ""}`}
styles={{ root: { flex: 2, maxWidth: 400 } }}
disabled={bucket.maxThroughputPercentage === 100}
/>
<TextField
value={bucket.maxThroughputPercentage.toString()}
@ -78,13 +92,21 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
styles={{
fieldGroup: { width: 80 },
}}
disabled={bucket.maxThroughputPercentage === 100}
/>
{bucket.id === 1 && (
<Toggle
onText="Enabled"
offText="Disabled"
checked={bucket.maxThroughputPercentage !== 100}
onChange={(event, checked) => onToggle(bucket.id, checked)}
styles={{ root: { marginBottom: 0 }, text: { fontSize: 12 } }}
></Toggle>
{/* {bucket.id === 1 && (
<Stack horizontal tokens={{ childrenGap: 4 }} verticalAlign="center">
<Icon iconName="TagSolid" />
<span>Data Explorer Query Bucket</span>
</Stack>
)}
)} */}
</Stack>
))}
</Stack>