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:
parent
0b2479517f
commit
6030900b40
@ -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' },
|
||||
],
|
||||
}),
|
||||
|
@ -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,
|
||||
})) ?? [];
|
||||
|
@ -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',
|
||||
},
|
||||
|
@ -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],
|
||||
|
@ -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>
|
||||
|
@ -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 (
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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' },
|
||||
|
@ -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)) {
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
) =>
|
||||
|
@ -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,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -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 = ({
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user