1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

fix: add clone feature toggle via API

This commit is contained in:
Ivar Conradi Østhus 2021-10-07 23:04:14 +02:00
parent 326b14fcec
commit 7406cbbaa7
4 changed files with 60 additions and 53 deletions

View File

@ -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 <span>Toggle not found</span>;
if (!feature || !feature.name) return <span>Toggle not found</span>;
return (
<Paper
@ -103,7 +85,7 @@ const CopyFeature = props => {
style={{ overflow: 'visible' }}
>
<div className={styles.header}>
<h1>Copy&nbsp;{copyToggle.name}</h1>
<h1>Copy&nbsp;{copyToggleName}</h1>
</div>
<ConditionallyRender
condition={apiError}
@ -114,9 +96,9 @@ const CopyFeature = props => {
You are about to create a new feature toggle by cloning the
configuration of feature toggle&nbsp;
<Link
to={getTogglePath(copyToggle.project, copyToggle.name)}
to={getTogglePath(projectId, copyToggleName)}
>
{copyToggle.name}
{copyToggleName}
</Link>
. 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,
};

View File

@ -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(

View File

@ -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
};
};

View File

@ -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}`;