Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit e68ab69

Browse files
committed
fix(): fix cards and types
1 parent 69ab59a commit e68ab69

File tree

11 files changed

+138
-68
lines changed

11 files changed

+138
-68
lines changed

icon.svg

Lines changed: 6 additions & 0 deletions
Loading

metadata.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"icon": "docker.svg",
2+
"icon": "icon.svg",
33
"ui": {
44
"dashboard-tab": {
55
"title": "Databases",

ui/public/clickhouse.png

986 Bytes
Loading

ui/public/mariadb.png

33.1 KB
Loading

ui/public/mongo.png

100 KB
Loading

ui/public/mysql.png

9.97 KB
Loading

ui/src/components/AddNewDatabaseCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ export const AddNewDatabaseCard = () => {
1515
<Card
1616
variant="outlined"
1717
sx={{
18-
cursor: "default",
1918
width: "265px",
2019
height: "205px",
2120
display: "flex",
2221
flexDirection: "column",
2322
alignItems: "center",
2423
justifyContent: "center",
24+
cursor: "pointer",
2525
}}
2626
onClick={handleClickOpen}
2727
>

ui/src/components/DatabaseCard.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const DatabaseCard = ({ database }: { database: IDBConnection }) => {
4545
>
4646
<Box sx={{ textAlign: "center", paddingY: 2 }}>
4747
<img
48-
src={`/${database.image}.png`}
48+
src={`https://raw.githubusercontent.com/docker/database-extension/main/ui/public/${database.image}.png`}
4949
width="40px"
5050
style={{
5151
filter: isConnected ? "none" : "grayscale(100%)",
@@ -74,9 +74,9 @@ export const DatabaseCard = ({ database }: { database: IDBConnection }) => {
7474
</Box>
7575
<Typography
7676
variant="h3"
77-
onClick={handleClickOpen}
77+
onClick={isConnected ? handleClickOpen : () => {}}
7878
sx={{
79-
cursor: "pointer",
79+
cursor: isConnected ? "pointer" : "",
8080
}}
8181
>
8282
{database.name}

ui/src/components/NewDatabaseDialog.tsx

Lines changed: 106 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,21 @@ import { createDockerDesktopClient } from "@docker/extension-api-client";
22
import { ExecResult } from "@docker/extension-api-client-types/dist/v1";
33
import {
44
Box,
5-
Button, CircularProgress,
6-
Dialog, DialogActions,
5+
Button,
6+
CircularProgress,
7+
Dialog,
8+
DialogActions,
79
DialogContent,
810
DialogProps,
911
DialogTitle,
1012
FormControl,
1113
InputLabel,
1214
MenuItem,
13-
Select, SelectChangeEvent, Stack, TextField, useMediaQuery
15+
Select,
16+
SelectChangeEvent,
17+
Stack,
18+
TextField,
19+
useMediaQuery,
1420
} from "@mui/material";
1521
import { Add } from "@mui/icons-material";
1622
import React, { useCallback } from "react";
@@ -49,48 +55,54 @@ export const NewDatabaseDialog = (props: DialogProps) => {
4955
const close = () => {
5056
resetForm();
5157
onClose?.({}, "escapeKeyDown");
52-
}
58+
};
5359

5460
const handleChangeProvider = (event: React.ChangeEvent<HTMLInputElement>) => {
5561
const provider = event.target.value as string;
5662
setProvider(provider);
57-
const { defaults } = officialDBs.find(db => db.id === provider);
58-
setDatabase(defaults.database);
59-
setPort(defaults.port);
60-
setUsername(defaults.username);
61-
setPassword(defaults.password || "");
62-
setIsValid(true);
63-
}
63+
const foundProvider = officialDBs.find((db) => db.id === provider);
64+
if (foundProvider) {
65+
setDatabase(foundProvider.defaults.database);
66+
setPort(foundProvider.defaults.port);
67+
setUsername(foundProvider.defaults.username);
68+
setPassword(foundProvider.defaults.password || "");
69+
setIsValid(true);
70+
}
71+
};
6472

6573
const handleChangeUsername = (event: React.ChangeEvent<HTMLInputElement>) => {
6674
setUsername(event.target.value as string);
67-
setIsValid((provider && username && port && database) as boolean);
68-
}
75+
setIsValid(Boolean(provider && username && port && database));
76+
};
6977

7078
const handleChangePassword = (event: React.ChangeEvent<HTMLInputElement>) => {
7179
setPassword(event.target.value as string);
72-
}
80+
};
7381

7482
const handleChangePort = (event: React.ChangeEvent<HTMLInputElement>) => {
7583
// TODO: check port availability
7684
setPort(event.target.value as string);
77-
setIsValid((provider && username && port && database) as boolean);
78-
}
85+
setIsValid(Boolean(provider && username && port && database));
86+
};
7987

8088
const handleChangeDatabase = (event: React.ChangeEvent<HTMLInputElement>) => {
8189
setDatabase(event.target.value as string);
82-
setIsValid((provider && username && port && database) as boolean);
83-
}
90+
setIsValid(Boolean(provider && username && port && database));
91+
};
8492

8593
const handleCreateDatabase = async () => {
86-
const { image, defaults } = officialDBs.find((db) => db.id === provider);
94+
const foundDB = officialDBs.find((db) => db.id === provider);
95+
if (!foundDB) return;
96+
97+
const { image, defaults } = foundDB;
8798

8899
let envs = [];
89-
const values = { password, username, database }
100+
const values = { password, username, database };
90101
if (defaults.envs) {
91102
for (const key in defaults.envs) {
92103
const value = defaults.envs[key];
93104
const variableName = value.replaceAll("%", "");
105+
// @ts-expect-error type this
94106
const resolvedValue = values[variableName];
95107
envs.push("-e", `${key}=${resolvedValue}`);
96108
}
@@ -99,14 +111,20 @@ export const NewDatabaseDialog = (props: DialogProps) => {
99111
setCreatingContainer(true);
100112
let containerID = "";
101113
try {
102-
const result = await ddClient.docker.cli.exec("run", ["-d", "-p", port, ...envs, image]);
114+
const result = await ddClient.docker.cli.exec("run", [
115+
"-d",
116+
"-p",
117+
port,
118+
...envs,
119+
image,
120+
]);
103121
containerID = result.stdout.trim();
104122
} catch (e) {
105-
console.log(e)
123+
console.log(e);
106124
setCreatingContainer(false);
107125
setError((e as ExecResult).stderr);
108126

109-
return
127+
return;
110128
}
111129

112130
const connectionString = getConnectionString(provider, {
@@ -116,59 +134,97 @@ export const NewDatabaseDialog = (props: DialogProps) => {
116134
port: port.split(":")[0],
117135
});
118136

137+
if (!connectionString) return;
138+
119139
let name = "";
120140
try {
121-
const result = await ddClient.docker.cli.exec("inspect", ["-f", "{{.Name}}", containerID]);
141+
const result = await ddClient.docker.cli.exec("inspect", [
142+
"-f",
143+
"{{.Name}}",
144+
containerID,
145+
]);
122146
name = result.stdout.trim().replaceAll("/", "");
123147
} catch (e) {
124-
console.log(e)
148+
console.log(e);
125149
}
126150

127151
const connection: IDBConnection = {
128152
id: containerID,
129153
name,
130154
connectionString,
131155
image,
132-
}
156+
};
133157

134158
setValue((current: IConnection[]) => [...current, connection]);
135159

136160
setCreatingContainer(false);
137-
setCurrentDatabase(connection)
161+
setCurrentDatabase(connection);
138162
close();
139-
}
163+
};
140164

141165
const { fullWidth = true, ...rest } = props;
142166
return (
143167
<Dialog fullWidth={fullWidth} onClose={close} {...other}>
144-
<DialogTitle>
145-
Create a new database
146-
</DialogTitle>
168+
<DialogTitle>Create a new database</DialogTitle>
147169
<DialogContent>
148170
<Stack gap={1.5} mt={2}>
149171
<TextField
150172
select
151-
labelId="database-label"
173+
// label="database-label"
152174
id="provider"
153175
value={provider}
154176
label="Select a database type"
155177
onChange={handleChangeProvider}
156178
>
157-
{ officialDBs.map((db, key) => (
158-
<MenuItem key={key} value={db.id}>{db.name}</MenuItem>
179+
{officialDBs.map((db, key) => (
180+
<MenuItem key={key} value={db.id}>
181+
{db.name}
182+
</MenuItem>
159183
))}
160184
</TextField>
161-
<TextField id="port" label="Port" value={port} onChange={handleChangePort} variant="outlined" />
162-
<TextField id="database" label="Database name" value={database} onChange={handleChangeDatabase} variant="outlined" />
163-
<TextField id="username" label="Username" value={username} onChange={handleChangeUsername} variant="outlined" />
164-
<TextField id="password" type="password" label="Password" value={password} onChange={handleChangePassword} variant="outlined" />
165-
{ error && <Box sx={{
166-
padding: 1,
167-
borderRadius: 1,
168-
backgroundColor: (theme) => useDarkTheme
169-
? theme.palette.docker.red[200]
170-
: theme.palette.docker.red[100] // red-100 should be "#FDEAEA" but it's not 🤷‍♂️
171-
}}>{error}</Box> }
185+
<TextField
186+
id="port"
187+
label="Port"
188+
value={port}
189+
onChange={handleChangePort}
190+
variant="outlined"
191+
/>
192+
<TextField
193+
id="database"
194+
label="Database name"
195+
value={database}
196+
onChange={handleChangeDatabase}
197+
variant="outlined"
198+
/>
199+
<TextField
200+
id="username"
201+
label="Username"
202+
value={username}
203+
onChange={handleChangeUsername}
204+
variant="outlined"
205+
/>
206+
<TextField
207+
id="password"
208+
type="password"
209+
label="Password"
210+
value={password}
211+
onChange={handleChangePassword}
212+
variant="outlined"
213+
/>
214+
{error && (
215+
<Box
216+
sx={{
217+
padding: 1,
218+
borderRadius: 1,
219+
backgroundColor: (theme) =>
220+
useDarkTheme
221+
? theme.palette.docker.red[200]
222+
: theme.palette.docker.red[100], // red-100 should be "#FDEAEA" but it's not 🤷‍♂️
223+
}}
224+
>
225+
{error}
226+
</Box>
227+
)}
172228
</Stack>
173229
</DialogContent>
174230
<DialogActions>
@@ -181,8 +237,10 @@ export const NewDatabaseDialog = (props: DialogProps) => {
181237
startIcon={
182238
creatingContainer ? <CircularProgress size={20} /> : <Add />
183239
}
184-
>Create</Button>
240+
>
241+
Create
242+
</Button>
185243
</DialogActions>
186244
</Dialog>
187-
)
188-
}
245+
);
246+
};

ui/src/utils/index.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IConnection, IDatabase, IDatabaseProvider, IDBConnection } from "./types";
1+
import { IConnection, IDatabaseProvider } from "./types";
22

33
export const officialDBs: IDatabaseProvider[] = [
44
{
@@ -10,7 +10,7 @@ export const officialDBs: IDatabaseProvider[] = [
1010
username: "default",
1111
database: "default",
1212
password: "mysecretpassword",
13-
}
13+
},
1414
},
1515
{
1616
id: "postgres",
@@ -25,8 +25,8 @@ export const officialDBs: IDatabaseProvider[] = [
2525
POSTGRES_PASSWORD: "%password%",
2626
POSTGRES_USER: "%username%",
2727
POSTGRES_DB: "%database%",
28-
}
29-
}
28+
},
29+
},
3030
},
3131
{
3232
id: "mysql",
@@ -41,8 +41,8 @@ export const officialDBs: IDatabaseProvider[] = [
4141
MYSQL_ROOT_PASSWORD: "%password%",
4242
MYSQL_DATABASE: "%database%",
4343
MYSQL_USER: "%username%",
44-
}
45-
}
44+
},
45+
},
4646
},
4747
{
4848
id: "mariadb",
@@ -57,10 +57,10 @@ export const officialDBs: IDatabaseProvider[] = [
5757
MARIADB_ROOT_PASSWORD: "%password%",
5858
MARIADB_DATABASE: "%database%",
5959
MARIADB_USER: "%username%",
60-
}
61-
}
60+
},
61+
},
6262
},
63-
]
63+
];
6464

