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..afffb15
--- /dev/null
+++ b/ui/src/components/ConnectionOptions.tsx
@@ -0,0 +1,64 @@
+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 openURI = (connectionURI: string, saPassword: string) => {
+ copyToClipboard(saPassword);
+ // wait 1 second
+ setTimeout(() => {
+ window.location.href = connectionURI;
+ }, 1000);
+}
+
+export const ConnectionOptions = ({ container, trackEvent }) => {
+
+if (osName !== "Windows") {
+ return (
+ <>
+
+ {
+ trackEvent('OpenADS', { containerId: container.Id });
+ openURI(container.adsConnectionURI(), container.SApassword);
+ }}>
+
+
+
+
+ {
+ trackEvent('OpenVSC', { containerId: container.Id });
+ openURI(container.vscConnectionURI(), container.SApassword);
+ }}>
+
+
+
+ >
+ );
+} else {
+ return (
+ <>
+
+ {
+ trackEvent('OpenADS', { containerId: container.Id });
+ openURI(container.adsConnectionURI(), container.SApassword);
+ }}>
+
+
+
+
+ {
+ trackEvent('OpenVSC', { containerId: container.Id });
+ openURI(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..a0c5b7a 100644
--- a/ui/src/models/SqlContainer.tsx
+++ b/ui/src/models/SqlContainer.tsx
@@ -41,7 +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&trustServerCertificate=true&persistSecurityInfo=true&savePassword=true`;
}
}