11import React , { useEffect , useState } from 'react' ;
2- 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' ;
2+ 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 , CircularProgress } from '@mui/material' ;
33import { CatalogItemWithName , CatalogItemCard , CatalogItem } from './PromptCard' ;
44import AddIcon from '@mui/icons-material/Add' ;
55import { Ref } from '../Refs' ;
@@ -8,7 +8,7 @@ import { parse, stringify } from 'yaml';
88import { getRegistry } from '../Registry' ;
99import { FolderOpenRounded , Search , Settings } from '@mui/icons-material' ;
1010import { tryRunImageSync } from '../FileWatcher' ;
11- import { CATALOG_URL , MCP_POLICY_NAME , POLL_INTERVAL } from '../Constants' ;
11+ import { CATALOG_URL , DD_BUILD_WITH_SECRET_SUPPORT , MCP_POLICY_NAME , POLL_INTERVAL } from '../Constants' ;
1212import { SecretList } from './SecretList' ;
1313import Secrets from '../Secrets' ;
1414
@@ -21,9 +21,17 @@ interface CatalogGridProps {
2121 settingsBadgeProps : BadgeProps ;
2222}
2323
24- const filterCatalog = ( catalogItems : CatalogItemWithName [ ] , registryItems : { [ key : string ] : { ref : string } } , showRegistered : boolean , showUnregistered : boolean , search : string ) =>
25- catalogItems . filter ( ( item ) => ( showRegistered || ! Object . keys ( registryItems ) . includes ( item . name ) ) && ( showUnregistered || Object . keys ( registryItems ) . includes ( item . name ) ) && ( item . name . toLowerCase ( ) . includes ( search . toLowerCase ( ) ) ) ) ;
24+ const filterCatalog = ( catalogItems : CatalogItemWithName [ ] , registryItems : { [ key : string ] : { ref : string } } , search : string ) =>
25+ catalogItems . filter ( ( item ) => item . name . toLowerCase ( ) . includes ( search . toLowerCase ( ) ) ) ;
2626
27+ const parseDDVersion = ( ddVersion : string ) => {
28+ //eg: Docker Desktop 4.40.0 (184396)
29+ const [ , , version , build ] = ddVersion . split ( ' ' ) ;
30+ return {
31+ version,
32+ build : parseInt ( build . replace ( '(' , '' ) . replace ( ')' , '' ) )
33+ }
34+ }
2735const NEVER_SHOW_AGAIN_KEY = 'registry-sync-never-show-again' ;
2836
2937export const CatalogGrid : React . FC < CatalogGridProps > = ( {
@@ -35,14 +43,13 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
3543 settingsBadgeProps
3644} ) => {
3745 const [ catalogItems , setCatalogItems ] = useState < CatalogItemWithName [ ] > ( [ ] ) ;
38- const [ showRegistered , setShowRegistered ] = useState < boolean > ( true ) ;
39- const [ showUnregistered , setShowUnregistered ] = useState < boolean > ( true ) ;
4046 const [ showReloadModal , setShowReloadModal ] = useState < boolean > ( false ) ;
4147 const [ search , setSearch ] = useState < string > ( '' ) ;
4248 const [ tab , setTab ] = useState < number > ( 0 ) ;
4349 const [ secrets , setSecrets ] = useState < Secrets . Secret [ ] > ( [ ] ) ;
50+ const [ ddVersion , setDdVersion ] = useState < { version : string , build : number } | null > ( null ) ;
4451
45- const filteredCatalogItems = filterCatalog ( catalogItems , registryItems , showRegistered , showUnregistered , search ) ;
52+ const filteredCatalogItems = filterCatalog ( catalogItems , registryItems , search ) ;
4653
4754 const loadCatalog = async ( showNotification = true ) => {
4855 const cachedCatalog = localStorage . getItem ( 'catalog' ) ;
@@ -51,7 +58,7 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
5158 const catalog = await response . text ( ) ;
5259 const items = parse ( catalog ) [ 'registry' ] as { [ key : string ] : CatalogItem }
5360 const itemsWithName = Object . entries ( items ) . map ( ( [ name , item ] ) => ( { name, ...item } ) ) ;
54- const filteredItems = filterCatalog ( itemsWithName , registryItems , showRegistered , showUnregistered , search ) ;
61+ const filteredItems = filterCatalog ( itemsWithName , registryItems , search ) ;
5562 setCatalogItems ( filteredItems ) ;
5663 localStorage . setItem ( 'catalog' , JSON . stringify ( filteredItems ) ) ;
5764 if ( showNotification ) {
@@ -73,7 +80,12 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
7380 setSecrets ( response || [ ] ) ;
7481 }
7582
76- const registerCatalogItem = async ( item : CatalogItemWithName ) => {
83+ const loadDDVersion = async ( ) => {
84+ const ddVersionResult = await client . docker . cli . exec ( 'version' , [ '--format' , 'json' ] )
85+ setDdVersion ( parseDDVersion ( JSON . parse ( ddVersionResult . stdout ) . Server . Platform . Name ) ) ;
86+ }
87+
88+ const registerCatalogItem = async ( item : CatalogItemWithName , showNotification = true ) => {
7789 try {
7890 const currentRegistry = await getRegistry ( client ) ;
7991 const newRegistry = { ...currentRegistry , [ item . name ] : { ref : item . ref } } ;
@@ -84,12 +96,18 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
8496 } ]
8597 } )
8698 await tryRunImageSync ( client , [ '--rm' , '-v' , 'docker-prompts:/docker-prompts' , '--workdir' , '/docker-prompts' , 'vonwig/function_write_files:latest' , `'${ payload } '` ] )
87- client . desktopUI . toast . success ( 'Prompt registered successfully. Restart Claude Desktop to apply.' ) ;
99+ if ( showNotification ) {
100+ client . desktopUI . toast . success ( 'Prompt registered successfully. Restart Claude Desktop to apply.' ) ;
101+ }
88102 onRegistryChange ( ) ;
89- setShowReloadModal ( ! localStorage . getItem ( NEVER_SHOW_AGAIN_KEY ) ) ;
103+ if ( showNotification ) {
104+ setShowReloadModal ( ! localStorage . getItem ( NEVER_SHOW_AGAIN_KEY ) ) ;
105+ }
90106 }
91107 catch ( error ) {
92- client . desktopUI . toast . error ( 'Failed to register prompt: ' + error ) ;
108+ if ( showNotification ) {
109+ client . desktopUI . toast . error ( 'Failed to register prompt: ' + error ) ;
110+ }
93111 }
94112 }
95113
@@ -116,6 +134,7 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
116134 useEffect ( ( ) => {
117135 loadCatalog ( false ) ;
118136 loadSecrets ( ) ;
137+ loadDDVersion ( ) ;
119138 const interval = setInterval ( ( ) => {
120139 loadCatalog ( false ) ;
121140 loadSecrets ( ) ;
@@ -129,6 +148,10 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
129148 catalogItems . some ( ( c ) => c . name === i )
130149 )
131150
151+ if ( ! ddVersion ) {
152+ return < CircularProgress />
153+ }
154+
132155
133156 return (
134157 < Stack spacing = { 2 } justifyContent = 'center' alignItems = 'center' >
@@ -188,6 +211,7 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
188211 client . host . openExternal ( Ref . fromRef ( item . ref ) . toURL ( true ) ) ;
189212 } }
190213 item = { item }
214+ ddVersion = { ddVersion }
191215 canRegister = { canRegister }
192216 registered = { Object . keys ( registryItems ) . some ( ( i ) => i === item . name ) }
193217 register = { registerCatalogItem }
@@ -215,7 +239,7 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
215239 { tab === 1 && < Grid2 container spacing = { 1 } width = '90vw' maxWidth = { 1000 } >
216240 { Object . entries ( registryItems ) . map ( ( [ name , item ] ) => (
217241 name . toLowerCase ( ) . includes ( search . toLowerCase ( ) ) && < Grid2 size = { { xs : 12 , sm : 6 , md : 4 } } key = { name } >
218- < CatalogItemCard item = { catalogItems . find ( ( i ) => i . name === name ) ! } openUrl = { ( ) => {
242+ < CatalogItemCard ddVersion = { ddVersion } item = { catalogItems . find ( ( i ) => i . name === name ) ! } openUrl = { ( ) => {
219243 client . host . openExternal ( Ref . fromRef ( item . ref ) . toURL ( true ) ) ;
220244 } } canRegister = { canRegister } registered = { true } register = { registerCatalogItem } unregister = { unregisterCatalogItem } onSecretChange = { async ( secret ) => {
221245 await Secrets . addSecret ( client , { name : secret . name , value : secret . value , policies : [ MCP_POLICY_NAME ] } )
@@ -224,7 +248,7 @@ export const CatalogGrid: React.FC<CatalogGridProps> = ({
224248 </ Grid2 >
225249 ) ) }
226250 </ Grid2 > }
227- { tab === 2 && < SecretList secrets = { secrets } /> }
251+ { tab === 2 && ddVersion && < SecretList secrets = { secrets } ddVersion = { ddVersion } /> }
228252 </ Stack >
229253 ) ;
230254} ;
0 commit comments