11import React , { useEffect , useState } from 'react' ;
22import AddIcon from '@mui/icons-material/Add' ;
33import { createDockerDesktopClient } from '@docker/extension-api-client' ;
4- import { Stack , Typography , Button , ButtonGroup , Grid , debounce , Card , CardContent , IconButton , Alert } from '@mui/material' ;
4+ import { Stack , Typography , Button , ButtonGroup , Grid , debounce , Card , CardContent , IconButton , Alert , DialogTitle , Dialog , DialogContent , FormControlLabel , Checkbox } from '@mui/material' ;
55import { CatalogItem , CatalogItemCard , CatalogItemWithName } from './components/PromptCard' ;
66import { parse , stringify } from 'yaml' ;
77import { Ref } from './Refs' ;
88import { RegistrySyncStatus } from './components/RegistrySyncStatus' ;
99import { getRegistry } from './Registry' ;
10- import { ClaudeConfigSyncStatus } from './components/ClaudeConfigSyncStatus' ;
11- import { FolderOpen , FolderOpenOutlined , FolderOpenRounded , VolumeUp } from '@mui/icons-material' ;
10+ import { ClaudeConfigSyncStatus , setNeverShowAgain } from './components/ClaudeConfigSyncStatus' ;
11+ import { FolderOpenRounded , } from '@mui/icons-material' ;
12+
13+ const NEVER_SHOW_AGAIN_KEY = 'registry-sync-never-show-again' ;
1214
1315type RegistryItem = {
1416 ref : string ;
@@ -24,25 +26,16 @@ export function App() {
2426 const [ catalogItems , setCatalogItems ] = useState < CatalogItemWithName [ ] > ( [ ] ) ;
2527 const [ canRegister , setCanRegister ] = useState ( false ) ;
2628 const [ registryItems , setRegistryItems ] = useState < { [ key : string ] : { ref : string } } > ( { } ) ;
27- const [ status , setStatus ] = useState < {
28- status : 'idle' | 'loading' | 'error' ,
29- message : string
30- } > ( {
31- status : 'idle' ,
32- message : ''
33- } ) ;
34-
29+ const [ showReloadModal , setShowReloadModal ] = useState ( false ) ;
3530 const [ hasConfig , setHasConfig ] = useState ( false ) ;
3631
3732 const loadCatalog = async ( ) => {
38- setStatus ( { status : 'loading' , message : 'Grabbing latest prompt catalog...' } ) ;
3933 try {
4034 const response = await fetch ( CATALOG_URL ) ;
4135 const catalog = await response . text ( ) ;
4236 const items = parse ( catalog ) [ 'registry' ] as { [ key : string ] : CatalogItem }
4337 const itemsWithName = Object . entries ( items ) . map ( ( [ name , item ] ) => ( { name, ...item } ) ) ;
4438 setCatalogItems ( itemsWithName ) ;
45- setStatus ( { status : 'idle' , message : '' } ) ;
4639 }
4740 catch ( error ) {
4841 client . desktopUI . toast . error ( 'Failed to get latest catalog: ' + error ) ;
@@ -52,11 +45,9 @@ export function App() {
5245 const loadRegistry = async ( ) => {
5346 setRegistryLoaded ( false ) ;
5447 setCanRegister ( false ) ;
55- setStatus ( { status : 'loading' , message : 'Grabbing prompt registry...' } ) ;
5648 try {
5749 const result = await getRegistry ( client )
5850 setRegistryItems ( result || { } ) ;
59- setStatus ( { status : 'idle' , message : '' } ) ;
6051 setRegistryLoaded ( true ) ;
6152
6253 }
@@ -83,6 +74,7 @@ export function App() {
8374 await client . docker . cli . exec ( 'run' , [ '--rm' , '-v' , 'docker-prompts:/docker-prompts' , '--workdir' , '/docker-prompts' , 'vonwig/function_write_files:latest' , `'${ payload } '` ] )
8475 client . desktopUI . toast . success ( 'Prompt registered successfully. Restart Claude Desktop to apply.' ) ;
8576 await loadRegistry ( ) ;
77+ setShowReloadModal ( ! localStorage . getItem ( NEVER_SHOW_AGAIN_KEY ) ) ;
8678 }
8779 catch ( error ) {
8880 client . desktopUI . toast . error ( 'Failed to register prompt: ' + error ) ;
@@ -102,10 +94,12 @@ export function App() {
10294 await client . docker . cli . exec ( 'run' , [ '--rm' , '-v' , 'docker-prompts:/docker-prompts' , '--workdir' , '/docker-prompts' , 'vonwig/function_write_files:latest' , `'${ payload } '` ] )
10395 client . desktopUI . toast . success ( 'Prompt unregistered successfully. Restart Claude Desktop to apply.' ) ;
10496 await loadRegistry ( ) ;
97+ setShowReloadModal ( ! localStorage . getItem ( NEVER_SHOW_AGAIN_KEY ) ) ;
10598 }
10699 catch ( error ) {
107100 client . desktopUI . toast . error ( 'Failed to unregister prompt: ' + error )
108101 }
102+
109103 }
110104
111105 useEffect ( ( ) => {
@@ -126,8 +120,25 @@ export function App() {
126120
127121 return (
128122 < div >
123+ < Dialog open = { showReloadModal } onClose = { ( ) => setShowReloadModal ( false ) } >
124+ < DialogTitle > Registry Updated</ DialogTitle >
125+ < DialogContent >
126+ < Typography sx = { { marginBottom : 2 } } >
127+ You have updated the registry.
128+ Use the keybind { client . host . platform === 'win32' ? 'Ctrl' : '⌘' } + R to refresh MCP servers in Claude Desktop.
129+ </ Typography >
130+ < Stack direction = "row" justifyContent = "space-between" >
131+ < Button onClick = { ( ) => {
132+ setShowReloadModal ( false )
133+ } } > Close</ Button >
134+ < FormControlLabel control = { < Checkbox defaultChecked = { Boolean ( localStorage . getItem ( NEVER_SHOW_AGAIN_KEY ) ) } onChange = { ( e ) => localStorage . setItem ( NEVER_SHOW_AGAIN_KEY , e . target . checked . toString ( ) ) } /> } label = "Don't show this again" />
135+ </ Stack >
136+ </ DialogContent >
137+ </ Dialog >
138+
129139 < Stack direction = "column" spacing = { 1 } >
130140 < div >
141+
131142 < ButtonGroup >
132143 < Button onClick = { loadCatalog } > Refresh catalog</ Button >
133144 < Button onClick = { loadRegistry } > Refresh registry</ Button >
0 commit comments