6565
export const isOfficialDB = (image: string) => {
6666
console.log("is official", image);
@@ -96,16 +96,23 @@ export const setToLocalStorage = (key: string, value: string) => {
9696

9797
export const getDefaultConnectionStringFromImage = (image: string) => {
9898
if (!isOfficialDB(image)) {
99-
throw new Error(`Unsupported database ${image}`)
99+
throw new Error(`Unsupported database ${image}`);
100100
}
101-
const { id, defaults } = officialDBs.find((db) => image === db.image) || {};
101+
const foundDB = officialDBs.find((db) => image === db.image);
102+
if (!foundDB) return;
102103

104+
const { id, defaults } = foundDB;
105+
106+
// @ts-expect-error type this
103107
return getConnectionString(id, defaults);
104108
};
105-
export const getConnectionString = (provider: string, connection: IConnection) => {
109+
export const getConnectionString = (
110+
provider: string,
111+
connection: IConnection
112+
) => {
106113
const port = connection.port.split(":")[0];
107114

108-
let credentials = connection.username
115+
let credentials = connection.username;
109116
if (connection.password) {
110117
credentials += `:${connection.password}`;
111118
}
@@ -125,4 +132,4 @@ export const getConnectionString = (provider: string, connection: IConnection) =
125132
case provider.includes("clickhouse"):
126133
return "ch://localhost:19000?username=default";
127134
}
128-
};
135+
};

0 commit comments

Comments
 (0)