mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: create edit and creat feature screen
This commit is contained in:
		
							parent
							
								
									53cff04349
								
							
						
					
					
						commit
						8c82a6bceb
					
				| @ -24,7 +24,9 @@ const BreadcrumbNav = () => { | |||||||
|                 item !== 'strategies' && |                 item !== 'strategies' && | ||||||
|                 item !== 'features' && |                 item !== 'features' && | ||||||
|                 item !== 'features2' &&  |                 item !== 'features2' &&  | ||||||
|                 item !== 'create-toggle' |                 item !== 'create-toggle'&&  | ||||||
|  |                 item !== 'settings'   | ||||||
|  | 
 | ||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|  | |||||||
| @ -0,0 +1,103 @@ | |||||||
|  | import FormTemplate from '../../../common/FormTemplate/FormTemplate'; | ||||||
|  | import { useHistory } from 'react-router-dom'; | ||||||
|  | import FeatureForm from '../FeatureForm/FeatureForm'; | ||||||
|  | import useFeatureForm from '../hooks/useFeatureForm'; | ||||||
|  | import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig'; | ||||||
|  | import useToast from '../../../../hooks/useToast'; | ||||||
|  | import useFeatureApi from '../../../../hooks/api/actions/useFeatureApi/useFeatureApi'; | ||||||
|  | import { CREATE_FEATURE } from '../../../providers/AccessProvider/permissions'; | ||||||
|  | import PermissionButton from '../../../common/PermissionButton/PermissionButton'; | ||||||
|  | 
 | ||||||
|  | const CreateFeature = () => { | ||||||
|  |     /* @ts-ignore */ | ||||||
|  |     const { setToastData, setToastApiError } = useToast(); | ||||||
|  |     const { uiConfig } = useUiConfig(); | ||||||
|  |     const history = useHistory(); | ||||||
|  | 
 | ||||||
|  |     const { | ||||||
|  |         type, | ||||||
|  |         setType, | ||||||
|  |         name, | ||||||
|  |         setName, | ||||||
|  |         project, | ||||||
|  |         setProject, | ||||||
|  |         description, | ||||||
|  |         setDescription, | ||||||
|  |         getTogglePayload, | ||||||
|  |         validateName, | ||||||
|  |         clearErrors, | ||||||
|  |         errors, | ||||||
|  |     } = useFeatureForm(); | ||||||
|  | 
 | ||||||
|  |     const { createFeatureToggle, loading } = useFeatureApi(); | ||||||
|  | 
 | ||||||
|  |     const handleSubmit = async (e: Event) => { | ||||||
|  |         e.preventDefault(); | ||||||
|  |         clearErrors(); | ||||||
|  |         await validateName(name); | ||||||
|  |         const payload = getTogglePayload(); | ||||||
|  |         try { | ||||||
|  |             await createFeatureToggle(project, payload); | ||||||
|  |             history.push(`/projects/${project}/features2/${name}`); | ||||||
|  |             setToastData({ | ||||||
|  |                 title: 'Toggle created successfully', | ||||||
|  |                 text: 'Now you can start using your toggle.', | ||||||
|  |                 confetti: true, | ||||||
|  |                 type: 'success', | ||||||
|  |             }); | ||||||
|  |         } catch (e: any) { | ||||||
|  |             setToastApiError(e.toString()); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const formatApiCode = () => { | ||||||
|  |         return `curl --location --request POST '${ | ||||||
|  |             uiConfig.unleashUrl | ||||||
|  |         }/api/admin/projects/${project}/features' \\ | ||||||
|  |     --header 'Authorization: INSERT_API_KEY' \\ | ||||||
|  |     --header 'Content-Type: application/json' \\ | ||||||
|  |     --data-raw '${JSON.stringify(getTogglePayload(), undefined, 2)}'`;
 | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const handleCancel = () => { | ||||||
|  |         history.goBack(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <FormTemplate | ||||||
|  |             loading={loading} | ||||||
|  |             title="Create Feature toggle" | ||||||
|  |             description="Feature toggles support different use cases, each with their own specific needs such as simple static routing or more complex routing. | ||||||
|  |             The feature toggle is disabled when created and you decide when to enable" | ||||||
|  |             documentationLink="https://docs.getunleash.io/" | ||||||
|  |             formatApiCode={formatApiCode} | ||||||
|  |         > | ||||||
|  |             <FeatureForm | ||||||
|  |                 type={type} | ||||||
|  |                 name={name} | ||||||
|  |                 project={project} | ||||||
|  |                 description={description} | ||||||
|  |                 setType={setType} | ||||||
|  |                 setName={setName} | ||||||
|  |                 setProject={setProject} | ||||||
|  |                 setDescription={setDescription} | ||||||
|  |                 errors={errors} | ||||||
|  |                 handleSubmit={handleSubmit} | ||||||
|  |                 handleCancel={handleCancel} | ||||||
|  |                 mode="Create" | ||||||
|  |                 clearErrors={clearErrors} | ||||||
|  |             > | ||||||
|  |                 <PermissionButton | ||||||
|  |                     onClick={handleSubmit} | ||||||
|  |                     permission={CREATE_FEATURE} | ||||||
|  |                     projectId={project} | ||||||
|  |                     type="submit" | ||||||
|  |                 > | ||||||
|  |                     Create toggle | ||||||
|  |                 </PermissionButton> | ||||||
|  |             </FeatureForm> | ||||||
|  |         </FormTemplate> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default CreateFeature; | ||||||
| @ -0,0 +1,115 @@ | |||||||
|  | import FormTemplate from '../../../common/FormTemplate/FormTemplate'; | ||||||
|  | import { useHistory, useParams } from 'react-router-dom'; | ||||||
|  | import FeatureForm from '../FeatureForm/FeatureForm'; | ||||||
|  | import useFeatureForm from '../hooks/useFeatureForm'; | ||||||
|  | import useUiConfig from '../../../../hooks/api/getters/useUiConfig/useUiConfig'; | ||||||
|  | import useToast from '../../../../hooks/useToast'; | ||||||
|  | import useFeatureApi from '../../../../hooks/api/actions/useFeatureApi/useFeatureApi'; | ||||||
|  | import useFeature from '../../../../hooks/api/getters/useFeature/useFeature'; | ||||||
|  | import { IFeatureViewParams } from '../../../../interfaces/params'; | ||||||
|  | import * as jsonpatch from 'fast-json-patch'; | ||||||
|  | import PermissionButton from '../../../common/PermissionButton/PermissionButton'; | ||||||
|  | import { UPDATE_FEATURE } from '../../../providers/AccessProvider/permissions'; | ||||||
|  | 
 | ||||||
|  | const EditFeature = () => { | ||||||
|  |     /* @ts-ignore */ | ||||||
|  |     const { setToastData, setToastApiError } = useToast(); | ||||||
|  |     const { uiConfig } = useUiConfig(); | ||||||
|  |     const history = useHistory(); | ||||||
|  |     const { projectId, featureId } = useParams<IFeatureViewParams>(); | ||||||
|  |     const { patchFeatureToggle, loading } = useFeatureApi(); | ||||||
|  |     const { feature } = useFeature(projectId, featureId); | ||||||
|  | 
 | ||||||
|  |     const { | ||||||
|  |         type, | ||||||
|  |         setType, | ||||||
|  |         name, | ||||||
|  |         setName, | ||||||
|  |         project, | ||||||
|  |         setProject, | ||||||
|  |         description, | ||||||
|  |         setDescription, | ||||||
|  |         getTogglePayload, | ||||||
|  |         clearErrors, | ||||||
|  |         errors, | ||||||
|  |     } = useFeatureForm( | ||||||
|  |         feature?.name, | ||||||
|  |         feature?.type, | ||||||
|  |         feature?.project, | ||||||
|  |         feature?.description | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     const createPatch = () => { | ||||||
|  |         const comparison = { ...feature, type, description }; | ||||||
|  |         const patch = jsonpatch.compare(feature, comparison); | ||||||
|  |         return patch; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const handleSubmit = async (e: Event) => { | ||||||
|  |         e.preventDefault(); | ||||||
|  |         clearErrors(); | ||||||
|  |         const patch = createPatch(); | ||||||
|  |         try { | ||||||
|  |             await patchFeatureToggle(project, featureId, patch); | ||||||
|  |             history.push(`/projects/${project}/features2/${name}`); | ||||||
|  |             setToastData({ | ||||||
|  |                 title: 'Toggle updated successfully', | ||||||
|  |                 text: 'Now you can start using your toggle.', | ||||||
|  |                 type: 'success', | ||||||
|  |             }); | ||||||
|  |         } catch (e: any) { | ||||||
|  |             setToastApiError(e.toString()); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const formatApiCode = () => { | ||||||
|  |         return `curl --location --request PUT '${ | ||||||
|  |             uiConfig.unleashUrl | ||||||
|  |         }/api/admin/projects/${projectId}/features/${featureId}' \\ | ||||||
|  |     --header 'Authorization: INSERT_API_KEY' \\ | ||||||
|  |     --header 'Content-Type: application/json' \\ | ||||||
|  |     --data-raw '${JSON.stringify(getTogglePayload(), undefined, 2)}'`;
 | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const handleCancel = () => { | ||||||
|  |         history.goBack(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <FormTemplate | ||||||
|  |             loading={loading} | ||||||
|  |             title="Create Feature toggle" | ||||||
|  |             description="Feature toggles support different use cases, each with their own specific needs such as simple static routing or more complex routing. | ||||||
|  |             The feature toggle is disabled when created and you decide when to enable" | ||||||
|  |             documentationLink="https://docs.getunleash.io/" | ||||||
|  |             formatApiCode={formatApiCode} | ||||||
|  |         > | ||||||
|  |             <FeatureForm | ||||||
|  |                 type={type} | ||||||
|  |                 name={name} | ||||||
|  |                 project={project} | ||||||
|  |                 description={description} | ||||||
|  |                 setType={setType} | ||||||
|  |                 setName={setName} | ||||||
|  |                 setProject={setProject} | ||||||
|  |                 setDescription={setDescription} | ||||||
|  |                 errors={errors} | ||||||
|  |                 handleSubmit={handleSubmit} | ||||||
|  |                 handleCancel={handleCancel} | ||||||
|  |                 mode="Edit" | ||||||
|  |                 clearErrors={clearErrors} | ||||||
|  |             > | ||||||
|  |                 <PermissionButton | ||||||
|  |                     onClick={handleSubmit} | ||||||
|  |                     permission={UPDATE_FEATURE} | ||||||
|  |                     projectId={project} | ||||||
|  |                     type="submit" | ||||||
|  |                 > | ||||||
|  |                     Edit toggle | ||||||
|  |                 </PermissionButton> | ||||||
|  |             </FeatureForm> | ||||||
|  |         </FormTemplate> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default EditFeature; | ||||||
| @ -0,0 +1,61 @@ | |||||||
|  | import { makeStyles } from '@material-ui/core/styles'; | ||||||
|  | 
 | ||||||
|  | export const useStyles = makeStyles(theme => ({ | ||||||
|  |     container: { | ||||||
|  |         maxWidth: '400px', | ||||||
|  |     }, | ||||||
|  |     form: { | ||||||
|  |         display: 'flex', | ||||||
|  |         flexDirection: 'column', | ||||||
|  |         height: '100%', | ||||||
|  |     }, | ||||||
|  |     input: { width: '100%', marginBottom: '1rem' }, | ||||||
|  |     selectInput: { | ||||||
|  |         marginBottom: '1rem', | ||||||
|  |         minWidth: '400px', | ||||||
|  |         [theme.breakpoints.down(600)]: { | ||||||
|  |             minWidth: '379px', | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  |     label: { | ||||||
|  |         minWidth: '300px', | ||||||
|  |         [theme.breakpoints.down(600)]: { | ||||||
|  |             minWidth: 'auto', | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  |     buttonContainer: { | ||||||
|  |         marginTop: 'auto', | ||||||
|  |         display: 'flex', | ||||||
|  |         justifyContent: 'flex-end', | ||||||
|  |     }, | ||||||
|  |     cancelButton: { | ||||||
|  |         marginRight: '1.5rem', | ||||||
|  |     }, | ||||||
|  |     inputDescription: { | ||||||
|  |         marginBottom: '0.5rem', | ||||||
|  |     }, | ||||||
|  |     typeDescription: { | ||||||
|  |         //@ts-ignore
 | ||||||
|  |         fontSize: theme.fontSizes.smallBody, | ||||||
|  |         color: theme.palette.grey[600], | ||||||
|  |         top: '-13px', | ||||||
|  |         position: 'relative', | ||||||
|  |     }, | ||||||
|  |     formHeader: { | ||||||
|  |         fontWeight: 'normal', | ||||||
|  |         marginTop: '0', | ||||||
|  |     }, | ||||||
|  |     header: { | ||||||
|  |         fontWeight: 'normal', | ||||||
|  |     }, | ||||||
|  |     permissionErrorContainer: { | ||||||
|  |         position: 'relative', | ||||||
|  |     }, | ||||||
|  |     errorMessage: { | ||||||
|  |         //@ts-ignore
 | ||||||
|  |         fontSize: theme.fontSizes.smallBody, | ||||||
|  |         color: theme.palette.error.main, | ||||||
|  |         position: 'absolute', | ||||||
|  |         top: '-8px', | ||||||
|  |     }, | ||||||
|  | })); | ||||||
| @ -0,0 +1,145 @@ | |||||||
|  | import { | ||||||
|  |     CREATE_FEATURE, | ||||||
|  |     UPDATE_FEATURE, | ||||||
|  | } from '../../../providers/AccessProvider/permissions'; | ||||||
|  | import Input from '../../../common/Input/Input'; | ||||||
|  | import { Button } from '@material-ui/core'; | ||||||
|  | import { useStyles } from './FeatureForm.styles'; | ||||||
|  | import FeatureTypeSelect from '../../FeatureView2/FeatureSettings/FeatureSettingsMetadata/FeatureTypeSelect/FeatureTypeSelect'; | ||||||
|  | import { CF_DESC_ID, CF_TYPE_ID } from '../../../../testIds'; | ||||||
|  | import useFeatureTypes from '../../../../hooks/api/getters/useFeatureTypes/useFeatureTypes'; | ||||||
|  | import { KeyboardArrowDownOutlined } from '@material-ui/icons'; | ||||||
|  | import { useContext } from 'react'; | ||||||
|  | import useUser from '../../../../hooks/api/getters/useUser/useUser'; | ||||||
|  | import { projectFilterGenerator } from '../../../../utils/project-filter-generator'; | ||||||
|  | import FeatureProjectSelect from '../../FeatureView2/FeatureSettings/FeatureSettingsProject/FeatureProjectSelect/FeatureProjectSelect'; | ||||||
|  | import AccessContext from '../../../../contexts/AccessContext'; | ||||||
|  | import ConditionallyRender from '../../../common/ConditionallyRender'; | ||||||
|  | import { trim } from '../../../common/util'; | ||||||
|  | 
 | ||||||
|  | interface IFeatureToggleForm { | ||||||
|  |     type: string; | ||||||
|  |     name: string; | ||||||
|  |     description: string; | ||||||
|  |     project: string; | ||||||
|  |     setType: React.Dispatch<React.SetStateAction<string>>; | ||||||
|  |     setName: React.Dispatch<React.SetStateAction<string>>; | ||||||
|  |     setDescription: React.Dispatch<React.SetStateAction<string>>; | ||||||
|  |     setProject: React.Dispatch<React.SetStateAction<string>>; | ||||||
|  |     handleSubmit: (e: any) => void; | ||||||
|  |     handleCancel: () => void; | ||||||
|  |     errors: { [key: string]: string }; | ||||||
|  |     mode: string; | ||||||
|  |     clearErrors: () => void; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const FeatureForm: React.FC<IFeatureToggleForm> = ({ | ||||||
|  |     children, | ||||||
|  |     type, | ||||||
|  |     name, | ||||||
|  |     description, | ||||||
|  |     project, | ||||||
|  |     setType, | ||||||
|  |     setName, | ||||||
|  |     setDescription, | ||||||
|  |     setProject, | ||||||
|  |     handleSubmit, | ||||||
|  |     handleCancel, | ||||||
|  |     errors, | ||||||
|  |     mode, | ||||||
|  |     clearErrors, | ||||||
|  | }) => { | ||||||
|  |     const styles = useStyles(); | ||||||
|  |     const { hasAccess } = useContext(AccessContext); | ||||||
|  |     const { featureTypes } = useFeatureTypes(); | ||||||
|  |     const { permissions } = useUser(); | ||||||
|  |     const editable = hasAccess(UPDATE_FEATURE, project); | ||||||
|  | 
 | ||||||
|  |     const renderToggleDescription = () => { | ||||||
|  |         return featureTypes.find(toggle => toggle.id === type)?.description; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <form onSubmit={handleSubmit} className={styles.form}> | ||||||
|  |             <div className={styles.container}> | ||||||
|  |                 <p className={styles.inputDescription}> | ||||||
|  |                     What kind of feature toggle do you want to create? | ||||||
|  |                 </p> | ||||||
|  |                 <FeatureTypeSelect | ||||||
|  |                     value={type} | ||||||
|  |                     onChange={e => setType(e.target.value)} | ||||||
|  |                     label={'Toggle type'} | ||||||
|  |                     id="feature-type-select" | ||||||
|  |                     editable | ||||||
|  |                     inputProps={{ | ||||||
|  |                         'data-test': CF_TYPE_ID, | ||||||
|  |                     }} | ||||||
|  |                     IconComponent={KeyboardArrowDownOutlined} | ||||||
|  |                     className={styles.selectInput} | ||||||
|  |                 /> | ||||||
|  |                 <p className={styles.typeDescription}> | ||||||
|  |                     {renderToggleDescription()} | ||||||
|  |                 </p> | ||||||
|  | 
 | ||||||
|  |                 <p className={styles.inputDescription}> | ||||||
|  |                     What would you like to call your toggle? | ||||||
|  |                 </p> | ||||||
|  |                 <Input | ||||||
|  |                     disabled={mode === 'Edit'} | ||||||
|  |                     className={styles.input} | ||||||
|  |                     label="Name" | ||||||
|  |                     error={Boolean(errors.name)} | ||||||
|  |                     errorText={errors.name} | ||||||
|  |                     onFocus={() => clearErrors()} | ||||||
|  |                     value={name} | ||||||
|  |                     onChange={e => setName(trim(e.target.value))} | ||||||
|  |                 /> | ||||||
|  |                 <ConditionallyRender | ||||||
|  |                     condition={editable} | ||||||
|  |                     show={ | ||||||
|  |                         <p className={styles.inputDescription}> | ||||||
|  |                             In which project do you want to save the toggle? | ||||||
|  |                         </p> | ||||||
|  |                     } | ||||||
|  |                 /> | ||||||
|  |                 <FeatureProjectSelect | ||||||
|  |                     value={project} | ||||||
|  |                     onChange={e => setProject(e.target.value)} | ||||||
|  |                     enabled={editable} | ||||||
|  |                     label="Project" | ||||||
|  |                     filter={projectFilterGenerator( | ||||||
|  |                         { permissions }, | ||||||
|  |                         CREATE_FEATURE | ||||||
|  |                     )} | ||||||
|  |                     IconComponent={KeyboardArrowDownOutlined} | ||||||
|  |                     className={styles.selectInput} | ||||||
|  |                 /> | ||||||
|  | 
 | ||||||
|  |                 <p className={styles.inputDescription}> | ||||||
|  |                     How would you describe your feature toggle? | ||||||
|  |                 </p> | ||||||
|  |                 <Input | ||||||
|  |                     className={styles.input} | ||||||
|  |                     multiline | ||||||
|  |                     rows={4} | ||||||
|  |                     label="Description" | ||||||
|  |                     placeholder="A short description of the feature toggle" | ||||||
|  |                     value={description} | ||||||
|  |                     inputProps={{ | ||||||
|  |                         'data-test': CF_DESC_ID, | ||||||
|  |                     }} | ||||||
|  |                     onChange={e => setDescription(e.target.value)} | ||||||
|  |                 /> | ||||||
|  |             </div> | ||||||
|  | 
 | ||||||
|  |             <div className={styles.buttonContainer}> | ||||||
|  |                 <Button onClick={handleCancel} className={styles.cancelButton}> | ||||||
|  |                     Cancel | ||||||
|  |                 </Button> | ||||||
|  |                 {children} | ||||||
|  |             </div> | ||||||
|  |         </form> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default FeatureForm; | ||||||
| @ -0,0 +1,90 @@ | |||||||
|  | import { useEffect, useState } from 'react'; | ||||||
|  | import { useParams } from 'react-router-dom'; | ||||||
|  | import useFeatureApi from '../../../../hooks/api/actions/useFeatureApi/useFeatureApi'; | ||||||
|  | import useQueryParams from '../../../../hooks/useQueryParams'; | ||||||
|  | import { IFeatureViewParams } from '../../../../interfaces/params'; | ||||||
|  | 
 | ||||||
|  | const useFeatureForm = ( | ||||||
|  |     initialName = '', | ||||||
|  |     initialType = 'release', | ||||||
|  |     initialProject = 'default', | ||||||
|  |     initialDescription = '' | ||||||
|  | ) => { | ||||||
|  |     const { projectId } = useParams<IFeatureViewParams>(); | ||||||
|  |     const params = useQueryParams(); | ||||||
|  |     const { validateFeatureToggleName } = useFeatureApi(); | ||||||
|  |     const toggleQueryName = params.get('name'); | ||||||
|  |     const [type, setType] = useState(initialType); | ||||||
|  |     const [name, setName] = useState(toggleQueryName || initialName); | ||||||
|  |     const [project, setProject] = useState(projectId || initialProject); | ||||||
|  |     const [description, setDescription] = useState(initialDescription); | ||||||
|  |     const [errors, setErrors] = useState({}); | ||||||
|  | 
 | ||||||
|  |     useEffect(() => { | ||||||
|  |         setType(initialType); | ||||||
|  |     }, [initialType]); | ||||||
|  | 
 | ||||||
|  |     useEffect(() => { | ||||||
|  |         if (!toggleQueryName) setName(initialName); | ||||||
|  |         else setName(toggleQueryName); | ||||||
|  |     }, [initialName, toggleQueryName]); | ||||||
|  | 
 | ||||||
|  |     useEffect(() => { | ||||||
|  |         if (!projectId) setProject(initialProject); | ||||||
|  |         else setProject(projectId); | ||||||
|  |     }, [initialProject, projectId]); | ||||||
|  | 
 | ||||||
|  |     useEffect(() => { | ||||||
|  |         setDescription(initialDescription); | ||||||
|  |     }, [initialDescription]); | ||||||
|  | 
 | ||||||
|  |     const getTogglePayload = () => { | ||||||
|  |         return { | ||||||
|  |             type: type, | ||||||
|  |             name: name, | ||||||
|  |             projectId: project, | ||||||
|  |             description: description, | ||||||
|  |         }; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const validateName = async (name: string) => { | ||||||
|  |         if (name.length === 0) { | ||||||
|  |             setErrors(prev => ({ ...prev, name: 'Name can not be empty.' })); | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |         if (name.length > 0) { | ||||||
|  |             try { | ||||||
|  |                 await validateFeatureToggleName(name); | ||||||
|  |             } catch (err: any) { | ||||||
|  |                 setErrors(prev => ({ | ||||||
|  |                     ...prev, | ||||||
|  |                     name: | ||||||
|  |                         err && err.message | ||||||
|  |                             ? err.message | ||||||
|  |                             : 'Could not check name', | ||||||
|  |                 })); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const clearErrors = () => { | ||||||
|  |         setErrors({}); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     return { | ||||||
|  |         type, | ||||||
|  |         setType, | ||||||
|  |         name, | ||||||
|  |         setName, | ||||||
|  |         project, | ||||||
|  |         setProject, | ||||||
|  |         description, | ||||||
|  |         setDescription, | ||||||
|  |         getTogglePayload, | ||||||
|  |         validateName, | ||||||
|  |         clearErrors, | ||||||
|  |         errors, | ||||||
|  |     }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | export default useFeatureForm; | ||||||
| @ -31,13 +31,13 @@ import RedirectFeatureViewPage from '../../page/features/redirect'; | |||||||
| import RedirectArchive from '../feature/RedirectArchive/RedirectArchive'; | import RedirectArchive from '../feature/RedirectArchive/RedirectArchive'; | ||||||
| import EnvironmentList from '../environments/EnvironmentList/EnvironmentList'; | import EnvironmentList from '../environments/EnvironmentList/EnvironmentList'; | ||||||
| import FeatureView2 from '../feature/FeatureView2/FeatureView2'; | import FeatureView2 from '../feature/FeatureView2/FeatureView2'; | ||||||
| import FeatureCreate from '../feature/FeatureCreate/FeatureCreate'; |  | ||||||
| import ProjectRoles from '../admin/project-roles/ProjectRoles/ProjectRoles'; | import ProjectRoles from '../admin/project-roles/ProjectRoles/ProjectRoles'; | ||||||
| import CreateProjectRole from '../admin/project-roles/CreateProjectRole/CreateProjectRole'; | import CreateProjectRole from '../admin/project-roles/CreateProjectRole/CreateProjectRole'; | ||||||
| import EditProjectRole from '../admin/project-roles/EditProjectRole/EditProjectRole'; | import EditProjectRole from '../admin/project-roles/EditProjectRole/EditProjectRole'; | ||||||
| import CreateUser from '../admin/users/CreateUser/CreateUser'; | import CreateUser from '../admin/users/CreateUser/CreateUser'; | ||||||
| import EditUser from '../admin/users/EditUser/EditUser'; | import EditUser from '../admin/users/EditUser/EditUser'; | ||||||
| import CreateApiToken from '../admin/api-token/CreateApiToken/CreateApiToken'; | import CreateApiToken from '../admin/api-token/CreateApiToken/CreateApiToken'; | ||||||
|  | <<<<<<< HEAD | ||||||
| import CreateEnvironment from '../environments/CreateEnvironment/CreateEnvironment'; | import CreateEnvironment from '../environments/CreateEnvironment/CreateEnvironment'; | ||||||
| import EditEnvironment from '../environments/EditEnvironment/EditEnvironment'; | import EditEnvironment from '../environments/EditEnvironment/EditEnvironment'; | ||||||
| import CreateContext from '../context/CreateContext/CreateContext'; | import CreateContext from '../context/CreateContext/CreateContext'; | ||||||
| @ -46,6 +46,10 @@ import EditTagType from '../tagTypes/EditTagType/EditTagType'; | |||||||
| import CreateTagType from '../tagTypes/CreateTagType/CreateTagType'; | import CreateTagType from '../tagTypes/CreateTagType/CreateTagType'; | ||||||
| import EditProject from '../project/Project/EditProject/EditProject'; | import EditProject from '../project/Project/EditProject/EditProject'; | ||||||
| import CreateProject from '../project/Project/CreateProject/CreateProject'; | import CreateProject from '../project/Project/CreateProject/CreateProject'; | ||||||
|  | ======= | ||||||
|  | import CreateFeature from '../feature/CreateFeature/CreateFeature/CreateFeature'; | ||||||
|  | import EditFeature from '../feature/CreateFeature/EditFeature/EditFeature'; | ||||||
|  | >>>>>>> 937e090b (feat: create edit and creat feature screen) | ||||||
| 
 | 
 | ||||||
| export const routes = [ | export const routes = [ | ||||||
|     // Project
 |     // Project
 | ||||||
| @ -95,6 +99,15 @@ export const routes = [ | |||||||
|         layout: 'main', |         layout: 'main', | ||||||
|         menu: {}, |         menu: {}, | ||||||
|     }, |     }, | ||||||
|  |     { | ||||||
|  |         path: '/projects/:projectId/features2/:featureId/settings', | ||||||
|  |         parent: '/projects', | ||||||
|  |         title: 'Edit Feature', | ||||||
|  |         component: EditFeature, | ||||||
|  |         type: 'protected', | ||||||
|  |         layout: 'main', | ||||||
|  |         menu: {}, | ||||||
|  |     }, | ||||||
|     { |     { | ||||||
|         path: '/projects/:projectId/features2/:featureId', |         path: '/projects/:projectId/features2/:featureId', | ||||||
|         parent: '/projects', |         parent: '/projects', | ||||||
| @ -118,7 +131,7 @@ export const routes = [ | |||||||
|         path: '/projects/:projectId/create-toggle', |         path: '/projects/:projectId/create-toggle', | ||||||
|         parent: '/projects/:id/features', |         parent: '/projects/:id/features', | ||||||
|         title: 'Create feature toggle', |         title: 'Create feature toggle', | ||||||
|         component: FeatureCreate, |         component: CreateFeature, | ||||||
|         type: 'protected', |         type: 'protected', | ||||||
|         layout: 'main', |         layout: 'main', | ||||||
|         menu: {}, |         menu: {}, | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user