mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-28 21:32:05 +00:00
Compare commits
9 Commits
esbuild
...
e2e-test-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4be1389705 | ||
|
|
65844414dd | ||
|
|
b9461de695 | ||
|
|
0473c49cc6 | ||
|
|
53ea8dc528 | ||
|
|
8b7d43823a | ||
|
|
3ab7e93bab | ||
|
|
9e2efa01e5 | ||
|
|
ba5ab37bac |
29
.github/workflows/ci.yml
vendored
29
.github/workflows/ci.yml
vendored
@@ -167,7 +167,7 @@ jobs:
|
|||||||
nuget:
|
nuget:
|
||||||
name: Publish Nuget
|
name: Publish Nuget
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
||||||
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted, accessibility]
|
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
||||||
@@ -191,7 +191,7 @@ jobs:
|
|||||||
nugetmpac:
|
nugetmpac:
|
||||||
name: Publish Nuget MPAC
|
name: Publish Nuget MPAC
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
||||||
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted, accessibility]
|
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
||||||
@@ -213,28 +213,3 @@ jobs:
|
|||||||
name: packages
|
name: packages
|
||||||
with:
|
with:
|
||||||
path: "*.nupkg"
|
path: "*.nupkg"
|
||||||
nugetie:
|
|
||||||
name: Publish Nuget IE
|
|
||||||
if: github.ref == 'refs/heads/master' || contains(github.ref, 'hotfix/') || contains(github.ref, 'release/')
|
|
||||||
needs: [lint, format, compile, build, unittest, endtoendemulator, endtoendhosted, accessibility]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
NUGET_SOURCE: ${{ secrets.NUGET_SOURCE }}
|
|
||||||
AZURE_DEVOPS_PAT: ${{ secrets.AZURE_DEVOPS_PAT }}
|
|
||||||
steps:
|
|
||||||
- uses: nuget/setup-nuget@v1
|
|
||||||
with:
|
|
||||||
nuget-api-key: ${{ secrets.NUGET_API_KEY }}
|
|
||||||
- name: Download Dist Folder
|
|
||||||
uses: actions/download-artifact@v2
|
|
||||||
with:
|
|
||||||
name: dist
|
|
||||||
- run: cp ./configs/prod.json config.json
|
|
||||||
- run: sed -i 's/Azure.Cosmos.DB.Data.Explorer/Azure.Cosmos.DB.Data.Explorer.IE/g' DataExplorer.nuspec
|
|
||||||
- run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "GitHub" -Password "$AZURE_DEVOPS_PAT"
|
|
||||||
- run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}"
|
|
||||||
- run: nuget push -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
|
|
||||||
- uses: actions/upload-artifact@v2
|
|
||||||
name: packages
|
|
||||||
with:
|
|
||||||
path: "*.nupkg"
|
|
||||||
|
|||||||
BIN
.vs/slnx.sqlite
BIN
.vs/slnx.sqlite
Binary file not shown.
47
package-lock.json
generated
47
package-lock.json
generated
@@ -9231,53 +9231,6 @@
|
|||||||
"through": "~2.3.6"
|
"through": "~2.3.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"esbuild-loader": {
|
|
||||||
"version": "2.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-2.7.0.tgz",
|
|
||||||
"integrity": "sha512-1v7PVHZ+GvHPlTYVKjNDblUZbzx58Iwt0LJrBI1INzi4/UHz9D3IJ/skNOimaypHDTohj6HtS3ExWJX2xCRzWg==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"esbuild": "^0.8.17",
|
|
||||||
"loader-utils": "^2.0.0",
|
|
||||||
"type-fest": "^0.20.2",
|
|
||||||
"webpack-sources": "^2.2.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"esbuild": {
|
|
||||||
"version": "0.8.26",
|
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.8.26.tgz",
|
|
||||||
"integrity": "sha512-u3MMHOOumdWoAKF+073GHPpzvVB2cM+y9VD4ZwYs1FAQ6atRPISya35dbrbOu/mM68mQ42P+nwPzQVBTfQhkvQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"loader-utils": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"big.js": "^5.2.2",
|
|
||||||
"emojis-list": "^3.0.0",
|
|
||||||
"json5": "^2.1.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type-fest": {
|
|
||||||
"version": "0.20.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
|
|
||||||
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"webpack-sources": {
|
|
||||||
"version": "2.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz",
|
|
||||||
"integrity": "sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"source-list-map": "^2.0.1",
|
|
||||||
"source-map": "^0.6.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"escalade": {
|
"escalade": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@azure/arm-cosmosdb": "9.1.0",
|
"@azure/arm-cosmosdb": "9.1.0",
|
||||||
"@azure/cosmos": "3.9.0",
|
"@azure/cosmos": "3.9.0",
|
||||||
"@azure/cosmos-language-service": "0.0.5",
|
|
||||||
"@azure/identity": "1.1.0",
|
"@azure/identity": "1.1.0",
|
||||||
|
"@azure/cosmos-language-service": "0.0.5",
|
||||||
"@jupyterlab/services": "6.0.0-rc.2",
|
"@jupyterlab/services": "6.0.0-rc.2",
|
||||||
"@jupyterlab/terminal": "3.0.0-rc.2",
|
"@jupyterlab/terminal": "3.0.0-rc.2",
|
||||||
"@microsoft/applicationinsights-web": "2.5.9",
|
"@microsoft/applicationinsights-web": "2.5.9",
|
||||||
@@ -139,7 +139,6 @@
|
|||||||
"enzyme": "3.11.0",
|
"enzyme": "3.11.0",
|
||||||
"enzyme-adapter-react-16": "1.15.5",
|
"enzyme-adapter-react-16": "1.15.5",
|
||||||
"enzyme-to-json": "3.6.1",
|
"enzyme-to-json": "3.6.1",
|
||||||
"esbuild-loader": "2.7.0",
|
|
||||||
"eslint": "7.8.1",
|
"eslint": "7.8.1",
|
||||||
"eslint-cli": "1.1.1",
|
"eslint-cli": "1.1.1",
|
||||||
"eslint-plugin-no-null": "1.0.2",
|
"eslint-plugin-no-null": "1.0.2",
|
||||||
|
|||||||
@@ -362,7 +362,7 @@ export enum CollectionTabKind {
|
|||||||
Gallery = 17,
|
Gallery = 17,
|
||||||
NotebookViewer = 18,
|
NotebookViewer = 18,
|
||||||
Schema = 19,
|
Schema = 19,
|
||||||
SettingsV2 = 20
|
SettingsV2 = 19
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TerminalKind {
|
export enum TerminalKind {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { IColumn, Text } from "office-ui-fabric-react";
|
|
||||||
import {
|
import {
|
||||||
getAutoPilotV3SpendElement,
|
getAutoPilotV3SpendElement,
|
||||||
getEstimatedSpendingElement,
|
getEstimatedSpendElement,
|
||||||
|
getEstimatedAutoscaleSpendElement,
|
||||||
manualToAutoscaleDisclaimerElement,
|
manualToAutoscaleDisclaimerElement,
|
||||||
ttlWarning,
|
ttlWarning,
|
||||||
indexingPolicynUnsavedWarningMessage,
|
indexingPolicynUnsavedWarningMessage,
|
||||||
@@ -19,37 +19,11 @@ import {
|
|||||||
mongoIndexingPolicyDisclaimer,
|
mongoIndexingPolicyDisclaimer,
|
||||||
mongoIndexingPolicyAADError,
|
mongoIndexingPolicyAADError,
|
||||||
mongoIndexTransformationRefreshingMessage,
|
mongoIndexTransformationRefreshingMessage,
|
||||||
renderMongoIndexTransformationRefreshMessage,
|
renderMongoIndexTransformationRefreshMessage
|
||||||
ManualEstimatedSpendingDisplayProps,
|
|
||||||
PriceBreakdown,
|
|
||||||
getRuPriceBreakdown
|
|
||||||
} from "./SettingsRenderUtils";
|
} from "./SettingsRenderUtils";
|
||||||
|
|
||||||
class SettingsRenderUtilsTestComponent extends React.Component {
|
class SettingsRenderUtilsTestComponent extends React.Component {
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const estimatedSpendingColumns: IColumn[] = [
|
|
||||||
{ key: "costType", name: "", fieldName: "costType", minWidth: 100, maxWidth: 200, isResizable: true },
|
|
||||||
{ key: "hourly", name: "Hourly", fieldName: "hourly", minWidth: 100, maxWidth: 200, isResizable: true },
|
|
||||||
{ key: "daily", name: "Daily", fieldName: "daily", minWidth: 100, maxWidth: 200, isResizable: true },
|
|
||||||
{ key: "monthly", name: "Monthly", fieldName: "monthly", minWidth: 100, maxWidth: 200, isResizable: true }
|
|
||||||
];
|
|
||||||
const estimatedSpendingItems: ManualEstimatedSpendingDisplayProps[] = [
|
|
||||||
{
|
|
||||||
costType: <Text>Current Cost</Text>,
|
|
||||||
hourly: <Text>$ 1.02</Text>,
|
|
||||||
daily: <Text>$ 24.48</Text>,
|
|
||||||
monthly: <Text>$ 744.6</Text>
|
|
||||||
}
|
|
||||||
];
|
|
||||||
const priceBreakdown: PriceBreakdown = {
|
|
||||||
hourlyPrice: 1.02,
|
|
||||||
dailyPrice: 24.48,
|
|
||||||
monthlyPrice: 744.6,
|
|
||||||
pricePerRu: 0.00051,
|
|
||||||
currency: "RMB",
|
|
||||||
currencySign: "¥"
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{getAutoPilotV3SpendElement(1000, false)}
|
{getAutoPilotV3SpendElement(1000, false)}
|
||||||
@@ -57,7 +31,9 @@ class SettingsRenderUtilsTestComponent extends React.Component {
|
|||||||
{getAutoPilotV3SpendElement(1000, true)}
|
{getAutoPilotV3SpendElement(1000, true)}
|
||||||
{getAutoPilotV3SpendElement(undefined, true)}
|
{getAutoPilotV3SpendElement(undefined, true)}
|
||||||
|
|
||||||
{getEstimatedSpendingElement(estimatedSpendingColumns, estimatedSpendingItems, 1000, 2, priceBreakdown, false)}
|
{getEstimatedSpendElement(1000, "mooncake", 2, false)}
|
||||||
|
|
||||||
|
{getEstimatedAutoscaleSpendElement(1000, "mooncake", 2, false)}
|
||||||
|
|
||||||
{manualToAutoscaleDisclaimerElement}
|
{manualToAutoscaleDisclaimerElement}
|
||||||
{ttlWarning}
|
{ttlWarning}
|
||||||
@@ -93,14 +69,4 @@ describe("SettingsUtils functions", () => {
|
|||||||
const wrapper = shallow(<SettingsRenderUtilsTestComponent />);
|
const wrapper = shallow(<SettingsRenderUtilsTestComponent />);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return correct price breakdown for a manual RU setting of 500, 1 region, multimaster disabled", () => {
|
|
||||||
const prices = getRuPriceBreakdown(500, "", 1, false, false);
|
|
||||||
expect(prices.hourlyPrice).toBe(0.04);
|
|
||||||
expect(prices.dailyPrice).toBe(0.96);
|
|
||||||
expect(prices.monthlyPrice).toBe(29.2);
|
|
||||||
expect(prices.pricePerRu).toBe(0.00008);
|
|
||||||
expect(prices.currency).toBe("USD");
|
|
||||||
expect(prices.currencySign).toBe("$");
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3,13 +3,14 @@ import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
|
|||||||
import { AutopilotDocumentation, hoursInAMonth } from "../../../Shared/Constants";
|
import { AutopilotDocumentation, hoursInAMonth } from "../../../Shared/Constants";
|
||||||
import { Urls, StyleConstants } from "../../../Common/Constants";
|
import { Urls, StyleConstants } from "../../../Common/Constants";
|
||||||
import {
|
import {
|
||||||
|
computeAutoscaleUsagePriceHourly,
|
||||||
getPriceCurrency,
|
getPriceCurrency,
|
||||||
getCurrencySign,
|
getCurrencySign,
|
||||||
getAutoscalePricePerRu,
|
getAutoscalePricePerRu,
|
||||||
getMultimasterMultiplier,
|
getMultimasterMultiplier,
|
||||||
computeRUUsagePriceHourly,
|
computeRUUsagePriceHourly,
|
||||||
getPricePerRu,
|
getPricePerRu,
|
||||||
estimatedCostDisclaimer
|
calculateEstimateNumber
|
||||||
} from "../../../Utils/PricingUtils";
|
} from "../../../Utils/PricingUtils";
|
||||||
import {
|
import {
|
||||||
ITextFieldStyles,
|
ITextFieldStyles,
|
||||||
@@ -31,41 +32,10 @@ import {
|
|||||||
MessageBarType,
|
MessageBarType,
|
||||||
Stack,
|
Stack,
|
||||||
Spinner,
|
Spinner,
|
||||||
SpinnerSize,
|
SpinnerSize
|
||||||
DetailsList,
|
|
||||||
IColumn,
|
|
||||||
SelectionMode,
|
|
||||||
DetailsListLayoutMode,
|
|
||||||
IDetailsRowProps,
|
|
||||||
DetailsRow,
|
|
||||||
IDetailsColumnStyles
|
|
||||||
} from "office-ui-fabric-react";
|
} from "office-ui-fabric-react";
|
||||||
import { isDirtyTypes, isDirty } from "./SettingsUtils";
|
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: 12 } };
|
export const infoAndToolTipTextStyle: ITextStyles = { root: { fontSize: 12 } };
|
||||||
|
|
||||||
export const noLeftPaddingCheckBoxStyle: ICheckboxStyles = {
|
export const noLeftPaddingCheckBoxStyle: ICheckboxStyles = {
|
||||||
@@ -134,16 +104,6 @@ export const transparentDetailsRowStyles: Partial<IDetailsRowStyles> = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const transparentDetailsHeaderStyle: Partial<IDetailsColumnStyles> = {
|
|
||||||
root: {
|
|
||||||
selectors: {
|
|
||||||
":hover": {
|
|
||||||
background: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const customDetailsListStyles: Partial<IDetailsListStyles> = {
|
export const customDetailsListStyles: Partial<IDetailsListStyles> = {
|
||||||
root: {
|
root: {
|
||||||
selectors: {
|
selectors: {
|
||||||
@@ -170,10 +130,6 @@ export const messageBarStyles: Partial<IMessageBarStyles> = { root: { marginTop:
|
|||||||
|
|
||||||
export const throughputUnit = "RU/s";
|
export const throughputUnit = "RU/s";
|
||||||
|
|
||||||
export function onRenderRow(props: IDetailsRowProps): JSX.Element {
|
|
||||||
return <DetailsRow {...props} styles={transparentDetailsRowStyles} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getAutoPilotV3SpendElement = (
|
export const getAutoPilotV3SpendElement = (
|
||||||
maxAutoPilotThroughputSet: number,
|
maxAutoPilotThroughputSet: number,
|
||||||
isDatabaseThroughput: boolean,
|
isDatabaseThroughput: boolean,
|
||||||
@@ -209,61 +165,63 @@ export const getAutoPilotV3SpendElement = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getRuPriceBreakdown = (
|
export const getEstimatedAutoscaleSpendElement = (
|
||||||
throughput: number,
|
throughput: number,
|
||||||
serverId: string,
|
serverId: string,
|
||||||
numberOfRegions: number,
|
regions: number,
|
||||||
isMultimaster: boolean,
|
multimaster: boolean
|
||||||
isAutoscale: boolean
|
): JSX.Element => {
|
||||||
): PriceBreakdown => {
|
const hourlyPrice: number = computeAutoscaleUsagePriceHourly(serverId, throughput, regions, multimaster);
|
||||||
const hourlyPrice: number = computeRUUsagePriceHourly({
|
const monthlyPrice: number = hourlyPrice * hoursInAMonth;
|
||||||
serverId: serverId,
|
const currency: string = getPriceCurrency(serverId);
|
||||||
requestUnits: throughput,
|
const currencySign: string = getCurrencySign(serverId);
|
||||||
numberOfRegions: numberOfRegions,
|
const pricePerRu =
|
||||||
multimasterEnabled: isMultimaster,
|
getAutoscalePricePerRu(serverId, getMultimasterMultiplier(regions, multimaster)) *
|
||||||
isAutoscale: isAutoscale
|
getMultimasterMultiplier(regions, multimaster);
|
||||||
});
|
|
||||||
const basePricePerRu: number = isAutoscale
|
return (
|
||||||
? getAutoscalePricePerRu(serverId, getMultimasterMultiplier(numberOfRegions, isMultimaster))
|
<Text id="autoscaleSpendElement">
|
||||||
: getPricePerRu(serverId);
|
Estimated monthly cost ({currency}) is{" "}
|
||||||
return {
|
<b>
|
||||||
hourlyPrice: hourlyPrice,
|
{currencySign}
|
||||||
dailyPrice: hourlyPrice * 24,
|
{calculateEstimateNumber(monthlyPrice / 10)}
|
||||||
monthlyPrice: hourlyPrice * hoursInAMonth,
|
{` - `}
|
||||||
pricePerRu: basePricePerRu * getMultimasterMultiplier(numberOfRegions, isMultimaster),
|
{currencySign}
|
||||||
currency: getPriceCurrency(serverId),
|
{calculateEstimateNumber(monthlyPrice)}{" "}
|
||||||
currencySign: getCurrencySign(serverId)
|
</b>
|
||||||
};
|
({"regions: "} {regions}, {throughput / 10} - {throughput} RU/s, {currencySign}
|
||||||
|
{pricePerRu}/RU)
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getEstimatedSpendingElement = (
|
export const getEstimatedSpendElement = (
|
||||||
estimatedSpendingColumns: IColumn[],
|
|
||||||
estimatedSpendingItems: EstimatedSpendingDisplayProps[],
|
|
||||||
throughput: number,
|
throughput: number,
|
||||||
numberOfRegions: number,
|
serverId: string,
|
||||||
priceBreakdown: PriceBreakdown,
|
regions: number,
|
||||||
isAutoscale: boolean
|
multimaster: boolean
|
||||||
): JSX.Element => {
|
): JSX.Element => {
|
||||||
const ruRange: string = isAutoscale ? throughput / 10 + " RU/s - " : "";
|
const hourlyPrice: number = computeRUUsagePriceHourly(serverId, throughput, regions, multimaster);
|
||||||
|
const dailyPrice: number = hourlyPrice * 24;
|
||||||
|
const monthlyPrice: number = hourlyPrice * hoursInAMonth;
|
||||||
|
const currency: string = getPriceCurrency(serverId);
|
||||||
|
const currencySign: string = getCurrencySign(serverId);
|
||||||
|
const pricePerRu = getPricePerRu(serverId) * getMultimasterMultiplier(regions, multimaster);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack {...addMongoIndexStackProps} styles={mediumWidthStackStyles}>
|
<Text id="throughputSpendElement">
|
||||||
<DetailsList
|
Estimated cost ({currency}):{" "}
|
||||||
disableSelectionZone
|
<b>
|
||||||
items={estimatedSpendingItems}
|
{currencySign}
|
||||||
columns={estimatedSpendingColumns}
|
{calculateEstimateNumber(hourlyPrice)} hourly {` / `}
|
||||||
selectionMode={SelectionMode.none}
|
{currencySign}
|
||||||
layoutMode={DetailsListLayoutMode.justified}
|
{calculateEstimateNumber(dailyPrice)} daily {` / `}
|
||||||
onRenderRow={onRenderRow}
|
{currencySign}
|
||||||
/>
|
{calculateEstimateNumber(monthlyPrice)} monthly{" "}
|
||||||
<Text id="throughputSpendElement">
|
</b>
|
||||||
({"regions: "} {numberOfRegions}, {ruRange}
|
({"regions: "} {regions}, {throughput}RU/s, {currencySign}
|
||||||
{throughput} RU/s, {priceBreakdown.currencySign}
|
{pricePerRu}/RU)
|
||||||
{priceBreakdown.pricePerRu}/RU)
|
</Text>
|
||||||
</Text>
|
|
||||||
<Text>
|
|
||||||
<em>{estimatedCostDisclaimer}</em>
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -307,13 +265,6 @@ export const updateThroughputDelayedApplyWarningMessage: JSX.Element = (
|
|||||||
</Text>
|
</Text>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const saveThroughputWarningMessage: JSX.Element = (
|
|
||||||
<Text styles={infoAndToolTipTextStyle}>
|
|
||||||
Your bill will be affected as you update your throughput settings. Please review the updated cost estimate below
|
|
||||||
before saving your changes
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
|
|
||||||
const getCurrentThroughput = (
|
const getCurrentThroughput = (
|
||||||
isAutoscale: boolean,
|
isAutoscale: boolean,
|
||||||
throughput: number,
|
throughput: number,
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
Text,
|
Text,
|
||||||
SelectionMode,
|
SelectionMode,
|
||||||
|
IDetailsRowProps,
|
||||||
|
DetailsRow,
|
||||||
IColumn,
|
IColumn,
|
||||||
MessageBar,
|
MessageBar,
|
||||||
MessageBarType,
|
MessageBarType,
|
||||||
@@ -19,11 +21,11 @@ import {
|
|||||||
mongoIndexingPolicyDisclaimer,
|
mongoIndexingPolicyDisclaimer,
|
||||||
mediumWidthStackStyles,
|
mediumWidthStackStyles,
|
||||||
subComponentStackProps,
|
subComponentStackProps,
|
||||||
|
transparentDetailsRowStyles,
|
||||||
createAndAddMongoIndexStackProps,
|
createAndAddMongoIndexStackProps,
|
||||||
separatorStyles,
|
separatorStyles,
|
||||||
indexingPolicynUnsavedWarningMessage,
|
indexingPolicynUnsavedWarningMessage,
|
||||||
infoAndToolTipTextStyle,
|
infoAndToolTipTextStyle
|
||||||
onRenderRow
|
|
||||||
} from "../../SettingsRenderUtils";
|
} from "../../SettingsRenderUtils";
|
||||||
import { MongoIndex } from "../../../../../Utils/arm/generatedClients/2020-04-01/types";
|
import { MongoIndex } from "../../../../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import {
|
import {
|
||||||
@@ -138,6 +140,10 @@ export class MongoIndexingPolicyComponent extends React.Component<MongoIndexingP
|
|||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onRenderRow = (props: IDetailsRowProps): JSX.Element => {
|
||||||
|
return <DetailsRow {...props} styles={transparentDetailsRowStyles} />;
|
||||||
|
};
|
||||||
|
|
||||||
private getActionButton = (arrayPosition: number, isCurrentIndex: boolean): JSX.Element => {
|
private getActionButton = (arrayPosition: number, isCurrentIndex: boolean): JSX.Element => {
|
||||||
return isCurrentIndex ? (
|
return isCurrentIndex ? (
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -247,7 +253,7 @@ export class MongoIndexingPolicyComponent extends React.Component<MongoIndexingP
|
|||||||
items={initialIndexes}
|
items={initialIndexes}
|
||||||
columns={this.initialIndexesColumns}
|
columns={this.initialIndexesColumns}
|
||||||
selectionMode={SelectionMode.none}
|
selectionMode={SelectionMode.none}
|
||||||
onRenderRow={onRenderRow}
|
onRenderRow={this.onRenderRow}
|
||||||
layoutMode={DetailsListLayoutMode.justified}
|
layoutMode={DetailsListLayoutMode.justified}
|
||||||
/>
|
/>
|
||||||
{this.renderIndexesToBeAdded()}
|
{this.renderIndexesToBeAdded()}
|
||||||
@@ -273,7 +279,7 @@ export class MongoIndexingPolicyComponent extends React.Component<MongoIndexingP
|
|||||||
items={indexesToBeDropped}
|
items={indexesToBeDropped}
|
||||||
columns={this.indexesToBeDroppedColumns}
|
columns={this.indexesToBeDroppedColumns}
|
||||||
selectionMode={SelectionMode.none}
|
selectionMode={SelectionMode.none}
|
||||||
onRenderRow={onRenderRow}
|
onRenderRow={this.onRenderRow}
|
||||||
layoutMode={DetailsListLayoutMode.justified}
|
layoutMode={DetailsListLayoutMode.justified}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ describe("ThroughputInputAutoPilotV3Component", () => {
|
|||||||
expect(wrapper.exists("#throughputInput")).toEqual(true);
|
expect(wrapper.exists("#throughputInput")).toEqual(true);
|
||||||
expect(wrapper.exists("#autopilotInput")).toEqual(false);
|
expect(wrapper.exists("#autopilotInput")).toEqual(false);
|
||||||
expect(wrapper.exists("#throughputSpendElement")).toEqual(true);
|
expect(wrapper.exists("#throughputSpendElement")).toEqual(true);
|
||||||
|
expect(wrapper.exists("#autoscaleSpendElement")).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("autopilot input visible", () => {
|
it("autopilot input visible", () => {
|
||||||
@@ -71,7 +72,8 @@ describe("ThroughputInputAutoPilotV3Component", () => {
|
|||||||
|
|
||||||
wrapper.setProps({ wasAutopilotOriginallySet: true });
|
wrapper.setProps({ wasAutopilotOriginallySet: true });
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.exists("#throughputSpendElement")).toEqual(true);
|
expect(wrapper.exists("#autoscaleSpendElement")).toEqual(true);
|
||||||
|
expect(wrapper.exists("#throughputSpendElement")).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("spendAck checkbox visible", () => {
|
it("spendAck checkbox visible", () => {
|
||||||
|
|||||||
@@ -8,15 +8,10 @@ import {
|
|||||||
checkBoxAndInputStackProps,
|
checkBoxAndInputStackProps,
|
||||||
getChoiceGroupStyles,
|
getChoiceGroupStyles,
|
||||||
messageBarStyles,
|
messageBarStyles,
|
||||||
getEstimatedSpendingElement,
|
getEstimatedSpendElement,
|
||||||
|
getEstimatedAutoscaleSpendElement,
|
||||||
getAutoPilotV3SpendElement,
|
getAutoPilotV3SpendElement,
|
||||||
manualToAutoscaleDisclaimerElement,
|
manualToAutoscaleDisclaimerElement
|
||||||
saveThroughputWarningMessage,
|
|
||||||
ManualEstimatedSpendingDisplayProps,
|
|
||||||
AutoscaleEstimatedSpendingDisplayProps,
|
|
||||||
PriceBreakdown,
|
|
||||||
getRuPriceBreakdown,
|
|
||||||
transparentDetailsHeaderStyle
|
|
||||||
} from "../../SettingsRenderUtils";
|
} from "../../SettingsRenderUtils";
|
||||||
import {
|
import {
|
||||||
Text,
|
Text,
|
||||||
@@ -28,9 +23,7 @@ import {
|
|||||||
Label,
|
Label,
|
||||||
Link,
|
Link,
|
||||||
MessageBar,
|
MessageBar,
|
||||||
MessageBarType,
|
MessageBarType
|
||||||
FontIcon,
|
|
||||||
IColumn
|
|
||||||
} from "office-ui-fabric-react";
|
} from "office-ui-fabric-react";
|
||||||
import { ToolTipLabelComponent } from "../ToolTipLabelComponent";
|
import { ToolTipLabelComponent } from "../ToolTipLabelComponent";
|
||||||
import { getSanitizedInputValue, IsComponentDirtyResult, isDirty } from "../../SettingsUtils";
|
import { getSanitizedInputValue, IsComponentDirtyResult, isDirty } from "../../SettingsUtils";
|
||||||
@@ -39,7 +32,7 @@ import * as DataModels from "../../../../../Contracts/DataModels";
|
|||||||
import { Int32 } from "../../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
import { Int32 } from "../../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
||||||
import { userContext } from "../../../../../UserContext";
|
import { userContext } from "../../../../../UserContext";
|
||||||
import { SubscriptionType } from "../../../../../Contracts/SubscriptionType";
|
import { SubscriptionType } from "../../../../../Contracts/SubscriptionType";
|
||||||
import { usageInGB, calculateEstimateNumber } from "../../../../../Utils/PricingUtils";
|
import { usageInGB } from "../../../../../Utils/PricingUtils";
|
||||||
import { Features } from "../../../../../Common/Constants";
|
import { Features } from "../../../../../Common/Constants";
|
||||||
|
|
||||||
export interface ThroughputInputAutoPilotV3Props {
|
export interface ThroughputInputAutoPilotV3Props {
|
||||||
@@ -172,243 +165,33 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isDirty: boolean = this.IsComponentDirty().isDiscardable;
|
|
||||||
const serverId: string = this.props.serverId;
|
const serverId: string = this.props.serverId;
|
||||||
|
const offerThroughput: number = this.props.throughput;
|
||||||
|
|
||||||
const regions = account?.properties?.readLocations?.length || 1;
|
const regions = account?.properties?.readLocations?.length || 1;
|
||||||
const multimaster = account?.properties?.enableMultipleWriteLocations || false;
|
const multimaster = account?.properties?.enableMultipleWriteLocations || false;
|
||||||
|
|
||||||
let estimatedSpend: JSX.Element;
|
let estimatedSpend: JSX.Element;
|
||||||
|
|
||||||
if (!this.props.isAutoPilotSelected) {
|
if (!this.props.isAutoPilotSelected) {
|
||||||
estimatedSpend = this.getEstimatedManualSpendElement(
|
estimatedSpend = getEstimatedSpendElement(
|
||||||
// if migrating from autoscale to manual, we use the autoscale RUs value as that is what will be set...
|
// if migrating from autoscale to manual, we use the autoscale RUs value as that is what will be set...
|
||||||
this.overrideWithAutoPilotSettings() ? this.props.maxAutoPilotThroughput : this.props.throughputBaseline,
|
this.overrideWithAutoPilotSettings() ? this.props.maxAutoPilotThroughput : offerThroughput,
|
||||||
serverId,
|
serverId,
|
||||||
regions,
|
regions,
|
||||||
multimaster,
|
multimaster
|
||||||
isDirty ? this.props.throughput : undefined
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
estimatedSpend = this.getEstimatedAutoscaleSpendElement(
|
estimatedSpend = getEstimatedAutoscaleSpendElement(
|
||||||
this.props.maxAutoPilotThroughputBaseline,
|
this.props.maxAutoPilotThroughput,
|
||||||
serverId,
|
serverId,
|
||||||
regions,
|
regions,
|
||||||
multimaster,
|
multimaster
|
||||||
isDirty ? this.props.maxAutoPilotThroughput : undefined
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return estimatedSpend;
|
return estimatedSpend;
|
||||||
};
|
};
|
||||||
|
|
||||||
private getEstimatedAutoscaleSpendElement = (
|
|
||||||
throughput: number,
|
|
||||||
serverId: string,
|
|
||||||
numberOfRegions: number,
|
|
||||||
isMultimaster: boolean,
|
|
||||||
newThroughput?: number
|
|
||||||
): JSX.Element => {
|
|
||||||
const prices: PriceBreakdown = getRuPriceBreakdown(throughput, serverId, numberOfRegions, isMultimaster, true);
|
|
||||||
const estimatedSpendingColumns: IColumn[] = [
|
|
||||||
{
|
|
||||||
key: "costType",
|
|
||||||
name: "",
|
|
||||||
fieldName: "costType",
|
|
||||||
minWidth: 100,
|
|
||||||
maxWidth: 200,
|
|
||||||
isResizable: true,
|
|
||||||
styles: transparentDetailsHeaderStyle
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "minPerMonth",
|
|
||||||
name: "Min Per Month",
|
|
||||||
fieldName: "minPerMonth",
|
|
||||||
minWidth: 100,
|
|
||||||
maxWidth: 200,
|
|
||||||
isResizable: true,
|
|
||||||
styles: transparentDetailsHeaderStyle
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "maxPerMonth",
|
|
||||||
name: "Max Per Month",
|
|
||||||
fieldName: "maxPerMonth",
|
|
||||||
minWidth: 100,
|
|
||||||
maxWidth: 200,
|
|
||||||
isResizable: true,
|
|
||||||
styles: transparentDetailsHeaderStyle
|
|
||||||
}
|
|
||||||
];
|
|
||||||
const estimatedSpendingItems: AutoscaleEstimatedSpendingDisplayProps[] = [
|
|
||||||
{
|
|
||||||
costType: <Text>Current Cost</Text>,
|
|
||||||
minPerMonth: (
|
|
||||||
<Text>
|
|
||||||
{prices.currencySign} {calculateEstimateNumber(prices.monthlyPrice / 10)}
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
maxPerMonth: (
|
|
||||||
<Text>
|
|
||||||
{prices.currencySign} {calculateEstimateNumber(prices.monthlyPrice)}
|
|
||||||
</Text>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
if (newThroughput) {
|
|
||||||
const newPrices: PriceBreakdown = getRuPriceBreakdown(
|
|
||||||
newThroughput,
|
|
||||||
serverId,
|
|
||||||
numberOfRegions,
|
|
||||||
isMultimaster,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
estimatedSpendingItems.unshift({
|
|
||||||
costType: (
|
|
||||||
<Text>
|
|
||||||
<b>Updated Cost</b>
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
minPerMonth: (
|
|
||||||
<Text>
|
|
||||||
<b>
|
|
||||||
{newPrices.currencySign} {calculateEstimateNumber(newPrices.monthlyPrice / 10)}
|
|
||||||
</b>
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
maxPerMonth: (
|
|
||||||
<Text>
|
|
||||||
<b>
|
|
||||||
{newPrices.currencySign} {calculateEstimateNumber(newPrices.monthlyPrice)}
|
|
||||||
</b>
|
|
||||||
</Text>
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return getEstimatedSpendingElement(
|
|
||||||
estimatedSpendingColumns,
|
|
||||||
estimatedSpendingItems,
|
|
||||||
newThroughput ?? throughput,
|
|
||||||
numberOfRegions,
|
|
||||||
prices,
|
|
||||||
true
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
private getEstimatedManualSpendElement = (
|
|
||||||
throughput: number,
|
|
||||||
serverId: string,
|
|
||||||
numberOfRegions: number,
|
|
||||||
isMultimaster: boolean,
|
|
||||||
newThroughput?: number
|
|
||||||
): JSX.Element => {
|
|
||||||
const prices: PriceBreakdown = getRuPriceBreakdown(throughput, serverId, numberOfRegions, isMultimaster, false);
|
|
||||||
const estimatedSpendingColumns: IColumn[] = [
|
|
||||||
{
|
|
||||||
key: "costType",
|
|
||||||
name: "",
|
|
||||||
fieldName: "costType",
|
|
||||||
minWidth: 100,
|
|
||||||
maxWidth: 200,
|
|
||||||
isResizable: true,
|
|
||||||
styles: transparentDetailsHeaderStyle
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "hourly",
|
|
||||||
name: "Hourly",
|
|
||||||
fieldName: "hourly",
|
|
||||||
minWidth: 100,
|
|
||||||
maxWidth: 200,
|
|
||||||
isResizable: true,
|
|
||||||
styles: transparentDetailsHeaderStyle
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "daily",
|
|
||||||
name: "Daily",
|
|
||||||
fieldName: "daily",
|
|
||||||
minWidth: 100,
|
|
||||||
maxWidth: 200,
|
|
||||||
isResizable: true,
|
|
||||||
styles: transparentDetailsHeaderStyle
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "monthly",
|
|
||||||
name: "Monthly",
|
|
||||||
fieldName: "monthly",
|
|
||||||
minWidth: 100,
|
|
||||||
maxWidth: 200,
|
|
||||||
isResizable: true,
|
|
||||||
styles: transparentDetailsHeaderStyle
|
|
||||||
}
|
|
||||||
];
|
|
||||||
const estimatedSpendingItems: ManualEstimatedSpendingDisplayProps[] = [
|
|
||||||
{
|
|
||||||
costType: <Text>Current Cost</Text>,
|
|
||||||
hourly: (
|
|
||||||
<Text>
|
|
||||||
{prices.currencySign} {calculateEstimateNumber(prices.hourlyPrice)}
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
daily: (
|
|
||||||
<Text>
|
|
||||||
{prices.currencySign} {calculateEstimateNumber(prices.dailyPrice)}
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
monthly: (
|
|
||||||
<Text>
|
|
||||||
{prices.currencySign} {calculateEstimateNumber(prices.monthlyPrice)}
|
|
||||||
</Text>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
if (newThroughput) {
|
|
||||||
const newPrices: PriceBreakdown = getRuPriceBreakdown(
|
|
||||||
newThroughput,
|
|
||||||
serverId,
|
|
||||||
numberOfRegions,
|
|
||||||
isMultimaster,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
estimatedSpendingItems.unshift({
|
|
||||||
costType: (
|
|
||||||
<Text>
|
|
||||||
<b>Updated Cost</b>
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
hourly: (
|
|
||||||
<Text>
|
|
||||||
<b>
|
|
||||||
{newPrices.currencySign} {calculateEstimateNumber(newPrices.hourlyPrice)}
|
|
||||||
</b>
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
daily: (
|
|
||||||
<Text>
|
|
||||||
<b>
|
|
||||||
{newPrices.currencySign} {calculateEstimateNumber(newPrices.dailyPrice)}
|
|
||||||
</b>
|
|
||||||
</Text>
|
|
||||||
),
|
|
||||||
monthly: (
|
|
||||||
<Text>
|
|
||||||
<b>
|
|
||||||
{newPrices.currencySign} {calculateEstimateNumber(newPrices.monthlyPrice)}
|
|
||||||
</b>
|
|
||||||
</Text>
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return getEstimatedSpendingElement(
|
|
||||||
estimatedSpendingColumns,
|
|
||||||
estimatedSpendingItems,
|
|
||||||
newThroughput ?? throughput,
|
|
||||||
numberOfRegions,
|
|
||||||
prices,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
private getAutoPilotUsageCost = (): JSX.Element => {
|
private getAutoPilotUsageCost = (): JSX.Element => {
|
||||||
if (!this.props.maxAutoPilotThroughput) {
|
if (!this.props.maxAutoPilotThroughput) {
|
||||||
return <></>;
|
return <></>;
|
||||||
@@ -535,12 +318,6 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
|
|
||||||
private renderThroughputInput = (): JSX.Element => (
|
private renderThroughputInput = (): JSX.Element => (
|
||||||
<Stack {...titleAndInputStackProps}>
|
<Stack {...titleAndInputStackProps}>
|
||||||
<Text>
|
|
||||||
Estimate your required throughput with
|
|
||||||
<Link target="_blank" href="https://cosmos.azure.com/capacitycalculator/">
|
|
||||||
{` capacity calculator`} <FontIcon iconName="NavigateExternalInline" />
|
|
||||||
</Link>
|
|
||||||
</Text>
|
|
||||||
<TextField
|
<TextField
|
||||||
required
|
required
|
||||||
type="number"
|
type="number"
|
||||||
@@ -572,24 +349,13 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
onChange={this.onSpendAckChecked}
|
onChange={this.onSpendAckChecked}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<br />
|
|
||||||
{this.props.isFixed && <p>When using a collection with fixed storage capacity, you can set up to 10,000 RU/s.</p>}
|
{this.props.isFixed && <p>When using a collection with fixed storage capacity, you can set up to 10,000 RU/s.</p>}
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|
||||||
private renderWarningMessage = (): JSX.Element => {
|
|
||||||
let warningMessage: JSX.Element;
|
|
||||||
if (this.IsComponentDirty().isDiscardable) {
|
|
||||||
warningMessage = saveThroughputWarningMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <>{warningMessage && <MessageBar messageBarType={MessageBarType.warning}>{warningMessage}</MessageBar>}</>;
|
|
||||||
};
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack {...checkBoxAndInputStackProps}>
|
<Stack {...checkBoxAndInputStackProps}>
|
||||||
{this.renderWarningMessage()}
|
|
||||||
{this.renderThroughputModeChoices()}
|
{this.renderThroughputModeChoices()}
|
||||||
|
|
||||||
{this.props.isAutoPilotSelected ? this.renderAutoPilotInput() : this.renderThroughputInput()}
|
{this.props.isAutoPilotSelected ? this.renderAutoPilotInput() : this.renderThroughputInput()}
|
||||||
|
|||||||
@@ -8,21 +8,6 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<StyledMessageBarBase
|
|
||||||
messageBarType={5}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
styles={
|
|
||||||
Object {
|
|
||||||
"root": Object {
|
|
||||||
"fontSize": 12,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Your bill will be affected as you update your throughput settings. Please review the updated cost estimate below before saving your changes
|
|
||||||
</Text>
|
|
||||||
</StyledMessageBarBase>
|
|
||||||
<Stack>
|
<Stack>
|
||||||
<StyledLabelBase
|
<StyledLabelBase
|
||||||
id="settingsV2RadioButtonLabelId"
|
id="settingsV2RadioButtonLabelId"
|
||||||
@@ -229,19 +214,6 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text>
|
|
||||||
Estimate your required throughput with
|
|
||||||
<StyledLinkBase
|
|
||||||
href="https://cosmos.azure.com/capacitycalculator/"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
capacity calculator
|
|
||||||
|
|
||||||
<Component
|
|
||||||
iconName="NavigateExternalInline"
|
|
||||||
/>
|
|
||||||
</StyledLinkBase>
|
|
||||||
</Text>
|
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="throughputInput"
|
id="throughputInput"
|
||||||
@@ -267,142 +239,38 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
|
|||||||
type="number"
|
type="number"
|
||||||
value="100"
|
value="100"
|
||||||
/>
|
/>
|
||||||
<Stack
|
<Text
|
||||||
styles={
|
id="throughputSpendElement"
|
||||||
Object {
|
|
||||||
"root": Object {
|
|
||||||
"width": 600,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tokens={
|
|
||||||
Object {
|
|
||||||
"childrenGap": 10,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<StyledWithViewportComponent
|
Estimated cost (
|
||||||
columns={
|
USD
|
||||||
Array [
|
):
|
||||||
Object {
|
|
||||||
"fieldName": "costType",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "costType",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "",
|
|
||||||
"styles": Object {
|
|
||||||
"root": Object {
|
|
||||||
"selectors": Object {
|
|
||||||
":hover": Object {
|
|
||||||
"background": "transparent",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"fieldName": "hourly",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "hourly",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "Hourly",
|
|
||||||
"styles": Object {
|
|
||||||
"root": Object {
|
|
||||||
"selectors": Object {
|
|
||||||
":hover": Object {
|
|
||||||
"background": "transparent",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"fieldName": "daily",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "daily",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "Daily",
|
|
||||||
"styles": Object {
|
|
||||||
"root": Object {
|
|
||||||
"selectors": Object {
|
|
||||||
":hover": Object {
|
|
||||||
"background": "transparent",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"fieldName": "monthly",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "monthly",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "Monthly",
|
|
||||||
"styles": Object {
|
|
||||||
"root": Object {
|
|
||||||
"selectors": Object {
|
|
||||||
":hover": Object {
|
|
||||||
"background": "transparent",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
disableSelectionZone={true}
|
|
||||||
items={
|
|
||||||
Array [
|
|
||||||
Object {
|
|
||||||
"costType": <Text>
|
|
||||||
Current Cost
|
|
||||||
</Text>,
|
|
||||||
"daily": <Text>
|
|
||||||
$
|
|
||||||
|
|
||||||
0.19
|
<b>
|
||||||
</Text>,
|
|
||||||
"hourly": <Text>
|
|
||||||
$
|
|
||||||
|
|
||||||
0.0080
|
|
||||||
</Text>,
|
|
||||||
"monthly": <Text>
|
|
||||||
$
|
|
||||||
|
|
||||||
5.84
|
|
||||||
</Text>,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
layoutMode={1}
|
|
||||||
onRenderRow={[Function]}
|
|
||||||
selectionMode={0}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
id="throughputSpendElement"
|
|
||||||
>
|
|
||||||
(
|
|
||||||
regions:
|
|
||||||
|
|
||||||
1
|
|
||||||
,
|
|
||||||
100
|
|
||||||
RU/s,
|
|
||||||
$
|
$
|
||||||
0.00008
|
0.0080
|
||||||
/RU)
|
hourly
|
||||||
</Text>
|
/
|
||||||
<Text>
|
$
|
||||||
<em>
|
0.19
|
||||||
*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
daily
|
||||||
</em>
|
/
|
||||||
</Text>
|
$
|
||||||
</Stack>
|
5.84
|
||||||
|
monthly
|
||||||
|
|
||||||
|
</b>
|
||||||
|
(
|
||||||
|
regions:
|
||||||
|
|
||||||
|
1
|
||||||
|
,
|
||||||
|
100
|
||||||
|
RU/s,
|
||||||
|
$
|
||||||
|
0.00008
|
||||||
|
/RU)
|
||||||
|
</Text>
|
||||||
<StyledCheckboxBase
|
<StyledCheckboxBase
|
||||||
checked={false}
|
checked={false}
|
||||||
id="spendAckCheckBox"
|
id="spendAckCheckBox"
|
||||||
@@ -420,7 +288,6 @@ exports[`ThroughputInputAutoPilotV3Component spendAck checkbox visible 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<br />
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
`;
|
`;
|
||||||
@@ -502,19 +369,6 @@ exports[`ThroughputInputAutoPilotV3Component throughput input visible 1`] = `
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Text>
|
|
||||||
Estimate your required throughput with
|
|
||||||
<StyledLinkBase
|
|
||||||
href="https://cosmos.azure.com/capacitycalculator/"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
capacity calculator
|
|
||||||
|
|
||||||
<Component
|
|
||||||
iconName="NavigateExternalInline"
|
|
||||||
/>
|
|
||||||
</StyledLinkBase>
|
|
||||||
</Text>
|
|
||||||
<StyledTextFieldBase
|
<StyledTextFieldBase
|
||||||
disabled={false}
|
disabled={false}
|
||||||
id="throughputInput"
|
id="throughputInput"
|
||||||
@@ -540,143 +394,38 @@ exports[`ThroughputInputAutoPilotV3Component throughput input visible 1`] = `
|
|||||||
type="number"
|
type="number"
|
||||||
value="100"
|
value="100"
|
||||||
/>
|
/>
|
||||||
<Stack
|
<Text
|
||||||
styles={
|
id="throughputSpendElement"
|
||||||
Object {
|
|
||||||
"root": Object {
|
|
||||||
"width": 600,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tokens={
|
|
||||||
Object {
|
|
||||||
"childrenGap": 10,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<StyledWithViewportComponent
|
Estimated cost (
|
||||||
columns={
|
USD
|
||||||
Array [
|
):
|
||||||
Object {
|
|
||||||
"fieldName": "costType",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "costType",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "",
|
|
||||||
"styles": Object {
|
|
||||||
"root": Object {
|
|
||||||
"selectors": Object {
|
|
||||||
":hover": Object {
|
|
||||||
"background": "transparent",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"fieldName": "hourly",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "hourly",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "Hourly",
|
|
||||||
"styles": Object {
|
|
||||||
"root": Object {
|
|
||||||
"selectors": Object {
|
|
||||||
":hover": Object {
|
|
||||||
"background": "transparent",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"fieldName": "daily",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "daily",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "Daily",
|
|
||||||
"styles": Object {
|
|
||||||
"root": Object {
|
|
||||||
"selectors": Object {
|
|
||||||
":hover": Object {
|
|
||||||
"background": "transparent",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"fieldName": "monthly",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "monthly",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "Monthly",
|
|
||||||
"styles": Object {
|
|
||||||
"root": Object {
|
|
||||||
"selectors": Object {
|
|
||||||
":hover": Object {
|
|
||||||
"background": "transparent",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
disableSelectionZone={true}
|
|
||||||
items={
|
|
||||||
Array [
|
|
||||||
Object {
|
|
||||||
"costType": <Text>
|
|
||||||
Current Cost
|
|
||||||
</Text>,
|
|
||||||
"daily": <Text>
|
|
||||||
$
|
|
||||||
|
|
||||||
0.19
|
<b>
|
||||||
</Text>,
|
|
||||||
"hourly": <Text>
|
|
||||||
$
|
|
||||||
|
|
||||||
0.0080
|
|
||||||
</Text>,
|
|
||||||
"monthly": <Text>
|
|
||||||
$
|
|
||||||
|
|
||||||
5.84
|
|
||||||
</Text>,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
layoutMode={1}
|
|
||||||
onRenderRow={[Function]}
|
|
||||||
selectionMode={0}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
id="throughputSpendElement"
|
|
||||||
>
|
|
||||||
(
|
|
||||||
regions:
|
|
||||||
|
|
||||||
1
|
|
||||||
,
|
|
||||||
100
|
|
||||||
RU/s,
|
|
||||||
$
|
$
|
||||||
0.00008
|
0.0080
|
||||||
/RU)
|
hourly
|
||||||
</Text>
|
/
|
||||||
<Text>
|
$
|
||||||
<em>
|
0.19
|
||||||
*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
daily
|
||||||
</em>
|
/
|
||||||
</Text>
|
$
|
||||||
</Stack>
|
5.84
|
||||||
<br />
|
monthly
|
||||||
|
|
||||||
|
</b>
|
||||||
|
(
|
||||||
|
regions:
|
||||||
|
|
||||||
|
1
|
||||||
|
,
|
||||||
|
100
|
||||||
|
RU/s,
|
||||||
|
$
|
||||||
|
0.00008
|
||||||
|
/RU)
|
||||||
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -60,100 +60,66 @@ exports[`SettingsUtils functions render 1`] = `
|
|||||||
</StyledLinkBase>
|
</StyledLinkBase>
|
||||||
.
|
.
|
||||||
</Text>
|
</Text>
|
||||||
<Stack
|
<Text
|
||||||
styles={
|
id="throughputSpendElement"
|
||||||
Object {
|
|
||||||
"root": Object {
|
|
||||||
"width": 600,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tokens={
|
|
||||||
Object {
|
|
||||||
"childrenGap": 10,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<StyledWithViewportComponent
|
Estimated cost (
|
||||||
columns={
|
RMB
|
||||||
Array [
|
):
|
||||||
Object {
|
|
||||||
"fieldName": "costType",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "costType",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"fieldName": "hourly",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "hourly",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "Hourly",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"fieldName": "daily",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "daily",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "Daily",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"fieldName": "monthly",
|
|
||||||
"isResizable": true,
|
|
||||||
"key": "monthly",
|
|
||||||
"maxWidth": 200,
|
|
||||||
"minWidth": 100,
|
|
||||||
"name": "Monthly",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
disableSelectionZone={true}
|
|
||||||
items={
|
|
||||||
Array [
|
|
||||||
Object {
|
|
||||||
"costType": <Text>
|
|
||||||
Current Cost
|
|
||||||
</Text>,
|
|
||||||
"daily": <Text>
|
|
||||||
$ 24.48
|
|
||||||
</Text>,
|
|
||||||
"hourly": <Text>
|
|
||||||
$ 1.02
|
|
||||||
</Text>,
|
|
||||||
"monthly": <Text>
|
|
||||||
$ 744.6
|
|
||||||
</Text>,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
layoutMode={1}
|
|
||||||
onRenderRow={[Function]}
|
|
||||||
selectionMode={0}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
id="throughputSpendElement"
|
|
||||||
>
|
|
||||||
(
|
|
||||||
regions:
|
|
||||||
|
|
||||||
2
|
<b>
|
||||||
,
|
|
||||||
1000
|
|
||||||
RU/s,
|
|
||||||
¥
|
¥
|
||||||
0.00051
|
1.02
|
||||||
/RU)
|
hourly
|
||||||
</Text>
|
/
|
||||||
<Text>
|
¥
|
||||||
<em>
|
24.48
|
||||||
*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account
|
daily
|
||||||
</em>
|
/
|
||||||
</Text>
|
¥
|
||||||
</Stack>
|
744.60
|
||||||
|
monthly
|
||||||
|
|
||||||
|
</b>
|
||||||
|
(
|
||||||
|
regions:
|
||||||
|
|
||||||
|
2
|
||||||
|
,
|
||||||
|
1000
|
||||||
|
RU/s,
|
||||||
|
¥
|
||||||
|
0.00051
|
||||||
|
/RU)
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
id="autoscaleSpendElement"
|
||||||
|
>
|
||||||
|
Estimated monthly cost (
|
||||||
|
RMB
|
||||||
|
) is
|
||||||
|
|
||||||
|
<b>
|
||||||
|
¥
|
||||||
|
111.69
|
||||||
|
-
|
||||||
|
¥
|
||||||
|
1116.90
|
||||||
|
|
||||||
|
</b>
|
||||||
|
(
|
||||||
|
regions:
|
||||||
|
|
||||||
|
2
|
||||||
|
,
|
||||||
|
100
|
||||||
|
-
|
||||||
|
1000
|
||||||
|
RU/s,
|
||||||
|
¥
|
||||||
|
0.000765
|
||||||
|
/RU)
|
||||||
|
</Text>
|
||||||
<Text
|
<Text
|
||||||
id="manualToAutoscaleDisclaimerElement"
|
id="manualToAutoscaleDisclaimerElement"
|
||||||
styles={
|
styles={
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<json-editor
|
<json-editor
|
||||||
params="{ content: queryResults, isReadOnly: true, ariaLabel: 'Query results' }"
|
params="{ content: queryResults, isReadOnly: true, ariaLabel: 'Query results' }"
|
||||||
data-bind="visible: queryResults() && queryResults().length > 0 && isResultToggled() && allResultsMetadata().length > 0 && !error()"
|
data-bind="visible: queryResults().length > 0 && isResultToggled() && allResultsMetadata().length > 0 && !error()"
|
||||||
>
|
>
|
||||||
</json-editor>
|
</json-editor>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -142,7 +142,7 @@
|
|||||||
<notebook-viewer-tab params="{data: $data}"></notebook-viewer-tab>
|
<notebook-viewer-tab params="{data: $data}"></notebook-viewer-tab>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
|
|
||||||
<!-- ko if: $data.tabKind === 20 -->
|
<!-- ko if: $data.tabKind === 19 -->
|
||||||
<settings-tab-v2 params="{data: $data}"></settings-tab-v2>
|
<settings-tab-v2 params="{data: $data}"></settings-tab-v2>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -551,7 +551,7 @@ export default class Collection implements ViewModels.Collection {
|
|||||||
|
|
||||||
const tabTitle = !this.offer() ? "Settings" : "Scale & Settings";
|
const tabTitle = !this.offer() ? "Settings" : "Scale & Settings";
|
||||||
const pendingNotificationsPromise: Q.Promise<DataModels.Notification> = this._getPendingThroughputSplitNotification();
|
const pendingNotificationsPromise: Q.Promise<DataModels.Notification> = this._getPendingThroughputSplitNotification();
|
||||||
const matchingTabs = this.container.tabsManager.getTabs(ViewModels.CollectionTabKind.SettingsV2, tab => {
|
const matchingTabs = this.container.tabsManager.getTabs(ViewModels.CollectionTabKind.Settings, tab => {
|
||||||
return tab.collection && tab.collection.databaseId === this.databaseId && tab.collection.id() === this.id();
|
return tab.collection && tab.collection.databaseId === this.databaseId && tab.collection.id() === this.id();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ export class TabRouteHandler {
|
|||||||
): void {
|
): void {
|
||||||
this._initRouter();
|
this._initRouter();
|
||||||
const parseHash = (newHash: string, oldHash: string) => this._tabRouter.parse(newHash);
|
const parseHash = (newHash: string, oldHash: string) => this._tabRouter.parse(newHash);
|
||||||
const defaultRoutedCallback = (request: string, data: { route: any; params: string[]; isFirst: boolean }) => {};
|
const defaultRoutedCallback = (request: string, data: { route: any; params: string[]; isFirst: boolean }) => {
|
||||||
|
console.log(request);
|
||||||
|
};
|
||||||
this._tabRouter.routed.add(onMatch || defaultRoutedCallback);
|
this._tabRouter.routed.add(onMatch || defaultRoutedCallback);
|
||||||
hasher.initialized.add(parseHash);
|
hasher.initialized.add(parseHash);
|
||||||
hasher.changed.add(parseHash);
|
hasher.changed.add(parseHash);
|
||||||
|
|||||||
@@ -25,151 +25,39 @@ describe("PricingUtils Tests", () => {
|
|||||||
|
|
||||||
describe("computeRUUsagePriceHourly()", () => {
|
describe("computeRUUsagePriceHourly()", () => {
|
||||||
it("should return 0 for NaN regions default cloud", () => {
|
it("should return 0 for NaN regions default cloud", () => {
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
const value = PricingUtils.computeRUUsagePriceHourly("default", 1, null, false);
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: null,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: false
|
|
||||||
});
|
|
||||||
expect(value).toBe(0);
|
|
||||||
});
|
|
||||||
it("should return 0 for NaN regions default cloud, autoscale", () => {
|
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: null,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: true
|
|
||||||
});
|
|
||||||
expect(value).toBe(0);
|
expect(value).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return 0 for -1 regions", () => {
|
it("should return 0 for -1 regions", () => {
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
const value = PricingUtils.computeRUUsagePriceHourly("default", 1, -1, false);
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: -1,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: false
|
|
||||||
});
|
|
||||||
expect(value).toBe(0);
|
|
||||||
});
|
|
||||||
it("should return 0 for -1 regions, autoscale", () => {
|
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: -1,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: true
|
|
||||||
});
|
|
||||||
expect(value).toBe(0);
|
expect(value).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return 0.00008 for default cloud, 1RU, 1 region, multimaster disabled", () => {
|
it("should return 0.00008 for default cloud, 1RU, 1 region, multimaster disabled", () => {
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
const value = PricingUtils.computeRUUsagePriceHourly("default", 1, 1, false);
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 1,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: false
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00008);
|
expect(value).toBe(0.00008);
|
||||||
});
|
});
|
||||||
it("should return 0.00008 for default cloud, 1RU, 1 region, multimaster disabled, autoscale", () => {
|
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 1,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: true
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00012);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return 0.00051 for Mooncake cloud, 1RU, 1 region, multimaster disabled", () => {
|
it("should return 0.00051 for Mooncake cloud, 1RU, 1 region, multimaster disabled", () => {
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
const value = PricingUtils.computeRUUsagePriceHourly("mooncake", 1, 1, false);
|
||||||
serverId: "mooncake",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 1,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: false
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00051);
|
expect(value).toBe(0.00051);
|
||||||
});
|
});
|
||||||
it("should return 0.00051 for Mooncake cloud, 1RU, 1 region, multimaster disabled, autoscale", () => {
|
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
|
||||||
serverId: "mooncake",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 1,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: true
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00076);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return 0.00016 for default cloud, 1RU, 2 regions, multimaster disabled", () => {
|
it("should return 0.00016 for default cloud, 1RU, 2 regions, multimaster disabled", () => {
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
const value = PricingUtils.computeRUUsagePriceHourly("default", 1, 2, false);
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 2,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: false
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00016);
|
expect(value).toBe(0.00016);
|
||||||
});
|
});
|
||||||
it("should return 0.00016 for default cloud, 1RU, 2 regions, multimaster disabled, autoscale", () => {
|
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 2,
|
|
||||||
multimasterEnabled: false,
|
|
||||||
isAutoscale: true
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00024);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return 0.00008 for default cloud, 1RU, 1 region, multimaster enabled", () => {
|
it("should return 0.00008 for default cloud, 1RU, 1 region, multimaster enabled", () => {
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
const value = PricingUtils.computeRUUsagePriceHourly("default", 1, 1, true);
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 1,
|
|
||||||
multimasterEnabled: true,
|
|
||||||
isAutoscale: false
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00008);
|
expect(value).toBe(0.00008);
|
||||||
});
|
});
|
||||||
it("should return 0.00008 for default cloud, 1RU, 1 region, multimaster enabled, autoscale", () => {
|
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 1,
|
|
||||||
multimasterEnabled: true,
|
|
||||||
isAutoscale: true
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00012);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return 0.00048 for default cloud, 1RU, 2 region, multimaster enabled", () => {
|
it("should return 0.00048 for default cloud, 1RU, 2 region, multimaster enabled", () => {
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
const value = PricingUtils.computeRUUsagePriceHourly("default", 1, 2, true);
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 2,
|
|
||||||
multimasterEnabled: true,
|
|
||||||
isAutoscale: false
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00048);
|
expect(value).toBe(0.00048);
|
||||||
});
|
});
|
||||||
it("should return 0.00048 for default cloud, 1RU, 2 region, multimaster enabled, autoscale", () => {
|
|
||||||
const value = PricingUtils.computeRUUsagePriceHourly({
|
|
||||||
serverId: "default",
|
|
||||||
requestUnits: 1,
|
|
||||||
numberOfRegions: 2,
|
|
||||||
multimasterEnabled: true,
|
|
||||||
isAutoscale: true
|
|
||||||
});
|
|
||||||
expect(value).toBe(0.00096);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("getPriceCurrency()", () => {
|
describe("getPriceCurrency()", () => {
|
||||||
|
|||||||
@@ -1,17 +1,6 @@
|
|||||||
import * as AutoPilotUtils from "../Utils/AutoPilotUtils";
|
import * as AutoPilotUtils from "../Utils/AutoPilotUtils";
|
||||||
import * as Constants from "../Shared/Constants";
|
import * as Constants from "../Shared/Constants";
|
||||||
|
|
||||||
interface ComputeRUUsagePriceHourlyArgs {
|
|
||||||
serverId: string;
|
|
||||||
requestUnits: number;
|
|
||||||
numberOfRegions: number;
|
|
||||||
multimasterEnabled: boolean;
|
|
||||||
isAutoscale: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const estimatedCostDisclaimer =
|
|
||||||
"*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Anything that is not a number should return 0
|
* Anything that is not a number should return 0
|
||||||
* Otherwise, return numberOfRegions
|
* Otherwise, return numberOfRegions
|
||||||
@@ -58,16 +47,15 @@ export function getMultimasterMultiplier(numberOfRegions: number, multimasterEna
|
|||||||
return multimasterMultiplier;
|
return multimasterMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function computeRUUsagePriceHourly({
|
export function computeRUUsagePriceHourly(
|
||||||
serverId,
|
serverId: string,
|
||||||
requestUnits,
|
requestUnits: number,
|
||||||
numberOfRegions,
|
numberOfRegions: number,
|
||||||
multimasterEnabled,
|
multimasterEnabled: boolean
|
||||||
isAutoscale
|
): number {
|
||||||
}: ComputeRUUsagePriceHourlyArgs): number {
|
|
||||||
const regionMultiplier: number = getRegionMultiplier(numberOfRegions, multimasterEnabled);
|
const regionMultiplier: number = getRegionMultiplier(numberOfRegions, multimasterEnabled);
|
||||||
const multimasterMultiplier: number = getMultimasterMultiplier(numberOfRegions, multimasterEnabled);
|
const multimasterMultiplier: number = getMultimasterMultiplier(numberOfRegions, multimasterEnabled);
|
||||||
const pricePerRu = isAutoscale ? getAutoscalePricePerRu(serverId, multimasterMultiplier) : getPricePerRu(serverId);
|
const pricePerRu = getPricePerRu(serverId);
|
||||||
const ruCharge = requestUnits * pricePerRu * multimasterMultiplier * regionMultiplier;
|
const ruCharge = requestUnits * pricePerRu * multimasterMultiplier * regionMultiplier;
|
||||||
|
|
||||||
return Number(ruCharge.toFixed(5));
|
return Number(ruCharge.toFixed(5));
|
||||||
@@ -171,19 +159,28 @@ export function getAutoPilotV3SpendHtml(maxAutoPilotThroughputSet: number, isDat
|
|||||||
}' target='_blank' aria-label='Learn more about autoscale throughput'>Learn more</a>.`;
|
}' target='_blank' aria-label='Learn more about autoscale throughput'>Learn more</a>.`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function computeAutoscaleUsagePriceHourly(
|
||||||
|
serverId: string,
|
||||||
|
requestUnits: number,
|
||||||
|
numberOfRegions: number,
|
||||||
|
multimasterEnabled: boolean
|
||||||
|
): number {
|
||||||
|
const regionMultiplier: number = getRegionMultiplier(numberOfRegions, multimasterEnabled);
|
||||||
|
const multimasterMultiplier: number = getMultimasterMultiplier(numberOfRegions, multimasterEnabled);
|
||||||
|
|
||||||
|
const pricePerRu = getAutoscalePricePerRu(serverId, multimasterMultiplier);
|
||||||
|
const ruCharge = requestUnits * pricePerRu * multimasterMultiplier * regionMultiplier;
|
||||||
|
|
||||||
|
return Number(ruCharge.toFixed(5));
|
||||||
|
}
|
||||||
|
|
||||||
export function getEstimatedAutoscaleSpendHtml(
|
export function getEstimatedAutoscaleSpendHtml(
|
||||||
throughput: number,
|
throughput: number,
|
||||||
serverId: string,
|
serverId: string,
|
||||||
regions: number,
|
regions: number,
|
||||||
multimaster: boolean
|
multimaster: boolean
|
||||||
): string {
|
): string {
|
||||||
const hourlyPrice: number = computeRUUsagePriceHourly({
|
const hourlyPrice: number = computeAutoscaleUsagePriceHourly(serverId, throughput, regions, multimaster);
|
||||||
serverId: serverId,
|
|
||||||
requestUnits: throughput,
|
|
||||||
numberOfRegions: regions,
|
|
||||||
multimasterEnabled: multimaster,
|
|
||||||
isAutoscale: true
|
|
||||||
});
|
|
||||||
const monthlyPrice: number = hourlyPrice * Constants.hoursInAMonth;
|
const monthlyPrice: number = hourlyPrice * Constants.hoursInAMonth;
|
||||||
const currency: string = getPriceCurrency(serverId);
|
const currency: string = getPriceCurrency(serverId);
|
||||||
const currencySign: string = getCurrencySign(serverId);
|
const currencySign: string = getCurrencySign(serverId);
|
||||||
@@ -206,13 +203,7 @@ export function getEstimatedSpendHtml(
|
|||||||
regions: number,
|
regions: number,
|
||||||
multimaster: boolean
|
multimaster: boolean
|
||||||
): string {
|
): string {
|
||||||
const hourlyPrice: number = computeRUUsagePriceHourly({
|
const hourlyPrice: number = computeRUUsagePriceHourly(serverId, throughput, regions, multimaster);
|
||||||
serverId: serverId,
|
|
||||||
requestUnits: throughput,
|
|
||||||
numberOfRegions: regions,
|
|
||||||
multimasterEnabled: multimaster,
|
|
||||||
isAutoscale: false
|
|
||||||
});
|
|
||||||
const dailyPrice: number = hourlyPrice * 24;
|
const dailyPrice: number = hourlyPrice * 24;
|
||||||
const monthlyPrice: number = hourlyPrice * Constants.hoursInAMonth;
|
const monthlyPrice: number = hourlyPrice * Constants.hoursInAMonth;
|
||||||
const currency: string = getPriceCurrency(serverId);
|
const currency: string = getPriceCurrency(serverId);
|
||||||
@@ -226,7 +217,7 @@ export function getEstimatedSpendHtml(
|
|||||||
`${currencySign}${calculateEstimateNumber(monthlyPrice)} monthly </b> ` +
|
`${currencySign}${calculateEstimateNumber(monthlyPrice)} monthly </b> ` +
|
||||||
`(${regions} ${regions === 1 ? "region" : "regions"}, ${throughput}RU/s, ${currencySign}${pricePerRu}/RU)` +
|
`(${regions} ${regions === 1 ? "region" : "regions"}, ${throughput}RU/s, ${currencySign}${pricePerRu}/RU)` +
|
||||||
`<p style='padding: 10px 0px 0px 0px;'>` +
|
`<p style='padding: 10px 0px 0px 0px;'>` +
|
||||||
`<em>${estimatedCostDisclaimer}</em></p>`
|
`<em>*This cost is an estimate and may vary based on the regions where your account is deployed and potential discounts applied to your account</em></p>`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,13 +228,9 @@ export function getEstimatedSpendAcknowledgeString(
|
|||||||
multimaster: boolean,
|
multimaster: boolean,
|
||||||
isAutoscale: boolean
|
isAutoscale: boolean
|
||||||
): string {
|
): string {
|
||||||
const hourlyPrice: number = computeRUUsagePriceHourly({
|
const hourlyPrice: number = isAutoscale
|
||||||
serverId: serverId,
|
? computeAutoscaleUsagePriceHourly(serverId, throughput, regions, multimaster)
|
||||||
requestUnits: throughput,
|
: computeRUUsagePriceHourly(serverId, throughput, regions, multimaster);
|
||||||
numberOfRegions: regions,
|
|
||||||
multimasterEnabled: multimaster,
|
|
||||||
isAutoscale: isAutoscale
|
|
||||||
});
|
|
||||||
const dailyPrice: number = hourlyPrice * 24;
|
const dailyPrice: number = hourlyPrice * 24;
|
||||||
const monthlyPrice: number = hourlyPrice * Constants.hoursInAMonth;
|
const monthlyPrice: number = hourlyPrice * Constants.hoursInAMonth;
|
||||||
const currencySign: string = getCurrencySign(serverId);
|
const currencySign: string = getCurrencySign(serverId);
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ describe("Collection Add and Delete Cassandra spec", () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const testName = (expect as any).getState().currentTestName;
|
const testName = (expect as any).getState().currentTestName;
|
||||||
await page.screenshot({ path: `failed-${testName}.jpg` });
|
await page.screenshot({ path: `./failed-${testName}.jpg` });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ describe("Collection Add and Delete Mongo spec", () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const testName = (expect as any).getState().currentTestName;
|
const testName = (expect as any).getState().currentTestName;
|
||||||
await page.screenshot({ path: `failed-${testName}.jpg` });
|
await page.screenshot({ path: `./failed-${testName}.jpg` });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ describe("Collection Add and Delete SQL spec", () => {
|
|||||||
// validate created
|
// validate created
|
||||||
// open database menu
|
// open database menu
|
||||||
await frame.waitForSelector('div[class="splashScreen"] > div[class="title"]', { visible: true });
|
await frame.waitForSelector('div[class="splashScreen"] > div[class="title"]', { visible: true });
|
||||||
await frame.waitFor(CREATE_DELAY);
|
await frame.waitFor(LOADING_STATE_DELAY);
|
||||||
await frame.waitForSelector('div[class="splashScreen"] > div[class="title"]', { visible: true });
|
await frame.waitForSelector('div[class="splashScreen"] > div[class="title"]', { visible: true });
|
||||||
const databases = await frame.$$(`div[class="databaseHeader main1 nodeItem "] > div[class="treeNodeHeader "]`);
|
const databases = await frame.$$(`div[class="databaseHeader main1 nodeItem "] > div[class="treeNodeHeader "]`);
|
||||||
const selectedDbId = await frame.evaluate(element => {
|
const selectedDbId = await frame.evaluate(element => {
|
||||||
@@ -139,7 +139,7 @@ describe("Collection Add and Delete SQL spec", () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const testName = (expect as any).getState().currentTestName;
|
const testName = (expect as any).getState().currentTestName;
|
||||||
await page.screenshot({ path: `failed-${testName}.jpg` });
|
await page.screenshot({ path: `./failed-${testName}.jpg` });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ describe("Collection Add and Delete Tables spec", () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const testName = (expect as any).getState().currentTestName;
|
const testName = (expect as any).getState().currentTestName;
|
||||||
await page.screenshot({ path: `failed-${testName}.jpg` });
|
await page.screenshot({ path: `./failed-${testName}.jpg` });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"target": "es2017",
|
"target": "es5",
|
||||||
"lib": ["es5", "es6", "dom", "webworker.importscripts"],
|
"lib": ["es5", "es6", "dom", "webworker.importscripts"],
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ const CaseSensitivePathsPlugin = require("case-sensitive-paths-webpack-plugin");
|
|||||||
const CreateFileWebpack = require("create-file-webpack");
|
const CreateFileWebpack = require("create-file-webpack");
|
||||||
const childProcess = require("child_process");
|
const childProcess = require("child_process");
|
||||||
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
|
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
|
||||||
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
const isCI = require("is-ci");
|
const isCI = require("is-ci");
|
||||||
const { ESBuildPlugin, ESBuildMinifyPlugin } = require("esbuild-loader");
|
|
||||||
|
|
||||||
const gitSha = childProcess.execSync("git rev-parse HEAD").toString("utf8");
|
const gitSha = childProcess.execSync("git rev-parse HEAD").toString("utf8");
|
||||||
|
|
||||||
@@ -56,20 +56,37 @@ const htmlRule = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// We compile our own code with ts-loader
|
||||||
const typescriptRule = {
|
const typescriptRule = {
|
||||||
test: /\.tsx?$/,
|
test: /\.tsx?$/,
|
||||||
use: [
|
use: [
|
||||||
{
|
{
|
||||||
loader: "esbuild-loader",
|
loader: "ts-loader",
|
||||||
options: {
|
options: {
|
||||||
loader: "tsx",
|
transpileOnly: true
|
||||||
target: "es2017"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
exclude: /node_modules/
|
exclude: /node_modules/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Third party modules are compiled with babel since using ts-loader that much causes webpack to run out of memory
|
||||||
|
const ModulesRule = {
|
||||||
|
test: /\.js$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "babel-loader",
|
||||||
|
options: {
|
||||||
|
cacheDirectory: ".cache/babel",
|
||||||
|
presets: [["@babel/preset-env", { targets: { ie: "11" }, useBuiltIns: false }]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
include: /node_modules/,
|
||||||
|
// Exclude large modules we know don't need transpiling
|
||||||
|
exclude: /vega|monaco|plotly/
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = function(env = {}, argv = {}) {
|
module.exports = function(env = {}, argv = {}) {
|
||||||
const mode = argv.mode || "development";
|
const mode = argv.mode || "development";
|
||||||
const rules = [fontRule, lessRule, imagesRule, cssRule, htmlRule, typescriptRule];
|
const rules = [fontRule, lessRule, imagesRule, cssRule, htmlRule, typescriptRule];
|
||||||
@@ -79,6 +96,7 @@ module.exports = function(env = {}, argv = {}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (mode === "production") {
|
if (mode === "production") {
|
||||||
|
rules.push(ModulesRule);
|
||||||
envVars.NODE_ENV = "production";
|
envVars.NODE_ENV = "production";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +105,6 @@ module.exports = function(env = {}, argv = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const plugins = [
|
const plugins = [
|
||||||
new ESBuildPlugin(),
|
|
||||||
new CleanWebpackPlugin(["dist"]),
|
new CleanWebpackPlugin(["dist"]),
|
||||||
new CreateFileWebpack({
|
new CreateFileWebpack({
|
||||||
path: "./dist",
|
path: "./dist",
|
||||||
@@ -194,8 +211,13 @@ module.exports = function(env = {}, argv = {}) {
|
|||||||
optimization: {
|
optimization: {
|
||||||
minimize: mode === "production" ? true : false,
|
minimize: mode === "production" ? true : false,
|
||||||
minimizer: [
|
minimizer: [
|
||||||
new ESBuildMinifyPlugin({
|
new TerserPlugin({
|
||||||
target: "es2017" // Syntax to compile to (see options below for possible values)
|
cache: ".cache/terser",
|
||||||
|
terserOptions: {
|
||||||
|
// These options increase our initial bundle size by ~5% but the builds are significantly faster and won't run out of memory
|
||||||
|
compress: false,
|
||||||
|
mangle: true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user