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
This commit is contained in:
vchske 2020-07-08 10:02:47 -07:00 committed by GitHub
parent 512f56c28a
commit 955d08e4d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 132 additions and 18 deletions

View File

@ -15,7 +15,7 @@
.infoBoxMessage { .infoBoxMessage {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: normal;
width: 320px; width: 320px;
padding-top: 2px; padding-top: 2px;
color: @BaseHigh; color: @BaseHigh;

View File

@ -374,6 +374,8 @@ export class HttpStatusCodes {
export class Urls { export class Urls {
public static feedbackEmail = "https://aka.ms/cosmosdbfeedback?subject=Cosmos%20DB%20Data%20Explorer%20Feedback"; public static feedbackEmail = "https://aka.ms/cosmosdbfeedback?subject=Cosmos%20DB%20Data%20Explorer%20Feedback";
public static autoscaleMigration = "https://aka.ms/cosmos-autoscale-migration"; 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 { export class HashRoutePrefixes {

View File

@ -61,9 +61,8 @@
<span><img class="infoBoxIcon" src="/info_color.svg" alt="Promo"></span> <span><img class="infoBoxIcon" src="/info_color.svg" alt="Promo"></span>
<span class="infoBoxDetails"> <span class="infoBoxDetails">
<span class="infoBoxMessage" data-bind="text: upsellMessage, attr: { title: upsellMessage }"></span> <span class="infoBoxMessage" data-bind="text: upsellMessage, attr: { title: upsellMessage }"></span>
<a class="underlinedLink" id="linkAddCollection" data-bind="attr: { 'aria-label': upsellMessageAriaLabel }" <a class="underlinedLink" id="linkAddCollection" data-bind="text: upsellAnchorText, attr: { 'href': upsellAnchorUrl, 'aria-label': upsellMessageAriaLabel }"
target="_blank" href="https://aka.ms/azure-cosmos-db-pricing" tabindex="0"> target="_blank" href="" tabindex="0"></a>
More details</a>
</span> </span>
</div> </div>
</div> </div>

View File

@ -13,7 +13,29 @@ describe("Add Collection Pane", () => {
kind: "DocumentDB", kind: "DocumentDB",
location: "", location: "",
name: "mock", 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, type: undefined,
tags: [] tags: []
}; };
@ -68,5 +90,23 @@ describe("Add Collection Pane", () => {
addCollectionPane.partitionKey("/label"); addCollectionPane.partitionKey("/label");
expect(addCollectionPane.isValid()).toBe(true); 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");
});
}); });
}); });

View File

