mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-21 01:41:31 +00:00
migrate AddDatabase component
This commit is contained in:
32518
package-lock.json
generated
32518
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -52,6 +52,7 @@
|
||||
"clean-webpack-plugin": "0.1.19",
|
||||
"clipboard-copy": "4.0.1",
|
||||
"copy-webpack-plugin": "6.0.2",
|
||||
"core-js": "3.5.0",
|
||||
"crossroads": "0.12.2",
|
||||
"css-element-queries": "1.1.1",
|
||||
"d3": "6.1.1",
|
||||
@@ -238,4 +239,4 @@
|
||||
"prettier": {
|
||||
"printWidth": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import { NotebookUtil } from "./Notebook/NotebookUtil";
|
||||
import AddCollectionPane from "./Panes/AddCollectionPane";
|
||||
import { AddCollectionPanel } from "./Panes/AddCollectionPanel";
|
||||
import AddDatabasePane from "./Panes/AddDatabasePane";
|
||||
import { AddDatabasePaneF } from "./Panes/AddDatabasePaneF";
|
||||
import { BrowseQueriesPane } from "./Panes/BrowseQueriesPane";
|
||||
import CassandraAddCollectionPane from "./Panes/CassandraAddCollectionPane";
|
||||
import { ContextualPaneBase } from "./Panes/ContextualPaneBase";
|
||||
@@ -2491,4 +2492,10 @@ export default class Explorer {
|
||||
/>
|
||||
);
|
||||
}
|
||||
public openAddDatabasePane(): void {
|
||||
this.openSidePanel(
|
||||
"Add Database",
|
||||
<AddDatabasePaneF explorer={this} openNotificationConsole={this.expandConsole} closePanel={this.closeSidePanel} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +286,8 @@ function createNewDatabase(container: Explorer): CommandButtonComponentProps {
|
||||
iconSrc: AddDatabaseIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
container.addDatabasePane.open();
|
||||
// container.addDatabasePane.open();
|
||||
container.openAddDatabasePane();
|
||||
document.getElementById("linkAddDatabase").focus();
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
|
||||
22
src/Explorer/Panes/AddDatabasePaneF/Tooltip/index.tsx
Normal file
22
src/Explorer/Panes/AddDatabasePaneF/Tooltip/index.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { useId } from "@uifabric/react-hooks";
|
||||
import { Icon } from "office-ui-fabric-react";
|
||||
import { ITooltipHostStyles, TooltipHost } from "office-ui-fabric-react/lib/Tooltip";
|
||||
import * as React from "react";
|
||||
|
||||
const calloutProps = { gapSpace: 0 };
|
||||
const hostStyles: Partial<ITooltipHostStyles> = { root: { display: "inline-block" } };
|
||||
|
||||
export interface TooltipProps {
|
||||
children: string;
|
||||
}
|
||||
export const Tooltip: React.FunctionComponent = ({ children }: TooltipProps) => {
|
||||
const tooltipId = useId("tooltip");
|
||||
|
||||
return (
|
||||
<span>
|
||||
<TooltipHost content={children} id={tooltipId} calloutProps={calloutProps} styles={hostStyles}>
|
||||
<Icon iconName="InfoSolid" className="panelInfoIcon" />
|
||||
</TooltipHost>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
480
src/Explorer/Panes/AddDatabasePaneF/index.tsx
Normal file
480
src/Explorer/Panes/AddDatabasePaneF/index.tsx
Normal file
@@ -0,0 +1,480 @@
|
||||
import { Checkbox, TextField } from "office-ui-fabric-react";
|
||||
import React, { FunctionComponent, useEffect, useState } from "react";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import { createDatabase } from "../../../Common/dataAccess/createDatabase";
|
||||
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
||||
import { configContext, Platform } from "../../../ConfigContext";
|
||||
import * as DataModels from "../../../Contracts/DataModels";
|
||||
import { SubscriptionType } from "../../../Contracts/SubscriptionType";
|
||||
import * as SharedConstants from "../../../Shared/Constants";
|
||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { userContext } from "../../../UserContext";
|
||||
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
|
||||
import * as PricingUtils from "../../../Utils/PricingUtils";
|
||||
import { ThroughputInput } from "../../Controls/ThroughputInput/ThroughputInput";
|
||||
import Explorer from "../../Explorer";
|
||||
import { GenericRightPaneComponent, GenericRightPaneProps } from "../GenericRightPaneComponent";
|
||||
import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent";
|
||||
import { Tooltip } from "./Tooltip";
|
||||
|
||||
export interface AddDatabasePaneProps {
|
||||
explorer: Explorer;
|
||||
closePanel: () => void;
|
||||
openNotificationConsole: () => void;
|
||||
}
|
||||
|
||||
export const AddDatabasePaneF: FunctionComponent<AddDatabasePaneProps> = ({
|
||||
explorer: container,
|
||||
closePanel,
|
||||
openNotificationConsole,
|
||||
}: AddDatabasePaneProps) => {
|
||||
const getSharedThroughputDefault = (): boolean => {
|
||||
const { subscriptionType } = userContext;
|
||||
if (subscriptionType === SubscriptionType.EA || container.isServerlessEnabled()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const _isAutoPilotSelectedAndWhatTier = (): DataModels.AutoPilotCreationSettings => {
|
||||
if (isAutoPilotSelected && maxAutoPilotThroughputSet) {
|
||||
return {
|
||||
maxThroughput: maxAutoPilotThroughputSet * 1,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const isCassandraAccount: boolean = userContext.apiType === "Cassandra";
|
||||
const databaseLabel: string = isCassandraAccount ? "keyspace" : "database";
|
||||
const collectionsLabel: string = isCassandraAccount ? "tables" : "collections";
|
||||
|
||||
const databaseIdLabel: string = isCassandraAccount ? "Keyspace id" : "Database id";
|
||||
const databaseIdPlaceHolder: string = isCassandraAccount ? "Type a new keyspace id" : "Type a new database id";
|
||||
|
||||
const [databaseId, setDatabaseId] = useState<string>("");
|
||||
const databaseIdTooltipText = `A ${
|
||||
isCassandraAccount ? "keyspace" : "database"
|
||||
} is a logical container of one or more ${isCassandraAccount ? "tables" : "collections"}`;
|
||||
|
||||
const databaseLevelThroughputTooltipText = `Provisioned throughput at the ${databaseLabel} level will be shared across all ${collectionsLabel} within the ${databaseLabel}.`;
|
||||
const [databaseCreateNewShared, setDatabaseCreateNewShared] = useState<boolean>(getSharedThroughputDefault());
|
||||
const [formErrorsDetails, setFormErrorsDetails] = useState<string>();
|
||||
const [formErrors, setFormErrors] = useState<string>("");
|
||||
|
||||
const throughputDefaults = container.collectionCreationDefaults.throughput;
|
||||
|
||||
const [throughput, setThroughput] = useState<number>(throughputDefaults.shared);
|
||||
|
||||
const [maxThroughputRU, setMaxThroughputRU] = useState<number>(throughputDefaults.unlimitedmax);
|
||||
const [minThroughputRU, setMinThroughputRU] = useState<number>(throughputDefaults.unlimitedmin);
|
||||
const maxThroughputRUText: string = maxThroughputRU?.toLocaleString();
|
||||
const [isAutoPilotSelected, setIsAutoPilotSelected] = useState<boolean>(container.isAutoscaleDefaultEnabled());
|
||||
const [throughputRangeText, setThroughputRangeText] = useState<string>(
|
||||
isAutoPilotSelected
|
||||
? AutoPilotUtils.getAutoPilotHeaderText()
|
||||
: `Throughput (${minThroughputRU?.toLocaleString()} - ${maxThroughputRU?.toLocaleString()} RU/s)`
|
||||
);
|
||||
const [throughputSpendAckText, setThroughputSpendAckText] = useState<string>();
|
||||
const [throughputSpendAck, setThroughputSpendAck] = useState<boolean>(false);
|
||||
const canExceedMaximumValue: boolean = container.canExceedMaximumValue();
|
||||
const [throughputSpendAckVisible, setThroughputSpendAckVisible] = useState<boolean>(() => {
|
||||
if (isAutoPilotSelected) {
|
||||
const autoscaleThroughput = maxAutoPilotThroughputSet * 1;
|
||||
return autoscaleThroughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K;
|
||||
}
|
||||
|
||||
const selectedThroughput: number = throughput;
|
||||
const maxRU: number = maxThroughputRU && maxThroughputRU;
|
||||
|
||||
const isMaxRUGreaterThanDefault: boolean = maxRU > SharedConstants.CollectionCreation.DefaultCollectionRUs100K;
|
||||
const isThroughputSetGreaterThanDefault: boolean =
|
||||
selectedThroughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K;
|
||||
|
||||
if (canExceedMaximumValue) {
|
||||
return isThroughputSetGreaterThanDefault;
|
||||
}
|
||||
|
||||
return isThroughputSetGreaterThanDefault && isMaxRUGreaterThanDefault;
|
||||
});
|
||||
const [requestUnitsUsageCost, setRequestUnitsUsageCost] = useState<string>(() => {
|
||||
const offerThroughput: number = throughput;
|
||||
if (offerThroughput < minThroughputRU || (offerThroughput > maxThroughputRU && !canExceedMaximumValue)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const account = userContext.databaseAccount;
|
||||
if (!account) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const regions =
|
||||
(account && account.properties && account.properties.readLocations && account.properties.readLocations.length) ||
|
||||
1;
|
||||
const multimaster = (account && account.properties && account.properties.enableMultipleWriteLocations) || false;
|
||||
|
||||
let estimatedSpendAcknowledge: string;
|
||||
let estimatedSpend: string;
|
||||
if (!isAutoPilotSelected) {
|
||||
estimatedSpend = PricingUtils.getEstimatedSpendHtml(offerThroughput, userContext.portalEnv, regions, multimaster);
|
||||
estimatedSpendAcknowledge = PricingUtils.getEstimatedSpendAcknowledgeString(
|
||||
offerThroughput,
|
||||
userContext.portalEnv,
|
||||
regions,
|
||||
multimaster,
|
||||
isAutoPilotSelected
|
||||
);
|
||||
} else {
|
||||
estimatedSpend = PricingUtils.getEstimatedAutoscaleSpendHtml(
|
||||
maxAutoPilotThroughputSet,
|
||||
userContext.portalEnv,
|
||||
regions,
|
||||
multimaster
|
||||
);
|
||||
estimatedSpendAcknowledge = PricingUtils.getEstimatedSpendAcknowledgeString(
|
||||
maxAutoPilotThroughputSet,
|
||||
userContext.portalEnv,
|
||||
regions,
|
||||
multimaster,
|
||||
isAutoPilotSelected
|
||||
);
|
||||
}
|
||||
// TODO: change throughputSpendAckText to be a computed value, instead of having this side effect
|
||||
setThroughputSpendAckText(estimatedSpendAcknowledge);
|
||||
return estimatedSpend;
|
||||
});
|
||||
const canRequestSupport = () => {
|
||||
if (
|
||||
configContext.platform !== Platform.Emulator &&
|
||||
!userContext.isTryCosmosDBSubscription &&
|
||||
configContext.platform !== Platform.Portal
|
||||
) {
|
||||
const offerThroughput: number = throughput;
|
||||
return offerThroughput <= 100000;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
const [costsVisible, setCostsVisible] = useState<boolean>(configContext.platform !== Platform.Emulator);
|
||||
const isFreeTierAccount: boolean = userContext.databaseAccount?.properties?.enableFreeTier;
|
||||
const upsellMessage: string = PricingUtils.getUpsellMessage(
|
||||
userContext.portalEnv,
|
||||
isFreeTierAccount,
|
||||
container.isFirstResourceCreated(),
|
||||
userContext.defaultExperience,
|
||||
false
|
||||
);
|
||||
const upsellMessageAriaLabel: string = `${upsellMessage}. Click ${
|
||||
isFreeTierAccount ? "to learn more" : "for more details"
|
||||
}`;
|
||||
const upsellAnchorUrl: string = isFreeTierAccount ? Constants.Urls.freeTierInformation : Constants.Urls.cosmosPricing;
|
||||
|
||||
const upsellAnchorText: string = isFreeTierAccount ? "Learn more" : "More details";
|
||||
const [maxAutoPilotThroughputSet, setMaxAutoPilotThroughputSet] = useState<number>(
|
||||
AutoPilotUtils.minAutoPilotThroughput
|
||||
);
|
||||
|
||||
const [autoPilotUsageCost, setAutoPilotUsageCost] = useState<string>(() => {
|
||||
const autoPilot = _isAutoPilotSelectedAndWhatTier();
|
||||
if (!autoPilot) {
|
||||
return "";
|
||||
}
|
||||
return PricingUtils.getAutoPilotV3SpendHtml(autoPilot.maxThroughput, true /* isDatabaseThroughput */);
|
||||
});
|
||||
const ruToolTipText: string = PricingUtils.getRuToolTipText();
|
||||
|
||||
const canConfigureThroughput = !container.isServerlessEnabled();
|
||||
const showUpsellMessage = () => {
|
||||
if (container.isServerlessEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isFreeTierAccount) {
|
||||
return databaseCreateNewShared;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
const title: string = container?.addDatabaseText() || "New Database";
|
||||
const [isExecuting, setIsExecuting] = useState<boolean>(false);
|
||||
|
||||
const _updateThroughputLimitByDatabase = () => {
|
||||
const throughputDefaults = container.collectionCreationDefaults.throughput;
|
||||
setThroughput(throughputDefaults.shared);
|
||||
setMaxThroughputRU(throughputDefaults.unlimitedmax);
|
||||
setMinThroughputRU(throughputDefaults.unlimitedmin);
|
||||
};
|
||||
useEffect(() => {
|
||||
_updateThroughputLimitByDatabase();
|
||||
}, [databaseCreateNewShared]);
|
||||
|
||||
useEffect(() => {
|
||||
setDatabaseCreateNewShared(getSharedThroughputDefault());
|
||||
}, [userContext.subscriptionType]);
|
||||
|
||||
useEffect(() => {
|
||||
setDatabaseId("");
|
||||
setDatabaseCreateNewShared(getSharedThroughputDefault());
|
||||
setIsAutoPilotSelected(container.isAutoscaleDefaultEnabled());
|
||||
setMaxAutoPilotThroughputSet(AutoPilotUtils.minAutoPilotThroughput);
|
||||
_updateThroughputLimitByDatabase();
|
||||
setThroughputSpendAck(false);
|
||||
}, [container.flight]);
|
||||
|
||||
useEffect(() => {
|
||||
const addDatabasePaneOpenMessage = {
|
||||
subscriptionType: SubscriptionType[userContext.subscriptionType],
|
||||
subscriptionQuotaId: userContext.quotaId,
|
||||
defaultsCheck: {
|
||||
throughput: throughput,
|
||||
flight: container.flight(),
|
||||
},
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
};
|
||||
TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage);
|
||||
}, []);
|
||||
|
||||
const submit = () => {
|
||||
if (!_isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const offerThroughput: number = _computeOfferThroughput();
|
||||
|
||||
const addDatabasePaneStartMessage = {
|
||||
database: {
|
||||
id: databaseId,
|
||||
shared: databaseCreateNewShared,
|
||||
},
|
||||
offerThroughput,
|
||||
subscriptionType: SubscriptionType[userContext.subscriptionType],
|
||||
subscriptionQuotaId: userContext.quotaId,
|
||||
defaultsCheck: {
|
||||
flight: container.flight(),
|
||||
},
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
};
|
||||
const startKey: number = TelemetryProcessor.traceStart(Action.CreateDatabase, addDatabasePaneStartMessage);
|
||||
setFormErrors("");
|
||||
setIsExecuting(true);
|
||||
|
||||
const createDatabaseParams: DataModels.CreateDatabaseParams = {
|
||||
databaseId: addDatabasePaneStartMessage.database.id,
|
||||
databaseLevelThroughput: addDatabasePaneStartMessage.database.shared,
|
||||
};
|
||||
|
||||
if (isAutoPilotSelected) {
|
||||
createDatabaseParams.autoPilotMaxThroughput = maxAutoPilotThroughputSet;
|
||||
} else {
|
||||
createDatabaseParams.offerThroughput = addDatabasePaneStartMessage.offerThroughput;
|
||||
}
|
||||
|
||||
createDatabase(createDatabaseParams).then(
|
||||
() => {
|
||||
_onCreateDatabaseSuccess(offerThroughput, startKey);
|
||||
},
|
||||
(error: string) => {
|
||||
_onCreateDatabaseFailure(error, offerThroughput, startKey);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const _onCreateDatabaseSuccess = (offerThroughput: number, startKey: number): void => {
|
||||
setIsExecuting(false);
|
||||
closePanel();
|
||||
container.refreshAllDatabases();
|
||||
const addDatabasePaneSuccessMessage = {
|
||||
database: {
|
||||
id: databaseId,
|
||||
shared: databaseCreateNewShared,
|
||||
},
|
||||
offerThroughput: offerThroughput,
|
||||
subscriptionType: SubscriptionType[userContext.subscriptionType],
|
||||
subscriptionQuotaId: userContext.quotaId,
|
||||
defaultsCheck: {
|
||||
flight: container.flight(),
|
||||
},
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
};
|
||||
TelemetryProcessor.traceSuccess(Action.CreateDatabase, addDatabasePaneSuccessMessage, startKey);
|
||||
};
|
||||
|
||||
const _onCreateDatabaseFailure = (error: string, offerThroughput: number, startKey: number): void => {
|
||||
setIsExecuting(false);
|
||||
const errorMessage = getErrorMessage(error);
|
||||
setFormErrors(errorMessage);
|
||||
setFormErrorsDetails(errorMessage);
|
||||
const addDatabasePaneFailedMessage = {
|
||||
database: {
|
||||
id: databaseId,
|
||||
shared: databaseCreateNewShared,
|
||||
},
|
||||
offerThroughput: offerThroughput,
|
||||
subscriptionType: SubscriptionType[userContext.subscriptionType],
|
||||
subscriptionQuotaId: userContext.quotaId,
|
||||
defaultsCheck: {
|
||||
flight: container.flight(),
|
||||
},
|
||||
dataExplorerArea: Constants.Areas.ContextualPane,
|
||||
error: errorMessage,
|
||||
errorStack: getErrorStack(error),
|
||||
};
|
||||
TelemetryProcessor.traceFailure(Action.CreateDatabase, addDatabasePaneFailedMessage, startKey);
|
||||
};
|
||||
|
||||
const _getThroughput = (): number => {
|
||||
return isNaN(throughput) ? 0 : Number(throughput);
|
||||
};
|
||||
|
||||
const _computeOfferThroughput = (): number => {
|
||||
if (!canConfigureThroughput) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (isAutoPilotSelected) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return _getThroughput();
|
||||
};
|
||||
|
||||
const _isValid = (): boolean => {
|
||||
// TODO add feature flag that disables validation for customers with custom accounts
|
||||
if (isAutoPilotSelected) {
|
||||
const autoPilot = _isAutoPilotSelectedAndWhatTier();
|
||||
if (
|
||||
!autoPilot ||
|
||||
!autoPilot.maxThroughput ||
|
||||
!AutoPilotUtils.isValidAutoPilotThroughput(autoPilot.maxThroughput)
|
||||
) {
|
||||
setFormErrors(
|
||||
`Please enter a value greater than ${AutoPilotUtils.minAutoPilotThroughput} for autopilot throughput`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const throughput = _getThroughput();
|
||||
|
||||
if (throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && !throughputSpendAck) {
|
||||
setFormErrors(`Please acknowledge the estimated daily spend.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const autoscaleThroughput = maxAutoPilotThroughputSet * 1;
|
||||
|
||||
if (
|
||||
isAutoPilotSelected &&
|
||||
autoscaleThroughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K &&
|
||||
!throughputSpendAck
|
||||
) {
|
||||
setFormErrors(`Please acknowledge the estimated monthly spend.`);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
const handleonChangeDBId = React.useCallback(
|
||||
(event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {
|
||||
setDatabaseId(newValue || "");
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const genericPaneProps: GenericRightPaneProps = {
|
||||
container,
|
||||
formError: formErrors,
|
||||
formErrorDetail: formErrorsDetails,
|
||||
id: "copynotebookpane",
|
||||
isExecuting,
|
||||
title,
|
||||
submitButtonText: "OK",
|
||||
onClose: closePanel,
|
||||
onSubmit: submit,
|
||||
};
|
||||
|
||||
return (
|
||||
<GenericRightPaneComponent {...genericPaneProps}>
|
||||
<form style={{ height: "100%" }}>
|
||||
<div className="paneContentContainer" role="dialog" aria-labelledby="databaseTitle">
|
||||
{showUpsellMessage && formErrors === "" && (
|
||||
<PanelInfoErrorComponent
|
||||
message={upsellMessage}
|
||||
messageType="info"
|
||||
showErrorDetails={false}
|
||||
openNotificationConsole={openNotificationConsole}
|
||||
link={upsellAnchorUrl}
|
||||
linkText={upsellAnchorText}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="paneMainContent">
|
||||
<div>
|
||||
<p>
|
||||
<span className="mandatoryStar">*</span>
|
||||
<span>{databaseIdLabel}</span>
|
||||
<Tooltip>{databaseIdTooltipText}</Tooltip>
|
||||
</p>
|
||||
|
||||
<TextField
|
||||
id="database-id"
|
||||
type="text"
|
||||
aria-required="true"
|
||||
autoComplete="off"
|
||||
pattern="[^/?#\\]*[^/?# \\]"
|
||||
title="May not end with space nor contain characters '\' '/' '#' '?'"
|
||||
size={40}
|
||||
aria-label={databaseIdLabel}
|
||||
placeholder={databaseIdPlaceHolder}
|
||||
value={databaseId}
|
||||
onChange={handleonChangeDBId}
|
||||
autoFocus
|
||||
/>
|
||||
|
||||
<div
|
||||
className="databaseProvision"
|
||||
aria-label="New database provision support"
|
||||
style={{ display: "block ruby" }}
|
||||
>
|
||||
<Checkbox
|
||||
title="Provision shared throughput"
|
||||
styles={{
|
||||
text: { fontSize: 12 },
|
||||
checkbox: { width: 12, height: 12 },
|
||||
label: { padding: 0, alignItems: "center" },
|
||||
}}
|
||||
tabIndex={0}
|
||||
label="Provision throughput"
|
||||
className="databaseProvisionText"
|
||||
checked={databaseCreateNewShared}
|
||||
onChange={() => setDatabaseCreateNewShared(!databaseCreateNewShared)}
|
||||
/>
|
||||
<Tooltip>{databaseLevelThroughputTooltipText}</Tooltip>
|
||||
</div>
|
||||
{databaseCreateNewShared && (
|
||||
<div>
|
||||
<ThroughputInput
|
||||
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !container?.isFirstResourceCreated()}
|
||||
isDatabase={true}
|
||||
setThroughputValue={(throughput: number) => setThroughput(throughput)}
|
||||
setIsAutoscale={(isAutoscale: boolean) => setIsAutoPilotSelected(isAutoscale)}
|
||||
onCostAcknowledgeChange={(isAcknowledged: boolean) => setThroughputSpendAck(isAcknowledged)}
|
||||
/>
|
||||
|
||||
{canRequestSupport && (
|
||||
<p>
|
||||
<a href="https://aka.ms/cosmosdbfeedback?subject=Cosmos%20DB%20More%20Throughput%20Request">
|
||||
Contact support{" "}
|
||||
</a>
|
||||
for more than <span>{maxThroughputRUText} </span> RU/s.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</GenericRightPaneComponent>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user