mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-08 03:57:31 +00:00
Compare commits
6 Commits
fix_a11y_s
...
languy-add
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cc98f0b62 | ||
|
|
5c8016ecd6 | ||
|
|
605117c62d | ||
|
|
7a809cd2bc | ||
|
|
0a51e24b94 | ||
|
|
f36a881679 |
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"JUNO_ENDPOINT": "https://tools-staging.cosmos.azure.com",
|
"JUNO_ENDPOINT": "https://tools-staging.cosmos.azure.com",
|
||||||
"isTerminalEnabled" : true
|
"isTerminalEnabled" : true,
|
||||||
|
"isPhoenixEnabled" : true
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"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,6 +6866,11 @@
|
|||||||
"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",
|
||||||
@@ -10815,6 +10820,21 @@
|
|||||||
"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",
|
||||||
@@ -20978,6 +20998,28 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"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,6 +86,7 @@
|
|||||||
"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,6 +99,7 @@ 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 {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ 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;
|
||||||
msalRedirectURI?: string;
|
msalRedirectURI?: string;
|
||||||
@@ -71,6 +72,7 @@ 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,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function resetConfigContext(): void {
|
export function resetConfigContext(): void {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ export enum TabKind {
|
|||||||
Graph,
|
Graph,
|
||||||
SQLQuery,
|
SQLQuery,
|
||||||
ScaleSettings,
|
ScaleSettings,
|
||||||
|
DataUploader,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ 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>;
|
||||||
@@ -364,6 +365,7 @@ 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 { minAutoPilotThroughput } from "../../../../../Utils/AutoPilotUtils";
|
import { autoPilotThroughput1K, autoPilotThroughput4K } 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={minAutoPilotThroughput}
|
min={userContext.features.freetierAutoscaleThroughput ? autoPilotThroughput1K : autoPilotThroughput4K}
|
||||||
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,6 +5,7 @@ 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,6 +14,7 @@ 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;
|
||||||
@@ -23,15 +24,20 @@ 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>(AutoPilotUtils.minAutoPilotThroughput);
|
const [throughput, setThroughput] = useState<number>(
|
||||||
|
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);
|
||||||
@@ -151,11 +157,15 @@ 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") {
|
||||||
setThroughput(AutoPilotUtils.minAutoPilotThroughput);
|
const defaultThroughput =
|
||||||
|
isFreeTier && userContext.features.freetierAutoscaleThroughput
|
||||||
|
? AutoPilotUtils.autoPilotThroughput1K
|
||||||
|
: AutoPilotUtils.autoPilotThroughput4K;
|
||||||
|
setThroughput(defaultThroughput);
|
||||||
setIsAutoScaleSelected(true);
|
setIsAutoScaleSelected(true);
|
||||||
setThroughputValue(AutoPilotUtils.minAutoPilotThroughput);
|
setThroughputValue(defaultThroughput);
|
||||||
setIsAutoscale(true);
|
setIsAutoscale(true);
|
||||||
checkThroughputCap(AutoPilotUtils.minAutoPilotThroughput);
|
checkThroughputCap(defaultThroughput);
|
||||||
} else {
|
} else {
|
||||||
setThroughput(SharedConstants.CollectionCreation.DefaultCollectionRUs400);
|
setThroughput(SharedConstants.CollectionCreation.DefaultCollectionRUs400);
|
||||||
setIsAutoScaleSelected(false);
|
setIsAutoScaleSelected(false);
|
||||||
@@ -226,7 +236,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
|||||||
}}
|
}}
|
||||||
onChange={(event, newInput?: string) => onThroughputValueChange(newInput)}
|
onChange={(event, newInput?: string) => onThroughputValueChange(newInput)}
|
||||||
step={AutoPilotUtils.autoPilotIncrementStep}
|
step={AutoPilotUtils.autoPilotIncrementStep}
|
||||||
min={AutoPilotUtils.minAutoPilotThroughput}
|
min={
|
||||||
|
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,6 +3,7 @@
|
|||||||
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]}
|
||||||
|
|||||||
@@ -386,6 +386,12 @@ 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);
|
||||||
@@ -1238,7 +1244,10 @@ 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 = userContext.features.notebooksDownBanner || useNotebook.getState().isPhoenixNotebooks;
|
const isNotebookEnabled =
|
||||||
|
userContext.features.notebooksDownBanner ||
|
||||||
|
useNotebook.getState().isPhoenixNotebooks ||
|
||||||
|
useNotebook.getState().isPhoenixFeatures;
|
||||||
useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled);
|
useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled);
|
||||||
useNotebook
|
useNotebook
|
||||||
.getState()
|
.getState()
|
||||||
|
|||||||
5
src/Explorer/Notebook/DataUploader/DataUploader.less
Normal file
5
src/Explorer/Notebook/DataUploader/DataUploader.less
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.dataUploader {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
209
src/Explorer/Notebook/DataUploader/DataUploader.tsx
Normal file
209
src/Explorer/Notebook/DataUploader/DataUploader.tsx
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
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);
|
||||||
48
src/Explorer/Notebook/DataUploader/DataUploaderAdapter.tsx
Normal file
48
src/Explorer/Notebook/DataUploader/DataUploaderAdapter.tsx
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/Explorer/Notebook/DataUploader/DataUploaderUtils.ts
Normal file
44
src/Explorer/Notebook/DataUploader/DataUploaderUtils.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
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,6 +19,7 @@ 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();
|
||||||
@@ -27,34 +28,34 @@ export class NotebookContainerClient {
|
|||||||
maxTimeout: Notebook.retryAttemptDelayMs,
|
maxTimeout: Notebook.retryAttemptDelayMs,
|
||||||
minTimeout: Notebook.retryAttemptDelayMs,
|
minTimeout: Notebook.retryAttemptDelayMs,
|
||||||
};
|
};
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
|
||||||
if (notebookServerInfo?.notebookServerEndpoint) {
|
this.initHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
||||||
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
|
||||||
} else {
|
|
||||||
const unsub = useNotebook.subscribe(
|
|
||||||
(newServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => {
|
|
||||||
if (newServerInfo?.notebookServerEndpoint) {
|
|
||||||
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
|
||||||
}
|
|
||||||
unsub();
|
|
||||||
},
|
|
||||||
(state) => state.notebookServerInfo
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private initHeartbeat(delayMs: number): void {
|
||||||
* Heartbeat: each ping schedules another ping
|
this.scheduleHeartbeat(delayMs);
|
||||||
*/
|
|
||||||
private scheduleHeartbeat(delayMs: number): void {
|
useNotebook.subscribe(
|
||||||
setTimeout(async () => {
|
() => this.scheduleHeartbeat(delayMs),
|
||||||
const memoryUsageInfo = await this.getMemoryUsage();
|
(state) => state.notebookServerInfo
|
||||||
useNotebook.getState().setMemoryUsageInfo(memoryUsageInfo);
|
);
|
||||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
}
|
||||||
if (notebookServerInfo?.notebookServerEndpoint) {
|
|
||||||
this.scheduleHeartbeat(Constants.Notebook.heartbeatDelayMs);
|
private scheduleHeartbeat(delayMs: number) {
|
||||||
}
|
if (this.scheduleTimerId) {
|
||||||
}, delayMs);
|
clearInterval(this.scheduleTimerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
||||||
|
if (notebookServerInfo?.notebookServerEndpoint) {
|
||||||
|
this.scheduleTimerId = setInterval(async () => {
|
||||||
|
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
||||||
|
if (notebookServerInfo?.notebookServerEndpoint) {
|
||||||
|
const memoryUsageInfo = await this.getMemoryUsage();
|
||||||
|
useNotebook.getState().setMemoryUsageInfo(memoryUsageInfo);
|
||||||
|
}
|
||||||
|
}, delayMs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
|
public async getMemoryUsage(): Promise<DataModels.MemoryUsageInfo> {
|
||||||
|
|||||||
@@ -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,6 +4,7 @@
|
|||||||
|
|
||||||
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";
|
||||||
@@ -68,6 +69,10 @@ 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,6 +26,7 @@ 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,6 +86,14 @@ 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,6 +249,7 @@ 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) =>
|
||||||
@@ -483,6 +484,7 @@ 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,9 +146,10 @@ 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)) {
|
||||||
setFormErrors(
|
const minAutoPilotThroughput = userContext.features.freetierAutoscaleThroughput
|
||||||
`Please enter a value greater than ${AutoPilotUtils.minAutoPilotThroughput} for autopilot throughput`
|
? AutoPilotUtils.autoPilotThroughput1K
|
||||||
);
|
: AutoPilotUtils.autoPilotThroughput4K;
|
||||||
|
setFormErrors(`Please enter a value greater than ${minAutoPilotThroughput} for autopilot throughput`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,6 +242,7 @@ 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,6 +262,7 @@ 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)}
|
||||||
@@ -335,6 +336,7 @@ 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,7 +10,6 @@ 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";
|
||||||
|
|
||||||
@@ -104,11 +103,14 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
|
|||||||
switch (location.type) {
|
switch (location.type) {
|
||||||
case "MyNotebooks":
|
case "MyNotebooks":
|
||||||
parent = {
|
parent = {
|
||||||
name: ResourceTreeAdapter.MyNotebooksTitle,
|
name: useNotebook.getState().notebookFolderName,
|
||||||
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,6 +35,60 @@ 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 },
|
||||||
@@ -54,6 +108,60 @@ 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,6 +27,60 @@ 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 = {
|
||||||
|
|||||||
41
src/Explorer/Tabs/DataUploaderTab.ts
Normal file
41
src/Explorer/Tabs/DataUploaderTab.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -574,6 +574,52 @@ 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,6 +526,15 @@ 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,6 +283,15 @@ 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,4 +1,5 @@
|
|||||||
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;
|
||||||
@@ -8,12 +9,6 @@ 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;
|
||||||
@@ -34,11 +29,22 @@ 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) => downcased.set(key.toLowerCase(), value);
|
const set = (value: string, key: string) => {
|
||||||
|
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;
|
||||||
|
|
||||||
@@ -82,10 +88,9 @@ 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,11 +1,16 @@
|
|||||||
export const minAutoPilotThroughput = 4000;
|
import { userContext } from "UserContext";
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -351,6 +351,11 @@ 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;
|
||||||
@@ -373,6 +378,9 @@ 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