@ -69,6 +69,8 @@ export default class AddCollectionPane extends ContextualPaneBase implements Vie
public uniqueKeysPlaceholder: ko.Computed<string>; public uniqueKeysPlaceholder: ko.Computed<string>;
public upsellMessage: ko.PureComputed<string>; public upsellMessage: ko.PureComputed<string>;
public upsellMessageAriaLabel: ko.PureComputed<string>; public upsellMessageAriaLabel: ko.PureComputed<string>;
public upsellAnchorUrl: ko.PureComputed<string>;
public upsellAnchorText: ko.PureComputed<string>;
public debugstring: ko.Computed<string>; public debugstring: ko.Computed<string>;
public displayCollectionThroughput: ko.Computed<boolean>; public displayCollectionThroughput: ko.Computed<boolean>;
public isAutoPilotSelected: ko.Observable<boolean>; public isAutoPilotSelected: ko.Observable<boolean>;
@ -508,11 +510,19 @@ export default class AddCollectionPane extends ContextualPaneBase implements Vie
}); });
this.upsellMessage = ko.pureComputed<string>(() => { this.upsellMessage = ko.pureComputed<string>(() => {
return PricingUtils.getUpsellMessage(this.container.serverId()); return PricingUtils.getUpsellMessage(this.container.serverId(), this.isFreeTierAccount());
}); });
this.upsellMessageAriaLabel = ko.pureComputed<string>(() => { this.upsellMessageAriaLabel = ko.pureComputed<string>(() => {
return `${this.upsellMessage()}. Click for more details`; return `${this.upsellMessage()}. Click ${this.isFreeTierAccount() ? "to learn more" : "for more details"}`;
});
this.upsellAnchorUrl = ko.pureComputed<string>(() => {
return this.isFreeTierAccount() ? Constants.Urls.freeTierInformation : Constants.Urls.cosmosPricing;
});
this.upsellAnchorText = ko.pureComputed<string>(() => {
return this.isFreeTierAccount() ? "Learn more" : "More details";
}); });
this.displayCollectionThroughput = ko.computed<boolean>(() => { this.displayCollectionThroughput = ko.computed<boolean>(() => {

View File

@ -53,9 +53,8 @@
<span><img class="infoBoxIcon" src="/info_color.svg" alt="Promo"></span> <span><img class="infoBoxIcon" src="/info_color.svg" alt="Promo"></span>
<span class="infoBoxDetails"> <span class="infoBoxDetails">
<span class="infoBoxMessage" data-bind="text: upsellMessage, attr: { title: upsellMessage }"></span> <span class="infoBoxMessage" data-bind="text: upsellMessage, attr: { title: upsellMessage }"></span>
<a class="underlinedLink" id="linkAddDatabase" data-bind="attr: { 'aria-label': upsellMessageAriaLabel }" <a class="underlinedLink" id="linkAddDatabase" data-bind="text: upsellAnchorText, attr: { 'href': upsellAnchorUrl, 'aria-label': upsellMessageAriaLabel }"
target="_blank" href="https://aka.ms/azure-cosmos-db-pricing" tabindex="0"> target="_blank" href="" tabindex="0"></a>
More details</a>
</span> </span>
</div> </div>
</div> </div>

View File

@ -1,3 +1,4 @@
import * as Constants from "../../Common/Constants";
import * as ViewModels from "../../Contracts/ViewModels"; import * as ViewModels from "../../Contracts/ViewModels";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import AddDatabasePane from "./AddDatabasePane"; import AddDatabasePane from "./AddDatabasePane";
@ -5,6 +6,37 @@ import AddDatabasePane from "./AddDatabasePane";
describe("Add Database Pane", () => { describe("Add Database Pane", () => {
describe("getSharedThroughputDefault()", () => { describe("getSharedThroughputDefault()", () => {
let explorer: ViewModels.Explorer; 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(() => { beforeEach(() => {
explorer = new Explorer({ explorer = new Explorer({
@ -43,5 +75,23 @@ describe("Add Database Pane", () => {
const addDatabasePane = explorer.addDatabasePane as AddDatabasePane; const addDatabasePane = explorer.addDatabasePane as AddDatabasePane;
expect(addDatabasePane.getSharedThroughputDefault()).toBe(true); 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");
});
}); });
}); });

View File

@ -38,6 +38,8 @@ export default class AddDatabasePane extends ContextualPaneBase implements ViewM
public costsVisible: ko.PureComputed<boolean>; public costsVisible: ko.PureComputed<boolean>;
public upsellMessage: ko.PureComputed<string>; public upsellMessage: ko.PureComputed<string>;
public upsellMessageAriaLabel: ko.PureComputed<string>; public upsellMessageAriaLabel: ko.PureComputed<string>;
public upsellAnchorUrl: ko.PureComputed<string>;
public upsellAnchorText: ko.PureComputed<string>;
public isAutoPilotSelected: ko.Observable<boolean>; public isAutoPilotSelected: ko.Observable<boolean>;
public selectedAutoPilotTier: ko.Observable<DataModels.AutopilotTier>; public selectedAutoPilotTier: ko.Observable<DataModels.AutopilotTier>;
public autoPilotTiersList: ko.ObservableArray<ViewModels.DropdownOption<DataModels.AutopilotTier>>; public autoPilotTiersList: ko.ObservableArray<ViewModels.DropdownOption<DataModels.AutopilotTier>>;
@ -228,11 +230,19 @@ export default class AddDatabasePane extends ContextualPaneBase implements ViewM
}); });
this.upsellMessage = ko.pureComputed<string>(() => { this.upsellMessage = ko.pureComputed<string>(() => {
return PricingUtils.getUpsellMessage(this.container.serverId()); return PricingUtils.getUpsellMessage(this.container.serverId(), this.isFreeTierAccount());
}); });
this.upsellMessageAriaLabel = ko.pureComputed<string>(() => { this.upsellMessageAriaLabel = ko.pureComputed<string>(() => {
return `${this.upsellMessage()}. Click for more details`; return `${this.upsellMessage()}. Click ${this.isFreeTierAccount() ? "to learn more" : "for more details"}`;
});
this.upsellAnchorUrl = ko.pureComputed<string>(() => {
return this.isFreeTierAccount() ? Constants.Urls.freeTierInformation : Constants.Urls.cosmosPricing;
});
this.upsellAnchorText = ko.pureComputed<string>(() => {
return this.isFreeTierAccount() ? "Learn more" : "More details";
}); });
} }

View File

@ -279,12 +279,16 @@ 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"): string { export function getUpsellMessage(serverId: string = "default", isFreeTier: boolean = false): string {
let price: number = Constants.OfferPricing.MonthlyPricing.default.Standard.StartingPrice; 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") { if (serverId === "mooncake") {
price = Constants.OfferPricing.MonthlyPricing.mooncake.Standard.StartingPrice; 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`;
} }