From 955d08e4d0722aa0ef2610ca18e4084ed0a90e1c Mon Sep 17 00:00:00 2001 From: vchske Date: Wed, 8 Jul 2020 10:02:47 -0700 Subject: [PATCH] Added a different message if the account is free tier (#69) * Added a different upsell message if the account is free tier * Fixing prettier and unit tests --- less/infobox.less | 2 +- src/Common/Constants.ts | 2 + src/Explorer/Panes/AddCollectionPane.html | 5 +- src/Explorer/Panes/AddCollectionPane.test.ts | 42 +++++++++++++++- src/Explorer/Panes/AddCollectionPane.ts | 14 +++++- src/Explorer/Panes/AddDatabasePane.html | 5 +- src/Explorer/Panes/AddDatabasePane.test.ts | 50 ++++++++++++++++++++ src/Explorer/Panes/AddDatabasePane.ts | 14 +++++- src/Utils/PricingUtils.ts | 16 ++++--- 9 files changed, 132 insertions(+), 18 deletions(-) diff --git a/less/infobox.less b/less/infobox.less index a58666850..01c421b0e 100644 --- a/less/infobox.less +++ b/less/infobox.less @@ -15,7 +15,7 @@ .infoBoxMessage { overflow: hidden; text-overflow: ellipsis; - white-space: nowrap; + white-space: normal; width: 320px; padding-top: 2px; color: @BaseHigh; diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index 11ef3c9dc..860c74317 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -374,6 +374,8 @@ export class HttpStatusCodes { export class Urls { public static feedbackEmail = "https://aka.ms/cosmosdbfeedback?subject=Cosmos%20DB%20Data%20Explorer%20Feedback"; public static autoscaleMigration = "https://aka.ms/cosmos-autoscale-migration"; + public static freeTierInformation = "https://aka.ms/cosmos-free-tier"; + public static cosmosPricing = "https://aka.ms/azure-cosmos-db-pricing"; } export class HashRoutePrefixes { diff --git a/src/Explorer/Panes/AddCollectionPane.html b/src/Explorer/Panes/AddCollectionPane.html index 0ef820d02..58d7cd3ef 100644 --- a/src/Explorer/Panes/AddCollectionPane.html +++ b/src/Explorer/Panes/AddCollectionPane.html @@ -61,9 +61,8 @@ Promo - - More details + diff --git a/src/Explorer/Panes/AddCollectionPane.test.ts b/src/Explorer/Panes/AddCollectionPane.test.ts index e6552a2c3..abdf7194f 100644 --- a/src/Explorer/Panes/AddCollectionPane.test.ts +++ b/src/Explorer/Panes/AddCollectionPane.test.ts @@ -13,7 +13,29 @@ describe("Add Collection Pane", () => { kind: "DocumentDB", location: "", name: "mock", - properties: undefined, + properties: { + documentEndpoint: "", + cassandraEndpoint: "", + gremlinEndpoint: "", + tableEndpoint: "", + enableFreeTier: false + }, + type: undefined, + tags: [] + }; + + const mockFreeTierDatabaseAccount: ViewModels.DatabaseAccount = { + id: "mock", + kind: "DocumentDB", + location: "", + name: "mock", + properties: { + documentEndpoint: "", + cassandraEndpoint: "", + gremlinEndpoint: "", + tableEndpoint: "", + enableFreeTier: true + }, type: undefined, tags: [] }; @@ -68,5 +90,23 @@ describe("Add Collection Pane", () => { addCollectionPane.partitionKey("/label"); expect(addCollectionPane.isValid()).toBe(true); }); + + it("should display free tier text in upsell messaging", () => { + explorer.databaseAccount(mockFreeTierDatabaseAccount); + const addCollectionPane = explorer.addCollectionPane as AddCollectionPane; + expect(addCollectionPane.isFreeTierAccount()).toBe(true); + expect(addCollectionPane.upsellMessage()).toContain("With free tier discount"); + expect(addCollectionPane.upsellAnchorUrl()).toBe(Constants.Urls.freeTierInformation); + expect(addCollectionPane.upsellAnchorText()).toBe("Learn more"); + }); + + it("should display standard texr in upsell messaging", () => { + explorer.databaseAccount(mockDatabaseAccount); + const addCollectionPane = explorer.addCollectionPane as AddCollectionPane; + expect(addCollectionPane.isFreeTierAccount()).toBe(false); + expect(addCollectionPane.upsellMessage()).toContain("Start at"); + expect(addCollectionPane.upsellAnchorUrl()).toBe(Constants.Urls.cosmosPricing); + expect(addCollectionPane.upsellAnchorText()).toBe("More details"); + }); }); }); diff --git a/src/Explorer/Panes/AddCollectionPane.ts b/src/Explorer/Panes/AddCollectionPane.ts index 6b896e741..5df974ffa 100644 --- a/src/Explorer/Panes/AddCollectionPane.ts +++ b/src/Explorer/Panes/AddCollectionPane.ts @@ -69,6 +69,8 @@ export default class AddCollectionPane extends ContextualPaneBase implements Vie public uniqueKeysPlaceholder: ko.Computed; public upsellMessage: ko.PureComputed; public upsellMessageAriaLabel: ko.PureComputed; + public upsellAnchorUrl: ko.PureComputed; + public upsellAnchorText: ko.PureComputed; public debugstring: ko.Computed; public displayCollectionThroughput: ko.Computed; public isAutoPilotSelected: ko.Observable; @@ -508,11 +510,19 @@ export default class AddCollectionPane extends ContextualPaneBase implements Vie }); this.upsellMessage = ko.pureComputed(() => { - return PricingUtils.getUpsellMessage(this.container.serverId()); + return PricingUtils.getUpsellMessage(this.container.serverId(), this.isFreeTierAccount()); }); this.upsellMessageAriaLabel = ko.pureComputed(() => { - return `${this.upsellMessage()}. Click for more details`; + return `${this.upsellMessage()}. Click ${this.isFreeTierAccount() ? "to learn more" : "for more details"}`; + }); + + this.upsellAnchorUrl = ko.pureComputed(() => { + return this.isFreeTierAccount() ? Constants.Urls.freeTierInformation : Constants.Urls.cosmosPricing; + }); + + this.upsellAnchorText = ko.pureComputed(() => { + return this.isFreeTierAccount() ? "Learn more" : "More details"; }); this.displayCollectionThroughput = ko.computed(() => { diff --git a/src/Explorer/Panes/AddDatabasePane.html b/src/Explorer/Panes/AddDatabasePane.html index fdc601f13..e652ce7bf 100644 --- a/src/Explorer/Panes/AddDatabasePane.html +++ b/src/Explorer/Panes/AddDatabasePane.html @@ -53,9 +53,8 @@ Promo - - More details + diff --git a/src/Explorer/Panes/AddDatabasePane.test.ts b/src/Explorer/Panes/AddDatabasePane.test.ts index 8816d70be..bee4e9f06 100644 --- a/src/Explorer/Panes/AddDatabasePane.test.ts +++ b/src/Explorer/Panes/AddDatabasePane.test.ts @@ -1,3 +1,4 @@ +import * as Constants from "../../Common/Constants"; import * as ViewModels from "../../Contracts/ViewModels"; import Explorer from "../Explorer"; import AddDatabasePane from "./AddDatabasePane"; @@ -5,6 +6,37 @@ import AddDatabasePane from "./AddDatabasePane"; describe("Add Database Pane", () => { describe("getSharedThroughputDefault()", () => { let explorer: ViewModels.Explorer; + const mockDatabaseAccount: ViewModels.DatabaseAccount = { + id: "mock", + kind: "DocumentDB", + location: "", + name: "mock", + properties: { + documentEndpoint: "", + cassandraEndpoint: "", + gremlinEndpoint: "", + tableEndpoint: "", + enableFreeTier: false + }, + type: undefined, + tags: [] + }; + + const mockFreeTierDatabaseAccount: ViewModels.DatabaseAccount = { + id: "mock", + kind: "DocumentDB", + location: "", + name: "mock", + properties: { + documentEndpoint: "", + cassandraEndpoint: "", + gremlinEndpoint: "", + tableEndpoint: "", + enableFreeTier: true + }, + type: undefined, + tags: [] + }; beforeEach(() => { explorer = new Explorer({ @@ -43,5 +75,23 @@ describe("Add Database Pane", () => { const addDatabasePane = explorer.addDatabasePane as AddDatabasePane; expect(addDatabasePane.getSharedThroughputDefault()).toBe(true); }); + + it("should display free tier text in upsell messaging", () => { + explorer.databaseAccount(mockFreeTierDatabaseAccount); + const addDatabasePane = explorer.addDatabasePane as AddDatabasePane; + expect(addDatabasePane.isFreeTierAccount()).toBe(true); + expect(addDatabasePane.upsellMessage()).toContain("With free tier discount"); + expect(addDatabasePane.upsellAnchorUrl()).toBe(Constants.Urls.freeTierInformation); + expect(addDatabasePane.upsellAnchorText()).toBe("Learn more"); + }); + + it("should display standard texr in upsell messaging", () => { + explorer.databaseAccount(mockDatabaseAccount); + const addDatabasePane = explorer.addDatabasePane as AddDatabasePane; + expect(addDatabasePane.isFreeTierAccount()).toBe(false); + expect(addDatabasePane.upsellMessage()).toContain("Start at"); + expect(addDatabasePane.upsellAnchorUrl()).toBe(Constants.Urls.cosmosPricing); + expect(addDatabasePane.upsellAnchorText()).toBe("More details"); + }); }); }); diff --git a/src/Explorer/Panes/AddDatabasePane.ts b/src/Explorer/Panes/AddDatabasePane.ts index 4288a7062..8cb20d708 100644 --- a/src/Explorer/Panes/AddDatabasePane.ts +++ b/src/Explorer/Panes/AddDatabasePane.ts @@ -38,6 +38,8 @@ export default class AddDatabasePane extends ContextualPaneBase implements ViewM public costsVisible: ko.PureComputed; public upsellMessage: ko.PureComputed; public upsellMessageAriaLabel: ko.PureComputed; + public upsellAnchorUrl: ko.PureComputed; + public upsellAnchorText: ko.PureComputed; public isAutoPilotSelected: ko.Observable; public selectedAutoPilotTier: ko.Observable; public autoPilotTiersList: ko.ObservableArray>; @@ -228,11 +230,19 @@ export default class AddDatabasePane extends ContextualPaneBase implements ViewM }); this.upsellMessage = ko.pureComputed(() => { - return PricingUtils.getUpsellMessage(this.container.serverId()); + return PricingUtils.getUpsellMessage(this.container.serverId(), this.isFreeTierAccount()); }); this.upsellMessageAriaLabel = ko.pureComputed(() => { - return `${this.upsellMessage()}. Click for more details`; + return `${this.upsellMessage()}. Click ${this.isFreeTierAccount() ? "to learn more" : "for more details"}`; + }); + + this.upsellAnchorUrl = ko.pureComputed(() => { + return this.isFreeTierAccount() ? Constants.Urls.freeTierInformation : Constants.Urls.cosmosPricing; + }); + + this.upsellAnchorText = ko.pureComputed(() => { + return this.isFreeTierAccount() ? "Learn more" : "More details"; }); } diff --git a/src/Utils/PricingUtils.ts b/src/Utils/PricingUtils.ts index ae69581f8..35cddd422 100644 --- a/src/Utils/PricingUtils.ts +++ b/src/Utils/PricingUtils.ts @@ -279,12 +279,16 @@ export function getEstimatedSpendAcknowledgeString( )} - ${currencySign}${calculateEstimateNumber(monthlyPrice)} monthly cost for the throughput above.`; } -export function getUpsellMessage(serverId: string = "default"): string { - let price: number = Constants.OfferPricing.MonthlyPricing.default.Standard.StartingPrice; +export function getUpsellMessage(serverId: string = "default", isFreeTier: boolean = false): string { + 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.`; + } else { + let price: number = Constants.OfferPricing.MonthlyPricing.default.Standard.StartingPrice; - if (serverId === "mooncake") { - price = Constants.OfferPricing.MonthlyPricing.mooncake.Standard.StartingPrice; + if (serverId === "mooncake") { + price = Constants.OfferPricing.MonthlyPricing.mooncake.Standard.StartingPrice; + } + + return `Start at ${getCurrencySign(serverId)}${price}/mo per database, multiple containers included`; } - - return `Start at ${getCurrencySign(serverId)}${price}/mo per database, multiple containers included`; }