Making further enhancements to workflow

This commit is contained in:
Chuck Skelton
2026-06-18 14:56:54 -07:00
parent 29260c9ca7
commit 1b93dbd26e
3 changed files with 69 additions and 29 deletions
@@ -1,6 +1,7 @@
import { import {
Checkbox, Checkbox,
ChoiceGroup, ChoiceGroup,
DefaultButton,
FontIcon, FontIcon,
IChoiceGroupOption, IChoiceGroupOption,
IMessageBarStyles, IMessageBarStyles,
@@ -18,6 +19,7 @@ import {
TextField, TextField,
Toggle, Toggle,
} from "@fluentui/react"; } from "@fluentui/react";
import { useDialog } from "Explorer/Controls/Dialog";
import { Keys, t } from "Localization"; import { Keys, t } from "Localization";
import React from "react"; import React from "react";
import * as DataModels from "../../../../../Contracts/DataModels"; import * as DataModels from "../../../../../Contracts/DataModels";
@@ -90,10 +92,15 @@ export interface ThroughputInputAutoPilotV3Props {
onHotPartitionKeyRateLimitingPolicyChange: (newPolicy: DataModels.HotPartitionKeyRateLimitingPolicy) => void; onHotPartitionKeyRateLimitingPolicyChange: (newPolicy: DataModels.HotPartitionKeyRateLimitingPolicy) => void;
} }
interface IsThroughputComponentDirtyResult extends IsComponentDirtyResult {
priceHasChanged: boolean;
}
interface ThroughputInputAutoPilotV3State { interface ThroughputInputAutoPilotV3State {
spendAckChecked: boolean; spendAckChecked: boolean;
exceedFreeTierThroughput: boolean; exceedFreeTierThroughput: boolean;
} }
export class ThroughputInputAutoPilotV3Component extends React.Component< export class ThroughputInputAutoPilotV3Component extends React.Component<
ThroughputInputAutoPilotV3Props, ThroughputInputAutoPilotV3Props,
ThroughputInputAutoPilotV3State ThroughputInputAutoPilotV3State
@@ -135,14 +142,16 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
this.shouldCheckComponentIsDirty = false; this.shouldCheckComponentIsDirty = false;
}; };
public IsComponentDirty = (): IsComponentDirtyResult => { public IsComponentDirty = (): IsThroughputComponentDirtyResult => {
let isSaveable = false; let isSaveable = false;
let isDiscardable = false; let isDiscardable = false;
let priceHasChanged = false;
if (this.props.isEnabled) { if (this.props.isEnabled) {
if (this.hasProvisioningTypeChanged()) { if (this.hasProvisioningTypeChanged()) {
isSaveable = true; isSaveable = true;
isDiscardable = true; isDiscardable = true;
priceHasChanged = true;
} else if ( } else if (
isHotPartitionKeyThrottlingEnabled() && isHotPartitionKeyThrottlingEnabled() &&
isDirty(this.props.hotPartitionKeyRateLimitingPolicy, this.props.hotPartitionKeyRateLimitingPolicyBaseline) isDirty(this.props.hotPartitionKeyRateLimitingPolicy, this.props.hotPartitionKeyRateLimitingPolicyBaseline)
@@ -152,6 +161,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
} else if (this.props.isAutoPilotSelected) { } else if (this.props.isAutoPilotSelected) {
if (isDirty(this.props.maxAutoPilotThroughput, this.props.maxAutoPilotThroughputBaseline)) { if (isDirty(this.props.maxAutoPilotThroughput, this.props.maxAutoPilotThroughputBaseline)) {
isDiscardable = true; isDiscardable = true;
priceHasChanged = true;
if ( if (
this.props.softAllowedMaximumThroughput this.props.softAllowedMaximumThroughput
? this.props.maxAutoPilotThroughput <= this.props.softAllowedMaximumThroughput && ? this.props.maxAutoPilotThroughput <= this.props.softAllowedMaximumThroughput &&
@@ -165,6 +175,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
if (isDirty(this.props.throughput, this.props.throughputBaseline)) { if (isDirty(this.props.throughput, this.props.throughputBaseline)) {
isDiscardable = true; isDiscardable = true;
isSaveable = true; isSaveable = true;
priceHasChanged = true;
if ( if (
!this.props.throughput || !this.props.throughput ||
this.props.throughput < this.props.minimum || this.props.throughput < this.props.minimum ||
@@ -177,7 +188,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
} }
} }
} }
return { isSaveable, isDiscardable }; return { isSaveable, isDiscardable, priceHasChanged };
}; };
public constructor(props: ThroughputInputAutoPilotV3Props) { public constructor(props: ThroughputInputAutoPilotV3Props) {
@@ -210,7 +221,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
return <></>; return <></>;
} }
const isDirty: boolean = this.IsComponentDirty().isDiscardable; const isDirty: boolean = this.IsComponentDirty().priceHasChanged;
const regions = account?.properties?.readLocations?.length || 1; const regions = account?.properties?.readLocations?.length || 1;
const multimaster = account?.properties?.enableMultipleWriteLocations || false; const multimaster = account?.properties?.enableMultipleWriteLocations || false;
@@ -858,7 +869,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
private renderWarningMessage = (): JSX.Element => { private renderWarningMessage = (): JSX.Element => {
let warningMessage: JSX.Element; let warningMessage: JSX.Element;
if (this.IsComponentDirty().isDiscardable) { if (this.IsComponentDirty().priceHasChanged) {
warningMessage = saveThroughputWarningMessage; warningMessage = saveThroughputWarningMessage;
} }
@@ -889,34 +900,60 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
onText={t(Keys.common.on)} onText={t(Keys.common.on)}
offText={t(Keys.common.off)} offText={t(Keys.common.off)}
checked={!!this.props.hotPartitionKeyRateLimitingPolicy} checked={!!this.props.hotPartitionKeyRateLimitingPolicy}
disabled={!!this.props.hotPartitionKeyRateLimitingPolicy}
onChange={(_ev, checked) => { onChange={(_ev, checked) => {
if (checked) { if (checked) {
this.props.onHotPartitionKeyRateLimitingPolicyChange({ useDialog.getState().showOkCancelModalDialog(
maximumPerPartitionKeyThroughputUtilizationPercent: t(Keys.controls.settings.scale.rateLimitConfirmOverride),
this.props.hotPartitionKeyRateLimitingPolicyBaseline "",
?.maximumPerPartitionKeyThroughputUtilizationPercent ?? 75, t(Keys.common.yes),
}); () =>
} else { this.props.onHotPartitionKeyRateLimitingPolicyChange({
this.props.onHotPartitionKeyRateLimitingPolicyChange(null); maximumPerPartitionKeyThroughputUtilizationPercent:
this.props.hotPartitionKeyRateLimitingPolicyBaseline
?.maximumPerPartitionKeyThroughputUtilizationPercent ?? 75, //CTODO: move default to common const when we get final default value from backend team
}),
t(Keys.common.no),
undefined,
<>
{t(Keys.controls.settings.scale.rateLimitOverrideWarning1)}
<br />
<br />
{t(Keys.controls.settings.scale.rateLimitOverrideWarning2)}
</>,
);
} }
}} }}
/> />
</Stack> </Stack>
<Slider <Stack horizontal tokens={{ childrenGap: 10 }} style={{ alignItems: "end" }}>
disabled={!this.props.hotPartitionKeyRateLimitingPolicy} <Slider
label={t(Keys.controls.settings.scale.rateLimitPolicyMaxThroughputUtilizationLabel)} disabled={!this.props.hotPartitionKeyRateLimitingPolicy}
min={51} label={t(Keys.controls.settings.scale.rateLimitPolicyMaxThroughputUtilizationLabel)}
max={100} min={51}
ariaValueText={(value: number) => `${value} percent`} max={100}
valueFormat={(value: number) => `${value}%`} ariaValueText={(value: number) => `${value} percent`}
showValue valueFormat={(value: number) => `${value}%`}
value={this.props.hotPartitionKeyRateLimitingPolicy?.maximumPerPartitionKeyThroughputUtilizationPercent ?? 75} showValue
onChange={(value: number) => value={
this.props.onHotPartitionKeyRateLimitingPolicyChange({ this.props.hotPartitionKeyRateLimitingPolicy?.maximumPerPartitionKeyThroughputUtilizationPercent ?? 75
maximumPerPartitionKeyThroughputUtilizationPercent: value, }
}) onChange={(value: number) =>
} this.props.onHotPartitionKeyRateLimitingPolicyChange({
/> maximumPerPartitionKeyThroughputUtilizationPercent: value,
})
}
styles={{ root: { width: "75%" } }}
/>
<DefaultButton
text="Reset to default"
onClick={() =>
this.props.onHotPartitionKeyRateLimitingPolicyChange({
maximumPerPartitionKeyThroughputUtilizationPercent: 75,
})
}
/>
</Stack>
</Stack> </Stack>
); );
}; };
+5 -2
View File
@@ -895,8 +895,11 @@
"keyspaceSharedThroughput": "This table shared throughput is configured at the keyspace", "keyspaceSharedThroughput": "This table shared throughput is configured at the keyspace",
"throughputRangeLabel": "Throughput ({{min}} - {{max}} RU/s)", "throughputRangeLabel": "Throughput ({{min}} - {{max}} RU/s)",
"unlimited": "unlimited", "unlimited": "unlimited",
"rateLimitingPolicyTitle": "Rate limiting policy", "rateLimitingPolicyTitle": "Override default rate limiting policy",
"rateLimitPolicyMaxThroughputUtilizationLabel": "Max per partition key Throughput utilization" "rateLimitPolicyMaxThroughputUtilizationLabel": "Max partition key throughput utilization",
"rateLimitOverrideWarning1": "Overriding the default rate limiting is irreversible. Though you will be able to manually reset the value to its default, the policy will remain overriden at the value you set.",
"rateLimitOverrideWarning2": "Are you sure you wish to continue?",
"rateLimitConfirmOverride": "Confirm override"
}, },
"partitionKeyEditor": { "partitionKeyEditor": {
"changePartitionKey": "Change {{partitionKeyName}}", "changePartitionKey": "Change {{partitionKeyName}}",
@@ -9,7 +9,7 @@
import { configContext } from "../../../../ConfigContext"; import { configContext } from "../../../../ConfigContext";
import { armRequest } from "../../request"; import { armRequest } from "../../request";
import * as Types from "./types"; import * as Types from "./types";
const apiVersion = "2025-11-01-preview"; const apiVersion = "2026-04-01-preview";
/* Lists the SQL databases under an existing Azure Cosmos DB database account. */ /* Lists the SQL databases under an existing Azure Cosmos DB database account. */
export async function listSqlDatabases( export async function listSqlDatabases(