diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index e40977ded..124030cbd 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -99,6 +99,7 @@ export class Flights { public static readonly PhoenixNotebooks = "phoenixnotebooks"; public static readonly PhoenixFeatures = "phoenixfeatures"; public static readonly NotebooksDownBanner = "notebooksdownbanner"; + public static readonly FreeTierAutoscaleThroughput = "freetierautoscalethroughput"; } export class AfecFeatures { diff --git a/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputInputAutoPilotV3Component.tsx b/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputInputAutoPilotV3Component.tsx index c958b5a6a..d64387aeb 100644 --- a/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputInputAutoPilotV3Component.tsx +++ b/src/Explorer/Controls/Settings/SettingsSubComponents/ThroughputInputComponents/ThroughputInputAutoPilotV3Component.tsx @@ -19,7 +19,7 @@ import { Action, ActionModifiers } from "../../../../../Shared/Telemetry/Telemet import * as TelemetryProcessor from "../../../../../Shared/Telemetry/TelemetryProcessor"; import { userContext } from "../../../../../UserContext"; import * as AutoPilotUtils from "../../../../../Utils/AutoPilotUtils"; -import { minAutoPilotThroughput } from "../../../../../Utils/AutoPilotUtils"; +import { autoPilotThroughput1K, autoPilotThroughput4K } from "../../../../../Utils/AutoPilotUtils"; import { calculateEstimateNumber, usageInGB } from "../../../../../Utils/PricingUtils"; import { Int32 } from "../../../../Panes/Tables/Validators/EntityPropertyValidationCommon"; import { @@ -540,7 +540,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component< step={AutoPilotUtils.autoPilotIncrementStep} value={this.overrideWithProvisionedThroughputSettings() ? "" : this.props.maxAutoPilotThroughput?.toString()} onChange={this.onAutoPilotThroughputChange} - min={minAutoPilotThroughput} + min={userContext.features.freetierAutoscaleThroughput ? autoPilotThroughput1K : autoPilotThroughput4K} errorMessage={this.props.throughputError} /> {!this.overrideWithProvisionedThroughputSettings() && this.getAutoPilotUsageCost()} diff --git a/src/Explorer/Controls/ThroughputInput/ThroughputInput.test.tsx b/src/Explorer/Controls/ThroughputInput/ThroughputInput.test.tsx index 9d1733da0..ef3281801 100644 --- a/src/Explorer/Controls/ThroughputInput/ThroughputInput.test.tsx +++ b/src/Explorer/Controls/ThroughputInput/ThroughputInput.test.tsx @@ -5,6 +5,7 @@ const props = { isDatabase: false, showFreeTierExceedThroughputTooltip: true, isSharded: true, + isFreeTier: false, setThroughputValue: () => jest.fn(), setIsAutoscale: () => jest.fn(), setIsThroughputCapExceeded: () => jest.fn(), diff --git a/src/Explorer/Controls/ThroughputInput/ThroughputInput.tsx b/src/Explorer/Controls/ThroughputInput/ThroughputInput.tsx index ff4d7ed25..c7bb00212 100644 --- a/src/Explorer/Controls/ThroughputInput/ThroughputInput.tsx +++ b/src/Explorer/Controls/ThroughputInput/ThroughputInput.tsx @@ -14,6 +14,7 @@ import "./ThroughputInput.less"; export interface ThroughputInputProps { isDatabase: boolean; isSharded: boolean; + isFreeTier: boolean; showFreeTierExceedThroughputTooltip: boolean; setThroughputValue: (throughput: number) => void; setIsAutoscale: (isAutoscale: boolean) => void; @@ -23,15 +24,20 @@ export interface ThroughputInputProps { export const ThroughputInput: FunctionComponent = ({ isDatabase, + isSharded, + isFreeTier, showFreeTierExceedThroughputTooltip, setThroughputValue, setIsAutoscale, setIsThroughputCapExceeded, - isSharded, onCostAcknowledgeChange, }: ThroughputInputProps) => { const [isAutoscaleSelected, setIsAutoScaleSelected] = useState(true); - const [throughput, setThroughput] = useState(AutoPilotUtils.minAutoPilotThroughput); + const [throughput, setThroughput] = useState( + isFreeTier && userContext.features.freetierAutoscaleThroughput + ? AutoPilotUtils.autoPilotThroughput1K + : AutoPilotUtils.autoPilotThroughput4K + ); const [isCostAcknowledged, setIsCostAcknowledged] = useState(false); const [throughputError, setThroughputError] = useState(""); const [totalThroughputUsed, setTotalThroughputUsed] = useState(0); @@ -151,11 +157,15 @@ export const ThroughputInput: FunctionComponent = ({ const handleOnChangeMode = (event: React.ChangeEvent, mode: string): void => { if (mode === "Autoscale") { - setThroughput(AutoPilotUtils.minAutoPilotThroughput); + const defaultThroughput = + isFreeTier && userContext.features.freetierAutoscaleThroughput + ? AutoPilotUtils.autoPilotThroughput1K + : AutoPilotUtils.autoPilotThroughput4K; + setThroughput(defaultThroughput); setIsAutoScaleSelected(true); - setThroughputValue(AutoPilotUtils.minAutoPilotThroughput); + setThroughputValue(defaultThroughput); setIsAutoscale(true); - checkThroughputCap(AutoPilotUtils.minAutoPilotThroughput); + checkThroughputCap(defaultThroughput); } else { setThroughput(SharedConstants.CollectionCreation.DefaultCollectionRUs400); setIsAutoScaleSelected(false); @@ -226,7 +236,11 @@ export const ThroughputInput: FunctionComponent = ({ }} onChange={(event, newInput?: string) => onThroughputValueChange(newInput)} step={AutoPilotUtils.autoPilotIncrementStep} - min={AutoPilotUtils.minAutoPilotThroughput} + min={ + userContext.features.freetierAutoscaleThroughput + ? AutoPilotUtils.autoPilotThroughput1K + : AutoPilotUtils.autoPilotThroughput4K + } value={throughput.toString()} aria-label="Max request units per second" required={true} diff --git a/src/Explorer/Controls/ThroughputInput/__snapshots__/ThroughputInput.test.tsx.snap b/src/Explorer/Controls/ThroughputInput/__snapshots__/ThroughputInput.test.tsx.snap index d3a8ecf23..0ef66b3d9 100644 --- a/src/Explorer/Controls/ThroughputInput/__snapshots__/ThroughputInput.test.tsx.snap +++ b/src/Explorer/Controls/ThroughputInput/__snapshots__/ThroughputInput.test.tsx.snap @@ -3,6 +3,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = ` (this.newDatabaseThroughput = throughput)} setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)} setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) => @@ -483,6 +484,7 @@ export class AddCollectionPanel extends React.Component (this.collectionThroughput = throughput)} setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)} setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) => diff --git a/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx b/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx index 4b0535175..708358568 100644 --- a/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx +++ b/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx @@ -146,9 +146,10 @@ export const AddDatabasePanel: FunctionComponent = ({ // TODO add feature flag that disables validation for customers with custom accounts if (isAutoscaleSelected) { if (!AutoPilotUtils.isValidAutoPilotThroughput(throughput)) { - setFormErrors( - `Please enter a value greater than ${AutoPilotUtils.minAutoPilotThroughput} for autopilot throughput` - ); + const minAutoPilotThroughput = userContext.features.freetierAutoscaleThroughput + ? AutoPilotUtils.autoPilotThroughput1K + : AutoPilotUtils.autoPilotThroughput4K; + setFormErrors(`Please enter a value greater than ${minAutoPilotThroughput} for autopilot throughput`); return false; } } @@ -241,6 +242,7 @@ export const AddDatabasePanel: FunctionComponent = ({ 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)} diff --git a/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.tsx b/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.tsx index c2b310500..7f269d214 100644 --- a/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.tsx +++ b/src/Explorer/Panes/CassandraAddCollectionPane/CassandraAddCollectionPane.tsx @@ -262,6 +262,7 @@ export const CassandraAddCollectionPane: FunctionComponent (newKeySpaceThroughput = throughput)} setIsAutoscale={(isAutoscale: boolean) => (isNewKeySpaceAutoscale = isAutoscale)} setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)} @@ -335,6 +336,7 @@ export const CassandraAddCollectionPane: FunctionComponent (tableThroughput = throughput)} setIsAutoscale={(isAutoscale: boolean) => (isTableAutoscale = isAutoscale)} setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)} diff --git a/src/Platform/Hosted/extractFeatures.ts b/src/Platform/Hosted/extractFeatures.ts index 4b498c03b..bbd8bac78 100644 --- a/src/Platform/Hosted/extractFeatures.ts +++ b/src/Platform/Hosted/extractFeatures.ts @@ -1,4 +1,5 @@ export type Features = { + // set only via feature flags readonly canExceedMaximumValue: boolean; readonly cosmosdb: boolean; readonly enableChangeFeedPolicy: boolean; @@ -8,12 +9,6 @@ export type Features = { readonly enableReactPane: boolean; readonly enableRightPanelV2: boolean; readonly enableSchema: boolean; - autoscaleDefault: boolean; - partitionKeyDefault: boolean; - partitionKeyDefault2: boolean; - phoenixNotebooks: boolean; - phoenixFeatures: boolean; - notebooksDownBanner: boolean; readonly enableSDKoperations: boolean; readonly enableSpark: boolean; readonly enableTtl: boolean; @@ -34,11 +29,22 @@ export type Features = { readonly mongoProxyEndpoint?: string; readonly mongoProxyAPIs?: string; readonly enableThroughputCap: boolean; + + // can be set via both flight and feature flag + autoscaleDefault: boolean; + partitionKeyDefault: boolean; + partitionKeyDefault2: boolean; + phoenixNotebooks: boolean; + phoenixFeatures: boolean; + notebooksDownBanner: boolean; + freetierAutoscaleThroughput: boolean; }; export function extractFeatures(given = new URLSearchParams(window.location.search)): Features { const downcased = new URLSearchParams(); - const set = (value: string, key: string) => downcased.set(key.toLowerCase(), value); + const set = (value: string, key: string) => { + downcased.set(key.toLowerCase(), value); + }; const get = (key: string, defaultValue?: string) => downcased.get("feature." + key) ?? downcased.get(key) ?? defaultValue; @@ -86,6 +92,7 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear phoenixFeatures: "true" === get("phoenixfeatures"), notebooksDownBanner: "true" === get("notebooksDownBanner"), enableThroughputCap: "true" === get("enablethroughputcap"), + freetierAutoscaleThroughput: "true" === get("freetierautoscalethroughput"), }; } diff --git a/src/Utils/AutoPilotUtils.ts b/src/Utils/AutoPilotUtils.ts index 4566cab82..05bca7978 100644 --- a/src/Utils/AutoPilotUtils.ts +++ b/src/Utils/AutoPilotUtils.ts @@ -1,11 +1,16 @@ -export const minAutoPilotThroughput = 4000; +import { userContext } from "UserContext"; +export const autoPilotThroughput1K = 1000; export const autoPilotIncrementStep = 1000; +export const autoPilotThroughput4K = 4000; export function isValidAutoPilotThroughput(maxThroughput: number): boolean { if (!maxThroughput) { return false; } + const minAutoPilotThroughput = userContext.features.freetierAutoscaleThroughput + ? autoPilotThroughput4K + : autoPilotThroughput1K; if (maxThroughput < minAutoPilotThroughput) { return false; } diff --git a/src/hooks/useKnockoutExplorer.ts b/src/hooks/useKnockoutExplorer.ts index 245fc1fdb..de1bde524 100644 --- a/src/hooks/useKnockoutExplorer.ts +++ b/src/hooks/useKnockoutExplorer.ts @@ -373,6 +373,9 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) { if (inputs.flights.indexOf(Flights.NotebooksDownBanner) !== -1) { userContext.features.notebooksDownBanner = true; } + if (inputs.flights.indexOf(Flights.FreeTierAutoscaleThroughput) !== -1) { + userContext.features.freetierAutoscaleThroughput = true; + } } }