mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-05 18:47:41 +00:00
Compare commits
1 Commits
languy-add
...
users/kche
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87eb38e645 |
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@@ -12,8 +12,7 @@
|
|||||||
"--inspect-brk",
|
"--inspect-brk",
|
||||||
"${workspaceRoot}/node_modules/jest/bin/jest.js",
|
"${workspaceRoot}/node_modules/jest/bin/jest.js",
|
||||||
"--runInBand",
|
"--runInBand",
|
||||||
"--coverage",
|
"--coverage", "false"
|
||||||
"false"
|
|
||||||
],
|
],
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"internalConsoleOptions": "neverOpen",
|
"internalConsoleOptions": "neverOpen",
|
||||||
@@ -27,8 +26,7 @@
|
|||||||
"--inspect-brk",
|
"--inspect-brk",
|
||||||
"${workspaceRoot}/node_modules/jest/bin/jest.js",
|
"${workspaceRoot}/node_modules/jest/bin/jest.js",
|
||||||
"${fileBasenameNoExtension}",
|
"${fileBasenameNoExtension}",
|
||||||
"--coverage",
|
"--coverage", "false",
|
||||||
"false",
|
|
||||||
// "--watch",
|
// "--watch",
|
||||||
// // --no-cache only used to make --watch work. Otherwise jest ignores the breakpoints.
|
// // --no-cache only used to make --watch work. Otherwise jest ignores the breakpoints.
|
||||||
// // https://github.com/facebook/jest/issues/6683
|
// // https://github.com/facebook/jest/issues/6683
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"JUNO_ENDPOINT": "https://tools-staging.cosmos.azure.com",
|
"JUNO_ENDPOINT": "https://tools-staging.cosmos.azure.com",
|
||||||
"isTerminalEnabled" : true,
|
"isTerminalEnabled" : true
|
||||||
"isPhoenixEnabled" : true
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"JUNO_ENDPOINT": "https://tools.cosmos.azure.com",
|
"JUNO_ENDPOINT": "https://tools.cosmos.azure.com",
|
||||||
"isTerminalEnabled" : false,
|
"isTerminalEnabled" : false
|
||||||
"isPhoenixEnabled" : false
|
|
||||||
}
|
}
|
||||||
|
|||||||
42
package-lock.json
generated
42
package-lock.json
generated
@@ -6866,11 +6866,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||||
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
|
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
|
||||||
},
|
},
|
||||||
"attr-accept": {
|
|
||||||
"version": "2.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz",
|
|
||||||
"integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg=="
|
|
||||||
},
|
|
||||||
"aws-sign2": {
|
"aws-sign2": {
|
||||||
"version": "0.7.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
|
||||||
@@ -10820,21 +10815,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
|
||||||
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
"integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
|
||||||
},
|
},
|
||||||
"file-selector": {
|
|
||||||
"version": "0.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.4.0.tgz",
|
|
||||||
"integrity": "sha512-iACCiXeMYOvZqlF1kTiYINzgepRBymz1wwjiuup9u9nayhb6g4fSwiyJ/6adli+EPwrWtpgQAh2PoS7HukEGEg==",
|
|
||||||
"requires": {
|
|
||||||
"tslib": "^2.0.3"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"tslib": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"file-uri-to-path": {
|
"file-uri-to-path": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||||
@@ -20998,28 +20978,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-dropzone": {
|
|
||||||
"version": "12.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-12.0.4.tgz",
|
|
||||||
"integrity": "sha512-fcqHEYe1MzAghU6/Hz86lHDlBNsA+lO48nAcm7/wA+kIzwS6uuJbUG33tBZjksj7GAZ1iUQ6NHwjUURPmSGang==",
|
|
||||||
"requires": {
|
|
||||||
"attr-accept": "^2.2.2",
|
|
||||||
"file-selector": "^0.4.0",
|
|
||||||
"prop-types": "^15.8.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"prop-types": {
|
|
||||||
"version": "15.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
|
||||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
|
||||||
"requires": {
|
|
||||||
"loose-envify": "^1.4.0",
|
|
||||||
"object-assign": "^4.1.1",
|
|
||||||
"react-is": "^16.13.1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"react-error-overlay": {
|
"react-error-overlay": {
|
||||||
"version": "6.0.9",
|
"version": "6.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
|
||||||
|
|||||||
@@ -86,7 +86,6 @@
|
|||||||
"react-dnd": "14.0.2",
|
"react-dnd": "14.0.2",
|
||||||
"react-dnd-html5-backend": "14.0.0",
|
"react-dnd-html5-backend": "14.0.0",
|
||||||
"react-dom": "16.13.1",
|
"react-dom": "16.13.1",
|
||||||
"react-dropzone": "12.0.4",
|
|
||||||
"react-hotkeys": "2.0.0",
|
"react-hotkeys": "2.0.0",
|
||||||
"react-i18next": "11.8.5",
|
"react-i18next": "11.8.5",
|
||||||
"react-notification-system": "0.2.17",
|
"react-notification-system": "0.2.17",
|
||||||
|
|||||||
@@ -99,7 +99,6 @@ export class Flights {
|
|||||||
public static readonly PhoenixNotebooks = "phoenixnotebooks";
|
public static readonly PhoenixNotebooks = "phoenixnotebooks";
|
||||||
public static readonly PhoenixFeatures = "phoenixfeatures";
|
public static readonly PhoenixFeatures = "phoenixfeatures";
|
||||||
public static readonly NotebooksDownBanner = "notebooksdownbanner";
|
public static readonly NotebooksDownBanner = "notebooksdownbanner";
|
||||||
public static readonly FreeTierAutoscaleThroughput = "freetierautoscalethroughput";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AfecFeatures {
|
export class AfecFeatures {
|
||||||
|
|||||||
@@ -236,12 +236,13 @@ describe("MongoProxyClient", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns a production endpoint", () => {
|
it("returns a production endpoint", () => {
|
||||||
const endpoint = getEndpoint("https://main.documentdb.ext.azure.com");
|
const endpoint = getEndpoint();
|
||||||
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/mongo/explorer");
|
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/mongo/explorer");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("returns a development endpoint", () => {
|
it("returns a development endpoint", () => {
|
||||||
const endpoint = getEndpoint("https://localhost:1234");
|
updateConfigContext({ MONGO_BACKEND_ENDPOINT: "https://localhost:1234" });
|
||||||
|
const endpoint = getEndpoint();
|
||||||
expect(endpoint).toEqual("https://localhost:1234/api/mongo/explorer");
|
expect(endpoint).toEqual("https://localhost:1234/api/mongo/explorer");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -249,7 +250,7 @@ describe("MongoProxyClient", () => {
|
|||||||
updateUserContext({
|
updateUserContext({
|
||||||
authType: AuthType.EncryptedToken,
|
authType: AuthType.EncryptedToken,
|
||||||
});
|
});
|
||||||
const endpoint = getEndpoint("https://main.documentdb.ext.azure.com");
|
const endpoint = getEndpoint();
|
||||||
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
expect(endpoint).toEqual("https://main.documentdb.ext.azure.com/api/guest/mongo/explorer");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Constants as CosmosSDKConstants } from "@azure/cosmos";
|
import { Constants as CosmosSDKConstants } from "@azure/cosmos";
|
||||||
import queryString from "querystring";
|
import queryString from "querystring";
|
||||||
import { allowedMongoProxyEndpoints, validateEndpoint } from "Utils/EndpointValidation";
|
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { configContext } from "../ConfigContext";
|
import { configContext } from "../ConfigContext";
|
||||||
import * as DataModels from "../Contracts/DataModels";
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
@@ -337,17 +336,14 @@ export function createMongoCollectionWithProxy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getFeatureEndpointOrDefault(feature: string): string {
|
export function getFeatureEndpointOrDefault(feature: string): string {
|
||||||
const endpoint =
|
return hasFlag(userContext.features.mongoProxyAPIs, feature)
|
||||||
hasFlag(userContext.features.mongoProxyAPIs, feature) &&
|
? getEndpoint(userContext.features.mongoProxyEndpoint)
|
||||||
validateEndpoint(userContext.features.mongoProxyEndpoint, allowedMongoProxyEndpoints)
|
: getEndpoint();
|
||||||
? userContext.features.mongoProxyEndpoint
|
|
||||||
: configContext.MONGO_BACKEND_ENDPOINT || configContext.BACKEND_ENDPOINT;
|
|
||||||
|
|
||||||
return getEndpoint(endpoint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getEndpoint(endpoint: string): string {
|
export function getEndpoint(customEndpoint?: string): string {
|
||||||
let url = endpoint + "/api/mongo/explorer";
|
let url = customEndpoint ? customEndpoint : configContext.MONGO_BACKEND_ENDPOINT || configContext.BACKEND_ENDPOINT;
|
||||||
|
url += "/api/mongo/explorer";
|
||||||
|
|
||||||
if (userContext.authType === AuthType.EncryptedToken) {
|
if (userContext.authType === AuthType.EncryptedToken) {
|
||||||
url = url.replace("api/mongo", "api/guest/mongo");
|
url = url.replace("api/mongo", "api/guest/mongo");
|
||||||
|
|||||||
@@ -1,16 +1,4 @@
|
|||||||
import {
|
import { JunoEndpoints } from "Common/Constants";
|
||||||
allowedAadEndpoints,
|
|
||||||
allowedArcadiaEndpoints,
|
|
||||||
allowedArmEndpoints,
|
|
||||||
allowedBackendEndpoints,
|
|
||||||
allowedEmulatorEndpoints,
|
|
||||||
allowedGraphEndpoints,
|
|
||||||
allowedHostedExplorerEndpoints,
|
|
||||||
allowedJunoOrigins,
|
|
||||||
allowedMongoBackendEndpoints,
|
|
||||||
allowedMsalRedirectEndpoints,
|
|
||||||
validateEndpoint,
|
|
||||||
} from "Utils/EndpointValidation";
|
|
||||||
|
|
||||||
export enum Platform {
|
export enum Platform {
|
||||||
Portal = "Portal",
|
Portal = "Portal",
|
||||||
@@ -20,7 +8,7 @@ export enum Platform {
|
|||||||
|
|
||||||
export interface ConfigContext {
|
export interface ConfigContext {
|
||||||
platform: Platform;
|
platform: Platform;
|
||||||
allowedParentFrameOrigins: ReadonlyArray<string>;
|
allowedParentFrameOrigins: string[];
|
||||||
gitSha?: string;
|
gitSha?: string;
|
||||||
proxyPath?: string;
|
proxyPath?: string;
|
||||||
AAD_ENDPOINT: string;
|
AAD_ENDPOINT: string;
|
||||||
@@ -40,9 +28,9 @@ export interface ConfigContext {
|
|||||||
GITHUB_TEST_ENV_CLIENT_ID: string;
|
GITHUB_TEST_ENV_CLIENT_ID: string;
|
||||||
GITHUB_CLIENT_SECRET?: string; // No need to inject secret for prod. Juno already knows it.
|
GITHUB_CLIENT_SECRET?: string; // No need to inject secret for prod. Juno already knows it.
|
||||||
isTerminalEnabled: boolean;
|
isTerminalEnabled: boolean;
|
||||||
isPhoenixEnabled: boolean;
|
|
||||||
hostedExplorerURL: string;
|
hostedExplorerURL: string;
|
||||||
armAPIVersion?: string;
|
armAPIVersion?: string;
|
||||||
|
allowedJunoOrigins: string[];
|
||||||
msalRedirectURI?: string;
|
msalRedirectURI?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +44,8 @@ let configContext: Readonly<ConfigContext> = {
|
|||||||
`^https:\\/\\/[\\.\\w]*ext\\.azure\\.(com|cn|us)$`,
|
`^https:\\/\\/[\\.\\w]*ext\\.azure\\.(com|cn|us)$`,
|
||||||
`^https:\\/\\/[\\.\\w]*\\.ext\\.microsoftazure\\.de$`,
|
`^https:\\/\\/[\\.\\w]*\\.ext\\.microsoftazure\\.de$`,
|
||||||
`^https://cosmos-db-dataexplorer-germanycentral.azurewebsites.de$`,
|
`^https://cosmos-db-dataexplorer-germanycentral.azurewebsites.de$`,
|
||||||
], // Webpack injects this at build time
|
],
|
||||||
|
// Webpack injects this at build time
|
||||||
gitSha: process.env.GIT_SHA,
|
gitSha: process.env.GIT_SHA,
|
||||||
hostedExplorerURL: "https://cosmos.azure.com/",
|
hostedExplorerURL: "https://cosmos.azure.com/",
|
||||||
AAD_ENDPOINT: "https://login.microsoftonline.com/",
|
AAD_ENDPOINT: "https://login.microsoftonline.com/",
|
||||||
@@ -72,7 +61,14 @@ let configContext: Readonly<ConfigContext> = {
|
|||||||
JUNO_ENDPOINT: "https://tools.cosmos.azure.com",
|
JUNO_ENDPOINT: "https://tools.cosmos.azure.com",
|
||||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||||
isTerminalEnabled: false,
|
isTerminalEnabled: false,
|
||||||
isPhoenixEnabled: false,
|
allowedJunoOrigins: [
|
||||||
|
JunoEndpoints.Test,
|
||||||
|
JunoEndpoints.Test2,
|
||||||
|
JunoEndpoints.Test3,
|
||||||
|
JunoEndpoints.Prod,
|
||||||
|
JunoEndpoints.Stage,
|
||||||
|
"https://localhost",
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export function resetConfigContext(): void {
|
export function resetConfigContext(): void {
|
||||||
@@ -83,50 +79,6 @@ export function resetConfigContext(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function updateConfigContext(newContext: Partial<ConfigContext>): void {
|
export function updateConfigContext(newContext: Partial<ConfigContext>): void {
|
||||||
if (!newContext) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.ARM_ENDPOINT, allowedArmEndpoints)) {
|
|
||||||
delete newContext.ARM_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.AAD_ENDPOINT, allowedAadEndpoints)) {
|
|
||||||
delete newContext.AAD_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.EMULATOR_ENDPOINT, allowedEmulatorEndpoints)) {
|
|
||||||
delete newContext.EMULATOR_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.GRAPH_ENDPOINT, allowedGraphEndpoints)) {
|
|
||||||
delete newContext.GRAPH_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.ARCADIA_ENDPOINT, allowedArcadiaEndpoints)) {
|
|
||||||
delete newContext.ARCADIA_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.BACKEND_ENDPOINT, allowedBackendEndpoints)) {
|
|
||||||
delete newContext.BACKEND_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.MONGO_BACKEND_ENDPOINT, allowedMongoBackendEndpoints)) {
|
|
||||||
delete newContext.MONGO_BACKEND_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.JUNO_ENDPOINT, allowedJunoOrigins)) {
|
|
||||||
delete newContext.JUNO_ENDPOINT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.hostedExplorerURL, allowedHostedExplorerEndpoints)) {
|
|
||||||
delete newContext.hostedExplorerURL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validateEndpoint(newContext.msalRedirectURI, allowedMsalRedirectEndpoints)) {
|
|
||||||
delete newContext.msalRedirectURI;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object.assign(configContext, newContext);
|
Object.assign(configContext, newContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,8 +102,18 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
|
|||||||
});
|
});
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
try {
|
try {
|
||||||
const { ...externalConfig } = await response.json();
|
const { allowedParentFrameOrigins, allowedJunoOrigins, ...externalConfig } = await response.json();
|
||||||
updateConfigContext(externalConfig);
|
Object.assign(configContext, externalConfig);
|
||||||
|
if (allowedParentFrameOrigins && allowedParentFrameOrigins.length > 0) {
|
||||||
|
updateConfigContext({
|
||||||
|
allowedParentFrameOrigins: [...configContext.allowedParentFrameOrigins, ...allowedParentFrameOrigins],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (allowedJunoOrigins && allowedJunoOrigins.length > 0) {
|
||||||
|
updateConfigContext({
|
||||||
|
allowedJunoOrigins: [...configContext.allowedJunoOrigins, ...allowedJunoOrigins],
|
||||||
|
});
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Unable to parse json in config file");
|
console.error("Unable to parse json in config file");
|
||||||
console.error(error);
|
console.error(error);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ export enum TabKind {
|
|||||||
Graph,
|
Graph,
|
||||||
SQLQuery,
|
SQLQuery,
|
||||||
ScaleSettings,
|
ScaleSettings,
|
||||||
DataUploader,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -142,7 +142,6 @@ export interface Collection extends CollectionBase {
|
|||||||
onGraphDocumentsClick(): void;
|
onGraphDocumentsClick(): void;
|
||||||
onMongoDBDocumentsClick(): void;
|
onMongoDBDocumentsClick(): void;
|
||||||
onSchemaAnalyzerClick(): void;
|
onSchemaAnalyzerClick(): void;
|
||||||
onDataUploaderClick(): void;
|
|
||||||
openTab(): void;
|
openTab(): void;
|
||||||
|
|
||||||
onSettingsClick: () => Promise<void>;
|
onSettingsClick: () => Promise<void>;
|
||||||
@@ -365,7 +364,6 @@ export enum CollectionTabKind {
|
|||||||
CollectionSettingsV2 = 20,
|
CollectionSettingsV2 = 20,
|
||||||
DatabaseSettingsV2 = 21,
|
DatabaseSettingsV2 = 21,
|
||||||
SchemaAnalyzer = 22,
|
SchemaAnalyzer = 22,
|
||||||
DataUploader = 23,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum TerminalKind {
|
export enum TerminalKind {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { Action, ActionModifiers } from "../../../../../Shared/Telemetry/Telemet
|
|||||||
import * as TelemetryProcessor from "../../../../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "../../../../../UserContext";
|
import { userContext } from "../../../../../UserContext";
|
||||||
import * as AutoPilotUtils from "../../../../../Utils/AutoPilotUtils";
|
import * as AutoPilotUtils from "../../../../../Utils/AutoPilotUtils";
|
||||||
import { autoPilotThroughput1K, autoPilotThroughput4K } from "../../../../../Utils/AutoPilotUtils";
|
import { minAutoPilotThroughput } from "../../../../../Utils/AutoPilotUtils";
|
||||||
import { calculateEstimateNumber, usageInGB } from "../../../../../Utils/PricingUtils";
|
import { calculateEstimateNumber, usageInGB } from "../../../../../Utils/PricingUtils";
|
||||||
import { Int32 } from "../../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
import { Int32 } from "../../../../Panes/Tables/Validators/EntityPropertyValidationCommon";
|
||||||
import {
|
import {
|
||||||
@@ -540,7 +540,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
step={AutoPilotUtils.autoPilotIncrementStep}
|
step={AutoPilotUtils.autoPilotIncrementStep}
|
||||||
value={this.overrideWithProvisionedThroughputSettings() ? "" : this.props.maxAutoPilotThroughput?.toString()}
|
value={this.overrideWithProvisionedThroughputSettings() ? "" : this.props.maxAutoPilotThroughput?.toString()}
|
||||||
onChange={this.onAutoPilotThroughputChange}
|
onChange={this.onAutoPilotThroughputChange}
|
||||||
min={userContext.features.freetierAutoscaleThroughput ? autoPilotThroughput1K : autoPilotThroughput4K}
|
min={minAutoPilotThroughput}
|
||||||
errorMessage={this.props.throughputError}
|
errorMessage={this.props.throughputError}
|
||||||
/>
|
/>
|
||||||
{!this.overrideWithProvisionedThroughputSettings() && this.getAutoPilotUsageCost()}
|
{!this.overrideWithProvisionedThroughputSettings() && this.getAutoPilotUsageCost()}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,6 @@ const props = {
|
|||||||
isDatabase: false,
|
isDatabase: false,
|
||||||
showFreeTierExceedThroughputTooltip: true,
|
showFreeTierExceedThroughputTooltip: true,
|
||||||
isSharded: true,
|
isSharded: true,
|
||||||
isFreeTier: false,
|
|
||||||
setThroughputValue: () => jest.fn(),
|
setThroughputValue: () => jest.fn(),
|
||||||
setIsAutoscale: () => jest.fn(),
|
setIsAutoscale: () => jest.fn(),
|
||||||
setIsThroughputCapExceeded: () => jest.fn(),
|
setIsThroughputCapExceeded: () => jest.fn(),
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import "./ThroughputInput.less";
|
|||||||
export interface ThroughputInputProps {
|
export interface ThroughputInputProps {
|
||||||
isDatabase: boolean;
|
isDatabase: boolean;
|
||||||
isSharded: boolean;
|
isSharded: boolean;
|
||||||
isFreeTier: boolean;
|
|
||||||
showFreeTierExceedThroughputTooltip: boolean;
|
showFreeTierExceedThroughputTooltip: boolean;
|
||||||
setThroughputValue: (throughput: number) => void;
|
setThroughputValue: (throughput: number) => void;
|
||||||
setIsAutoscale: (isAutoscale: boolean) => void;
|
setIsAutoscale: (isAutoscale: boolean) => void;
|
||||||
@@ -24,20 +23,15 @@ export interface ThroughputInputProps {
|
|||||||
|
|
||||||
export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||||
isDatabase,
|
isDatabase,
|
||||||
isSharded,
|
|
||||||
isFreeTier,
|
|
||||||
showFreeTierExceedThroughputTooltip,
|
showFreeTierExceedThroughputTooltip,
|
||||||
setThroughputValue,
|
setThroughputValue,
|
||||||
setIsAutoscale,
|
setIsAutoscale,
|
||||||
setIsThroughputCapExceeded,
|
setIsThroughputCapExceeded,
|
||||||
|
isSharded,
|
||||||
onCostAcknowledgeChange,
|
onCostAcknowledgeChange,
|
||||||
}: ThroughputInputProps) => {
|
}: ThroughputInputProps) => {
|
||||||
const [isAutoscaleSelected, setIsAutoScaleSelected] = useState<boolean>(true);
|
const [isAutoscaleSelected, setIsAutoScaleSelected] = useState<boolean>(true);
|
||||||
const [throughput, setThroughput] = useState<number>(
|
const [throughput, setThroughput] = useState<number>(AutoPilotUtils.minAutoPilotThroughput);
|
||||||
isFreeTier && userContext.features.freetierAutoscaleThroughput
|
|
||||||
? AutoPilotUtils.autoPilotThroughput1K
|
|
||||||
: AutoPilotUtils.autoPilotThroughput4K
|
|
||||||
);
|
|
||||||
const [isCostAcknowledged, setIsCostAcknowledged] = useState<boolean>(false);
|
const [isCostAcknowledged, setIsCostAcknowledged] = useState<boolean>(false);
|
||||||
const [throughputError, setThroughputError] = useState<string>("");
|
const [throughputError, setThroughputError] = useState<string>("");
|
||||||
const [totalThroughputUsed, setTotalThroughputUsed] = useState<number>(0);
|
const [totalThroughputUsed, setTotalThroughputUsed] = useState<number>(0);
|
||||||
@@ -157,15 +151,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
|
|
||||||
const handleOnChangeMode = (event: React.ChangeEvent<HTMLInputElement>, mode: string): void => {
|
const handleOnChangeMode = (event: React.ChangeEvent<HTMLInputElement>, mode: string): void => {
|
||||||
if (mode === "Autoscale") {
|
if (mode === "Autoscale") {
|
||||||
const defaultThroughput =
|
setThroughput(AutoPilotUtils.minAutoPilotThroughput);
|
||||||
isFreeTier && userContext.features.freetierAutoscaleThroughput
|
|
||||||
? AutoPilotUtils.autoPilotThroughput1K
|
|
||||||
: AutoPilotUtils.autoPilotThroughput4K;
|
|
||||||
setThroughput(defaultThroughput);
|
|
||||||
setIsAutoScaleSelected(true);
|
setIsAutoScaleSelected(true);
|
||||||
setThroughputValue(defaultThroughput);
|
setThroughputValue(AutoPilotUtils.minAutoPilotThroughput);
|
||||||
setIsAutoscale(true);
|
setIsAutoscale(true);
|
||||||
checkThroughputCap(defaultThroughput);
|
checkThroughputCap(AutoPilotUtils.minAutoPilotThroughput);
|
||||||
} else {
|
} else {
|
||||||
setThroughput(SharedConstants.CollectionCreation.DefaultCollectionRUs400);
|
setThroughput(SharedConstants.CollectionCreation.DefaultCollectionRUs400);
|
||||||
setIsAutoScaleSelected(false);
|
setIsAutoScaleSelected(false);
|
||||||
@@ -236,11 +226,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
}}
|
}}
|
||||||
onChange={(event, newInput?: string) => onThroughputValueChange(newInput)}
|
onChange={(event, newInput?: string) => onThroughputValueChange(newInput)}
|
||||||
step={AutoPilotUtils.autoPilotIncrementStep}
|
step={AutoPilotUtils.autoPilotIncrementStep}
|
||||||
min={
|
min={AutoPilotUtils.minAutoPilotThroughput}
|
||||||
userContext.features.freetierAutoscaleThroughput
|
|
||||||
? AutoPilotUtils.autoPilotThroughput1K
|
|
||||||
: AutoPilotUtils.autoPilotThroughput4K
|
|
||||||
}
|
|
||||||
value={throughput.toString()}
|
value={throughput.toString()}
|
||||||
aria-label="Max request units per second"
|
aria-label="Max request units per second"
|
||||||
required={true}
|
required={true}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
exports[`ThroughputInput Pane should render Default properly 1`] = `
|
exports[`ThroughputInput Pane should render Default properly 1`] = `
|
||||||
<ThroughputInput
|
<ThroughputInput
|
||||||
isDatabase={false}
|
isDatabase={false}
|
||||||
isFreeTier={false}
|
|
||||||
isSharded={true}
|
isSharded={true}
|
||||||
onCostAcknowledgeChange={[Function]}
|
onCostAcknowledgeChange={[Function]}
|
||||||
setIsAutoscale={[Function]}
|
setIsAutoscale={[Function]}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { Link } from "@fluentui/react/lib/Link";
|
import { Link } from "@fluentui/react/lib/Link";
|
||||||
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
|
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
|
||||||
import { IGalleryItem } from "Juno/JunoClient";
|
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointValidation";
|
|
||||||
import shallow from "zustand/shallow";
|
import shallow from "zustand/shallow";
|
||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
||||||
@@ -26,6 +24,7 @@ import * as ViewModels from "../Contracts/ViewModels";
|
|||||||
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
||||||
import { useSidePanel } from "../hooks/useSidePanel";
|
import { useSidePanel } from "../hooks/useSidePanel";
|
||||||
import { useTabs } from "../hooks/useTabs";
|
import { useTabs } from "../hooks/useTabs";
|
||||||
|
import { IGalleryItem } from "../Juno/JunoClient";
|
||||||
import { PhoenixClient } from "../Phoenix/PhoenixClient";
|
import { PhoenixClient } from "../Phoenix/PhoenixClient";
|
||||||
import * as ExplorerSettings from "../Shared/ExplorerSettings";
|
import * as ExplorerSettings from "../Shared/ExplorerSettings";
|
||||||
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
||||||
@@ -47,7 +46,7 @@ import * as FileSystemUtil from "./Notebook/FileSystemUtil";
|
|||||||
import { SnapshotRequest } from "./Notebook/NotebookComponent/types";
|
import { SnapshotRequest } from "./Notebook/NotebookComponent/types";
|
||||||
import { NotebookContentItem, NotebookContentItemType } from "./Notebook/NotebookContentItem";
|
import { NotebookContentItem, NotebookContentItemType } from "./Notebook/NotebookContentItem";
|
||||||
import type NotebookManager from "./Notebook/NotebookManager";
|
import type NotebookManager from "./Notebook/NotebookManager";
|
||||||
import { NotebookPaneContent } from "./Notebook/NotebookManager";
|
import type { NotebookPaneContent } from "./Notebook/NotebookManager";
|
||||||
import { NotebookUtil } from "./Notebook/NotebookUtil";
|
import { NotebookUtil } from "./Notebook/NotebookUtil";
|
||||||
import { useNotebook } from "./Notebook/useNotebook";
|
import { useNotebook } from "./Notebook/useNotebook";
|
||||||
import { AddCollectionPanel } from "./Panes/AddCollectionPanel";
|
import { AddCollectionPanel } from "./Panes/AddCollectionPanel";
|
||||||
@@ -174,11 +173,7 @@ export default class Explorer {
|
|||||||
this.resourceTree = new ResourceTreeAdapter(this);
|
this.resourceTree = new ResourceTreeAdapter(this);
|
||||||
|
|
||||||
// Override notebook server parameters from URL parameters
|
// Override notebook server parameters from URL parameters
|
||||||
if (
|
if (userContext.features.notebookServerUrl && userContext.features.notebookServerToken) {
|
||||||
userContext.features.notebookServerUrl &&
|
|
||||||
validateEndpoint(userContext.features.notebookServerUrl, allowedNotebookServerUrls) &&
|
|
||||||
userContext.features.notebookServerToken
|
|
||||||
) {
|
|
||||||
useNotebook.getState().setNotebookServerInfo({
|
useNotebook.getState().setNotebookServerInfo({
|
||||||
notebookServerEndpoint: userContext.features.notebookServerUrl,
|
notebookServerEndpoint: userContext.features.notebookServerUrl,
|
||||||
authToken: userContext.features.notebookServerToken,
|
authToken: userContext.features.notebookServerToken,
|
||||||
@@ -190,6 +185,19 @@ export default class Explorer {
|
|||||||
useNotebook.getState().setNotebookBasePath(userContext.features.notebookBasePath);
|
useNotebook.getState().setNotebookBasePath(userContext.features.notebookBasePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (userContext.features.livyEndpoint) {
|
||||||
|
useNotebook.getState().setSparkClusterConnectionInfo({
|
||||||
|
userName: undefined,
|
||||||
|
password: undefined,
|
||||||
|
endpoints: [
|
||||||
|
{
|
||||||
|
endpoint: userContext.features.livyEndpoint,
|
||||||
|
kind: DataModels.SparkClusterEndpointKind.Livy,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.refreshExplorer();
|
this.refreshExplorer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,12 +394,6 @@ export default class Explorer {
|
|||||||
});
|
});
|
||||||
connectionStatus.status = ConnectionStatusType.Failed;
|
connectionStatus.status = ConnectionStatusType.Failed;
|
||||||
useNotebook.getState().resetContainerConnection(connectionStatus);
|
useNotebook.getState().resetContainerConnection(connectionStatus);
|
||||||
useDialog
|
|
||||||
.getState()
|
|
||||||
.showOkModalDialog(
|
|
||||||
"Connection Failed",
|
|
||||||
"We are unable to connect to the temporary workspace. Please try again in a few minutes. If the error persists, file a support ticket."
|
|
||||||
);
|
|
||||||
throw error;
|
throw error;
|
||||||
} finally {
|
} finally {
|
||||||
useNotebook.getState().setIsAllocating(false);
|
useNotebook.getState().setIsAllocating(false);
|
||||||
@@ -415,10 +417,7 @@ export default class Explorer {
|
|||||||
connectionStatus.status = ConnectionStatusType.Connected;
|
connectionStatus.status = ConnectionStatusType.Connected;
|
||||||
useNotebook.getState().setConnectionInfo(connectionStatus);
|
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||||
useNotebook.getState().setNotebookServerInfo({
|
useNotebook.getState().setNotebookServerInfo({
|
||||||
notebookServerEndpoint:
|
notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.data.notebookServerUrl,
|
||||||
(validateEndpoint(userContext.features.notebookServerUrl, allowedNotebookServerUrls) &&
|
|
||||||
userContext.features.notebookServerUrl) ||
|
|
||||||
connectionInfo.data.notebookServerUrl,
|
|
||||||
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
|
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
|
||||||
forwardingId: connectionInfo.data.forwardingId,
|
forwardingId: connectionInfo.data.forwardingId,
|
||||||
});
|
});
|
||||||
@@ -1244,10 +1243,7 @@ export default class Explorer {
|
|||||||
await useNotebook.getState().refreshNotebooksEnabledStateForAccount();
|
await useNotebook.getState().refreshNotebooksEnabledStateForAccount();
|
||||||
|
|
||||||
// TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount
|
// TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount
|
||||||
const isNotebookEnabled =
|
const isNotebookEnabled = userContext.features.notebooksDownBanner || useNotebook.getState().isPhoenixNotebooks;
|
||||||
userContext.features.notebooksDownBanner ||
|
|
||||||
useNotebook.getState().isPhoenixNotebooks ||
|
|
||||||
useNotebook.getState().isPhoenixFeatures;
|
|
||||||
useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled);
|
useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled);
|
||||||
useNotebook
|
useNotebook
|
||||||
.getState()
|
.getState()
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
.dataUploader {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
import { ImmutableOutput } from "@nteract/commutable";
|
|
||||||
import { actions, AppState, ContentRef, KernelRef, selectors } from "@nteract/core";
|
|
||||||
import Immutable from "immutable";
|
|
||||||
import React, { CSSProperties, useCallback, useMemo } from "react";
|
|
||||||
import { useDropzone } from "react-dropzone";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { Dispatch } from "redux";
|
|
||||||
import "./DataUploader.less";
|
|
||||||
|
|
||||||
interface DataUploaderPureProps {
|
|
||||||
contentRef: ContentRef;
|
|
||||||
kernelRef: KernelRef;
|
|
||||||
databaseId: string;
|
|
||||||
collectionId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getColor = (props) => {
|
|
||||||
if (props.isDragAccept) {
|
|
||||||
return "#00e676";
|
|
||||||
}
|
|
||||||
if (props.isDragReject) {
|
|
||||||
return "#ff1744";
|
|
||||||
}
|
|
||||||
if (props.isFocused) {
|
|
||||||
return "#2196f3";
|
|
||||||
}
|
|
||||||
return "#eeeeee";
|
|
||||||
};
|
|
||||||
|
|
||||||
interface DataUploaderDispatchProps {
|
|
||||||
runCell: (contentRef: ContentRef, cellId: string) => void;
|
|
||||||
addTransform: (transform: React.ComponentType & { MIMETYPE: string }) => void;
|
|
||||||
updateCell: (text: string, id: string, contentRef: ContentRef) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
type DataUploaderProps = DataUploaderPureProps & StateProps & DataUploaderDispatchProps;
|
|
||||||
|
|
||||||
const DataUploader: React.FC<DataUploaderProps> = (props) => {
|
|
||||||
// componentDidMount(): void {
|
|
||||||
// loadTransform(this.props);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// private onAnalyzeButtonClick = (filter: string = DefaultFilter, sampleSize: string = this.state.sampleSize) => {
|
|
||||||
// const query = {
|
|
||||||
// command: "listSchema",
|
|
||||||
// database: this.props.databaseId,
|
|
||||||
// collection: this.props.collectionId,
|
|
||||||
// outputType: this.state.outputType,
|
|
||||||
// filter,
|
|
||||||
// sampleSize,
|
|
||||||
// };
|
|
||||||
|
|
||||||
// this.setState({
|
|
||||||
// isFiltering: true,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// this.props.updateCell(JSON.stringify(query), this.props.firstCellId, this.props.contentRef);
|
|
||||||
|
|
||||||
// this.clickAnalyzeTelemetryStartKey = traceStart(Action.DataUploaderClickAnalyze, {
|
|
||||||
// database: this.props.databaseId,
|
|
||||||
// collection: this.props.collectionId,
|
|
||||||
// sampleSize,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// this.props.runCell(this.props.contentRef, this.props.firstCellId);
|
|
||||||
// };
|
|
||||||
|
|
||||||
const { firstCellId: id, contentRef, kernelStatus } = props;
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.log("firstCellId: id, contentRef, kernelStatus", id, contentRef, kernelStatus);
|
|
||||||
|
|
||||||
const isKernelBusy = kernelStatus === "busy";
|
|
||||||
const isKernelIdle = kernelStatus === "idle";
|
|
||||||
|
|
||||||
const baseStyle: CSSProperties = {
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
alignItems: "center",
|
|
||||||
padding: "20px",
|
|
||||||
borderWidth: 2,
|
|
||||||
borderRadius: 2,
|
|
||||||
borderColor: "#eeeeee",
|
|
||||||
borderStyle: "dashed",
|
|
||||||
backgroundColor: "#fafafa",
|
|
||||||
color: "#bdbdbd",
|
|
||||||
transition: "border .3s ease-in-out",
|
|
||||||
};
|
|
||||||
|
|
||||||
const activeStyle = {
|
|
||||||
borderColor: "#2196f3",
|
|
||||||
};
|
|
||||||
|
|
||||||
const acceptStyle = {
|
|
||||||
borderColor: "#00e676",
|
|
||||||
};
|
|
||||||
|
|
||||||
const rejectStyle = {
|
|
||||||
borderColor: "#ff1744",
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDrop = useCallback((acceptedFiles) => {
|
|
||||||
//eslint-disable-next-line no-console
|
|
||||||
console.log("acceptedFiles", acceptedFiles);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
|
|
||||||
onDrop,
|
|
||||||
accept: ".json",
|
|
||||||
});
|
|
||||||
|
|
||||||
const style = useMemo(
|
|
||||||
() => ({
|
|
||||||
...baseStyle,
|
|
||||||
...(isDragActive ? activeStyle : {}),
|
|
||||||
...(isDragAccept ? acceptStyle : {}),
|
|
||||||
...(isDragReject ? rejectStyle : {}),
|
|
||||||
}),
|
|
||||||
[isDragActive, isDragReject, isDragAccept]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!id) {
|
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div {...getRootProps({ style })}>
|
|
||||||
<input {...getInputProps()} />
|
|
||||||
<div>Drag and drop your json file here</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface StateProps {
|
|
||||||
firstCellId: string;
|
|
||||||
kernelStatus: string;
|
|
||||||
outputs: Immutable.List<ImmutableOutput>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface InitialProps {
|
|
||||||
kernelRef: string;
|
|
||||||
contentRef: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Redux
|
|
||||||
const makeMapStateToProps = (state: AppState, initialProps: InitialProps) => {
|
|
||||||
const { kernelRef, contentRef } = initialProps;
|
|
||||||
const mapStateToProps = (state: AppState) => {
|
|
||||||
let kernelStatus;
|
|
||||||
let firstCellId;
|
|
||||||
let outputs;
|
|
||||||
|
|
||||||
const kernel = selectors.kernel(state, { kernelRef });
|
|
||||||
if (kernel) {
|
|
||||||
kernelStatus = kernel.status;
|
|
||||||
}
|
|
||||||
|
|
||||||
const content = selectors.content(state, { contentRef });
|
|
||||||
if (content?.type === "notebook") {
|
|
||||||
const cellOrder = selectors.notebook.cellOrder(content.model);
|
|
||||||
if (cellOrder.size > 0) {
|
|
||||||
firstCellId = cellOrder.first() as string;
|
|
||||||
|
|
||||||
const model = selectors.model(state, { contentRef });
|
|
||||||
if (model && model.type === "notebook") {
|
|
||||||
const cell = selectors.notebook.cellById(model, { id: firstCellId });
|
|
||||||
if (cell) {
|
|
||||||
outputs = cell.get("outputs", Immutable.List());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
firstCellId,
|
|
||||||
kernelStatus,
|
|
||||||
outputs,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return mapStateToProps;
|
|
||||||
};
|
|
||||||
|
|
||||||
const makeMapDispatchToProps = () => {
|
|
||||||
const mapDispatchToProps = (dispatch: Dispatch) => {
|
|
||||||
return {
|
|
||||||
addTransform: (transform: React.ComponentType & { MIMETYPE: string }) => {
|
|
||||||
return dispatch(
|
|
||||||
actions.addTransform({
|
|
||||||
mediaType: transform.MIMETYPE,
|
|
||||||
component: transform,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
runCell: (contentRef: ContentRef, cellId: string) => {
|
|
||||||
return dispatch(
|
|
||||||
actions.executeCell({
|
|
||||||
contentRef,
|
|
||||||
id: cellId,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
updateCell: (text: string, id: string, contentRef: ContentRef) => {
|
|
||||||
dispatch(actions.updateCellSource({ id, contentRef, value: text }));
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return mapDispatchToProps;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(makeMapStateToProps, makeMapDispatchToProps)(DataUploader);
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { actions, createContentRef, createKernelRef, KernelRef } from "@nteract/core";
|
|
||||||
import DataUploader from "Explorer/Notebook/DataUploader/DataUploader";
|
|
||||||
import * as React from "react";
|
|
||||||
import { Provider } from "react-redux";
|
|
||||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
|
||||||
import {
|
|
||||||
NotebookComponentBootstrapper,
|
|
||||||
NotebookComponentBootstrapperOptions,
|
|
||||||
} from "../NotebookComponent/NotebookComponentBootstrapper";
|
|
||||||
import { DataUploaderNotebook } from "./DataUploaderUtils";
|
|
||||||
|
|
||||||
export class DataUploaderAdapter extends NotebookComponentBootstrapper implements ReactAdapter {
|
|
||||||
public parameters: unknown;
|
|
||||||
private kernelRef: KernelRef;
|
|
||||||
|
|
||||||
constructor(options: NotebookComponentBootstrapperOptions, private databaseId: string, private collectionId: string) {
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
if (!this.contentRef) {
|
|
||||||
this.contentRef = createContentRef();
|
|
||||||
this.kernelRef = createKernelRef();
|
|
||||||
|
|
||||||
this.getStore().dispatch(
|
|
||||||
actions.fetchContent({
|
|
||||||
filepath: DataUploaderNotebook.path,
|
|
||||||
params: {},
|
|
||||||
kernelRef: this.kernelRef,
|
|
||||||
contentRef: this.contentRef,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderComponent(): JSX.Element {
|
|
||||||
const props = {
|
|
||||||
contentRef: this.contentRef,
|
|
||||||
kernelRef: this.kernelRef,
|
|
||||||
databaseId: this.databaseId,
|
|
||||||
collectionId: this.collectionId,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Provider store={this.getStore()}>
|
|
||||||
<DataUploader {...props} />;
|
|
||||||
</Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
import { Notebook } from "@nteract/commutable";
|
|
||||||
import { IContent } from "@nteract/types";
|
|
||||||
import * as InMemoryContentProviderUtils from "../NotebookComponent/ContentProviders/InMemoryContentProviderUtils";
|
|
||||||
|
|
||||||
const notebookName = "data-uploader-component-notebook.ipynb";
|
|
||||||
const notebookPath = InMemoryContentProviderUtils.toContentUri(notebookName);
|
|
||||||
const notebook: Notebook = {
|
|
||||||
cells: [
|
|
||||||
{
|
|
||||||
cell_type: "code",
|
|
||||||
metadata: {},
|
|
||||||
execution_count: 0,
|
|
||||||
outputs: [],
|
|
||||||
source: "",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
metadata: {
|
|
||||||
kernelspec: {
|
|
||||||
displayName: "Mongo",
|
|
||||||
language: "mongocli",
|
|
||||||
name: "mongo",
|
|
||||||
},
|
|
||||||
language_info: {
|
|
||||||
file_extension: "ipynb",
|
|
||||||
mimetype: "application/json",
|
|
||||||
name: "mongo",
|
|
||||||
version: "1.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nbformat: 4,
|
|
||||||
nbformat_minor: 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const DataUploaderNotebook: IContent<"notebook"> = {
|
|
||||||
name: notebookName,
|
|
||||||
path: notebookPath,
|
|
||||||
type: "notebook",
|
|
||||||
writable: true,
|
|
||||||
created: "",
|
|
||||||
last_modified: "",
|
|
||||||
mimetype: "application/x-ipynb+json",
|
|
||||||
content: notebook,
|
|
||||||
format: "json",
|
|
||||||
};
|
|
||||||
@@ -19,7 +19,6 @@ export class NotebookContainerClient {
|
|||||||
private isResettingWorkspace: boolean;
|
private isResettingWorkspace: boolean;
|
||||||
private phoenixClient: PhoenixClient;
|
private phoenixClient: PhoenixClient;
|
||||||
private retryOptions: promiseRetry.Options;
|
private retryOptions: promiseRetry.Options;
|
||||||
private scheduleTimerId: NodeJS.Timeout;
|
|
||||||
|
|
||||||
constructor(private onConnectionLost: () => void) {
|
constructor(private onConnectionLost: () => void) {
|
||||||
this.phoenixClient = new PhoenixClient();
|
this.phoenixClient = new PhoenixClient();
|
||||||
@@ -28,36 +27,36 @@ export class NotebookContainerClient {
|
|||||||
maxTimeout: Notebook.retryAttemptDelayMs,
|
maxTimeout: Notebook.retryAttemptDelayMs,
|
||||||
minTimeout: Notebook.retryAttemptDelayMs,
|
minTimeout: Notebook.retryAttemptDelayMs,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.initHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private initHeartbeat(delayMs: number): void {
|
|
||||||
this.scheduleHeartbeat(delayMs);
|
|
||||||
|
|
||||||
useNotebook.subscribe(
|
|
||||||
() => this.scheduleHeartbeat(delayMs),
|
|
||||||
(state) => state.notebookServerInfo
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private scheduleHeartbeat(delayMs: number) {
|
|
||||||
if (this.scheduleTimerId) {
|
|
||||||
clearInterval(this.scheduleTimerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
||||||
if (notebookServerInfo?.notebookServerEndpoint) {
|
if (notebookServerInfo?.notebookServerEndpoint) {
|
||||||
this.scheduleTimerId = setInterval(async () => {
|
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
} else {
|
||||||
if (notebookServerInfo?.notebookServerEndpoint) {
|
const unsub = useNotebook.subscribe(
|
||||||
const memoryUsageInfo = await this.getMemoryUsage();
|
(newServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => {
|
||||||
useNotebook.getState().setMemoryUsageInfo(memoryUsageInfo);
|
if (newServerInfo?.notebookServerEndpoint) {
|
||||||
}
|
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||||
}, delayMs);
|
}
|
||||||
|
unsub();
|
||||||
|
},
|
||||||
|
(state) => state.notebookServerInfo
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Heartbeat: each ping schedules another ping
|
||||||
|
*/
|
||||||
|
private scheduleHeartbeat(delayMs: number): void {
|
||||||
|
setTimeout(async () => {
|
||||||
|
const memoryUsageInfo = await this.getMemoryUsage();
|
||||||
|
useNotebook.getState().setMemoryUsageInfo(memoryUsageInfo);
|
||||||
|
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
||||||
|
if (notebookServerInfo?.notebookServerEndpoint) {
|
||||||
|
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||||
|
}
|
||||||
|
}, delayMs);
|
||||||
|
}
|
||||||
|
|
||||||
public async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
|
public async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
||||||
if (!notebookServerInfo || !notebookServerInfo.notebookServerEndpoint) {
|
if (!notebookServerInfo || !notebookServerInfo.notebookServerEndpoint) {
|
||||||
|
|||||||
@@ -303,8 +303,8 @@ export class NotebookContentClient {
|
|||||||
private getServerConfig(): ServerConfig {
|
private getServerConfig(): ServerConfig {
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
||||||
return {
|
return {
|
||||||
endpoint: notebookServerInfo?.notebookServerEndpoint,
|
endpoint: notebookServerInfo.notebookServerEndpoint,
|
||||||
token: notebookServerInfo?.authToken,
|
token: notebookServerInfo.authToken,
|
||||||
crossDomain: true,
|
crossDomain: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
import { ImmutableNotebook } from "@nteract/commutable";
|
import { ImmutableNotebook } from "@nteract/commutable";
|
||||||
import type { IContentProvider } from "@nteract/core";
|
import type { IContentProvider } from "@nteract/core";
|
||||||
import { DataUploaderNotebook } from "Explorer/Notebook/DataUploader/DataUploaderUtils";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { contents } from "rx-jupyter";
|
import { contents } from "rx-jupyter";
|
||||||
import { Areas, HttpStatusCodes } from "../../Common/Constants";
|
import { Areas, HttpStatusCodes } from "../../Common/Constants";
|
||||||
@@ -69,10 +68,6 @@ export default class NotebookManager {
|
|||||||
readonly: true,
|
readonly: true,
|
||||||
content: SchemaAnalyzerNotebook,
|
content: SchemaAnalyzerNotebook,
|
||||||
},
|
},
|
||||||
[DataUploaderNotebook.path]: {
|
|
||||||
readonly: true,
|
|
||||||
content: DataUploaderNotebook,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gitHubContentProvider = new GitHubContentProvider({
|
this.gitHubContentProvider = new GitHubContentProvider({
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ describe("OpenActions", () => {
|
|||||||
collection.onDocumentDBDocumentsClick = jest.fn();
|
collection.onDocumentDBDocumentsClick = jest.fn();
|
||||||
collection.onMongoDBDocumentsClick = jest.fn();
|
collection.onMongoDBDocumentsClick = jest.fn();
|
||||||
collection.onSchemaAnalyzerClick = jest.fn();
|
collection.onSchemaAnalyzerClick = jest.fn();
|
||||||
collection.onDataUploaderClick = jest.fn();
|
|
||||||
collection.onTableEntitiesClick = jest.fn();
|
collection.onTableEntitiesClick = jest.fn();
|
||||||
collection.onGraphDocumentsClick = jest.fn();
|
collection.onGraphDocumentsClick = jest.fn();
|
||||||
collection.onNewQueryClick = jest.fn();
|
collection.onNewQueryClick = jest.fn();
|
||||||
|
|||||||
@@ -86,14 +86,6 @@ function openCollectionTab(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
action.tabKind === ActionContracts.TabKind.DataUploader ||
|
|
||||||
action.tabKind === ActionContracts.TabKind[ActionContracts.TabKind.DataUploader]
|
|
||||||
) {
|
|
||||||
collection.onDataUploaderClick();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
action.tabKind === ActionContracts.TabKind.TableEntities ||
|
action.tabKind === ActionContracts.TabKind.TableEntities ||
|
||||||
action.tabKind === ActionContracts.TabKind[ActionContracts.TabKind.TableEntities]
|
action.tabKind === ActionContracts.TabKind[ActionContracts.TabKind.TableEntities]
|
||||||
|
|||||||
@@ -249,7 +249,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
showFreeTierExceedThroughputTooltip={this.isFreeTierAccount() && !isFirstResourceCreated}
|
showFreeTierExceedThroughputTooltip={this.isFreeTierAccount() && !isFirstResourceCreated}
|
||||||
isDatabase={true}
|
isDatabase={true}
|
||||||
isSharded={this.state.isSharded}
|
isSharded={this.state.isSharded}
|
||||||
isFreeTier={this.isFreeTierAccount()}
|
|
||||||
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
||||||
@@ -484,7 +483,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
showFreeTierExceedThroughputTooltip={this.isFreeTierAccount() && !isFirstResourceCreated}
|
showFreeTierExceedThroughputTooltip={this.isFreeTierAccount() && !isFirstResourceCreated}
|
||||||
isDatabase={false}
|
isDatabase={false}
|
||||||
isSharded={this.state.isSharded}
|
isSharded={this.state.isSharded}
|
||||||
isFreeTier={this.isFreeTierAccount()}
|
|
||||||
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
||||||
|
|||||||
@@ -146,10 +146,9 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
|
|||||||
// TODO add feature flag that disables validation for customers with custom accounts
|
// TODO add feature flag that disables validation for customers with custom accounts
|
||||||
if (isAutoscaleSelected) {
|
if (isAutoscaleSelected) {
|
||||||
if (!AutoPilotUtils.isValidAutoPilotThroughput(throughput)) {
|
if (!AutoPilotUtils.isValidAutoPilotThroughput(throughput)) {
|
||||||
const minAutoPilotThroughput = userContext.features.freetierAutoscaleThroughput
|
setFormErrors(
|
||||||
? AutoPilotUtils.autoPilotThroughput1K
|
`Please enter a value greater than ${AutoPilotUtils.minAutoPilotThroughput} for autopilot throughput`
|
||||||
: AutoPilotUtils.autoPilotThroughput4K;
|
);
|
||||||
setFormErrors(`Please enter a value greater than ${minAutoPilotThroughput} for autopilot throughput`);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +241,6 @@ export const AddDatabasePanel: FunctionComponent<AddDatabasePaneProps> = ({
|
|||||||
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
|
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
|
||||||
isDatabase={true}
|
isDatabase={true}
|
||||||
isSharded={databaseCreateNewShared}
|
isSharded={databaseCreateNewShared}
|
||||||
isFreeTier={isFreeTierAccount}
|
|
||||||
setThroughputValue={(newThroughput: number) => (throughput = newThroughput)}
|
setThroughputValue={(newThroughput: number) => (throughput = newThroughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (isAutoscaleSelected = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (isAutoscaleSelected = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
||||||
|
|||||||
@@ -262,7 +262,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
|
|||||||
}
|
}
|
||||||
isDatabase
|
isDatabase
|
||||||
isSharded
|
isSharded
|
||||||
isFreeTier={isFreeTierAccount}
|
|
||||||
setThroughputValue={(throughput: number) => (newKeySpaceThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (newKeySpaceThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (isNewKeySpaceAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (isNewKeySpaceAutoscale = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
||||||
@@ -336,7 +335,6 @@ export const CassandraAddCollectionPane: FunctionComponent<CassandraAddCollectio
|
|||||||
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
|
showFreeTierExceedThroughputTooltip={isFreeTierAccount && !useDatabases.getState().isFirstResourceCreated()}
|
||||||
isDatabase={false}
|
isDatabase={false}
|
||||||
isSharded
|
isSharded
|
||||||
isFreeTier={isFreeTierAccount}
|
|
||||||
setThroughputValue={(throughput: number) => (tableThroughput = throughput)}
|
setThroughputValue={(throughput: number) => (tableThroughput = throughput)}
|
||||||
setIsAutoscale={(isAutoscale: boolean) => (isTableAutoscale = isAutoscale)}
|
setIsAutoscale={(isAutoscale: boolean) => (isTableAutoscale = isAutoscale)}
|
||||||
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
setIsThroughputCapExceeded={(isCapExceeded: boolean) => setIsThroughputCapExceeded(isCapExceeded)}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUti
|
|||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import { NotebookContentItem, NotebookContentItemType } from "../../Notebook/NotebookContentItem";
|
import { NotebookContentItem, NotebookContentItemType } from "../../Notebook/NotebookContentItem";
|
||||||
import { useNotebook } from "../../Notebook/useNotebook";
|
import { useNotebook } from "../../Notebook/useNotebook";
|
||||||
|
import { ResourceTreeAdapter } from "../../Tree/ResourceTreeAdapter";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||||
import { CopyNotebookPaneComponent, CopyNotebookPaneProps } from "./CopyNotebookPaneComponent";
|
import { CopyNotebookPaneComponent, CopyNotebookPaneProps } from "./CopyNotebookPaneComponent";
|
||||||
|
|
||||||
@@ -103,14 +104,11 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
|
|||||||
switch (location.type) {
|
switch (location.type) {
|
||||||
case "MyNotebooks":
|
case "MyNotebooks":
|
||||||
parent = {
|
parent = {
|
||||||
name: useNotebook.getState().notebookFolderName,
|
name: ResourceTreeAdapter.MyNotebooksTitle,
|
||||||
path: useNotebook.getState().notebookBasePath,
|
path: useNotebook.getState().notebookBasePath,
|
||||||
type: NotebookContentItemType.Directory,
|
type: NotebookContentItemType.Directory,
|
||||||
};
|
};
|
||||||
isGithubTree = false;
|
isGithubTree = false;
|
||||||
if (useNotebook.getState().isPhoenixNotebooks) {
|
|
||||||
await container.allocateContainer();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "GitHub":
|
case "GitHub":
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -35,60 +35,6 @@ const {
|
|||||||
Smallint,
|
Smallint,
|
||||||
Tinyint,
|
Tinyint,
|
||||||
Timestamp,
|
Timestamp,
|
||||||
// List
|
|
||||||
List_Ascii,
|
|
||||||
List_Bigint,
|
|
||||||
List_Blob,
|
|
||||||
List_Boolean,
|
|
||||||
List_Date,
|
|
||||||
List_Decimal,
|
|
||||||
List_Double,
|
|
||||||
List_Float,
|
|
||||||
List_Int,
|
|
||||||
List_Text,
|
|
||||||
List_Timestamp,
|
|
||||||
List_Uuid,
|
|
||||||
List_Varchar,
|
|
||||||
List_Varint,
|
|
||||||
List_Inet,
|
|
||||||
List_Smallint,
|
|
||||||
List_Tinyint,
|
|
||||||
// Map
|
|
||||||
Map_Ascii,
|
|
||||||
Map_Bigint,
|
|
||||||
Map_Blob,
|
|
||||||
Map_Boolean,
|
|
||||||
Map_Date,
|
|
||||||
Map_Decimal,
|
|
||||||
Map_Double,
|
|
||||||
Map_Float,
|
|
||||||
Map_Int,
|
|
||||||
Map_Text,
|
|
||||||
Map_Timestamp,
|
|
||||||
Map_Uuid,
|
|
||||||
Map_Varchar,
|
|
||||||
Map_Varint,
|
|
||||||
Map_Inet,
|
|
||||||
Map_Smallint,
|
|
||||||
Map_Tinyint,
|
|
||||||
// Set
|
|
||||||
Set_Ascii,
|
|
||||||
Set_Bigint,
|
|
||||||
Set_Blob,
|
|
||||||
Set_Boolean,
|
|
||||||
Set_Date,
|
|
||||||
Set_Decimal,
|
|
||||||
Set_Double,
|
|
||||||
Set_Float,
|
|
||||||
Set_Int,
|
|
||||||
Set_Text,
|
|
||||||
Set_Timestamp,
|
|
||||||
Set_Uuid,
|
|
||||||
Set_Varchar,
|
|
||||||
Set_Varint,
|
|
||||||
Set_Inet,
|
|
||||||
Set_Smallint,
|
|
||||||
Set_Tinyint,
|
|
||||||
} = TableConstants.CassandraType;
|
} = TableConstants.CassandraType;
|
||||||
export const cassandraOptions = [
|
export const cassandraOptions = [
|
||||||
{ key: Text, text: Text },
|
{ key: Text, text: Text },
|
||||||
@@ -108,60 +54,6 @@ export const cassandraOptions = [
|
|||||||
{ key: Smallint, text: Smallint },
|
{ key: Smallint, text: Smallint },
|
||||||
{ key: Tinyint, text: Tinyint },
|
{ key: Tinyint, text: Tinyint },
|
||||||
{ key: Timestamp, text: Timestamp },
|
{ key: Timestamp, text: Timestamp },
|
||||||
// List
|
|
||||||
{ key: List_Ascii, text: List_Ascii },
|
|
||||||
{ key: List_Bigint, text: List_Bigint },
|
|
||||||
{ key: List_Blob, text: List_Blob },
|
|
||||||
{ key: List_Boolean, text: List_Boolean },
|
|
||||||
{ key: List_Date, text: List_Date },
|
|
||||||
{ key: List_Decimal, text: List_Decimal },
|
|
||||||
{ key: List_Double, text: List_Double },
|
|
||||||
{ key: List_Float, text: List_Float },
|
|
||||||
{ key: List_Int, text: List_Int },
|
|
||||||
{ key: List_Text, text: List_Text },
|
|
||||||
{ key: List_Timestamp, text: List_Timestamp },
|
|
||||||
{ key: List_Uuid, text: List_Uuid },
|
|
||||||
{ key: List_Varchar, text: List_Varchar },
|
|
||||||
{ key: List_Varint, text: List_Varint },
|
|
||||||
{ key: List_Inet, text: List_Inet },
|
|
||||||
{ key: List_Smallint, text: List_Smallint },
|
|
||||||
{ key: List_Tinyint, text: List_Tinyint },
|
|
||||||
// Map
|
|
||||||
{ key: Map_Ascii, text: Map_Ascii },
|
|
||||||
{ key: Map_Bigint, text: Map_Bigint },
|
|
||||||
{ key: Map_Blob, text: Map_Blob },
|
|
||||||
{ key: Map_Boolean, text: Map_Boolean },
|
|
||||||
{ key: Map_Date, text: Map_Date },
|
|
||||||
{ key: Map_Decimal, text: Map_Decimal },
|
|
||||||
{ key: Map_Double, text: Map_Double },
|
|
||||||
{ key: Map_Float, text: Map_Float },
|
|
||||||
{ key: Map_Int, text: Map_Int },
|
|
||||||
{ key: Map_Text, text: Map_Text },
|
|
||||||
{ key: Map_Timestamp, text: Map_Timestamp },
|
|
||||||
{ key: Map_Uuid, text: Map_Uuid },
|
|
||||||
{ key: Map_Varchar, text: Map_Varchar },
|
|
||||||
{ key: Map_Varint, text: Map_Varint },
|
|
||||||
{ key: Map_Inet, text: Map_Inet },
|
|
||||||
{ key: Map_Smallint, text: Map_Smallint },
|
|
||||||
{ key: Map_Tinyint, text: Map_Tinyint },
|
|
||||||
// Set
|
|
||||||
{ key: Set_Ascii, text: Set_Ascii },
|
|
||||||
{ key: Set_Bigint, text: Set_Bigint },
|
|
||||||
{ key: Set_Blob, text: Set_Blob },
|
|
||||||
{ key: Set_Boolean, text: Set_Boolean },
|
|
||||||
{ key: Set_Date, text: Set_Date },
|
|
||||||
{ key: Set_Decimal, text: Set_Decimal },
|
|
||||||
{ key: Set_Double, text: Set_Double },
|
|
||||||
{ key: Set_Float, text: Set_Float },
|
|
||||||
{ key: Set_Int, text: Set_Int },
|
|
||||||
{ key: Set_Text, text: Set_Text },
|
|
||||||
{ key: Set_Timestamp, text: Set_Timestamp },
|
|
||||||
{ key: Set_Uuid, text: Set_Uuid },
|
|
||||||
{ key: Set_Varchar, text: Set_Varchar },
|
|
||||||
{ key: Set_Varint, text: Set_Varint },
|
|
||||||
{ key: Set_Inet, text: Set_Inet },
|
|
||||||
{ key: Set_Smallint, text: Set_Smallint },
|
|
||||||
{ key: Set_Tinyint, text: Set_Tinyint },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export const imageProps: IImageProps = {
|
export const imageProps: IImageProps = {
|
||||||
|
|||||||
@@ -27,60 +27,6 @@ export const CassandraType = {
|
|||||||
Inet: "Inet",
|
Inet: "Inet",
|
||||||
Smallint: "Smallint",
|
Smallint: "Smallint",
|
||||||
Tinyint: "Tinyint",
|
Tinyint: "Tinyint",
|
||||||
|
|
||||||
List_Ascii: "List<Ascii>",
|
|
||||||
List_Bigint: "List<Bigint>",
|
|
||||||
List_Blob: "List<Blob>",
|
|
||||||
List_Boolean: "List<Boolean>",
|
|
||||||
List_Date: "List<Date>",
|
|
||||||
List_Decimal: "List<Decimal>",
|
|
||||||
List_Double: "List<Double>",
|
|
||||||
List_Float: "List<Float>",
|
|
||||||
List_Int: "List<Int>",
|
|
||||||
List_Text: "List<Text>",
|
|
||||||
List_Timestamp: "List<Timestamp>",
|
|
||||||
List_Uuid: "List<Uuid>",
|
|
||||||
List_Varchar: "List<Varchar>",
|
|
||||||
List_Varint: "List<Varint>",
|
|
||||||
List_Inet: "List<Inet>",
|
|
||||||
List_Smallint: "List<Smallint>",
|
|
||||||
List_Tinyint: "List<Tinyint>",
|
|
||||||
|
|
||||||
Map_Ascii: "Map<Ascii>",
|
|
||||||
Map_Bigint: "Map<Bigint>",
|
|
||||||
Map_Blob: "Map<Blob>",
|
|
||||||
Map_Boolean: "Map<Boolean>",
|
|
||||||
Map_Date: "Map<Date>",
|
|
||||||
Map_Decimal: "Map<Decimal>",
|
|
||||||
Map_Double: "Map<Double>",
|
|
||||||
Map_Float: "Map<Float>",
|
|
||||||
Map_Int: "Map<Int>",
|
|
||||||
Map_Text: "Map<Text>",
|
|
||||||
Map_Timestamp: "Map<Timestamp>",
|
|
||||||
Map_Uuid: "Map<Uuid>",
|
|
||||||
Map_Varchar: "Map<Varchar>",
|
|
||||||
Map_Varint: "Map<Varint>",
|
|
||||||
Map_Inet: "Map<Inet>",
|
|
||||||
Map_Smallint: "Map<Smallint>",
|
|
||||||
Map_Tinyint: "Map<Tinyint>",
|
|
||||||
|
|
||||||
Set_Ascii: "Set<Ascii>",
|
|
||||||
Set_Bigint: "Set<Bigint>",
|
|
||||||
Set_Blob: "Set<Blob>",
|
|
||||||
Set_Boolean: "Set<Boolean>",
|
|
||||||
Set_Date: "Set<Date>",
|
|
||||||
Set_Decimal: "Set<Decimal>",
|
|
||||||
Set_Double: "Set<Double>",
|
|
||||||
Set_Float: "Set<Float>",
|
|
||||||
Set_Int: "Set<Int>",
|
|
||||||
Set_Text: "Set<Text>",
|
|
||||||
Set_Timestamp: "Set<Timestamp>",
|
|
||||||
Set_Uuid: "Set<Uuid>",
|
|
||||||
Set_Varchar: "Set<Varchar>",
|
|
||||||
Set_Varint: "Set<Varint>",
|
|
||||||
Set_Inet: "Set<Inet>",
|
|
||||||
Set_Smallint: "Set<Smallint>",
|
|
||||||
Set_Tinyint: "Set<Tinyint>",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ClauseRule = {
|
export const ClauseRule = {
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import * as Constants from "../../Common/Constants";
|
|
||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
|
||||||
import { traceSuccess } from "../../Shared/Telemetry/TelemetryProcessor";
|
|
||||||
import { DataUploaderAdapter } from "../Notebook/DataUploader/DataUploaderAdapter";
|
|
||||||
import NotebookTabBase, { NotebookTabBaseOptions } from "./NotebookTabBase";
|
|
||||||
|
|
||||||
export default class DataUploaderTab extends NotebookTabBase {
|
|
||||||
public readonly html = '<div data-bind="react:DataUploaderAdapter" style="height: 100%"></div>';
|
|
||||||
private DataUploaderAdapter: DataUploaderAdapter;
|
|
||||||
|
|
||||||
constructor(options: NotebookTabBaseOptions) {
|
|
||||||
super(options);
|
|
||||||
this.DataUploaderAdapter = new DataUploaderAdapter(
|
|
||||||
{
|
|
||||||
contentRef: undefined,
|
|
||||||
notebookClient: NotebookTabBase.clientManager,
|
|
||||||
},
|
|
||||||
options.collection?.databaseId,
|
|
||||||
options.collection?.id()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public onActivate(): void {
|
|
||||||
traceSuccess(
|
|
||||||
Action.Tab,
|
|
||||||
{
|
|
||||||
databaseName: this.collection?.databaseId,
|
|
||||||
collectionName: this.collection?.id,
|
|
||||||
dataExplorerArea: Constants.Areas.Tab,
|
|
||||||
tabTitle: "Upload",
|
|
||||||
},
|
|
||||||
this.onLoadStartKey
|
|
||||||
);
|
|
||||||
|
|
||||||
super.onActivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected buildCommandBarOptions(): void {
|
|
||||||
this.updateNavbarWithTabsButtons();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -215,13 +215,13 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
|||||||
{
|
{
|
||||||
metric: "Request Charge",
|
metric: "Request Charge",
|
||||||
value: this.state.requestChargeDisplayText,
|
value: this.state.requestChargeDisplayText,
|
||||||
toolTip: "Request Charge",
|
toolTip: "",
|
||||||
isQueryMetricsEnabled: true,
|
isQueryMetricsEnabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
metric: "Showing Results",
|
metric: "Showing Results",
|
||||||
value: this.state.showingDocumentsDisplayText,
|
value: this.state.showingDocumentsDisplayText,
|
||||||
toolTip: "Showing Results",
|
toolTip: "",
|
||||||
isQueryMetricsEnabled: true,
|
isQueryMetricsEnabled: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -574,52 +574,6 @@ export default class Collection implements ViewModels.Collection {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
public onDataUploaderClick = async () => {
|
|
||||||
if (useNotebook.getState().isPhoenixFeatures) {
|
|
||||||
await this.container.allocateContainer();
|
|
||||||
}
|
|
||||||
useSelectedNode.getState().setSelectedNode(this);
|
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.SchemaAnalyzer);
|
|
||||||
const DataUploaderTab = await (await import("../Tabs/DataUploaderTab")).default;
|
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
|
||||||
description: "Data uploader node",
|
|
||||||
databaseName: this.databaseId,
|
|
||||||
collectionName: this.id(),
|
|
||||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const tab of useTabs.getState().openedTabs) {
|
|
||||||
if (
|
|
||||||
tab instanceof DataUploaderTab &&
|
|
||||||
tab.collection?.databaseId === this.databaseId &&
|
|
||||||
tab.collection?.id() === this.id()
|
|
||||||
) {
|
|
||||||
return useTabs.getState().activateTab(tab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const startKey = TelemetryProcessor.traceStart(Action.Tab, {
|
|
||||||
databaseName: this.databaseId,
|
|
||||||
collectionName: this.id(),
|
|
||||||
dataExplorerArea: Constants.Areas.Tab,
|
|
||||||
tabTitle: "Upload",
|
|
||||||
});
|
|
||||||
this.documentIds([]);
|
|
||||||
useTabs.getState().activateNewTab(
|
|
||||||
new DataUploaderTab({
|
|
||||||
account: userContext.databaseAccount,
|
|
||||||
masterKey: userContext.masterKey || "",
|
|
||||||
container: this.container,
|
|
||||||
tabKind: ViewModels.CollectionTabKind.DataUploader,
|
|
||||||
title: "Upload",
|
|
||||||
tabPath: "",
|
|
||||||
collection: this,
|
|
||||||
node: this,
|
|
||||||
onLoadStartKey: startKey,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
public onSettingsClick = async (): Promise<void> => {
|
public onSettingsClick = async (): Promise<void> => {
|
||||||
useSelectedNode.getState().setSelectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit;
|
const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit;
|
||||||
|
|||||||
@@ -526,15 +526,6 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
.getState()
|
.getState()
|
||||||
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.SchemaAnalyzer]),
|
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.SchemaAnalyzer]),
|
||||||
});
|
});
|
||||||
|
|
||||||
children.push({
|
|
||||||
label: "Data Upload (Preview)",
|
|
||||||
onClick: collection.onDataUploaderClick.bind(collection),
|
|
||||||
isSelected: () =>
|
|
||||||
useSelectedNode
|
|
||||||
.getState()
|
|
||||||
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.DataUploader]),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {
|
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {
|
||||||
|
|||||||
@@ -283,15 +283,6 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
.getState()
|
.getState()
|
||||||
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.SchemaAnalyzer]),
|
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.SchemaAnalyzer]),
|
||||||
});
|
});
|
||||||
|
|
||||||
children.push({
|
|
||||||
label: "Data Upload (Preview)",
|
|
||||||
onClick: collection.onDataUploaderClick.bind(collection),
|
|
||||||
isSelected: () =>
|
|
||||||
useSelectedNode
|
|
||||||
.getState()
|
|
||||||
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.DataUploader]),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {
|
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import ko from "knockout";
|
import ko from "knockout";
|
||||||
import { allowedJunoOrigins, validateEndpoint } from "Utils/EndpointValidation";
|
|
||||||
import { GetGithubClientId } from "Utils/GitHubUtils";
|
import { GetGithubClientId } from "Utils/GitHubUtils";
|
||||||
import { HttpHeaders, HttpStatusCodes } from "../Common/Constants";
|
import { HttpHeaders, HttpStatusCodes } from "../Common/Constants";
|
||||||
import { configContext } from "../ConfigContext";
|
import { configContext } from "../ConfigContext";
|
||||||
@@ -485,7 +484,7 @@ export class JunoClient {
|
|||||||
// public for tests
|
// public for tests
|
||||||
public static getJunoEndpoint(): string {
|
public static getJunoEndpoint(): string {
|
||||||
const junoEndpoint = userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
const junoEndpoint = userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
||||||
if (!validateEndpoint(junoEndpoint, allowedJunoOrigins)) {
|
if (configContext.allowedJunoOrigins.indexOf(new URL(junoEndpoint).origin) === -1) {
|
||||||
const error = `${junoEndpoint} not allowed as juno endpoint`;
|
const error = `${junoEndpoint} not allowed as juno endpoint`;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import promiseRetry, { AbortError } from "p-retry";
|
import promiseRetry, { AbortError } from "p-retry";
|
||||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||||
import { allowedJunoOrigins, validateEndpoint } from "Utils/EndpointValidation";
|
|
||||||
import {
|
import {
|
||||||
Areas,
|
Areas,
|
||||||
ConnectionStatusType,
|
ConnectionStatusType,
|
||||||
@@ -155,7 +154,7 @@ export class PhoenixClient {
|
|||||||
public static getPhoenixEndpoint(): string {
|
public static getPhoenixEndpoint(): string {
|
||||||
const phoenixEndpoint =
|
const phoenixEndpoint =
|
||||||
userContext.features.phoenixEndpoint ?? userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
userContext.features.phoenixEndpoint ?? userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
||||||
if (!validateEndpoint(phoenixEndpoint, allowedJunoOrigins)) {
|
if (configContext.allowedJunoOrigins.indexOf(new URL(phoenixEndpoint).origin) === -1) {
|
||||||
const error = `${phoenixEndpoint} not allowed as juno endpoint`;
|
const error = `${phoenixEndpoint} not allowed as juno endpoint`;
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
export type Features = {
|
export type Features = {
|
||||||
// set only via feature flags
|
|
||||||
readonly canExceedMaximumValue: boolean;
|
readonly canExceedMaximumValue: boolean;
|
||||||
readonly cosmosdb: boolean;
|
readonly cosmosdb: boolean;
|
||||||
readonly enableChangeFeedPolicy: boolean;
|
readonly enableChangeFeedPolicy: boolean;
|
||||||
@@ -9,6 +8,12 @@ export type Features = {
|
|||||||
readonly enableReactPane: boolean;
|
readonly enableReactPane: boolean;
|
||||||
readonly enableRightPanelV2: boolean;
|
readonly enableRightPanelV2: boolean;
|
||||||
readonly enableSchema: boolean;
|
readonly enableSchema: boolean;
|
||||||
|
autoscaleDefault: boolean;
|
||||||
|
partitionKeyDefault: boolean;
|
||||||
|
partitionKeyDefault2: boolean;
|
||||||
|
phoenixNotebooks: boolean;
|
||||||
|
phoenixFeatures: boolean;
|
||||||
|
notebooksDownBanner: boolean;
|
||||||
readonly enableSDKoperations: boolean;
|
readonly enableSDKoperations: boolean;
|
||||||
readonly enableSpark: boolean;
|
readonly enableSpark: boolean;
|
||||||
readonly enableTtl: boolean;
|
readonly enableTtl: boolean;
|
||||||
@@ -18,6 +23,7 @@ export type Features = {
|
|||||||
readonly hostedDataExplorer: boolean;
|
readonly hostedDataExplorer: boolean;
|
||||||
readonly junoEndpoint?: string;
|
readonly junoEndpoint?: string;
|
||||||
readonly phoenixEndpoint?: string;
|
readonly phoenixEndpoint?: string;
|
||||||
|
readonly livyEndpoint?: string;
|
||||||
readonly notebookBasePath?: string;
|
readonly notebookBasePath?: string;
|
||||||
readonly notebookServerToken?: string;
|
readonly notebookServerToken?: string;
|
||||||
readonly notebookServerUrl?: string;
|
readonly notebookServerUrl?: string;
|
||||||
@@ -29,22 +35,11 @@ export type Features = {
|
|||||||
readonly mongoProxyEndpoint?: string;
|
readonly mongoProxyEndpoint?: string;
|
||||||
readonly mongoProxyAPIs?: string;
|
readonly mongoProxyAPIs?: string;
|
||||||
readonly enableThroughputCap: boolean;
|
readonly enableThroughputCap: boolean;
|
||||||
|
|
||||||
// can be set via both flight and feature flag
|
|
||||||
autoscaleDefault: boolean;
|
|
||||||
partitionKeyDefault: boolean;
|
|
||||||
partitionKeyDefault2: boolean;
|
|
||||||
phoenixNotebooks?: boolean;
|
|
||||||
phoenixFeatures?: boolean;
|
|
||||||
notebooksDownBanner: boolean;
|
|
||||||
freetierAutoscaleThroughput: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function extractFeatures(given = new URLSearchParams(window.location.search)): Features {
|
export function extractFeatures(given = new URLSearchParams(window.location.search)): Features {
|
||||||
const downcased = new URLSearchParams();
|
const downcased = new URLSearchParams();
|
||||||
const set = (value: string, key: string) => {
|
const set = (value: string, key: string) => downcased.set(key.toLowerCase(), value);
|
||||||
downcased.set(key.toLowerCase(), value);
|
|
||||||
};
|
|
||||||
const get = (key: string, defaultValue?: string) =>
|
const get = (key: string, defaultValue?: string) =>
|
||||||
downcased.get("feature." + key) ?? downcased.get(key) ?? defaultValue;
|
downcased.get("feature." + key) ?? downcased.get(key) ?? defaultValue;
|
||||||
|
|
||||||
@@ -77,6 +72,7 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
|||||||
mongoProxyAPIs: get("mongoproxyapis"),
|
mongoProxyAPIs: get("mongoproxyapis"),
|
||||||
junoEndpoint: get("junoendpoint"),
|
junoEndpoint: get("junoendpoint"),
|
||||||
phoenixEndpoint: get("phoenixendpoint"),
|
phoenixEndpoint: get("phoenixendpoint"),
|
||||||
|
livyEndpoint: get("livyendpoint"),
|
||||||
notebookBasePath: get("notebookbasepath"),
|
notebookBasePath: get("notebookbasepath"),
|
||||||
notebookServerToken: get("notebookservertoken"),
|
notebookServerToken: get("notebookservertoken"),
|
||||||
notebookServerUrl: get("notebookserverurl"),
|
notebookServerUrl: get("notebookserverurl"),
|
||||||
@@ -88,9 +84,10 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
|||||||
autoscaleDefault: "true" === get("autoscaledefault"),
|
autoscaleDefault: "true" === get("autoscaledefault"),
|
||||||
partitionKeyDefault: "true" === get("partitionkeytest"),
|
partitionKeyDefault: "true" === get("partitionkeytest"),
|
||||||
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
|
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
|
||||||
|
phoenixNotebooks: "true" === get("phoenixnotebooks"),
|
||||||
|
phoenixFeatures: "true" === get("phoenixfeatures"),
|
||||||
notebooksDownBanner: "true" === get("notebooksDownBanner"),
|
notebooksDownBanner: "true" === get("notebooksDownBanner"),
|
||||||
enableThroughputCap: "true" === get("enablethroughputcap"),
|
enableThroughputCap: "true" === get("enablethroughputcap"),
|
||||||
freetierAutoscaleThroughput: "true" === get("freetierautoscalethroughput"),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import { userContext } from "UserContext";
|
export const minAutoPilotThroughput = 4000;
|
||||||
|
|
||||||
export const autoPilotThroughput1K = 1000;
|
|
||||||
export const autoPilotIncrementStep = 1000;
|
export const autoPilotIncrementStep = 1000;
|
||||||
export const autoPilotThroughput4K = 4000;
|
|
||||||
|
|
||||||
export function isValidAutoPilotThroughput(maxThroughput: number): boolean {
|
export function isValidAutoPilotThroughput(maxThroughput: number): boolean {
|
||||||
if (!maxThroughput) {
|
if (!maxThroughput) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const minAutoPilotThroughput = userContext.features.freetierAutoscaleThroughput
|
|
||||||
? autoPilotThroughput4K
|
|
||||||
: autoPilotThroughput1K;
|
|
||||||
if (maxThroughput < minAutoPilotThroughput) {
|
if (maxThroughput < minAutoPilotThroughput) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
import { JunoEndpoints } from "Common/Constants";
|
|
||||||
import * as Logger from "../Common/Logger";
|
|
||||||
|
|
||||||
export function validateEndpoint(
|
|
||||||
endpointToValidate: string | undefined,
|
|
||||||
allowedEndpoints: ReadonlyArray<string>
|
|
||||||
): boolean {
|
|
||||||
try {
|
|
||||||
return validateEndpointInternal(
|
|
||||||
endpointToValidate,
|
|
||||||
allowedEndpoints.map((e) => e)
|
|
||||||
);
|
|
||||||
} catch (reason) {
|
|
||||||
Logger.logError(`${endpointToValidate} not allowed`, "validateEndpoint");
|
|
||||||
Logger.logError(`${JSON.stringify(reason)}`, "validateEndpoint");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function validateEndpointInternal(
|
|
||||||
endpointToValidate: string | undefined,
|
|
||||||
allowedEndpoints: ReadonlyArray<string>
|
|
||||||
): boolean {
|
|
||||||
if (endpointToValidate === undefined) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const originToValidate: string = new URL(endpointToValidate).origin;
|
|
||||||
const allowedOrigins: string[] = allowedEndpoints.map((allowedEndpoint) => new URL(allowedEndpoint).origin) || [];
|
|
||||||
const valid = allowedOrigins.indexOf(originToValidate) >= 0;
|
|
||||||
|
|
||||||
if (!valid) {
|
|
||||||
throw new Error(
|
|
||||||
`${endpointToValidate} is not an allowed endpoint. Allowed endpoints are ${allowedEndpoints.toString()}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const allowedArmEndpoints: ReadonlyArray<string> = [
|
|
||||||
"https://management.azure.com",
|
|
||||||
"https://management.usgovcloudapi.net",
|
|
||||||
"https://management.chinacloudapi.cn",
|
|
||||||
];
|
|
||||||
|
|
||||||
export const allowedAadEndpoints: ReadonlyArray<string> = ["https://login.microsoftonline.com/"];
|
|
||||||
|
|
||||||
export const allowedBackendEndpoints: ReadonlyArray<string> = [
|
|
||||||
"https://main.documentdb.ext.azure.com",
|
|
||||||
"https://main.documentdb.ext.azure.cn",
|
|
||||||
"https://main.documentdb.ext.azure.us",
|
|
||||||
"https://localhost:12901",
|
|
||||||
"https://localhost:1234",
|
|
||||||
];
|
|
||||||
|
|
||||||
export const allowedMongoProxyEndpoints: ReadonlyArray<string> = [
|
|
||||||
"https://main.documentdb.ext.azure.com",
|
|
||||||
"https://main.documentdb.ext.azure.cn",
|
|
||||||
"https://main.documentdb.ext.azure.us",
|
|
||||||
"https://localhost:12901",
|
|
||||||
];
|
|
||||||
|
|
||||||
export const allowedEmulatorEndpoints: ReadonlyArray<string> = ["https://localhost:8081"];
|
|
||||||
|
|
||||||
export const allowedMongoBackendEndpoints: ReadonlyArray<string> = ["https://localhost:1234"];
|
|
||||||
|
|
||||||
export const allowedGraphEndpoints: ReadonlyArray<string> = ["https://graph.windows.net"];
|
|
||||||
|
|
||||||
export const allowedArcadiaEndpoints: ReadonlyArray<string> = ["https://workspaceartifacts.projectarcadia.net"];
|
|
||||||
|
|
||||||
export const allowedHostedExplorerEndpoints: ReadonlyArray<string> = ["https://cosmos.azure.com/"];
|
|
||||||
|
|
||||||
export const allowedMsalRedirectEndpoints: ReadonlyArray<string> = [
|
|
||||||
"https://cosmos-explorer-preview.azurewebsites.net/",
|
|
||||||
];
|
|
||||||
|
|
||||||
export const allowedJunoOrigins: ReadonlyArray<string> = [
|
|
||||||
JunoEndpoints.Test,
|
|
||||||
JunoEndpoints.Test2,
|
|
||||||
JunoEndpoints.Test3,
|
|
||||||
JunoEndpoints.Prod,
|
|
||||||
JunoEndpoints.Stage,
|
|
||||||
"https://localhost",
|
|
||||||
];
|
|
||||||
|
|
||||||
export const allowedNotebookServerUrls: ReadonlyArray<string> = [];
|
|
||||||
@@ -4,7 +4,7 @@ export function isInvalidParentFrameOrigin(event: MessageEvent): boolean {
|
|||||||
return !isValidOrigin(configContext.allowedParentFrameOrigins, event);
|
return !isValidOrigin(configContext.allowedParentFrameOrigins, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidOrigin(allowedOrigins: ReadonlyArray<string>, event: MessageEvent): boolean {
|
function isValidOrigin(allowedOrigins: string[], event: MessageEvent): boolean {
|
||||||
const eventOrigin = (event && event.origin) || "";
|
const eventOrigin = (event && event.origin) || "";
|
||||||
const windowOrigin = (window && window.origin) || "";
|
const windowOrigin = (window && window.origin) || "";
|
||||||
if (eventOrigin === windowOrigin) {
|
if (eventOrigin === windowOrigin) {
|
||||||
|
|||||||
@@ -351,11 +351,6 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
|
|||||||
if (inputs.features) {
|
if (inputs.features) {
|
||||||
Object.assign(userContext.features, extractFeatures(new URLSearchParams(inputs.features)));
|
Object.assign(userContext.features, extractFeatures(new URLSearchParams(inputs.features)));
|
||||||
}
|
}
|
||||||
//Updating phoenix feature flags for MPAC based of config context
|
|
||||||
if (configContext.isPhoenixEnabled === true) {
|
|
||||||
userContext.features.phoenixNotebooks = true;
|
|
||||||
userContext.features.phoenixFeatures = true;
|
|
||||||
}
|
|
||||||
if (inputs.flights) {
|
if (inputs.flights) {
|
||||||
if (inputs.flights.indexOf(Flights.AutoscaleTest) !== -1) {
|
if (inputs.flights.indexOf(Flights.AutoscaleTest) !== -1) {
|
||||||
userContext.features.autoscaleDefault;
|
userContext.features.autoscaleDefault;
|
||||||
@@ -378,9 +373,6 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
|
|||||||
if (inputs.flights.indexOf(Flights.NotebooksDownBanner) !== -1) {
|
if (inputs.flights.indexOf(Flights.NotebooksDownBanner) !== -1) {
|
||||||
userContext.features.notebooksDownBanner = true;
|
userContext.features.notebooksDownBanner = true;
|
||||||
}
|
}
|
||||||
if (inputs.flights.indexOf(Flights.FreeTierAutoscaleThroughput) !== -1) {
|
|
||||||
userContext.features.freetierAutoscaleThroughput = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user