mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-21 01:41:31 +00:00
Refactored Settings Tab (#161)
* added SettingsV2 Tab * lint changes * foxed failing test * Addressed PR comments - removed dangerouslySetInnerHtml - removed underscore dependency - added AccessibleElement - removed unnecesary exceptions to linting * split render into separate functions - removed sinon in test - Added some enums to replace constant strings - removed dangerously set inner html - made autopilot input as StatefulValue * add settingscomponent snapshot * fixed linting errors * fixed errors * addressed PR comments - Moved StatefulValue to new class - Split render to more functions for throughputInputComponents * Added sub components - Added tests for SettingsRenderUtls - Added empty test files for adding tests later * Moved all inputs to fluent UI - removed rupm - added reusable styles * Added Tabs - Added ToolTipLabel component - Removed toggleables for individual components - Removed accessible elements - Added IndexingPolicyComponent * Added more tests * Addressed PR comments * Moved Label radio buttons to choicegroup * fixed lint errors * Removed StatefulValue - Moved conflict res tab to the end - Added styling for autpilot radiobuttons * fixed linting errors * fix bugs from merge to master * fixed formatting issue * Addressed PR comments - Added unit tests for smaller methods within each component * fixed linting errors * removed redundant snapshots * removed empty line * made separate props objects for subcomponents * Moved dirty checks to sub components * Made indesing policy component height = 80% of view port - modified auto pilot v3 messages - Added Fluent UI tolltip - * Moved warning messages inline * moved conflict res helpers out * fixed bugs * added stack style for message * fixed tests * Added tests * fixed linting and format errors * undid changes * more edits * fixed compile errors * fixed compile errors * fixed errors * fixed bug with save and discard buttons * fixed compile errors * addressed PR comments
This commit is contained in:
committed by
GitHub
parent
4ecdfe60eb
commit
fc722e87be
@@ -0,0 +1,235 @@
|
||||
import * as React from "react";
|
||||
import * as Constants from "../../../../Common/Constants";
|
||||
import { ThroughputInputAutoPilotV3Component } from "./ThroughputInputComponents/ThroughputInputAutoPilotV3Component";
|
||||
import * as ViewModels from "../../../../Contracts/ViewModels";
|
||||
import * as DataModels from "../../../../Contracts/DataModels";
|
||||
import * as SharedConstants from "../../../../Shared/Constants";
|
||||
import Explorer from "../../../Explorer";
|
||||
import { PlatformType } from "../../../../PlatformType";
|
||||
import {
|
||||
getTextFieldStyles,
|
||||
subComponentStackProps,
|
||||
titleAndInputStackProps,
|
||||
throughputUnit,
|
||||
getThroughputApplyLongDelayMessage,
|
||||
getThroughputApplyShortDelayMessage,
|
||||
updateThroughputBeyondLimitWarningMessage,
|
||||
updateThroughputDelayedApplyWarningMessage
|
||||
} from "../SettingsRenderUtils";
|
||||
import { getMaxRUs, getMinRUs, hasDatabaseSharedThroughput } from "../SettingsUtils";
|
||||
import * as AutoPilotUtils from "../../../../Utils/AutoPilotUtils";
|
||||
import { Text, TextField, Stack, Label, MessageBar, MessageBarType } from "office-ui-fabric-react";
|
||||
|
||||
export interface ScaleComponentProps {
|
||||
collection: ViewModels.Collection;
|
||||
container: Explorer;
|
||||
isFixedContainer: boolean;
|
||||
autoPilotTiersList: ViewModels.DropdownOption<DataModels.AutopilotTier>[];
|
||||
onThroughputChange: (newThroughput: number) => void;
|
||||
throughput: number;
|
||||
throughputBaseline: number;
|
||||
autoPilotThroughput: number;
|
||||
autoPilotThroughputBaseline: number;
|
||||
isAutoPilotSelected: boolean;
|
||||
wasAutopilotOriginallySet: boolean;
|
||||
onAutoPilotSelected: (isAutoPilotSelected: boolean) => void;
|
||||
onMaxAutoPilotThroughputChange: (newThroughput: number) => void;
|
||||
onScaleSaveableChange: (isScaleSaveable: boolean) => void;
|
||||
onScaleDiscardableChange: (isScaleDiscardable: boolean) => void;
|
||||
initialNotification: DataModels.Notification;
|
||||
}
|
||||
|
||||
export class ScaleComponent extends React.Component<ScaleComponentProps> {
|
||||
private isEmulator: boolean;
|
||||
constructor(props: ScaleComponentProps) {
|
||||
super(props);
|
||||
this.isEmulator = this.props.container.isEmulator;
|
||||
}
|
||||
|
||||
public isAutoScaleEnabled = (): boolean => {
|
||||
const accountCapabilities: DataModels.Capability[] = this.props.container?.databaseAccount()?.properties
|
||||
?.capabilities;
|
||||
const enableAutoScaleCapability =
|
||||
accountCapabilities &&
|
||||
accountCapabilities.find((capability: DataModels.Capability) => {
|
||||
return (
|
||||
capability &&
|
||||
capability.name &&
|
||||
capability.name.toLowerCase() === Constants.CapabilityNames.EnableAutoScale.toLowerCase()
|
||||
);
|
||||
});
|
||||
|
||||
return !!enableAutoScaleCapability;
|
||||
};
|
||||
|
||||
private getStorageCapacityTitle = (): JSX.Element => {
|
||||
// Mongo container with system partition key still treat as "Fixed"
|
||||
const isFixed =
|
||||
!this.props.collection.partitionKey ||
|
||||
(this.props.container.isPreferredApiMongoDB() && this.props.collection.partitionKey.systemKey);
|
||||
const capacity: string = isFixed ? "Fixed" : "Unlimited";
|
||||
return (
|
||||
<Stack {...titleAndInputStackProps}>
|
||||
<Label>Storage capacity</Label>
|
||||
<Text>{capacity}</Text>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
public getMaxRUThroughputInputLimit = (): number => {
|
||||
if (this.props.container?.getPlatformType() === PlatformType.Hosted && this.props.collection.partitionKey) {
|
||||
return SharedConstants.CollectionCreation.DefaultCollectionRUs1Million;
|
||||
}
|
||||
|
||||
return getMaxRUs(this.props.collection, this.props.container);
|
||||
};
|
||||
|
||||
public getThroughputTitle = (): string => {
|
||||
if (this.props.isAutoPilotSelected) {
|
||||
return AutoPilotUtils.getAutoPilotHeaderText(false);
|
||||
}
|
||||
|
||||
const minThroughput: string = getMinRUs(this.props.collection, this.props.container).toLocaleString();
|
||||
const maxThroughput: string =
|
||||
this.canThroughputExceedMaximumValue() && !this.props.isFixedContainer
|
||||
? "unlimited"
|
||||
: getMaxRUs(this.props.collection, this.props.container).toLocaleString();
|
||||
return `Throughput (${minThroughput} - ${maxThroughput} RU/s)`;
|
||||
};
|
||||
|
||||
public canThroughputExceedMaximumValue = (): boolean => {
|
||||
const isPublicAzurePortal: boolean =
|
||||
this.props.container.getPlatformType() === PlatformType.Portal &&
|
||||
!this.props.container.isRunningOnNationalCloud();
|
||||
const hasPartitionKey = !!this.props.collection.partitionKey;
|
||||
|
||||
return isPublicAzurePortal && hasPartitionKey;
|
||||
};
|
||||
|
||||
public getInitialNotificationElement = (): JSX.Element => {
|
||||
if (this.props.initialNotification) {
|
||||
return this.getLongDelayMessage();
|
||||
}
|
||||
|
||||
const offer = this.props.collection?.offer && this.props.collection.offer();
|
||||
if (
|
||||
offer &&
|
||||
Object.keys(offer).find(value => {
|
||||
return value === "headers";
|
||||
}) &&
|
||||
!!(offer as DataModels.OfferWithHeaders).headers[Constants.HttpHeaders.offerReplacePending]
|
||||
) {
|
||||
const throughput = offer?.content?.offerAutopilotSettings?.maxThroughput;
|
||||
|
||||
const targetThroughput =
|
||||
offer.content?.offerAutopilotSettings?.targetMaxThroughput || offer?.content?.offerThroughput;
|
||||
|
||||
return getThroughputApplyShortDelayMessage(
|
||||
this.props.isAutoPilotSelected,
|
||||
throughput,
|
||||
throughputUnit,
|
||||
this.props.collection.databaseId,
|
||||
this.props.collection.id(),
|
||||
targetThroughput
|
||||
);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
public getThroughputWarningMessage = (): JSX.Element => {
|
||||
const throughputExceedsBackendLimits: boolean =
|
||||
this.canThroughputExceedMaximumValue() &&
|
||||
getMaxRUs(this.props.collection, this.props.container) <=
|
||||
SharedConstants.CollectionCreation.DefaultCollectionRUs1Million &&
|
||||
this.props.throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs1Million;
|
||||
|
||||
if (throughputExceedsBackendLimits && !!this.props.collection.partitionKey && !this.props.isFixedContainer) {
|
||||
return updateThroughputBeyondLimitWarningMessage;
|
||||
}
|
||||
|
||||
const throughputExceedsMaxValue: boolean =
|
||||
!this.isEmulator && this.props.throughput > getMaxRUs(this.props.collection, this.props.container);
|
||||
|
||||
if (throughputExceedsMaxValue && !!this.props.collection.partitionKey && !this.props.isFixedContainer) {
|
||||
return updateThroughputDelayedApplyWarningMessage;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
public getLongDelayMessage = (): JSX.Element => {
|
||||
const matches: string[] = this.props.initialNotification?.description.match(
|
||||
`Throughput update for (.*) ${throughputUnit}`
|
||||
);
|
||||
|
||||
const throughput = this.props.throughputBaseline;
|
||||
const targetThroughput: number = matches.length > 1 && Number(matches[1]);
|
||||
if (targetThroughput) {
|
||||
return getThroughputApplyLongDelayMessage(
|
||||
this.props.wasAutopilotOriginallySet,
|
||||
throughput,
|
||||
throughputUnit,
|
||||
this.props.collection.databaseId,
|
||||
this.props.collection.id(),
|
||||
targetThroughput
|
||||
);
|
||||
}
|
||||
return <></>;
|
||||
};
|
||||
|
||||
private getThroughputInputComponent = (): JSX.Element => (
|
||||
<ThroughputInputAutoPilotV3Component
|
||||
databaseAccount={this.props.container.databaseAccount()}
|
||||
serverId={this.props.container.serverId()}
|
||||
throughput={this.props.throughput}
|
||||
throughputBaseline={this.props.throughputBaseline}
|
||||
onThroughputChange={this.props.onThroughputChange}
|
||||
minimum={getMinRUs(this.props.collection, this.props.container)}
|
||||
maximum={this.getMaxRUThroughputInputLimit()}
|
||||
isEnabled={!hasDatabaseSharedThroughput(this.props.collection)}
|
||||
canExceedMaximumValue={this.canThroughputExceedMaximumValue()}
|
||||
label={this.getThroughputTitle()}
|
||||
isEmulator={this.isEmulator}
|
||||
isFixed={this.props.isFixedContainer}
|
||||
isAutoPilotSelected={this.props.isAutoPilotSelected}
|
||||
onAutoPilotSelected={this.props.onAutoPilotSelected}
|
||||
wasAutopilotOriginallySet={this.props.wasAutopilotOriginallySet}
|
||||
maxAutoPilotThroughput={this.props.autoPilotThroughput}
|
||||
maxAutoPilotThroughputBaseline={this.props.autoPilotThroughputBaseline}
|
||||
onMaxAutoPilotThroughputChange={this.props.onMaxAutoPilotThroughputChange}
|
||||
spendAckChecked={false}
|
||||
onScaleSaveableChange={this.props.onScaleSaveableChange}
|
||||
onScaleDiscardableChange={this.props.onScaleDiscardableChange}
|
||||
getThroughputWarningMessage={this.getThroughputWarningMessage}
|
||||
/>
|
||||
);
|
||||
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<Stack {...subComponentStackProps}>
|
||||
{this.getInitialNotificationElement() && (
|
||||
<MessageBar messageBarType={MessageBarType.warning}>{this.getInitialNotificationElement()}</MessageBar>
|
||||
)}
|
||||
{!this.isAutoScaleEnabled() && (
|
||||
<Stack {...subComponentStackProps}>
|
||||
{this.getThroughputInputComponent()}
|
||||
{this.getStorageCapacityTitle()}
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{/* TODO: Replace link with call to the Azure Support blade */}
|
||||
{this.isAutoScaleEnabled() && (
|
||||
<Stack {...titleAndInputStackProps}>
|
||||
<Text>Throughput (RU/s)</Text>
|
||||
<TextField disabled styles={getTextFieldStyles(undefined, undefined)} />
|
||||
<Text>
|
||||
Your account has custom settings that prevents setting throughput at the container level. Please work with
|
||||
your Cosmos DB engineering team point of contact to make changes.
|
||||
</Text>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user