Remove Explorer.features (#563)

In addition this makes the URL-passed feature flags type safe
This commit is contained in:
Jordi Bunster 2021-03-22 12:04:06 -07:00 committed by GitHub
parent b1aeab6b84
commit f33ec09040
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 140 additions and 159 deletions

View File

@ -98,31 +98,6 @@ export class CapabilityNames {
public static readonly EnableServerless: string = "EnableServerless"; public static readonly EnableServerless: string = "EnableServerless";
} }
export class Features {
public static readonly cosmosdb = "cosmosdb";
public static readonly enableChangeFeedPolicy = "enablechangefeedpolicy";
public static readonly executeSproc = "dataexplorerexecutesproc";
public static readonly hostedDataExplorer = "hosteddataexplorerenabled";
public static readonly enableTtl = "enablettl";
public static readonly enableNotebooks = "enablenotebooks";
public static readonly enableSpark = "enablespark";
public static readonly livyEndpoint = "livyendpoint";
public static readonly notebookServerUrl = "notebookserverurl";
public static readonly notebookServerToken = "notebookservertoken";
public static readonly notebookBasePath = "notebookbasepath";
public static readonly canExceedMaximumValue = "canexceedmaximumvalue";
public static readonly enableFixedCollectionWithSharedThroughput = "enablefixedcollectionwithsharedthroughput";
public static readonly ttl90Days = "ttl90days";
public static readonly enableRightPanelV2 = "enablerightpanelv2";
public static readonly enableSchema = "enableschema";
public static readonly enableSDKoperations = "enablesdkoperations";
public static readonly showMinRUSurvey = "showminrusurvey";
public static readonly enableDatabaseSettingsTabV1 = "enabledbsettingsv1";
public static readonly selfServeType = "selfservetype";
public static readonly enableKOPanel = "enablekopanel";
public static readonly enableReactPane = "enablereactpane";
}
// flight names returned from the portal are always lowercase // flight names returned from the portal are always lowercase
export class Flights { export class Flights {
public static readonly SettingsV2 = "settingsv2"; public static readonly SettingsV2 = "settingsv2";

View File

@ -376,7 +376,6 @@ export interface DataExplorerInputsFrame {
masterKey?: string; masterKey?: string;
hasWriteAccess?: boolean; hasWriteAccess?: boolean;
authorizationToken?: string; authorizationToken?: string;
features: { [key: string]: string };
csmEndpoint?: string; csmEndpoint?: string;
dnsSuffix?: string; dnsSuffix?: string;
serverId?: string; serverId?: string;

View File

@ -139,9 +139,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
this.shouldShowIndexingPolicyEditor = this.shouldShowIndexingPolicyEditor =
this.container && !this.container.isPreferredApiCassandra() && !this.container.isPreferredApiMongoDB(); this.container && !this.container.isPreferredApiCassandra() && !this.container.isPreferredApiMongoDB();
this.changeFeedPolicyVisible = this.collection?.container.isFeatureEnabled( this.changeFeedPolicyVisible = userContext.features.enableChangeFeedPolicy;
Constants.Features.enableChangeFeedPolicy
);
// Mongo container with system partition key still treat as "Fixed" // Mongo container with system partition key still treat as "Fixed"
this.isFixedContainer = this.isFixedContainer =

View File

@ -12,7 +12,6 @@ import {
TextField, TextField,
} from "office-ui-fabric-react"; } from "office-ui-fabric-react";
import React from "react"; import React from "react";
import { Features } from "../../../../../Common/Constants";
import * as DataModels from "../../../../../Contracts/DataModels"; import * as DataModels from "../../../../../Contracts/DataModels";
import { SubscriptionType } from "../../../../../Contracts/SubscriptionType"; import { SubscriptionType } from "../../../../../Contracts/SubscriptionType";
import * as SharedConstants from "../../../../../Shared/Constants"; import * as SharedConstants from "../../../../../Shared/Constants";
@ -465,7 +464,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
const href = `https://ncv.microsoft.com/vRBTO37jmO?ctx={"AzureSubscriptionId":"${userContext.subscriptionId}","CosmosDBAccountName":"${userContext.databaseAccount?.name}"}`; const href = `https://ncv.microsoft.com/vRBTO37jmO?ctx={"AzureSubscriptionId":"${userContext.subscriptionId}","CosmosDBAccountName":"${userContext.databaseAccount?.name}"}`;
const oneTBinKB = 1000000000; const oneTBinKB = 1000000000;
const minRUperGB = 10; const minRUperGB = 10;
const featureFlagEnabled = window.dataExplorer?.isFeatureEnabled(Features.showMinRUSurvey); const featureFlagEnabled = userContext.features.showMinRUSurvey;
const collectionIsEligible = const collectionIsEligible =
userContext.subscriptionType !== SubscriptionType.Internal && userContext.subscriptionType !== SubscriptionType.Internal &&
this.props.usageSizeInKB > oneTBinKB && this.props.usageSizeInKB > oneTBinKB &&

View File

@ -895,7 +895,6 @@ exports[`SettingsComponent renders 1`] = `
"validPartitionKeyValue": [Function], "validPartitionKeyValue": [Function],
"visible": [Function], "visible": [Function],
}, },
"features": [Function],
"flight": [Function], "flight": [Function],
"graphStylingPane": GraphStylingPane { "graphStylingPane": GraphStylingPane {
"container": [Circular], "container": [Circular],
@ -2092,7 +2091,6 @@ exports[`SettingsComponent renders 1`] = `
"validPartitionKeyValue": [Function], "validPartitionKeyValue": [Function],
"visible": [Function], "visible": [Function],
}, },
"features": [Function],
"flight": [Function], "flight": [Function],
"graphStylingPane": GraphStylingPane { "graphStylingPane": GraphStylingPane {
"container": [Circular], "container": [Circular],
@ -3302,7 +3300,6 @@ exports[`SettingsComponent renders 1`] = `
"validPartitionKeyValue": [Function], "validPartitionKeyValue": [Function],
"visible": [Function], "visible": [Function],
}, },
"features": [Function],
"flight": [Function], "flight": [Function],
"graphStylingPane": GraphStylingPane { "graphStylingPane": GraphStylingPane {
"container": [Circular], "container": [Circular],
@ -4499,7 +4496,6 @@ exports[`SettingsComponent renders 1`] = `
"validPartitionKeyValue": [Function], "validPartitionKeyValue": [Function],
"visible": [Function], "visible": [Function],
}, },
"features": [Function],
"flight": [Function], "flight": [Function],
"graphStylingPane": GraphStylingPane { "graphStylingPane": GraphStylingPane {
"container": [Circular], "container": [Circular],

View File

@ -329,7 +329,7 @@ export default class Explorer {
this.isNotebookEnabled( this.isNotebookEnabled(
userContext.authType !== AuthType.ResourceToken && userContext.authType !== AuthType.ResourceToken &&
((await this._containsDefaultNotebookWorkspace(this.databaseAccount())) || ((await this._containsDefaultNotebookWorkspace(this.databaseAccount())) ||
this.isFeatureEnabled(Constants.Features.enableNotebooks)) userContext.features.enableNotebooks)
); );
TelemetryProcessor.trace(Action.NotebookEnabled, ActionModifiers.Mark, { TelemetryProcessor.trace(Action.NotebookEnabled, ActionModifiers.Mark, {
@ -351,7 +351,7 @@ export default class Explorer {
this.isSparkEnabledForAccount() && this.isSparkEnabledForAccount() &&
this.arcadiaWorkspaces() && this.arcadiaWorkspaces() &&
this.arcadiaWorkspaces().length > 0) || this.arcadiaWorkspaces().length > 0) ||
this.isFeatureEnabled(Constants.Features.enableSpark) userContext.features.enableSpark
); );
if (this.isSparkEnabled()) { if (this.isSparkEnabled()) {
appInsights.trackEvent( appInsights.trackEvent(
@ -375,7 +375,6 @@ export default class Explorer {
}); });
this.memoryUsageInfo = ko.observable<DataModels.MemoryUsageInfo>(); this.memoryUsageInfo = ko.observable<DataModels.MemoryUsageInfo>();
this.features = ko.observable();
this.queriesClient = new QueriesClient(this); this.queriesClient = new QueriesClient(this);
this.resourceTokenDatabaseId = ko.observable<string>(); this.resourceTokenDatabaseId = ko.observable<string>();
@ -387,11 +386,9 @@ export default class Explorer {
this.isPublishNotebookPaneEnabled = ko.observable<boolean>(false); this.isPublishNotebookPaneEnabled = ko.observable<boolean>(false);
this.isCopyNotebookPaneEnabled = ko.observable<boolean>(false); this.isCopyNotebookPaneEnabled = ko.observable<boolean>(false);
this.canExceedMaximumValue = ko.computed<boolean>(() => this.canExceedMaximumValue = ko.computed<boolean>(() => userContext.features.canExceedMaximumValue);
this.isFeatureEnabled(Constants.Features.canExceedMaximumValue)
);
this.isSchemaEnabled = ko.computed<boolean>(() => this.isFeatureEnabled(Constants.Features.enableSchema)); this.isSchemaEnabled = ko.computed<boolean>(() => userContext.features.enableSchema);
this.isAutoscaleDefaultEnabled = ko.observable<boolean>(false); this.isAutoscaleDefaultEnabled = ko.observable<boolean>(false);
@ -471,7 +468,7 @@ export default class Explorer {
}); });
this.isFixedCollectionWithSharedThroughputSupported = ko.computed(() => { this.isFixedCollectionWithSharedThroughputSupported = ko.computed(() => {
if (this.isFeatureEnabled(Constants.Features.enableFixedCollectionWithSharedThroughput)) { if (userContext.features.enableFixedCollectionWithSharedThroughput) {
return true; return true;
} }
@ -530,9 +527,7 @@ export default class Explorer {
() => () =>
configContext.platform === Platform.Portal && !this.isRunningOnNationalCloud() && !this.isPreferredApiGraph() configContext.platform === Platform.Portal && !this.isRunningOnNationalCloud() && !this.isPreferredApiGraph()
); );
this.isRightPanelV2Enabled = ko.computed<boolean>(() => this.isRightPanelV2Enabled = ko.computed<boolean>(() => userContext.features.enableRightPanelV2);
this.isFeatureEnabled(Constants.Features.enableRightPanelV2)
);
this.defaultExperience.subscribe((defaultExperience: string) => { this.defaultExperience.subscribe((defaultExperience: string) => {
if ( if (
defaultExperience && defaultExperience &&
@ -883,42 +878,29 @@ export default class Explorer {
}); });
// Override notebook server parameters from URL parameters // Override notebook server parameters from URL parameters
const featureSubcription = this.features.subscribe((features) => { if (userContext.features.notebookServerUrl && userContext.features.notebookServerToken) {
const serverInfo = this.notebookServerInfo(); this.notebookServerInfo({
if (this.isFeatureEnabled(Constants.Features.notebookServerUrl)) { notebookServerEndpoint: userContext.features.notebookServerUrl,
serverInfo.notebookServerEndpoint = features[Constants.Features.notebookServerUrl]; authToken: userContext.features.notebookServerToken,
});
} }
if (this.isFeatureEnabled(Constants.Features.notebookServerToken)) { if (userContext.features.notebookBasePath) {
serverInfo.authToken = features[Constants.Features.notebookServerToken]; this.notebookBasePath(userContext.features.notebookBasePath);
}
this.notebookServerInfo(serverInfo);
this.notebookServerInfo.valueHasMutated();
if (this.isFeatureEnabled(Constants.Features.notebookBasePath)) {
this.notebookBasePath(features[Constants.Features.notebookBasePath]);
} }
if (this.isFeatureEnabled(Constants.Features.livyEndpoint)) { if (userContext.features.livyEndpoint) {
this.sparkClusterConnectionInfo({ this.sparkClusterConnectionInfo({
userName: undefined, userName: undefined,
password: undefined, password: undefined,
endpoints: [ endpoints: [
{ {
endpoint: features[Constants.Features.livyEndpoint], endpoint: userContext.features.livyEndpoint,
kind: DataModels.SparkClusterEndpointKind.Livy, kind: DataModels.SparkClusterEndpointKind.Livy,
}, },
], ],
}); });
this.sparkClusterConnectionInfo.valueHasMutated();
} }
if (this.isFeatureEnabled(Constants.Features.enableSDKoperations)) {
updateUserContext({ useSDKOperations: true });
}
featureSubcription.dispose();
});
} }
public openEnableSynapseLinkDialog(): void { public openEnableSynapseLinkDialog(): void {
@ -1002,20 +984,6 @@ export default class Explorer {
return this.selectedNode() == null; return this.selectedNode() == null;
} }
public isFeatureEnabled(feature: string): boolean {
const features = this.features();
if (!features) {
return false;
}
if (feature in features && features[feature]) {
return true;
}
return false;
}
public logConsoleData(consoleData: ConsoleData): void { public logConsoleData(consoleData: ConsoleData): void {
this.setNotificationConsoleData(consoleData); this.setNotificationConsoleData(consoleData);
} }
@ -1258,12 +1226,12 @@ export default class Explorer {
throw error; throw error;
} finally { } finally {
// Overwrite with feature flags // Overwrite with feature flags
if (this.isFeatureEnabled(Constants.Features.notebookServerUrl)) { if (userContext.features.notebookServerUrl) {
connectionInfo.notebookServerEndpoint = this.features()[Constants.Features.notebookServerUrl]; connectionInfo.notebookServerEndpoint = userContext.features.notebookServerUrl;
} }
if (this.isFeatureEnabled(Constants.Features.notebookServerToken)) { if (userContext.features.notebookServerToken) {
connectionInfo.authToken = this.features()[Constants.Features.notebookServerToken]; connectionInfo.authToken = userContext.features.notebookServerToken;
} }
this.notebookServerInfo(connectionInfo); this.notebookServerInfo(connectionInfo);
@ -1413,7 +1381,6 @@ export default class Explorer {
if (inputs.defaultCollectionThroughput) { if (inputs.defaultCollectionThroughput) {
this.collectionCreationDefaults = inputs.defaultCollectionThroughput; this.collectionCreationDefaults = inputs.defaultCollectionThroughput;
} }
this.features(inputs.features);
this.databaseAccount(databaseAccount); this.databaseAccount(databaseAccount);
this.subscriptionType(inputs.subscriptionType ?? SharedConstants.CollectionCreation.DefaultSubscriptionType); this.subscriptionType(inputs.subscriptionType ?? SharedConstants.CollectionCreation.DefaultSubscriptionType);
this.hasWriteAccess(inputs.hasWriteAccess ?? true); this.hasWriteAccess(inputs.hasWriteAccess ?? true);
@ -2367,7 +2334,7 @@ export default class Explorer {
public onNewCollectionClicked(): void { public onNewCollectionClicked(): void {
if (this.isPreferredApiCassandra()) { if (this.isPreferredApiCassandra()) {
this.cassandraAddCollectionPane.open(); this.cassandraAddCollectionPane.open();
} else if (this.isFeatureEnabled(Constants.Features.enableReactPane)) { } else if (userContext.features.enableReactPane) {
this.openAddCollectionPanel(); this.openAddCollectionPanel();
} else { } else {
this.addCollectionPane.open(this.selectedDatabaseId()); this.addCollectionPane.open(this.selectedDatabaseId());
@ -2501,7 +2468,7 @@ export default class Explorer {
} }
public openDeleteCollectionConfirmationPane(): void { public openDeleteCollectionConfirmationPane(): void {
this.isFeatureEnabled(Constants.Features.enableKOPanel) userContext.features.enableKOPanel
? this.deleteCollectionConfirmationPane.open() ? this.deleteCollectionConfirmationPane.open()
: this.openSidePanel( : this.openSidePanel(
"Delete Collection", "Delete Collection",

View File

@ -994,7 +994,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
this.container.openEnableSynapseLinkDialog(); this.container.openEnableSynapseLinkDialog();
} }
public ttl90DaysEnabled: () => boolean = () => this.container.isFeatureEnabled(Constants.Features.ttl90Days); public ttl90DaysEnabled: () => boolean = () => userContext.features.ttl90Days;
public isValid(): boolean { public isValid(): boolean {
// TODO add feature flag that disables validation for customers with custom accounts // TODO add feature flag that disables validation for customers with custom accounts
@ -1202,7 +1202,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
if (this.isAnalyticalStorageOn()) { if (this.isAnalyticalStorageOn()) {
// TODO: always default to 90 days once the backend hotfix is deployed // TODO: always default to 90 days once the backend hotfix is deployed
return this.container.isFeatureEnabled(Constants.Features.ttl90Days) return userContext.features.ttl90Days
? Constants.AnalyticalStorageTtl.Days90 ? Constants.AnalyticalStorageTtl.Days90
: Constants.AnalyticalStorageTtl.Infinite; : Constants.AnalyticalStorageTtl.Infinite;
} }

View File

@ -905,7 +905,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
if (this.state.enableAnalyticalStore) { if (this.state.enableAnalyticalStore) {
// TODO: always default to 90 days once the backend hotfix is deployed // TODO: always default to 90 days once the backend hotfix is deployed
return this.props.explorer.isFeatureEnabled(Constants.Features.ttl90Days) return userContext.features.ttl90Days
? Constants.AnalyticalStorageTtl.Days90 ? Constants.AnalyticalStorageTtl.Days90
: Constants.AnalyticalStorageTtl.Infinite; : Constants.AnalyticalStorageTtl.Infinite;
} }

View File

@ -882,8 +882,6 @@ export default class DocumentsTab extends TabsBase {
buttons.push(DocumentsTab._createUploadButton(this.collection.container)); buttons.push(DocumentsTab._createUploadButton(this.collection.container));
} }
const features = this.collection.container.features() || {};
return buttons; return buttons;
} }

View File

@ -58,9 +58,7 @@ export default class Database implements ViewModels.Database {
}); });
const pendingNotificationsPromise: Promise<DataModels.Notification> = this.getPendingThroughputSplitNotification(); const pendingNotificationsPromise: Promise<DataModels.Notification> = this.getPendingThroughputSplitNotification();
const useDatabaseSettingsTabV1: boolean = this.container.isFeatureEnabled( const useDatabaseSettingsTabV1 = userContext.features.enableDatabaseSettingsTabV1;
Constants.Features.enableDatabaseSettingsTabV1
);
const tabKind: ViewModels.CollectionTabKind = useDatabaseSettingsTabV1 const tabKind: ViewModels.CollectionTabKind = useDatabaseSettingsTabV1
? ViewModels.CollectionTabKind.DatabaseSettings ? ViewModels.CollectionTabKind.DatabaseSettings
: ViewModels.CollectionTabKind.DatabaseSettingsV2; : ViewModels.CollectionTabKind.DatabaseSettingsV2;

View File

@ -3,13 +3,14 @@ import * as ko from "knockout";
import * as Constants from "../../Common/Constants"; import * as Constants from "../../Common/Constants";
import { deleteStoredProcedure } from "../../Common/dataAccess/deleteStoredProcedure"; import { deleteStoredProcedure } from "../../Common/dataAccess/deleteStoredProcedure";
import { executeStoredProcedure } from "../../Common/dataAccess/executeStoredProcedure"; import { executeStoredProcedure } from "../../Common/dataAccess/executeStoredProcedure";
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
import * as ViewModels from "../../Contracts/ViewModels"; import * as ViewModels from "../../Contracts/ViewModels";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants"; import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor"; import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import StoredProcedureTab from "../Tabs/StoredProcedureTab"; import StoredProcedureTab from "../Tabs/StoredProcedureTab";
import TabsBase from "../Tabs/TabsBase"; import TabsBase from "../Tabs/TabsBase";
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
const sampleStoredProcedureBody: string = `// SAMPLE STORED PROCEDURE const sampleStoredProcedureBody: string = `// SAMPLE STORED PROCEDURE
function sample(prefix) { function sample(prefix) {
@ -56,7 +57,7 @@ export default class StoredProcedure {
this.rid = data._rid; this.rid = data._rid;
this.id = ko.observable(data.id); this.id = ko.observable(data.id);
this.body = ko.observable(data.body as string); this.body = ko.observable(data.body as string);
this.isExecuteEnabled = this.container.isFeatureEnabled(Constants.Features.executeSproc); this.isExecuteEnabled = userContext.features.executeSproc;
} }
public static create(source: ViewModels.Collection, event: MouseEvent) { public static create(source: ViewModels.Collection, event: MouseEvent) {

View File

@ -1,17 +1,22 @@
import { extractFeatures } from "./extractFeatures"; import { extractFeatures } from "./extractFeatures";
describe("extractFeatures", () => { describe("extractFeatures", () => {
it("correctly detects feature flags", () => { it("correctly detects feature flags in a case insensitive manner", () => {
// Search containing non-features, with Camelcase keys and uri encoded values const url = "https://localhost:10001/12345/notebook";
const params = new URLSearchParams( const token = "super secret";
"?platform=Hosted&feature.notebookserverurl=https%3A%2F%2Flocalhost%3A10001%2F12345%2Fnotebook&feature.notebookServerToken=token&feature.enablenotebooks=true&key=mykey" const notebooksEnabled = false;
); const params = new URLSearchParams({
platform: "Hosted",
"feature.NOTEBOOKSERVERURL": url,
"feature.NoTeBooKServerToken": token,
"feature.NotAFeature": "nope",
"feature.ENABLEnotebooks": notebooksEnabled.toString(),
});
const features = extractFeatures(params); const features = extractFeatures(params);
expect(features).toEqual({ expect(features.notebookServerUrl).toBe(url);
notebookserverurl: "https://localhost:10001/12345/notebook", expect(features.notebookServerToken).toBe(token);
notebookservertoken: "token", expect(features.enableNotebooks).toBe(notebooksEnabled);
enablenotebooks: "true",
});
}); });
}); });

View File

@ -1,14 +1,56 @@
export function extractFeatures(params?: URLSearchParams): { [key: string]: string } { export type Features = {
readonly canExceedMaximumValue: boolean;
readonly cosmosdb: boolean;
readonly enableChangeFeedPolicy: boolean;
readonly enableDatabaseSettingsTabV1: boolean;
readonly enableFixedCollectionWithSharedThroughput: boolean;
readonly enableKOPanel: boolean;
readonly enableNotebooks: boolean;
readonly enableReactPane: boolean;
readonly enableRightPanelV2: boolean;
readonly enableSchema: boolean;
readonly enableSDKoperations: boolean;
readonly enableSpark: boolean;
readonly enableTtl: boolean;
readonly executeSproc: boolean;
readonly hostedDataExplorer: boolean;
readonly livyEndpoint?: string;
readonly notebookBasePath?: string;
readonly notebookServerToken?: string;
readonly notebookServerUrl?: string;
readonly selfServeType?: string;
readonly showMinRUSurvey: boolean;
readonly ttl90Days: boolean;
};
export function extractFeatures(params?: URLSearchParams): Features {
params = params || new URLSearchParams(window.parent.location.search); params = params || new URLSearchParams(window.parent.location.search);
const featureParamRegex = /feature.(.*)/i; const downcased = new URLSearchParams();
const features: { [key: string]: string } = {}; params.forEach((value, key) => downcased.append(key.toLocaleLowerCase(), value));
params.forEach((value: string, param: string) => { const get = (key: string) => downcased.get("feature." + key.toLocaleLowerCase()) ?? undefined;
if (featureParamRegex.test(param)) {
const matches: string[] = param.match(featureParamRegex); return {
if (matches.length > 0) { canExceedMaximumValue: "true" === get("canexceedmaximumvalue"),
features[matches[1].toLowerCase()] = value; cosmosdb: "true" === get("cosmosdb"),
} enableChangeFeedPolicy: "true" === get("enablechangefeedpolicy"),
} enableDatabaseSettingsTabV1: "true" === get("enabledbsettingsv1"),
}); enableFixedCollectionWithSharedThroughput: "true" === get("enablefixedcollectionwithsharedthroughput"),
return features; enableKOPanel: "true" === get("enablekopanel"),
enableNotebooks: "true" === get("enablenotebooks"),
enableReactPane: "true" === get("enablereactpane"),
enableRightPanelV2: "true" === get("enablerightpanelv2"),
enableSchema: "true" === get("enableschema"),
enableSDKoperations: "true" === get("enablesdkoperations"),
enableSpark: "true" === get("enablespark"),
enableTtl: "true" === get("enablettl"),
executeSproc: "true" === get("dataexplorerexecutesproc"),
hostedDataExplorer: "true" === get("hosteddataexplorerenabled"),
livyEndpoint: get("livyendpoint"),
notebookBasePath: get("notebookbasepath"),
notebookServerToken: get("notebookservertoken"),
notebookServerUrl: get("notebookserverurl"),
selfServeType: get("selfservetype"),
showMinRUSurvey: "true" === get("showminrusurvey"),
ttl90Days: "true" === get("ttl90days"),
};
} }

View File

@ -2,34 +2,44 @@ import { AuthType } from "./AuthType";
import { DatabaseAccount } from "./Contracts/DataModels"; import { DatabaseAccount } from "./Contracts/DataModels";
import { SubscriptionType } from "./Contracts/SubscriptionType"; import { SubscriptionType } from "./Contracts/SubscriptionType";
import { DefaultAccountExperienceType } from "./DefaultAccountExperienceType"; import { DefaultAccountExperienceType } from "./DefaultAccountExperienceType";
import { extractFeatures, Features } from "./Platform/Hosted/extractFeatures";
interface UserContext { interface UserContext {
authType?: AuthType; readonly authType?: AuthType;
masterKey?: string; readonly masterKey?: string;
subscriptionId?: string; readonly subscriptionId?: string;
resourceGroup?: string; readonly resourceGroup?: string;
databaseAccount?: DatabaseAccount; readonly databaseAccount?: DatabaseAccount;
endpoint?: string; readonly endpoint?: string;
accessToken?: string; readonly accessToken?: string;
authorizationToken?: string; readonly authorizationToken?: string;
resourceToken?: string; readonly resourceToken?: string;
defaultExperience?: DefaultAccountExperienceType; readonly useSDKOperations: boolean;
useSDKOperations?: boolean; readonly defaultExperience?: DefaultAccountExperienceType;
subscriptionType?: SubscriptionType; readonly subscriptionType?: SubscriptionType;
quotaId?: string; readonly quotaId?: string;
// API Type is not yet provided by ARM. You need to manually inspect all the capabilities+kind so we abstract that logic in userContext // API Type is not yet provided by ARM. You need to manually inspect all the capabilities+kind so we abstract that logic in userContext
// This is coming in a future Cosmos ARM API version as a prperty on databaseAccount // This is coming in a future Cosmos ARM API version as a prperty on databaseAccount
apiType?: ApiType; readonly apiType?: ApiType;
isTryCosmosDBSubscription?: boolean; readonly isTryCosmosDBSubscription?: boolean;
portalEnv?: PortalEnv; readonly portalEnv?: PortalEnv;
readonly features: Features;
} }
type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra"; type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra";
export type PortalEnv = "localhost" | "blackforest" | "fairfax" | "mooncake" | "prod" | "dev"; export type PortalEnv = "localhost" | "blackforest" | "fairfax" | "mooncake" | "prod" | "dev";
const userContext: UserContext = { isTryCosmosDBSubscription: false, portalEnv: "prod" }; const features = extractFeatures();
const { enableSDKoperations: useSDKOperations } = features;
function updateUserContext(newContext: UserContext): void { const userContext: UserContext = {
isTryCosmosDBSubscription: false,
portalEnv: "prod",
features,
useSDKOperations,
};
function updateUserContext(newContext: Partial<UserContext>): void {
Object.assign(userContext, newContext); Object.assign(userContext, newContext);
Object.assign(userContext, { apiType: apiType(userContext.databaseAccount) }); Object.assign(userContext, { apiType: apiType(userContext.databaseAccount) });
} }

View File

@ -18,7 +18,6 @@ import {
ResourceToken, ResourceToken,
} from "../HostedExplorerChildFrame"; } from "../HostedExplorerChildFrame";
import { emulatorAccount } from "../Platform/Emulator/emulatorAccount"; import { emulatorAccount } from "../Platform/Emulator/emulatorAccount";
import { extractFeatures } from "../Platform/Hosted/extractFeatures";
import { parseResourceTokenConnectionString } from "../Platform/Hosted/Helpers/ResourceTokenUtils"; import { parseResourceTokenConnectionString } from "../Platform/Hosted/Helpers/ResourceTokenUtils";
import { import {
getDatabaseAccountKindFromExperience, getDatabaseAccountKindFromExperience,
@ -101,7 +100,6 @@ async function configureHostedWithAAD(config: AAD, explorerParams: ExplorerParam
resourceGroup, resourceGroup,
masterKey: keys.primaryMasterKey, masterKey: keys.primaryMasterKey,
authorizationToken: `Bearer ${config.authorizationToken}`, authorizationToken: `Bearer ${config.authorizationToken}`,
features: extractFeatures(),
}); });
return explorer; return explorer;
} }
@ -128,7 +126,6 @@ function configureHostedWithConnectionString(config: ConnectionString, explorerP
explorer.configure({ explorer.configure({
databaseAccount, databaseAccount,
masterKey: config.masterKey, masterKey: config.masterKey,
features: extractFeatures(),
}); });
return explorer; return explorer;
} }
@ -157,10 +154,7 @@ function configureHostedWithResourceToken(config: ResourceToken, explorerParams:
if (parsedResourceToken.partitionKey) { if (parsedResourceToken.partitionKey) {
explorer.resourceTokenPartitionKey(parsedResourceToken.partitionKey); explorer.resourceTokenPartitionKey(parsedResourceToken.partitionKey);
} }
explorer.configure({ explorer.configure({ databaseAccount });
databaseAccount,
features: extractFeatures(),
});
return explorer; return explorer;
} }
@ -181,7 +175,6 @@ function configureHostedWithEncryptedToken(config: EncryptedToken, explorerParam
properties: getDatabaseAccountPropertiesFromMetadata(config.encryptedTokenMetadata), properties: getDatabaseAccountPropertiesFromMetadata(config.encryptedTokenMetadata),
tags: {}, tags: {},
}, },
features: extractFeatures(),
}); });
return explorer; return explorer;
} }