mirror of
https://github.com/Unleash/unleash.git
synced 2025-09-24 17:51:14 +02:00
[Gitar] Cleaning up stale flag: projectListImprovements with value true (#8212)
Co-authored-by: Gitar <noreply@gitar.co> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com>
This commit is contained in:
parent
9f5e909436
commit
5dd0fb9f44
@ -1,88 +0,0 @@
|
|||||||
import type { FC } from 'react';
|
|
||||||
import { styled } from '@mui/material';
|
|
||||||
import type { ProjectSchema, ProjectSchemaOwners } from 'openapi';
|
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
|
||||||
import { AvatarGroup } from 'component/common/AvatarGroup/AvatarGroup';
|
|
||||||
|
|
||||||
export interface IProjectOwnersProps {
|
|
||||||
owners?: ProjectSchema['owners'];
|
|
||||||
}
|
|
||||||
|
|
||||||
const useOwnersMap = () => {
|
|
||||||
const { uiConfig } = useUiConfig();
|
|
||||||
|
|
||||||
return (
|
|
||||||
owner: ProjectSchemaOwners[0],
|
|
||||||
): {
|
|
||||||
name: string;
|
|
||||||
imageUrl?: string;
|
|
||||||
email?: string;
|
|
||||||
} => {
|
|
||||||
if (owner.ownerType === 'user') {
|
|
||||||
return {
|
|
||||||
name: owner.name,
|
|
||||||
imageUrl: owner.imageUrl || undefined,
|
|
||||||
email: owner.email || undefined,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (owner.ownerType === 'group') {
|
|
||||||
return {
|
|
||||||
name: owner.name,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
name: 'System',
|
|
||||||
imageUrl: `${uiConfig.unleashUrl}/logo-unleash.png`,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const StyledUserName = styled('p')(({ theme }) => ({
|
|
||||||
fontSize: theme.typography.body1.fontSize,
|
|
||||||
margin: theme.spacing(0, 0, 0.5, 0),
|
|
||||||
overflowX: 'hidden',
|
|
||||||
textOverflow: 'ellipsis',
|
|
||||||
textWrap: 'nowrap',
|
|
||||||
alignSelf: 'end',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledContainer = styled('div')(() => ({
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledHeader = styled('h3')(({ theme }) => ({
|
|
||||||
margin: theme.spacing(0, 0, 1),
|
|
||||||
fontSize: theme.typography.caption.fontSize,
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
fontWeight: theme.typography.fontWeightRegular,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledWrapper = styled('div')(({ theme }) => ({
|
|
||||||
padding: theme.spacing(1.5, 0, 2.5, 3),
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
minWidth: 0,
|
|
||||||
}));
|
|
||||||
|
|
||||||
export const ProjectOwners: FC<IProjectOwnersProps> = ({ owners = [] }) => {
|
|
||||||
const ownersMap = useOwnersMap();
|
|
||||||
const users = owners.map(ownersMap);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledWrapper>
|
|
||||||
<StyledContainer>
|
|
||||||
<StyledHeader>
|
|
||||||
{owners.length === 1 ? 'Owner' : 'Owners'}
|
|
||||||
</StyledHeader>
|
|
||||||
<AvatarGroup users={users} avatarLimit={8} />
|
|
||||||
</StyledContainer>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={owners.length === 1}
|
|
||||||
show={<StyledUserName>{users[0]?.name}</StyledUserName>}
|
|
||||||
elseShow={<div />}
|
|
||||||
/>
|
|
||||||
</StyledWrapper>
|
|
||||||
);
|
|
||||||
};
|
|
@ -2,12 +2,9 @@ import type React from 'react';
|
|||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import { Box, styled } from '@mui/material';
|
import { Box, styled } from '@mui/material';
|
||||||
import {
|
import {
|
||||||
|
ProjectOwners,
|
||||||
type IProjectOwnersProps,
|
type IProjectOwnersProps,
|
||||||
ProjectOwners as LegacyProjectOwners,
|
} from './ProjectOwners/ProjectOwners';
|
||||||
} from '../LegacyProjectOwners/LegacyProjectOwners';
|
|
||||||
import { ProjectOwners } from './ProjectOwners/ProjectOwners';
|
|
||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
|
||||||
|
|
||||||
interface IProjectCardFooterProps {
|
interface IProjectCardFooterProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
@ -31,20 +28,13 @@ const StyledFooter = styled(Box)<{ disabled: boolean }>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const ProjectCardFooter: FC<IProjectCardFooterProps> = ({
|
export const ProjectCardFooter: FC<IProjectCardFooterProps> = ({
|
||||||
id,
|
|
||||||
children,
|
children,
|
||||||
owners,
|
owners,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
}) => {
|
}) => {
|
||||||
const projectListImprovementsEnabled = useUiFlag('projectListImprovements');
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledFooter disabled={disabled}>
|
<StyledFooter disabled={disabled}>
|
||||||
<ConditionallyRender
|
<ProjectOwners owners={owners} />
|
||||||
condition={Boolean(projectListImprovementsEnabled)}
|
|
||||||
show={<ProjectOwners owners={owners} />}
|
|
||||||
elseShow={<LegacyProjectOwners owners={owners} />}
|
|
||||||
/>
|
|
||||||
{children}
|
{children}
|
||||||
</StyledFooter>
|
</StyledFooter>
|
||||||
);
|
);
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import LockIcon from '@mui/icons-material/Lock';
|
|
||||||
import ProtectedProjectIcon from '@mui/icons-material/LockOutlined';
|
import ProtectedProjectIcon from '@mui/icons-material/LockOutlined';
|
||||||
import VisibilityOffIcon from '@mui/icons-material/VisibilityOff';
|
|
||||||
import PrivateProjectIcon from '@mui/icons-material/VisibilityOffOutlined';
|
import PrivateProjectIcon from '@mui/icons-material/VisibilityOffOutlined';
|
||||||
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
|
import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip';
|
||||||
import { Badge } from 'component/common/Badge/Badge';
|
|
||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
|
||||||
import { styled } from '@mui/material';
|
import { styled } from '@mui/material';
|
||||||
|
|
||||||
interface IProjectModeBadgeProps {
|
interface IProjectModeBadgeProps {
|
||||||
@ -19,50 +15,28 @@ const StyledIcon = styled('div')(({ theme }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
export const ProjectModeBadge: FC<IProjectModeBadgeProps> = ({ mode }) => {
|
export const ProjectModeBadge: FC<IProjectModeBadgeProps> = ({ mode }) => {
|
||||||
const projectListImprovementsEnabled = useUiFlag('projectListImprovements');
|
|
||||||
|
|
||||||
if (mode === 'private') {
|
if (mode === 'private') {
|
||||||
if (projectListImprovementsEnabled) {
|
|
||||||
return (
|
|
||||||
<HtmlTooltip
|
|
||||||
title="This project's collaboration mode is set to private. The project and associated feature flags can only be seen by members of the project."
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<StyledIcon>
|
|
||||||
<PrivateProjectIcon fontSize='inherit' />
|
|
||||||
</StyledIcon>
|
|
||||||
</HtmlTooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<HtmlTooltip
|
<HtmlTooltip
|
||||||
title="This project's collaboration mode is set to private. The project and associated feature flags can only be seen by members of the project."
|
title="This project's collaboration mode is set to private. The project and associated feature flags can only be seen by members of the project."
|
||||||
arrow
|
arrow
|
||||||
>
|
>
|
||||||
<Badge color='warning' icon={<VisibilityOffIcon />} />
|
<StyledIcon>
|
||||||
|
<PrivateProjectIcon fontSize='inherit' />
|
||||||
|
</StyledIcon>
|
||||||
</HtmlTooltip>
|
</HtmlTooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode === 'protected') {
|
if (mode === 'protected') {
|
||||||
if (projectListImprovementsEnabled) {
|
|
||||||
return (
|
|
||||||
<HtmlTooltip
|
|
||||||
title="This project's collaboration mode is set to protected. Only admins and project members can submit change requests."
|
|
||||||
arrow
|
|
||||||
>
|
|
||||||
<StyledIcon>
|
|
||||||
<ProtectedProjectIcon fontSize='inherit' />
|
|
||||||
</StyledIcon>
|
|
||||||
</HtmlTooltip>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<HtmlTooltip
|
<HtmlTooltip
|
||||||
title="This project's collaboration mode is set to protected. Only admins and project members can submit change requests."
|
title="This project's collaboration mode is set to protected. Only admins and project members can submit change requests."
|
||||||
arrow
|
arrow
|
||||||
>
|
>
|
||||||
<Badge color='warning' icon={<LockIcon />} />
|
<StyledIcon>
|
||||||
|
<ProtectedProjectIcon fontSize='inherit' />
|
||||||
|
</StyledIcon>
|
||||||
</HtmlTooltip>
|
</HtmlTooltip>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,6 @@ export const ArchiveProjectList: FC = () => {
|
|||||||
<SearchHighlightProvider value={searchValue}>
|
<SearchHighlightProvider value={searchValue}>
|
||||||
<ProjectGroup
|
<ProjectGroup
|
||||||
loading={loading}
|
loading={loading}
|
||||||
searchValue={searchValue}
|
|
||||||
projects={filteredProjects}
|
projects={filteredProjects}
|
||||||
placeholder='No archived projects found'
|
placeholder='No archived projects found'
|
||||||
ProjectCardComponent={ProjectCard}
|
ProjectCardComponent={ProjectCard}
|
||||||
|
@ -1,249 +0,0 @@
|
|||||||
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 { ProjectSchema } from 'openapi';
|
|
||||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
|
||||||
import AccessContext from 'contexts/AccessContext';
|
|
||||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
|
||||||
import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton';
|
|
||||||
import { CREATE_PROJECT } from 'component/providers/AccessProvider/permissions';
|
|
||||||
import Add from '@mui/icons-material/Add';
|
|
||||||
import ApiError from 'component/common/ApiError/ApiError';
|
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
|
||||||
import { Link, styled, useMediaQuery } from '@mui/material';
|
|
||||||
import { Link as RouterLink } from 'react-router-dom';
|
|
||||||
import theme from 'themes/theme';
|
|
||||||
import { Search } from 'component/common/Search/Search';
|
|
||||||
import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature';
|
|
||||||
import type { ITooltipResolverProps } from 'component/common/TooltipResolver/TooltipResolver';
|
|
||||||
import { ReactComponent as ProPlanIcon } from 'assets/icons/pro-enterprise-feature-badge.svg';
|
|
||||||
import { ReactComponent as ProPlanIconLight } from 'assets/icons/pro-enterprise-feature-badge-light.svg';
|
|
||||||
import { safeRegExp } from '@server/util/escape-regex';
|
|
||||||
import { ThemeMode } from 'component/common/ThemeMode/ThemeMode';
|
|
||||||
import { useProfile } from 'hooks/api/getters/useProfile/useProfile';
|
|
||||||
import { groupProjects } from './group-projects';
|
|
||||||
import { ProjectGroup } from './ProjectGroup';
|
|
||||||
import { CreateProjectDialog } from '../Project/CreateProject/NewCreateProjectForm/CreateProjectDialog';
|
|
||||||
|
|
||||||
const StyledApiError = styled(ApiError)(({ theme }) => ({
|
|
||||||
maxWidth: '500px',
|
|
||||||
marginBottom: theme.spacing(2),
|
|
||||||
}));
|
|
||||||
|
|
||||||
const StyledContainer = styled('div')(({ theme }) => ({
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
gap: theme.spacing(4),
|
|
||||||
}));
|
|
||||||
|
|
||||||
type PageQueryType = Partial<Record<'search', string>>;
|
|
||||||
|
|
||||||
interface ICreateButtonData {
|
|
||||||
disabled: boolean;
|
|
||||||
tooltip?: Omit<ITooltipResolverProps, 'children'>;
|
|
||||||
endIcon?: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
const NAVIGATE_TO_CREATE_PROJECT = 'NAVIGATE_TO_CREATE_PROJECT';
|
|
||||||
|
|
||||||
function resolveCreateButtonData(
|
|
||||||
isOss: boolean,
|
|
||||||
hasAccess: boolean,
|
|
||||||
): ICreateButtonData {
|
|
||||||
if (isOss) {
|
|
||||||
return {
|
|
||||||
disabled: true,
|
|
||||||
tooltip: {
|
|
||||||
titleComponent: (
|
|
||||||
<PremiumFeature feature='adding-new-projects' tooltip />
|
|
||||||
),
|
|
||||||
sx: { maxWidth: '320px' },
|
|
||||||
variant: 'custom',
|
|
||||||
},
|
|
||||||
endIcon: (
|
|
||||||
<ThemeMode
|
|
||||||
darkmode={<ProPlanIconLight />}
|
|
||||||
lightmode={<ProPlanIcon />}
|
|
||||||
/>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
} else if (!hasAccess) {
|
|
||||||
return {
|
|
||||||
tooltip: {
|
|
||||||
title: 'You do not have permission to create new projects',
|
|
||||||
},
|
|
||||||
disabled: true,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
tooltip: { title: 'Click to create a new project' },
|
|
||||||
disabled: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProjectCreationButton: FC = () => {
|
|
||||||
const [searchParams] = useSearchParams();
|
|
||||||
const showCreateDialog = Boolean(searchParams.get('create'));
|
|
||||||
const [openCreateDialog, setOpenCreateDialog] = useState(showCreateDialog);
|
|
||||||
const { hasAccess } = useContext(AccessContext);
|
|
||||||
const { isOss, loading } = useUiConfig();
|
|
||||||
|
|
||||||
const createButtonData = resolveCreateButtonData(
|
|
||||||
isOss(),
|
|
||||||
hasAccess(CREATE_PROJECT),
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<ResponsiveButton
|
|
||||||
Icon={Add}
|
|
||||||
endIcon={createButtonData.endIcon}
|
|
||||||
onClick={() => setOpenCreateDialog(true)}
|
|
||||||
maxWidth='700px'
|
|
||||||
permission={CREATE_PROJECT}
|
|
||||||
disabled={createButtonData.disabled || loading}
|
|
||||||
tooltipProps={createButtonData.tooltip}
|
|
||||||
data-testid={NAVIGATE_TO_CREATE_PROJECT}
|
|
||||||
>
|
|
||||||
New project
|
|
||||||
</ResponsiveButton>
|
|
||||||
<CreateProjectDialog
|
|
||||||
open={openCreateDialog}
|
|
||||||
onClose={() => setOpenCreateDialog(false)}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ProjectList = () => {
|
|
||||||
const { projects, loading, error, refetch } = useProjects();
|
|
||||||
|
|
||||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
|
||||||
const [searchParams, setSearchParams] = useSearchParams();
|
|
||||||
const [searchValue, setSearchValue] = useState(
|
|
||||||
searchParams.get('search') || '',
|
|
||||||
);
|
|
||||||
|
|
||||||
const myProjects = new Set(useProfile().profile?.projects || []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const tableState: PageQueryType = {};
|
|
||||||
if (searchValue) {
|
|
||||||
tableState.search = searchValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
setSearchParams(tableState, {
|
|
||||||
replace: true,
|
|
||||||
});
|
|
||||||
}, [searchValue, setSearchParams]);
|
|
||||||
|
|
||||||
const filteredProjects = useMemo(() => {
|
|
||||||
const regExp = safeRegExp(searchValue, 'i');
|
|
||||||
return (
|
|
||||||
searchValue
|
|
||||||
? projects.filter((project) => regExp.test(project.name))
|
|
||||||
: projects
|
|
||||||
).sort((a, b) => {
|
|
||||||
if (a?.favorite && !b?.favorite) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (!a?.favorite && b?.favorite) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
}, [projects, searchValue]);
|
|
||||||
|
|
||||||
const groupedProjects = useMemo(() => {
|
|
||||||
return groupProjects(myProjects, filteredProjects);
|
|
||||||
}, [filteredProjects, myProjects]);
|
|
||||||
|
|
||||||
const projectCount =
|
|
||||||
filteredProjects.length < projects.length
|
|
||||||
? `${filteredProjects.length} of ${projects.length}`
|
|
||||||
: projects.length;
|
|
||||||
|
|
||||||
const ProjectGroupComponent = (props: {
|
|
||||||
sectionTitle?: string;
|
|
||||||
projects: ProjectSchema[];
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<ProjectGroup
|
|
||||||
loading={loading}
|
|
||||||
searchValue={searchValue}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContent
|
|
||||||
isLoading={loading}
|
|
||||||
header={
|
|
||||||
<PageHeader
|
|
||||||
title={`Projects (${projectCount})`}
|
|
||||||
actions={
|
|
||||||
<>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={!isSmallScreen}
|
|
||||||
show={
|
|
||||||
<>
|
|
||||||
<Search
|
|
||||||
initialValue={searchValue}
|
|
||||||
onChange={setSearchValue}
|
|
||||||
/>
|
|
||||||
<PageHeader.Divider />
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<>
|
|
||||||
<Link
|
|
||||||
component={RouterLink}
|
|
||||||
to='/projects-archive'
|
|
||||||
>
|
|
||||||
Archived projects
|
|
||||||
</Link>
|
|
||||||
<PageHeader.Divider />
|
|
||||||
</>
|
|
||||||
|
|
||||||
<ProjectCreationButton />
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={isSmallScreen}
|
|
||||||
show={
|
|
||||||
<Search
|
|
||||||
initialValue={searchValue}
|
|
||||||
onChange={setSearchValue}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</PageHeader>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<StyledContainer>
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={error}
|
|
||||||
show={() => (
|
|
||||||
<StyledApiError
|
|
||||||
onClick={refetch}
|
|
||||||
text='Error fetching projects'
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<ProjectGroupComponent
|
|
||||||
sectionTitle='My projects'
|
|
||||||
projects={groupedProjects.myProjects}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ProjectGroupComponent
|
|
||||||
sectionTitle='Other projects'
|
|
||||||
projects={groupedProjects.otherProjects}
|
|
||||||
/>
|
|
||||||
</StyledContainer>
|
|
||||||
</PageContent>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,13 +1,11 @@
|
|||||||
import type { ComponentType, ReactNode } from 'react';
|
import type { ComponentType, ReactNode } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { ProjectCard as LegacyProjectCard } from '../ProjectCard/LegacyProjectCard';
|
|
||||||
import { ProjectCard as NewProjectCard } from '../ProjectCard/ProjectCard';
|
import { ProjectCard as NewProjectCard } from '../ProjectCard/ProjectCard';
|
||||||
import type { ProjectSchema } from 'openapi';
|
import type { ProjectSchema } from 'openapi';
|
||||||
import loadingData from './loadingData';
|
import loadingData from './loadingData';
|
||||||
import { TablePlaceholder } from 'component/common/Table';
|
import { TablePlaceholder } from 'component/common/Table';
|
||||||
import { styled, Typography } from '@mui/material';
|
import { styled, Typography } from '@mui/material';
|
||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
|
||||||
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
import { flexColumn } from 'themes/themeStyles';
|
import { flexColumn } from 'themes/themeStyles';
|
||||||
|
|
||||||
@ -52,10 +50,6 @@ type ProjectGroupProps = {
|
|||||||
HeaderActions?: ReactNode;
|
HeaderActions?: ReactNode;
|
||||||
projects: ProjectSchema[];
|
projects: ProjectSchema[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
/**
|
|
||||||
* @deprecated remove with projectListImprovements
|
|
||||||
*/
|
|
||||||
searchValue?: string;
|
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
ProjectCardComponent?: ComponentType<ProjectSchema & any>;
|
ProjectCardComponent?: ComponentType<ProjectSchema & any>;
|
||||||
link?: boolean;
|
link?: boolean;
|
||||||
@ -67,15 +61,11 @@ export const ProjectGroup = ({
|
|||||||
HeaderActions,
|
HeaderActions,
|
||||||
projects,
|
projects,
|
||||||
loading,
|
loading,
|
||||||
searchValue,
|
|
||||||
placeholder = 'No projects available.',
|
placeholder = 'No projects available.',
|
||||||
ProjectCardComponent,
|
ProjectCardComponent,
|
||||||
link = true,
|
link = true,
|
||||||
}: ProjectGroupProps) => {
|
}: ProjectGroupProps) => {
|
||||||
const projectListImprovementsEnabled = useUiFlag('projectListImprovements');
|
const ProjectCard = ProjectCardComponent ?? NewProjectCard;
|
||||||
const ProjectCard =
|
|
||||||
ProjectCardComponent ??
|
|
||||||
(projectListImprovementsEnabled ? NewProjectCard : LegacyProjectCard);
|
|
||||||
const { searchQuery } = useSearchHighlightContext();
|
const { searchQuery } = useSearchHighlightContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -91,10 +81,7 @@ export const ProjectGroup = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={
|
condition={Boolean(sectionSubtitle)}
|
||||||
Boolean(sectionSubtitle) &&
|
|
||||||
projectListImprovementsEnabled
|
|
||||||
}
|
|
||||||
show={
|
show={
|
||||||
<Typography variant='body2' color='text.secondary'>
|
<Typography variant='body2' color='text.secondary'>
|
||||||
{sectionSubtitle}
|
{sectionSubtitle}
|
||||||
@ -108,11 +95,11 @@ export const ProjectGroup = ({
|
|||||||
condition={projects.length < 1 && !loading}
|
condition={projects.length < 1 && !loading}
|
||||||
show={
|
show={
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={(searchValue || searchQuery)?.length > 0}
|
condition={searchQuery?.length > 0}
|
||||||
show={
|
show={
|
||||||
<TablePlaceholder>
|
<TablePlaceholder>
|
||||||
No projects found matching “
|
No projects found matching “
|
||||||
{searchValue || searchQuery}
|
{searchQuery}
|
||||||
”
|
”
|
||||||
</TablePlaceholder>
|
</TablePlaceholder>
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { type FC, useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import useProjects from 'hooks/api/getters/useProjects/useProjects';
|
import useProjects from 'hooks/api/getters/useProjects/useProjects';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||||
@ -9,11 +9,9 @@ import theme from 'themes/theme';
|
|||||||
import { Search } from 'component/common/Search/Search';
|
import { Search } from 'component/common/Search/Search';
|
||||||
import { useProfile } from 'hooks/api/getters/useProfile/useProfile';
|
import { useProfile } from 'hooks/api/getters/useProfile/useProfile';
|
||||||
import { ProjectGroup } from './ProjectGroup';
|
import { ProjectGroup } from './ProjectGroup';
|
||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
|
||||||
import { ProjectsListSort } from './ProjectsListSort/ProjectsListSort';
|
import { ProjectsListSort } from './ProjectsListSort/ProjectsListSort';
|
||||||
import { useProjectsListState } from './hooks/useProjectsListState';
|
import { useProjectsListState } from './hooks/useProjectsListState';
|
||||||
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
import { ProjectList as LegacyProjectList } from './LegacyProjectList';
|
|
||||||
import { ProjectCreationButton } from './ProjectCreationButton/ProjectCreationButton';
|
import { ProjectCreationButton } from './ProjectCreationButton/ProjectCreationButton';
|
||||||
import { useGroupedProjects } from './hooks/useGroupedProjects';
|
import { useGroupedProjects } from './hooks/useGroupedProjects';
|
||||||
import { useProjectsSearchAndSort } from './hooks/useProjectsSearchAndSort';
|
import { useProjectsSearchAndSort } from './hooks/useProjectsSearchAndSort';
|
||||||
@ -30,7 +28,7 @@ const StyledContainer = styled('div')(({ theme }) => ({
|
|||||||
gap: theme.spacing(6),
|
gap: theme.spacing(6),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const NewProjectList = () => {
|
export const ProjectList = () => {
|
||||||
const { projects, loading, error, refetch } = useProjects();
|
const { projects, loading, error, refetch } = useProjects();
|
||||||
|
|
||||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
||||||
@ -140,13 +138,3 @@ const NewProjectList = () => {
|
|||||||
</PageContent>
|
</PageContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ProjectList: FC = () => {
|
|
||||||
const projectListImprovementsEnabled = useUiFlag('projectListImprovements');
|
|
||||||
|
|
||||||
if (projectListImprovementsEnabled) {
|
|
||||||
return <NewProjectList />;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <LegacyProjectList />;
|
|
||||||
};
|
|
||||||
|
@ -86,7 +86,6 @@ export type UiFlags = {
|
|||||||
enableLegacyVariants?: boolean;
|
enableLegacyVariants?: boolean;
|
||||||
navigationSidebar?: boolean;
|
navigationSidebar?: boolean;
|
||||||
flagCreator?: boolean;
|
flagCreator?: boolean;
|
||||||
projectListImprovements?: boolean;
|
|
||||||
onboardingUI?: boolean;
|
onboardingUI?: boolean;
|
||||||
eventTimeline?: boolean;
|
eventTimeline?: boolean;
|
||||||
personalDashboardUI?: boolean;
|
personalDashboardUI?: boolean;
|
||||||
|
@ -56,7 +56,6 @@ export type IFlagKey =
|
|||||||
| 'extendedMetrics'
|
| 'extendedMetrics'
|
||||||
| 'removeUnsafeInlineStyleSrc'
|
| 'removeUnsafeInlineStyleSrc'
|
||||||
| 'originMiddleware'
|
| 'originMiddleware'
|
||||||
| 'projectListImprovements'
|
|
||||||
| 'useProjectReadModel'
|
| 'useProjectReadModel'
|
||||||
| 'addonUsageMetrics'
|
| 'addonUsageMetrics'
|
||||||
| 'onboardingMetrics'
|
| 'onboardingMetrics'
|
||||||
@ -280,10 +279,6 @@ const flags: IFlags = {
|
|||||||
process.env.UNLEASH_EXPERIMENTAL_ORIGIN_MIDDLEWARE,
|
process.env.UNLEASH_EXPERIMENTAL_ORIGIN_MIDDLEWARE,
|
||||||
false,
|
false,
|
||||||
),
|
),
|
||||||
projectListImprovements: parseEnvVarBoolean(
|
|
||||||
process.env.UNLEASH_EXPERIMENTAL_PROJECT_LIST_IMPROVEMENTS,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
useProjectReadModel: parseEnvVarBoolean(
|
useProjectReadModel: parseEnvVarBoolean(
|
||||||
process.env.UNLEASH_EXPERIMENTAL_USE_PROJECT_READ_MODEL,
|
process.env.UNLEASH_EXPERIMENTAL_USE_PROJECT_READ_MODEL,
|
||||||
false,
|
false,
|
||||||
|
@ -51,7 +51,6 @@ process.nextTick(async () => {
|
|||||||
enableLegacyVariants: false,
|
enableLegacyVariants: false,
|
||||||
extendedMetrics: true,
|
extendedMetrics: true,
|
||||||
originMiddleware: true,
|
originMiddleware: true,
|
||||||
projectListImprovements: true,
|
|
||||||
useProjectReadModel: true,
|
useProjectReadModel: true,
|
||||||
addonUsageMetrics: true,
|
addonUsageMetrics: true,
|
||||||
onboardingMetrics: true,
|
onboardingMetrics: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user