Copilot assisted changes to remove shared throughput options in add database/container.

This commit is contained in:
Jade Welton
2026-04-16 12:09:03 -07:00
parent df6f24780d
commit 1362df56da
9 changed files with 76 additions and 366 deletions

1
package-lock.json generated
View File

@@ -15862,6 +15862,7 @@
"version": "2.3.2", "version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"optional": true, "optional": true,
"os": [ "os": [

View File

@@ -1,3 +0,0 @@
export function getNewDatabaseSharedThroughputDefault(): boolean {
return false;
}

View File

@@ -17,7 +17,6 @@ import {
} from "@fluentui/react"; } from "@fluentui/react";
import * as Constants from "Common/Constants"; import * as Constants from "Common/Constants";
import { createCollection } from "Common/dataAccess/createCollection"; import { createCollection } from "Common/dataAccess/createCollection";
import { getNewDatabaseSharedThroughputDefault } from "Common/DatabaseUtility";
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils"; import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
import { configContext, Platform } from "ConfigContext"; import { configContext, Platform } from "ConfigContext";
import * as DataModels from "Contracts/DataModels"; import * as DataModels from "Contracts/DataModels";
@@ -77,7 +76,6 @@ export const DefaultVectorEmbeddingPolicy: DataModels.VectorEmbeddingPolicy = {
export interface AddCollectionPanelState { export interface AddCollectionPanelState {
createNewDatabase: boolean; createNewDatabase: boolean;
newDatabaseId: string; newDatabaseId: string;
isSharedThroughputChecked: boolean;
selectedDatabaseId: string; selectedDatabaseId: string;
collectionId: string; collectionId: string;
enableIndexing: boolean; enableIndexing: boolean;
@@ -103,8 +101,6 @@ export interface AddCollectionPanelState {
} }
export class AddCollectionPanel extends React.Component<AddCollectionPanelProps, AddCollectionPanelState> { export class AddCollectionPanel extends React.Component<AddCollectionPanelProps, AddCollectionPanelState> {
private newDatabaseThroughput: number;
private isNewDatabaseAutoscale: boolean;
private collectionThroughput: number; private collectionThroughput: number;
private isCollectionAutoscale: boolean; private isCollectionAutoscale: boolean;
private isCostAcknowledged: boolean; private isCostAcknowledged: boolean;
@@ -117,7 +113,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
createNewDatabase: createNewDatabase:
userContext.apiType !== "Tables" && configContext.platform !== Platform.Fabric && !this.props.databaseId, userContext.apiType !== "Tables" && configContext.platform !== Platform.Fabric && !this.props.databaseId,
newDatabaseId: props.isQuickstart ? this.getSampleDBName() : "", newDatabaseId: props.isQuickstart ? this.getSampleDBName() : "",
isSharedThroughputChecked: getNewDatabaseSharedThroughputDefault(),
selectedDatabaseId: selectedDatabaseId:
userContext.apiType === "Tables" ? CollectionCreation.TablesAPIDefaultDatabase : this.props.databaseId, userContext.apiType === "Tables" ? CollectionCreation.TablesAPIDefaultDatabase : this.props.databaseId,
collectionId: props.isQuickstart ? `Sample${getCollectionName()}` : "", collectionId: props.isQuickstart ? `Sample${getCollectionName()}` : "",
@@ -351,61 +346,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
this.setState({ newDatabaseId: event.target.value }) this.setState({ newDatabaseId: event.target.value })
} }
/> />
{!isServerlessAccount() && (
<Stack horizontal>
<Checkbox
label={t(Keys.panes.addCollection.shareThroughput, {
collectionName: getCollectionName(true).toLocaleLowerCase(),
})}
checked={this.state.isSharedThroughputChecked}
styles={{
text: { fontSize: 12, color: "var(--colorNeutralForeground1)" },
checkbox: { width: 12, height: 12 },
label: { padding: 0, alignItems: "center" },
root: {
selectors: {
":hover .ms-Checkbox-text": { color: "var(--colorNeutralForeground1)" },
},
},
}}
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
this.setState({ isSharedThroughputChecked: isChecked })
}
/>
<TooltipHost
directionalHint={DirectionalHint.bottomLeftEdge}
content={t(Keys.panes.addCollection.shareThroughputTooltip, {
collectionName: getCollectionName(true).toLocaleLowerCase(),
})}
>
<Icon
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={t(Keys.panes.addCollection.shareThroughputTooltip, {
collectionName: getCollectionName(true).toLocaleLowerCase(),
})}
/>
</TooltipHost>
</Stack>
)}
{!isServerlessAccount() && this.state.isSharedThroughputChecked && (
<ThroughputInput
showFreeTierExceedThroughputTooltip={isFreeTierAccount() && !isFirstResourceCreated}
isDatabase={true}
isSharded={this.state.isSharded}
isFreeTier={isFreeTierAccount()}
isQuickstart={this.props.isQuickstart}
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
this.setState({ isThroughputCapExceeded })
}
onCostAcknowledgeChange={(isAcknowledge: boolean) => (this.isCostAcknowledged = isAcknowledge)}
/>
)}
</Stack> </Stack>
)} )}
{!this.state.createNewDatabase && ( {!this.state.createNewDatabase && (
@@ -515,9 +455,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
</Stack> </Stack>
)} )}
{userContext.apiType === "Mongo" && {userContext.apiType === "Mongo" && this.props.explorer.isFixedCollectionWithSharedThroughputSupported() && (
(!this.state.isSharedThroughputChecked ||
this.props.explorer.isFixedCollectionWithSharedThroughputSupported()) && (
<Stack> <Stack>
<Stack horizontal style={{ marginTop: -5, marginBottom: -4 }}> <Stack horizontal style={{ marginTop: -5, marginBottom: -4 }}>
<span className="mandatoryStar">*&nbsp;</span> <span className="mandatoryStar">*&nbsp;</span>
@@ -1191,7 +1129,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
} }
if (this.state.createNewDatabase) { if (this.state.createNewDatabase) {
return !this.state.isSharedThroughputChecked; return true;
} }
if (this.state.enableDedicatedThroughput) { if (this.state.enableDedicatedThroughput) {
@@ -1206,9 +1144,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
return false; return false;
} }
return this.state.createNewDatabase return this.state.createNewDatabase ? false : this.isSelectedDatabaseSharedThroughput();
? this.state.isSharedThroughputChecked
: this.isSelectedDatabaseSharedThroughput();
} }
private shouldShowVectorSearchParameters() { private shouldShowVectorSearchParameters() {
@@ -1253,9 +1189,9 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
return false; return false;
} }
const throughput = this.state.createNewDatabase ? this.newDatabaseThroughput : this.collectionThroughput; const throughput = this.collectionThroughput;
if (throughput > CollectionCreation.DefaultCollectionRUs100K && !this.isCostAcknowledged) { if (throughput > CollectionCreation.DefaultCollectionRUs100K && !this.isCostAcknowledged) {
const errorMessage = this.isNewDatabaseAutoscale const errorMessage = this.isCollectionAutoscale
? t(Keys.panes.addCollection.acknowledgeSpendErrorMonthly) ? t(Keys.panes.addCollection.acknowledgeSpendErrorMonthly)
: t(Keys.panes.addCollection.acknowledgeSpendErrorDaily); : t(Keys.panes.addCollection.acknowledgeSpendErrorDaily);
this.setState({ errorMessage }); this.setState({ errorMessage });
@@ -1379,9 +1315,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
database: { database: {
id: databaseId, id: databaseId,
new: this.state.createNewDatabase, new: this.state.createNewDatabase,
shared: this.state.createNewDatabase shared: this.state.createNewDatabase ? false : this.isSelectedDatabaseSharedThroughput(),
? this.state.isSharedThroughputChecked
: this.isSelectedDatabaseSharedThroughput(),
}, },
collection: { collection: {
id: this.state.collectionId, id: this.state.collectionId,
@@ -1399,7 +1333,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
const startKey: number = TelemetryProcessor.traceStart(Action.CreateCollection, telemetryData); const startKey: number = TelemetryProcessor.traceStart(Action.CreateCollection, telemetryData);
const databaseLevelThroughput: boolean = this.state.createNewDatabase const databaseLevelThroughput: boolean = this.state.createNewDatabase
? this.state.isSharedThroughputChecked ? false
: this.isSelectedDatabaseSharedThroughput() && !this.state.enableDedicatedThroughput; : this.isSelectedDatabaseSharedThroughput() && !this.state.enableDedicatedThroughput;
let offerThroughput: number; let offerThroughput: number;
@@ -1410,13 +1344,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
autoPilotMaxThroughput = DEFAULT_FABRIC_NATIVE_CONTAINER_THROUGHPUT; autoPilotMaxThroughput = DEFAULT_FABRIC_NATIVE_CONTAINER_THROUGHPUT;
offerThroughput = undefined; offerThroughput = undefined;
} else if (databaseLevelThroughput) { } else if (databaseLevelThroughput) {
if (this.state.createNewDatabase) { // Existing shared database: no collection-level throughput needed
if (this.isNewDatabaseAutoscale) {
autoPilotMaxThroughput = this.newDatabaseThroughput;
} else {
offerThroughput = this.newDatabaseThroughput;
}
}
} else { } else {
if (this.isCollectionAutoscale) { if (this.isCollectionAutoscale) {
autoPilotMaxThroughput = this.collectionThroughput; autoPilotMaxThroughput = this.collectionThroughput;

View File

@@ -105,49 +105,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
type="text" type="text"
value="" value=""
/> />
<Stack
horizontal={true}
>
<StyledCheckboxBase
checked={false}
label="Share throughput across containers"
onChange={[Function]}
styles={
{
"checkbox": {
"height": 12,
"width": 12,
},
"label": {
"alignItems": "center",
"padding": 0,
},
"root": {
"selectors": {
":hover .ms-Checkbox-text": {
"color": "var(--colorNeutralForeground1)",
},
},
},
"text": {
"color": "var(--colorNeutralForeground1)",
"fontSize": 12,
},
}
}
/>
<StyledTooltipHostBase
content="Throughput configured at the database level will be shared across all containers within the database."
directionalHint={4}
>
<Icon
ariaLabel="Throughput configured at the database level will be shared across all containers within the database."
className="panelInfoIcon"
iconName="Info"
tabIndex={0}
/>
</StyledTooltipHostBase>
</Stack>
</Stack> </Stack>
<Separator <Separator
className="panelSeparator" className="panelSeparator"

View File

@@ -1,5 +1,4 @@
import { Checkbox, Stack, Text, TextField } from "@fluentui/react"; import { Stack, Text, TextField } from "@fluentui/react";
import { getNewDatabaseSharedThroughputDefault } from "Common/DatabaseUtility";
import { Keys, t } from "Localization"; import { Keys, t } from "Localization";
import { ValidCosmosDbIdDescription, ValidCosmosDbIdInputPattern } from "Utils/ValidationUtils"; import { ValidCosmosDbIdDescription, ValidCosmosDbIdInputPattern } from "Utils/ValidationUtils";
import React, { FunctionComponent, useEffect, useState } from "react"; import React, { FunctionComponent, useEffect, useState } from "react";
@@ -9,15 +8,11 @@ import { InfoTooltip } from "../../../Common/Tooltip/InfoTooltip";
import { createDatabase } from "../../../Common/dataAccess/createDatabase"; import { createDatabase } from "../../../Common/dataAccess/createDatabase";
import * as DataModels from "../../../Contracts/DataModels"; import * as DataModels from "../../../Contracts/DataModels";
import { SubscriptionType } from "../../../Contracts/SubscriptionType"; import { SubscriptionType } from "../../../Contracts/SubscriptionType";
import * as SharedConstants from "../../../Shared/Constants";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants"; import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor"; import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../../UserContext"; import { userContext } from "../../../UserContext";
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
import { isServerlessAccount } from "../../../Utils/CapabilityUtils";
import { getUpsellMessage } from "../../../Utils/PricingUtils"; import { getUpsellMessage } from "../../../Utils/PricingUtils";
import { useSidePanel } from "../../../hooks/useSidePanel"; import { useSidePanel } from "../../../hooks/useSidePanel";
import { ThroughputInput } from "../../Controls/ThroughputInput/ThroughputInput";
import Explorer from "../../Explorer"; import Explorer from "../../Explorer";
import { useDatabases } from "../../useDatabases"; import { useDatabases } from "../../useDatabases";
import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent"; import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent";
@@ -34,9 +29,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
buttonElement, buttonElement,
}: AddDatabasePaneProps) => { }: AddDatabasePaneProps) => {
const closeSidePanel = useSidePanel((state) => state.closeSidePanel); const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
let throughput: number;
let isAutoscaleSelected: boolean;
let isCostAcknowledged: boolean;
const { subscriptionType } = userContext; const { subscriptionType } = userContext;
const isCassandraAccount: boolean = userContext.apiType === "Cassandra"; const isCassandraAccount: boolean = userContext.apiType === "Cassandra";
const databaseLabel: string = isCassandraAccount ? "keyspace" : "database"; const databaseLabel: string = isCassandraAccount ? "keyspace" : "database";
@@ -49,23 +41,15 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
const [databaseId, setDatabaseId] = useState<string>(""); const [databaseId, setDatabaseId] = useState<string>("");
const databaseIdTooltipText = t(Keys.panes.addDatabase.databaseTooltip, { databaseLabel, collectionsLabel }); const databaseIdTooltipText = t(Keys.panes.addDatabase.databaseTooltip, { databaseLabel, collectionsLabel });
const databaseLevelThroughputTooltipText = t(Keys.panes.addDatabase.shareThroughputTooltip, {
databaseLabel,
collectionsLabel,
});
const [databaseCreateNewShared, setDatabaseCreateNewShared] = useState<boolean>(
getNewDatabaseSharedThroughputDefault(),
);
const [formErrors, setFormErrors] = useState<string>(""); const [formErrors, setFormErrors] = useState<string>("");
const [isExecuting, setIsExecuting] = useState<boolean>(false); const [isExecuting, setIsExecuting] = useState<boolean>(false);
const [isThroughputCapExceeded, setIsThroughputCapExceeded] = useState<boolean>(false);
const isFreeTierAccount: boolean = userContext.databaseAccount?.properties?.enableFreeTier; const isFreeTierAccount: boolean = userContext.databaseAccount?.properties?.enableFreeTier;
const addDatabasePaneMessage = { const addDatabasePaneMessage = {
database: { database: {
id: databaseId, id: databaseId,
shared: databaseCreateNewShared, shared: false,
}, },
subscriptionType: SubscriptionType[subscriptionType], subscriptionType: SubscriptionType[subscriptionType],
subscriptionQuotaId: userContext.quotaId, subscriptionQuotaId: userContext.quotaId,
@@ -76,9 +60,7 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
const addDatabasePaneOpenMessage = { const addDatabasePaneOpenMessage = {
subscriptionType: SubscriptionType[subscriptionType], subscriptionType: SubscriptionType[subscriptionType],
subscriptionQuotaId: userContext.quotaId, subscriptionQuotaId: userContext.quotaId,
defaultsCheck: { defaultsCheck: {},
throughput,
},
dataExplorerArea: Constants.Areas.ContextualPane, dataExplorerArea: Constants.Areas.ContextualPane,
}; };
TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage); TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage);
@@ -88,13 +70,8 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
}, []); }, []);
const onSubmit = () => { const onSubmit = () => {
if (!_isValid()) {
return;
}
const addDatabasePaneStartMessage = { const addDatabasePaneStartMessage = {
...addDatabasePaneMessage, ...addDatabasePaneMessage,
throughput,
}; };
const startKey: number = TelemetryProcessor.traceStart(Action.CreateDatabase, addDatabasePaneStartMessage); const startKey: number = TelemetryProcessor.traceStart(Action.CreateDatabase, addDatabasePaneStartMessage);
setFormErrors(""); setFormErrors("");
@@ -102,69 +79,41 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
const createDatabaseParams: DataModels.CreateDatabaseParams = { const createDatabaseParams: DataModels.CreateDatabaseParams = {
databaseId: addDatabasePaneStartMessage.database.id, databaseId: addDatabasePaneStartMessage.database.id,
databaseLevelThroughput: addDatabasePaneStartMessage.database.shared, databaseLevelThroughput: false,
}; };
if (isAutoscaleSelected) {
createDatabaseParams.autoPilotMaxThroughput = addDatabasePaneStartMessage.throughput;
} else {
createDatabaseParams.offerThroughput = addDatabasePaneStartMessage.throughput;
}
createDatabase(createDatabaseParams).then( createDatabase(createDatabaseParams).then(
() => { () => {
_onCreateDatabaseSuccess(throughput, startKey); _onCreateDatabaseSuccess(startKey);
}, },
(error: string) => { (error: string) => {
_onCreateDatabaseFailure(error, throughput, startKey); _onCreateDatabaseFailure(error, startKey);
}, },
); );
}; };
const _onCreateDatabaseSuccess = (offerThroughput: number, startKey: number): void => { const _onCreateDatabaseSuccess = (startKey: number): void => {
setIsExecuting(false); setIsExecuting(false);
closeSidePanel(); closeSidePanel();
container.refreshAllDatabases(); container.refreshAllDatabases();
const addDatabasePaneSuccessMessage = { const addDatabasePaneSuccessMessage = {
...addDatabasePaneMessage, ...addDatabasePaneMessage,
offerThroughput,
}; };
TelemetryProcessor.traceSuccess(Action.CreateDatabase, addDatabasePaneSuccessMessage, startKey); TelemetryProcessor.traceSuccess(Action.CreateDatabase, addDatabasePaneSuccessMessage, startKey);
}; };
const _onCreateDatabaseFailure = (error: string, offerThroughput: number, startKey: number): void => { const _onCreateDatabaseFailure = (error: string, startKey: number): void => {
setIsExecuting(false); setIsExecuting(false);
const errorMessage = getErrorMessage(error); const errorMessage = getErrorMessage(error);
setFormErrors(errorMessage); setFormErrors(errorMessage);
const addDatabasePaneFailedMessage = { const addDatabasePaneFailedMessage = {
...addDatabasePaneMessage, ...addDatabasePaneMessage,
offerThroughput,
error: errorMessage, error: errorMessage,
errorStack: getErrorStack(error), errorStack: getErrorStack(error),
}; };
TelemetryProcessor.traceFailure(Action.CreateDatabase, addDatabasePaneFailedMessage, startKey); TelemetryProcessor.traceFailure(Action.CreateDatabase, addDatabasePaneFailedMessage, startKey);
}; };
const _isValid = (): boolean => {
// TODO add feature flag that disables validation for customers with custom accounts
if (isAutoscaleSelected) {
if (!AutoPilotUtils.isValidAutoPilotThroughput(throughput)) {
setFormErrors(t(Keys.panes.addDatabase.greaterThanError, { minValue: AutoPilotUtils.autoPilotThroughput1K }));
return false;
}
}
if (throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && !isCostAcknowledged) {
setFormErrors(
isAutoscaleSelected
? t(Keys.panes.addDatabase.acknowledgeSpendErrorMonthly)
: t(Keys.panes.addDatabase.acknowledgeSpendErrorDaily),
);
return false;
}
return true;
};
const handleonChangeDBId = React.useCallback( const handleonChangeDBId = React.useCallback(
(event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => { (event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {
setDatabaseId(newValue || ""); setDatabaseId(newValue || "");
@@ -176,7 +125,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
formError: formErrors, formError: formErrors,
isExecuting, isExecuting,
submitButtonText: t(Keys.common.ok), submitButtonText: t(Keys.common.ok),
isSubmitButtonDisabled: isThroughputCapExceeded,
onSubmit, onSubmit,
}; };
@@ -224,42 +172,7 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
data-lpignore={true} data-lpignore={true}
data-1p-ignore={true} data-1p-ignore={true}
/> />
{!isServerlessAccount() && (
<Stack horizontal>
<Checkbox
title={t(Keys.panes.addDatabase.provisionSharedThroughputTitle)}
styles={{
text: { fontSize: 12, color: "var(--colorNeutralForeground1)" },
checkbox: { width: 12, height: 12 },
label: { padding: 0, alignItems: "center" },
root: {
selectors: {
":hover .ms-Checkbox-text": { color: "var(--colorNeutralForeground1)" },
},
},
}}
label={t(Keys.panes.addDatabase.provisionThroughputLabel)}
checked={databaseCreateNewShared}
onChange={() => setDatabaseCreateNewShared(!databaseCreateNewShared)}
/>
<InfoTooltip>{databaseLevelThroughputTooltipText}</InfoTooltip>
</Stack> </Stack>
)}
</Stack>
{!isServerlessAccount() && databaseCreateNewShared && (
<ThroughputInput
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
isDatabase={true}
isSharded={databaseCreateNewShared}
isFreeTier={isFreeTierAccount}
setThroughputValue={(newThroughput: number) => (throughput = newThroughput)}
setIsAutoscale={(isAutoscale: boolean) => (isAutoscaleSelected = isAutoscale)}
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
onCostAcknowledgeChange={(isAcknowledged: boolean) => (isCostAcknowledged = isAcknowledged)}
/>
)}
</div> </div>
</RightPaneForm> </RightPaneForm>
); );

View File

@@ -4,7 +4,6 @@ exports[`AddDatabasePane Pane should render Default properly 1`] = `
<RightPaneForm <RightPaneForm
formError="" formError=""
isExecuting={false} isExecuting={false}
isSubmitButtonDisabled={false}
onSubmit={[Function]} onSubmit={[Function]}
submitButtonText="OK" submitButtonText="OK"
> >
@@ -61,42 +60,6 @@ exports[`AddDatabasePane Pane should render Default properly 1`] = `
type="text" type="text"
value="" value=""
/> />
<Stack
horizontal={true}
>
<StyledCheckboxBase
checked={false}
label="Provision throughput"
onChange={[Function]}
styles={
{
"checkbox": {
"height": 12,
"width": 12,
},
"label": {
"alignItems": "center",
"padding": 0,
},
"root": {
"selectors": {
":hover .ms-Checkbox-text": {
"color": "var(--colorNeutralForeground1)",
},
},
},
"text": {
"color": "var(--colorNeutralForeground1)",
"fontSize": 12,
},
}
}
title="Provision shared throughput"
/>
<InfoTooltip>
Provisioned throughput at the database level will be shared across all collections within the database.
</InfoTooltip>
</Stack>
</Stack> </Stack>
</div> </div>
</RightPaneForm> </RightPaneForm>

View File

@@ -15,7 +15,7 @@ describe("Cassandra add collection pane test", () => {
it("should render default properly", () => { it("should render default properly", () => {
expect(screen.getByRole("radio", { name: "Create new keyspace", checked: true })).toBeDefined(); expect(screen.getByRole("radio", { name: "Create new keyspace", checked: true })).toBeDefined();
expect(screen.getByRole("checkbox", { name: "Provision shared throughput", checked: false })).toBeDefined(); expect(screen.queryByRole("checkbox", { name: "Provision shared throughput" })).toBeNull();
}); });
it("click on use existing", () => { it("click on use existing", () => {

View File

@@ -1,4 +1,4 @@
import { Checkbox, Dropdown, IDropdownOption, Link, Stack, Text, TextField } from "@fluentui/react"; import { Dropdown, IDropdownOption, Link, Stack, Text, TextField } from "@fluentui/react";
import * as Constants from "Common/Constants"; import * as Constants from "Common/Constants";
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils"; import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
import { InfoTooltip } from "Common/Tooltip/InfoTooltip"; import { InfoTooltip } from "Common/Tooltip/InfoTooltip";
@@ -27,8 +27,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
explorer: container, explorer: container,
cassandraApiClient, cassandraApiClient,
}: CassandraAddCollectionPaneProps) => { }: CassandraAddCollectionPaneProps) => {
let newKeySpaceThroughput: number;
let isNewKeySpaceAutoscale: boolean;
let tableThroughput: number; let tableThroughput: number;
let isTableAutoscale: boolean; let isTableAutoscale: boolean;
let isCostAcknowledged: boolean; let isCostAcknowledged: boolean;
@@ -52,7 +50,7 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
collection: { collection: {
id: tableId, id: tableId,
storage: Constants.BackendDefaults.multiPartitionStorageInGb, storage: Constants.BackendDefaults.multiPartitionStorageInGb,
offerThroughput: newKeySpaceThroughput || tableThroughput, offerThroughput: tableThroughput,
partitionKey: "", partitionKey: "",
databaseId: keyspaceCreateNew ? newKeyspaceId : existingKeyspaceId, databaseId: keyspaceCreateNew ? newKeyspaceId : existingKeyspaceId,
}, },
@@ -60,18 +58,17 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
subscriptionQuotaId: userContext.quotaId, subscriptionQuotaId: userContext.quotaId,
defaultsCheck: { defaultsCheck: {
storage: "u", storage: "u",
throughput: newKeySpaceThroughput || tableThroughput, throughput: tableThroughput,
}, },
dataExplorerArea: Constants.Areas.ContextualPane, dataExplorerArea: Constants.Areas.ContextualPane,
}; };
const onSubmit = async () => { const onSubmit = async () => {
const throughput = keyspaceCreateNew ? newKeySpaceThroughput : tableThroughput; const throughput = tableThroughput;
const keyspaceId = keyspaceCreateNew ? newKeyspaceId : existingKeyspaceId; const keyspaceId = keyspaceCreateNew ? newKeyspaceId : existingKeyspaceId;
if (throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && !isCostAcknowledged) { if (throughput > SharedConstants.CollectionCreation.DefaultCollectionRUs100K && !isCostAcknowledged) {
const errorMessage = const errorMessage = isTableAutoscale
isNewKeySpaceAutoscale || isTableAutoscale
? t(Keys.panes.addCollection.acknowledgeSpendErrorMonthly) ? t(Keys.panes.addCollection.acknowledgeSpendErrorMonthly)
: t(Keys.panes.addCollection.acknowledgeSpendErrorDaily); : t(Keys.panes.addCollection.acknowledgeSpendErrorDaily);
setFormError(errorMessage); setFormError(errorMessage);
@@ -79,14 +76,10 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
} }
setIsExecuting(true); setIsExecuting(true);
const autoPilotCommand = `cosmosdb_autoscale_max_throughput`;
const createKeyspaceQueryPrefix = `CREATE KEYSPACE ${keyspaceId.trim()} WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 3 }`; const createKeyspaceQueryPrefix = `CREATE KEYSPACE ${keyspaceId.trim()} WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 3 }`;
const createKeyspaceQuery: string = isKeyspaceShared const createKeyspaceQuery = `${createKeyspaceQueryPrefix};`;
? isNewKeySpaceAutoscale
? `${createKeyspaceQueryPrefix} AND ${autoPilotCommand}=${newKeySpaceThroughput};`
: `${createKeyspaceQueryPrefix} AND cosmosdb_provisioned_throughput=${newKeySpaceThroughput};`
: `${createKeyspaceQueryPrefix};`;
let tableQuery: string; let tableQuery: string;
const autoPilotCommand = `cosmosdb_autoscale_max_throughput`;
const createTableQueryPrefix = `CREATE TABLE ${keyspaceId}.${tableId.trim()} ${userTableQuery}`; const createTableQueryPrefix = `CREATE TABLE ${keyspaceId}.${tableId.trim()} ${userTableQuery}`;
if (tableThroughput) { if (tableThroughput) {
@@ -177,7 +170,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
tabIndex={0} tabIndex={0}
onChange={() => { onChange={() => {
setKeyspaceCreateNew(true); setKeyspaceCreateNew(true);
setIsKeyspaceShared(false);
setExistingKeyspaceId(""); setExistingKeyspaceId("");
}} }}
/> />
@@ -192,7 +184,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
tabIndex={0} tabIndex={0}
onChange={() => { onChange={() => {
setKeyspaceCreateNew(false); setKeyspaceCreateNew(false);
setIsKeyspaceShared(false);
}} }}
/> />
<span className="panelRadioBtnLabel">{t(Keys.panes.addCollection.useExisting)}</span> <span className="panelRadioBtnLabel">{t(Keys.panes.addCollection.useExisting)}</span>
@@ -214,25 +205,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
ariaLabel="Keyspace id" ariaLabel="Keyspace id"
autoFocus autoFocus
/> />
{!isServerlessAccount() && (
<Stack horizontal>
<Checkbox
label="Provision shared throughput"
checked={isKeyspaceShared}
styles={{
text: { fontSize: 12 },
checkbox: { width: 12, height: 12 },
label: { padding: 0, alignItems: "center" },
}}
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) => setIsKeyspaceShared(isChecked)}
/>
<InfoTooltip>
Provisioned throughput at the keyspace level will be shared across unlimited number of tables within
the keyspace
</InfoTooltip>
</Stack>
)}
</Stack> </Stack>
)} )}
@@ -256,21 +228,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
responsiveMode={999} responsiveMode={999}
/> />
)} )}
{!isServerlessAccount() && keyspaceCreateNew && isKeyspaceShared && (
<ThroughputInput
showFreeTierExceedThroughputTooltip={
isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()
}
isDatabase
isSharded
isFreeTier={isFreeTierAccount}
setThroughputValue={(throughput: number) => (newKeySpaceThroughput = throughput)}
setIsAutoscale={(isAutoscale: boolean) => (isNewKeySpaceAutoscale = isAutoscale)}
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
onCostAcknowledgeChange={(isAcknowledged: boolean) => (isCostAcknowledged = isAcknowledged)}
/>
)}
</Stack> </Stack>
<Stack> <Stack>
@@ -328,7 +285,7 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
<InfoTooltip>{t(Keys.panes.cassandraAddCollection.provisionDedicatedThroughputTooltip)}</InfoTooltip> <InfoTooltip>{t(Keys.panes.cassandraAddCollection.provisionDedicatedThroughputTooltip)}</InfoTooltip>
</Stack> </Stack>
)} )}
{!isServerlessAccount() && (!isKeyspaceShared || dedicateTableThroughput) && ( {!isServerlessAccount() && (keyspaceCreateNew || !isKeyspaceShared || dedicateTableThroughput) && (
<ThroughputInput <ThroughputInput
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()} showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
isDatabase={false} isDatabase={false}

View File

@@ -438,21 +438,15 @@
"keyspaceIdLabel": "Keyspace id", "keyspaceIdLabel": "Keyspace id",
"databaseIdPlaceholder": "Type a new {{databaseLabel}} id", "databaseIdPlaceholder": "Type a new {{databaseLabel}} id",
"databaseTooltip": "A {{databaseLabel}} is a logical container of one or more {{collectionsLabel}}", "databaseTooltip": "A {{databaseLabel}} is a logical container of one or more {{collectionsLabel}}",
"shareThroughput": "Share throughput across {{collectionsLabel}}",
"shareThroughputTooltip": "Provisioned throughput at the {{databaseLabel}} level will be shared across all {{collectionsLabel}} within the {{databaseLabel}}.",
"greaterThanError": "Please enter a value greater than {{minValue}} for autopilot throughput", "greaterThanError": "Please enter a value greater than {{minValue}} for autopilot throughput",
"acknowledgeSpendError": "Please acknowledge the estimated {{period}} spend.", "acknowledgeSpendError": "Please acknowledge the estimated {{period}} spend.",
"acknowledgeSpendErrorMonthly": "Please acknowledge the estimated monthly spend.", "acknowledgeSpendErrorMonthly": "Please acknowledge the estimated monthly spend.",
"acknowledgeSpendErrorDaily": "Please acknowledge the estimated daily spend.", "acknowledgeSpendErrorDaily": "Please acknowledge the estimated daily spend."
"provisionSharedThroughputTitle": "Provision shared throughput",
"provisionThroughputLabel": "Provision throughput"
}, },
"addCollection": { "addCollection": {
"createNew": "Create new", "createNew": "Create new",
"useExisting": "Use existing", "useExisting": "Use existing",
"databaseTooltip": "A database is analogous to a namespace. It is the unit of management for a set of {{collectionName}}.", "databaseTooltip": "A database is analogous to a namespace. It is the unit of management for a set of {{collectionName}}.",
"shareThroughput": "Share throughput across {{collectionName}}",
"shareThroughputTooltip": "Throughput configured at the database level will be shared across all {{collectionName}} within the database.",
"collectionIdLabel": "{{collectionName}} id", "collectionIdLabel": "{{collectionName}} id",
"collectionIdTooltip": "Unique identifier for the {{collectionName}} and used for id-based routing through REST and all SDKs.", "collectionIdTooltip": "Unique identifier for the {{collectionName}} and used for id-based routing through REST and all SDKs.",
"collectionIdPlaceholder": "e.g., {{collectionName}}1", "collectionIdPlaceholder": "e.g., {{collectionName}}1",