@@ -12,51 +12,36 @@ import {
1212import { Button } from '@patternfly/react-core/dist/esm/components/Button' ;
1313import {
1414 Modal ,
15- ModalBody ,
1615 ModalFooter ,
1716 ModalHeader ,
1817 ModalVariant ,
1918} from '@patternfly/react-core/dist/esm/components/Modal' ;
20- import { ValidatedOptions } from '@patternfly/react-core/helpers' ;
21- import { TextInput } from '@patternfly/react-core/dist/esm/components/TextInput' ;
2219import { Dropdown , DropdownItem } from '@patternfly/react-core/dist/esm/components/Dropdown' ;
2320import { MenuToggle } from '@patternfly/react-core/dist/esm/components/MenuToggle' ;
24- import { Form } from '@patternfly/react-core/dist/esm/components/Form' ;
25- import { HelperText , HelperTextItem } from '@patternfly/react-core/dist/esm/components/HelperText' ;
26- import { PlusCircleIcon } from '@patternfly/react-icons/dist/esm/icons/plus-circle-icon' ;
27- import ThemeAwareFormGroupWrapper from '~/shared/components/ThemeAwareFormGroupWrapper' ;
2821import { SecretsSecretListItem , WorkspacesPodSecretMount } from '~/generated/data-contracts' ;
2922import { useNotebookAPI } from '~/app/hooks/useNotebookAPI' ;
3023import { useNamespaceContext } from '~/app/context/NamespaceContextProvider' ;
24+ import { SecretsApiCreateModal } from './secrets/SecretsApiCreateModal' ;
3125
3226interface WorkspaceFormPropertiesSecretsProps {
3327 secrets : WorkspacesPodSecretMount [ ] ;
3428 setSecrets : ( secrets : WorkspacesPodSecretMount [ ] ) => void ;
3529}
3630
37- const DEFAULT_MODE_OCTAL = ( 420 ) . toString ( 8 ) ;
38-
3931export const WorkspaceFormPropertiesSecrets : React . FC < WorkspaceFormPropertiesSecretsProps > = ( {
4032 secrets,
4133 setSecrets,
4234} ) => {
43- const [ isModalOpen , setIsModalOpen ] = useState ( false ) ;
35+ const { api } = useNotebookAPI ( ) ;
36+ const { selectedNamespace } = useNamespaceContext ( ) ;
37+
38+ const [ isApiCreateModalOpen , setIsApiCreateModalOpen ] = useState ( false ) ;
4439 const [ isDeleteModalOpen , setIsDeleteModalOpen ] = useState ( false ) ;
45- const [ formData , setFormData ] = useState < WorkspacesPodSecretMount > ( {
46- secretName : '' ,
47- mountPath : '' ,
48- defaultMode : parseInt ( DEFAULT_MODE_OCTAL , 8 ) ,
49- } ) ;
50- const [ editIndex , setEditIndex ] = useState < number | null > ( null ) ;
51- const [ defaultMode , setDefaultMode ] = useState ( DEFAULT_MODE_OCTAL ) ;
5240 const [ deleteIndex , setDeleteIndex ] = useState < number | null > ( null ) ;
53- const [ isDefaultModeValid , setIsDefaultModeValid ] = useState ( true ) ;
5441 const [ dropdownOpen , setDropdownOpen ] = useState < number | null > ( null ) ;
42+ // Keep baseline secrets fetching from PR #698 for future attach functionality
5543 const [ , setAvailableSecrets ] = useState < SecretsSecretListItem [ ] > ( [ ] ) ;
5644
57- const { api } = useNotebookAPI ( ) ;
58- const { selectedNamespace } = useNamespaceContext ( ) ;
59-
6045 useEffect ( ( ) => {
6146 const fetchSecrets = async ( ) => {
6247 const secretsResponse = await api . secrets . listSecrets ( selectedNamespace ) ;
@@ -70,56 +55,6 @@ export const WorkspaceFormPropertiesSecrets: React.FC<WorkspaceFormPropertiesSec
7055 setDeleteIndex ( i ) ;
7156 } , [ ] ) ;
7257
73- const handleEdit = useCallback (
74- ( index : number ) => {
75- setFormData ( secrets [ index ] ) ;
76- setDefaultMode ( secrets [ index ] . defaultMode ?. toString ( 8 ) ?? DEFAULT_MODE_OCTAL ) ;
77- setEditIndex ( index ) ;
78- setIsModalOpen ( true ) ;
79- } ,
80- [ secrets ] ,
81- ) ;
82-
83- const handleDefaultModeInput = useCallback (
84- ( val : string ) => {
85- if ( val . length <= 3 ) {
86- // 0 no permissions, 4 read only, 5 read + execute, 6 read + write, 7 all permissions
87- setDefaultMode ( val ) ;
88- const permissions = [ '0' , '4' , '5' , '6' , '7' ] ;
89- const isValid = Array . from ( val ) . every ( ( char ) => permissions . includes ( char ) ) ;
90- if ( val . length < 3 || ! isValid ) {
91- setIsDefaultModeValid ( false ) ;
92- } else {
93- setIsDefaultModeValid ( true ) ;
94- }
95- const decimalVal = parseInt ( val , 8 ) ;
96- setFormData ( { ...formData , defaultMode : decimalVal } ) ;
97- }
98- } ,
99- [ setFormData , setIsDefaultModeValid , setDefaultMode , formData ] ,
100- ) ;
101-
102- const clearForm = useCallback ( ( ) => {
103- setFormData ( { secretName : '' , mountPath : '' , defaultMode : 420 } ) ;
104- setEditIndex ( null ) ;
105- setIsModalOpen ( false ) ;
106- setIsDefaultModeValid ( true ) ;
107- } , [ ] ) ;
108-
109- const handleAddOrEditSubmit = useCallback ( ( ) => {
110- if ( ! formData . secretName || ! formData . mountPath ) {
111- return ;
112- }
113- if ( editIndex !== null ) {
114- const updated = [ ...secrets ] ;
115- updated [ editIndex ] = formData ;
116- setSecrets ( updated ) ;
117- } else {
118- setSecrets ( [ ...secrets , formData ] ) ;
119- }
120- clearForm ( ) ;
121- } , [ clearForm , editIndex , formData , secrets , setSecrets ] ) ;
122-
12358 const handleDelete = useCallback ( ( ) => {
12459 if ( deleteIndex === null ) {
12560 return ;
@@ -146,7 +81,7 @@ export const WorkspaceFormPropertiesSecrets: React.FC<WorkspaceFormPropertiesSec
14681 < Tr key = { index } >
14782 < Td > { secret . secretName } </ Td >
14883 < Td > { secret . mountPath } </ Td >
149- < Td > { secret . defaultMode ?. toString ( 8 ) ?? DEFAULT_MODE_OCTAL } </ Td >
84+ < Td > { secret . defaultMode ?. toString ( 8 ) ?? '644' } </ Td >
15085 < Td isActionCell >
15186 < Dropdown
15287 toggle = { ( toggleRef ) => (
@@ -164,7 +99,6 @@ export const WorkspaceFormPropertiesSecrets: React.FC<WorkspaceFormPropertiesSec
16499 onSelect = { ( ) => setDropdownOpen ( null ) }
165100 popperProps = { { position : 'right' } }
166101 >
167- < DropdownItem onClick = { ( ) => handleEdit ( index ) } > Edit</ DropdownItem >
168102 < DropdownItem onClick = { ( ) => openDeleteModal ( index ) } > Remove</ DropdownItem >
169103 </ Dropdown >
170104 </ Td >
@@ -173,86 +107,28 @@ export const WorkspaceFormPropertiesSecrets: React.FC<WorkspaceFormPropertiesSec
173107 </ Tbody >
174108 </ Table >
175109 ) }
176- < Button
177- variant = "primary"
178- icon = { < PlusCircleIcon /> }
179- onClick = { ( ) => setIsModalOpen ( true ) }
180- style = { { marginTop : '1rem' , width : 'fit-content' } }
181- >
182- Create Secret
183- </ Button >
184- < Modal isOpen = { isModalOpen } onClose = { clearForm } variant = { ModalVariant . small } >
185- < ModalHeader
186- title = { editIndex === null ? 'Create Secret' : 'Edit Secret' }
187- labelId = "secret-modal-title"
188- description = {
189- editIndex === null
190- ? 'Add a secret to securely use API keys, tokens, or other credentials in your workspace.'
191- : ''
192- }
193- />
194- < ModalBody id = "secret-modal-box-body" >
195- < Form onSubmit = { handleAddOrEditSubmit } >
196- < ThemeAwareFormGroupWrapper label = "Secret Name" isRequired fieldId = "secret-name" >
197- < TextInput
198- name = "secretName"
199- isRequired
200- type = "text"
201- value = { formData . secretName }
202- onChange = { ( _ , val ) => setFormData ( { ...formData , secretName : val } ) }
203- id = "secret-name"
204- />
205- </ ThemeAwareFormGroupWrapper >
206- < ThemeAwareFormGroupWrapper label = "Mount Path" isRequired fieldId = "mount-path" >
207- < TextInput
208- name = "mountPath"
209- isRequired
210- type = "text"
211- value = { formData . mountPath }
212- onChange = { ( _ , val ) => setFormData ( { ...formData , mountPath : val } ) }
213- id = "mount-path"
214- />
215- </ ThemeAwareFormGroupWrapper >
216- < ThemeAwareFormGroupWrapper
217- label = "Default Mode"
218- isRequired
219- fieldId = "default-mode"
220- helperTextNode = {
221- ! isDefaultModeValid ? (
222- < HelperText >
223- < HelperTextItem variant = "error" >
224- Must be a valid UNIX file system permission value (i.e. 644)
225- </ HelperTextItem >
226- </ HelperText >
227- ) : null
228- }
229- >
230- < TextInput
231- name = "defaultMode"
232- isRequired
233- type = "text"
234- value = { defaultMode }
235- validated = { ! isDefaultModeValid ? ValidatedOptions . error : undefined }
236- onChange = { ( _ , val ) => handleDefaultModeInput ( val ) }
237- id = "default-mode"
238- />
239- </ ThemeAwareFormGroupWrapper >
240- </ Form >
241- </ ModalBody >
242- < ModalFooter >
243- < Button
244- key = "confirm"
245- variant = "primary"
246- onClick = { handleAddOrEditSubmit }
247- isDisabled = { ! isDefaultModeValid }
248- >
249- { editIndex !== null ? 'Save' : 'Create' }
250- </ Button >
251- < Button key = "cancel" variant = "link" onClick = { clearForm } >
252- Cancel
253- </ Button >
254- </ ModalFooter >
255- </ Modal >
110+ < div style = { { display : 'flex' , gap : '0.5rem' , marginTop : '1rem' } } >
111+ < Button
112+ variant = "primary"
113+ onClick = { ( ) => setIsApiCreateModalOpen ( true ) }
114+ style = { { width : 'fit-content' } }
115+ >
116+ Create New Secret
117+ </ Button >
118+ </ div >
119+
120+ { /* <SecretsAttachModal
121+ isOpen={isAttachModalOpen}
122+ setIsOpen={setIsAttachModalOpen}
123+ onClose={handleAttachSecrets}
124+ selectedSecrets={selectedSecretNames}
125+ availableSecrets={availableSecrets}
126+ initialMountPath={attachedMountPath}
127+ initialDefaultMode={attachedDefaultMode}
128+ /> */ }
129+
130+ < SecretsApiCreateModal isOpen = { isApiCreateModalOpen } setIsOpen = { setIsApiCreateModalOpen } />
131+
256132 < Modal
257133 isOpen = { isDeleteModalOpen }
258134 onClose = { ( ) => setIsDeleteModalOpen ( false ) }
0 commit comments