mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-21 18:01:39 +00:00
Integrate PSQL shell in quick start guide
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
* Wrapper around Notebook server terminal
|
* Wrapper around Notebook server terminal
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { useTerminal } from "hooks/useTerminal";
|
||||||
import postRobot from "post-robot";
|
import postRobot from "post-robot";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as DataModels from "../../../Contracts/DataModels";
|
import * as DataModels from "../../../Contracts/DataModels";
|
||||||
@@ -40,6 +41,7 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
|
|||||||
|
|
||||||
handleFrameLoad(event: React.SyntheticEvent<HTMLIFrameElement, Event>): void {
|
handleFrameLoad(event: React.SyntheticEvent<HTMLIFrameElement, Event>): void {
|
||||||
this.terminalWindow = (event.target as HTMLIFrameElement).contentWindow;
|
this.terminalWindow = (event.target as HTMLIFrameElement).contentWindow;
|
||||||
|
useTerminal.getState().setTerminal(this.terminalWindow);
|
||||||
this.sendPropsToTerminalFrame();
|
this.sendPropsToTerminalFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +77,7 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
|
|||||||
} else if (StringUtils.endsWith(notebookServerEndpoint, "cassandra")) {
|
} else if (StringUtils.endsWith(notebookServerEndpoint, "cassandra")) {
|
||||||
terminalEndpoint = this.props.databaseAccount?.properties.cassandraEndpoint;
|
terminalEndpoint = this.props.databaseAccount?.properties.cassandraEndpoint;
|
||||||
} else if (StringUtils.endsWith(notebookServerEndpoint, "postgresql")) {
|
} else if (StringUtils.endsWith(notebookServerEndpoint, "postgresql")) {
|
||||||
return (this.props.databaseAccount?.properties as any).postgresqlEndpoint;
|
return "c.vimeng-postgre-citus.postgres.database.azure.com";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (terminalEndpoint) {
|
if (terminalEndpoint) {
|
||||||
|
|||||||
@@ -186,9 +186,7 @@ export default class Explorer {
|
|||||||
useNotebook.getState().setNotebookBasePath(userContext.features.notebookBasePath);
|
useNotebook.getState().setNotebookBasePath(userContext.features.notebookBasePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userContext.apiType !== "Postgres") {
|
this.refreshExplorer();
|
||||||
this.refreshExplorer();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async initiateAndRefreshNotebookList(): Promise<void> {
|
public async initiateAndRefreshNotebookList(): Promise<void> {
|
||||||
@@ -1249,9 +1247,11 @@ export default class Explorer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async refreshExplorer(): Promise<void> {
|
public async refreshExplorer(): Promise<void> {
|
||||||
userContext.authType === AuthType.ResourceToken
|
if (userContext.apiType !== "Postgres") {
|
||||||
? this.refreshDatabaseForResourceToken()
|
userContext.authType === AuthType.ResourceToken
|
||||||
: this.refreshAllDatabases();
|
? this.refreshDatabaseForResourceToken()
|
||||||
|
: this.refreshAllDatabases();
|
||||||
|
}
|
||||||
await useNotebook.getState().refreshNotebooksEnabledStateForAccount();
|
await useNotebook.getState().refreshNotebooksEnabledStateForAccount();
|
||||||
|
|
||||||
// TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount
|
// TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount
|
||||||
|
|||||||
@@ -85,14 +85,11 @@ export function createStaticCommandBarButtons(
|
|||||||
(userContext.apiType === "Mongo" &&
|
(userContext.apiType === "Mongo" &&
|
||||||
useNotebook.getState().isShellEnabled &&
|
useNotebook.getState().isShellEnabled &&
|
||||||
selectedNodeState.isDatabaseNodeOrNoneSelected()) ||
|
selectedNodeState.isDatabaseNodeOrNoneSelected()) ||
|
||||||
userContext.apiType === "Cassandra" ||
|
userContext.apiType === "Cassandra"
|
||||||
userContext.apiType === "Postgres"
|
|
||||||
) {
|
) {
|
||||||
notebookButtons.push(createDivider());
|
notebookButtons.push(createDivider());
|
||||||
if (userContext.apiType === "Cassandra") {
|
if (userContext.apiType === "Cassandra") {
|
||||||
notebookButtons.push(createOpenCassandraTerminalButton(container));
|
notebookButtons.push(createOpenCassandraTerminalButton(container));
|
||||||
} else if (userContext.apiType === "Postgres") {
|
|
||||||
notebookButtons.push(createOpenPsqlTerminalButton(container));
|
|
||||||
} else {
|
} else {
|
||||||
notebookButtons.push(createOpenMongoTerminalButton(container));
|
notebookButtons.push(createOpenMongoTerminalButton(container));
|
||||||
}
|
}
|
||||||
@@ -612,16 +609,7 @@ function createStaticCommandBarButtonsForResourceToken(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createPostgreButtons(container: Explorer): CommandButtonComponentProps[] {
|
export function createPostgreButtons(container: Explorer): CommandButtonComponentProps[] {
|
||||||
const postgreShellLabel = "Open PostgreSQL Shell";
|
const openPostgreShellBtn = createOpenPsqlTerminalButton(container);
|
||||||
const openPostgreShellBtn = {
|
|
||||||
iconSrc: HostedTerminalIcon,
|
|
||||||
iconAlt: postgreShellLabel,
|
|
||||||
onCommandClick: () => container.openNotebookTerminal(ViewModels.TerminalKind.Mongo),
|
|
||||||
commandButtonLabel: postgreShellLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
ariaLabel: postgreShellLabel,
|
|
||||||
};
|
|
||||||
|
|
||||||
return [openPostgreShellBtn];
|
return [openPostgreShellBtn];
|
||||||
}
|
}
|
||||||
|
|||||||
105
src/Explorer/Quickstart/PostgreQuickstartCommands.ts
Normal file
105
src/Explorer/Quickstart/PostgreQuickstartCommands.ts
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
export const newTableCommand = `DROP SCHEMA IF EXISTS cosmosdb_tutorial CASCADE;
|
||||||
|
CREATE SCHEMA cosmosdb_tutorial;
|
||||||
|
SET search_path to cosmosdb_tutorial;
|
||||||
|
CREATE TABLE github_users
|
||||||
|
(
|
||||||
|
user_id bigint,
|
||||||
|
url text,
|
||||||
|
login text,
|
||||||
|
avatar_url text,
|
||||||
|
gravatar_id text,
|
||||||
|
display_login text
|
||||||
|
);
|
||||||
|
CREATE TABLE github_events
|
||||||
|
(
|
||||||
|
event_id bigint,
|
||||||
|
event_type text,
|
||||||
|
event_public boolean,
|
||||||
|
repo_id bigint,
|
||||||
|
payload jsonb,
|
||||||
|
repo jsonb,
|
||||||
|
user_id bigint,
|
||||||
|
org jsonb,
|
||||||
|
created_at timestamp
|
||||||
|
);
|
||||||
|
CREATE INDEX event_type_index ON github_events (event_type);
|
||||||
|
CREATE INDEX payload_index ON github_events USING GIN (payload jsonb_path_ops);
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const newTableCommandForDisplay = `DROP SCHEMA IF EXISTS cosmosdb_tutorial CASCADE;
|
||||||
|
CREATE SCHEMA cosmosdb_tutorial;
|
||||||
|
|
||||||
|
-- Using schema created for tutorial
|
||||||
|
SET search_path to cosmosdb_tutorial;
|
||||||
|
|
||||||
|
CREATE TABLE github_users
|
||||||
|
(
|
||||||
|
user_id bigint,
|
||||||
|
url text,
|
||||||
|
login text,
|
||||||
|
avatar_url text,
|
||||||
|
gravatar_id text,
|
||||||
|
display_login text
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE github_events
|
||||||
|
(
|
||||||
|
event_id bigint,
|
||||||
|
event_type text,
|
||||||
|
event_public boolean,
|
||||||
|
repo_id bigint,
|
||||||
|
payload jsonb,
|
||||||
|
repo jsonb,
|
||||||
|
user_id bigint,
|
||||||
|
org jsonb,
|
||||||
|
created_at timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
--Create indexes on events table
|
||||||
|
CREATE INDEX event_type_index ON github_events (event_type);
|
||||||
|
CREATE INDEX payload_index ON github_events USING GIN (payload jsonb_path_ops);`;
|
||||||
|
|
||||||
|
export const distributeTableCommand = `SET search_path to cosmosdb_tutorial;
|
||||||
|
SELECT create_distributed_table('github_users', 'user_id');
|
||||||
|
SELECT create_distributed_table('github_events', 'user_id');
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const distributeTableCommandForDisplay = `-- Using schema created for the tutorial
|
||||||
|
SET search_path to cosmosdb_tutorial;
|
||||||
|
|
||||||
|
SELECT create_distributed_table('github_users', 'user_id');
|
||||||
|
SELECT create_distributed_table('github_events', 'user_id');`;
|
||||||
|
|
||||||
|
export const loadDataCommand = `SET search_path to cosmosdb_tutorial;
|
||||||
|
\\COPY github_users FROM PROGRAM 'curl https://examples.citusdata.com/users.csv' WITH (FORMAT CSV)
|
||||||
|
\\COPY github_events FROM PROGRAM 'curl https://examples.citusdata.com/events.csv' WITH (FORMAT CSV)
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const loadDataCommandForDisplay = `-- Using schema created for the tutorial
|
||||||
|
SET search_path to cosmosdb_tutorial;
|
||||||
|
|
||||||
|
-- download users and store in table
|
||||||
|
\\COPY github_users FROM PROGRAM 'curl https://examples.citusdata.com/users.csv' WITH (FORMAT CSV)
|
||||||
|
\\COPY github_events FROM PROGRAM 'curl https://examples.citusdata.com/events.csv' WITH (FORMAT CSV)`;
|
||||||
|
|
||||||
|
export const queryCommand = `SET search_path to cosmosdb_tutorial;
|
||||||
|
SELECT count(*) FROM github_users;
|
||||||
|
SELECT created_at, event_type, repo->>'name' AS repo_name
|
||||||
|
FROM github_events
|
||||||
|
WHERE user_id = 3861633;
|
||||||
|
SELECT date_trunc('hour', created_at) AS hour, sum((payload->>'distinct_size')::int) AS num_commits FROM github_events WHERE event_type = 'PushEvent' AND payload @> '{"ref":"refs/heads/master"}' GROUP BY hour ORDER BY hour;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const queryCommandForDisplay = `-- Using schema created for the tutorial
|
||||||
|
SET search_path to cosmosdb_tutorial;
|
||||||
|
|
||||||
|
-- count all rows (across shards)
|
||||||
|
SELECT count(*) FROM github_users;
|
||||||
|
|
||||||
|
-- Find all events for a single user.
|
||||||
|
SELECT created_at, event_type, repo->>'name' AS repo_name
|
||||||
|
FROM github_events
|
||||||
|
WHERE user_id = 3861633;
|
||||||
|
|
||||||
|
-- Find the number of commits on the master branch per hour
|
||||||
|
SELECT date_trunc('hour', created_at) AS hour, sum((payload->>'distinct_size')::int) AS num_commits FROM github_events WHERE event_type = 'PushEvent' AND payload @> '{"ref":"refs/heads/master"}' GROUP BY hour ORDER BY hour;`;
|
||||||
@@ -11,6 +11,17 @@ import {
|
|||||||
Text,
|
Text,
|
||||||
TextField,
|
TextField,
|
||||||
} from "@fluentui/react";
|
} from "@fluentui/react";
|
||||||
|
import {
|
||||||
|
distributeTableCommand,
|
||||||
|
distributeTableCommandForDisplay,
|
||||||
|
loadDataCommand,
|
||||||
|
loadDataCommandForDisplay,
|
||||||
|
newTableCommand,
|
||||||
|
newTableCommandForDisplay,
|
||||||
|
queryCommand,
|
||||||
|
queryCommandForDisplay,
|
||||||
|
} from "Explorer/Quickstart/PostgreQuickstartCommands";
|
||||||
|
import { useTerminal } from "hooks/useTerminal";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import Youtube from "react-youtube";
|
import Youtube from "react-youtube";
|
||||||
import Pivot1SelectedIcon from "../../../images/Pivot1_selected.svg";
|
import Pivot1SelectedIcon from "../../../images/Pivot1_selected.svg";
|
||||||
@@ -35,65 +46,6 @@ enum GuideSteps {
|
|||||||
|
|
||||||
export const QuickstartGuide: React.FC = (): JSX.Element => {
|
export const QuickstartGuide: React.FC = (): JSX.Element => {
|
||||||
const [currentStep, setCurrentStep] = useState<number>(0);
|
const [currentStep, setCurrentStep] = useState<number>(0);
|
||||||
const newTableCommand = `DROP SCHEMA IF EXISTS cosmosdb_tutorial CASCADE;
|
|
||||||
CREATE SCHEMA cosmosdb_tutorial;
|
|
||||||
|
|
||||||
-- Using schema created for tutorial
|
|
||||||
SET search_path to cosmosdb_tutorial;
|
|
||||||
|
|
||||||
CREATE TABLE github_users
|
|
||||||
(
|
|
||||||
user_id bigint,
|
|
||||||
url text,
|
|
||||||
login text,
|
|
||||||
avatar_url text,
|
|
||||||
gravatar_id text,
|
|
||||||
display_login text
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE github_events
|
|
||||||
(
|
|
||||||
event_id bigint,
|
|
||||||
event_type text,
|
|
||||||
event_public boolean,
|
|
||||||
repo_id bigint,
|
|
||||||
payload jsonb,
|
|
||||||
repo jsonb,
|
|
||||||
user_id bigint,
|
|
||||||
org jsonb,
|
|
||||||
created_at timestamp
|
|
||||||
);
|
|
||||||
|
|
||||||
--Create indexes on events table
|
|
||||||
CREATE INDEX event_type_index ON github_events (event_type);
|
|
||||||
CREATE INDEX payload_index ON github_events USING GIN (payload jsonb_path_ops); `;
|
|
||||||
|
|
||||||
const distributeTableCommand = `-- Using schema created for the tutorial
|
|
||||||
SET search_path to cosmosdb_tutorial;
|
|
||||||
|
|
||||||
SELECT create_distributed_table('github_users', 'user_id');
|
|
||||||
SELECT create_distributed_table('github_events', 'user_id'); `;
|
|
||||||
|
|
||||||
const loadDataCommand = `-- Using schema created for the tutorial
|
|
||||||
SET search_path to cosmosdb_tutorial;
|
|
||||||
|
|
||||||
-- download users and store in table
|
|
||||||
\\COPY github_users FROM PROGRAM 'curl https://examples.citusdata.com/users.csv' WITH (FORMAT CSV)
|
|
||||||
\\COPY github_events FROM PROGRAM 'curl https://examples.citusdata.com/events.csv' WITH (FORMAT CSV) `;
|
|
||||||
|
|
||||||
const queryCommand = `-- Using schema created for the tutorial
|
|
||||||
SET search_path to cosmosdb_tutorial;
|
|
||||||
|
|
||||||
-- count all rows (across shards)
|
|
||||||
SELECT count(*) FROM github_users;
|
|
||||||
|
|
||||||
-- Find all events for a single user.
|
|
||||||
SELECT created_at, event_type, repo->>'name' AS repo_name
|
|
||||||
FROM github_events
|
|
||||||
WHERE user_id = 3861633;
|
|
||||||
|
|
||||||
-- Find the number of commits on the master branch per hour
|
|
||||||
SELECT date_trunc('hour', created_at) AS hour, sum((payload->>'distinct_size')::int) AS num_commits FROM github_events WHERE event_type = 'PushEvent' AND payload @> '{"ref":"refs/heads/master"}' GROUP BY hour ORDER BY hour; `;
|
|
||||||
|
|
||||||
const onCopyBtnClicked = (selector: string): void => {
|
const onCopyBtnClicked = (selector: string): void => {
|
||||||
const textfield: HTMLInputElement = document.querySelector(selector);
|
const textfield: HTMLInputElement = document.querySelector(selector);
|
||||||
@@ -170,14 +122,19 @@ SELECT date_trunc('hour', created_at) AS hour, sum((payload->>'distinct_size')::
|
|||||||
>
|
>
|
||||||
<Stack style={{ marginTop: 20 }}>
|
<Stack style={{ marginTop: 20 }}>
|
||||||
<Text>Let’s create two tables github_users and github_events in “cosmosdb_tutorial” schema.</Text>
|
<Text>Let’s create two tables github_users and github_events in “cosmosdb_tutorial” schema.</Text>
|
||||||
<DefaultButton style={{ marginTop: 16, width: 150 }}>Create new table</DefaultButton>
|
<DefaultButton
|
||||||
|
style={{ marginTop: 16, width: 150 }}
|
||||||
|
onClick={() => useTerminal.getState().sendMessage(newTableCommand)}
|
||||||
|
>
|
||||||
|
Create new table
|
||||||
|
</DefaultButton>
|
||||||
<Stack horizontal style={{ marginTop: 16 }}>
|
<Stack horizontal style={{ marginTop: 16 }}>
|
||||||
<TextField
|
<TextField
|
||||||
id="newTableCommand"
|
id="newTableCommand"
|
||||||
multiline
|
multiline
|
||||||
rows={5}
|
rows={5}
|
||||||
readOnly
|
readOnly
|
||||||
defaultValue={newTableCommand}
|
defaultValue={newTableCommandForDisplay}
|
||||||
styles={{
|
styles={{
|
||||||
root: { width: "90%" },
|
root: { width: "90%" },
|
||||||
field: {
|
field: {
|
||||||
@@ -210,14 +167,19 @@ SELECT date_trunc('hour', created_at) AS hour, sum((payload->>'distinct_size')::
|
|||||||
<br />
|
<br />
|
||||||
We are choosing “user_id” as the distribution column for our sample dataset.
|
We are choosing “user_id” as the distribution column for our sample dataset.
|
||||||
</Text>
|
</Text>
|
||||||
<DefaultButton style={{ marginTop: 16, width: 200 }}>Create distributed table</DefaultButton>
|
<DefaultButton
|
||||||
|
style={{ marginTop: 16, width: 200 }}
|
||||||
|
onClick={() => useTerminal.getState().sendMessage(distributeTableCommand)}
|
||||||
|
>
|
||||||
|
Create distributed table
|
||||||
|
</DefaultButton>
|
||||||
<Stack horizontal style={{ marginTop: 16 }}>
|
<Stack horizontal style={{ marginTop: 16 }}>
|
||||||
<TextField
|
<TextField
|
||||||
id="distributeTableCommand"
|
id="distributeTableCommand"
|
||||||
multiline
|
multiline
|
||||||
rows={5}
|
rows={5}
|
||||||
readOnly
|
readOnly
|
||||||
defaultValue={distributeTableCommand}
|
defaultValue={distributeTableCommandForDisplay}
|
||||||
styles={{
|
styles={{
|
||||||
root: { width: "90%" },
|
root: { width: "90%" },
|
||||||
field: {
|
field: {
|
||||||
@@ -245,14 +207,19 @@ SELECT date_trunc('hour', created_at) AS hour, sum((payload->>'distinct_size')::
|
|||||||
>
|
>
|
||||||
<Stack style={{ marginTop: 20 }}>
|
<Stack style={{ marginTop: 20 }}>
|
||||||
<Text>Let's load the two tables with a sample dataset generated from the GitHub API.</Text>
|
<Text>Let's load the two tables with a sample dataset generated from the GitHub API.</Text>
|
||||||
<DefaultButton style={{ marginTop: 16, width: 110 }}>Load data</DefaultButton>
|
<DefaultButton
|
||||||
|
style={{ marginTop: 16, width: 110 }}
|
||||||
|
onClick={() => useTerminal.getState().sendMessage(loadDataCommand)}
|
||||||
|
>
|
||||||
|
Load data
|
||||||
|
</DefaultButton>
|
||||||
<Stack horizontal style={{ marginTop: 16 }}>
|
<Stack horizontal style={{ marginTop: 16 }}>
|
||||||
<TextField
|
<TextField
|
||||||
id="loadDataCommand"
|
id="loadDataCommand"
|
||||||
multiline
|
multiline
|
||||||
rows={5}
|
rows={5}
|
||||||
readOnly
|
readOnly
|
||||||
defaultValue={loadDataCommand}
|
defaultValue={loadDataCommandForDisplay}
|
||||||
styles={{
|
styles={{
|
||||||
root: { width: "90%" },
|
root: { width: "90%" },
|
||||||
field: {
|
field: {
|
||||||
@@ -282,14 +249,19 @@ SELECT date_trunc('hour', created_at) AS hour, sum((payload->>'distinct_size')::
|
|||||||
<Text>
|
<Text>
|
||||||
Congratulations on creating and distributing your tables. Now, it's time to run your first query!
|
Congratulations on creating and distributing your tables. Now, it's time to run your first query!
|
||||||
</Text>
|
</Text>
|
||||||
<DefaultButton style={{ marginTop: 16, width: 115 }}>Try queries</DefaultButton>
|
<DefaultButton
|
||||||
|
style={{ marginTop: 16, width: 115 }}
|
||||||
|
onClick={() => useTerminal.getState().sendMessage(queryCommand)}
|
||||||
|
>
|
||||||
|
Try queries
|
||||||
|
</DefaultButton>
|
||||||
<Stack horizontal style={{ marginTop: 16 }}>
|
<Stack horizontal style={{ marginTop: 16 }}>
|
||||||
<TextField
|
<TextField
|
||||||
id="queryCommand"
|
id="queryCommand"
|
||||||
multiline
|
multiline
|
||||||
rows={5}
|
rows={5}
|
||||||
readOnly
|
readOnly
|
||||||
defaultValue={queryCommand}
|
defaultValue={queryCommandForDisplay}
|
||||||
styles={{
|
styles={{
|
||||||
root: { width: "90%" },
|
root: { width: "90%" },
|
||||||
field: {
|
field: {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const QuickstartTab: React.FC<QuickstartTabProps> = ({ explorer }: Quicks
|
|||||||
}, []);
|
}, []);
|
||||||
const getNotebookServerInfo = (): NotebookWorkspaceConnectionInfo => ({
|
const getNotebookServerInfo = (): NotebookWorkspaceConnectionInfo => ({
|
||||||
authToken: notebookServerInfo.authToken,
|
authToken: notebookServerInfo.authToken,
|
||||||
notebookServerEndpoint: `${notebookServerInfo.notebookServerEndpoint?.replace(/\/+$/, "")}/mongo`,
|
notebookServerEndpoint: `${notebookServerInfo.notebookServerEndpoint?.replace(/\/+$/, "")}/postgresql`,
|
||||||
forwardingId: notebookServerInfo.forwardingId,
|
forwardingId: notebookServerInfo.forwardingId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* JupyterLab applications based on jupyterLab components
|
* JupyterLab applications based on jupyterLab components
|
||||||
*/
|
*/
|
||||||
import { ServerConnection, TerminalManager } from "@jupyterlab/services";
|
import { ServerConnection, TerminalManager } from "@jupyterlab/services";
|
||||||
import { IMessage } from "@jupyterlab/services/lib/terminal/terminal";
|
import { IMessage, ITerminalConnection } from "@jupyterlab/services/lib/terminal/terminal";
|
||||||
import { Terminal } from "@jupyterlab/terminal";
|
import { Terminal } from "@jupyterlab/terminal";
|
||||||
import { Panel, Widget } from "@phosphor/widgets";
|
import { Panel, Widget } from "@phosphor/widgets";
|
||||||
import { userContext } from "UserContext";
|
import { userContext } from "UserContext";
|
||||||
@@ -46,7 +46,7 @@ export class JupyterLabAppFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async createTerminalApp(serverSettings: ServerConnection.ISettings) {
|
public async createTerminalApp(serverSettings: ServerConnection.ISettings): Promise<ITerminalConnection> {
|
||||||
const manager = new TerminalManager({
|
const manager = new TerminalManager({
|
||||||
serverSettings: serverSettings,
|
serverSettings: serverSettings,
|
||||||
});
|
});
|
||||||
@@ -68,7 +68,7 @@ export class JupyterLabAppFactory {
|
|||||||
|
|
||||||
if (!term) {
|
if (!term) {
|
||||||
console.error("Failed starting terminal");
|
console.error("Failed starting terminal");
|
||||||
return;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
term.title.closable = false;
|
term.title.closable = false;
|
||||||
@@ -90,5 +90,7 @@ export class JupyterLabAppFactory {
|
|||||||
window.addEventListener("unload", () => {
|
window.addEventListener("unload", () => {
|
||||||
panel.dispose();
|
panel.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return session;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { ServerConnection } from "@jupyterlab/services";
|
import { ServerConnection } from "@jupyterlab/services";
|
||||||
|
import { IMessage, ITerminalConnection } from "@jupyterlab/services/lib/terminal/terminal";
|
||||||
import "@jupyterlab/terminal/style/index.css";
|
import "@jupyterlab/terminal/style/index.css";
|
||||||
import { MessageTypes } from "Contracts/ExplorerContracts";
|
import { MessageTypes } from "Contracts/ExplorerContracts";
|
||||||
import postRobot from "post-robot";
|
import postRobot from "post-robot";
|
||||||
@@ -41,7 +42,7 @@ const createServerSettings = (props: TerminalProps): ServerConnection.ISettings
|
|||||||
return ServerConnection.makeSettings(options);
|
return ServerConnection.makeSettings(options);
|
||||||
};
|
};
|
||||||
|
|
||||||
const initTerminal = async (props: TerminalProps) => {
|
const initTerminal = async (props: TerminalProps): Promise<ITerminalConnection> => {
|
||||||
// Initialize userContext (only properties which are needed by TelemetryProcessor)
|
// Initialize userContext (only properties which are needed by TelemetryProcessor)
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
subscriptionId: props.subscriptionId,
|
subscriptionId: props.subscriptionId,
|
||||||
@@ -55,10 +56,12 @@ const initTerminal = async (props: TerminalProps) => {
|
|||||||
const startTime = TelemetryProcessor.traceStart(Action.OpenTerminal, data);
|
const startTime = TelemetryProcessor.traceStart(Action.OpenTerminal, data);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await new JupyterLabAppFactory(() => closeTab(props.tabId)).createTerminalApp(serverSettings);
|
const session = await new JupyterLabAppFactory(() => closeTab(props.tabId)).createTerminalApp(serverSettings);
|
||||||
TelemetryProcessor.traceSuccess(Action.OpenTerminal, data, startTime);
|
TelemetryProcessor.traceSuccess(Action.OpenTerminal, data, startTime);
|
||||||
|
return session;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
TelemetryProcessor.traceFailure(Action.OpenTerminal, data, startTime);
|
TelemetryProcessor.traceFailure(Action.OpenTerminal, data, startTime);
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -70,6 +73,7 @@ const closeTab = (tabId: string): void => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const main = async (): Promise<void> => {
|
const main = async (): Promise<void> => {
|
||||||
|
let session: ITerminalConnection;
|
||||||
postRobot.on(
|
postRobot.on(
|
||||||
"props",
|
"props",
|
||||||
{
|
{
|
||||||
@@ -80,7 +84,22 @@ const main = async (): Promise<void> => {
|
|||||||
// Typescript definition for event is wrong. So read props by casting to <any>
|
// Typescript definition for event is wrong. So read props by casting to <any>
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const props = (event as any).data as TerminalProps;
|
const props = (event as any).data as TerminalProps;
|
||||||
await initTerminal(props);
|
session = await initTerminal(props);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
postRobot.on(
|
||||||
|
"sendMessage",
|
||||||
|
{
|
||||||
|
window: window.parent,
|
||||||
|
domain: window.location.origin,
|
||||||
|
},
|
||||||
|
async (event) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const message = (event as any).data as IMessage;
|
||||||
|
if (session) {
|
||||||
|
session.send(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -112,25 +112,27 @@ function apiType(account: DatabaseAccount | undefined): ApiType {
|
|||||||
return "SQL";
|
return "SQL";
|
||||||
}
|
}
|
||||||
|
|
||||||
const capabilities = account.properties?.capabilities;
|
return "Postgres";
|
||||||
if (capabilities) {
|
|
||||||
if (capabilities.find((c) => c.name === "EnableCassandra")) {
|
// const capabilities = account.properties?.capabilities;
|
||||||
return "Cassandra";
|
// if (capabilities) {
|
||||||
}
|
// if (capabilities.find((c) => c.name === "EnableCassandra")) {
|
||||||
if (capabilities.find((c) => c.name === "EnableGremlin")) {
|
// return "Cassandra";
|
||||||
return "Gremlin";
|
// }
|
||||||
}
|
// if (capabilities.find((c) => c.name === "EnableGremlin")) {
|
||||||
if (capabilities.find((c) => c.name === "EnableMongo")) {
|
// return "Gremlin";
|
||||||
return "Mongo";
|
// }
|
||||||
}
|
// if (capabilities.find((c) => c.name === "EnableMongo")) {
|
||||||
if (capabilities.find((c) => c.name === "EnableTable")) {
|
// return "Mongo";
|
||||||
return "Tables";
|
// }
|
||||||
}
|
// if (capabilities.find((c) => c.name === "EnableTable")) {
|
||||||
}
|
// return "Tables";
|
||||||
if (account.kind === "MongoDB" || account.kind === "Parse") {
|
// }
|
||||||
return "Mongo";
|
// }
|
||||||
}
|
// if (account.kind === "MongoDB" || account.kind === "Parse") {
|
||||||
return "SQL";
|
// return "Mongo";
|
||||||
|
// }
|
||||||
|
// return "SQL";
|
||||||
}
|
}
|
||||||
|
|
||||||
export { userContext, updateUserContext };
|
export { userContext, updateUserContext };
|
||||||
|
|||||||
26
src/hooks/useTerminal.ts
Normal file
26
src/hooks/useTerminal.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import postRobot from "post-robot";
|
||||||
|
import create, { UseStore } from "zustand";
|
||||||
|
|
||||||
|
interface TerminalState {
|
||||||
|
terminalWindow: Window;
|
||||||
|
setTerminal: (terminalWindow: Window) => void;
|
||||||
|
sendMessage: (message: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTerminal: UseStore<TerminalState> = create((set, get) => ({
|
||||||
|
terminalWindow: undefined,
|
||||||
|
setTerminal: (terminalWindow: Window) => {
|
||||||
|
set({ terminalWindow });
|
||||||
|
},
|
||||||
|
sendMessage: (message: string) => {
|
||||||
|
const terminalWindow = get().terminalWindow;
|
||||||
|
postRobot.send(
|
||||||
|
terminalWindow,
|
||||||
|
"sendMessage",
|
||||||
|
{ type: "stdin", content: [message] },
|
||||||
|
{
|
||||||
|
domain: window.location.origin,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}));
|
||||||
Reference in New Issue
Block a user