Skip to content

Commit

Permalink
More catalog-oriented CSS tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
ColinMcNeil committed Feb 28, 2025
1 parent efe1a16 commit 4e28003
Showing 2 changed files with 55 additions and 50 deletions.
14 changes: 7 additions & 7 deletions src/extension/ui/src/components/CatalogGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { useEffect, useState } from 'react';
import { Card, CardContent, IconButton, Alert, Stack, Button, Typography, Grid2, Select, MenuItem, FormControl, InputLabel, Switch, FormGroup, FormControlLabel, Dialog, DialogTitle, DialogContent, Checkbox, Badge, BadgeProps, Link, TextField, Tabs, Tab, Tooltip } from '@mui/material';
import { Card, CardContent, IconButton, Alert, Stack, Button, Typography, Grid2, Select, MenuItem, FormControl, InputLabel, Switch, FormGroup, FormControlLabel, Dialog, DialogTitle, DialogContent, Checkbox, Badge, BadgeProps, Link, TextField, Tabs, Tab, Tooltip, InputAdornment } from '@mui/material';
import { CatalogItemWithName, CatalogItemCard, CatalogItem } from './PromptCard';
import AddIcon from '@mui/icons-material/Add';
import { Ref } from '../Refs';
import { v1 } from "@docker/extension-api-client-types";
import { parse, stringify } from 'yaml';
import { getRegistry } from '../Registry';
import { FolderOpenRounded, Settings } from '@mui/icons-material';
import { FolderOpenRounded, Search, Settings } from '@mui/icons-material';
import { tryRunImageSync } from '../FileWatcher';
import { CATALOG_URL, POLL_INTERVAL } from '../Constants';

@@ -143,10 +143,10 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
<Typography sx={{ width: '100%' }}>You have some prompts registered which are not available in the catalog.</Typography>
</Alert>}
<Tabs value={tab} onChange={(e, v) => setTab(v)} sx={{ mb: 0, mt: 1 }}>
<Tooltip title="These are all of the prompts you have available across the catalog.">
<Tooltip title="These are all of the tiles you have available across the catalog.">
<Tab sx={{ fontSize: '1.5em' }} label="Available" />
</Tooltip>
<Tooltip title="These are prompts which you have allowed MCP clients to use.">
<Tooltip title="These are tiles which you have allowed MCP clients to use.">
<Tab sx={{ fontSize: '1.5em' }} label="Allowed" />
</Tooltip>
</Tabs>
@@ -167,7 +167,7 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
</Stack>
</FormGroup >

