mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-23 02:41:39 +00:00
Updated to a tab
This commit is contained in:
@@ -7,6 +7,10 @@ import {
|
||||
ContainerPolicyComponent,
|
||||
ContainerPolicyComponentProps,
|
||||
} from "Explorer/Controls/Settings/SettingsSubComponents/ContainerPolicyComponent";
|
||||
import {
|
||||
ThroughputBucketsComponent,
|
||||
ThroughputBucketsComponentProps,
|
||||
} from "Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputBucketsComponent";
|
||||
import { useDatabases } from "Explorer/useDatabases";
|
||||
import { isFullTextSearchEnabled, isVectorSearchEnabled } from "Utils/CapabilityUtils";
|
||||
import { isRunningOnPublicCloud } from "Utils/CloudUtils";
|
||||
@@ -338,7 +342,8 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
||||
this.state.isIndexingPolicyDirty ||
|
||||
this.state.isConflictResolutionDirty ||
|
||||
this.state.isComputedPropertiesDirty ||
|
||||
(!!this.state.currentMongoIndexes && this.state.isMongoIndexingPolicySaveable)
|
||||
(!!this.state.currentMongoIndexes && this.state.isMongoIndexingPolicySaveable) ||
|
||||
this.state.isThroughputBucketsSaveable
|
||||
);
|
||||
};
|
||||
|
||||
@@ -350,7 +355,8 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
||||
this.state.isIndexingPolicyDirty ||
|
||||
this.state.isConflictResolutionDirty ||
|
||||
this.state.isComputedPropertiesDirty ||
|
||||
(!!this.state.currentMongoIndexes && this.state.isMongoIndexingPolicyDiscardable)
|
||||
(!!this.state.currentMongoIndexes && this.state.isMongoIndexingPolicyDiscardable) ||
|
||||
this.state.isThroughputBucketsSaveable
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1055,6 +1061,24 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
||||
}
|
||||
}
|
||||
|
||||
if (this.throughputBucketsEnabled && this.state.isThroughputBucketsSaveable) {
|
||||
const updatedOffer: DataModels.Offer = await updateOffer({
|
||||
databaseId: this.collection.databaseId,
|
||||
collectionId: this.collection.id(),
|
||||
currentOffer: this.collection.offer(),
|
||||
autopilotThroughput: this.collection.offer().autoscaleMaxThroughput
|
||||
? this.collection.offer().autoscaleMaxThroughput
|
||||
: undefined,
|
||||
manualThroughput: this.collection.offer().manualThroughput
|
||||
? this.collection.offer().manualThroughput
|
||||
: undefined,
|
||||
throughputBuckets: this.state.throughputBuckets,
|
||||
});
|
||||
this.collection.offer(updatedOffer);
|
||||
this.offer = updatedOffer;
|
||||
this.setState({ isThroughputBucketsSaveable: false });
|
||||
}
|
||||
|
||||
if (this.state.isScaleSaveable) {
|
||||
const updateOfferParams: DataModels.UpdateOfferParams = {
|
||||
databaseId: this.collection.databaseId,
|
||||
@@ -1062,8 +1086,6 @@ 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.throughputBucketsEnabled &&
|
||||
this.state.isThroughputBucketsSaveable && { throughputBuckets: this.state.throughputBuckets }),
|
||||
};
|
||||
if (this.hasProvisioningTypeChanged()) {
|
||||
if (this.state.isAutoPilotSelected) {
|
||||
@@ -1130,11 +1152,6 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
||||
onMaxAutoPilotThroughputChange: this.onMaxAutoPilotThroughputChange,
|
||||
onScaleSaveableChange: this.onScaleSaveableChange,
|
||||
onScaleDiscardableChange: this.onScaleDiscardableChange,
|
||||
throughputBucketsBaseline: this.state.throughputBucketsBaseline,
|
||||
throughputBuckets: this.state.throughputBuckets,
|
||||
enableThroughputBuckets: this.isCollectionSettingsTab && this.throughputBucketsEnabled,
|
||||
onThroughputBucketChange: this.onThroughputBucketChange,
|
||||
onThroughputBucketsSaveableChange: this.onThroughputBucketsSaveableChange,
|
||||
throughputError: this.state.throughputError,
|
||||
};
|
||||
|
||||
@@ -1242,6 +1259,13 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
||||
onConflictResolutionDirtyChange: this.onConflictResolutionDirtyChange,
|
||||
};
|
||||
|
||||
const throughputBucketsComponentProps: ThroughputBucketsComponentProps = {
|
||||
currentBuckets: this.state.throughputBuckets,
|
||||
throughputBucketsBaseline: this.state.throughputBucketsBaseline,
|
||||
onBucketsChange: this.onThroughputBucketChange,
|
||||
onSaveableChange: this.onThroughputBucketsSaveableChange,
|
||||
};
|
||||
|
||||
const partitionKeyComponentProps: PartitionKeyComponentProps = {
|
||||
database: useDatabases.getState().findDatabaseWithId(this.collection.databaseId),
|
||||
collection: this.collection,
|
||||
@@ -1304,6 +1328,13 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
||||
});
|
||||
}
|
||||
|
||||
if (this.throughputBucketsEnabled) {
|
||||
tabs.push({
|
||||
tab: SettingsV2TabTypes.ThroughputBucketsTab,
|
||||
content: <ThroughputBucketsComponent {...throughputBucketsComponentProps} />,
|
||||
});
|
||||
}
|
||||
|
||||
const pivotProps: IPivotProps = {
|
||||
onLinkClick: this.onPivotChange,
|
||||
selectedKey: SettingsV2TabTypes[this.state.selectedTab],
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
titleAndInputStackProps,
|
||||
} from "../SettingsRenderUtils";
|
||||
import { hasDatabaseSharedThroughput } from "../SettingsUtils";
|
||||
import { ThroughputBucketsComponent } from "./ThroughputInputComponents/ThroughputBucketsComponent";
|
||||
import { ThroughputInputAutoPilotV3Component } from "./ThroughputInputComponents/ThroughputInputAutoPilotV3Component";
|
||||
|
||||
export interface ScaleComponentProps {
|
||||
@@ -34,22 +33,10 @@ export interface ScaleComponentProps {
|
||||
onMaxAutoPilotThroughputChange: (newThroughput: number) => void;
|
||||
onScaleSaveableChange: (isScaleSaveable: boolean) => void;
|
||||
onScaleDiscardableChange: (isScaleDiscardable: boolean) => void;
|
||||
throughputBuckets: DataModels.ThroughputBucket[];
|
||||
throughputBucketsBaseline: DataModels.ThroughputBucket[];
|
||||
enableThroughputBuckets: boolean;
|
||||
onThroughputBucketChange: (throughputBuckets: DataModels.ThroughputBucket[]) => void;
|
||||
onThroughputBucketsSaveableChange: (isSaveable: boolean) => void;
|
||||
throughputError?: string;
|
||||
}
|
||||
|
||||
interface ScaleComponentState {
|
||||
isThroughputSaveable: boolean;
|
||||
isThroughputBucketsSaveable: boolean;
|
||||
isThroughputDiscardable: boolean;
|
||||
isThroughputBucketsDiscardable: boolean;
|
||||
}
|
||||
|
||||
export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleComponentState> {
|
||||
export class ScaleComponent extends React.Component<ScaleComponentProps> {
|
||||
private isEmulator: boolean;
|
||||
private offer: DataModels.Offer;
|
||||
private databaseId: string;
|
||||
@@ -61,12 +48,6 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
|
||||
this.offer = this.props.database?.offer() || this.props.collection?.offer();
|
||||
this.databaseId = this.props.database?.id() || this.props.collection.databaseId;
|
||||
this.collectionId = this.props.collection?.id();
|
||||
this.state = {
|
||||
isThroughputSaveable: false,
|
||||
isThroughputBucketsSaveable: false,
|
||||
isThroughputDiscardable: false,
|
||||
isThroughputBucketsDiscardable: false,
|
||||
};
|
||||
}
|
||||
|
||||
public isAutoScaleEnabled = (): boolean => {
|
||||
@@ -80,6 +61,7 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
|
||||
capability.name.toLowerCase() === Constants.CapabilityNames.EnableAutoScale.toLowerCase()
|
||||
);
|
||||
});
|
||||
|
||||
return !!enableAutoScaleCapability;
|
||||
};
|
||||
|
||||
@@ -99,6 +81,7 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
|
||||
if (userContext.isTryCosmosDBSubscription) {
|
||||
return SharedConstants.CollectionCreation.DefaultCollectionRUs400;
|
||||
}
|
||||
|
||||
return this.offer?.minimumThroughput || SharedConstants.CollectionCreation.DefaultCollectionRUs400;
|
||||
};
|
||||
|
||||
@@ -154,8 +137,8 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
|
||||
maxAutoPilotThroughputBaseline={this.props.autoPilotThroughputBaseline}
|
||||
onMaxAutoPilotThroughputChange={this.props.onMaxAutoPilotThroughputChange}
|
||||
spendAckChecked={false}
|
||||
onScaleSaveableChange={this.handleThroughputSaveableChange}
|
||||
onScaleDiscardableChange={this.handleThroughputDiscardableChange}
|
||||
onScaleSaveableChange={this.props.onScaleSaveableChange}
|
||||
onScaleDiscardableChange={this.props.onScaleDiscardableChange}
|
||||
usageSizeInKB={this.props.collection?.usageSizeInKB()}
|
||||
throughputError={this.props.throughputError}
|
||||
instantMaximumThroughput={this.offer?.instantMaximumThroughput}
|
||||
@@ -184,42 +167,6 @@ export class ScaleComponent extends React.Component<ScaleComponentProps, ScaleCo
|
||||
);
|
||||
}
|
||||
|
||||
private updateScaleSettingsState = (updates: Partial<ScaleComponentState>) => {
|
||||
this.setState(
|
||||
(prevState) => {
|
||||
const hasChanges = Object.keys(updates).some(
|
||||
(key) => prevState[key as keyof ScaleComponentState] !== updates[key as keyof ScaleComponentState],
|
||||
);
|
||||
return hasChanges ? { ...prevState, ...updates } : null;
|
||||
},
|
||||
() => {
|
||||
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);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
private handleThroughputSaveableChange = (isSaveable: boolean) => {
|
||||
this.updateScaleSettingsState({ isThroughputSaveable: isSaveable });
|
||||
};
|
||||
|
||||
private handleThroughputDiscardableChange = (isDiscardable: boolean) => {
|
||||
this.updateScaleSettingsState({ isThroughputDiscardable: isDiscardable });
|
||||
};
|
||||
|
||||
private handleThroughputBucketsSaveableChange = (isSaveable: boolean) => {
|
||||
this.updateScaleSettingsState({ isThroughputBucketsSaveable: isSaveable });
|
||||
};
|
||||
|
||||
private handleThroughputBucketsDiscardableChange = (isDiscardable: boolean) => {
|
||||
this.updateScaleSettingsState({ isThroughputBucketsDiscardable: isDiscardable });
|
||||
};
|
||||
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<Stack {...subComponentStackProps}>
|
||||
@@ -235,15 +182,6 @@ 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 && (
|
||||
<ThroughputBucketsComponent
|
||||
currentBuckets={this.props.throughputBuckets}
|
||||
throughputBucketsBaseline={this.props.throughputBucketsBaseline}
|
||||
onBucketsChange={this.props.onThroughputBucketChange}
|
||||
onSaveableChange={this.handleThroughputBucketsSaveableChange}
|
||||
onDiscardableChange={this.handleThroughputBucketsDiscardableChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* TODO: Replace link with call to the Azure Support blade */}
|
||||
{this.isAutoScaleEnabled() && (
|
||||
|
||||
@@ -10,12 +10,11 @@ const DEFAULT_BUCKETS = Array.from({ length: MAX_BUCKET_SIZES }, (_, i) => ({
|
||||
maxThroughputPercentage: 100,
|
||||
}));
|
||||
|
||||
interface ThroughputBucketsComponentProps {
|
||||
export interface ThroughputBucketsComponentProps {
|
||||
currentBuckets: ThroughputBucket[];
|
||||
throughputBucketsBaseline: ThroughputBucket[];
|
||||
onBucketsChange: (updatedBuckets: ThroughputBucket[]) => void;
|
||||
onSaveableChange: (isSaveable: boolean) => void;
|
||||
onDiscardableChange: (isDiscardable: boolean) => void;
|
||||
}
|
||||
|
||||
export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = ({
|
||||
@@ -23,7 +22,6 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
throughputBucketsBaseline,
|
||||
onBucketsChange,
|
||||
onSaveableChange,
|
||||
onDiscardableChange,
|
||||
}) => {
|
||||
const getThroughputBuckets = (buckets: ThroughputBucket[]): ThroughputBucket[] => {
|
||||
if (!buckets || buckets.length === 0) {
|
||||
@@ -45,13 +43,13 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
useEffect(() => {
|
||||
setThroughputBuckets(getThroughputBuckets(currentBuckets));
|
||||
onSaveableChange(false);
|
||||
onDiscardableChange(false);
|
||||
// onDiscardableChange(false);
|
||||
}, [currentBuckets]);
|
||||
|
||||
useEffect(() => {
|
||||
const isChanged = isDirty(throughputBuckets, getThroughputBuckets(throughputBucketsBaseline));
|
||||
onSaveableChange(isChanged);
|
||||
onDiscardableChange(isChanged);
|
||||
// onDiscardableChange(isChanged);
|
||||
}, [throughputBuckets]);
|
||||
|
||||
const handleBucketChange = (id: number, newValue: number) => {
|
||||
@@ -69,7 +67,7 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
|
||||
return (
|
||||
<Stack tokens={{ childrenGap: "m" }} styles={{ root: { width: "70%", maxWidth: 700 } }}>
|
||||
<Label>Throughput groups</Label>
|
||||
<Label>Throughput Buckets</Label>
|
||||
<Stack>
|
||||
{throughputBuckets?.map((bucket) => (
|
||||
<Stack key={bucket.id} horizontal tokens={{ childrenGap: 8 }} verticalAlign="center">
|
||||
@@ -80,7 +78,7 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
value={bucket.maxThroughputPercentage}
|
||||
onChange={(newValue) => handleBucketChange(bucket.id, newValue)}
|
||||
showValue={false}
|
||||
label={`Group ${bucket.id}${bucket.id === 1 ? " (Data Explorer Query Group)" : ""}`}
|
||||
label={`Group ${bucket.id}${bucket.id === 1 ? " (Data Explorer Query Bucket)" : ""}`}
|
||||
styles={{ root: { flex: 2, maxWidth: 400 } }}
|
||||
disabled={bucket.maxThroughputPercentage === 100}
|
||||
/>
|
||||
@@ -94,9 +92,13 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
}}
|
||||
disabled={bucket.maxThroughputPercentage === 100}
|
||||
/>
|
||||
{/* <IconButton
|
||||
iconProps={{ iconName: bucket.maxThroughputPercentage === 100 ? "Add" : "Remove" }}
|
||||
onClick={() => onToggle(bucket.id, bucket.maxThroughputPercentage === 100)}
|
||||
></IconButton> */}
|
||||
<Toggle
|
||||
onText="Enabled"
|
||||
offText="Disabled"
|
||||
onText="Active"
|
||||
offText="Inactive"
|
||||
checked={bucket.maxThroughputPercentage !== 100}
|
||||
onChange={(event, checked) => onToggle(bucket.id, checked)}
|
||||
styles={{ root: { marginBottom: 0 }, text: { fontSize: 12 } }}
|
||||
|
||||
@@ -56,6 +56,7 @@ export enum SettingsV2TabTypes {
|
||||
PartitionKeyTab,
|
||||
ComputedPropertiesTab,
|
||||
ContainerVectorPolicyTab,
|
||||
ThroughputBucketsTab,
|
||||
}
|
||||
|
||||
export enum ContainerPolicyTabTypes {
|
||||
@@ -168,6 +169,8 @@ export const getTabTitle = (tab: SettingsV2TabTypes): string => {
|
||||
return "Computed Properties";
|
||||
case SettingsV2TabTypes.ContainerVectorPolicyTab:
|
||||
return "Container Policies";
|
||||
case SettingsV2TabTypes.ThroughputBucketsTab:
|
||||
return "Throughput Buckets";
|
||||
default:
|
||||
throw new Error(`Unknown tab ${tab}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user