1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

feat: show Changes scheduled in feature variants even when CR are dis… (#5613)

show Changes scheduled in feature variants even when CR are disabled

Modifies existing hook to call the new `change-requests/scheduled`
endpoint that returns the relevant scheduled change requests even when
change requests are disabled

Rename the ChangeRequestIdentityData to ScheduledChangeRequestViewModel
for consistency (finalised schemas will replace the BE and FE types in a
follow up PR)

Closes #
[1-1746](https://linear.app/unleash/issue/1-1746/show-change-scheduled-badge-in-feature-environment-variants-even-if)

<img width="1486" alt="Screenshot 2023-12-12 at 14 24 44"
src="https://github.com/Unleash/unleash/assets/104830839/7c4e92ef-81d8-423e-8b78-9015ede59952">

---------

Signed-off-by: andreas-unleash <andreas@getunleash.ai>
This commit is contained in:
andreas-unleash 2023-12-12 15:34:32 +02:00 committed by GitHub
parent bc62a98f51
commit 4376697250
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 94 additions and 41 deletions

View File

@ -11,10 +11,8 @@ import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
import { usePendingChangeRequests } from 'hooks/api/getters/usePendingChangeRequests/usePendingChangeRequests';
import { useHighestPermissionChangeRequestEnvironment } from 'hooks/useHighestPermissionChangeRequestEnvironment';
import {
ChangeRequestIdentityData,
useScheduledChangeRequestsWithFlags,
} from 'hooks/api/getters/useScheduledChangeRequestsWithFlags/useScheduledChangeRequestsWithFlags';
import { useScheduledChangeRequestsWithFlags } from 'hooks/api/getters/useScheduledChangeRequestsWithFlags/useScheduledChangeRequestsWithFlags';
import { ScheduledChangeRequestViewModel } from 'hooks/api/getters/useScheduledChangeRequestsWithStrategy/useScheduledChangeRequestsWithStrategy';
interface IFeatureArchiveDialogProps {
isOpen: boolean;
@ -128,7 +126,7 @@ const ArchiveParentError = ({
};
const ScheduledChangeRequestAlert: VFC<{
changeRequests?: ChangeRequestIdentityData[];
changeRequests?: ScheduledChangeRequestViewModel[];
projectId: string;
}> = ({ changeRequests, projectId }) => {
if (changeRequests && changeRequests.length > 0) {

View File

@ -14,7 +14,7 @@ import { ChangesScheduledBadge } from 'component/changeRequest/ModifiedInChangeR
import { IFeatureChange } from 'component/changeRequest/changeRequest.types';
import { Badge } from 'component/common/Badge/Badge';
import {
ChangeRequestIdentityData,
ScheduledChangeRequestViewModel,
useScheduledChangeRequestsWithStrategy,
} from 'hooks/api/getters/useScheduledChangeRequestsWithStrategy/useScheduledChangeRequestsWithStrategy';
@ -114,7 +114,7 @@ const ChangeRequestStatusBadge = ({
const renderHeaderChildren = (
changes?: UseStrategyChangeFromRequestResult,
scheduledChanges?: ChangeRequestIdentityData[],
scheduledChanges?: ScheduledChangeRequestViewModel[],
): JSX.Element[] => {
const badges: JSX.Element[] = [];
if (changes?.length === 0 && scheduledChanges?.length === 0) {

View File

@ -136,6 +136,25 @@ const changeRequestConfig = () =>
'get',
);
const disableChangeRequests = () =>
testServerRoute(
server,
'/api/admin/projects/default/change-requests/config',
[
{
environment: 'development',
type: 'development',
changeRequestEnabled: false,
},
{
environment: 'production',
type: 'production',
changeRequestEnabled: false,
},
],
'get',
);
const feature = () => {
testServerRoute(server, '/api/admin/projects/default/features/feature1', {
environments: [
@ -246,7 +265,28 @@ describe('Change request badges for variants', () => {
testServerRoute(
server,
'/api/admin/projects/default/change-requests/pending/feature1',
'/api/admin/projects/default/change-requests/scheduled',
[changeRequest],
);
render(<Component />, {
route: '/projects/default/features/feature1/variants',
permissions: [
{
permission: ADMIN,
},
],
});
await screen.findByText('Changes Scheduled');
});
test('should render the badge when scheduled request with "patchVariant" action when change requests are disabled', async () => {
disableChangeRequests();
const changeRequest = scheduledRequest('patchVariant', 1);
testServerRoute(
server,
'/api/admin/projects/default/change-requests/scheduled',
[changeRequest],
);

View File

@ -1,39 +1,25 @@
import { usePendingChangeRequestsForFeature } from 'hooks/api/getters/usePendingChangeRequestsForFeature/usePendingChangeRequestsForFeature';
import { useScheduledChangeRequestsWithVariant } from 'hooks/api/getters/useScheduledChangeRequestsWithVariants/useScheduledChangeRequestsWithVariant';
export const useVariantsFromScheduledRequests = (
projectId: string,
featureId: string,
environment: string,
): number[] => {
const { changeRequests } = usePendingChangeRequestsForFeature(
const { changeRequests } = useScheduledChangeRequestsWithVariant(
projectId,
featureId,
);
const scheduledEnvironmentRequests =
changeRequests?.filter(
(request) =>
request.environment === environment &&
request.state === 'Scheduled',
) || [];
const filtered = changeRequests?.filter(
(changeRequestIdentity) =>
changeRequestIdentity.environment === environment,
);
const result: number[] = [];
if (scheduledEnvironmentRequests.length === 0) {
return result;
if (filtered) {
return filtered.map(
(changeRequestIdentity) => changeRequestIdentity.id,
);
}
scheduledEnvironmentRequests.forEach((scheduledRequest) => {
const feature = scheduledRequest?.features.find(
(feature) => feature.name === featureId,
);
const change = feature?.changes.find((change) => {
return change.action === 'patchVariant';
});
if (change) {
result.push(scheduledRequest.id);
}
});
return result;
return [];
};

View File

@ -1,6 +1,7 @@
import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler';
import { useEnterpriseSWR } from '../useEnterpriseSWR/useEnterpriseSWR';
import { ScheduledChangeRequestViewModel } from '../useScheduledChangeRequestsWithStrategy/useScheduledChangeRequestsWithStrategy';
const fetcher = (path: string) => {
return fetch(path)
@ -8,11 +9,6 @@ const fetcher = (path: string) => {
.then((res) => res.json());
};
export type ChangeRequestIdentityData = {
id: number;
title?: string;
};
export const useScheduledChangeRequestsWithFlags = (
project: string,
flags: string[],
@ -20,7 +16,7 @@ export const useScheduledChangeRequestsWithFlags = (
const queryString = flags.map((flag) => `feature=${flag}`).join('&');
const { data, error, mutate } = useEnterpriseSWR<
ChangeRequestIdentityData[]
ScheduledChangeRequestViewModel[]
>(
[],
formatApiPath(

View File

@ -8,8 +8,9 @@ const fetcher = (path: string) => {
.then((res) => res.json());
};
export type ChangeRequestIdentityData = {
export type ScheduledChangeRequestViewModel = {
id: number;
environment: string;
title?: string;
};
@ -18,7 +19,7 @@ export const useScheduledChangeRequestsWithStrategy = (
strategyId: string,
) => {
const { data, error, mutate } = useEnterpriseSWR<
ChangeRequestIdentityData[]
ScheduledChangeRequestViewModel[]
>(
[],
formatApiPath(

View File

@ -0,0 +1,32 @@
import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler';
import { useEnterpriseSWR } from '../useEnterpriseSWR/useEnterpriseSWR';
import { ScheduledChangeRequestViewModel } from '../useScheduledChangeRequestsWithStrategy/useScheduledChangeRequestsWithStrategy';
const fetcher = (path: string) => {
return fetch(path)
.then(handleErrorResponses('ChangeRequest'))
.then((res) => res.json());
};
export const useScheduledChangeRequestsWithVariant = (
project: string,
feature: string,
) => {
const { data, error, mutate } = useEnterpriseSWR<
ScheduledChangeRequestViewModel[]
>(
[],
formatApiPath(
`api/admin/projects/${project}/change-requests/scheduled?variantForFlag=${feature}`,
),
fetcher,
);
return {
changeRequests: data,
loading: !error && !data,
refetch: mutate,
error,
};
};