mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-24 20:24:13 +00:00
default throughput bucket
This commit is contained in:
@@ -76,11 +76,11 @@ describe("ThroughputBucketsComponent", () => {
|
||||
fireEvent.change(input, { target: { value: "70" } });
|
||||
|
||||
expect(mockOnBucketsChange).toHaveBeenCalledWith([
|
||||
{ id: 1, maxThroughputPercentage: 70 },
|
||||
{ id: 2, maxThroughputPercentage: 60 },
|
||||
{ id: 3, maxThroughputPercentage: 100 },
|
||||
{ id: 4, maxThroughputPercentage: 100 },
|
||||
{ id: 5, maxThroughputPercentage: 100 },
|
||||
{ id: 1, maxThroughputPercentage: 70, isDefaultBucket: false },
|
||||
{ id: 2, maxThroughputPercentage: 60, isDefaultBucket: false },
|
||||
{ id: 3, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 4, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 5, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -102,11 +102,11 @@ describe("ThroughputBucketsComponent", () => {
|
||||
fireEvent.change(input2, { target: { value: "80" } });
|
||||
|
||||
expect(mockOnBucketsChange).toHaveBeenCalledWith([
|
||||
{ id: 1, maxThroughputPercentage: 70 },
|
||||
{ id: 2, maxThroughputPercentage: 80 },
|
||||
{ id: 3, maxThroughputPercentage: 100 },
|
||||
{ id: 4, maxThroughputPercentage: 100 },
|
||||
{ id: 5, maxThroughputPercentage: 100 },
|
||||
{ id: 1, maxThroughputPercentage: 70, isDefaultBucket: false },
|
||||
{ id: 2, maxThroughputPercentage: 80, isDefaultBucket: false },
|
||||
{ id: 3, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 4, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 5, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -134,8 +134,8 @@ describe("ThroughputBucketsComponent", () => {
|
||||
<ThroughputBucketsComponent
|
||||
{...defaultProps}
|
||||
currentBuckets={[
|
||||
{ id: 1, maxThroughputPercentage: 100 },
|
||||
{ id: 2, maxThroughputPercentage: 50 },
|
||||
{ id: 1, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 2, maxThroughputPercentage: 50, isDefaultBucket: false },
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
@@ -157,21 +157,21 @@ describe("ThroughputBucketsComponent", () => {
|
||||
fireEvent.click(toggles[0]);
|
||||
|
||||
expect(mockOnBucketsChange).toHaveBeenCalledWith([
|
||||
{ id: 1, maxThroughputPercentage: 100 },
|
||||
{ id: 2, maxThroughputPercentage: 60 },
|
||||
{ id: 3, maxThroughputPercentage: 100 },
|
||||
{ id: 4, maxThroughputPercentage: 100 },
|
||||
{ id: 5, maxThroughputPercentage: 100 },
|
||||
{ id: 1, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 2, maxThroughputPercentage: 60, isDefaultBucket: false },
|
||||
{ id: 3, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 4, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 5, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
]);
|
||||
|
||||
fireEvent.click(toggles[0]);
|
||||
|
||||
expect(mockOnBucketsChange).toHaveBeenCalledWith([
|
||||
{ id: 1, maxThroughputPercentage: 50 },
|
||||
{ id: 2, maxThroughputPercentage: 60 },
|
||||
{ id: 3, maxThroughputPercentage: 100 },
|
||||
{ id: 4, maxThroughputPercentage: 100 },
|
||||
{ id: 5, maxThroughputPercentage: 100 },
|
||||
{ id: 1, maxThroughputPercentage: 50, isDefaultBucket: false },
|
||||
{ id: 2, maxThroughputPercentage: 60, isDefaultBucket: false },
|
||||
{ id: 3, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 4, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
{ id: 5, maxThroughputPercentage: 100, isDefaultBucket: false },
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
import { Label, Slider, Stack, TextField, Toggle } from "@fluentui/react";
|
||||
import {
|
||||
Dropdown,
|
||||
Icon,
|
||||
IDropdownOption,
|
||||
Label,
|
||||
Link,
|
||||
Slider,
|
||||
Stack,
|
||||
Text,
|
||||
TextField,
|
||||
Toggle,
|
||||
TooltipHost,
|
||||
} from "@fluentui/react";
|
||||
import { ThroughputBucket } from "Contracts/DataModels";
|
||||
import React, { FC, useEffect, useState } from "react";
|
||||
import { isDirty } from "../../SettingsUtils";
|
||||
@@ -8,6 +20,7 @@ const MAX_BUCKET_SIZES = 5;
|
||||
const DEFAULT_BUCKETS = Array.from({ length: MAX_BUCKET_SIZES }, (_, i) => ({
|
||||
id: i + 1,
|
||||
maxThroughputPercentage: 100,
|
||||
isDefaultBucket: false,
|
||||
}));
|
||||
|
||||
export interface ThroughputBucketsComponentProps {
|
||||
@@ -23,19 +36,46 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
onBucketsChange,
|
||||
onSaveableChange,
|
||||
}) => {
|
||||
const NoDefaultThroughputSelectedKey: number = -1;
|
||||
const getThroughputBuckets = (buckets: ThroughputBucket[]): ThroughputBucket[] => {
|
||||
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,
|
||||
const adjustedDefaultBuckets: ThroughputBucket[] = Array.from(
|
||||
{ length: maxBuckets },
|
||||
(_, i) =>
|
||||
({
|
||||
id: i + 1,
|
||||
maxThroughputPercentage: 100,
|
||||
isDefaultBucket: false,
|
||||
}) as ThroughputBucket,
|
||||
);
|
||||
|
||||
return adjustedDefaultBuckets.map((defaultBucket: ThroughputBucket) => {
|
||||
const incoming: ThroughputBucket = buckets?.find((bucket) => bucket.id === defaultBucket.id);
|
||||
|
||||
return {
|
||||
...defaultBucket,
|
||||
...incoming,
|
||||
...(incoming?.isDefaultBucket && { isDefaultBucket: true }),
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const getThroughputBucketOptions = (): IDropdownOption[] => {
|
||||
const noDefaultThroughputBucketSelected: IDropdownOption[] = [
|
||||
{ key: NoDefaultThroughputSelectedKey, text: "No Default Throughput Bucket Selected" },
|
||||
];
|
||||
|
||||
const throughputBucketOptions: IDropdownOption[] = throughputBuckets
|
||||
.filter((bucket) => bucket.maxThroughputPercentage !== 100)
|
||||
.map((bucket) => ({
|
||||
key: bucket.id,
|
||||
text: `Bucket ${bucket.id} - ${bucket.maxThroughputPercentage}%`,
|
||||
}));
|
||||
|
||||
return [...noDefaultThroughputBucketSelected, ...throughputBucketOptions];
|
||||
};
|
||||
|
||||
const [throughputBuckets, setThroughputBuckets] = useState<ThroughputBucket[]>(getThroughputBuckets(currentBuckets));
|
||||
@@ -52,7 +92,13 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
|
||||
const handleBucketChange = (id: number, newValue: number) => {
|
||||
const updatedBuckets = throughputBuckets.map((bucket) =>
|
||||
bucket.id === id ? { ...bucket, maxThroughputPercentage: newValue } : bucket,
|
||||
bucket.id === id
|
||||
? {
|
||||
...bucket,
|
||||
maxThroughputPercentage: newValue,
|
||||
isDefaultBucket: newValue === 100 ? false : bucket.isDefaultBucket,
|
||||
}
|
||||
: bucket,
|
||||
);
|
||||
setThroughputBuckets(updatedBuckets);
|
||||
const settingsChanged = isDirty(updatedBuckets, throughputBuckets);
|
||||
@@ -63,6 +109,35 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
handleBucketChange(id, checked ? 50 : 100);
|
||||
};
|
||||
|
||||
const onDefaultBucketToggle = (id: number, checked: boolean): void => {
|
||||
const updatedBuckets: ThroughputBucket[] = throughputBuckets.map((bucket) =>
|
||||
bucket.id === id ? { ...bucket, isDefaultBucket: checked } : { ...bucket, isDefaultBucket: false },
|
||||
);
|
||||
setThroughputBuckets(updatedBuckets);
|
||||
const settingsChanged = isDirty(updatedBuckets, throughputBuckets);
|
||||
settingsChanged && onBucketsChange(updatedBuckets);
|
||||
};
|
||||
|
||||
const onRenderDefaultThroughputBucketLabel = (): JSX.Element => {
|
||||
const tooltipContent = (): JSX.Element => (
|
||||
<Text>
|
||||
The default throughput bucket is used for operations that do not specify a particular bucket.{" "}
|
||||
<Link href="https://aka.ms/cosmsodb-bucketing" target="_blank">
|
||||
Learn more.
|
||||
</Link>
|
||||
</Text>
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack horizontal verticalAlign="center">
|
||||
<Label>Default Throughput Bucket</Label>
|
||||
<TooltipHost content={tooltipContent()}>
|
||||
<Icon iconName="Info" styles={{ root: { marginLeft: 4, marginTop: 5 } }} />
|
||||
</TooltipHost>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack tokens={{ childrenGap: "m" }} styles={{ root: { width: "70%", maxWidth: 700 } }}>
|
||||
<Label styles={{ root: { color: "var(--colorNeutralForeground1)" } }}>Throughput Buckets</Label>
|
||||
@@ -108,9 +183,32 @@ export const ThroughputBucketsComponent: FC<ThroughputBucketsComponentProps> = (
|
||||
text: { fontSize: 12, color: "var(--colorNeutralForeground1)" },
|
||||
}}
|
||||
></Toggle>
|
||||
{/* <Toggle
|
||||
onText="Default"
|
||||
offText="Not Default"
|
||||
checked={bucket.isDefaultBucket || false}
|
||||
onChange={(_, checked) => onDefaultBucketToggle(bucket.id, checked)}
|
||||
disabled={bucket.maxThroughputPercentage === 100}
|
||||
styles={{
|
||||
root: { marginBottom: 0 },
|
||||
text: { fontSize: 12, color: "var(--colorNeutralForeground1)" },
|
||||
}}
|
||||
/> */}
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
<Dropdown
|
||||
placeholder="Select a default throughput bucket"
|
||||
label="Default Throughput Bucket"
|
||||
options={getThroughputBucketOptions()}
|
||||
selectedKey={
|
||||
throughputBuckets?.find((throughputbucket: ThroughputBucket) => throughputbucket.isDefaultBucket)?.id ||
|
||||
NoDefaultThroughputSelectedKey
|
||||
}
|
||||
onChange={(_, option) => onDefaultBucketToggle(option.key as number, true)}
|
||||
styles={{ root: { width: "50%" } }}
|
||||
onRenderLabel={onRenderDefaultThroughputBucketLabel}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user