Updating error message on mongo collection create (#118)

* 1) Updated mongo collection create pane to display a better error when a shard key is ill formed.
2) Updated an error message to use double quotes since no string interpolation is used. I thought it was included in a previoue PR but I guess the change didn't get staged.
This commit is contained in:
vchske 2020-08-06 10:56:40 -07:00 committed by GitHub
parent a64109ebaa
commit d45af21996
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 81 deletions

View File

@ -301,7 +301,6 @@ src/Utils/NotebookConfigurationUtils.ts
src/Utils/OfferUtils.test.ts src/Utils/OfferUtils.test.ts
src/Utils/OfferUtils.ts src/Utils/OfferUtils.ts
src/Utils/PricingUtils.test.ts src/Utils/PricingUtils.test.ts
src/Utils/PricingUtils.ts
src/Utils/QueryUtils.test.ts src/Utils/QueryUtils.test.ts
src/Utils/QueryUtils.ts src/Utils/QueryUtils.ts
src/Utils/StringUtils.test.ts src/Utils/StringUtils.test.ts

View File

@ -1,67 +1,69 @@
import * as DataModels from "../Contracts/DataModels"; import * as DataModels from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels"; import * as ViewModels from "../Contracts/ViewModels";
export function replaceKnownError(err: string): string { export function replaceKnownError(err: string): string {
if ( if (
window.dataExplorer.subscriptionType() === ViewModels.SubscriptionType.Internal && window.dataExplorer.subscriptionType() === ViewModels.SubscriptionType.Internal &&
err.indexOf("SharedOffer is Disabled for your account") >= 0 err.indexOf("SharedOffer is Disabled for your account") >= 0
) { ) {
return "Database throughput is not supported for internal subscriptions."; return "Database throughput is not supported for internal subscriptions.";
} } else if (err.indexOf("Partition key paths must contain only valid") >= 0) {
return "Partition key paths must contain only valid characters and not contain a trailing slash or wildcard character.";
return err; }
}
return err;
export function parse(err: any): DataModels.ErrorDataModel[] { }
try {
return _parse(err); export function parse(err: any): DataModels.ErrorDataModel[] {
} catch (e) { try {
return [<DataModels.ErrorDataModel>{ message: JSON.stringify(err) }]; return _parse(err);
} } catch (e) {
} return [<DataModels.ErrorDataModel>{ message: JSON.stringify(err) }];
}
function _parse(err: any): DataModels.ErrorDataModel[] { }
var normalizedErrors: DataModels.ErrorDataModel[] = [];
if (err.message && !err.code) { function _parse(err: any): DataModels.ErrorDataModel[] {
normalizedErrors.push(err); var normalizedErrors: DataModels.ErrorDataModel[] = [];
} else { if (err.message && !err.code) {
const innerErrors: any[] = _getInnerErrors(err.message); normalizedErrors.push(err);
normalizedErrors = innerErrors.map(innerError => } else {
typeof innerError === "string" ? { message: innerError } : innerError const innerErrors: any[] = _getInnerErrors(err.message);
); normalizedErrors = innerErrors.map(innerError =>
} typeof innerError === "string" ? { message: innerError } : innerError
);
return normalizedErrors; }
}
return normalizedErrors;
function _getInnerErrors(message: string): any[] { }
/*
The backend error message has an inner-message which is a stringified object. function _getInnerErrors(message: string): any[] {
/*
For SQL errors, the "errors" property is an array of SqlErrorDataModel. The backend error message has an inner-message which is a stringified object.
Example:
"Message: {"Errors":["Resource with specified id or name already exists"]}\r\nActivityId: 80005000008d40b6a, Request URI: /apps/19000c000c0a0005/services/mctestdocdbprod-MasterService-0-00066ab9937/partitions/900005f9000e676fb8/replicas/13000000000955p" For SQL errors, the "errors" property is an array of SqlErrorDataModel.
For non-SQL errors the "Errors" propery is an array of string. Example:
Example: "Message: {"Errors":["Resource with specified id or name already exists"]}\r\nActivityId: 80005000008d40b6a, Request URI: /apps/19000c000c0a0005/services/mctestdocdbprod-MasterService-0-00066ab9937/partitions/900005f9000e676fb8/replicas/13000000000955p"
"Message: {"errors":[{"severity":"Error","location":{"start":7,"end":8},"code":"SC1001","message":"Syntax error, incorrect syntax near '.'."}]}\r\nActivityId: d3300016d4084e310a, Request URI: /apps/12401f9e1df77/services/dc100232b1f44545/partitions/f86f3bc0001a2f78/replicas/13085003638s" For non-SQL errors the "Errors" propery is an array of string.
*/ Example:
"Message: {"errors":[{"severity":"Error","location":{"start":7,"end":8},"code":"SC1001","message":"Syntax error, incorrect syntax near '.'."}]}\r\nActivityId: d3300016d4084e310a, Request URI: /apps/12401f9e1df77/services/dc100232b1f44545/partitions/f86f3bc0001a2f78/replicas/13085003638s"
let innerMessage: any = null; */
const singleLineMessage = message.replace(/[\r\n]|\r|\n/g, ""); let innerMessage: any = null;
try {
// Multi-Partition error flavor const singleLineMessage = message.replace(/[\r\n]|\r|\n/g, "");
const regExp = /^(.*)ActivityId: (.*)/g; try {
const regString = regExp.exec(singleLineMessage); // Multi-Partition error flavor
const innerMessageString = regString[1]; const regExp = /^(.*)ActivityId: (.*)/g;
innerMessage = JSON.parse(innerMessageString); const regString = regExp.exec(singleLineMessage);
} catch (e) { const innerMessageString = regString[1];
// Single-partition error flavor innerMessage = JSON.parse(innerMessageString);
const regExp = /^Message: (.*)ActivityId: (.*), Request URI: (.*)/g; } catch (e) {
const regString = regExp.exec(singleLineMessage); // Single-partition error flavor
const innerMessageString = regString[1]; const regExp = /^Message: (.*)ActivityId: (.*), Request URI: (.*)/g;
innerMessage = JSON.parse(innerMessageString); const regString = regExp.exec(singleLineMessage);
} const innerMessageString = regString[1];
innerMessage = JSON.parse(innerMessageString);
return innerMessage.errors ? innerMessage.errors : innerMessage.Errors; }
}
return innerMessage.errors ? innerMessage.errors : innerMessage.Errors;
}

