1
1
import React , { useEffect , useState } from 'react' ;
2
2
import AddIcon from '@mui/icons-material/Add' ;
3
3
import { 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' ;
5
5
import { CatalogItem , CatalogItemCard , CatalogItemWithName } from './components/PromptCard' ;
6
6
import { parse , stringify } from 'yaml' ;
7
7
import { Ref } from './Refs' ;
8
8
import { RegistrySyncStatus } from './components/RegistrySyncStatus' ;
9
9
import { 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' ;
12
14
13
15
type RegistryItem = {
14
16
ref : string ;
@@ -24,25 +26,16 @@ export function App() {
24
26
const [ catalogItems , setCatalogItems ] = useState < CatalogItemWithName [ ] > ( [ ] ) ;
25
27
const [ canRegister , setCanRegister ] = useState ( false ) ;
26
28
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 ) ;
35
30
const [ hasConfig , setHasConfig ] = useState ( false ) ;
36
31
37
32
const loadCatalog = async ( ) => {
38
- setStatus ( { status : 'loading' , message : 'Grabbing latest prompt catalog...' } ) ;
39
33
try {
40
34
const response = await fetch ( CATALOG_URL ) ;
41
35
const catalog = await response . text ( ) ;
42
36
const items = parse ( catalog ) [ 'registry' ] as { [ key : string ] : CatalogItem }
43
37
const itemsWithName = Object . entries ( items ) . map ( ( [ name , item ] ) => ( { name, ...item } ) ) ;
44
38
setCatalogItems ( itemsWithName ) ;
45
- setStatus ( { status : 'idle' , message : '' } ) ;
46
39
}
47
40
catch ( error ) {
48
41
client . desktopUI . toast . error ( 'Failed to get latest catalog: ' + error ) ;
@@ -52,11 +45,9 @@ export function App() {
52
45
const loadRegistry = async ( ) => {
53
46
setRegistryLoaded ( false ) ;
54
47
setCanRegister ( false ) ;
55
- setStatus ( { status : 'loading' , message : 'Grabbing prompt registry...' } ) ;
56
48
try {
57
49
const result = await getRegistry ( client )
58
50
setRegistryItems ( result || { } ) ;
59
- setStatus ( { status : 'idle' , message : '' } ) ;
60
51
setRegistryLoaded ( true ) ;
61
52
62
53
}
@@ -83,6 +74,7 @@ export function App() {
83
74
await client . docker . cli . exec ( 'run' , [ '--rm' , '-v' , 'docker-prompts:/docker-prompts' , '--workdir' , '/docker-prompts' , 'vonwig/function_write_files:latest' , `'${ payload } '` ] )
84
75
client . desktopUI . toast . success ( 'Prompt registered successfully. Restart Claude Desktop to apply.' ) ;
85
76
await loadRegistry ( ) ;
77
+ setShowReloadModal ( ! localStorage . getItem ( NEVER_SHOW_AGAIN_KEY ) ) ;
86
78
}
87
79
catch ( error ) {
88
80
client . desktopUI . toast . error ( 'Failed to register prompt: ' + error ) ;
@@ -102,10 +94,12 @@ export function App() {
102
94
await client . docker . cli . exec ( 'run' , [ '--rm' , '-v' , 'docker-prompts:/docker-prompts' , '--workdir' , '/docker-prompts' , 'vonwig/function_write_files:latest' , `'${ payload } '` ] )
103
95
client . desktopUI . toast . success ( 'Prompt unregistered successfully. Restart Claude Desktop to apply.' ) ;
104
96
await loadRegistry ( ) ;
97
+ setShowReloadModal ( ! localStorage . getItem ( NEVER_SHOW_AGAIN_KEY ) ) ;
105
98
}
106
99
catch ( error ) {
107
100
client . desktopUI . toast . error ( 'Failed to unregister prompt: ' + error )
108
101
}
102
+
109
103
}
110
104
111
105
useEffect ( ( ) => {
@@ -126,8 +120,25 @@ export function App() {
126
120
127
121
return (
128
122
< 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
+
129
139
< Stack direction = "column" spacing = { 1 } >
130
140
< div >
141
+
131
142
< ButtonGroup >
132
143
< Button onClick = { loadCatalog } > Refresh catalog</ Button >
133
144
< Button onClick = { loadRegistry } > Refresh registry</ Button >
0 commit comments