mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-23 00:22:19 +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