Add PSQL button

This commit is contained in:
artrejo 2022-09-16 00:17:07 -07:00
parent c2673ec707
commit 0c25eee29c
14 changed files with 73 additions and 62 deletions

View File

@ -1,5 +1,5 @@
{
"JUNO_ENDPOINT": "https://tools.cosmos.azure.com",
"isTerminalEnabled" : false,
"isPhoenixEnabled" : false
}
"JUNO_ENDPOINT": "https://localhost",
"isTerminalEnabled": false,
"isPhoenixEnabled": false
}

View File

@ -423,6 +423,6 @@ export class JunoEndpoints {
public static readonly Test = "https://juno-test.documents-dev.windows-int.net";
public static readonly Test2 = "https://juno-test2.documents-dev.windows-int.net";
public static readonly Test3 = "https://juno-test3.documents-dev.windows-int.net";
public static readonly Prod = "https://tools.cosmos.azure.com";
public static readonly Prod = "https://localhost";
public static readonly Stage = "https://tools-staging.cosmos.azure.com";
}

View File

@ -69,7 +69,7 @@ let configContext: Readonly<ConfigContext> = {
ARCADIA_LIVY_ENDPOINT_DNS_ZONE: "dev.azuresynapse.net",
GITHUB_CLIENT_ID: "6cb2f63cf6f7b5cbdeca", // Registered OAuth app: https://github.com/organizations/AzureCosmosDBNotebooks/settings/applications/1189306
GITHUB_TEST_ENV_CLIENT_ID: "b63fc8cbf87fd3c6e2eb", // Registered OAuth app: https://github.com/organizations/AzureCosmosDBNotebooks/settings/applications/1777772
JUNO_ENDPOINT: "https://tools.cosmos.azure.com",
JUNO_ENDPOINT: "https://localhost",
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
isTerminalEnabled: false,
isPhoenixEnabled: false,

View File

@ -372,6 +372,7 @@ export enum TerminalKind {
Default = 0,
Mongo = 1,
Cassandra = 2,
PostgreSQL = 3,
}
export interface DataExplorerInputsFrame {

View File

@ -74,6 +74,9 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
this.props.databaseAccount?.properties.mongoEndpoint || this.props.databaseAccount?.properties.documentEndpoint;
} else if (StringUtils.endsWith(notebookServerEndpoint, "cassandra")) {
terminalEndpoint = this.props.databaseAccount?.properties.cassandraEndpoint;
} else if (StringUtils.endsWith(notebookServerEndpoint, "postgresql ")) {
terminalEndpoint =
this.props.databaseAccount?.properties.mongoEndpoint || this.props.databaseAccount?.properties.documentEndpoint;
}
if (terminalEndpoint) {

View File

@ -20,7 +20,7 @@ import {
ContainerConnectionInfo,
IPhoenixConnectionInfoResult,
IProvisionData,
IResponse,
IResponse
} from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels";
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
@ -98,7 +98,8 @@ export default class Explorer {
dataExplorerArea: Constants.Areas.ResourceTree,
});
this._isInitializingNotebooks = false;
this.phoenixClient = new PhoenixClient();
this.phoenixClient = new PhoenixClient(userContext.databaseAccount.id);
useNotebook.subscribe(
() => this.refreshCommandBarButtons(),
(state) => state.isNotebooksEnabledForAccount
@ -356,7 +357,7 @@ export default class Explorer {
(notebookServerInfo && notebookServerInfo.notebookServerEndpoint === undefined))
) {
const provisionData: IProvisionData = {
cosmosEndpoint: userContext.databaseAccount.properties.documentEndpoint,
cosmosEndpoint: userContext?.databaseAccount?.properties?.documentEndpoint,
poolId: PoolIdType.DefaultPoolId,
};
const connectionStatus: ContainerConnectionInfo = {
@ -1061,6 +1062,10 @@ export default class Explorer {
title = "Cassandra Shell";
break;
case ViewModels.TerminalKind.PostgreSQL:
title = "PSQL Shell";
break;
default:
throw new Error("Terminal kind: ${kind} not supported");
}

View File

@ -95,6 +95,8 @@ export function createStaticCommandBarButtons(
}
}
notebookButtons.push(createOpenPsqlTerminalButton(container));
notebookButtons.forEach((btn) => {
if (btn.commandButtonLabel.indexOf("Cassandra") !== -1) {
if (!useNotebook.getState().isPhoenixFeatures) {
@ -104,6 +106,10 @@ export function createStaticCommandBarButtons(
if (!useNotebook.getState().isPhoenixFeatures) {
applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.mongoShellTemporarilyDownMsg);
}
} else if (btn.commandButtonLabel.indexOf("PSQL") !== -1) {
if (!useNotebook.getState().isPhoenixFeatures) {
applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.mongoShellTemporarilyDownMsg);
}
} else if (!useNotebook.getState().isPhoenixNotebooks) {
applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.temporarilyDownMsg);
}
@ -519,6 +525,28 @@ function createOpenCassandraTerminalButton(container: Explorer): CommandButtonCo
};
}
function createOpenPsqlTerminalButton(container: Explorer): CommandButtonComponentProps {
const label = "Open PSQL Shell";
const disableButton =
!useNotebook.getState().isNotebooksEnabledForAccount && !useNotebook.getState().isNotebookEnabled;
return {
iconSrc: HostedTerminalIcon,
iconAlt: label,
onCommandClick: () => {
if (useNotebook.getState().isNotebookEnabled) {
container.openNotebookTerminal(ViewModels.TerminalKind.PostgreSQL);
}
},
commandButtonLabel: label,
hasPopup: false,
disabled: disableButton,
ariaLabel: label,
tooltipText: !disableButton
? ""
: "This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.",
};
}
function createNotebookWorkspaceResetButton(container: Explorer): CommandButtonComponentProps {
const label = "Reset Workspace";
return {

View File

@ -8,7 +8,7 @@ import {
ProgressIndicator,
Stack,
Text,
TooltipHost,
TooltipHost
} from "@fluentui/react";
import { useId } from "@fluentui/react-hooks";
import { ActionButton, DefaultButton } from "@fluentui/react/lib/Button";
@ -124,8 +124,8 @@ export const ConnectionStatus: React.FC<Props> = ({ container }: Props): JSX.Ele
content={
containerInfo?.status === ContainerStatusType.Active
? `Connected to temporary workspace. This temporary workspace will get disconnected in ${Math.round(
containerInfo.durationLeftInMinutes
)} minutes.`
containerInfo.durationLeftInMinutes
)} minutes.`
: toolTipContent
}
>
@ -153,9 +153,9 @@ export const ConnectionStatus: React.FC<Props> = ({ container }: Props): JSX.Ele
)}
</Stack>
{!isBarDismissed &&
containerInfo.status &&
containerInfo.status === ContainerStatusType.Active &&
Math.round(containerInfo.durationLeftInMinutes) <= Notebook.remainingTimeForAlert ? (
containerInfo.status &&
containerInfo.status === ContainerStatusType.Active &&
Math.round(containerInfo.durationLeftInMinutes) <= Notebook.remainingTimeForAlert ? (
<FocusTrapCallout
role="alertdialog"
className={styles.callout}

View File

@ -23,7 +23,7 @@ export class NotebookContainerClient {
private scheduleTimerId: NodeJS.Timeout;
constructor(private onConnectionLost: () => void) {
this.phoenixClient = new PhoenixClient();
this.phoenixClient = new PhoenixClient(userContext.databaseAccount.id);
this.retryOptions = {
retries: Notebook.retryAttempts,
maxTimeout: Notebook.retryAttemptDelayMs,

View File

@ -307,7 +307,7 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
let isPhoenixFeatures = false;
const isPublicInternetAllowed = isPublicInternetAccessAllowed();
const phoenixClient = new PhoenixClient();
const phoenixClient = new PhoenixClient(userContext.databaseAccount.id);
const dbAccountAllowedInfo = await phoenixClient.getDbAccountAllowedStatus();
if (dbAccountAllowedInfo.status === HttpStatusCodes.OK) {

View File

@ -95,6 +95,10 @@ export default class TerminalTab extends TabsBase {
endpointSuffix = "cassandra";
break;
case ViewModels.TerminalKind.PostgreSQL:
endpointSuffix = "postgresql";
break;
default:
throw new Error(`Terminal kind: ${options.kind} not supported`);
}

View File

@ -4,7 +4,7 @@ import "bootstrap/dist/css/bootstrap.css";
import { QuickstartCarousel } from "Explorer/Tutorials/QuickstartCarousel";
import { QuickstartTutorial } from "Explorer/Tutorials/QuickstartTutorial";
import { useCarousel } from "hooks/useCarousel";
import React, { useState } from "react";
import React from "react";
import ReactDOM from "react-dom";
import "../externals/jquery-ui.min.css";
import "../externals/jquery-ui.min.js";
@ -28,8 +28,6 @@ import "../less/TableStyles/EntityEditor.less";
import "../less/TableStyles/fulldatatables.less";
import "../less/TableStyles/queryBuilder.less";
import "../less/tree.less";
import { CollapsedResourceTree } from "./Common/CollapsedResourceTree";
import { ResourceTreeContainer } from "./Common/ResourceTreeContainer";
import "./Explorer/Controls/Accordion/AccordionComponent.less";
import "./Explorer/Controls/CollapsiblePanel/CollapsiblePanelComponent.less";
import { Dialog } from "./Explorer/Controls/Dialog";
@ -56,21 +54,11 @@ import "./Shared/appInsights";
initializeIcons();
const App: React.FunctionComponent = () => {
const [isLeftPaneExpanded, setIsLeftPaneExpanded] = useState<boolean>(true);
const isCarouselOpen = useCarousel((state) => state.shouldOpen);
const config = useConfig();
const explorer = useKnockoutExplorer(config?.platform);
const toggleLeftPaneExpanded = () => {
setIsLeftPaneExpanded(!isLeftPaneExpanded);
if (isLeftPaneExpanded) {
document.getElementById("expandToggleLeftPaneButton").focus();
} else {
document.getElementById("collapseToggleLeftPaneButton").focus();
}
};
if (!explorer) {
return <LoadingExplorer />;
}
@ -82,24 +70,6 @@ const App: React.FunctionComponent = () => {
<CommandBar container={explorer} />
{/* Collections Tree and Tabs - Begin */}
<div className="resourceTreeAndTabs">
{/* Collections Tree - Start */}
<div id="resourcetree" data-test="resourceTreeId" className="resourceTree">
<div className="collectionsTreeWithSplitter">
{/* Collections Tree Expanded - Start */}
<ResourceTreeContainer
container={explorer}
toggleLeftPaneExpanded={toggleLeftPaneExpanded}
isLeftPaneExpanded={isLeftPaneExpanded}
/>
{/* Collections Tree Expanded - End */}
{/* Collections Tree Collapsed - Start */}
<CollapsedResourceTree
toggleLeftPaneExpanded={toggleLeftPaneExpanded}
isLeftPaneExpanded={isLeftPaneExpanded}
/>
{/* Collections Tree Collapsed - End */}
</div>
</div>
<Tabs explorer={explorer} />
</div>
{/* Collections Tree and Tabs - End */}

View File

@ -8,7 +8,7 @@ import {
ContainerStatusType,
HttpHeaders,
HttpStatusCodes,
Notebook,
Notebook
} from "../Common/Constants";
import { getErrorMessage, getErrorStack } from "../Common/ErrorHandlingUtils";
import * as Logger from "../Common/Logger";
@ -23,7 +23,7 @@ import {
IPhoenixError,
IProvisionData,
IResponse,
PhoenixErrorType,
PhoenixErrorType
} from "../Contracts/DataModels";
import { useNotebook } from "../Explorer/Notebook/useNotebook";
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
@ -31,6 +31,7 @@ import { userContext } from "../UserContext";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
export class PhoenixClient {
private armResourceId: string;
private containerHealthHandler: NodeJS.Timeout;
private retryOptions: promiseRetry.Options = {
retries: Notebook.retryAttempts,
@ -38,6 +39,10 @@ export class PhoenixClient {
minTimeout: Notebook.retryAttemptDelayMs,
};
constructor(armResourceId: string) {
this.armResourceId = armResourceId;
}
public async allocateContainer(provisionData: IProvisionData): Promise<IResponse<IPhoenixConnectionInfoResult>> {
return this.executeContainerAssignmentOperation(provisionData, "allocate");
}
@ -205,22 +210,17 @@ export class PhoenixClient {
}
}
public static getPhoenixEndpoint(): string {
const phoenixEndpoint =
public getPhoenixControlPlanePathPrefix(): string {
const toolsEndpoint =
userContext.features.phoenixEndpoint ?? userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
if (!validateEndpoint(phoenixEndpoint, allowedJunoOrigins)) {
const error = `${phoenixEndpoint} not allowed as juno endpoint`;
if (!validateEndpoint(toolsEndpoint, allowedJunoOrigins)) {
const error = `${toolsEndpoint} not allowed as tools endpoint`;
console.error(error);
throw new Error(error);
}
return phoenixEndpoint;
}
public getPhoenixControlPlanePathPrefix(): string {
return `${PhoenixClient.getPhoenixEndpoint()}/api/controlplane/toolscontainer/cosmosaccounts${
userContext.databaseAccount.id
}`;
return `${toolsEndpoint}/api/controlplane/toolscontainer/cosmosaccounts${this.armResourceId}`;
}
private static getHeaders(): HeadersInit {

View File

@ -17,7 +17,7 @@ export class JupyterLabAppFactory {
}
private isMongoShellStarted(content: string | undefined) {
this.isShellStarted = content?.includes("MongoDB shell version");
this.isShellStarted = content?.includes("MongoDB shell version") || content?.includes("citus=>");
}
private isCassandraShellStarted(content: string | undefined) {