import * as React from "react"; import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils"; import { AutopilotDocumentation, hoursInAMonth } from "../../../Shared/Constants"; import { Urls, StyleConstants } from "../../../Common/Constants"; import { getPriceCurrency, getCurrencySign, getAutoscalePricePerRu, getMultimasterMultiplier, computeRUUsagePriceHourly, getPricePerRu, estimatedCostDisclaimer, } from "../../../Utils/PricingUtils"; import { ITextFieldStyles, ICheckboxStyles, IStackProps, IStackTokens, IChoiceGroupStyles, Link, Text, IMessageBarStyles, ITextStyles, IDetailsRowStyles, IStackStyles, IDetailsListStyles, IDropdownStyles, ISeparatorStyles, MessageBar, MessageBarType, Stack, Spinner, SpinnerSize, DetailsList, IColumn, SelectionMode, DetailsListLayoutMode, IDetailsRowProps, DetailsRow, IDetailsColumnStyles, } from "office-ui-fabric-react"; import { isDirtyTypes, isDirty } 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 } }; 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 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 getAutoPilotV3SpendElement = ( maxAutoPilotThroughputSet: number, isDatabaseThroughput: boolean, requestUnitsUsageCostElement?: JSX.Element ): JSX.Element => { if (!maxAutoPilotThroughputSet) { return <>; } const resource: string = isDatabaseThroughput ? "database" : "container"; return ( <> Your {resource} throughput will automatically scale from{" "} {AutoPilotUtils.getMinRUsBasedOnUserInput(maxAutoPilotThroughputSet)} RU/s (10% of max RU/s) -{" "} {maxAutoPilotThroughputSet} RU/s {" "} based on usage.
{requestUnitsUsageCostElement} After the first {AutoPilotUtils.getStorageBasedOnUserInput(maxAutoPilotThroughputSet)} GB of data stored, the max RU/s will be automatically upgraded based on the new storage value. {" "} Learn more . ); }; 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 basePricePerRu: number = isAutoscale ? getAutoscalePricePerRu(serverId, getMultimasterMultiplier(numberOfRegions, isMultimaster)) : getPricePerRu(serverId); return { hourlyPrice: hourlyPrice, dailyPrice: hourlyPrice * 24, monthlyPrice: hourlyPrice * hoursInAMonth, pricePerRu: basePricePerRu * getMultimasterMultiplier(numberOfRegions, isMultimaster), currency: getPriceCurrency(serverId), currencySign: getCurrencySign(serverId), }; }; export const getEstimatedSpendingElement = ( estimatedSpendingColumns: IColumn[], estimatedSpendingItems: EstimatedSpendingDisplayProps[], throughput: number, numberOfRegions: number, priceBreakdown: PriceBreakdown, isAutoscale: boolean ): JSX.Element => { const ruRange: string = isAutoscale ? throughput / 10 + " RU/s - " : ""; return ( ({"regions: "} {numberOfRegions}, {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 updateThroughputBeyondLimitWarningMessage: JSX.Element = ( You are about to request an increase in throughput beyond the pre-allocated capacity. The service will scale out and increase throughput for the selected container. This operation will take 1-3 business days to complete. You can track the status of this request in Notifications. ); 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 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): 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", }, }, }, ], });