Support serverless accounts (#109)
* Changes for serverless accounts * Dont show upsell message for serverless accounts * Update CassandraAddCollectionPane to support serverless
This commit is contained in:
parent
dc67c5f40b
commit
33969581ac
|
@ -101,6 +101,7 @@ export class CapabilityNames {
|
|||
public static readonly EnableNotebooks: string = "EnableNotebooks";
|
||||
public static readonly EnableStorageAnalytics: string = "EnableStorageAnalytics";
|
||||
public static readonly EnableMongo: string = "EnableMongo";
|
||||
public static readonly EnableServerless: string = "EnableServerless";
|
||||
}
|
||||
|
||||
export class Features {
|
||||
|
|
|
@ -118,6 +118,7 @@ export default class Explorer {
|
|||
public isPreferredApiGraph: ko.Computed<boolean>;
|
||||
public isPreferredApiTable: ko.Computed<boolean>;
|
||||
public isFixedCollectionWithSharedThroughputSupported: ko.Computed<boolean>;
|
||||
public isServerlessEnabled: ko.Computed<boolean>;
|
||||
public isEmulator: boolean;
|
||||
public isAccountReady: ko.Observable<boolean>;
|
||||
public canSaveQueries: ko.Computed<boolean>;
|
||||
|
@ -509,6 +510,14 @@ export default class Explorer {
|
|||
return false;
|
||||
});
|
||||
|
||||
this.isServerlessEnabled = ko.computed(
|
||||
() =>
|
||||
this.databaseAccount &&
|
||||
this.databaseAccount()?.properties?.capabilities?.find(
|
||||
item => item.name === Constants.CapabilityNames.EnableServerless
|
||||
) !== undefined
|
||||
);
|
||||
|
||||
this.isPreferredApiMongoDB = ko.computed(() => {
|
||||
const defaultExperience = (this.defaultExperience && this.defaultExperience()) || "";
|
||||
if (defaultExperience.toLowerCase() === Constants.DefaultAccountExperience.MongoDB.toLowerCase()) {
|
||||
|
@ -1406,14 +1415,11 @@ export default class Explorer {
|
|||
dataExplorerArea: Constants.Areas.ResourceTree
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Refactor
|
||||
const deferred: Q.Deferred<any> = Q.defer();
|
||||
const offerPromise: Q.Promise<DataModels.Offer[]> = this.documentClientUtility.readOffers();
|
||||
this._setLoadingStatusText("Fetching offers...");
|
||||
|
||||
offerPromise.then(
|
||||
(offers: DataModels.Offer[]) => {
|
||||
this._setLoadingStatusText("Successfully fetched offers.");
|
||||
const refreshDatabases = (offers?: DataModels.Offer[]) => {
|
||||
this._setLoadingStatusText("Fetching databases...");
|
||||
this.documentClientUtility.readDatabases(null /*options*/).then(
|
||||
(databases: DataModels.Database[]) => {
|
||||
|
@ -1466,6 +1472,18 @@ export default class Explorer {
|
|||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
if (this.isServerlessEnabled()) {
|
||||
// Serverless accounts don't support offers call
|
||||
refreshDatabases();
|
||||
} else {
|
||||
const offerPromise: Q.Promise<DataModels.Offer[]> = this.documentClientUtility.readOffers();
|
||||
this._setLoadingStatusText("Fetching offers...");
|
||||
offerPromise.then(
|
||||
(offers: DataModels.Offer[]) => {
|
||||
this._setLoadingStatusText("Successfully fetched offers.");
|
||||
refreshDatabases(offers);
|
||||
},
|
||||
error => {
|
||||
this._setLoadingStatusText("Failed to fetch offers.");
|
||||
|
@ -1487,6 +1505,7 @@ export default class Explorer {
|
|||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return deferred.promise.then(
|
||||
() => {
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<!-- Add collection errors - End -->
|
||||
|
||||
<!-- upsell message - start -->
|
||||
<div class="infoBoxContainer" aria-live="assertive" data-bind="visible: formErrors && !formErrors()">
|
||||
<div class="infoBoxContainer" aria-live="assertive" data-bind="visible: showUpsellMessage && showUpsellMessage() && formErrors && !formErrors()">
|
||||
<div class="infoBoxContent">
|
||||
<span><img class="infoBoxIcon" src="/info_color.svg" alt="Promo"></span>
|
||||
<span class="infoBoxDetails">
|
||||
|
@ -112,7 +112,9 @@
|
|||
<datalist id="databasesList" data-bind="foreach: databaseIds" data-bind="visible: databaseCreateNew">
|
||||
<option data-bind="value: $data">
|
||||
</datalist>
|
||||
|
||||
<!-- Database provisioned throughput - Start -->
|
||||
<!-- ko if: canConfigureThroughput -->
|
||||
<div class="databaseProvision" aria-label="New database provision support"
|
||||
data-bind="visible: databaseCreateNew">
|
||||
<input tabindex="0" type="checkbox" data-test="addCollectionPane-databaseSharedThroughput"
|
||||
|
@ -187,6 +189,7 @@
|
|||
</throughput-input>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
<!-- Database provisioned throughput - End -->
|
||||
</div>
|
||||
|
||||
|
@ -414,7 +417,10 @@
|
|||
more</a></p>
|
||||
</div>
|
||||
<!-- large parition key - end -->
|
||||
<!-- Provision collection throughput checkox - start -->
|
||||
|
||||
<!-- Provision collection throughput - start -->
|
||||
<!-- ko if: canConfigureThroughput -->
|
||||
<!-- Provision collection throughput checkbox - start -->
|
||||
<div class="pkPadding" data-bind="visible: databaseHasSharedOffer() && !databaseCreateNew()">
|
||||
<input type="checkbox" id="collectionSharedThroughput"
|
||||
data-bind="checked: collectionWithThroughputInShared, attr: {title:collectionWithThroughputInSharedTitle}" />
|
||||
|
@ -434,7 +440,8 @@
|
|||
level.</span>
|
||||
</span>
|
||||
</div>
|
||||
<!-- Provision collection throughput checkox - end -->
|
||||
<!-- Provision collection throughput checkbox - end -->
|
||||
|
||||
<!-- Provision collection throughput spinner - start -->
|
||||
<!-- ko if: hasAutoPilotV2FeatureFlag && !hasAutoPilotV2FeatureFlag() -->
|
||||
<div data-bind="visible: displayCollectionThroughput" data-test="addCollection-displayCollectionThroughput">
|
||||
|
@ -467,6 +474,7 @@
|
|||
</throughput-input-autopilot-v3>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- ko if: hasAutoPilotV2FeatureFlag && hasAutoPilotV2FeatureFlag() -->
|
||||
<div data-bind="visible: displayCollectionThroughput" data-test="addCollection-displayCollectionThroughput">
|
||||
<!-- 3 -->
|
||||
|
@ -499,8 +507,10 @@
|
|||
</throughput-input>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
|
||||
<!-- Provision collection throughput spinner - end -->
|
||||
<!-- /ko -->
|
||||
<!-- Provision collection throughput - end -->
|
||||
|
||||
<!-- Enable analytical storage - start -->
|
||||
<div class="enableAnalyticalStorage pkPadding" aria-label="Enable Analytical Store"
|
||||
data-bind="visible: isSynapseLinkSupported">
|
||||
|
|
|
@ -93,6 +93,8 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||
public canExceedMaximumValue: ko.PureComputed<boolean>;
|
||||
public hasAutoPilotV2FeatureFlag: ko.PureComputed<boolean>;
|
||||
public ruToolTipText: ko.Computed<string>;
|
||||
public canConfigureThroughput: ko.PureComputed<boolean>;
|
||||
public showUpsellMessage: ko.PureComputed<boolean>;
|
||||
|
||||
private _databaseOffers: HashMap<DataModels.Offer>;
|
||||
private _isSynapseLinkEnabled: ko.Computed<boolean>;
|
||||
|
@ -102,6 +104,8 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||
this._databaseOffers = new HashMap<DataModels.Offer>();
|
||||
this.hasAutoPilotV2FeatureFlag = ko.pureComputed(() => this.container.hasAutoPilotV2FeatureFlag());
|
||||
this.ruToolTipText = ko.pureComputed(() => PricingUtils.getRuToolTipText(this.hasAutoPilotV2FeatureFlag()));
|
||||
this.canConfigureThroughput = ko.pureComputed(() => !this.container.isServerlessEnabled());
|
||||
this.showUpsellMessage = ko.pureComputed(() => !this.container.isServerlessEnabled());
|
||||
this.formWarnings = ko.observable<string>();
|
||||
this.collectionId = ko.observable<string>();
|
||||
this.databaseId = ko.observable<string>();
|
||||
|
@ -591,6 +595,11 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||
if (config.platform === Platform.Emulator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.container.isServerlessEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.container.isPreferredApiDocumentDB()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -723,10 +732,19 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||
}
|
||||
|
||||
private _computeOfferThroughput(): number {
|
||||
if (this.databaseCreateNewShared()) {
|
||||
return this.isSharedAutoPilotSelected() ? undefined : this._getThroughput();
|
||||
if (!this.canConfigureThroughput()) {
|
||||
return undefined;
|
||||
}
|
||||
return this.isAutoPilotSelected() ? undefined : this._getThroughput();
|
||||
|
||||
if (this.isAutoPilotSelected()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (this.databaseCreateNewShared() && this.isSharedAutoPilotSelected()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this._getThroughput();
|
||||
}
|
||||
|
||||
public submit() {
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<!-- Add database errors - End -->
|
||||
|
||||
<!-- upsell message - start -->
|
||||
<div class="infoBoxContainer" aria-live="assertive" data-bind="visible: formErrors && !formErrors()">
|
||||
<div class="infoBoxContainer" aria-live="assertive" data-bind="visible: showUpsellMessage && showUpsellMessage() && formErrors && !formErrors()">
|
||||
<div class="infoBoxContent">
|
||||
<span><img class="infoBoxIcon" src="/info_color.svg" alt="Promo"></span>
|
||||
<span class="infoBoxDetails">
|
||||
|
@ -76,6 +76,9 @@
|
|||
title="May not end with space nor contain characters '\' '/' '#' '?'" placeholder="Type a new database id"
|
||||
size="40" class="collid" data-bind="textInput: databaseId, hasFocus: firstFieldHasFocus"
|
||||
aria-label="Database id" autofocus>
|
||||
|
||||
<!-- Database provisioned throughput - Start -->
|
||||
<!-- ko if: canConfigureThroughput -->
|
||||
<div class="databaseProvision" aria-label="New database provision support">
|
||||
<input tabindex="0" type="checkbox" id="addDatabasePane-databaseSharedThroughput"
|
||||
title="Provision shared throughput" data-bind="checked: databaseCreateNewShared" />
|
||||
|
@ -156,6 +159,7 @@
|
|||
support</a> for more than <span data-bind="text: maxThroughputRUText"></span> RU/s.</p>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
<!-- Database provisioned throughput - End -->
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -49,6 +49,8 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
public hasAutoPilotV2FeatureFlag: ko.PureComputed<boolean>;
|
||||
public ruToolTipText: ko.Computed<string>;
|
||||
public isFreeTierAccount: ko.Computed<boolean>;
|
||||
public canConfigureThroughput: ko.PureComputed<boolean>;
|
||||
public showUpsellMessage: ko.PureComputed<boolean>;
|
||||
|
||||
constructor(options: ViewModels.PaneOptions) {
|
||||
super(options);
|
||||
|
@ -56,6 +58,8 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
this.databaseId = ko.observable<string>();
|
||||
this.hasAutoPilotV2FeatureFlag = ko.pureComputed(() => this.container.hasAutoPilotV2FeatureFlag());
|
||||
this.ruToolTipText = ko.pureComputed(() => PricingUtils.getRuToolTipText(this.hasAutoPilotV2FeatureFlag()));
|
||||
this.canConfigureThroughput = ko.pureComputed(() => !this.container.isServerlessEnabled());
|
||||
this.showUpsellMessage = ko.pureComputed(() => !this.container.isServerlessEnabled());
|
||||
|
||||
this.canExceedMaximumValue = ko.pureComputed(() => this.container.canExceedMaximumValue());
|
||||
|
||||
|
@ -522,7 +526,15 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
}
|
||||
|
||||
private _computeOfferThroughput(): number {
|
||||
return this.isAutoPilotSelected() ? undefined : this._getThroughput();
|
||||
if (!this.canConfigureThroughput()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (this.isAutoPilotSelected()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this._getThroughput();
|
||||
}
|
||||
|
||||
private _isValid(): boolean {
|
||||
|
|
|
@ -118,6 +118,8 @@
|
|||
<option data-bind="value: $data.id"> </option>
|
||||
</datalist>
|
||||
|
||||
<!-- Database provisioned throughput - Start -->
|
||||
<!-- ko if: canConfigureThroughput -->
|
||||
<div
|
||||
class="databaseProvision"
|
||||
aria-label="New database provision support"
|
||||
|
@ -202,6 +204,8 @@
|
|||
</throughput-input>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
<!-- Database provisioned throughput - End -->
|
||||
</div>
|
||||
<div class="seconddivpadding">
|
||||
<p>
|
||||
|
@ -231,6 +235,9 @@
|
|||
style="height:125px; width: calc(100% - 80px); resize: vertical;"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<!-- Provision table throughput - start -->
|
||||
<!-- ko if: canConfigureThroughput -->
|
||||
<div class="seconddivpadding" data-bind="visible: keyspaceHasSharedOffer() && !keyspaceCreateNew()">
|
||||
<input
|
||||
type="checkbox"
|
||||
|
@ -315,6 +322,8 @@
|
|||
</throughput-input>
|
||||
</div>
|
||||
<!-- /ko -->
|
||||
<!-- /ko -->
|
||||
<!-- Provision table throughput - end -->
|
||||
</div>
|
||||
<div class="paneFooter">
|
||||
<div class="leftpanel-okbut">
|
||||
|
|
|
@ -51,6 +51,7 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||
public hasAutoPilotV2FeatureFlag: ko.PureComputed<boolean>;
|
||||
public isFreeTierAccount: ko.Computed<boolean>;
|
||||
public ruToolTipText: ko.Computed<string>;
|
||||
public canConfigureThroughput: ko.PureComputed<boolean>;
|
||||
|
||||
private keyspaceOffers: HashMap<DataModels.Offer>;
|
||||
|
||||
|
@ -61,6 +62,7 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||
this.keyspaceCreateNew = ko.observable<boolean>(true);
|
||||
this.hasAutoPilotV2FeatureFlag = ko.pureComputed(() => this.container.hasAutoPilotV2FeatureFlag());
|
||||
this.ruToolTipText = ko.pureComputed(() => PricingUtils.getRuToolTipText(this.hasAutoPilotV2FeatureFlag()));
|
||||
this.canConfigureThroughput = ko.pureComputed(() => !this.container.isServerlessEnabled());
|
||||
this.keyspaceOffers = new HashMap<DataModels.Offer>();
|
||||
this.keyspaceIds = ko.observableArray<string>();
|
||||
this.keyspaceHasSharedOffer = ko.observable<boolean>(false);
|
||||
|
@ -365,7 +367,7 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||
const createTableQueryPrefix: string = `${this.createTableQuery()}${this.tableId().trim()} ${this.userTableQuery()}`;
|
||||
let createTableQuery: string;
|
||||
|
||||
if (this.dedicateTableThroughput() || !this.keyspaceHasSharedOffer()) {
|
||||
if (this.canConfigureThroughput() && (this.dedicateTableThroughput() || !this.keyspaceHasSharedOffer())) {
|
||||
if (this.isAutoPilotSelected() && this.selectedAutoPilotThroughput()) {
|
||||
createTableQuery = `${createTableQueryPrefix} WITH ${autoPilotCommand}=${this.selectedAutoPilotThroughput()};`;
|
||||
} else {
|
||||
|
|
|
@ -553,7 +553,7 @@ export default class Collection implements ViewModels.Collection {
|
|||
dataExplorerArea: Constants.Areas.ResourceTree
|
||||
});
|
||||
|
||||
const tabTitle = "Scale & Settings";
|
||||
const tabTitle = !this.offer() ? "Settings" : "Scale & Settings";
|
||||
const pendingNotificationsPromise: Q.Promise<DataModels.Notification> = this._getPendingThroughputSplitNotification();
|
||||
const matchingTabs: ViewModels.Tab[] = this.container.tabsManager.getTabs(
|
||||
ViewModels.CollectionTabKind.Settings,
|
||||
|
@ -561,6 +561,7 @@ export default class Collection implements ViewModels.Collection {
|
|||
return tab.collection && tab.collection.rid === this.rid;
|
||||
}
|
||||
);
|
||||
|
||||
let settingsTab: SettingsTab = matchingTabs && (matchingTabs[0] as SettingsTab);
|
||||
if (!settingsTab) {
|
||||
const startKey: number = TelemetryProcessor.traceStart(Action.Tab, {
|
||||
|
@ -582,7 +583,6 @@ export default class Collection implements ViewModels.Collection {
|
|||
documentClientUtility: this.container.documentClientUtility,
|
||||
collection: this,
|
||||
node: this,
|
||||
|
||||
selfLink: this.self,
|
||||
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/settings`,
|
||||
isActive: ko.observable(false),
|
||||
|
@ -658,7 +658,8 @@ export default class Collection implements ViewModels.Collection {
|
|||
|
||||
const collectionOffer = this._getOfferForCollection(offerInfoPromise.valueOf(), collectionDataModel);
|
||||
const isDatabaseShared = this.getDatabase() && this.getDatabase().isDatabaseShared();
|
||||
if (isDatabaseShared && !collectionOffer) {
|
||||
const isServerless = this.container.isServerlessEnabled();
|
||||
if ((isDatabaseShared || isServerless) && !collectionOffer) {
|
||||
this.quotaInfo(quotaInfo);
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.LoadOffers,
|
||||
|
|
|
@ -122,6 +122,10 @@ export default class Database implements ViewModels.Database {
|
|||
|
||||
public readSettings(): Q.Promise<void> {
|
||||
const deferred: Q.Deferred<void> = Q.defer<void>();
|
||||
if (this.container.isServerlessEnabled()) {
|
||||
deferred.resolve();
|
||||
}
|
||||
|
||||
this.container.isRefreshingExplorer(true);
|
||||
const databaseDataModel: DataModels.Database = <DataModels.Database>{
|
||||
id: this.id(),
|
||||
|
|
|
@ -235,7 +235,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||
});
|
||||
|
||||
children.push({
|
||||
label: database.isDatabaseShared() ? "Settings" : "Scale & Settings",
|
||||
label: database.isDatabaseShared() || this.container.isServerlessEnabled() ? "Settings" : "Scale & Settings",
|
||||
onClick: collection.onSettingsClick.bind(collection),
|
||||
isSelected: () => this.isDataNodeSelected(collection.rid, "Collection", ViewModels.CollectionTabKind.Settings)
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue