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

Feat: show change request data on segment project usage page (#5410)

Show usage in change requests if that'd cause you to not be able to move
the segment into a project.

- [x] ~Relies on changes from #5407 (and #5405, #5406) to go through
first.~


![image](https://github.com/Unleash/unleash/assets/17786332/e6b84664-db86-457e-885f-a86c95bc46ec)
This commit is contained in:
Thomas Heartman 2023-11-28 10:01:56 +01:00 committed by GitHub
parent 38a1fda28c
commit dba1c90db8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 157 additions and 24 deletions

View File

@ -12,8 +12,14 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { useOptionalPathParam } from 'hooks/useOptionalPathParam';
import { GO_BACK } from 'constants/navigate';
import { useStrategiesBySegment } from 'hooks/api/getters/useStrategiesBySegment/useStrategiesBySegment';
import {
ChangeRequestNewStrategy,
ChangeRequestUpdatedStrategy,
useStrategiesBySegment,
} from 'hooks/api/getters/useStrategiesBySegment/useStrategiesBySegment';
import { SegmentProjectAlert } from './SegmentProjectAlert';
import { sortStrategiesByFeature } from './SegmentDelete/SegmentDeleteUsedSegment/sort-strategies';
import { IFeatureStrategy } from 'interfaces/strategy';
interface ISegmentFormPartOneProps {
name: string;
@ -71,11 +77,20 @@ export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
const navigate = useNavigate();
const { projects, loading: loadingProjects } = useProjects();
const { strategies, loading: loadingStrategies } =
useStrategiesBySegment(segmentId);
const {
strategies,
changeRequestStrategies,
loading: loadingStrategies,
} = useStrategiesBySegment(segmentId);
const collectedStrategies = sortStrategiesByFeature<
IFeatureStrategy,
ChangeRequestUpdatedStrategy,
ChangeRequestNewStrategy
>(strategies ?? [], changeRequestStrategies ?? []);
const projectsUsed = new Set<string>(
strategies.map(({ projectId }) => projectId!).filter(Boolean),
collectedStrategies.map(({ projectId }) => projectId!).filter(Boolean),
);
const availableProjects = projects.filter(
({ id }) =>
@ -142,7 +157,7 @@ export const SegmentFormStepOne: React.FC<ISegmentFormPartOneProps> = ({
/>
<SegmentProjectAlert
projects={projects}
strategies={strategies}
strategies={collectedStrategies}
projectsUsed={Array.from(projectsUsed)}
availableProjects={availableProjects}
/>

View File

@ -0,0 +1,60 @@
import React from 'react';
import { render } from 'utils/testRenderer';
import { screen } from '@testing-library/react';
import { SegmentProjectAlert } from './SegmentProjectAlert';
describe('SegmentDeleteUsedSegment', () => {
it('should link to change requests for change request strategies', async () => {
const projectId = 'project1';
const strategies = [
{
projectId,
featureName: 'feature1',
strategyName: 'flexible rollout',
environment: 'default',
changeRequest: { id: 1, title: null },
},
{
projectId,
featureName: 'feature1',
strategyName: 'flexible rollout',
environment: 'default',
changeRequest: { id: 2, title: 'My cool CR' },
},
];
const projectsUsed = [...new Set(strategies.map((s) => s.projectId))];
render(
<SegmentProjectAlert
projects={[]}
availableProjects={[]}
projectsUsed={projectsUsed}
strategies={strategies}
/>,
);
const links = await screen.findAllByRole('link');
expect(links).toHaveLength(strategies.length + projectsUsed.length);
const [projectLink, crLink1, crLink2] = links;
expect(projectLink).toHaveTextContent(projectId);
expect(projectLink).toHaveAttribute('href', `/projects/${projectId}`);
expect(crLink1).toHaveTextContent('#1');
expect(crLink1).toHaveAccessibleDescription('Change request 1');
expect(crLink1).toHaveAttribute(
'href',
`/projects/${projectId}/change-requests/1`,
);
expect(crLink2).toHaveTextContent('#2 (My cool CR)');
expect(crLink2).toHaveAccessibleDescription('Change request 2');
expect(crLink2).toHaveAttribute(
'href',
`/projects/${projectId}/change-requests/2`,
);
});
});

View File

@ -6,6 +6,11 @@ import { Link } from 'react-router-dom';
import { formatStrategyName } from 'utils/strategyNames';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import {
ChangeRequestNewStrategy,
ChangeRequestStrategy,
ChangeRequestUpdatedStrategy,
} from 'hooks/api/getters/useStrategiesBySegment/useStrategiesBySegment';
const StyledUl = styled('ul')(({ theme }) => ({
listStyle: 'none',
@ -18,7 +23,11 @@ const StyledAlert = styled(Alert)(({ theme }) => ({
interface ISegmentProjectAlertProps {
projects: IProjectCard[];
strategies: IFeatureStrategy[];
strategies: (
| IFeatureStrategy
| ChangeRequestUpdatedStrategy
| ChangeRequestNewStrategy
)[];
projectsUsed: string[];
availableProjects: IProjectCard[];
}
@ -56,23 +65,9 @@ export const SegmentProjectAlert = ({
?.filter(
(strategy) => strategy.projectId === projectId,
)
.map((strategy) => (
<li key={strategy.id}>
<Link
to={formatEditStrategyPath(
strategy.projectId!,
strategy.featureName!,
strategy.environment!,
strategy.id,
.map((strategy, index) =>
strategyListItem(strategy, index),
)}
target='_blank'
rel='noreferrer'
>
{strategy.featureName!}{' '}
{formatStrategyNameParens(strategy)}
</Link>
</li>
))}
</ul>
</li>
))}
@ -100,10 +95,73 @@ export const SegmentProjectAlert = ({
return null;
};
const formatStrategyNameParens = (strategy: IFeatureStrategy): string => {
const formatStrategyNameParens = (strategy: {
strategyName?: string;
}): string => {
if (!strategy.strategyName) {
return '';
}
return `(${formatStrategyName(strategy.strategyName)})`;
};
export const formatChangeRequestPath = (
projectId: string,
changeRequestId: number,
): string => {
return `/projects/${projectId}/change-requests/${changeRequestId}`;
};
const strategyListItem = (
strategy:
| IFeatureStrategy
| ChangeRequestUpdatedStrategy
| ChangeRequestNewStrategy,
index: number,
) => {
const isChangeRequest = (
strategy: IFeatureStrategy | ChangeRequestStrategy,
): strategy is ChangeRequestStrategy => 'changeRequest' in strategy;
if (isChangeRequest(strategy)) {
const { id, title } = strategy.changeRequest;
const text = title ? `#${id} (${title})` : `#${id}`;
return (
<li key={`#${strategy.changeRequest.id}@${index}`}>
<p>
{strategy.featureName}{' '}
{`${formatStrategyNameParens(
strategy,
)} in change request `}
<Link
to={formatChangeRequestPath(strategy.projectId, id)}
target='_blank'
rel='noopener noreferrer'
title={`Change request ${id}`}
>
{text}
</Link>
</p>
</li>
);
} else {
return (
<li key={strategy.id}>
<Link
to={formatEditStrategyPath(
strategy.projectId!,
strategy.featureName!,
strategy.environment!,
strategy.id,
)}
target='_blank'
rel='noopener noreferrer'
>
{strategy.featureName!} {formatStrategyNameParens(strategy)}
</Link>
</li>
);
}
};