1
- import { CircularProgress , Dialog , DialogContent , DialogTitle , Divider , IconButton , Stack , TextField , Typography } from "@mui/material" ;
2
- import { Card , CardContent } from "@mui/material" ;
3
- import { useEffect , useState } from "react" ;
4
- import { CatalogItemRichened } from "../../types/catalog" ;
5
- import { Save , LockReset } from "@mui/icons-material" ;
6
- import ConfigurationModal from "./Modal" ;
7
- import Top from "./Top" ;
8
- import Center from "./Center" ;
9
- import Bottom from "./Bottom" ;
10
- import { v1 } from "@docker/extension-api-client-types" ;
11
- import { useSecrets } from "../../queries/useSecrets" ;
12
- import { useCatalogAll , useCatalogOperations } from "../../queries/useCatalog" ;
13
- import { MCP_POLICY_NAME } from "../../Constants" ;
1
+ import { v1 } from '@docker/extension-api-client-types' ;
2
+ import { LockReset , Save } from '@mui/icons-material' ;
3
+ import {
4
+ Card ,
5
+ CardActionArea ,
6
+ CardContent ,
7
+ CircularProgress ,
8
+ Dialog ,
9
+ DialogContent ,
10
+ DialogTitle ,
11
+ Divider ,
12
+ IconButton ,
13
+ Stack ,
14
+ TextField ,
15
+ Typography ,
16
+ } from '@mui/material' ;
17
+ import { useState } from 'react' ;
18
+
19
+ import { MCP_POLICY_NAME } from '../../Constants' ;
20
+ import { useCatalogAll , useCatalogOperations } from '../../queries/useCatalog' ;
21
+ import { useSecrets } from '../../queries/useSecrets' ;
22
+ import { CatalogItemRichened } from '../../types/catalog' ;
23
+ import Bottom from './Bottom' ;
24
+ import Center from './Center' ;
25
+ import ConfigurationModal from './Modal' ;
26
+ import Top from './Top' ;
14
27
15
28
type TileProps = {
16
- item : CatalogItemRichened ;
17
- client : v1 . DockerDesktopClient ;
18
- }
29
+ item : CatalogItemRichened ;
30
+ client : v1 . DockerDesktopClient ;
31
+ } ;
19
32
20
33
const Tile = ( { item, client } : TileProps ) => {
34
+ const [ showSecretDialog , setShowSecretDialog ] = useState ( false ) ;
35
+ const [ assignedSecrets ] = useState < { name : string ; assigned : boolean } [ ] > ( [ ] ) ;
36
+ const [ changedSecrets , setChangedSecrets ] = useState < {
37
+ [ key : string ] : string | undefined ;
38
+ } > ( { } ) ;
39
+ const [ secretLoading , setSecretLoading ] = useState ( false ) ;
40
+ const [ showConfigModal , setShowConfigModal ] = useState ( false ) ;
41
+ const { isLoading : secretsLoading , mutate : mutateSecret } =
42
+ useSecrets ( client ) ;
43
+ const { registerCatalogItem, unregisterCatalogItem } =
44
+ useCatalogOperations ( client ) ;
45
+ const { registryLoading } = useCatalogAll ( client ) ;
21
46
22
- const [ showSecretDialog , setShowSecretDialog ] = useState ( false )
23
- const [ assignedSecrets ] = useState < { name : string , assigned : boolean } [ ] > ( [ ] )
24
- const [ changedSecrets , setChangedSecrets ] = useState < { [ key : string ] : string | undefined } > ( { } )
25
- const [ secretLoading , setSecretLoading ] = useState ( false )
26
- const [ showConfigModal , setShowConfigModal ] = useState ( false )
27
- const { isLoading : secretsLoading , mutate : mutateSecret } = useSecrets ( client )
28
- const { registerCatalogItem, unregisterCatalogItem } = useCatalogOperations ( client )
29
- const { registryLoading } = useCatalogAll ( client )
30
-
31
- if ( registryLoading || secretsLoading ) {
32
- return < >
33
- < CircularProgress size = { 20 } />
34
- < Typography > Loading registry...</ Typography >
35
- </ >
36
- }
47
+ if ( registryLoading || secretsLoading ) {
48
+ return (
49
+ < >
50
+ < CircularProgress size = { 20 } />
51
+ < Typography > Loading registry...</ Typography >
52
+ </ >
53
+ ) ;
54
+ }
37
55
38
- const unAssignedSecrets = assignedSecrets . filter ( s => ! s . assigned )
56
+ const unAssignedSecrets = assignedSecrets . filter ( ( s ) => ! s . assigned ) ;
39
57
40
- return (
41
- < >
42
- < Dialog open = { showSecretDialog } onClose = { ( ) => setShowSecretDialog ( false ) } >
43
- < DialogTitle >
44
- < Typography variant = "h6" >
45
- Secrets
46
- </ Typography >
47
- </ DialogTitle >
48
- < DialogContent >
49
- < Stack direction = "column" spacing = { 2 } >
50
- { assignedSecrets ?. map ( secret => {
51
- const isAssigned = assignedSecrets . find ( s => s . name === secret . name )
52
- return (
53
- < Stack key = { secret . name } direction = "row" spacing = { 2 } alignItems = "center" >
54
- < Typography variant = "body2" > { secret . name } { isAssigned ?. assigned ? 'assigned' : 'not assigned' } </ Typography >
55
- < TextField placeholder = { isAssigned ?. assigned ? '********' : 'Enter secret value' } type = "password" key = { secret . name } label = { secret . name } value = { changedSecrets [ secret . name ] || '' } onChange = { ( event ) => setChangedSecrets ( { ...changedSecrets , [ secret . name ] : event . target . value } ) } />
56
- { isAssigned ?. assigned && changedSecrets [ secret . name ] && < IconButton onClick = { ( ) => setChangedSecrets ( { ...changedSecrets , [ secret . name ] : undefined } ) } >
57
- < LockReset />
58
- </ IconButton > }
59
- { changedSecrets [ secret . name ] && < IconButton onClick = { ( ) => {
60
- setSecretLoading ( true )
61
- mutateSecret . mutateAsync ( { name : secret . name , value : changedSecrets [ secret . name ] || '' , policies : [ MCP_POLICY_NAME ] } ) . then ( ( ) => {
62
- setSecretLoading ( false )
63
- const newChangedSecrets = { ...changedSecrets }
64
- delete newChangedSecrets [ secret . name ]
65
- setChangedSecrets ( newChangedSecrets )
66
- } )
67
- } } >
68
- { secretLoading ? < CircularProgress size = { 20 } /> : < Save /> }
69
- </ IconButton > }
70
- </ Stack >
71
- )
72
- } ) }
73
- </ Stack >
74
- </ DialogContent >
75
- </ Dialog >
76
- < ConfigurationModal
77
- open = { showConfigModal }
78
- onClose = { ( ) => setShowConfigModal ( false ) }
79
- catalogItem = { item }
80
- client = { client }
81
- />
82
- < Card onClick = { ( e ) => {
83
- if ( ( e . target as HTMLElement ) . tagName !== 'INPUT' ) {
84
- setShowConfigModal ( true )
85
- }
86
- } } sx = { { height : 150 , borderColor : 'divider' , borderWidth : 1 , borderStyle : 'solid' , p : 0 , cursor : 'pointer' , transition : 'background-color 0.1s ease' , '&:hover' : { backgroundColor : 'action.hover' } } } >
87
- < CardContent sx = { { paddingBottom : 0 , paddingTop : 2 } } >
88
- < Stack direction = "column" spacing = { 0 } >
89
- < Top onToggleRegister = { ( checked ) => {
90
- if ( checked ) {
91
- registerCatalogItem ( item )
92
- } else {
93
- unregisterCatalogItem ( item )
94
- }
95
- } } item = { item } />
96
- < Center item = { item } />
97
- < Divider sx = { { marginBottom : 1 } } />
98
- < Bottom item = { item } needsConfiguration = { Boolean ( unAssignedSecrets . length ) } />
99
- </ Stack >
100
- </ CardContent >
101
- </ Card >
102
- </ >
103
- )
104
- }
58
+ return (
59
+ < >
60
+ < Dialog
61
+ open = { showSecretDialog }
62
+ onClose = { ( ) => setShowSecretDialog ( false ) }
63
+ >
64
+ < DialogTitle >
65
+ < Typography variant = "h6" > Secrets</ Typography >
66
+ </ DialogTitle >
67
+ < DialogContent >
68
+ < Stack direction = "column" spacing = { 2 } >
69
+ { assignedSecrets ?. map ( ( secret ) => {
70
+ const isAssigned = assignedSecrets . find (
71
+ ( s ) => s . name === secret . name
72
+ ) ;
73
+ return (
74
+ < Stack
75
+ key = { secret . name }
76
+ direction = "row"
77
+ spacing = { 2 }
78
+ alignItems = "center"
79
+ >
80
+ < Typography variant = "body2" >
81
+ { secret . name } { ' ' }
82
+ { isAssigned ?. assigned ? 'assigned' : 'not assigned' }
83
+ </ Typography >
84
+ < TextField
85
+ placeholder = {
86
+ isAssigned ?. assigned ? '********' : 'Enter secret value'
87
+ }
88
+ type = "password"
89
+ key = { secret . name }
90
+ label = { secret . name }
91
+ value = { changedSecrets [ secret . name ] || '' }
92
+ onChange = { ( event ) =>
93
+ setChangedSecrets ( {
94
+ ...changedSecrets ,
95
+ [ secret . name ] : event . target . value ,
96
+ } )
97
+ }
98
+ />
99
+ { isAssigned ?. assigned && changedSecrets [ secret . name ] && (
100
+ < IconButton
101
+ onClick = { ( ) =>
102
+ setChangedSecrets ( {
103
+ ...changedSecrets ,
104
+ [ secret . name ] : undefined ,
105
+ } )
106
+ }
107
+ >
108
+ < LockReset />
109
+ </ IconButton >
110
+ ) }
111
+ { changedSecrets [ secret . name ] && (
112
+ < IconButton
113
+ onClick = { ( ) => {
114
+ setSecretLoading ( true ) ;
115
+ mutateSecret
116
+ . mutateAsync ( {
117
+ name : secret . name ,
118
+ value : changedSecrets [ secret . name ] || '' ,
119
+ policies : [ MCP_POLICY_NAME ] ,
120
+ } )
121
+ . then ( ( ) => {
122
+ setSecretLoading ( false ) ;
123
+ const newChangedSecrets = { ...changedSecrets } ;
124
+ delete newChangedSecrets [ secret . name ] ;
125
+ setChangedSecrets ( newChangedSecrets ) ;
126
+ } ) ;
127
+ } }
128
+ >
129
+ { secretLoading ? (
130
+ < CircularProgress size = { 20 } />
131
+ ) : (
132
+ < Save />
133
+ ) }
134
+ </ IconButton >
135
+ ) }
136
+ </ Stack >
137
+ ) ;
138
+ } ) }
139
+ </ Stack >
140
+ </ DialogContent >
141
+ </ Dialog >
142
+ < ConfigurationModal
143
+ open = { showConfigModal }
144
+ onClose = { ( ) => setShowConfigModal ( false ) }
145
+ catalogItem = { item }
146
+ client = { client }
147
+ />
148
+ < Card sx = { { height : 150 } } >
149
+ < CardActionArea
150
+ onClick = { ( e ) => {
151
+ if ( ( e . target as HTMLElement ) . tagName !== 'INPUT' ) {
152
+ setShowConfigModal ( true ) ;
153
+ }
154
+ } }
155
+ >
156
+ < CardContent sx = { { paddingBottom : 0 , paddingTop : 2 } } >
157
+ < Stack direction = "column" spacing = { 0 } >
158
+ < Top
159
+ onToggleRegister = { ( checked ) => {
160
+ if ( checked ) {
161
+ registerCatalogItem ( item ) ;
162
+ } else {
163
+ unregisterCatalogItem ( item ) ;
164
+ }
165
+ } }
166
+ item = { item }
167
+ />
168
+ < Center item = { item } />
169
+ < Divider sx = { { marginBottom : 1 } } />
170
+ < Bottom
171
+ item = { item }
172
+ needsConfiguration = { Boolean ( unAssignedSecrets . length ) }
173
+ />
174
+ </ Stack >
175
+ </ CardContent >
176
+ </ CardActionArea >
177
+ </ Card >
178
+ </ >
179
+ ) ;
180
+ } ;
105
181
106
- export default Tile ;
182
+ export default Tile ;
0 commit comments