{tab === 0 && <Grid2 container spacing={2} width='100%' maxWidth={1000}>
{tab === 0 && <Grid2 container spacing={1} width='90vw' maxWidth={1000}>
{filteredCatalogItems.map((item) => (
<Grid2 size={{ xs: 12, sm: 6, md: 4 }} key={item.name}>
<CatalogItemCard
@@ -194,9 +194,9 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
</Card>
</Grid2>
</Grid2>}
{tab === 1 && <Grid2 container spacing={2} width='100%' maxWidth={1000}>
{tab === 1 && <Grid2 container spacing={1} width='90vw' maxWidth={1000}>
{Object.entries(registryItems).map(([name, item]) => (
<Grid2 size={{ xs: 12, sm: 6, md: 4 }} key={name}>
name.toLowerCase().includes(search.toLowerCase()) && <Grid2 size={{ xs: 12, sm: 6, md: 4 }} key={name}>
<CatalogItemCard item={catalogItems.find((i) => i.name === name)!} openUrl={() => {
client.host.openExternal(Ref.fromRef(item.ref).toURL(true));
}} canRegister={canRegister} registered={true} register={registerCatalogItem} unregister={unregisterCatalogItem} />
91 changes: 48 additions & 43 deletions src/extension/ui/src/components/PromptCard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Badge, CircularProgress, Stack, Tooltip } from "@mui/material";
import { Badge, CircularProgress, Stack, Switch, Tooltip } from "@mui/material";
import Button from '@mui/material/Button';
import { Card, CardActions, CardContent, CardMedia, Typography } from "@mui/material";
import { Ref } from "../Refs";
import { useState } from "react";
import { trackEvent } from "../Usage";
import { Article, AttachFile, Build, LockRounded } from "@mui/icons-material";

const iconSize = 16

export interface CatalogItem {
description?: string;
icon?: string;
@@ -23,42 +25,45 @@ export interface CatalogItemWithName extends CatalogItem {
export function CatalogItemCard({ openUrl, item, canRegister, registered, register, unregister }: { openUrl: () => void, item: CatalogItemWithName, canRegister: boolean, registered: boolean, register: (item: CatalogItemWithName) => Promise<void>, unregister: (item: CatalogItemWithName) => Promise<void> }) {
const [isRegistering, setIsRegistering] = useState(false)
return (
<Card sx={(theme) => ({ height: '100%', borderColor: registered ? theme.palette.docker.grey[600] : theme.palette.docker.grey[400], borderWidth: registered ? 2 : 1 })} variant="outlined" >
<Card sx={(theme) => ({ height: 150, borderColor: registered ? theme.palette.docker.grey[600] : theme.palette.docker.grey[300], borderWidth: registered ? 1 : 0.5 })} variant="outlined" >
<Stack direction="column" height="100%" sx={{ justifyContent: 'space-between' }}>
<CardContent>
<a href="">
<Stack onClick={openUrl} direction="row" spacing={2} justifyContent="space-between" sx={{ cursor: 'pointer' }}>
<Typography gutterBottom variant="h5" component="div" sx={{ fontWeight: 'bold', textTransform: 'capitalize' }}>
<CardContent sx={{ p: 2, paddingBottom: 1, '&:hover .hover-underline': { textDecoration: 'underline' } }}>
<Stack onClick={openUrl} direction="row" spacing={1} justifyContent="space-between" sx={{ cursor: 'pointer' }}>
<Stack direction="column" spacing={1} >
<Typography className="hover-underline" gutterBottom component="div" sx={{ fontWeight: 'bold', textTransform: 'capitalize', fontSize: '1.2em' }}>
{item.name.replace('_', ' ')}
</Typography>
<CardMedia
component="img"
sx={{ width: 50, height: 50, padding: 1, background: 'white', borderRadius: 1 }}
alt={`Icon for ${item.name}`}
image={item.icon}
/>
<Tooltip title={item.description}>
<Typography variant="body2" sx={{ mt: 0.5 }}>
{item.description?.slice(0, 70)}...
</Typography>
</Tooltip>

</Stack>
</a>
<Typography variant="body2" sx={{ mt: 0.5 }}>
{item.description}
</Typography>
<CardMedia
component="img"
sx={{ width: 50, height: 50, padding: 1, background: 'white', borderRadius: 1, boxSizing: 'border-box', mt: -1 }}
alt={`Icon for ${item.name}`}
image={item.icon}
/>
</Stack>
</CardContent>
<CardActions sx={{ pt: 0 }}>
<CardActions sx={{ padding: 2, paddingTop: 0 }}>
<Stack direction="row" spacing={2} sx={{ alignItems: 'center', justifyContent: 'space-between', width: '100%' }}>
<Stack direction="row" spacing={2}>
<Stack direction="row" spacing={2} >
<Tooltip title="Prompts">
<Badge badgeContent={item.prompts || "0"} color="primary">
<Article />
<Article sx={{ fontSize: iconSize }} />
</Badge>
</Tooltip>
<Tooltip title="Resources">
<Badge badgeContent={item.resources?.length || "0"} color="secondary">
<AttachFile />
<AttachFile sx={{ fontSize: iconSize }} />
</Badge>
</Tooltip>
<Tooltip title="Tools">
<Badge badgeContent={item.tools?.length || "0"} color="success">
<Build />
<Build sx={{ fontSize: iconSize }} />
</Badge>
</Tooltip>
{item.secrets?.length && (
@@ -69,32 +74,32 @@ export function CatalogItemCard({ openUrl, item, canRegister, registered, regist
))}
</Stack>}>
<Badge badgeContent={item.secrets?.length || "0"} color="warning">
<LockRounded />
<LockRounded sx={{ fontSize: iconSize }} />
</Badge>
</Tooltip>
)}
</Stack>
<Button
size="small"
color={registered ? 'error' : 'primary'}
variant={registered ? 'outlined' : 'contained'}
onClick={() => {
trackEvent('registry-changed', { name: item.name, ref: item.ref, action: registered ? 'remove' : 'add' });
setIsRegistering(true)
if (registered) {
unregister(item).then(() => {
setIsRegistering(false)
})
} else {
register(item).then(() => {
setIsRegistering(false)
})
}
}}
disabled={!canRegister || isRegistering}
>
{isRegistering ? <CircularProgress size={20} /> : registered ? 'Block' : 'Allow'}
</Button>
<Tooltip title={registered ? "Blocking this tile will remove its tools, resources and prompts from being used in any MCP clients you have connected." : "Allowing this tile will expose its tools, resources and prompts to any MCP clients you have connected."}>
{isRegistering ? <CircularProgress size={20} /> : <Switch
size="small"
color={registered ? 'success' : 'primary'}
checked={registered}
onChange={(event, checked) => {
trackEvent('registry-changed', { name: item.name, ref: item.ref, action: registered ? 'remove' : 'add' });
setIsRegistering(true)
if (registered) {
unregister(item).then(() => {
setIsRegistering(false)
})
} else {
register(item).then(() => {
setIsRegistering(false)
})
}
}}
disabled={!canRegister || isRegistering}
/>}
</Tooltip>
</Stack>

</CardActions>

0 comments on commit 4e28003

Please sign in to comment.