mirror of
https://github.com/Unleash/unleash.git
synced 2025-11-10 01:19:53 +01:00
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>
197 lines
8.3 KiB
TypeScript
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 “
|
|
{state.query}
|
|
”
|
|
</TablePlaceholder>
|
|
) : (
|
|
<TablePlaceholder>
|
|
No projects available.
|
|
</TablePlaceholder>
|
|
)}
|
|
</>
|
|
)}
|
|
</SearchHighlightProvider>
|
|
</StyledContainer>
|
|
</PageContent>
|
|
);
|
|
};
|