View File

@ -373,12 +373,12 @@ describe("PricingUtils Tests", () => {
expect(value).toBe(1); expect(value).toBe(1);
}); });
it("should return 1 for -1", () => { it("should return -1 for -1", () => {
const value = PricingUtils.normalizeNumber(-1); const value = PricingUtils.normalizeNumber(-1);
expect(value).toBe(-1); expect(value).toBe(-1);
}); });
it("should return 1 for 0.1", () => { it("should return 0 for 0.1", () => {
const value = PricingUtils.normalizeNumber(0.1); const value = PricingUtils.normalizeNumber(0.1);
expect(value).toBe(0); expect(value).toBe(0);
}); });

View File

@ -7,10 +7,11 @@ import { AutopilotTier } from "../Contracts/DataModels";
* Otherwise, return numberOfRegions * Otherwise, return numberOfRegions
* @param number * @param number
*/ */
export function normalizeNumber(number: any): number { export function normalizeNumber(number: null | undefined | string | number): number {
const normalizedNumber: number = number === null ? 0 : isNaN(number) ? 0 : parseInt(number); if (!number) {
return 0;
return normalizedNumber; }
return Math.floor(Number(number));
} }
export function getRuToolTipText(isV2AutoPilot: boolean): string { export function getRuToolTipText(isV2AutoPilot: boolean): string {
@ -79,16 +80,16 @@ export function getPriceCurrency(serverId: string): string {
export function computeStorageUsagePrice(serverId: string, storageUsedRoundUpToGB: number): string { export function computeStorageUsagePrice(serverId: string, storageUsedRoundUpToGB: number): string {
if (serverId === "mooncake") { if (serverId === "mooncake") {
let storageCharge = storageUsedRoundUpToGB * Constants.OfferPricing.HourlyPricing.mooncake.Standard.PricePerGB; const storageCharge = storageUsedRoundUpToGB * Constants.OfferPricing.HourlyPricing.mooncake.Standard.PricePerGB;
return calculateEstimateNumber(storageCharge) + " " + Constants.OfferPricing.HourlyPricing.mooncake.Currency; return calculateEstimateNumber(storageCharge) + " " + Constants.OfferPricing.HourlyPricing.mooncake.Currency;
} }
let storageCharge = storageUsedRoundUpToGB * Constants.OfferPricing.HourlyPricing.default.Standard.PricePerGB; const storageCharge = storageUsedRoundUpToGB * Constants.OfferPricing.HourlyPricing.default.Standard.PricePerGB;
return calculateEstimateNumber(storageCharge) + " " + Constants.OfferPricing.HourlyPricing.default.Currency; return calculateEstimateNumber(storageCharge) + " " + Constants.OfferPricing.HourlyPricing.default.Currency;
} }
export function computeDisplayUsageString(usageInKB: number): string { export function computeDisplayUsageString(usageInKB: number): string {
let usageInMB = usageInKB / 1024, const usageInMB = usageInKB / 1024,
usageInGB = usageInMB / 1024, usageInGB = usageInMB / 1024,
displayUsageString = displayUsageString =
usageInGB > 0.1 usageInGB > 0.1
@ -100,7 +101,7 @@ export function computeDisplayUsageString(usageInKB: number): string {
} }
export function usageInGB(usageInKB: number): number { export function usageInGB(usageInKB: number): number {
let usageInMB = usageInKB / 1024, const usageInMB = usageInKB / 1024,
usageInGB = usageInMB / 1024; usageInGB = usageInMB / 1024;
return Math.ceil(usageInGB); return Math.ceil(usageInGB);
} }
@ -109,7 +110,7 @@ export function calculateEstimateNumber(n: number): string {
return n >= 1 ? n.toFixed(2) : n.toPrecision(2); return n >= 1 ? n.toFixed(2) : n.toPrecision(2);
} }
export function numberWithCommasFormatter(n: number) { export function numberWithCommasFormatter(n: number): string {
return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} }
@ -279,9 +280,9 @@ export function getEstimatedSpendAcknowledgeString(
)} - ${currencySign}${calculateEstimateNumber(monthlyPrice)} monthly cost for the throughput above.`; )} - ${currencySign}${calculateEstimateNumber(monthlyPrice)} monthly cost for the throughput above.`;
} }
export function getUpsellMessage(serverId: string = "default", isFreeTier: boolean = false): string { export function getUpsellMessage(serverId = "default", isFreeTier = false): string {
if (isFreeTier) { if (isFreeTier) {
return `With free tier discount, you'll get the first 400 RU/s and 5 GB of storage in this account for free. Charges will apply if your resource throughput exceeds 400 RU/s.`; return "With free tier discount, you'll get the first 400 RU/s and 5 GB of storage in this account for free. Charges will apply if your resource throughput exceeds 400 RU/s.";
} else { } else {
let price: number = Constants.OfferPricing.MonthlyPricing.default.Standard.StartingPrice; let price: number = Constants.OfferPricing.MonthlyPricing.default.Standard.StartingPrice;