mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-02-18 02:07:04 +00:00
Users/kcheekuri/aciconatinerpooling (#1008)
* initial changes for CP * Added container unprovisioning * Added postgreSQL terminal * changed postgres terminal -> shell * Initialize Container Request payload change * added postgres button * Added notebookServerInfo * Feature flag enabling and integration with phoenix * Remove postgre implementations * fix issues * fix format issues * fix format issues-1 * fix format issues-2 * fix format issues-3 * fix format issues-4 * fix format issues-5 * connection status component * connection status component-1 * connection status component-2 * connection status component-3 * address issues * removal of ms * removal of ms * removal of ms-1 * removal of time after connected * removal of time after connected * removing unnecessary code Co-authored-by: Srinath Narayanan <srnara@microsoft.com> Co-authored-by: Bala Lakshmi Narayanasami <balalakshmin@microsoft.com>
This commit is contained in:
parent
39dd293fc1
commit
95c9b7ee31
@ -96,6 +96,7 @@ export class Flights {
|
|||||||
public static readonly AutoscaleTest = "autoscaletest";
|
public static readonly AutoscaleTest = "autoscaletest";
|
||||||
public static readonly PartitionKeyTest = "partitionkeytest";
|
public static readonly PartitionKeyTest = "partitionkeytest";
|
||||||
public static readonly PKPartitionKeyTest = "pkpartitionkeytest";
|
public static readonly PKPartitionKeyTest = "pkpartitionkeytest";
|
||||||
|
public static readonly Phoenix = "phoenix";
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AfecFeatures {
|
export class AfecFeatures {
|
||||||
@ -337,6 +338,13 @@ export enum ConflictOperationType {
|
|||||||
Delete = "delete",
|
Delete = "delete",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ConnectionStatusType {
|
||||||
|
Connecting = "Connecting",
|
||||||
|
Allocating = "Allocating",
|
||||||
|
Connected = "Connected",
|
||||||
|
Failed = "Connection Failed",
|
||||||
|
}
|
||||||
|
|
||||||
export const EmulatorMasterKey =
|
export const EmulatorMasterKey =
|
||||||
//[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Well known public masterKey for emulator")]
|
//[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Well known public masterKey for emulator")]
|
||||||
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
|
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { ConnectionStatusType } from "../Common/Constants";
|
||||||
|
|
||||||
export interface DatabaseAccount {
|
export interface DatabaseAccount {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@ -496,3 +498,8 @@ export interface MemoryUsageInfo {
|
|||||||
freeKB: number;
|
freeKB: number;
|
||||||
totalKB: number;
|
totalKB: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ContainerConnectionInfo {
|
||||||
|
status: ConnectionStatusType;
|
||||||
|
//need to add ram and rom info
|
||||||
|
}
|
||||||
|
@ -181,8 +181,7 @@ export const Dialog: FC = () => {
|
|||||||
text: secondaryButtonText,
|
text: secondaryButtonText,
|
||||||
onClick: onSecondaryButtonClick,
|
onClick: onSecondaryButtonClick,
|
||||||
}
|
}
|
||||||
: {};
|
: undefined;
|
||||||
|
|
||||||
return visible ? (
|
return visible ? (
|
||||||
<FluentDialog {...dialogProps}>
|
<FluentDialog {...dialogProps}>
|
||||||
{choiceGroupProps && <ChoiceGroup {...choiceGroupProps} />}
|
{choiceGroupProps && <ChoiceGroup {...choiceGroupProps} />}
|
||||||
|
@ -34,6 +34,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"onRefreshDatabasesKeyPress": [Function],
|
"onRefreshDatabasesKeyPress": [Function],
|
||||||
"onRefreshResourcesClick": [Function],
|
"onRefreshResourcesClick": [Function],
|
||||||
|
"phoenixClient": PhoenixClient {},
|
||||||
"provideFeedbackEmail": [Function],
|
"provideFeedbackEmail": [Function],
|
||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
@ -101,6 +102,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"onRefreshDatabasesKeyPress": [Function],
|
"onRefreshDatabasesKeyPress": [Function],
|
||||||
"onRefreshResourcesClick": [Function],
|
"onRefreshResourcesClick": [Function],
|
||||||
|
"phoenixClient": PhoenixClient {},
|
||||||
"provideFeedbackEmail": [Function],
|
"provideFeedbackEmail": [Function],
|
||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
|
@ -4,6 +4,7 @@ import _ from "underscore";
|
|||||||
import { AuthType } from "../AuthType";
|
import { AuthType } from "../AuthType";
|
||||||
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
||||||
import * as Constants from "../Common/Constants";
|
import * as Constants from "../Common/Constants";
|
||||||
|
import { ConnectionStatusType } from "../Common/Constants";
|
||||||
import { readCollection } from "../Common/dataAccess/readCollection";
|
import { readCollection } from "../Common/dataAccess/readCollection";
|
||||||
import { readDatabases } from "../Common/dataAccess/readDatabases";
|
import { readDatabases } from "../Common/dataAccess/readDatabases";
|
||||||
import { isPublicInternetAccessAllowed } from "../Common/DatabaseAccountUtility";
|
import { isPublicInternetAccessAllowed } from "../Common/DatabaseAccountUtility";
|
||||||
@ -16,6 +17,7 @@ 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 { IGalleryItem } from "../Juno/JunoClient";
|
||||||
|
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";
|
||||||
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
||||||
@ -87,12 +89,13 @@ export default class Explorer {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private static readonly MaxNbDatabasesToAutoExpand = 5;
|
private static readonly MaxNbDatabasesToAutoExpand = 5;
|
||||||
|
private phoenixClient: PhoenixClient;
|
||||||
constructor() {
|
constructor() {
|
||||||
const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, {
|
const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, {
|
||||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
dataExplorerArea: Constants.Areas.ResourceTree,
|
||||||
});
|
});
|
||||||
this._isInitializingNotebooks = false;
|
this._isInitializingNotebooks = false;
|
||||||
|
this.phoenixClient = new PhoenixClient();
|
||||||
useNotebook.subscribe(
|
useNotebook.subscribe(
|
||||||
() => this.refreshCommandBarButtons(),
|
() => this.refreshCommandBarButtons(),
|
||||||
(state) => state.isNotebooksEnabledForAccount
|
(state) => state.isNotebooksEnabledForAccount
|
||||||
@ -343,19 +346,43 @@ export default class Explorer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._isInitializingNotebooks = true;
|
this._isInitializingNotebooks = true;
|
||||||
|
if (userContext.features.phoenix) {
|
||||||
|
const connectionStatus: DataModels.ContainerConnectionInfo = {
|
||||||
|
status: ConnectionStatusType.Allocating,
|
||||||
|
};
|
||||||
|
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||||
|
const provisionData = {
|
||||||
|
cosmosEndpoint: userContext.databaseAccount.properties.documentEndpoint,
|
||||||
|
resourceId: userContext.databaseAccount.id,
|
||||||
|
dbAccountName: userContext.databaseAccount.name,
|
||||||
|
aadToken: userContext.authorizationToken,
|
||||||
|
resourceGroup: userContext.resourceGroup,
|
||||||
|
subscriptionId: userContext.subscriptionId,
|
||||||
|
};
|
||||||
|
const connectionInfo = await this.phoenixClient.containerConnectionInfo(provisionData);
|
||||||
|
if (connectionInfo.data && connectionInfo.data.notebookServerUrl) {
|
||||||
|
connectionStatus.status = ConnectionStatusType.Connected;
|
||||||
|
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||||
|
|
||||||
await this.ensureNotebookWorkspaceRunning();
|
useNotebook.getState().setNotebookServerInfo({
|
||||||
const connectionInfo = await listConnectionInfo(
|
notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.data.notebookServerUrl,
|
||||||
userContext.subscriptionId,
|
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
|
||||||
userContext.resourceGroup,
|
});
|
||||||
databaseAccount.name,
|
}
|
||||||
"default"
|
} else {
|
||||||
);
|
await this.ensureNotebookWorkspaceRunning();
|
||||||
|
const connectionInfo = await listConnectionInfo(
|
||||||
|
userContext.subscriptionId,
|
||||||
|
userContext.resourceGroup,
|
||||||
|
databaseAccount.name,
|
||||||
|
"default"
|
||||||
|
);
|
||||||
|
|
||||||
useNotebook.getState().setNotebookServerInfo({
|
useNotebook.getState().setNotebookServerInfo({
|
||||||
notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.notebookServerEndpoint,
|
notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.notebookServerEndpoint,
|
||||||
authToken: userContext.features.notebookServerToken || connectionInfo.authToken,
|
authToken: userContext.features.notebookServerToken || connectionInfo.authToken,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
useNotebook.getState().initializeNotebooksTree(this.notebookManager);
|
useNotebook.getState().initializeNotebooksTree(this.notebookManager);
|
||||||
|
|
||||||
@ -364,7 +391,7 @@ export default class Explorer {
|
|||||||
this._isInitializingNotebooks = false;
|
this._isInitializingNotebooks = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public resetNotebookWorkspace() {
|
public resetNotebookWorkspace(): void {
|
||||||
if (!useNotebook.getState().isNotebookEnabled || !this.notebookManager?.notebookClient) {
|
if (!useNotebook.getState().isNotebookEnabled || !this.notebookManager?.notebookClient) {
|
||||||
handleError(
|
handleError(
|
||||||
"Attempt to reset notebook workspace, but notebook is not enabled",
|
"Attempt to reset notebook workspace, but notebook is not enabled",
|
||||||
@ -389,7 +416,6 @@ export default class Explorer {
|
|||||||
if (!databaseAccount) {
|
if (!databaseAccount) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { value: workspaces } = await listByDatabaseAccount(
|
const { value: workspaces } = await listByDatabaseAccount(
|
||||||
userContext.subscriptionId,
|
userContext.subscriptionId,
|
||||||
@ -906,7 +932,7 @@ export default class Explorer {
|
|||||||
await this.notebookManager?.notebookContentClient.updateItemChildrenInPlace(item);
|
await this.notebookManager?.notebookContentClient.updateItemChildrenInPlace(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
public openNotebookTerminal(kind: ViewModels.TerminalKind) {
|
public openNotebookTerminal(kind: ViewModels.TerminalKind): void {
|
||||||
let title: string;
|
let title: string;
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
@ -1026,7 +1052,10 @@ export default class Explorer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async handleOpenFileAction(path: string): Promise<void> {
|
public async handleOpenFileAction(path: string): Promise<void> {
|
||||||
if (!(await this._containsDefaultNotebookWorkspace(userContext.databaseAccount))) {
|
if (
|
||||||
|
userContext.features.phoenix === false &&
|
||||||
|
!(await this._containsDefaultNotebookWorkspace(userContext.databaseAccount))
|
||||||
|
) {
|
||||||
this._openSetupNotebooksPaneForQuickstart();
|
this._openSetupNotebooksPaneForQuickstart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1072,10 +1101,13 @@ export default class Explorer {
|
|||||||
? this.refreshDatabaseForResourceToken()
|
? this.refreshDatabaseForResourceToken()
|
||||||
: this.refreshAllDatabases();
|
: this.refreshAllDatabases();
|
||||||
await useNotebook.getState().refreshNotebooksEnabledStateForAccount();
|
await useNotebook.getState().refreshNotebooksEnabledStateForAccount();
|
||||||
const isNotebookEnabled: boolean =
|
let isNotebookEnabled = true;
|
||||||
userContext.authType !== AuthType.ResourceToken &&
|
if (!userContext.features.phoenix) {
|
||||||
((await this._containsDefaultNotebookWorkspace(userContext.databaseAccount)) ||
|
isNotebookEnabled =
|
||||||
userContext.features.enableNotebooks);
|
userContext.authType !== AuthType.ResourceToken &&
|
||||||
|
((await this._containsDefaultNotebookWorkspace(userContext.databaseAccount)) ||
|
||||||
|
userContext.features.enableNotebooks);
|
||||||
|
}
|
||||||
useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled);
|
useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled);
|
||||||
useNotebook.getState().setIsShellEnabled(isNotebookEnabled && isPublicInternetAccessAllowed());
|
useNotebook.getState().setIsShellEnabled(isNotebookEnabled && isPublicInternetAccessAllowed());
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
|||||||
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
|
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
|
||||||
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
||||||
|
|
||||||
|
uiFabricControlButtons.unshift(CommandBarUtil.createConnectionStatus("connectionStatus"));
|
||||||
|
|
||||||
if (useTabs.getState().activeTab?.tabKind === ViewModels.CollectionTabKind.NotebookV2) {
|
if (useTabs.getState().activeTab?.tabKind === ViewModels.CollectionTabKind.NotebookV2) {
|
||||||
uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker"));
|
uiFabricControlButtons.unshift(CommandBarUtil.createMemoryTracker("memoryTracker"));
|
||||||
}
|
}
|
||||||
|
@ -80,8 +80,9 @@ export function createStaticCommandBarButtons(
|
|||||||
}
|
}
|
||||||
|
|
||||||
notebookButtons.push(createOpenTerminalButton(container));
|
notebookButtons.push(createOpenTerminalButton(container));
|
||||||
|
if (userContext.features.phoenix === false) {
|
||||||
notebookButtons.push(createNotebookWorkspaceResetButton(container));
|
notebookButtons.push(createNotebookWorkspaceResetButton(container));
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
(userContext.apiType === "Mongo" &&
|
(userContext.apiType === "Mongo" &&
|
||||||
useNotebook.getState().isShellEnabled &&
|
useNotebook.getState().isShellEnabled &&
|
||||||
|
@ -13,6 +13,7 @@ import { StyleConstants } from "../../../Common/Constants";
|
|||||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||||
|
import { ConnectionStatus } from "./ConnectionStatusComponent";
|
||||||
import { MemoryTracker } from "./MemoryTrackerComponent";
|
import { MemoryTracker } from "./MemoryTrackerComponent";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -201,3 +202,10 @@ export const createMemoryTracker = (key: string): ICommandBarItemProps => {
|
|||||||
onRender: () => <MemoryTracker />,
|
onRender: () => <MemoryTracker />,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createConnectionStatus = (key: string): ICommandBarItemProps => {
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
onRender: () => <ConnectionStatus />,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
79
src/Explorer/Menus/CommandBar/ConnectionStatusComponent.less
Normal file
79
src/Explorer/Menus/CommandBar/ConnectionStatusComponent.less
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
@import "../../../../less/Common/Constants";
|
||||||
|
|
||||||
|
.connectionStatusContainer {
|
||||||
|
cursor: default;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0 9px;
|
||||||
|
border: 1px;
|
||||||
|
min-height: 44px;
|
||||||
|
|
||||||
|
> span {
|
||||||
|
padding-right: 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: @DataExplorerFont;
|
||||||
|
color: @DefaultFontColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.connectionStatusFailed{
|
||||||
|
color: #bd1919;
|
||||||
|
}
|
||||||
|
.ring-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ringringGreen {
|
||||||
|
border: 3px solid green;
|
||||||
|
border-radius: 30px;
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
position: absolute;
|
||||||
|
margin: .4285em 0em 0em 0.07477em;
|
||||||
|
animation: pulsate 3s ease-out;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
opacity: 0.0
|
||||||
|
}
|
||||||
|
.ringringYellow{
|
||||||
|
border: 3px solid #ffbf00;
|
||||||
|
border-radius: 30px;
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
position: absolute;
|
||||||
|
margin: .4285em 0em 0em 0.07477em;
|
||||||
|
animation: pulsate 3s ease-out;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
opacity: 0.0
|
||||||
|
}
|
||||||
|
.ringringRed{
|
||||||
|
border: 3px solid #bd1919;
|
||||||
|
border-radius: 30px;
|
||||||
|
height: 18px;
|
||||||
|
width: 18px;
|
||||||
|
position: absolute;
|
||||||
|
margin: .4285em 0em 0em 0.07477em;
|
||||||
|
animation: pulsate 3s ease-out;
|
||||||
|
animation-iteration-count: infinite;
|
||||||
|
opacity: 0.0
|
||||||
|
}
|
||||||
|
@keyframes pulsate {
|
||||||
|
0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}
|
||||||
|
15% {opacity: 0.8;}
|
||||||
|
25% {opacity: 0.6;}
|
||||||
|
45% {opacity: 0.4;}
|
||||||
|
70% {opacity: 0.3;}
|
||||||
|
100% {-webkit-transform: scale(.7, .7); opacity: 0.1;}
|
||||||
|
}
|
||||||
|
.locationGreenDot{
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 0.07em;
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
.locationYellowDot{
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 0.07em;
|
||||||
|
color: #ffbf00;
|
||||||
|
}
|
||||||
|
.locationRedDot{
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 0.07em;
|
||||||
|
color: #bd1919;
|
||||||
|
}
|
77
src/Explorer/Menus/CommandBar/ConnectionStatusComponent.tsx
Normal file
77
src/Explorer/Menus/CommandBar/ConnectionStatusComponent.tsx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { Icon, ProgressIndicator, Spinner, SpinnerSize, Stack, TooltipHost } from "@fluentui/react";
|
||||||
|
import * as React from "react";
|
||||||
|
import { ConnectionStatusType } from "../../../Common/Constants";
|
||||||
|
import { useNotebook } from "../../Notebook/useNotebook";
|
||||||
|
import "../CommandBar/ConnectionStatusComponent.less";
|
||||||
|
|
||||||
|
export const ConnectionStatus: React.FC = (): JSX.Element => {
|
||||||
|
const [second, setSecond] = React.useState("00");
|
||||||
|
const [minute, setMinute] = React.useState("00");
|
||||||
|
const [isActive, setIsActive] = React.useState(false);
|
||||||
|
const [counter, setCounter] = React.useState(0);
|
||||||
|
const [statusColor, setStatusColor] = React.useState("locationYellowDot");
|
||||||
|
const [statusColorAnimation, setStatusColorAnimation] = React.useState("ringringYellow");
|
||||||
|
const toolTipContent = "Hosted runtime status.";
|
||||||
|
React.useEffect(() => {
|
||||||
|
let intervalId: NodeJS.Timeout;
|
||||||
|
|
||||||
|
if (isActive) {
|
||||||
|
intervalId = setInterval(() => {
|
||||||
|
const secondCounter = counter % 60;
|
||||||
|
const minuteCounter = Math.floor(counter / 60);
|
||||||
|
const computedSecond: string = String(secondCounter).length === 1 ? `0${secondCounter}` : `${secondCounter}`;
|
||||||
|
const computedMinute: string = String(minuteCounter).length === 1 ? `0${minuteCounter}` : `${minuteCounter}`;
|
||||||
|
|
||||||
|
setSecond(computedSecond);
|
||||||
|
setMinute(computedMinute);
|
||||||
|
|
||||||
|
setCounter((counter) => counter + 1);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
return () => clearInterval(intervalId);
|
||||||
|
}, [isActive, counter]);
|
||||||
|
|
||||||
|
const stopTimer = () => {
|
||||||
|
setIsActive(false);
|
||||||
|
setCounter(0);
|
||||||
|
setSecond("00");
|
||||||
|
setMinute("00");
|
||||||
|
};
|
||||||
|
|
||||||
|
const connectionInfo = useNotebook((state) => state.connectionInfo);
|
||||||
|
if (!connectionInfo) {
|
||||||
|
return (
|
||||||
|
<Stack className="connectionStatusContainer" horizontal>
|
||||||
|
<span>Connecting</span>
|
||||||
|
<Spinner size={SpinnerSize.medium} />
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (connectionInfo && connectionInfo.status === ConnectionStatusType.Allocating && isActive === false) {
|
||||||
|
setIsActive(true);
|
||||||
|
} else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Connected && isActive === true) {
|
||||||
|
stopTimer();
|
||||||
|
setStatusColor("locationGreenDot");
|
||||||
|
setStatusColorAnimation("ringringGreen");
|
||||||
|
} else if (connectionInfo && connectionInfo.status === ConnectionStatusType.Failed && isActive === true) {
|
||||||
|
stopTimer();
|
||||||
|
setStatusColor("locationRedDot");
|
||||||
|
setStatusColorAnimation("ringringRed");
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<TooltipHost content={toolTipContent}>
|
||||||
|
<Stack className="connectionStatusContainer" horizontal>
|
||||||
|
<div className="ring-container">
|
||||||
|
<div className={statusColorAnimation}></div>
|
||||||
|
<Icon iconName="LocationDot" className={statusColor} />
|
||||||
|
</div>
|
||||||
|
<span className={connectionInfo.status === ConnectionStatusType.Failed ? "connectionStatusFailed" : ""}>
|
||||||
|
{connectionInfo.status}
|
||||||
|
</span>
|
||||||
|
{connectionInfo.status === ConnectionStatusType.Allocating && isActive && (
|
||||||
|
<ProgressIndicator description={minute + ":" + second} />
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</TooltipHost>
|
||||||
|
);
|
||||||
|
};
|
@ -109,7 +109,7 @@ const formWebSocketURL = (serverConfig: NotebookServiceConfig, kernelId: string,
|
|||||||
const q = params.toString();
|
const q = params.toString();
|
||||||
const suffix = q !== "" ? `?${q}` : "";
|
const suffix = q !== "" ? `?${q}` : "";
|
||||||
|
|
||||||
const url = (serverConfig.endpoint || "") + `api/kernels/${kernelId}/channels${suffix}`;
|
const url = (serverConfig.endpoint.slice(0, -1) || "") + `api/kernels/${kernelId}/channels${suffix}`;
|
||||||
|
|
||||||
return url.replace(/^http(s)?/, "ws$1");
|
return url.replace(/^http(s)?/, "ws$1");
|
||||||
};
|
};
|
||||||
|
@ -56,7 +56,7 @@ export class NotebookContainerClient {
|
|||||||
|
|
||||||
const { notebookServerEndpoint, authToken } = this.getNotebookServerConfig();
|
const { notebookServerEndpoint, authToken } = this.getNotebookServerConfig();
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`${notebookServerEndpoint}/api/metrics/memory`, {
|
const response = await fetch(`${notebookServerEndpoint}api/metrics/memory`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: authToken,
|
Authorization: authToken,
|
||||||
|
@ -36,7 +36,10 @@ export class NotebookContentClient {
|
|||||||
*
|
*
|
||||||
* @param parent parent folder
|
* @param parent parent folder
|
||||||
*/
|
*/
|
||||||
public createNewNotebookFile(parent: NotebookContentItem, isGithubTree?: boolean): Promise<NotebookContentItem> {
|
public async createNewNotebookFile(
|
||||||
|
parent: NotebookContentItem,
|
||||||
|
isGithubTree?: boolean
|
||||||
|
): Promise<NotebookContentItem> {
|
||||||
if (!parent || parent.type !== NotebookContentItemType.Directory) {
|
if (!parent || parent.type !== NotebookContentItemType.Directory) {
|
||||||
throw new Error(`Parent must be a directory: ${parent}`);
|
throw new Error(`Parent must be a directory: ${parent}`);
|
||||||
}
|
}
|
||||||
@ -99,7 +102,6 @@ export class NotebookContentClient {
|
|||||||
if (!parent || parent.type !== NotebookContentItemType.Directory) {
|
if (!parent || parent.type !== NotebookContentItemType.Directory) {
|
||||||
throw new Error(`Parent must be a directory: ${parent}`);
|
throw new Error(`Parent must be a directory: ${parent}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const filepath = NotebookUtil.getFilePath(parent.path, name);
|
const filepath = NotebookUtil.getFilePath(parent.path, name);
|
||||||
if (await this.checkIfFilepathExists(filepath)) {
|
if (await this.checkIfFilepathExists(filepath)) {
|
||||||
throw new Error(`File already exists: ${filepath}`);
|
throw new Error(`File already exists: ${filepath}`);
|
||||||
|
@ -28,6 +28,8 @@ interface NotebookState {
|
|||||||
myNotebooksContentRoot: NotebookContentItem;
|
myNotebooksContentRoot: NotebookContentItem;
|
||||||
gitHubNotebooksContentRoot: NotebookContentItem;
|
gitHubNotebooksContentRoot: NotebookContentItem;
|
||||||
galleryContentRoot: NotebookContentItem;
|
galleryContentRoot: NotebookContentItem;
|
||||||
|
connectionInfo: DataModels.ContainerConnectionInfo;
|
||||||
|
NotebookFolderName: string;
|
||||||
setIsNotebookEnabled: (isNotebookEnabled: boolean) => void;
|
setIsNotebookEnabled: (isNotebookEnabled: boolean) => void;
|
||||||
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => void;
|
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => void;
|
||||||
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => void;
|
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) => void;
|
||||||
@ -43,6 +45,7 @@ interface NotebookState {
|
|||||||
deleteNotebookItem: (item: NotebookContentItem, isGithubTree?: boolean) => void;
|
deleteNotebookItem: (item: NotebookContentItem, isGithubTree?: boolean) => void;
|
||||||
initializeNotebooksTree: (notebookManager: NotebookManager) => Promise<void>;
|
initializeNotebooksTree: (notebookManager: NotebookManager) => Promise<void>;
|
||||||
initializeGitHubRepos: (pinnedRepos: IPinnedRepo[]) => void;
|
initializeGitHubRepos: (pinnedRepos: IPinnedRepo[]) => void;
|
||||||
|
setConnectionInfo: (connectionInfo: DataModels.ContainerConnectionInfo) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
||||||
@ -65,6 +68,8 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
|||||||
myNotebooksContentRoot: undefined,
|
myNotebooksContentRoot: undefined,
|
||||||
gitHubNotebooksContentRoot: undefined,
|
gitHubNotebooksContentRoot: undefined,
|
||||||
galleryContentRoot: undefined,
|
galleryContentRoot: undefined,
|
||||||
|
connectionInfo: undefined,
|
||||||
|
NotebookFolderName: userContext.features.phoenix ? "My Notebooks Scratch" : "My Notebooks",
|
||||||
setIsNotebookEnabled: (isNotebookEnabled: boolean) => set({ isNotebookEnabled }),
|
setIsNotebookEnabled: (isNotebookEnabled: boolean) => set({ isNotebookEnabled }),
|
||||||
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => set({ isNotebooksEnabledForAccount }),
|
setIsNotebooksEnabledForAccount: (isNotebooksEnabledForAccount: boolean) => set({ isNotebooksEnabledForAccount }),
|
||||||
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) =>
|
setNotebookServerInfo: (notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo) =>
|
||||||
@ -169,7 +174,7 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
|||||||
},
|
},
|
||||||
initializeNotebooksTree: async (notebookManager: NotebookManager): Promise<void> => {
|
initializeNotebooksTree: async (notebookManager: NotebookManager): Promise<void> => {
|
||||||
const myNotebooksContentRoot = {
|
const myNotebooksContentRoot = {
|
||||||
name: "My Notebooks",
|
name: get().NotebookFolderName,
|
||||||
path: get().notebookBasePath,
|
path: get().notebookBasePath,
|
||||||
type: NotebookContentItemType.Directory,
|
type: NotebookContentItemType.Directory,
|
||||||
};
|
};
|
||||||
@ -178,13 +183,11 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
|||||||
path: "Gallery",
|
path: "Gallery",
|
||||||
type: NotebookContentItemType.File,
|
type: NotebookContentItemType.File,
|
||||||
};
|
};
|
||||||
const gitHubNotebooksContentRoot = notebookManager?.gitHubOAuthService?.isLoggedIn()
|
const gitHubNotebooksContentRoot = {
|
||||||
? {
|
name: "GitHub repos",
|
||||||
name: "GitHub repos",
|
path: "PsuedoDir",
|
||||||
path: "PsuedoDir",
|
type: NotebookContentItemType.Directory,
|
||||||
type: NotebookContentItemType.Directory,
|
};
|
||||||
}
|
|
||||||
: undefined;
|
|
||||||
set({
|
set({
|
||||||
myNotebooksContentRoot,
|
myNotebooksContentRoot,
|
||||||
galleryContentRoot,
|
galleryContentRoot,
|
||||||
@ -246,4 +249,5 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
|||||||
set({ gitHubNotebooksContentRoot });
|
set({ gitHubNotebooksContentRoot });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
setConnectionInfo: (connectionInfo: DataModels.ContainerConnectionInfo) => set({ connectionInfo }),
|
||||||
}));
|
}));
|
||||||
|
@ -5,6 +5,7 @@ import { getErrorMessage, handleError } from "../../../Common/ErrorHandlingUtils
|
|||||||
import { GitHubOAuthService } from "../../../GitHub/GitHubOAuthService";
|
import { GitHubOAuthService } from "../../../GitHub/GitHubOAuthService";
|
||||||
import { useSidePanel } from "../../../hooks/useSidePanel";
|
import { useSidePanel } from "../../../hooks/useSidePanel";
|
||||||
import { IPinnedRepo, JunoClient } from "../../../Juno/JunoClient";
|
import { IPinnedRepo, JunoClient } from "../../../Juno/JunoClient";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
import * as GitHubUtils from "../../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../../Utils/GitHubUtils";
|
||||||
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
@ -75,6 +76,8 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
|
|||||||
selectedLocation.owner,
|
selectedLocation.owner,
|
||||||
selectedLocation.repo
|
selectedLocation.repo
|
||||||
)} - ${selectedLocation.branch}`;
|
)} - ${selectedLocation.branch}`;
|
||||||
|
} else if (selectedLocation.type === "MyNotebooks" && userContext.features.phoenix) {
|
||||||
|
destination = "My Notebooks Scratch";
|
||||||
}
|
}
|
||||||
|
|
||||||
clearMessage = NotificationConsoleUtils.logConsoleProgress(`Copying ${name} to ${destination}`);
|
clearMessage = NotificationConsoleUtils.logConsoleProgress(`Copying ${name} to ${destination}`);
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
import React, { FormEvent, FunctionComponent } from "react";
|
import React, { FormEvent, FunctionComponent } from "react";
|
||||||
import { IPinnedRepo } from "../../../Juno/JunoClient";
|
import { IPinnedRepo } from "../../../Juno/JunoClient";
|
||||||
import * as GitHubUtils from "../../../Utils/GitHubUtils";
|
import * as GitHubUtils from "../../../Utils/GitHubUtils";
|
||||||
|
import { useNotebook } from "../../Notebook/useNotebook";
|
||||||
import { ResourceTreeAdapter } from "../../Tree/ResourceTreeAdapter";
|
import { ResourceTreeAdapter } from "../../Tree/ResourceTreeAdapter";
|
||||||
|
|
||||||
interface Location {
|
interface Location {
|
||||||
@ -46,11 +47,10 @@ export const CopyNotebookPaneComponent: FunctionComponent<CopyNotebookPaneProps>
|
|||||||
|
|
||||||
const getDropDownOptions = (): IDropdownOption[] => {
|
const getDropDownOptions = (): IDropdownOption[] => {
|
||||||
const options: IDropdownOption[] = [];
|
const options: IDropdownOption[] = [];
|
||||||
|
|
||||||
options.push({
|
options.push({
|
||||||
key: "MyNotebooks-Item",
|
key: "MyNotebooks-Item",
|
||||||
text: ResourceTreeAdapter.MyNotebooksTitle,
|
text: useNotebook.getState().NotebookFolderName,
|
||||||
title: ResourceTreeAdapter.MyNotebooksTitle,
|
title: useNotebook.getState().NotebookFolderName,
|
||||||
data: {
|
data: {
|
||||||
type: "MyNotebooks",
|
type: "MyNotebooks",
|
||||||
} as Location,
|
} as Location,
|
||||||
|
@ -23,6 +23,7 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
|
|||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"onRefreshDatabasesKeyPress": [Function],
|
"onRefreshDatabasesKeyPress": [Function],
|
||||||
"onRefreshResourcesClick": [Function],
|
"onRefreshResourcesClick": [Function],
|
||||||
|
"phoenixClient": PhoenixClient {},
|
||||||
"provideFeedbackEmail": [Function],
|
"provideFeedbackEmail": [Function],
|
||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
|
@ -13,6 +13,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
|||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"onRefreshDatabasesKeyPress": [Function],
|
"onRefreshDatabasesKeyPress": [Function],
|
||||||
"onRefreshResourcesClick": [Function],
|
"onRefreshResourcesClick": [Function],
|
||||||
|
"phoenixClient": PhoenixClient {},
|
||||||
"provideFeedbackEmail": [Function],
|
"provideFeedbackEmail": [Function],
|
||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
|
@ -131,14 +131,14 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
if (myNotebooksContentRoot) {
|
if (myNotebooksContentRoot) {
|
||||||
notebooksTree.children.push(buildMyNotebooksTree());
|
notebooksTree.children.push(buildMyNotebooksTree());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
if (container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
||||||
// collapse all other notebook nodes
|
// collapse all other notebook nodes
|
||||||
notebooksTree.children.forEach((node) => (node.isExpanded = false));
|
notebooksTree.children.forEach((node) => (node.isExpanded = false));
|
||||||
notebooksTree.children.push(buildGitHubNotebooksTree());
|
notebooksTree.children.push(buildGitHubNotebooksTree(true));
|
||||||
|
} else if (container.notebookManager && !container.notebookManager.gitHubOAuthService.isLoggedIn()) {
|
||||||
|
notebooksTree.children.push(buildGitHubNotebooksTree(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return notebooksTree;
|
return notebooksTree;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -178,7 +178,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
return myNotebooksTree;
|
return myNotebooksTree;
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildGitHubNotebooksTree = (): TreeNode => {
|
const buildGitHubNotebooksTree = (isConnected: boolean): TreeNode => {
|
||||||
const gitHubNotebooksTree: TreeNode = buildNotebookDirectoryNode(
|
const gitHubNotebooksTree: TreeNode = buildNotebookDirectoryNode(
|
||||||
gitHubNotebooksContentRoot,
|
gitHubNotebooksContentRoot,
|
||||||
(item: NotebookContentItem) => {
|
(item: NotebookContentItem) => {
|
||||||
@ -190,8 +190,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
},
|
},
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
const manageGitContextMenu: TreeNodeMenuItem[] = [
|
||||||
gitHubNotebooksTree.contextMenu = [
|
|
||||||
{
|
{
|
||||||
label: "Manage GitHub settings",
|
label: "Manage GitHub settings",
|
||||||
onClick: () =>
|
onClick: () =>
|
||||||
@ -216,7 +215,23 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
const connectGitContextMenu: TreeNodeMenuItem[] = [
|
||||||
|
{
|
||||||
|
label: "Connect to GitHub",
|
||||||
|
onClick: () =>
|
||||||
|
useSidePanel
|
||||||
|
.getState()
|
||||||
|
.openSidePanel(
|
||||||
|
"Connect to GitHub",
|
||||||
|
<GitHubReposPanel
|
||||||
|
explorer={container}
|
||||||
|
gitHubClientProp={container.notebookManager.gitHubClient}
|
||||||
|
junoClientProp={container.notebookManager.junoClient}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
gitHubNotebooksTree.contextMenu = isConnected ? manageGitContextMenu : connectGitContextMenu;
|
||||||
gitHubNotebooksTree.isExpanded = true;
|
gitHubNotebooksTree.isExpanded = true;
|
||||||
gitHubNotebooksTree.isAlphaSorted = true;
|
gitHubNotebooksTree.isAlphaSorted = true;
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ import UserDefinedFunction from "./UserDefinedFunction";
|
|||||||
|
|
||||||
export class ResourceTreeAdapter implements ReactAdapter {
|
export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
public static readonly MyNotebooksTitle = "My Notebooks";
|
public static readonly MyNotebooksTitle = "My Notebooks";
|
||||||
|
public static readonly MyNotebooksScratchTitle = "My Notebooks Scratch";
|
||||||
public static readonly GitHubReposTitle = "GitHub repos";
|
public static readonly GitHubReposTitle = "GitHub repos";
|
||||||
|
|
||||||
private static readonly DataTitle = "DATA";
|
private static readonly DataTitle = "DATA";
|
||||||
@ -130,9 +131,8 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
path: "Gallery",
|
path: "Gallery",
|
||||||
type: NotebookContentItemType.File,
|
type: NotebookContentItemType.File,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.myNotebooksContentRoot = {
|
this.myNotebooksContentRoot = {
|
||||||
name: ResourceTreeAdapter.MyNotebooksTitle,
|
name: useNotebook.getState().NotebookFolderName,
|
||||||
path: useNotebook.getState().notebookBasePath,
|
path: useNotebook.getState().notebookBasePath,
|
||||||
type: NotebookContentItemType.Directory,
|
type: NotebookContentItemType.Directory,
|
||||||
};
|
};
|
||||||
@ -146,16 +146,11 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
this.gitHubNotebooksContentRoot = {
|
||||||
if (this.container.notebookManager?.gitHubOAuthService.isLoggedIn()) {
|
name: ResourceTreeAdapter.GitHubReposTitle,
|
||||||
this.gitHubNotebooksContentRoot = {
|
path: ResourceTreeAdapter.PseudoDirPath,
|
||||||
name: ResourceTreeAdapter.GitHubReposTitle,
|
type: NotebookContentItemType.Directory,
|
||||||
path: ResourceTreeAdapter.PseudoDirPath,
|
};
|
||||||
type: NotebookContentItemType.Directory,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
this.gitHubNotebooksContentRoot = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all(refreshTasks);
|
return Promise.all(refreshTasks);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,7 @@ import "./Explorer/Controls/TreeComponent/treeComponent.less";
|
|||||||
import "./Explorer/Graph/GraphExplorerComponent/graphExplorer.less";
|
import "./Explorer/Graph/GraphExplorerComponent/graphExplorer.less";
|
||||||
import "./Explorer/Menus/CommandBar/CommandBarComponent.less";
|
import "./Explorer/Menus/CommandBar/CommandBarComponent.less";
|
||||||
import { CommandBar } from "./Explorer/Menus/CommandBar/CommandBarComponentAdapter";
|
import { CommandBar } from "./Explorer/Menus/CommandBar/CommandBarComponentAdapter";
|
||||||
|
import "./Explorer/Menus/CommandBar/ConnectionStatusComponent.less";
|
||||||
import "./Explorer/Menus/CommandBar/MemoryTrackerComponent.less";
|
import "./Explorer/Menus/CommandBar/MemoryTrackerComponent.less";
|
||||||
import "./Explorer/Menus/NotificationConsole/NotificationConsole.less";
|
import "./Explorer/Menus/NotificationConsole/NotificationConsole.less";
|
||||||
import { NotificationConsole } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
import { NotificationConsole } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||||
|
70
src/Phoenix/PhoenixClient.ts
Normal file
70
src/Phoenix/PhoenixClient.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { ConnectionStatusType, HttpHeaders, HttpStatusCodes } from "../Common/Constants";
|
||||||
|
import { configContext } from "../ConfigContext";
|
||||||
|
import * as DataModels from "../Contracts/DataModels";
|
||||||
|
import { useNotebook } from "../Explorer/Notebook/useNotebook";
|
||||||
|
import { userContext } from "../UserContext";
|
||||||
|
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
||||||
|
|
||||||
|
export interface IPhoenixResponse<T> {
|
||||||
|
status: number;
|
||||||
|
data: T;
|
||||||
|
}
|
||||||
|
export interface IPhoenixConnectionInfoResult {
|
||||||
|
readonly notebookAuthToken?: string;
|
||||||
|
readonly notebookServerUrl?: string;
|
||||||
|
}
|
||||||
|
export interface IProvosionData {
|
||||||
|
cosmosEndpoint: string;
|
||||||
|
resourceId: string;
|
||||||
|
dbAccountName: string;
|
||||||
|
aadToken: string;
|
||||||
|
resourceGroup: string;
|
||||||
|
subscriptionId: string;
|
||||||
|
}
|
||||||
|
export class PhoenixClient {
|
||||||
|
public async containerConnectionInfo(
|
||||||
|
provisionData: IProvosionData
|
||||||
|
): Promise<IPhoenixResponse<IPhoenixConnectionInfoResult>> {
|
||||||
|
const response = await window.fetch(`${this.getPhoenixContainerPoolingEndPoint()}/provision`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: PhoenixClient.getHeaders(),
|
||||||
|
body: JSON.stringify(provisionData),
|
||||||
|
});
|
||||||
|
let data: IPhoenixConnectionInfoResult;
|
||||||
|
if (response.status === HttpStatusCodes.OK) {
|
||||||
|
data = await response.json();
|
||||||
|
} else {
|
||||||
|
const connectionStatus: DataModels.ContainerConnectionInfo = {
|
||||||
|
status: ConnectionStatusType.Failed,
|
||||||
|
};
|
||||||
|
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: response.status,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getPhoenixEndpoint(): string {
|
||||||
|
const phoenixEndpoint = userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
||||||
|
if (configContext.allowedJunoOrigins.indexOf(new URL(phoenixEndpoint).origin) === -1) {
|
||||||
|
const error = `${phoenixEndpoint} not allowed as juno endpoint`;
|
||||||
|
console.error(error);
|
||||||
|
throw new Error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return phoenixEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPhoenixContainerPoolingEndPoint(): string {
|
||||||
|
return `${PhoenixClient.getPhoenixEndpoint()}/api/containerpooling`;
|
||||||
|
}
|
||||||
|
private static getHeaders(): HeadersInit {
|
||||||
|
const authorizationHeader = getAuthorizationHeader();
|
||||||
|
return {
|
||||||
|
[authorizationHeader.header]: authorizationHeader.token,
|
||||||
|
[HttpHeaders.contentType]: "application/json",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ export type Features = {
|
|||||||
autoscaleDefault: boolean;
|
autoscaleDefault: boolean;
|
||||||
partitionKeyDefault: boolean;
|
partitionKeyDefault: boolean;
|
||||||
partitionKeyDefault2: boolean;
|
partitionKeyDefault2: boolean;
|
||||||
|
phoenix: boolean;
|
||||||
readonly enableSDKoperations: boolean;
|
readonly enableSDKoperations: boolean;
|
||||||
readonly enableSpark: boolean;
|
readonly enableSpark: boolean;
|
||||||
readonly enableTtl: boolean;
|
readonly enableTtl: boolean;
|
||||||
@ -76,5 +77,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
|||||||
partitionKeyDefault: "true" === get("partitionkeytest"),
|
partitionKeyDefault: "true" === get("partitionkeytest"),
|
||||||
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
|
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
|
||||||
notebooksTemporarilyDown: "true" === get("notebookstemporarilydown", "true"),
|
notebooksTemporarilyDown: "true" === get("notebookstemporarilydown", "true"),
|
||||||
|
phoenix: "true" === get("phoenix"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
SortBy,
|
SortBy,
|
||||||
} from "../Explorer/Controls/NotebookGallery/GalleryViewerComponent";
|
} from "../Explorer/Controls/NotebookGallery/GalleryViewerComponent";
|
||||||
import Explorer from "../Explorer/Explorer";
|
import Explorer from "../Explorer/Explorer";
|
||||||
|
import { useNotebook } from "../Explorer/Notebook/useNotebook";
|
||||||
import { IGalleryItem, JunoClient } from "../Juno/JunoClient";
|
import { IGalleryItem, JunoClient } from "../Juno/JunoClient";
|
||||||
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
|
||||||
import { trace, traceFailure, traceStart, traceSuccess } from "../Shared/Telemetry/TelemetryProcessor";
|
import { trace, traceFailure, traceStart, traceSuccess } from "../Shared/Telemetry/TelemetryProcessor";
|
||||||
@ -223,11 +224,13 @@ export function downloadItem(
|
|||||||
|
|
||||||
const name = data.name;
|
const name = data.name;
|
||||||
useDialog.getState().showOkCancelModalDialog(
|
useDialog.getState().showOkCancelModalDialog(
|
||||||
"Download to My Notebooks",
|
`Download to ${useNotebook.getState().NotebookFolderName}`,
|
||||||
`Download ${name} from gallery as a copy to your notebooks to run and/or edit the notebook.`,
|
`Download ${name} from gallery as a copy to your notebooks to run and/or edit the notebook.`,
|
||||||
"Download",
|
"Download",
|
||||||
async () => {
|
async () => {
|
||||||
const clearInProgressMessage = logConsoleProgress(`Downloading ${name} to My Notebooks`);
|
const clearInProgressMessage = logConsoleProgress(
|
||||||
|
`Downloading ${name} to ${useNotebook.getState().NotebookFolderName}`
|
||||||
|
);
|
||||||
const startKey = traceStart(Action.NotebooksGalleryDownload, {
|
const startKey = traceStart(Action.NotebooksGalleryDownload, {
|
||||||
notebookId: data.id,
|
notebookId: data.id,
|
||||||
downloadCount: data.downloads,
|
downloadCount: data.downloads,
|
||||||
|
@ -339,6 +339,9 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
|
|||||||
if (inputs.flights.indexOf(Flights.PKPartitionKeyTest) !== -1) {
|
if (inputs.flights.indexOf(Flights.PKPartitionKeyTest) !== -1) {
|
||||||
userContext.features.partitionKeyDefault2 = true;
|
userContext.features.partitionKeyDefault2 = true;
|
||||||
}
|
}
|
||||||
|
if (inputs.flights.indexOf(Flights.Phoenix) !== -1) {
|
||||||
|
userContext.features.phoenix = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user