1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-20 00:08:02 +01:00

refactor: use union types for change request types (#5870)

This changes the two interfaces IChangeRequest and
IChangeRequestSchedule to be union types instead of interfaces. It also
extracts the constituents of those union types into proper types
themselves (so that they can be used in function type signatures etc).
It also updates the type names.

This turned out to be more work than I had imagined, but I think the end
result pays off, giving us more type safety and control.

I wanted to use just `ChangeRequest` for the IChangeRequest type, but
that caused issues due to naming collisions with the `ChangeRequest`
component that we have, causing tests to fail. I've named it
`ChangeRequestType` as a potential solution, but suggestions are
welcome.

The relevant changes are in
`frontend/src/component/changeRequest/changeRequest.types.ts`.
Everything else is updated references and some necessary refactoring to
respect the new types.
This commit is contained in:
Thomas Heartman 2024-01-12 13:15:43 +05:30 committed by GitHub
parent 6ba4591c7f
commit 39145e2617
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 214 additions and 122 deletions

View File

@ -5,7 +5,7 @@ import { Route, Routes } from 'react-router-dom';
import { render } from 'utils/testRenderer';
import { ChangeRequest } from './ChangeRequest';
import {
IChangeRequest,
ChangeRequestType,
IChangeRequestAddStrategy,
IChangeRequestEnabled,
} from '../changeRequest.types';
@ -98,7 +98,7 @@ const feature = () =>
const changeRequestWithDefaultChange = (
defaultChange: IChangeRequestEnabled | IChangeRequestAddStrategy,
) => {
const changeRequest: IChangeRequest = {
const changeRequest: ChangeRequestType = {
approvals: [],
rejections: [],
comments: [],
@ -142,7 +142,7 @@ const changeRequestWithDefaultChange = (
};
const changeRequest = (variants: StrategyVariantSchema[]) => {
const changeRequest: IChangeRequest = {
const changeRequest: ChangeRequestType = {
approvals: [],
rejections: [],
comments: [],

View File

@ -1,6 +1,6 @@
import { VFC } from 'react';
import { Box, Typography } from '@mui/material';
import type { IChangeRequest } from '../changeRequest.types';
import type { ChangeRequestType } from '../changeRequest.types';
import { FeatureToggleChanges } from './Changes/FeatureToggleChanges';
import { FeatureChange } from './Changes/Change/FeatureChange';
import { ChangeActions } from './Changes/Change/ChangeActions';
@ -8,7 +8,7 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
import { SegmentChange } from './Changes/Change/SegmentChange';
interface IChangeRequestProps {
changeRequest: IChangeRequest;
changeRequest: ChangeRequestType;
onRefetch?: () => void;
onNavigate?: () => void;
}

View File

@ -1,6 +1,6 @@
import React, { FC, useState } from 'react';
import {
IChangeRequest,
ChangeRequestType,
IChangeRequestAddStrategy,
IChangeRequestUpdateStrategy,
IChange,
@ -28,7 +28,7 @@ import { EditChange } from './EditChange';
import { useUiFlag } from 'hooks/useUiFlag';
import { NewEditChange } from './NewEditChange';
const useShowActions = (changeRequest: IChangeRequest, change: IChange) => {
const useShowActions = (changeRequest: ChangeRequestType, change: IChange) => {
const { isChangeRequestConfigured } = useChangeRequestsEnabled(
changeRequest.project,
);
@ -60,7 +60,7 @@ const StyledPopover = styled(Popover)(({ theme }) => ({
}));
export const ChangeActions: FC<{
changeRequest: IChangeRequest;
changeRequest: ChangeRequestType;
feature: string;
change: IChange;
onRefetch?: () => void;

View File

@ -3,6 +3,7 @@ import { screen } from '@testing-library/react';
import { FeatureChange } from './FeatureChange';
import {
ChangeRequestState,
ChangeRequestType,
IChangeRequestFeature,
IFeatureChange,
} from 'component/changeRequest/changeRequest.types';
@ -40,21 +41,39 @@ describe('Schedule conflicts', () => {
});
const changeRequest =
(feature: IChangeRequestFeature) => (state: ChangeRequestState) => ({
id: 1,
state,
title: '',
project: 'default',
environment: 'default',
minApprovals: 1,
createdBy: { id: 1, username: 'user1', imageUrl: '' },
createdAt: new Date(),
features: [feature],
segments: [],
approvals: [],
rejections: [],
comments: [],
});
(feature: IChangeRequestFeature) =>
(state: ChangeRequestState): ChangeRequestType => {
const shared = {
id: 1,
title: '',
project: 'default',
environment: 'default',
minApprovals: 1,
createdBy: { id: 1, username: 'user1', imageUrl: '' },
createdAt: new Date(),
features: [feature],
segments: [],
approvals: [],
rejections: [],
comments: [],
};
if (state === 'Scheduled') {
return {
...shared,
state,
schedule: {
scheduledAt: '2024-01-12T09:46:51+05:30',
status: 'pending',
},
};
}
return {
...shared,
state,
};
};
it.each(['Draft', 'Scheduled', 'In review', 'Approved'])(
'should show schedule conflicts (when they exist) for change request in the %s state',

View File

@ -1,7 +1,7 @@
import { FC, ReactNode } from 'react';
import {
IFeatureChange,
IChangeRequest,
ChangeRequestType,
IChangeRequestFeature,
} from '../../../changeRequest.types';
import { objectId } from 'utils/objectId';
@ -69,7 +69,7 @@ const InlineList = styled('ul')(({ theme }) => ({
export const FeatureChange: FC<{
actions: ReactNode;
index: number;
changeRequest: IChangeRequest;
changeRequest: ChangeRequestType;
change: IFeatureChange;
feature: IChangeRequestFeature;
onNavigate?: () => void;

View File

@ -2,7 +2,7 @@ import { Box } from '@mui/material';
import { FC, useState } from 'react';
import { Typography, Tooltip } from '@mui/material';
import TimeAgo from 'react-timeago';
import { IChangeRequest } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestType } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestStatusBadge } from 'component/changeRequest/ChangeRequestStatusBadge/ChangeRequestStatusBadge';
import {
StyledPaper,
@ -15,7 +15,7 @@ import { Separator } from '../../ChangeRequestSidebar/ChangeRequestSidebar';
import { ChangeRequestTitle } from '../../ChangeRequestSidebar/EnvironmentChangeRequest/ChangeRequestTitle';
import { UpdateCount } from 'component/changeRequest/UpdateCount';
export const ChangeRequestHeader: FC<{ changeRequest: IChangeRequest }> = ({
export const ChangeRequestHeader: FC<{ changeRequest: ChangeRequestType }> = ({
changeRequest,
}) => {
const [title, setTitle] = useState(changeRequest.title);

View File

@ -1,6 +1,6 @@
import { fireEvent, screen, waitFor, within } from '@testing-library/react';
import { testServerRoute, testServerSetup } from 'utils/testServer';
import { ChangeRequestState, IChangeRequest } from '../changeRequest.types';
import { ChangeRequestState, ChangeRequestType } from '../changeRequest.types';
import { render } from 'utils/testRenderer';
import { ChangeRequestOverview } from './ChangeRequestOverview';
import {
@ -14,11 +14,10 @@ const mockChangeRequest = (
featureName: string,
state: ChangeRequestState,
failureReason?: string,
): IChangeRequest => {
const result: IChangeRequest = {
): ChangeRequestType => {
const shared: Omit<ChangeRequestType, 'state' | 'schedule'> = {
id: 1,
environment: 'production',
state: state,
minApprovals: 1,
project: 'default',
createdBy: {
@ -60,26 +59,40 @@ const mockChangeRequest = (
};
if (state === 'Scheduled') {
result.schedule = {
scheduledAt: '2022-12-02T09:19:12.242Z',
status: 'pending',
if (failureReason) {
return {
...shared,
state,
schedule: {
scheduledAt: '2022-12-02T09:19:12.242Z',
status: 'failed',
reason: failureReason,
},
};
}
return {
...shared,
state,
schedule: {
scheduledAt: '2022-12-02T09:19:12.242Z',
status: 'pending',
},
};
}
if (failureReason) {
result.schedule!.failureReason = failureReason;
}
return result;
return {
...shared,
state,
};
};
const pendingChangeRequest = (changeRequest: IChangeRequest) =>
const pendingChangeRequest = (changeRequest: ChangeRequestType) =>
testServerRoute(
server,
'/api/admin/projects/default/change-requests/pending',
[changeRequest],
);
const changeRequest = (changeRequest: IChangeRequest) =>
const changeRequest = (changeRequest: ChangeRequestType) =>
testServerRoute(
server,
'/api/admin/projects/default/change-requests/1',

View File

@ -111,7 +111,9 @@ export const ChangeRequestOverview: FC = () => {
changeRequest.environment,
);
const hasSchedule = Boolean(changeRequest.schedule?.scheduledAt);
const hasSchedule = Boolean(
'schedule' in changeRequest && changeRequest.schedule?.scheduledAt,
);
const onApplyChanges = async () => {
try {
@ -259,6 +261,30 @@ export const ChangeRequestOverview: FC = () => {
const countOfChanges = changesCount(changeRequest);
const reason = (() => {
if (!('schedule' in changeRequest)) {
return undefined;
}
switch (changeRequest.schedule.status) {
case 'failed':
return (
(changeRequest.schedule.reason ||
changeRequest.schedule.failureReason) ??
undefined
);
case 'suspended':
return changeRequest.schedule.reason;
default:
return undefined;
}
})();
const scheduledAt =
'schedule' in changeRequest
? changeRequest.schedule.scheduledAt
: undefined;
return (
<>
<ChangeRequestHeader changeRequest={changeRequest} />
@ -266,8 +292,12 @@ export const ChangeRequestOverview: FC = () => {
<StyledAsideBox>
<ChangeRequestTimeline
state={changeRequest.state}
scheduledAt={changeRequest.schedule?.scheduledAt}
failureReason={changeRequest.schedule?.failureReason}
scheduledAt={
'schedule' in changeRequest
? changeRequest.schedule.scheduledAt
: undefined
}
failureReason={reason}
/>
<ChangeRequestReviewers changeRequest={changeRequest} />
</StyledAsideBox>
@ -417,10 +447,7 @@ export const ChangeRequestOverview: FC = () => {
<ConditionallyRender
condition={
scheduleChangeRequests &&
Boolean(
changeRequest.schedule
?.scheduledAt,
)
Boolean(scheduledAt)
}
show={
<StyledButton
@ -483,27 +510,22 @@ export const ChangeRequestOverview: FC = () => {
projectId={projectId}
environment={changeRequest.environment}
primaryButtonText={
changeRequest?.schedule?.scheduledAt
changeRequest.state === 'Scheduled'
? 'Update scheduled time'
: 'Schedule changes'
}
title={
changeRequest?.schedule?.scheduledAt
changeRequest.state === 'Scheduled'
? 'Update schedule'
: 'Schedule changes'
}
scheduledAt={
changeRequest?.schedule?.scheduledAt ||
undefined
}
scheduledAt={scheduledAt}
/>
<ChangeRequestApplyScheduledDialogue
open={showApplyScheduledDialog}
onConfirm={onApplyChanges}
onClose={onApplyScheduledAbort}
scheduledTime={
changeRequest?.schedule?.scheduledAt
}
scheduledTime={scheduledAt}
disabled={!allowChangeRequestActions || loading}
projectId={projectId}
environment={changeRequest.environment}
@ -512,9 +534,7 @@ export const ChangeRequestOverview: FC = () => {
open={showRejectScheduledDialog}
onConfirm={onReject}
onClose={onRejectScheduledAbort}
scheduledTime={
changeRequest?.schedule?.scheduledAt
}
scheduledTime={scheduledAt}
/>
</>
}

View File

@ -26,15 +26,16 @@ import {
} from './ChangeRequestReviewStatus.styles';
import {
ChangeRequestState,
IChangeRequest,
IChangeRequestSchedule,
ChangeRequestType,
ChangeRequestSchedule,
ChangeRequestScheduleFailed,
} from 'component/changeRequest/changeRequest.types';
import { getBrowserTimezone } from './utils';
import { ConditionallyRender } from '../../../common/ConditionallyRender/ConditionallyRender';
import { formatDateYMDHMS } from 'utils/formatDate';
interface ISuggestChangeReviewsStatusProps {
changeRequest: IChangeRequest;
changeRequest: ChangeRequestType;
onEditClick?: () => void;
}
const resolveBorder = (state: ChangeRequestState, theme: Theme) => {
@ -103,7 +104,7 @@ export const ChangeRequestReviewStatus: FC<ISuggestChangeReviewsStatusProps> =
};
interface IResolveComponentProps {
changeRequest: IChangeRequest;
changeRequest: ChangeRequestType;
onEditClick?: () => void;
}
@ -111,7 +112,7 @@ const ResolveComponent = ({
changeRequest,
onEditClick,
}: IResolveComponentProps) => {
const { state, schedule } = changeRequest;
const { state } = changeRequest;
if (!state) {
return null;
@ -134,6 +135,7 @@ const ResolveComponent = ({
}
if (state === 'Scheduled') {
const { schedule } = changeRequest;
return <Scheduled schedule={schedule} onEditClick={onEditClick} />;
}
@ -228,13 +230,11 @@ const StyledIconButton = styled(IconButton)({
});
interface IScheduledProps {
schedule?: IChangeRequest['schedule'];
schedule?: ChangeRequestSchedule;
onEditClick?: () => any;
}
const Scheduled = ({ schedule, onEditClick }: IScheduledProps) => {
const theme = useTheme();
const timezone = getBrowserTimezone();
const { locationSettings } = useLocationSettings();
if (!schedule?.scheduledAt) {
return null;
@ -258,9 +258,13 @@ const Scheduled = ({ schedule, onEditClick }: IScheduledProps) => {
<StyledScheduledBox>
<ConditionallyRender
condition={schedule?.status === 'pending'}
condition={schedule.status === 'pending'}
show={<ScheduledPending schedule={schedule} />}
elseShow={<ScheduledFailed schedule={schedule} />}
elseShow={
<ScheduledFailed
schedule={schedule as ChangeRequestScheduleFailed}
/>
}
/>
<StyledIconButton onClick={onEditClick}>
@ -273,7 +277,7 @@ const Scheduled = ({ schedule, onEditClick }: IScheduledProps) => {
const ScheduledFailed = ({
schedule,
}: { schedule: IChangeRequestSchedule }) => {
}: { schedule: ChangeRequestScheduleFailed }) => {
const theme = useTheme();
const timezone = getBrowserTimezone();
const { locationSettings } = useLocationSettings();
@ -293,7 +297,7 @@ const ScheduledFailed = ({
<Box>
<StyledReviewTitle color={theme.palette.error.main}>
Changes failed to be applied on {scheduledTime} because of{' '}
{schedule?.failureReason}
{schedule.reason ?? schedule.failureReason}
</StyledReviewTitle>
<Typography>Your timezone is {timezone}</Typography>
</Box>
@ -303,7 +307,7 @@ const ScheduledFailed = ({
const ScheduledPending = ({
schedule,
}: { schedule: IChangeRequestSchedule }) => {
}: { schedule: ChangeRequestSchedule }) => {
const theme = useTheme();
const timezone = getBrowserTimezone();
const { locationSettings } = useLocationSettings();

View File

@ -3,7 +3,7 @@ import { FC, ReactNode } from 'react';
import { ConditionallyRender } from '../../../common/ConditionallyRender/ConditionallyRender';
import { ChangeRequestRejections } from './ChangeRequestRejections';
import { ChangeRequestApprovals } from './ChangeRequestApprovals';
import { IChangeRequest } from '../../changeRequest.types';
import { ChangeRequestType } from '../../changeRequest.types';
const StyledBox = styled(Box)(({ theme }) => ({
marginBottom: theme.spacing(2),
@ -44,7 +44,7 @@ export const ChangeRequestReviewersWrapper: FC<{ header: ReactNode }> = ({
export const ChangeRequestReviewers: FC<{
changeRequest: Pick<
IChangeRequest,
ChangeRequestType,
'approvals' | 'rejections' | 'state' | 'minApprovals'
>;
}> = ({ changeRequest }) => (

View File

@ -1,7 +1,7 @@
import React, { FC, useState } from 'react';
import { Box, Button, IconButton, styled, Typography } from '@mui/material';
import Input from 'component/common/Input/Input';
import { IChangeRequest } from '../../changeRequest.types';
import { ChangeRequestType } from '../../changeRequest.types';
import { Edit } from '@mui/icons-material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useChangeRequestApi } from 'hooks/api/actions/useChangeRequestApi/useChangeRequestApi';
@ -25,7 +25,7 @@ export const StyledHeader = styled(Typography)(({ theme }) => ({
}));
export const ChangeRequestTitle: FC<{
environmentChangeRequest: IChangeRequest;
environmentChangeRequest: ChangeRequestType;
title: string;
setTitle: React.Dispatch<React.SetStateAction<string>>;
}> = ({ environmentChangeRequest, title, setTitle, children }) => {

View File

@ -7,7 +7,7 @@ import {
Typography,
useTheme,
} from '@mui/material';
import { IChangeRequest } from '../../changeRequest.types';
import { ChangeRequestType } from '../../changeRequest.types';
import { useNavigate } from 'react-router-dom';
import { ChangeRequestStatusBadge } from '../../ChangeRequestStatusBadge/ChangeRequestStatusBadge';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
@ -54,7 +54,7 @@ const ChangeRequestContent = styled(Box)(({ theme }) => ({
}));
export const EnvironmentChangeRequest: FC<{
environmentChangeRequest: IChangeRequest;
environmentChangeRequest: ChangeRequestType;
onClose: () => void;
onReview: (id: number, comment?: string) => void;
onDiscard: (id: number) => void;

View File

@ -1,14 +1,14 @@
import { FC, useState } from 'react';
import { screen } from '@testing-library/react';
import { ChangeRequestTitle } from './ChangeRequestTitle';
import { ChangeRequestState } from 'component/changeRequest/changeRequest.types';
import { UnscheduledChangeRequest } from 'component/changeRequest/changeRequest.types';
import userEvent from '@testing-library/user-event';
import { testServerRoute, testServerSetup } from 'utils/testServer';
import { render } from 'utils/testRenderer';
const changeRequest = {
const changeRequest: UnscheduledChangeRequest = {
id: 3,
state: 'Draft' as ChangeRequestState,
state: 'Draft' as const,
title: 'My title',
project: 'default',
environment: 'default',

View File

@ -1,5 +1,5 @@
import { VFC } from 'react';
import { IChangeRequest } from '../changeRequest.types';
import { ChangeRequestType } from '../changeRequest.types';
import { Badge } from 'component/common/Badge/Badge';
import {
AccessTime,
@ -11,7 +11,7 @@ import {
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
interface IChangeRequestStatusBadgeProps {
changeRequest: IChangeRequest | undefined;
changeRequest: ChangeRequestType | undefined;
}
const ReviewRequiredBadge: VFC = () => (
@ -71,12 +71,18 @@ export const ChangeRequestStatusBadge: VFC<IChangeRequestStatusBadgeProps> = ({
schedule!.scheduledAt,
).toLocaleString();
const tooltipTitle =
schedule?.status === 'pending'
? `Scheduled for ${scheduledAt}`
: `Failed on ${scheduledAt} because of ${
schedule!.failureReason
}`;
const tooltipTitle = (() => {
switch (schedule.status) {
case 'failed':
return `Failed on ${scheduledAt} because of ${
schedule.reason || schedule.failureReason
}`;
case 'suspended':
return schedule.reason;
default:
return `Scheduled for ${scheduledAt}`;
}
})();
return (
<HtmlTooltip title={tooltipTitle} arrow>

View File

@ -1,11 +1,11 @@
import { VFC } from 'react';
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
import { IChangeRequest } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestType } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestStatusBadge } from 'component/changeRequest/ChangeRequestStatusBadge/ChangeRequestStatusBadge';
interface IChangeRequestStatusCellProps {
value?: string | null; // FIXME: proper type
row: { original: IChangeRequest };
row: { original: ChangeRequestType };
}
export const ChangeRequestStatusCell: VFC<IChangeRequestStatusCellProps> = ({

View File

@ -3,7 +3,7 @@ import { IFeatureStrategy } from '../../interfaces/strategy';
import { IUser } from '../../interfaces/user';
import { SetStrategySortOrderSchema } from '../../openapi';
export interface IChangeRequest {
type BaseChangeRequest = {
id: number;
title: string;
project: string;
@ -17,15 +17,43 @@ export interface IChangeRequest {
rejections: IChangeRequestApproval[];
comments: IChangeRequestComment[];
conflict?: string;
state: ChangeRequestState;
schedule?: IChangeRequestSchedule;
}
};
export interface IChangeRequestSchedule {
export type UnscheduledChangeRequest = BaseChangeRequest & {
state: Exclude<ChangeRequestState, 'Scheduled'>;
};
export type ScheduledChangeRequest = BaseChangeRequest & {
state: 'Scheduled';
schedule: ChangeRequestSchedule;
};
export type ChangeRequestType =
| UnscheduledChangeRequest
| ScheduledChangeRequest;
export type ChangeRequestSchedulePending = {
status: 'pending';
scheduledAt: string;
status: 'pending' | 'failed';
failureReason?: string;
}
};
export type ChangeRequestScheduleFailed = {
status: 'failed';
scheduledAt: string;
failureReason?: string | null;
reason: string;
};
export type ChangeRequestScheduleSuspended = {
status: 'suspended';
scheduledAt: string;
reason: string;
};
export type ChangeRequestSchedule =
| ChangeRequestSchedulePending
| ChangeRequestScheduleFailed
| ChangeRequestScheduleSuspended;
export interface IChangeRequestEnvironmentConfig {
environment: string;

View File

@ -1,5 +1,5 @@
import { IChangeRequest } from './changeRequest.types';
import { ChangeRequestType } from './changeRequest.types';
export const changesCount = (changeRequest: IChangeRequest) =>
export const changesCount = (changeRequest: ChangeRequestType) =>
changeRequest.features.flatMap((feature) => feature.changes).length +
changeRequest.segments.length;

View File

@ -6,7 +6,7 @@ import { ADMIN } from 'component/providers/AccessProvider/permissions';
import { screen } from '@testing-library/dom';
import { Route, Routes } from 'react-router-dom';
import {
IChangeRequest,
ChangeRequestType,
ChangeRequestAction,
} from 'component/changeRequest/changeRequest.types';
@ -30,7 +30,7 @@ const strategy = {
const draftRequest = (
action: Omit<ChangeRequestAction, 'updateSegment'> = 'updateStrategy',
createdBy = 1,
): IChangeRequest => {
): ChangeRequestType => {
return {
id: 71,
title: 'Change request #71',

View File

@ -6,7 +6,7 @@ import { Dialogue } from 'component/common/Dialogue/Dialogue';
import { arraysHaveSameItems } from 'utils/arraysHaveSameItems';
import { Alert, List, ListItem, styled } from '@mui/material';
import { Link } from 'react-router-dom';
import { IChangeRequest } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestType } from 'component/changeRequest/changeRequest.types';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useChangeRequestsEnabled } from 'hooks/useChangeRequestsEnabled';
@ -29,7 +29,7 @@ interface IFeatureSettingsProjectConfirm {
onClose: () => void;
onClick: (args: any) => void;
feature: IFeatureToggle;
changeRequests: IChangeRequest[] | undefined;
changeRequests: ChangeRequestType[] | undefined;
}
const FeatureSettingsProjectConfirm = ({

View File

@ -5,7 +5,7 @@ import { screen } from '@testing-library/dom';
import { Route, Routes } from 'react-router-dom';
import {
ChangeRequestAction,
IChangeRequest,
ChangeRequestType,
} from 'component/changeRequest/changeRequest.types';
import { EnvironmentVariantsCard } from './EnvironmentVariantsCard';
import { IFeatureEnvironment } from 'interfaces/featureToggle';
@ -30,7 +30,7 @@ const strategy = {
const scheduledRequest = (
action: Omit<ChangeRequestAction, 'updateSegment'> = 'updateStrategy',
createdBy = 1,
): IChangeRequest => {
): ChangeRequestType => {
return {
id: 71,
title: 'Change request #71',

View File

@ -3,7 +3,7 @@ import { Box, Button, styled, Typography } from '@mui/material';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ChangeRequestSidebar } from 'component/changeRequest/ChangeRequestSidebar/ChangeRequestSidebar';
import { usePendingChangeRequests } from 'hooks/api/getters/usePendingChangeRequests/usePendingChangeRequests';
import { IChangeRequest } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestType } from 'component/changeRequest/changeRequest.types';
import { changesCount } from 'component/changeRequest/changesCount';
import { Sticky } from 'component/common/Sticky/Sticky';
import { useUiFlag } from 'hooks/useUiFlag';
@ -61,7 +61,7 @@ const StyledSpaciousDraftBanner = styled(Box)(({ theme }) => ({
}));
const DraftBannerContent: FC<{
changeRequests: IChangeRequest[];
changeRequests: ChangeRequestType[];
onClick: () => void;
}> = ({ changeRequests, onClick }) => {
const environments = changeRequests.map(({ environment }) => environment);
@ -165,7 +165,7 @@ export const DraftBanner: VFC<IDraftBannerProps> = ({ project }) => {
show={
<DraftBannerContent
changeRequests={
unfinishedChangeRequests as IChangeRequest[]
unfinishedChangeRequests as ChangeRequestType[]
}
onClick={() => {
setIsSidebarOpen(true);

View File

@ -1,7 +1,7 @@
import { FC } from 'react';
import useLoading from 'hooks/useLoading';
import { Box, styled, Typography } from '@mui/material';
import { IChangeRequest } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestType } from 'component/changeRequest/changeRequest.types';
import {
StyledCount,
@ -74,10 +74,12 @@ export const ChangeRequestsWidget: FC<IChangeRequestsWidgetProps> = ({
const { changeRequests, loading } = useProjectChangeRequests(projectId);
const loadingRef = useLoading(loading, `[data-loading="${LOADING_LABEL}"]`);
const toBeApplied = changeRequests?.filter(
(changeRequest: IChangeRequest) => changeRequest?.state === 'Approved',
(changeRequest: ChangeRequestType) =>
changeRequest?.state === 'Approved',
).length;
const toBeReviewed = changeRequests?.filter(
(changeRequest: IChangeRequest) => changeRequest?.state === 'In review',
(changeRequest: ChangeRequestType) =>
changeRequest?.state === 'In review',
).length;
return (

View File

@ -1,10 +1,10 @@
import useSWR from 'swr';
import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler';
import { IChangeRequest } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestType } from 'component/changeRequest/changeRequest.types';
export const useChangeRequest = (projectId: string, id: string) => {
const { data, error, mutate } = useSWR<IChangeRequest>(
const { data, error, mutate } = useSWR<ChangeRequestType>(
formatApiPath(`api/admin/projects/${projectId}/change-requests/${id}`),
fetcher,
{ refreshInterval: 15000 },

View File

@ -1,6 +1,6 @@
import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler';
import { IChangeRequest } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestType } from 'component/changeRequest/changeRequest.types';
import { useEnterpriseSWR } from '../useEnterpriseSWR/useEnterpriseSWR';
const fetcher = (path: string) => {
@ -10,7 +10,7 @@ const fetcher = (path: string) => {
};
export const usePendingChangeRequests = (project: string) => {
const { data, error, mutate } = useEnterpriseSWR<IChangeRequest[]>(
const { data, error, mutate } = useEnterpriseSWR<ChangeRequestType[]>(
[],
formatApiPath(`api/admin/projects/${project}/change-requests/pending`),
fetcher,

View File

@ -1,6 +1,6 @@
import { formatApiPath } from 'utils/formatPath';
import handleErrorResponses from '../httpErrorResponseHandler';
import { IChangeRequest } from 'component/changeRequest/changeRequest.types';
import { ChangeRequestType } from 'component/changeRequest/changeRequest.types';
import { useEnterpriseSWR } from '../useEnterpriseSWR/useEnterpriseSWR';
const fetcher = (path: string) => {
@ -13,7 +13,7 @@ export const usePendingChangeRequestsForFeature = (
project: string,
featureName: string,
) => {
const { data, error, mutate } = useEnterpriseSWR<IChangeRequest[]>(
const { data, error, mutate } = useEnterpriseSWR<ChangeRequestType[]>(
[],
formatApiPath(
`api/admin/projects/${project}/change-requests/pending/${featureName}`,

View File

@ -1,9 +1,9 @@
import { Alert } from '@mui/material';
import { oneOf } from 'utils/oneOf';
import { IChangeRequest } from '../component/changeRequest/changeRequest.types';
import { ChangeRequestType } from '../component/changeRequest/changeRequest.types';
export const useChangeRequestInReviewWarning = (
draft: IChangeRequest[] | undefined,
draft: ChangeRequestType[] | undefined,
) => {
const changeRequestInReviewOrApproved = (environment: string) => {
if (!draft) return false;