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

refactor: replace IProjectCard with openapi type (#8043)

Makes type consistent between frontend and schema generated from backend.
This commit is contained in:
Tymoteusz Czech 2024-09-02 15:25:28 +02:00 committed by GitHub
parent 0b2479517f
commit 6030900b40
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 59 additions and 67 deletions

View File

@ -36,7 +36,6 @@ test('When you have no projects, you should not get a project filter', () => {
test('When you have only one project, you should not get a project filter', () => {
const { result } = renderHook(() =>
useEventLogFilters(
// @ts-expect-error: omitting other properties we don't need
() => ({ projects: [{ id: 'a', name: 'A' }] }),
() => ({ features: [] }),
),
@ -52,9 +51,7 @@ test('When you have two one project, you should not get a project filter', () =>
useEventLogFilters(
() => ({
projects: [
// @ts-expect-error: omitting other properties we don't need
{ id: 'a', name: 'A' },
// @ts-expect-error: omitting other properties we don't need
{ id: 'b', name: 'B' },
],
}),

View File

@ -11,11 +11,11 @@ import {
type FeatureSearchResponseSchema,
type SearchFeaturesParams,
} from 'openapi';
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
import { useEventCreators } from 'hooks/api/getters/useEventCreators/useEventCreators';
export const useEventLogFilters = (
projectsHook: () => { projects: IProjectCard[] },
projectsHook: () => { projects: ProjectSchema[] },
featuresHook: (params: SearchFeaturesParams) => {
features: FeatureSearchResponseSchema[];
},
@ -27,7 +27,7 @@ export const useEventLogFilters = (
const [availableFilters, setAvailableFilters] = useState<IFilterItem[]>([]);
useEffect(() => {
const projectOptions =
projects?.map((project: IProjectCard) => ({
projects?.map((project: ProjectSchema) => ({
label: project.name,
value: project.id,
})) ?? [];

View File

@ -1,5 +1,5 @@
import useProjects from 'hooks/api/getters/useProjects/useProjects';
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
import GeneralSelect, {
type ISelectOption,
type IGeneralSelectProps,
@ -25,11 +25,11 @@ const FeatureProjectSelect = ({
return null;
}
const formatOption = (project: IProjectCard) => {
const formatOption = (project: ProjectSchema) => {
return {
key: project.id,
label: project.name,
title: project.description,
title: project.description || '',
sx: {
whiteSpace: 'pre-line',
},

View File

@ -10,10 +10,11 @@ export const useProjectColor = () => {
const projectsSortedByCreatedAt = useMemo(
() =>
projects
.sort(
(a, b) =>
new Date(a.createdAt).getTime() -
new Date(b.createdAt).getTime(),
.sort((a, b) =>
a.createdAt && b.createdAt
? new Date(a.createdAt).getTime() -
new Date(b.createdAt).getTime()
: 0,
)
.map((project) => project.id),
[projects],

View File

@ -14,7 +14,7 @@ import { ProjectCardFooter } from './ProjectCardFooter/ProjectCardFooter';
import { ProjectModeBadge } from './ProjectModeBadge/ProjectModeBadge';
import { ProjectIcon } from 'component/common/ProjectIcon/ProjectIcon';
import { FavoriteAction } from './FavoriteAction/FavoriteAction';
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
import { Box } from '@mui/material';
export const ProjectCard = ({
@ -27,7 +27,7 @@ export const ProjectCard = ({
mode,
favorite = false,
owners,
}: IProjectCard) => (
}: ProjectSchema & { onHover?: () => void }) => (
<StyledProjectCard onMouseEnter={onHover}>
<StyledProjectCardBody>
<StyledDivHeader>

View File

@ -12,12 +12,12 @@ import { Box, styled } from '@mui/material';
import { flexColumn } from 'themes/themeStyles';
import { TimeAgo } from 'component/common/TimeAgo/TimeAgo';
import { ProjectLastSeen } from './ProjectLastSeen/ProjectLastSeen';
import type { IProjectCard } from 'interfaces/project';
import { Highlighter } from 'component/common/Highlighter/Highlighter';
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { ProjectMembers } from './ProjectCardFooter/ProjectMembers/ProjectMembers';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { DEFAULT_PROJECT_ID } from 'hooks/api/getters/useDefaultProject/useDefaultProjectId';
import type { ProjectSchema } from 'openapi';
const StyledUpdated = styled('span')(({ theme }) => ({
color: theme.palette.text.secondary,
@ -45,6 +45,8 @@ const StyledHeader = styled('div')(({ theme }) => ({
alignItems: 'center',
}));
type ProjectCardProps = ProjectSchema & { onHover?: () => void };
export const ProjectCard = ({
name,
featureCount,
@ -58,7 +60,7 @@ export const ProjectCard = ({
createdAt,
lastUpdatedAt,
lastReportedFlagUsage,
}: IProjectCard) => {
}: ProjectCardProps) => {
const { searchQuery } = useSearchHighlightContext();
return (

View File

@ -2,7 +2,7 @@ import { type FC, useContext, useEffect, useMemo, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
import { PageContent } from 'component/common/PageContent/PageContent';
import AccessContext from 'contexts/AccessContext';
import { PageHeader } from 'component/common/PageHeader/PageHeader';
@ -169,7 +169,7 @@ export const ProjectList = () => {
const ProjectGroupComponent = (props: {
sectionTitle?: string;
projects: IProjectCard[];
projects: ProjectSchema[];
}) => {
return (
<ProjectGroup

View File

@ -3,8 +3,7 @@ import { Link } from 'react-router-dom';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { ProjectCard as LegacyProjectCard } from '../ProjectCard/LegacyProjectCard';
import { ProjectCard as NewProjectCard } from '../ProjectCard/ProjectCard';
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
import loadingData from './loadingData';
import { TablePlaceholder } from 'component/common/Table';
import { styled, Typography } from '@mui/material';
@ -51,14 +50,14 @@ type ProjectGroupProps = {
sectionTitle?: string;
sectionSubtitle?: string;
HeaderActions?: ReactNode;
projects: IProjectCard[];
projects: ProjectSchema[];
loading: boolean;
/**
* @deprecated remove with projectListImprovements
*/
searchValue?: string;
placeholder?: string;
ProjectCardComponent?: ComponentType<IProjectCard & any>;
ProjectCardComponent?: ComponentType<ProjectSchema & any>;
link?: boolean;
};
@ -129,7 +128,7 @@ export const ProjectGroup = ({
show={() => (
<>
{loadingData.map(
(project: IProjectCard) => (
(project: ProjectSchema) => (
<ProjectCard
data-loading
createdAt={project.createdAt}

View File

@ -1,10 +1,10 @@
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
import { groupProjects } from './group-projects';
test('should check that the project is a user project OR that it is a favorite', () => {
const myProjectIds = new Set(['my1', 'my2', 'my3']);
const projects: IProjectCard[] = [
const projects: ProjectSchema[] = [
{ id: 'my1', favorite: true },
{ id: 'my2', favorite: false },
{ id: 'my3' },

View File

@ -1,11 +1,11 @@
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
export const groupProjects = (
myProjectIds: Set<string>,
filteredProjects: IProjectCard[],
filteredProjects: ProjectSchema[],
) => {
const mine: IProjectCard[] = [];
const other: IProjectCard[] = [];
const mine: ProjectSchema[] = [];
const other: ProjectSchema[] = [];
for (const project of filteredProjects) {
if (project.favorite || myProjectIds.has(project.id)) {

View File

@ -1,9 +1,9 @@
import { useMemo } from 'react';
import { groupProjects } from '../group-projects';
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
export const useGroupedProjects = (
filteredAndSortedProjects: IProjectCard[],
filteredAndSortedProjects: ProjectSchema[],
myProjects: Set<string>,
) =>
useMemo(

View File

@ -1,8 +1,8 @@
import { renderHook } from '@testing-library/react';
import { useProjectsSearchAndSort } from './useProjectsSearchAndSort';
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
const projects: IProjectCard[] = [
const projects: ProjectSchema[] = [
{
name: 'A - Eagle',
id: '1',
@ -174,7 +174,7 @@ describe('useProjectsSearchAndSort', () => {
]);
});
it('should be able to deal with date', () => {
it('should be able to deal with updates', () => {
const hook = renderHook(
(sortBy: string) =>
useProjectsSearchAndSort(
@ -189,9 +189,9 @@ describe('useProjectsSearchAndSort', () => {
{
name: 'Project B',
id: '2',
createdAt: new Date('2024-02-01'),
lastUpdatedAt: new Date('2024-02-10'),
lastReportedFlagUsage: new Date('2024-02-15'),
createdAt: '2024-02-01',
lastUpdatedAt: '2024-02-10',
lastReportedFlagUsage: '2024-02-15',
},
],
undefined,

View File

@ -1,10 +1,10 @@
import { useMemo } from 'react';
import { safeRegExp } from '@server/util/escape-regex';
import type { IProjectCard } from 'interfaces/project';
import type { sortKeys } from '../ProjectsListSort/ProjectsListSort';
import type { ProjectSchema } from 'openapi';
export const useProjectsSearchAndSort = (
projects: IProjectCard[],
projects: ProjectSchema[],
query?: string | null,
sortBy?: (typeof sortKeys)[number] | null,
) =>

View File

@ -7,7 +7,7 @@ const loadingData = [
featureCount: 4,
createdAt: '',
description: '',
mode: '',
mode: 'open' as const,
},
{
id: 'loading2',
@ -17,7 +17,7 @@ const loadingData = [
featureCount: 4,
createdAt: '',
description: '',
mode: '',
mode: 'open' as const,
},
{
id: 'loading3',
@ -27,7 +27,7 @@ const loadingData = [
featureCount: 4,
createdAt: '',
description: '',
mode: '',
mode: 'open' as const,
},
{
id: 'loading4',
@ -37,7 +37,7 @@ const loadingData = [
featureCount: 4,
createdAt: '',
description: '',
mode: '',
mode: 'open' as const,
},
];

View File

@ -1,6 +1,6 @@
import { Alert, styled } from '@mui/material';
import { formatEditStrategyPath } from 'component/feature/FeatureStrategy/FeatureStrategyEdit/FeatureStrategyEdit';
import type { IProjectCard } from 'interfaces/project';
import type { ProjectSchema } from 'openapi';
import type { IFeatureStrategy } from 'interfaces/strategy';
import { Link } from 'react-router-dom';
import { formatStrategyName } from 'utils/strategyNames';
@ -22,14 +22,14 @@ const StyledAlert = styled(Alert)(({ theme }) => ({
}));
interface ISegmentProjectAlertProps {
projects: IProjectCard[];
projects: ProjectSchema[];
strategies: (
| IFeatureStrategy
| ChangeRequestUpdatedStrategy
| ChangeRequestNewStrategy
)[];
projectsUsed: string[];
availableProjects: IProjectCard[];
availableProjects: ProjectSchema[];
}
export const SegmentProjectAlert = ({

View File

@ -2,9 +2,8 @@ import useSWR, { mutate, type SWRConfiguration } from 'swr';
import { useState, useEffect } from 'react';
import { formatApiPath } from 'utils/formatPath';
import type { IProjectCard } from 'interfaces/project';
import handleErrorResponses from '../httpErrorResponseHandler';
import type { GetProjectsParams } from 'openapi';
import type { GetProjectsParams, ProjectsSchema } from 'openapi';
const useProjects = (options: SWRConfiguration & GetProjectsParams = {}) => {
const KEY = `api/admin/projects${options.archived ? '?archived=true' : ''}`;
@ -18,7 +17,7 @@ const useProjects = (options: SWRConfiguration & GetProjectsParams = {}) => {
.then((res) => res.json());
};
const { data, error } = useSWR<{ projects: IProjectCard[] }>(
const { data, error } = useSWR<{ projects: ProjectsSchema['projects'] }>(
KEY,
fetcher,
options,

View File

@ -1,24 +1,8 @@
import type { ProjectSchema, ProjectStatsSchema } from 'openapi';
import type { ProjectStatsSchema } from 'openapi';
import type { IFeatureFlagListItem } from './featureToggle';
import type { ProjectEnvironmentType } from 'component/project/Project/ProjectFeatureToggles/hooks/useEnvironmentsRef';
import type { ProjectMode } from 'component/project/Project/hooks/useProjectEnterpriseSettingsForm';
export interface IProjectCard {
name: string;
id: string;
createdAt: string | Date;
health?: number;
description?: string;
featureCount?: number;
mode?: string;
memberCount?: number;
onHover?: () => void;
favorite?: boolean;
owners?: ProjectSchema['owners'];
lastUpdatedAt?: Date | string;
lastReportedFlagUsage?: Date | string;
}
export type FeatureNamingType = {
pattern: string;
example: string;

View File

@ -41,6 +41,16 @@ export interface ProjectSchema {
health?: number;
/** The id of this project */
id: string;
/**
* Across all flags in your project this is the last time usage metrics where reported from connected applications.
* @nullable
*/
lastReportedFlagUsage?: string | null;
/**
* When this project was last updated.
* @nullable
*/
lastUpdatedAt?: string | null;
/** The number of members this project has */
memberCount?: number;
/** The project's [collaboration mode](https://docs.getunleash.io/reference/project-collaboration-mode). Determines whether non-project members can submit change requests or not. */