1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-11-10 01:19:53 +01:00
unleash.unleash/frontend/src/component/project/ProjectList/ProjectList.tsx
unleash-bot[bot] 8ddeed09fb
chore(AI): projectListViewToggle flag cleanup (#10527)
This PR cleans up the projectListViewToggle flag. These changes were
automatically generated by AI and should be reviewed carefully.

Fixes #10526

## 🧹 AI Flag Cleanup Summary
This change removes the `projectListViewToggle` feature flag and
hardcodes its
behavior. The feature, which allows toggling between card and list views
for
projects, is now permanently enabled.
### 🚮 Removed
- **Flag Definitions**
- Removed `projectListViewToggle` from `src/server-dev.ts`,
`src/lib/types/experimental.ts`, and
`frontend/src/interfaces/uiConfig.ts`.
- **Hooks & Conditionals**
- Removed `useUiFlag('projectListViewToggle')` calls from
`ProjectGroup.tsx`
and `ProjectList.tsx`.
- Removed conditional rendering logic based on the flag in
`ProjectGroup.tsx`
and `ProjectList.tsx`.
### 🛠 Kept
- **Project List View**
- The project list view functionality is now always available for
non-OSS
versions of Unleash.
- The `ProjectsListViewToggle` component is now always rendered when not
in an
OSS environment.
### 📝 Why
The `projectListViewToggle` feature flag was marked as completed and its
intended outcome was to be kept. The code has been updated to reflect
this by
removing the flag and making the feature a permanent part of the
application.
This simplifies the codebase by removing dead code paths and feature
flag
checks.

Co-authored-by: unleash-bot <194219037+unleash-bot[bot]@users.noreply.github.com>
2025-08-25 09:01:59 +01:00

197 lines
8.3 KiB
TypeScript

import { useCallback } from 'react';
import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { PageContent } from 'component/common/PageContent/PageContent';
import { PageHeader } from 'component/common/PageHeader/PageHeader';
import ApiError from 'component/common/ApiError/ApiError';
import { styled, useMediaQuery } from '@mui/material';
import theme from 'themes/theme';
import { Search } from 'component/common/Search/Search';
import { useProfile } from 'hooks/api/getters/useProfile/useProfile';
import { ProjectGroup } from './ProjectGroup.tsx';
import { ProjectsListSort } from './ProjectsListSort/ProjectsListSort.tsx';
import { useProjectsListState } from './hooks/useProjectsListState.ts';
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
import { ProjectCreationButton } from './ProjectCreationButton/ProjectCreationButton.tsx';
import { useGroupedProjects } from './hooks/useGroupedProjects.ts';
import { useProjectsSearchAndSort } from './hooks/useProjectsSearchAndSort.ts';
import { ProjectArchiveLink } from './ProjectArchiveLink/ProjectArchiveLink.tsx';
import { ProjectsListHeader } from './ProjectsListHeader/ProjectsListHeader.tsx';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { TablePlaceholder } from 'component/common/Table/index.ts';
import { ProjectsListViewToggle } from './ProjectsListViewToggle/ProjectsListViewToggle.tsx';
const StyledApiError = styled(ApiError)(({ theme }) => ({
maxWidth: '500px',
marginBottom: theme.spacing(2),
}));
const StyledContainer = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(4),
}));
export const ProjectList = () => {
const { projects, loading, error, refetch } = useProjects();
const { isOss } = useUiConfig();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
const [state, setState] = useProjectsListState();
const myProfileProjects = new Set(useProfile().profile?.projects || []);
const setSearchValue = useCallback(
(value: string) => setState({ query: value || undefined }),
[setState],
);
const sortedProjects = useProjectsSearchAndSort(
projects,
state.query,
state.sortBy,
);
const groupedProjects = useGroupedProjects(
sortedProjects,
myProfileProjects,
);
const projectCount =
sortedProjects.length < projects.length
? `${sortedProjects.length} of ${projects.length}`
: projects.length;
const myProjects = isOss() ? sortedProjects : groupedProjects.myProjects;
const otherProjects = isOss() ? [] : groupedProjects.otherProjects;
return (
<PageContent
isLoading={loading}
header={
<PageHeader
title={`Projects (${projectCount})`}
actions={
<>
<ConditionallyRender
condition={!isOss() && !isSmallScreen}
show={
<>
<Search
initialValue={state.query || ''}
onChange={setSearchValue}
/>
<PageHeader.Divider />
</>
}
/>
{!isOss() && <ProjectArchiveLink />}
<ProjectCreationButton
isDialogOpen={Boolean(state.create)}
setIsDialogOpen={(create) =>
setState({
create: create ? 'true' : undefined,
})
}
/>
</>
}
>
<ConditionallyRender
condition={!isOss() && isSmallScreen}
show={
<Search
initialValue={state.query || ''}
onChange={setSearchValue}
/>
}
/>
</PageHeader>
}
>
<StyledContainer>
<ConditionallyRender
condition={error}
show={() => (
<StyledApiError
onClick={refetch}
text='Error fetching projects'
/>
)}
/>
<SearchHighlightProvider value={state.query || ''}>
{myProjects.length > 0 && (
<div>
<ProjectsListHeader
helpText='Favorite projects, projects you own, and projects you are a member of'
actions={
<>
{!isOss() && (
<ProjectsListViewToggle
view={state.view}
setView={(view) =>
setState({ view })
}
/>
)}
<ProjectsListSort
sortBy={state.sortBy}
setSortBy={(sortBy) =>
setState({
sortBy: sortBy as typeof state.sortBy,
})
}
/>
</>
}
>
My projects
</ProjectsListHeader>
<ProjectGroup
loading={loading}
view={state.view}
projects={
isOss()
? sortedProjects
: groupedProjects.myProjects
}
/>
</div>
)}
{otherProjects.length > 0 && (
<div>
<ProjectsListHeader helpText='Projects in Unleash that you have access to.'>
Other projects
</ProjectsListHeader>
<ProjectGroup
loading={loading}
view={state.view}
projects={otherProjects}
/>
</div>
)}
{!loading &&
!myProjects.length &&
!otherProjects.length && (
<>
{state.query?.length ? (
<TablePlaceholder>
No projects found matching &ldquo;
{state.query}
&rdquo;
</TablePlaceholder>
) : (
<TablePlaceholder>
No projects available.
</TablePlaceholder>
)}
</>
)}
</SearchHighlightProvider>
</StyledContainer>
</PageContent>
);
};