Implement connection string tab for postgres (#1334)
This commit is contained in:
parent
7c77ffda6c
commit
81dfd76198
|
@ -397,6 +397,8 @@ export interface DataExplorerInputsFrame {
|
|||
dataExplorerVersion?: string;
|
||||
defaultCollectionThroughput?: CollectionCreationDefaults;
|
||||
isPostgresAccount?: boolean;
|
||||
// TODO: Update this param in the OSS extension to remove isFreeTier, isMarlinServerGroup, and make nodes a flat array instead of an nested array
|
||||
connectionStringParams?: any;
|
||||
flights?: readonly string[];
|
||||
features?: {
|
||||
[key: string]: string;
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
import {
|
||||
Checkbox,
|
||||
Dropdown,
|
||||
Icon,
|
||||
IconButton,
|
||||
IDropdownOption,
|
||||
ITextFieldStyles,
|
||||
Label,
|
||||
Link,
|
||||
Stack,
|
||||
Text,
|
||||
TextField,
|
||||
TooltipHost,
|
||||
} from "@fluentui/react";
|
||||
import React from "react";
|
||||
import { userContext } from "UserContext";
|
||||
|
||||
export const PostgresConnectTab: React.FC = (): JSX.Element => {
|
||||
const { adminLogin, nodes, enablePublicIpAccess } = userContext.postgresConnectionStrParams;
|
||||
const [usePgBouncerPort, setUsePgBouncerPort] = React.useState<boolean>(false);
|
||||
const [selectedNode, setSelectedNode] = React.useState<string>(nodes?.[0]?.value);
|
||||
const portNumber = usePgBouncerPort ? "6432" : "5432";
|
||||
|
||||
const onCopyBtnClicked = (selector: string): void => {
|
||||
const textfield: HTMLInputElement = document.querySelector(selector);
|
||||
textfield.select();
|
||||
document.execCommand("copy");
|
||||
};
|
||||
|
||||
const textfieldStyles: Partial<ITextFieldStyles> = {
|
||||
root: { width: "100%" },
|
||||
field: { backgroundColor: "rgb(230, 230, 230)" },
|
||||
fieldGroup: { borderColor: "rgb(138, 136, 134)" },
|
||||
subComponentStyles: { label: { fontWeight: 400 } },
|
||||
description: { fontWeight: 400 },
|
||||
};
|
||||
|
||||
const nodesDropdownOptions: IDropdownOption[] = nodes.map((node) => ({
|
||||
key: node.value,
|
||||
text: node.text,
|
||||
}));
|
||||
|
||||
const postgresSQLConnectionURL = `postgres://${adminLogin}:{your_password}@${selectedNode}:${portNumber}/citus?sslmode=require`;
|
||||
const psql = `psql "host=${selectedNode} port=${portNumber} dbname=citus user=${adminLogin} password={your_password} sslmode=require"`;
|
||||
const jdbc = `jdbc:postgresql://${selectedNode}:${portNumber}/citus?user=${adminLogin}&password={your_password}&sslmode=require`;
|
||||
const libpq = `host=${selectedNode} port=${portNumber} dbname=citus user=${adminLogin} password={your_password} sslmode=require`;
|
||||
const adoDotNet = `Server=${selectedNode};Database=citus;Port=${portNumber};User Id=${adminLogin};Password={your_password};Ssl Mode=Require;`;
|
||||
|
||||
return (
|
||||
<div style={{ width: "100%", padding: 16 }}>
|
||||
<Stack horizontal verticalAlign="center" style={{ marginBottom: 8 }}>
|
||||
<Label style={{ marginRight: 8 }}>Public IP addresses on worker nodes:</Label>
|
||||
<TooltipHost
|
||||
content="
|
||||
You can enable or disable public IP addresses on the worker nodes on 'Networking' page of your server group."
|
||||
>
|
||||
<Icon style={{ margin: "5px 8px 0 0", cursor: "default" }} iconName="Info" />
|
||||
</TooltipHost>
|
||||
|
||||
<TextField value={enablePublicIpAccess ? "On" : "Off"} readOnly disabled />
|
||||
</Stack>
|
||||
<Stack horizontal style={{ marginBottom: 8 }}>
|
||||
<Label style={{ marginRight: 85 }}>Show connection strings for</Label>
|
||||
<Dropdown
|
||||
options={nodesDropdownOptions}
|
||||
selectedKey={selectedNode}
|
||||
onChange={(_, option) => {
|
||||
const selectedNode = option.key as string;
|
||||
setSelectedNode(selectedNode);
|
||||
if (!selectedNode.startsWith("c.")) {
|
||||
setUsePgBouncerPort(false);
|
||||
}
|
||||
}}
|
||||
style={{ width: 200 }}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack horizontal style={{ marginBottom: 8 }}>
|
||||
<Label style={{ marginRight: 44 }}>PgBouncer connection strings</Label>
|
||||
<Checkbox
|
||||
boxSide="end"
|
||||
checked={usePgBouncerPort}
|
||||
onChange={(_, checked: boolean) => setUsePgBouncerPort(checked)}
|
||||
disabled={!selectedNode?.startsWith("c.")}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
<TextField
|
||||
label="PostgreSQL connection URL"
|
||||
id="postgresSQLConnectionURL"
|
||||
readOnly
|
||||
value={postgresSQLConnectionURL}
|
||||
styles={textfieldStyles}
|
||||
/>
|
||||
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#postgresSQLConnectionURL")} />
|
||||
</Stack>
|
||||
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
<TextField label="psql" id="psql" readOnly value={psql} styles={textfieldStyles} />
|
||||
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#psql")} />
|
||||
</Stack>
|
||||
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
<TextField label="JDBC" id="JDBC" readOnly value={jdbc} styles={textfieldStyles} />
|
||||
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#JDBC")} />
|
||||
</Stack>
|
||||
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
<TextField
|
||||
label="Node.js, Python, Ruby, PHP, C++ (libpq)"
|
||||
id="libpq"
|
||||
readOnly
|
||||
value={libpq}
|
||||
styles={textfieldStyles}
|
||||
/>
|
||||
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#libpq")} />
|
||||
</Stack>
|
||||
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
|
||||
<TextField label="ADO.NET" id="adoDotNet" readOnly value={adoDotNet} styles={textfieldStyles} />
|
||||
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#adoDotNet")} />
|
||||
</Stack>
|
||||
|
||||
<Label>Secure connections</Label>
|
||||
<Text>
|
||||
Only secure connections are supported. For production use cases, we recommend using the 'verify-full'
|
||||
mode to enforce TLS certificate verification. You will need to download the Hyperscale (Citus) certificate, and
|
||||
provide it when connecting to the database.{" "}
|
||||
<Link href="https://go.microsoft.com/fwlink/?linkid=2155061" target="_blank">
|
||||
Learn more
|
||||
</Link>
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -2,10 +2,12 @@ import { CollectionTabKind } from "Contracts/ViewModels";
|
|||
import Explorer from "Explorer/Explorer";
|
||||
import { SplashScreen } from "Explorer/SplashScreen/SplashScreen";
|
||||
import { ConnectTab } from "Explorer/Tabs/ConnectTab";
|
||||
import { PostgresConnectTab } from "Explorer/Tabs/PostgresConnectTab";
|
||||
import { QuickstartTab } from "Explorer/Tabs/QuickstartTab";
|
||||
import { useTeachingBubble } from "hooks/useTeachingBubble";
|
||||
import ko from "knockout";
|
||||
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import { userContext } from "UserContext";
|
||||
import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
|
||||
import errorIcon from "../../../images/close-black.svg";
|
||||
import { useObservable } from "../../hooks/useObservable";
|
||||
|
@ -189,7 +191,7 @@ const onKeyPressReactTab = (e: KeyboardEvent, tabKind: ReactTabKind): void => {
|
|||
const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => {
|
||||
switch (activeReactTab) {
|
||||
case ReactTabKind.Connect:
|
||||
return <ConnectTab />;
|
||||
return userContext.apiType === "Postgres" ? <PostgresConnectTab /> : <ConnectTab />;
|
||||
case ReactTabKind.Home:
|
||||
return <SplashScreen explorer={explorer} />;
|
||||
case ReactTabKind.Quickstart:
|
||||
|
|
|
@ -26,6 +26,20 @@ export interface CollectionCreationDefaults {
|
|||
throughput: ThroughputDefaults;
|
||||
}
|
||||
|
||||
export interface Node {
|
||||
text: string;
|
||||
value: string;
|
||||
ariaLabel: string;
|
||||
}
|
||||
|
||||
export interface PostgresConnectionStrParams {
|
||||
adminLogin: string;
|
||||
enablePublicIpAccess: boolean;
|
||||
nodes: Node[];
|
||||
isMarlinServerGroup: boolean;
|
||||
isFreeTier: boolean;
|
||||
}
|
||||
|
||||
interface UserContext {
|
||||
readonly authType?: AuthType;
|
||||
readonly masterKey?: string;
|
||||
|
@ -52,6 +66,7 @@ interface UserContext {
|
|||
collectionId: string;
|
||||
partitionKey?: string;
|
||||
};
|
||||
readonly postgresConnectionStrParams?: PostgresConnectionStrParams;
|
||||
collectionCreationDefaults: CollectionCreationDefaults;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import {
|
|||
} from "../Platform/Hosted/HostedUtils";
|
||||
import { CollectionCreation } from "../Shared/Constants";
|
||||
import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility";
|
||||
import { PortalEnv, updateUserContext, userContext } from "../UserContext";
|
||||
import { Node, PortalEnv, updateUserContext, userContext } from "../UserContext";
|
||||
import { listKeys } from "../Utils/arm/generatedClients/cosmos/databaseAccounts";
|
||||
import { DatabaseAccountListKeysResult } from "../Utils/arm/generatedClients/cosmos/types";
|
||||
import { getMsalInstance } from "../Utils/AuthorizationUtils";
|
||||
|
@ -357,6 +357,20 @@ function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
|
|||
|
||||
if (inputs.isPostgresAccount) {
|
||||
updateUserContext({ apiType: "Postgres" });
|
||||
|
||||
if (inputs.connectionStringParams) {
|
||||
// TODO: Remove after the nodes param has been updated to be a flat array in the OSS extension
|
||||
let flattenedNodesArray: Node[] = [];
|
||||
inputs.connectionStringParams.nodes?.forEach((node: Node | Node[]) => {
|
||||
if (Array.isArray(node)) {
|
||||
flattenedNodesArray = [...flattenedNodesArray, ...node];
|
||||
} else {
|
||||
flattenedNodesArray.push(node);
|
||||
}
|
||||
});
|
||||
inputs.connectionStringParams.nodes = flattenedNodesArray;
|
||||
updateUserContext({ postgresConnectionStrParams: inputs.connectionStringParams });
|
||||
}
|
||||
}
|
||||
|
||||
if (inputs.features) {
|
||||
|
|
Loading…
Reference in New Issue