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:
parent
326b14fcec
commit
7406cbbaa7
@ -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 {copyToggle.name}</h1>
|
||||
<h1>Copy {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
|
||||
<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,
|
||||
};
|
||||
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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}`;
|
||||
|
Loading…
Reference in New Issue
Block a user