import { DetailsRow, ICheckboxStyles, IChoiceGroupStyles, IDetailsColumnStyles, IDetailsListStyles, IDetailsRowProps, IDetailsRowStyles, IDropdownStyles, IMessageBarStyles, ISeparatorStyles, IStackProps, IStackStyles, IStackTokens, ITextFieldStyles, ITextStyles, Link, MessageBar, MessageBarType, Spinner, SpinnerSize, Stack, Text, } from "@fluentui/react"; import * as React from "react"; import { Urls } from "../../../Common/Constants"; import { StyleConstants } from "../../../Common/StyleConstants"; import { hoursInAMonth } from "../../../Shared/Constants"; import { computeRUUsagePriceHourly, estimatedCostDisclaimer, getAutoscalePricePerRu, getCurrencySign, getMultimasterMultiplier, getPriceCurrency, getPricePerRu, } from "../../../Utils/PricingUtils"; import { isDirty, isDirtyTypes } from "./SettingsUtils"; export interface EstimatedSpendingDisplayProps { costType: JSX.Element; } export interface ManualEstimatedSpendingDisplayProps extends EstimatedSpendingDisplayProps { hourly: JSX.Element; daily: JSX.Element; monthly: JSX.Element; } export interface AutoscaleEstimatedSpendingDisplayProps extends EstimatedSpendingDisplayProps { minPerMonth: JSX.Element; maxPerMonth: JSX.Element; } export interface PriceBreakdown { hourlyPrice: number; dailyPrice: number; monthlyPrice: number; pricePerRu: number; currency: string; currencySign: string; } export const infoAndToolTipTextStyle: ITextStyles = { root: { fontSize: 14, color: "windowtext" } }; export const noLeftPaddingCheckBoxStyle: ICheckboxStyles = { label: { margin: 0, padding: "2 0 2 0", }, text: { fontSize: 12, }, }; export const subComponentStackProps: Partial = { tokens: { childrenGap: 20 }, }; export const titleAndInputStackProps: Partial = { tokens: { childrenGap: 5 }, }; export const mongoWarningStackProps: Partial = { tokens: { childrenGap: 5 }, }; export const mongoErrorMessageStyles: Partial = { root: { marginLeft: 10 } }; export const createAndAddMongoIndexStackProps: Partial = { tokens: { childrenGap: 5 }, }; export const addMongoIndexStackProps: Partial = { tokens: { childrenGap: 10 }, }; export const checkBoxAndInputStackProps: Partial = { tokens: { childrenGap: 10 }, }; export const relaxedSpacingStackProps: Partial = { tokens: { childrenGap: 20 }, }; export const toolTipLabelStackTokens: IStackTokens = { childrenGap: 6, }; export const accordionStackTokens: IStackTokens = { childrenGap: 10, }; export const addMongoIndexSubElementsTokens: IStackTokens = { childrenGap: 20, }; export const mediumWidthStackStyles: IStackStyles = { root: { width: 600 } }; export const shortWidthTextFieldStyles: Partial = { root: { paddingLeft: 10, width: 210 } }; export const shortWidthDropDownStyles: Partial = { dropdown: { paddingleft: 10, width: 202 } }; export const transparentDetailsRowStyles: Partial = { root: { selectors: { ":hover": { background: "transparent", }, }, }, }; export const transparentDetailsHeaderStyle: Partial = { root: { selectors: { ":hover": { background: "transparent", }, }, }, }; export const customDetailsListStyles: Partial = { root: { selectors: { ".ms-FocusZone": { paddingTop: 0, }, }, }, }; export const separatorStyles: Partial = { root: [ { selectors: { "::before": { background: StyleConstants.BaseMedium, }, }, }, ], }; export const messageBarStyles: Partial = { root: { marginTop: "5px", backgroundColor: "white" }, text: { fontSize: 14 }, }; export const throughputUnit = "RU/s"; export function onRenderRow(props: IDetailsRowProps): JSX.Element { return ; } export const getRuPriceBreakdown = ( throughput: number, serverId: string, numberOfRegions: number, isMultimaster: boolean, isAutoscale: boolean, ): PriceBreakdown => { const hourlyPrice: number = computeRUUsagePriceHourly({ serverId: serverId, requestUnits: throughput, numberOfRegions: numberOfRegions, multimasterEnabled: isMultimaster, isAutoscale: isAutoscale, }); const multimasterMultiplier = getMultimasterMultiplier(numberOfRegions, isMultimaster); const pricePerRu: number = isAutoscale ? getAutoscalePricePerRu(serverId, multimasterMultiplier) : getPricePerRu(serverId, multimasterMultiplier); return { hourlyPrice, dailyPrice: hourlyPrice * 24, monthlyPrice: hourlyPrice * hoursInAMonth, pricePerRu, currency: getPriceCurrency(serverId), currencySign: getCurrencySign(serverId), }; }; export const getEstimatedSpendingElement = ( costElement: JSX.Element, throughput: number, numberOfRegions: number, priceBreakdown: PriceBreakdown, isAutoscale: boolean, ): JSX.Element => { const ruRange: string = isAutoscale ? throughput / 10 + " RU/s - " : ""; return ( Cost estimate* {costElement} How we calculate this {numberOfRegions} region{numberOfRegions > 1 && s} {ruRange} {throughput} RU/s {priceBreakdown.currencySign} {priceBreakdown.pricePerRu}/RU *{estimatedCostDisclaimer} ); }; export const manualToAutoscaleDisclaimerElement: JSX.Element = ( The starting autoscale max RU/s will be determined by the system, based on the current manual throughput settings and storage of your resource. After autoscale has been enabled, you can change the max RU/s.{" "} Learn more ); export const ttlWarning: JSX.Element = ( The system will automatically delete items based on the TTL value (in seconds) you provide, without needing a delete operation explicitly issued by a client application. For more information see,{" "} Time to Live (TTL) in Azure Cosmos DB . ); export const indexingPolicynUnsavedWarningMessage: JSX.Element = ( You have not saved the latest changes made to your indexing policy. Please click save to confirm the changes. ); export const updateThroughputDelayedApplyWarningMessage: JSX.Element = ( You are about to request an increase in throughput beyond the pre-allocated capacity. This operation will take some time to complete. ); export const getUpdateThroughputBeyondInstantLimitMessage = (instantMaximumThroughput: number): JSX.Element => { return ( Scaling up will take 4-6 hours as it exceeds what Azure Cosmos DB can instantly support currently based on your number of physical partitions. You can increase your throughput to {instantMaximumThroughput} instantly or proceed with this value and wait until the scale-up is completed. ); }; export const getUpdateThroughputBeyondSupportLimitMessage = ( instantMaximumThroughput: number, maximumThroughput: number, ): JSX.Element => { return ( <> Your request to increase throughput exceeds the pre-allocated capacity which may take longer than expected. There are three options you can choose from to proceed:
  1. You can instantly scale up to {instantMaximumThroughput} RU/s.
  2. {instantMaximumThroughput < maximumThroughput && (
  3. You can asynchronously scale up to any value under {maximumThroughput} RU/s in 4-6 hours.
  4. )}
  5. Your current quota max is {maximumThroughput} RU/s. To go over this limit, you must request a quota increase and the Azure Cosmos DB team will review. Learn more
); }; export const getUpdateThroughputBelowMinimumMessage = (minimum: number): JSX.Element => { return ( You are not able to lower throughput below your current minimum of {minimum} RU/s. For more information on this limit, please refer to our service quote documentation. Learn more ); }; export const saveThroughputWarningMessage: JSX.Element = ( Your bill will be affected as you update your throughput settings. Please review the updated cost estimate below before saving your changes ); const getCurrentThroughput = ( isAutoscale: boolean, throughput: number, throughputUnit: string, targetThroughput?: number, ): string => { if (targetThroughput) { if (throughput) { return isAutoscale ? `, Current autoscale throughput: ${Math.round( throughput / 10, )} - ${throughput} ${throughputUnit}, Target autoscale throughput: ${Math.round( targetThroughput / 10, )} - ${targetThroughput} ${throughputUnit}` : `, Current manual throughput: ${throughput} ${throughputUnit}, Target manual throughput: ${targetThroughput}`; } else { return isAutoscale ? `, Target autoscale throughput: ${Math.round(targetThroughput / 10)} - ${targetThroughput} ${throughputUnit}` : `, Target manual throughput: ${targetThroughput} ${throughputUnit}`; } } if (!targetThroughput && throughput) { return isAutoscale ? `, Current autoscale throughput: ${Math.round(throughput / 10)} - ${throughput} ${throughputUnit}` : `, Current manual throughput: ${throughput} ${throughputUnit}`; } return ""; }; export const getThroughputApplyDelayedMessage = ( isAutoscale: boolean, throughput: number, throughputUnit: string, databaseName: string, collectionName: string, requestedThroughput: number, ): JSX.Element => ( The request to increase the throughput has successfully been submitted. This operation will take 1-3 business days to complete. View the latest status in Notifications.
Database: {databaseName}, Container: {collectionName}{" "} {getCurrentThroughput(isAutoscale, throughput, throughputUnit, requestedThroughput)}
); export const getThroughputApplyShortDelayMessage = ( isAutoscale: boolean, throughput: number, throughputUnit: string, databaseName: string, collectionName: string, ): JSX.Element => ( A request to increase the throughput is currently in progress. This operation will take some time to complete.
{collectionName ? `Database: ${databaseName}, Container: ${collectionName} ` : `Database: ${databaseName} `} {getCurrentThroughput(isAutoscale, throughput, throughputUnit)}
); export const getThroughputApplyLongDelayMessage = ( isAutoscale: boolean, throughput: number, throughputUnit: string, databaseName: string, collectionName: string, requestedThroughput: number, ): JSX.Element => ( A request to increase the throughput is currently in progress. This operation will take 1-3 business days to complete. View the latest status in Notifications.
{collectionName ? `Database: ${databaseName}, Container: ${collectionName} ` : `Database: ${databaseName} `} {getCurrentThroughput(isAutoscale, throughput, throughputUnit, requestedThroughput)}
); export const getToolTipContainer = (content: string | JSX.Element): JSX.Element => content ? {content} : undefined; export const conflictResolutionLwwTooltip: JSX.Element = ( Gets or sets the name of a integer property in your documents which is used for the Last Write Wins (LWW) based conflict resolution scheme. By default, the system uses the system defined timestamp property, _ts to decide the winner for the conflicting versions of the document. Specify your own integer property if you want to override the default timestamp based conflict resolution. ); export const conflictResolutionCustomToolTip: JSX.Element = ( Gets or sets the name of a stored procedure (aka merge procedure) for resolving the conflicts. You can write application defined logic to determine the winner of the conflicting versions of a document. The stored procedure will get executed transactionally, exactly once, on the server side. If you do not provide a stored procedure, the conflicts will be populated in the {` conflicts feed`} . You can update/re-register the stored procedure at any time. ); export const changeFeedPolicyToolTip: JSX.Element = ( Enable change feed log retention policy to retain last 10 minutes of history for items in the container by default. To support this, the request unit (RU) charge for this container will be multiplied by a factor of two for writes. Reads are unaffected. ); export const mongoIndexingPolicyDisclaimer: JSX.Element = ( For queries that filter on multiple properties, create multiple single field indexes instead of a compound index. {` Compound indexes `} are only used for sorting query results. If you need to add a compound index, you can create one using the Mongo shell. ); export const mongoCompoundIndexNotSupportedMessage: JSX.Element = ( Collections with compound indexes are not yet supported in the indexing editor. To modify indexing policy for this collection, use the Mongo Shell. ); export const mongoIndexingPolicyAADError: JSX.Element = ( To use the indexing policy editor, please login to the {"azure portal."} ); export const mongoIndexTransformationRefreshingMessage: JSX.Element = ( Refreshing index transformation progress ); export const renderMongoIndexTransformationRefreshMessage = ( progress: number, performRefresh: () => void, ): JSX.Element => { if (progress === 0) { return ( {"You can make more indexing changes once the current index transformation is complete. "} {"Refresh to check if it has completed."} ); } else { return ( {`You can make more indexing changes once the current index transformation has completed. It is ${progress}% complete. `} {"Refresh to check the progress."} ); } }; export const getTextFieldStyles = (current: isDirtyTypes, baseline: isDirtyTypes): Partial => ({ fieldGroup: { height: 25, width: 300, borderColor: isDirty(current, baseline) ? StyleConstants.Dirty : "", selectors: { ":disabled": { backgroundColor: StyleConstants.BaseMedium, borderColor: StyleConstants.BaseMediumHigh, }, }, }, }); export const getChoiceGroupStyles = ( current: isDirtyTypes, baseline: isDirtyTypes, isHorizontal?: boolean, ): Partial => ({ flexContainer: [ { selectors: { ".ms-ChoiceField-field.is-checked::before": { borderColor: isDirty(current, baseline) ? StyleConstants.Dirty : "", }, ".ms-ChoiceField-field.is-checked::after": { borderColor: isDirty(current, baseline) ? StyleConstants.Dirty : "", }, ".ms-ChoiceField-wrapper label": { whiteSpace: "nowrap", fontSize: 14, fontFamily: StyleConstants.DataExplorerFont, padding: "2px 5px", }, }, display: isHorizontal ? "inline-flex" : "default", columnGap: isHorizontal ? "30px" : "default", }, ], });