Skip to content

Commit 11884da

Browse files
authored
Merge pull request #142 from docker/cm/0.2.41
Cm/0.2.41
2 parents 17327ba + 3663fd9 commit 11884da

25 files changed

+766
-1006
lines changed

src/extension/ui/src/App.tsx

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import React, { useState, Suspense } from 'react';
22
import { createDockerDesktopClient } from '@docker/extension-api-client';
33
import { Typography, Button, IconButton, Alert, DialogTitle, Dialog, DialogContent, CircularProgress, Paper, Box, SvgIcon, useTheme } from '@mui/material';
4-
import { CatalogItemWithName } from './types/catalog';
4+
import { CatalogItemRichened } from './types/catalog';
55
import { Close } from '@mui/icons-material';
66
import { CatalogGrid } from './components/CatalogGrid';
77
import { POLL_INTERVAL } from './Constants';
8-
import { CatalogProvider, useCatalogContext } from './context/CatalogContext';
9-
import { ConfigProvider } from './context/ConfigContext';
10-
import { MCPClientProvider, useMCPClientContext } from './context/MCPClientContext';
11-
import { RequiredImagesProvider, useRequiredImagesContext } from './context/RequiredImageContext';
128
import ConfigurationModal from './components/tile/Modal';
139
import LoadingState from './components/LoadingState';
10+
import { useCatalogAll } from './hooks/useCatalog';
11+
import { useRequiredImages } from './hooks/useRequiredImages';
12+
import { useMCPClient } from './hooks/useMCPClient';
13+
import { useConfig } from './hooks/useConfig';
14+
import { useSecrets } from './hooks/useSecrets';
1415

1516
export const client = createDockerDesktopClient();
1617

