Skip to content

Commit 9638607

Browse files
author
colinmcneil
committed
Implement secrets using new query
1 parent 9c6f0df commit 9638607

File tree

10 files changed

+56
-173
lines changed

10 files changed

+56
-173
lines changed

src/extension/ui/src/App.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,6 @@ export function App() {
5858
) : (
5959
<CatalogGrid
6060
appProps={appProps}
61-
setConfiguringItem={setConfiguringItem}
62-
showSettings={() => setSettings({ ...settings, showModal: true })}
6361
/>
6462
)}
6563
</>

src/extension/ui/src/Secrets.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@ namespace Secrets {
3838
export async function deleteSecret(client: v1.DockerDesktopClient, name: string): Promise<void> {
3939
try {
4040
const response = await client.extension.host?.cli.exec('host-binary', ['delete', '--name', name]);
41-
client.desktopUI.toast.success('Secret deleted successfully')
4241
if (!response) {
4342
client.desktopUI.toast.error('Failed to delete secret. Could not get response from host-binary.')
43+
throw new Error('Failed to delete secret. Could not get response from host-binary.')
4444
}
4545
if (response?.stderr) {
4646
client.desktopUI.toast.error('Failed to delete secret: ' + JSON.stringify(response))
47+
throw new Error('Failed to delete secret: ' + JSON.stringify(response))
4748
}
49+
client.desktopUI.toast.success('Secret deleted successfully')
4850
} catch (error) {
4951
if ((error as any).stderr) {
5052
client.desktopUI.toast.error('Failed to delete secret: ' + JSON.stringify(error))

src/extension/ui/src/components/CatalogGrid.tsx

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@ import { CATALOG_LAYOUT_SX } from '../Constants';
99
import { MCPClientState } from '../MCPClients';
1010

1111
const ToolCatalog = React.lazy(() => import('./tabs/ToolCatalog'));
12-
const YourEnvironment = React.lazy(() => import('./tabs/YourEnvironment'));
12+
const YourTools = React.lazy(() => import('./tabs/YourTools'));
1313

1414
// Initialize the Docker Desktop client
1515
const client = createDockerDesktopClient();
1616

1717
interface CatalogGridProps {
1818
appProps: any; // We'll use this to pass all our hook data
19-
showSettings: () => void;
20-
setConfiguringItem: (item: CatalogItemRichened) => void;
2119
}
2220

2321
const parseDDVersion = (ddVersion: string) => {
@@ -32,20 +30,13 @@ const NEVER_SHOW_AGAIN_KEY = 'registry-sync-never-show-again';
3230

3331
export const CatalogGrid: React.FC<CatalogGridProps> = ({
3432
appProps,
35-
setConfiguringItem,
3633
}) => {
3734
// Extract all the values we need from appProps
3835
const {
3936
catalogItems,
4037
registryItems,
41-
canRegister,
42-
registerCatalogItem,
43-
unregisterCatalogItem,
44-
tryUpdateSecrets,
45-
secrets,
4638
mcpClientStates,
4739
isLoading: mcpLoading,
48-
config
4940
} = appProps;
5041

5142
const [showReloadModal, setShowReloadModal] = useState<boolean>(false);
@@ -89,16 +80,6 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
8980
catalogItems.some((c: CatalogItemRichened) => c.name === i)
9081
)
9182

92-
const sortedCatalogItems = sort !== 'date-desc' ? [...catalogItems].sort((a, b) => {
93-
if (sort === 'name-asc') {
94-
return a.name.localeCompare(b.name);
95-
}
96-
if (sort === 'name-desc') {
97-
return b.name.localeCompare(a.name);
98-
}
99-
return 0;
100-
}) : catalogItems;
101-
10283
if (!ddVersion) {
10384
return <>
10485
<CircularProgress />
@@ -206,19 +187,9 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
206187
<Suspense fallback={<Box sx={{ display: 'flex', justifyContent: 'center', p: 4 }}><CircularProgress /></Box>}>
207188
{tab === 0 && (
208189
<ToolCatalog
209-
registryItems={registryItems}
210190
search={search}
211-
catalogItems={sortedCatalogItems}
212191
showMine={showMine}
213192
client={client}
214-
ddVersion={ddVersion}
215-
canRegister={canRegister}
216-
register={registerCatalogItem}
217-
unregister={unregisterCatalogItem}
218-
onSecretChange={tryUpdateSecrets}
219-
secrets={secrets}
220-
setConfiguringItem={setConfiguringItem}
221-
config={config || {}}
222193
/>
223194
)}
224195
{tab === 1 && (

src/extension/ui/src/components/tabs/ToolCatalog.tsx

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,18 @@
11
import React from 'react';
2-
import { Card, CardContent, Grid2, IconButton } from '@mui/material';
2+
import { Grid2 } from '@mui/material';
33
import Tile from '../tile/Index';
4-
import AddIcon from '@mui/icons-material/Add';
54
import { v1 } from "@docker/extension-api-client-types";
6-
import { CatalogItemRichened } from '../../types/catalog';
7-
import { Secret } from '../../types/secrets';
85
import { CATALOG_LAYOUT_SX } from '../../Constants';
6+
import { useCatalog } from '../../hooks/useCatalog';
97

108
interface ToolCatalogProps {
119
search: string;
12-
catalogItems: CatalogItemRichened[];
1310
client: v1.DockerDesktopClient;
14-
ddVersion: { version: string, build: number };
15-
canRegister: boolean;
16-
register: (item: CatalogItemRichened) => Promise<void>;
17-
unregister: (item: CatalogItemRichened) => Promise<void>;
18-
onSecretChange: (secret: { name: string, value: string }) => Promise<void>;
19-
secrets: Secret[];
20-
registryItems: { [key: string]: { ref: string, config: any } };
21-
setConfiguringItem: (item: CatalogItemRichened) => void;
22-
config: { [key: string]: { [key: string]: any } };
2311
showMine: boolean;
2412
}
2513

26-
const ToolCatalog: React.FC<ToolCatalogProps> = ({ config, search, catalogItems, client, registryItems, showMine }) => {
27-
14+
const ToolCatalog: React.FC<ToolCatalogProps> = ({ search, client, showMine }) => {
15+
const { catalogItems } = useCatalog(client)
2816
const filteredCatalogItems = catalogItems.filter(item => {
2917
const matchesSearch = item.name.toLowerCase().includes(search.toLowerCase());
3018
const hideBecauseItsNotMine = showMine && !item.registered;
@@ -34,13 +22,10 @@ const ToolCatalog: React.FC<ToolCatalogProps> = ({ config, search, catalogItems,
3422
return (
3523
<Grid2 container spacing={1} sx={CATALOG_LAYOUT_SX}>
3624
{filteredCatalogItems.map((catalogItem) => {
37-
const expectedKeys = catalogItem.config?.map((c: any) => c.name) || [];
38-
const unAssignedConfig = expectedKeys?.filter((c: any) => config[catalogItem.name]?.[c] === undefined);
3925
return (
4026
<Grid2 size={{ xs: 12, sm: 6, md: 4 }} key={catalogItem.name}>
4127
<Tile
4228
item={catalogItem}
43-
unAssignedConfig={unAssignedConfig}
4429
client={client}
4530
/>
4631
</Grid2>

src/extension/ui/src/components/tabs/YourTools.tsx

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,53 +7,27 @@ import { v1 } from '@docker/extension-api-client-types';
77
import { createDockerDesktopClient } from '@docker/extension-api-client';
88
import { CatalogItemRichened } from '../../types/catalog';
99
import { Secret } from '../../types/secrets';
10+
import { useCatalog } from '../../hooks/useCatalog';
1011
// Initialize the Docker Desktop client
1112
const client = createDockerDesktopClient();
1213

1314
interface YourToolsProps {
1415
search: string;
15-
registryItems: { [key: string]: { ref: string, config: any } };
16-
config: { [key: string]: { [key: string]: any } };
17-
canRegister: boolean;
18-
unregister: (item: CatalogItemRichened) => Promise<void>;
19-
setConfiguringItem: (item: CatalogItemRichened) => void;
20-
secrets: Secret[];
21-
catalogItems: CatalogItemRichened[];
22-
onSecretChange: (secret: { name: string, value: string }) => Promise<void>;
23-
ddVersion: { version: string, build: number };
2416
}
2517

2618
const YourTools: React.FC<YourToolsProps> = ({
2719
search,
28-
registryItems,
29-
catalogItems,
30-
ddVersion,
31-
canRegister,
32-
setConfiguringItem,
33-
secrets,
34-
unregister,
35-
onSecretChange,
36-
config
3720
}) => {
21+
const { catalogItems } = useCatalog(client)
3822
return (
3923
<Grid2 container spacing={1} sx={CATALOG_LAYOUT_SX}>
40-
{Object.entries(registryItems).map(([name, item]) => {
41-
if (!name.toLowerCase().includes(search.toLowerCase())) return null;
42-
const catalogItem = catalogItems.find(c => c.name === name);
43-
const unassignedConfig = catalogItem?.config?.filter((c: any) => !config[name]?.[c]) || [];
44-
const unassignedSecrets = catalogItem?.secrets?.filter((s: any) => !secrets.find((s: any) => s.name === s)) || [];
45-
if (!catalogItem) return <Grid2 size={{ xs: 12, sm: 6, md: 4 }} key={name}>
46-
<Alert severity="error">
47-
<AlertTitle><strong>{name}</strong> not in catalog</AlertTitle>
48-
You have registered a tile named <strong>{name}</strong> but it is not in the catalog. If this is not intentional, the catalog may have changed since.
49-
</Alert>
50-
</Grid2>;
24+
{catalogItems.map((catalogItem) => {
25+
if (!catalogItem.name.toLowerCase().includes(search.toLowerCase())) return null;
5126
return (
52-
<Grid2 size={{ xs: 12, sm: 6, md: 4 }} key={name}>
27+
<Grid2 size={{ xs: 12, sm: 6, md: 4 }} key={catalogItem.name}>
5328
<Tile
5429
item={catalogItem}
5530
client={client}
56-
unAssignedConfig={unassignedConfig}
5731
/>
5832
</Grid2>
5933
);

src/extension/ui/src/components/tile/Index.tsx

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,21 @@ import { Card, CardContent } from "@mui/material";
33
import { useEffect, useState } from "react";
44
import { CatalogItemRichened } from "../../types/catalog";
55
import { Save, LockReset } from "@mui/icons-material";
6-
import Secrets from "../../Secrets";
76
import ConfigurationModal from "./Modal";
87
import Top from "./Top";
98
import Center from "./Center";
109
import Bottom from "./Bottom";
1110
import { v1 } from "@docker/extension-api-client-types";
1211
import { useSecrets } from "../../hooks/useSecrets";
13-
import { useCatalog, useCatalogOperations, useRegistry } from "../../hooks/useCatalog";
12+
import { useCatalogOperations, useRegistry } from "../../hooks/useCatalog";
1413
import { MCP_POLICY_NAME } from "../../Constants";
1514

1615
type TileProps = {
1716
item: CatalogItemRichened;
1817
client: v1.DockerDesktopClient;
19-
unAssignedConfig: { name: string; assigned: boolean }[];
2018
}
2119

22-
const Tile = ({ item, client, unAssignedConfig }: TileProps) => {
20+
const Tile = ({ item, client }: TileProps) => {
2321

2422
const [showSecretDialog, setShowSecretDialog] = useState(false)
2523
const [assignedSecrets] = useState<{ name: string, assigned: boolean }[]>([])
@@ -94,10 +92,10 @@ const Tile = ({ item, client, unAssignedConfig }: TileProps) => {
9492
} else {
9593
unregisterCatalogItem(item)
9694
}
97-
}} item={item} unAssignedConfig={unAssignedConfig} unAssignedSecrets={unAssignedSecrets} />
95+
}} item={item} />
9896
<Center item={item} />
9997
<Divider sx={{ marginBottom: 1 }} />
100-
<Bottom item={item} needsConfiguration={Boolean(unAssignedSecrets.length || unAssignedConfig.length)} />
98+
<Bottom item={item} needsConfiguration={Boolean(unAssignedSecrets.length)} />
10199
</Stack>
102100
</CardContent>
103101
</Card >

src/extension/ui/src/components/tile/Modal.tsx

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@ import { Alert, Badge, Box, ButtonGroup, CircularProgress, Divider, FormControlL
22
import { CheckOutlined, Close, CloseOutlined, DeleteOutlined } from "@mui/icons-material";
33
import { useEffect, useMemo, useState } from "react";
44
import { CatalogItemRichened } from "../../types/catalog";
5-
import Secrets from "../../Secrets";
65
import { v1 } from "@docker/extension-api-client-types";
76
import { ASSIGNED_SECRET_PLACEHOLDER, CATALOG_LAYOUT_SX, MCP_POLICY_NAME, UNASSIGNED_SECRET_PLACEHOLDER } from "../../Constants";
87
import ConfigEditor from "./ConfigEditor";
98
import { useSecrets } from "../../hooks/useSecrets";
109
import { useCatalogOperations, useRegistry } from "../../hooks/useCatalog";
1110
import { useConfig } from "../../hooks/useConfig";
1211

13-
// Styles for the tab panel
1412
interface TabPanelProps {
1513
children?: React.ReactNode;
1614
index: number;
@@ -60,18 +58,15 @@ const ConfigurationModal = ({
6058
const { registerCatalogItem, unregisterCatalogItem } = useCatalogOperations(client)
6159
const { configLoading } = useConfig(client)
6260

61+
console.log('catalogItem', catalogItem)
62+
6363
useEffect(() => {
64-
if (localSecrets) return;
6564
setLocalSecrets(catalogItem.secrets.reduce((acc, secret) => {
6665
acc[secret.name] = secret.assigned ? ASSIGNED_SECRET_PLACEHOLDER : '';
6766
return acc;
6867
}, {} as { [key: string]: string | undefined }));
6968
}, [catalogItem.secrets]);
7069

71-
if (catalogItem.name === 'atlassian') {
72-
console.log(localSecrets)
73-
}
74-
7570
const toolChipStyle = {
7671
padding: '2px 8px',
7772
justifyContent: 'center',
@@ -113,8 +108,6 @@ const ConfigurationModal = ({
113108
</>
114109
}
115110

116-
const canRegister = catalogItem.canRegister;
117-
118111
return (
119112
<Modal
120113
open={open}
@@ -145,8 +138,8 @@ const ConfigurationModal = ({
145138
<Typography sx={{ mt: 2, maxHeight: '5em', overflow: 'auto' }} color="text.secondary">
146139
{catalogItem.description}
147140
</Typography>
148-
<Tooltip placement="right" title={!canRegister ? 'You must assign all secrets and configure the item before it can be used.' : ''}>
149-
<FormControlLabel control={<Switch disabled={!canRegister} checked={catalogItem.registered} onChange={(e) => registerCatalogItem(catalogItem)} />} label={catalogItem.registered ? 'Disable ' + `${catalogItem.name} tools` : 'Enable ' + `${catalogItem.name} tools`} sx={{ mt: 2 }} />
141+
<Tooltip placement="right" title={!catalogItem.canRegister ? 'You must assign all secrets and configure the item before it can be used.' : ''}>
142+
<FormControlLabel control={<Switch disabled={!catalogItem.canRegister} checked={catalogItem.registered} onChange={(e) => catalogItem.registered ? unregisterCatalogItem(catalogItem) : registerCatalogItem(catalogItem)} />} label={catalogItem.registered ? 'Disable ' + `${catalogItem.name} tools` : 'Enable ' + `${catalogItem.name} tools`} sx={{ mt: 2 }} />
150143
</Tooltip>
151144
<Divider sx={{ mt: 2 }} />
152145
<Typography variant="caption" sx={{ mt: 2, color: 'text.secondary' }}>
@@ -165,7 +158,7 @@ const ConfigurationModal = ({
165158
<Tabs value={tabValue} onChange={handleTabChange}>
166159
<Tab label="Tools" />
167160
{/* <Tab label="Prompts" /> */}
168-
<Tab disabled={contributesNoConfigOrSecrets} label={<Badge invisible={canRegister} sx={{ pl: 1, pr: 1 }} variant="dot" badgeContent={catalogItem.config && catalogItem.config.length > 0 ? 'Secrets' : 'Config'} color="error">Config & Secrets</Badge>} />
161+
<Tab disabled={contributesNoConfigOrSecrets} label={<Badge invisible={catalogItem.canRegister} sx={{ pl: 1, pr: 1 }} variant="dot" badgeContent={catalogItem.config && catalogItem.config.length > 0 ? 'Secrets' : 'Config'} color="error">Config & Secrets</Badge>} />
169162
</Tabs>
170163
</Box>
171164
<TabPanel value={tabValue} index={0} >
@@ -194,15 +187,13 @@ const ConfigurationModal = ({
194187
{
195188
catalogItem.secrets && catalogItem.secrets?.length > 0 ? (
196189
catalogItem.secrets.map(secret => {
197-
const secretEdited = secret.assigned ? localSecrets[secret.name] !== ASSIGNED_SECRET_PLACEHOLDER : localSecrets[secret.name] !== '';
198-
console.log(secret.name, secretEdited, secret.assigned, localSecrets[secret.name])
190+
const secretEdited = (secret.assigned && localSecrets[secret.name] !== ASSIGNED_SECRET_PLACEHOLDER) || (!secret.assigned && localSecrets[secret.name] !== '');
199191
return (
200192
<Stack key={secret.name} direction="row" spacing={2} alignItems="center">
201193
<TextField key={secret.name} label={secret.name} value={localSecrets[secret.name]} fullWidth onChange={(e) => {
202194
setLocalSecrets({ ...localSecrets, [secret.name]: e.target.value });
203195
}} type='password' />
204196
{secret.assigned && !secretEdited && <IconButton size="small" color="error" onClick={() => {
205-
setLocalSecrets({ ...localSecrets, [secret.name]: '' });
206197
mutateSecret.mutateAsync({ name: secret.name, value: undefined, policies: [MCP_POLICY_NAME] });
207198
}}>
208199
<DeleteOutlined />

src/extension/ui/src/components/tile/Top.tsx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
import { Settings } from "@mui/icons-material";
21
import { CardMedia, Stack, Switch, Tooltip, Typography } from "@mui/material";
32
import { CatalogItemRichened } from "../../types/catalog";
43

54
type TopProps = {
6-
unAssignedConfig: { name: string, assigned: boolean }[],
75
onToggleRegister: (checked: boolean) => void,
8-
unAssignedSecrets: { name: string, assigned: boolean }[],
96
item: CatalogItemRichened
107
}
118

0 commit comments

Comments
 (0)