From b424b524f413a0ee22277badc1ea042b81e344a8 Mon Sep 17 00:00:00 2001 From: Drew Skwiers-Koballa Date: Thu, 13 Feb 2025 17:22:51 -0800 Subject: [PATCH 1/3] adds VSCode connection button --- ui/package-lock.json | 40 +++++++++++++++ ui/package.json | 1 + ui/src/components/ConnectionOptions.tsx | 66 +++++++++++++++++++++++++ ui/src/components/ContainerList.tsx | 23 +++------ ui/src/models/SqlContainer.tsx | 4 ++ 5 files changed, 117 insertions(+), 17 deletions(-) create mode 100644 ui/src/components/ConnectionOptions.tsx diff --git a/ui/package-lock.json b/ui/package-lock.json index ee2565f..05111c2 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -17,6 +17,7 @@ "@mui/icons-material": "6.1.9", "@mui/material": "6.1.9", "react": "^18.2.0", + "react-device-detect": "^2.2.3", "react-dom": "^18.2.0" }, "devDependencies": { @@ -4605,6 +4606,19 @@ "node": ">=0.10.0" } }, + "node_modules/react-device-detect": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-device-detect/-/react-device-detect-2.2.3.tgz", + "integrity": "sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==", + "license": "MIT", + "dependencies": { + "ua-parser-js": "^1.0.33" + }, + "peerDependencies": { + "react": ">= 0.14.0", + "react-dom": ">= 0.14.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -5070,6 +5084,32 @@ "node": ">=4.2.0" } }, + "node_modules/ua-parser-js": { + "version": "1.0.40", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.40.tgz", + "integrity": "sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", diff --git a/ui/package.json b/ui/package.json index b59b412..11861c9 100644 --- a/ui/package.json +++ b/ui/package.json @@ -13,6 +13,7 @@ "@mui/icons-material": "6.1.9", "@mui/material": "6.1.9", "react": "^18.2.0", + "react-device-detect": "^2.2.3", "react-dom": "^18.2.0" }, "scripts": { diff --git a/ui/src/components/ConnectionOptions.tsx b/ui/src/components/ConnectionOptions.tsx new file mode 100644 index 0000000..6c181f9 --- /dev/null +++ b/ui/src/components/ConnectionOptions.tsx @@ -0,0 +1,66 @@ +import { osName } from 'react-device-detect'; +import { IconButton, Tooltip } from '@mui/material'; +import { DvrRounded } from '@mui/icons-material'; +import { copyToClipboard } from './ContainerList'; + +// copies the password to the clipboard, then opens the connectionURI +const openADS = (connectionURI: string, saPassword: string) => { + copyToClipboard(saPassword); + window.location.href = connectionURI; +} + +const openVSC = (connectionURI: string, saPassword: string) => { + copyToClipboard(saPassword); + window.location.href = connectionURI; +} + +export const ConnectionOptions = ({ container, trackEvent }) => { + +if (osName !== "Windows") { + return ( + <> + + { + trackEvent('OpenADS', { containerId: container.Id }); + openADS(container.adsConnectionURI(), container.SApassword); + }}> + + + + + { + trackEvent('OpenVSC', { containerId: container.Id }); + openVSC(container.vscConnectionURI(), container.SApassword); + }}> + + + + + ); +} else { + return ( + <> + + { + trackEvent('OpenADS', { containerId: container.Id }); + openADS(container.adsConnectionURI(), container.SApassword); + }}> + + + + + { + trackEvent('OpenVSC', { containerId: container.Id }); + openVSC(container.vscConnectionURI(), container.SApassword); + }}> + + + + + ); +} +} \ No newline at end of file diff --git a/ui/src/components/ContainerList.tsx b/ui/src/components/ContainerList.tsx index 183a3c3..f7747a7 100644 --- a/ui/src/components/ContainerList.tsx +++ b/ui/src/components/ContainerList.tsx @@ -1,12 +1,15 @@ import * as React from 'react'; import { AppBar, Box, Button, Chip, CircularProgress, Collapse, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, FormControl, IconButton, InputLabel, List, ListItem, ListItemIcon, ListItemText, OutlinedInput, Stack, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Toolbar, Tooltip, Typography } from '@mui/material'; -import { AddCircleRounded, ArticleRounded, ContentCopyRounded, StopRounded, PlayArrowRounded, KeyboardArrowUpRounded, KeyboardArrowDownRounded, TerminalRounded, DvrRounded, CloseRounded, DeleteRounded } from "@mui/icons-material"; +import { AddCircleRounded, ArticleRounded, ContentCopyRounded, StopRounded, PlayArrowRounded, KeyboardArrowUpRounded, KeyboardArrowDownRounded, TerminalRounded, CloseRounded, DeleteRounded } from "@mui/icons-material"; import { SqlContainer } from '../models/SqlContainer'; +import { ConnectionOptions } from './ConnectionOptions'; import { useDockerDesktopClient } from '../App'; -const copyToClipboard = (text: string) => { +export const copyToClipboard = (text: string) => { navigator.clipboard.writeText(text); + const ddClient = useDockerDesktopClient(); + ddClient.desktopUI.toast.success("Password copied to clipboard"); } const navigateToContainer = (containerId: string) => { @@ -14,12 +17,6 @@ const navigateToContainer = (containerId: string) => { ddClient.desktopUI.navigate.viewContainerLogs(containerId); } -// copies the password to the clipboard, then opens the connectionURI -const openADS = (connectionURI: string, saPassword: string) => { - copyToClipboard(saPassword); - window.location.href = connectionURI; -} - var ContainerStatus = ({ status }) => { if (status === "running") { return ( @@ -205,15 +202,7 @@ var ContainerRow = ({ container, startContainer, stopContainer, deleteContainer, - - { - trackEvent('OpenADS', { containerId: container.Id }); - openADS(container.adsConnectionURI(), container.SApassword); - }}> - - - + { trackEvent('ViewLogs', { containerId: container.Id }); diff --git a/ui/src/models/SqlContainer.tsx b/ui/src/models/SqlContainer.tsx index bc2d794..1636a20 100644 --- a/ui/src/models/SqlContainer.tsx +++ b/ui/src/models/SqlContainer.tsx @@ -44,4 +44,8 @@ export class SqlContainer { return `azuredatastudio://openConnectionDialog?connectionName=${this.Name}&server=localhost,${this.Port1433}&authenticationType=SqlLogin&user=sa&password=${this.SApassword}&database=master&connectionProperties={"trustServerCertificate":"true"}`; } + public vscConnectionURI(): string { + return `vscode://ms-mssql.mssql/connect?profileName=${this.Name}&server=localhost,${this.Port1433}&database=master&authenticationType=SqlLogin&user=sa&password=${this.SApassword}&trustServerCertificate=true&persistSecurityInfo=true`; + } + } From 48b711967a9d659f8b3a6539933f04b71db4d07f Mon Sep 17 00:00:00 2001 From: Drew Skwiers-Koballa Date: Thu, 20 Feb 2025 17:16:47 -0800 Subject: [PATCH 2/3] removes nonfunctional password param from uri --- ui/src/models/SqlContainer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/models/SqlContainer.tsx b/ui/src/models/SqlContainer.tsx index 1636a20..a0c5b7a 100644 --- a/ui/src/models/SqlContainer.tsx +++ b/ui/src/models/SqlContainer.tsx @@ -41,11 +41,11 @@ export class SqlContainer { } public adsConnectionURI(): string { - return `azuredatastudio://openConnectionDialog?connectionName=${this.Name}&server=localhost,${this.Port1433}&authenticationType=SqlLogin&user=sa&password=${this.SApassword}&database=master&connectionProperties={"trustServerCertificate":"true"}`; + return `azuredatastudio://openConnectionDialog?connectionName=${this.Name}&server=localhost,${this.Port1433}&authenticationType=SqlLogin&user=sa&database=master&connectionProperties={"trustServerCertificate":"true"}`; } public vscConnectionURI(): string { - return `vscode://ms-mssql.mssql/connect?profileName=${this.Name}&server=localhost,${this.Port1433}&database=master&authenticationType=SqlLogin&user=sa&password=${this.SApassword}&trustServerCertificate=true&persistSecurityInfo=true`; + return `vscode://ms-mssql.mssql/connect?profileName=${this.Name}&server=localhost,${this.Port1433}&database=master&authenticationType=SqlLogin&user=sa&trustServerCertificate=true&persistSecurityInfo=true&savePassword=true`; } } From 72cd2999ee46e3ea36610e00a3b7e55e1b1cc4ba Mon Sep 17 00:00:00 2001 From: Drew Skwiers-Koballa Date: Thu, 20 Feb 2025 17:17:03 -0800 Subject: [PATCH 3/3] make clipboard toast easier to see --- ui/src/components/ConnectionOptions.tsx | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/ui/src/components/ConnectionOptions.tsx b/ui/src/components/ConnectionOptions.tsx index 6c181f9..afffb15 100644 --- a/ui/src/components/ConnectionOptions.tsx +++ b/ui/src/components/ConnectionOptions.tsx @@ -4,14 +4,12 @@ import { DvrRounded } from '@mui/icons-material'; import { copyToClipboard } from './ContainerList'; // copies the password to the clipboard, then opens the connectionURI -const openADS = (connectionURI: string, saPassword: string) => { +const openURI = (connectionURI: string, saPassword: string) => { copyToClipboard(saPassword); - window.location.href = connectionURI; -} - -const openVSC = (connectionURI: string, saPassword: string) => { - copyToClipboard(saPassword); - window.location.href = connectionURI; + // wait 1 second + setTimeout(() => { + window.location.href = connectionURI; + }, 1000); } export const ConnectionOptions = ({ container, trackEvent }) => { @@ -23,7 +21,7 @@ if (osName !== "Windows") { { trackEvent('OpenADS', { containerId: container.Id }); - openADS(container.adsConnectionURI(), container.SApassword); + openURI(container.adsConnectionURI(), container.SApassword); }}> @@ -32,7 +30,7 @@ if (osName !== "Windows") { { trackEvent('OpenVSC', { containerId: container.Id }); - openVSC(container.vscConnectionURI(), container.SApassword); + openURI(container.vscConnectionURI(), container.SApassword); }}> @@ -46,7 +44,7 @@ if (osName !== "Windows") { { trackEvent('OpenADS', { containerId: container.Id }); - openADS(container.adsConnectionURI(), container.SApassword); + openURI(container.adsConnectionURI(), container.SApassword); }}> @@ -55,7 +53,7 @@ if (osName !== "Windows") { { trackEvent('OpenVSC', { containerId: container.Id }); - openVSC(container.vscConnectionURI(), container.SApassword); + openURI(container.vscConnectionURI(), container.SApassword); }}>