@@ -21,47 +22,42 @@ const DEFAULT_SETTINGS = {
2122

2223
export function App() {
2324
const [settings, setSettings] = useState<{ showModal: boolean, pollIntervalSeconds: number }>(localStorage.getItem('settings') ? JSON.parse(localStorage.getItem('settings') || '{}') : DEFAULT_SETTINGS);
24-
const [configuringItem, setConfiguringItem] = useState<CatalogItemWithName | null>(null);
25-
// Wrap the entire application with our providers
26-
return (
27-
<ConfigProvider client={client}>
28-
<RequiredImagesProvider client={client}>
29-
<CatalogProvider client={client}>
30-
<MCPClientProvider client={client}>
31-
<AppContent
32-
settings={settings}
33-
setSettings={setSettings}
34-
configuringItem={configuringItem}
35-
setConfiguringItem={setConfiguringItem}
36-
/>
37-
</MCPClientProvider>
38-
</CatalogProvider>
39-
</RequiredImagesProvider>
40-
</ConfigProvider>
41-
);
42-
}
25+
const [configuringItem, setConfiguringItem] = useState<CatalogItemRichened | null>(null);
4326

44-
interface AppContentProps {
45-
settings: { showModal: boolean, pollIntervalSeconds: number };
46-
setSettings: React.Dispatch<React.SetStateAction<{ showModal: boolean, pollIntervalSeconds: number }>>;
47-
configuringItem: CatalogItemWithName | null;
48-
setConfiguringItem: React.Dispatch<React.SetStateAction<CatalogItemWithName | null>>;
49-
}
27+
// Use hooks directly in the component
28+
const catalogAll = useCatalogAll(client);
29+
const requiredImages = useRequiredImages(client);
30+
const mcpClient = useMCPClient(client);
31+
const config = useConfig(client);
32+
const secrets = useSecrets(client);
33+
34+
// Create a context-like combined props object to pass to children
35+
const appProps = {
36+
// Catalog related props
37+
...catalogAll,
38+
39+
// Required images props
40+
...requiredImages,
41+
42+
// MCP Client props
43+
...mcpClient,
5044

51-
function AppContent({ settings, setSettings, setConfiguringItem }: AppContentProps) {
52-
const { secretsLoading, catalogLoading, registryLoading } = useCatalogContext();
53-
const { isLoading: imagesLoading } = useRequiredImagesContext();
45+
// Config props
46+
...config
47+
};
5448

55-
const isLoading = secretsLoading || catalogLoading || registryLoading || imagesLoading;
49+
const isLoading = catalogAll.catalogLoading ||
50+
catalogAll.registryLoading ||
51+
requiredImages.isLoading ||
52+
secrets.isLoading;
5653

5754
return (
5855
<>
5956
{isLoading ? (
60-
<LoadingState />
57+
<LoadingState appProps={appProps} />
6158
) : (
6259
<CatalogGrid
63-
setConfiguringItem={setConfiguringItem}
64-
showSettings={() => setSettings({ ...settings, showModal: true })}
60+
appProps={appProps}
6561
/>
6662
)}
6763
</>
File renamed without changes.

src/extension/ui/src/Registry.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { v1 } from "@docker/extension-api-client-types";
22
import { parse, stringify } from "yaml";
3-
import { readFileInPromptsVolume, writeFileToPromptsVolume } from "./FileWatcher";
3+
import { readFileInPromptsVolume, writeFileToPromptsVolume } from "./FileUtils";
44
import { mergeDeep } from "./MergeDeep";
55
import { ParsedParameters } from "./types/config";
66

src/extension/ui/src/Secrets.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// From secrets.yaml
22

33
import { v1 } from "@docker/extension-api-client-types";
4-
import { CatalogItemWithName } from "./types/catalog";
4+
import { CatalogItemRichened, CatalogItemWithName } from "./types/catalog";
55
import { Secret, StoredSecret, Policy } from "./types/secrets";
66

77
namespace Secrets {
@@ -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: 17 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
11
import React, { Suspense, useEffect, useState } from 'react';
22
import { IconButton, Alert, AlertTitle, Stack, Button, Typography, FormGroup, FormControlLabel, Dialog, DialogTitle, DialogContent, Checkbox, Badge, TextField, Tabs, Tab, CircularProgress, Box, Menu, Divider, Switch, MenuItem } from '@mui/material';
33
import { SwapVert, FolderOpenRounded } from '@mui/icons-material';
4-
import { useCatalogContext } from '../context/CatalogContext';
5-
import { useMCPClientContext } from '../context/MCPClientContext';
6-
import { useConfigContext } from '../context/ConfigContext';
74
import { createDockerDesktopClient } from '@docker/extension-api-client';
85
import { ExecResult } from '@docker/extension-api-client-types/dist/v0';
96
import YourClients from './tabs/YourClients';
10-
import { CatalogItemWithName } from '../types/catalog';
7+
import { CatalogItemRichened } from '../types/catalog';
118
import { CATALOG_LAYOUT_SX } from '../Constants';
9+
import { MCPClientState } from '../MCPClients';
1210

1311
const ToolCatalog = React.lazy(() => import('./tabs/ToolCatalog'));
14-
const YourEnvironment = React.lazy(() => import('./tabs/YourEnvironment'));
12+
const YourTools = React.lazy(() => import('./tabs/YourTools'));
1513

1614
// Initialize the Docker Desktop client
1715
const client = createDockerDesktopClient();
1816

1917
interface CatalogGridProps {
20-
showSettings: () => void;
21-
setConfiguringItem: (item: CatalogItemWithName) => void;
18+
appProps: any; // We'll use this to pass all our hook data
2219
}
2320

2421
const parseDDVersion = (ddVersion: string) => {
@@ -32,26 +29,15 @@ const parseDDVersion = (ddVersion: string) => {
3229
const NEVER_SHOW_AGAIN_KEY = 'registry-sync-never-show-again';
3330

3431
export const CatalogGrid: React.FC<CatalogGridProps> = ({
35-
setConfiguringItem,
32+
appProps,
3633
}) => {
34+
// Extract all the values we need from appProps
3735
const {
3836
catalogItems,
3937
registryItems,
40-
canRegister,
41-
registerCatalogItem,
42-
unregisterCatalogItem,
43-
tryUpdateSecrets,
44-
secrets
45-
} = useCatalogContext();
46-
47-
const {
4838
mcpClientStates,
49-
isLoading: mcpLoading
50-
} = useMCPClientContext();
51-
52-
const {
53-
config
54-
} = useConfigContext();
39+
isLoading: mcpLoading,
40+
} = appProps;
5541

5642
const [showReloadModal, setShowReloadModal] = useState<boolean>(false);
5743
const [search, setSearch] = useState<string>('');
@@ -91,27 +77,21 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
9177
}
9278

9379
const hasOutOfCatalog = catalogItems.length > 0 && Object.keys(registryItems).length > 0 && !Object.keys(registryItems).every((i) =>
94-
catalogItems.some((c) => c.name === i)
80+
catalogItems.some((c: CatalogItemRichened) => c.name === i)
9581
)
9682

97-
const sortedCatalogItems = sort !== 'date-desc' ? [...catalogItems].sort((a, b) => {
98-
if (sort === 'name-asc') {
99-
return a.name.localeCompare(b.name);
100-
}
101-
if (sort === 'name-desc') {
102-
return b.name.localeCompare(a.name);
103-
}
104-
return 0;
105-
}) : catalogItems;
106-
10783
if (!ddVersion) {
10884
return <>
10985
<CircularProgress />
11086
<Typography>Loading Docker Desktop version...</Typography>
11187
</>
11288
}
11389

114-
const noConfiguredClients = !mcpLoading && !Object.values(mcpClientStates || {}).some(state => state.exists && state.configured);
90+
// Check if there are any configured clients
91+
const noConfiguredClients = !mcpLoading && mcpClientStates ?
92+
!Object.values(mcpClientStates as Record<string, MCPClientState>).some(state =>
93+
state.exists && state.configured
94+
) : false;
11595

11696
return (
11797
<>
@@ -186,12 +166,6 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
186166
}} disableRipple>
187167
⏰ Most Recent
188168
</MenuItem>
189-
{/* <MenuItem onClick={() => setOpenMenus({ ...openMenus, 'demo-customized-menu': { anchorEl: null, open: false } })} disableRipple>
190-
️‍🔥 Trending
191-
</MenuItem>
192-
<MenuItem onClick={() => setOpenMenus({ ...openMenus, 'demo-customized-menu': { anchorEl: null, open: false } })} disableRipple>
193-
⬇️ Most Downloads
194-
</MenuItem> */}
195169
<Divider sx={{ my: 0.5 }} />
196170
<MenuItem sx={{ fontWeight: sort === 'name-asc' ? 'bold' : 'normal' }} onClick={() => {
197171
setOpenMenus({ ...openMenus, 'demo-customized-menu': { anchorEl: null, open: false } })
@@ -213,49 +187,19 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
213187
<Suspense fallback={<Box sx={{ display: 'flex', justifyContent: 'center', p: 4 }}><CircularProgress /></Box>}>
214188
{tab === 0 && (
215189
<ToolCatalog
216-
registryItems={registryItems}
217190
search={search}
218-
catalogItems={sortedCatalogItems}
219191
showMine={showMine}
220192
client={client}
221-
ddVersion={ddVersion}
222-
canRegister={canRegister}
223-
register={registerCatalogItem}
224-
unregister={unregisterCatalogItem}
225-
onSecretChange={tryUpdateSecrets}
226-
secrets={secrets}
227-
setConfiguringItem={setConfiguringItem}
228-
config={config || {}}
229-
/>
230-
)}
231-
{/* {tab === 1 && (
232-
<YourTools
233-
registryItems={registryItems}
234-
search={search}
235-
catalogItems={sortedCatalogItems}
236-
unregister={unregisterCatalogItem}
237-
onSecretChange={tryLoadSecrets}
238-
secrets={secrets}
239-
setConfiguringItem={setConfiguringItem}
240-
canRegister={canRegister}
241-
ddVersion={ddVersion}
242-
config={config || {}}
243-
/>
244-
)} */}
245-
{tab === 2 && ddVersion && (
246-
<YourEnvironment
247-
secrets={secrets}
248-
ddVersion={ddVersion}
249-
config={config || {}}
250193
/>
251194
)}
252195
{tab === 1 && (
253196
<YourClients
254-
client={client}
197+
appProps={appProps}
198+
ddVersion={ddVersion}
255199
/>
256200
)}
257201
</Suspense>
258202
</Stack>
259203
</>
260204
);
261-
};
205+
}

0 commit comments

Comments
 (0)