mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
feat: delete dependnecy button through change request (#4983)
This commit is contained in:
parent
0c069b1385
commit
2f84ac88e6
@ -9,11 +9,63 @@ import { useFeature } from 'hooks/api/getters/useFeature/useFeature';
|
||||
import { ChildrenTooltip } from './ChildrenTooltip';
|
||||
import PermissionButton from 'component/common/PermissionButton/PermissionButton';
|
||||
import { UPDATE_FEATURE_DEPENDENCY } from 'component/providers/AccessProvider/permissions';
|
||||
import { useCheckProjectPermissions } from 'hooks/useHasAccess';
|
||||
import { useCheckProjectAccess } from 'hooks/useHasAccess';
|
||||
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
|
||||
import { usePendingChangeRequests } from 'hooks/api/getters/usePendingChangeRequests/usePendingChangeRequests';
|
||||
import useToast from 'hooks/useToast';
|
||||
import { useHighestPermissionChangeRequestEnvironment } from 'hooks/useHighestPermissionChangeRequestEnvironment';
|
||||
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
|
||||
const useDeleteDependency = (project: string, featureId: string) => {
|
||||
const { addChange } = useChangeRequestApi();
|
||||
const { refetch: refetchChangeRequests } =
|
||||
usePendingChangeRequests(project);
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const { refetchFeature } = useFeature(project, featureId);
|
||||
const environment = useHighestPermissionChangeRequestEnvironment(project)();
|
||||
const { isChangeRequestConfiguredInAnyEnv } =
|
||||
useChangeRequestsEnabled(project);
|
||||
const { removeDependencies } = useDependentFeaturesApi(project);
|
||||
|
||||
const handleAddChange = async () => {
|
||||
if (!environment) {
|
||||
console.error('No change request environment');
|
||||
return;
|
||||
}
|
||||
await addChange(project, environment, [
|
||||
{
|
||||
action: 'deleteDependency',
|
||||
feature: featureId,
|
||||
payload: undefined,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
const deleteDependency = async () => {
|
||||
try {
|
||||
if (isChangeRequestConfiguredInAnyEnv()) {
|
||||
await handleAddChange();
|
||||
setToastData({
|
||||
text: `${featureId} dependency will be removed`,
|
||||
type: 'success',
|
||||
title: 'Change added to a draft',
|
||||
});
|
||||
await refetchChangeRequests();
|
||||
} else {
|
||||
await removeDependencies(featureId);
|
||||
setToastData({ title: 'Dependency removed', type: 'success' });
|
||||
await refetchFeature();
|
||||
}
|
||||
} catch (error) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
}
|
||||
};
|
||||
|
||||
return deleteDependency;
|
||||
};
|
||||
|
||||
export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => {
|
||||
const { removeDependencies } = useDependentFeaturesApi(feature.project);
|
||||
const { refetchFeature } = useFeature(feature.project, feature.name);
|
||||
const [showDependencyDialogue, setShowDependencyDialogue] = useState(false);
|
||||
const canAddParentDependency =
|
||||
Boolean(feature.project) &&
|
||||
@ -22,7 +74,11 @@ export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => {
|
||||
const hasParentDependency =
|
||||
Boolean(feature.project) && Boolean(feature.dependencies.length > 0);
|
||||
const hasChildren = Boolean(feature.project) && feature.children.length > 0;
|
||||
const checkAccess = useCheckProjectPermissions(feature.project);
|
||||
const environment = useHighestPermissionChangeRequestEnvironment(
|
||||
feature.project,
|
||||
)();
|
||||
const checkAccess = useCheckProjectAccess(feature.project);
|
||||
const deleteDependency = useDeleteDependency(feature.project, feature.name);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -59,17 +115,17 @@ export const DependencyRow: FC<{ feature: IFeatureToggle }> = ({ feature }) => {
|
||||
</StyledLink>
|
||||
</StyledDetail>
|
||||
<ConditionallyRender
|
||||
condition={checkAccess(UPDATE_FEATURE_DEPENDENCY)}
|
||||
condition={checkAccess(
|
||||
UPDATE_FEATURE_DEPENDENCY,
|
||||
environment,
|
||||
)}
|
||||
show={
|
||||
<DependencyActions
|
||||
feature={feature.name}
|
||||
onEdit={() =>
|
||||
setShowDependencyDialogue(true)
|
||||
}
|
||||
onDelete={async () => {
|
||||
await removeDependencies(feature.name);
|
||||
await refetchFeature();
|
||||
}}
|
||||
onDelete={deleteDependency}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
@ -4,6 +4,7 @@ import { render } from 'utils/testRenderer';
|
||||
import { FeatureOverviewSidePanelDetails } from './FeatureOverviewSidePanelDetails';
|
||||
import { IDependency, IFeatureToggle } from 'interfaces/featureToggle';
|
||||
import { testServerRoute, testServerSetup } from 'utils/testServer';
|
||||
import ToastRenderer from 'component/common/ToastRenderer/ToastRenderer';
|
||||
|
||||
const server = testServerSetup();
|
||||
|
||||
@ -12,6 +13,9 @@ const setupApi = () => {
|
||||
flags: {
|
||||
dependentFeatures: true,
|
||||
},
|
||||
versionInfo: {
|
||||
current: { oss: 'irrelevant', enterprise: 'some value' },
|
||||
},
|
||||
});
|
||||
testServerRoute(server, '/api/admin/projects/default/features/feature', {});
|
||||
testServerRoute(
|
||||
@ -19,6 +23,40 @@ const setupApi = () => {
|
||||
'/api/admin/projects/default/features/feature/parents',
|
||||
{},
|
||||
);
|
||||
testServerRoute(
|
||||
server,
|
||||
'/api/admin/projects/default/features/feature/dependencies',
|
||||
{},
|
||||
'delete',
|
||||
200,
|
||||
);
|
||||
};
|
||||
|
||||
const setupChangeRequestApi = () => {
|
||||
testServerRoute(
|
||||
server,
|
||||
'/api/admin/projects/default/change-requests/config',
|
||||
[
|
||||
{
|
||||
environment: 'development',
|
||||
type: 'development',
|
||||
requiredApprovals: null,
|
||||
changeRequestEnabled: true,
|
||||
},
|
||||
],
|
||||
);
|
||||
testServerRoute(
|
||||
server,
|
||||
'api/admin/projects/default/change-requests/pending',
|
||||
[],
|
||||
);
|
||||
testServerRoute(
|
||||
server,
|
||||
'api/admin/projects/default/environments/development/change-requests',
|
||||
{},
|
||||
'post',
|
||||
200,
|
||||
);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
@ -94,17 +132,20 @@ test('show children', async () => {
|
||||
|
||||
test('delete dependency', async () => {
|
||||
render(
|
||||
<FeatureOverviewSidePanelDetails
|
||||
feature={
|
||||
{
|
||||
name: 'feature',
|
||||
project: 'default',
|
||||
dependencies: [{ feature: 'some_parent' }],
|
||||
children: [] as string[],
|
||||
} as IFeatureToggle
|
||||
}
|
||||
header={''}
|
||||
/>,
|
||||
<>
|
||||
<ToastRenderer />
|
||||
<FeatureOverviewSidePanelDetails
|
||||
feature={
|
||||
{
|
||||
name: 'feature',
|
||||
project: 'default',
|
||||
dependencies: [{ feature: 'some_parent' }],
|
||||
children: [] as string[],
|
||||
} as IFeatureToggle
|
||||
}
|
||||
header={''}
|
||||
/>
|
||||
</>,
|
||||
{
|
||||
permissions: [
|
||||
{ permission: 'UPDATE_FEATURE_DEPENDENCY', project: 'default' },
|
||||
@ -122,6 +163,46 @@ test('delete dependency', async () => {
|
||||
|
||||
const deleteButton = await screen.findByText('Delete');
|
||||
userEvent.click(deleteButton);
|
||||
|
||||
await screen.findByText('Dependency removed');
|
||||
});
|
||||
|
||||
test('delete dependency with change request', async () => {
|
||||
setupChangeRequestApi();
|
||||
render(
|
||||
<>
|
||||
<ToastRenderer />
|
||||
<FeatureOverviewSidePanelDetails
|
||||
feature={
|
||||
{
|
||||
name: 'feature',
|
||||
project: 'default',
|
||||
dependencies: [{ feature: 'some_parent' }],
|
||||
children: [] as string[],
|
||||
} as IFeatureToggle
|
||||
}
|
||||
header={''}
|
||||
/>
|
||||
</>,
|
||||
{
|
||||
permissions: [
|
||||
/* deliberately no permissions */
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
await screen.findByText('Dependency:');
|
||||
await screen.findByText('some_parent');
|
||||
|
||||
const actionsButton = await screen.findByRole('button', {
|
||||
name: /Dependency actions/i,
|
||||
});
|
||||
userEvent.click(actionsButton);
|
||||
|
||||
const deleteButton = await screen.findByText('Delete');
|
||||
userEvent.click(deleteButton);
|
||||
|
||||
await screen.findByText('Change added to a draft');
|
||||
});
|
||||
|
||||
test('edit dependency', async () => {
|
||||
@ -147,7 +228,7 @@ test('edit dependency', async () => {
|
||||
await screen.findByText('Dependency:');
|
||||
await screen.findByText('some_parent');
|
||||
|
||||
const actionsButton = screen.getByRole('button', {
|
||||
const actionsButton = await screen.findByRole('button', {
|
||||
name: /Dependency actions/i,
|
||||
});
|
||||
userEvent.click(actionsButton);
|
||||
|
@ -60,9 +60,9 @@ export const useCheckProjectAccess = (projectId: string) => {
|
||||
const { isChangeRequestConfigured } = useChangeRequestsEnabled(projectId);
|
||||
const checkAccess = useCheckProjectPermissions(projectId);
|
||||
|
||||
return (permission: string, environment: string) => {
|
||||
return (permission: string, environment?: string) => {
|
||||
return (
|
||||
isChangeRequestConfigured(environment) ||
|
||||
(environment && isChangeRequestConfigured(environment)) ||
|
||||
checkAccess(permission, environment)
|
||||
);
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user