Skip to content

Commit cf30bb0

Browse files
author
colinmcneil
committed
Light UI polish
1 parent d687a16 commit cf30bb0

File tree

3 files changed

+37
-15
lines changed

3 files changed

+37
-15
lines changed

src/extension/ui/src/Secrets.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ namespace Secrets {
2828

2929
export async function addSecret(client: v1.DockerDesktopClient, secret: Secret): Promise<void> {
3030
try {
31-
await client.extension.host?.cli.exec('host-binary', ['--name', secret.name, '--value', secret.value]);
31+
const response = await client.extension.host?.cli.exec('host-binary', ['--name', secret.name, '--value', secret.value]);
32+
console.log('Response', response)
3233
client.desktopUI.toast.success('Secret set successfully')
3334
} catch (error) {
3435
client.desktopUI.toast.error('Failed to set secret: ' + error)

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

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,26 @@ const filterCatalog = (catalogItems: CatalogItemWithName[], registryItems: { [ke
2626

2727
const NEVER_SHOW_AGAIN_KEY = 'registry-sync-never-show-again';
2828

29-
const debounce = (func: (...args: any[]) => void, delay: number) => {
30-
let timeout: NodeJS.Timeout;
31-
return (...args: any[]) => {
32-
clearTimeout(timeout);
33-
timeout = setTimeout(() => func(...args), delay);
29+
const debounce = (inner: (...args: any[]) => Promise<void>, ms = 0) => {
30+
let timer: NodeJS.Timeout | null = null;
31+
let resolves: ((value: void | PromiseLike<void>) => void)[] = [];
32+
33+
return function (...args: any[]) {
34+
// Run the function after a certain amount of time
35+
if (timer) {
36+
clearTimeout(timer);
37+
}
38+
timer = setTimeout(() => {
39+
// Get the result of the inner function, then apply it to the resolve function of
40+
// each promise that has been created since the last time the inner function was run
41+
let result = inner(...args);
42+
resolves.forEach(r => r(result));
43+
resolves = [];
44+
}, ms);
45+
46+
return new Promise(r => resolves.push(r));
3447
};
3548
}
36-
3749
export const CatalogGrid: React.FC<CatalogGridProps> = ({
3850
registryItems,
3951
canRegister,
@@ -81,8 +93,8 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
8193
setSecrets(response || []);
8294
}
8395

84-
const debouncedAddSecret = debounce((client: v1.DockerDesktopClient, name: string, value: string) => {
85-
Secrets.addSecret(client, { name, value, policies: [MCP_POLICY_NAME] })
96+
const debouncedAddSecret = debounce(async (client: v1.DockerDesktopClient, name: string, value: string) => {
97+
await Secrets.addSecret(client, { name, value, policies: [MCP_POLICY_NAME] })
8698
loadSecrets();
8799
}, 1000);
88100

@@ -205,8 +217,8 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
205217
registered={Object.keys(registryItems).some((i) => i === item.name)}
206218
register={registerCatalogItem}
207219
unregister={unregisterCatalogItem}
208-
onSecretChange={(secret) => {
209-
debouncedAddSecret(client, secret.name, secret.value);
220+
onSecretChange={async (secret) => {
221+
await debouncedAddSecret(client, secret.name, secret.value);
210222
}}
211223
secrets={secrets}
212224
/>
@@ -229,7 +241,7 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
229241
name.toLowerCase().includes(search.toLowerCase()) && <Grid2 size={{ xs: 12, sm: 6, md: 4 }} key={name}>
230242
<CatalogItemCard item={catalogItems.find((i) => i.name === name)!} openUrl={() => {
231243
client.host.openExternal(Ref.fromRef(item.ref).toURL(true));
232-
}} canRegister={canRegister} registered={true} register={registerCatalogItem} unregister={unregisterCatalogItem} onSecretChange={(secret) => {
244+
}} canRegister={canRegister} registered={true} register={registerCatalogItem} unregister={unregisterCatalogItem} onSecretChange={async (secret) => {
233245
debouncedAddSecret(client, secret.name, secret.value);
234246
}} secrets={secrets} />
235247
</Grid2>

src/extension/ui/src/components/PromptCard.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export interface CatalogItemWithName extends CatalogItem {
2323
name: string;
2424
}
2525

26-
export function CatalogItemCard({ openUrl, item, canRegister, registered, register, unregister, onSecretChange, secrets }: { openUrl: () => void, item: CatalogItemWithName, canRegister: boolean, registered: boolean, register: (item: CatalogItemWithName) => Promise<void>, unregister: (item: CatalogItemWithName) => Promise<void>, onSecretChange: (secret: { name: string, value: string }) => void, secrets: Secrets.Secret[] }) {
26+
export function CatalogItemCard({ openUrl, item, canRegister, registered, register, unregister, onSecretChange, secrets }: { openUrl: () => void, item: CatalogItemWithName, canRegister: boolean, registered: boolean, register: (item: CatalogItemWithName) => Promise<void>, unregister: (item: CatalogItemWithName) => Promise<void>, onSecretChange: (secret: { name: string, value: string }) => Promise<void>, secrets: Secrets.Secret[] }) {
2727
const loadAssignedSecrets = () => {
2828
const assignedSecrets = Secrets.getAssignedSecrets(item, secrets);
2929
setAssignedSecrets(assignedSecrets)
@@ -32,6 +32,7 @@ export function CatalogItemCard({ openUrl, item, canRegister, registered, regist
3232
const [showSecretDialog, setShowSecretDialog] = useState(false)
3333
const [assignedSecrets, setAssignedSecrets] = useState<{ name: string, assigned: boolean }[]>([])
3434
const [changedSecrets, setChangedSecrets] = useState<{ [key: string]: string | undefined }>({})
35+
const [secretLoading, setSecretLoading] = useState(false)
3536

3637
useEffect(() => {
3738
loadAssignedSecrets()
@@ -53,8 +54,16 @@ export function CatalogItemCard({ openUrl, item, canRegister, registered, regist
5354
{assignedSecrets.find(s => s.name === secret.name)?.assigned && changedSecrets[secret.name] && <IconButton onClick={() => setChangedSecrets({ ...changedSecrets, [secret.name]: undefined })}>
5455
<LockReset />
5556
</IconButton>}
56-
{changedSecrets[secret.name] && <IconButton onClick={() => onSecretChange({ name: secret.name, value: changedSecrets[secret.name] || '' })}>
57-
<Save />
57+
{changedSecrets[secret.name] && <IconButton onClick={() => {
58+
setSecretLoading(true)
59+
onSecretChange({ name: secret.name, value: changedSecrets[secret.name] || '' }).then(() => {
60+
setSecretLoading(false)
61+
const newChangedSecrets = { ...changedSecrets }
62+
delete newChangedSecrets[secret.name]
63+
setChangedSecrets(newChangedSecrets)
64+
})
65+
}}>
66+
{secretLoading ? <CircularProgress size={20} /> : <Save />}
5867
</IconButton>}
5968
</Stack>
6069
))}

0 commit comments

Comments
 (0)