diff --git a/frontend/src/component/feature/create/CopyFeature/CopyFeature.jsx b/frontend/src/component/feature/create/CopyFeature/CopyFeature.jsx index 1a5994cf59..347dfae21a 100644 --- a/frontend/src/component/feature/create/CopyFeature/CopyFeature.jsx +++ b/frontend/src/component/feature/create/CopyFeature/CopyFeature.jsx @@ -19,31 +19,23 @@ import { trim } from '../../../common/util'; import ConditionallyRender from '../../../common/ConditionallyRender'; import { Alert } from '@material-ui/lab'; import { getTogglePath } from '../../../../utils/route-path-helpers'; +import useFeatureApi from '../../../../hooks/api/actions/useFeatureApi/useFeatureApi'; +import useFeature from '../../../../hooks/api/getters/useFeature/useFeature'; const CopyFeature = props => { // static displayName = `AddFeatureComponent-${getDisplayName(Component)}`; const [replaceGroupId, setReplaceGroupId] = useState(true); const [apiError, setApiError] = useState(''); - const [copyToggle, setCopyToggle] = useState(); const [nameError, setNameError] = useState(undefined); const [newToggleName, setNewToggleName] = useState(); + const { cloneFeatureToggle } = useFeatureApi(); const inputRef = useRef(); - const { name } = useParams(); - const copyToggleName = name; - - const { features } = props; + const { name: copyToggleName, id: projectId } = useParams(); + const { feature } = useFeature(projectId, copyToggleName); useEffect(() => { - const copyToggle = features.find(item => item.name === copyToggleName); - if (copyToggle) { - setCopyToggle(copyToggle); - - inputRef.current?.focus(); - } else { - props.fetchFeatureToggles(); - } - /* eslint-disable-next-line */ - }, [features.length]); + inputRef.current?.focus(); + }, []); const setValue = evt => { const value = trim(evt.target.value); @@ -71,31 +63,21 @@ const CopyFeature = props => { return; } - const { history } = props; - copyToggle.name = newToggleName; - - if (replaceGroupId) { - copyToggle.strategies.forEach(s => { - if (s.parameters && s.parameters.groupId) { - s.parameters.groupId = newToggleName; - } - }); - } - try { - props - .createFeatureToggle(copyToggle) - .then(() => - history.push( - getTogglePath(copyToggle.project, copyToggle.name) - ) - ); + await cloneFeatureToggle( + projectId, + copyToggleName, + { name: newToggleName, replaceGroupId } + ); + props.history.push( + getTogglePath(projectId, newToggleName) + ) } catch (e) { setApiError(e); } }; - if (!copyToggle) return Toggle not found; + if (!feature || !feature.name) return Toggle not found; return ( { style={{ overflow: 'visible' }} >
-

Copy {copyToggle.name}

+

Copy {copyToggleName}

{ You are about to create a new feature toggle by cloning the configuration of feature toggle  - {copyToggle.name} + {copyToggleName} . You must give the new feature toggle a unique name before you can proceed. @@ -157,10 +139,7 @@ const CopyFeature = props => { }; CopyFeature.propTypes = { - copyToggle: PropTypes.object, history: PropTypes.object.isRequired, - createFeatureToggle: PropTypes.func.isRequired, - fetchFeatureToggles: PropTypes.func.isRequired, validateName: PropTypes.func.isRequired, }; diff --git a/frontend/src/component/feature/create/CopyFeature/index.jsx b/frontend/src/component/feature/create/CopyFeature/index.jsx index 427bec1b56..a1e07db14d 100644 --- a/frontend/src/component/feature/create/CopyFeature/index.jsx +++ b/frontend/src/component/feature/create/CopyFeature/index.jsx @@ -1,24 +1,15 @@ import { connect } from 'react-redux'; import CopyFeatureComponent from './CopyFeature'; import { - createFeatureToggles, - validateName, - fetchFeatureToggles, + validateName } from '../../../../store/feature-toggle/actions'; const mapStateToProps = (state, props) => ({ history: props.history, - features: state.features.toJS(), - copyToggle: state.features - .toJS() - .find(toggle => toggle.name === props.copyToggleName), }); const mapDispatchToProps = dispatch => ({ validateName, - createFeatureToggle: featureToggle => - createFeatureToggles(featureToggle)(dispatch), - fetchFeatureToggles: () => fetchFeatureToggles()(dispatch), }); const FormAddContainer = connect( diff --git a/frontend/src/hooks/api/actions/useFeatureApi/useFeatureApi.ts b/frontend/src/hooks/api/actions/useFeatureApi/useFeatureApi.ts index 55822a5b7e..87fa316087 100644 --- a/frontend/src/hooks/api/actions/useFeatureApi/useFeatureApi.ts +++ b/frontend/src/hooks/api/actions/useFeatureApi/useFeatureApi.ts @@ -143,6 +143,26 @@ const useFeatureApi = () => { } }; + const cloneFeatureToggle = async ( + projectId: string, + featureId: string, + payload: {name: string, replaceGroupId: boolean} + ) => { + const path = `api/admin/projects/${projectId}/features/${featureId}/clone`; + const req = createRequest( + path, + { method: 'POST', body: JSON.stringify(payload) }, + ); + + try { + const res = await makeRequest(req.caller, req.id); + + return res; + } catch (e) { + throw e; + } + }; + return { changeFeatureProject, errors, @@ -152,6 +172,7 @@ const useFeatureApi = () => { deleteTagFromFeature, archiveFeatureToggle, patchFeatureToggle, + cloneFeatureToggle }; }; diff --git a/frontend/src/hooks/api/getters/useFeature/useFeature.ts b/frontend/src/hooks/api/getters/useFeature/useFeature.ts index de83e101f8..8c96c83938 100644 --- a/frontend/src/hooks/api/getters/useFeature/useFeature.ts +++ b/frontend/src/hooks/api/getters/useFeature/useFeature.ts @@ -17,13 +17,29 @@ const useFeature = ( id: string, options: IUseFeatureOptions = {} ) => { - const fetcher = () => { + const fetcher = async () => { const path = formatApiPath( `api/admin/projects/${projectId}/features/${id}` ); - return fetch(path, { + + const res = await fetch(path, { method: 'GET', - }).then(res => res.json()); + }); + + + // If the status code is not in the range 200-299, + // we still try to parse and throw it. + if (!res.ok) { + const error = new Error('An error occurred while fetching the data.') + // Attach extra info to the error object. + // @ts-ignore + error.info = await res.json(); + // @ts-ignore + error.status = res.status; + throw error; + } + + return res.json() }; const FEATURE_CACHE_KEY = `api/admin/projects/${projectId}/features/${id}`;