diff --git a/frontend/src/component/personalDashboard/WelcomeDialog.tsx b/frontend/src/component/personalDashboard/WelcomeDialog.tsx index 65391d11d5da..a74ff7a196a7 100644 --- a/frontend/src/component/personalDashboard/WelcomeDialog.tsx +++ b/frontend/src/component/personalDashboard/WelcomeDialog.tsx @@ -5,6 +5,7 @@ import { ReactComponent as UnleashLogoWhite } from 'assets/img/logoWithWhiteText import { ThemeMode } from '../common/ThemeMode/ThemeMode'; import onboardingConcepts from 'assets/img/onboardingConcepts.png'; import { ScreenReaderOnly } from '../common/ScreenReaderOnly/ScreenReaderOnly'; +import { formatAssetPath } from 'utils/formatPath'; const StyledDialog = styled(Dialog)(({ theme }) => ({ '& .MuiDialog-paper': { @@ -69,7 +70,7 @@ export const WelcomeDialog: FC = ({ open, onClose }) => { {' '} in order to work effectively with Unleash - +

Environments

diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureToggles.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureToggles.tsx index d3e2e485c3b2..ae3408e9c049 100644 --- a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureToggles.tsx +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectFeatureToggles.tsx @@ -33,17 +33,18 @@ import { useDefaultColumnVisibility } from './hooks/useDefaultColumnVisibility'; import { TableEmptyState } from './TableEmptyState/TableEmptyState'; import { useRowActions } from './hooks/useRowActions'; import { useSelectedData } from './hooks/useSelectedData'; -import { FeatureOverviewCell } from '../../../common/Table/cells/FeatureOverviewCell/FeatureOverviewCell'; +import { FeatureOverviewCell } from 'component/common/Table/cells/FeatureOverviewCell/FeatureOverviewCell'; import { useProjectFeatureSearch, useProjectFeatureSearchActions, } from './useProjectFeatureSearch'; import { AvatarCell } from './AvatarCell'; -import { ProjectOnboarding } from './ProjectOnboarding/ProjectOnboarding'; import { useUiFlag } from 'hooks/useUiFlag'; import { styled } from '@mui/material'; import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview'; import { ConnectSdkDialog } from '../../../onboarding/ConnectSdkDialog'; +import { ProjectOnboarding } from './ProjectOnboarding/ProjectOnboarding'; +import { useLocalStorageState } from 'hooks/useLocalStorageState'; interface IPaginatedProjectFeatureTogglesProps { environments: string[]; @@ -114,12 +115,21 @@ export const ProjectFeatureToggles = ({ const isPlaceholder = Boolean(initialLoad || (loading && total)); - const isOnboarded = - onboardingUIEnabled && project.onboardingStatus.status === 'onboarded'; - const isNotOnboarded = - onboardingUIEnabled && project.onboardingStatus.status !== 'onboarded'; - const hasFeaturesOrOnboarded = - (total !== undefined && total > 0) || isOnboarded; + const [onboardingFlow, setOnboardingFlow] = useLocalStorageState< + 'visible' | 'closed' + >(`onboarding-flow:v1-${projectId}`, 'visible'); + + const notOnboarding = + !onboardingUIEnabled || + (onboardingUIEnabled && + project.onboardingStatus.status === 'onboarded') || + onboardingFlow === 'closed'; + const isOnboarding = + onboardingUIEnabled && + project.onboardingStatus.status !== 'onboarded' && + onboardingFlow === 'visible'; + const showFeaturesTable = + (total !== undefined && total > 0) || notOnboarding; const columns = useMemo( () => [ @@ -406,16 +416,17 @@ export const ProjectFeatureToggles = ({ return ( } /> { {}} + setOnboardingFlow={() => {}} /> } /> @@ -45,9 +46,10 @@ test('Project can connect SDK', async () => { {}} + setOnboardingFlow={() => {}} /> } /> diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/ProjectOnboarding.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/ProjectOnboarding.tsx index d00324eedf2a..d708ad410756 100644 --- a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/ProjectOnboarding.tsx +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/ProjectOnboarding.tsx @@ -1,29 +1,204 @@ -import { styled } from '@mui/material'; -import { WelcomeToProject } from './WelcomeToProject'; +import { IconButton, styled, Tooltip, Typography } from '@mui/material'; +import Add from '@mui/icons-material/Add'; +import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions'; +import { FlagCreationButton } from '../ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader'; +import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton'; +import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview'; import { SdkExample } from './SdkExample'; +import CloseIcon from '@mui/icons-material/Close'; interface IProjectOnboardingProps { projectId: string; setConnectSdkOpen: (open: boolean) => void; + setOnboardingFlow: (status: 'visible' | 'closed') => void; +} + +interface ICreateFlagProps { + projectId: string; } const Container = styled('div')(({ theme }) => ({ display: 'flex', - width: '100%', + flexDirection: 'column', + backgroundColor: theme.palette.background.paper, + flexBasis: '70%', + borderRadius: theme.shape.borderRadiusLarge, +})); + +const TitleBox = styled('div')(({ theme }) => ({ + padding: theme.spacing(2, 7, 2, 7), + borderBottom: '1px solid', + borderColor: theme.palette.divider, + minHeight: '80px', +})); + +const Actions = styled('div')(({ theme }) => ({ + display: 'flex', + flexGrow: 1, +})); + +const ActionBox = styled('div')(({ theme }) => ({ + flexBasis: '50%', + padding: theme.spacing(3, 2, 6, 8), + display: 'flex', + gap: theme.spacing(3), + flexDirection: 'column', +})); + +const TitleContainer = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'row', gap: theme.spacing(2), + alignItems: 'center', + fontSize: theme.spacing(1.75), + fontWeight: 'bold', +})); + +const NeutralCircleContainer = styled('span')(({ theme }) => ({ + width: '28px', + height: '28px', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: theme.palette.neutral.border, + borderRadius: '50%', +})); + +const MainCircleContainer = styled(NeutralCircleContainer)(({ theme }) => ({ + backgroundColor: theme.palette.primary.main, + color: theme.palette.background.paper, +})); + +const ExistingFlagContainer = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + gap: theme.spacing(3), + height: '100%', +})); + +const SuccessContainer = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + + fontSize: theme.spacing(1.75), + fontWeight: 'bold', + backgroundColor: theme.palette.success.light, + borderRadius: theme.shape.borderRadiusLarge, + padding: theme.spacing(2, 2, 2, 2), +})); + +const TitleRow = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', })); export const ProjectOnboarding = ({ projectId, setConnectSdkOpen, + setOnboardingFlow, }: IProjectOnboardingProps) => { + const { project } = useProjectOverview(projectId); + const isFirstFlagCreated = + project.onboardingStatus.status === 'first-flag-created'; + + const closeOnboardingFlow = () => { + setOnboardingFlow('closed'); + }; + return ( - - + + + + Welcome to your project + + + + + + + + + Complete the steps below to start working with this project + + + + + {project.onboardingStatus.status === + 'first-flag-created' ? ( + + ) : ( + + )} + + + + 2 + Connect an SDK + + + Your project is not yet connected to any SDK. To start + using your feature flag, connect an SDK to the project. + + { + setConnectSdkOpen(true); + }} + maxWidth='200px' + projectId={projectId} + Icon={Add} + disabled={!isFirstFlagCreated} + permission={CREATE_FEATURE} + > + Connect SDK + + + + + + ); }; + +const CreateFlag = ({ projectId }: ICreateFlagProps) => { + const { refetch } = useProjectOverview(projectId); + return ( + <> + + 1 + Create a feature flag + + +

The project currently holds no feature flags.
+
Create one to get started.
+ + + + ); +}; + +const ExistingFlag = () => { + return ( + + + + Create a feature flag + + + + Congratulations! You have created your first flag + + + Click into the flag below to customize the flag further + + + + ); +}; diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/SdkExample.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/SdkExample.tsx index da68efd621bd..5a46884f655a 100644 --- a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/SdkExample.tsx +++ b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/SdkExample.tsx @@ -4,28 +4,13 @@ import Select from 'component/common/select'; import { useState } from 'react'; import { allSdks } from '../../../../onboarding/sharedTypes'; -const Container = styled('div')(({ theme }) => ({ +const TitleContainer = styled('div')(({ theme }) => ({ display: 'flex', - flexDirection: 'column', - backgroundColor: theme.palette.background.paper, - flexBasis: '30%', - borderRadius: theme.shape.borderRadiusLarge, -})); - -const TitleBox = styled('div')(({ theme }) => ({ - padding: theme.spacing(2, 7, 2, 7), - borderBottom: '1px solid', - borderColor: theme.palette.divider, - minHeight: '80px', + flexDirection: 'row', + gap: theme.spacing(2), alignItems: 'center', - display: 'flex', -})); - -const ContentBox = styled('div')(({ theme }) => ({ - padding: theme.spacing(3, 2, 6, 8), - display: 'flex', - gap: theme.spacing(3), - flexDirection: 'column', + fontSize: theme.spacing(1.75), + fontWeight: 'bold', })); const StyledLink = styled(Link)({ @@ -45,27 +30,22 @@ export const SdkExample = () => { setSelectedSdk(event.target.value); }; return ( - - - View SDK Example - - - - - See an example implementation of your preferred SDK. - - + Go to example + ); }; diff --git a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/WelcomeToProject.tsx b/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/WelcomeToProject.tsx deleted file mode 100644 index 6a1e98410340..000000000000 --- a/frontend/src/component/project/Project/PaginatedProjectFeatureToggles/ProjectOnboarding/WelcomeToProject.tsx +++ /dev/null @@ -1,179 +0,0 @@ -import { styled, Typography } from '@mui/material'; -import Add from '@mui/icons-material/Add'; -import { CREATE_FEATURE } from 'component/providers/AccessProvider/permissions'; -import { FlagCreationButton } from '../ProjectFeatureTogglesHeader/ProjectFeatureTogglesHeader'; -import ResponsiveButton from 'component/common/ResponsiveButton/ResponsiveButton'; -import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview'; - -interface IWelcomeToProjectProps { - projectId: string; - setConnectSdkOpen: (open: boolean) => void; -} - -interface ICreateFlagProps { - projectId: string; -} - -const Container = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - backgroundColor: theme.palette.background.paper, - flexBasis: '70%', - borderRadius: theme.shape.borderRadiusLarge, -})); - -const TitleBox = styled('div')(({ theme }) => ({ - padding: theme.spacing(2, 7, 2, 7), - borderBottom: '1px solid', - borderColor: theme.palette.divider, - minHeight: '80px', -})); - -const Actions = styled('div')(({ theme }) => ({ - display: 'flex', - flexGrow: 1, -})); - -const ActionBox = styled('div')(({ theme }) => ({ - flexBasis: '50%', - padding: theme.spacing(3, 2, 6, 8), - display: 'flex', - gap: theme.spacing(3), - flexDirection: 'column', -})); - -const TitleContainer = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'row', - gap: theme.spacing(2), - alignItems: 'center', - fontSize: theme.spacing(1.75), - fontWeight: 'bold', -})); - -const NeutralCircleContainer = styled('span')(({ theme }) => ({ - width: '28px', - height: '28px', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - backgroundColor: theme.palette.neutral.border, - borderRadius: '50%', -})); - -const MainCircleContainer = styled(NeutralCircleContainer)(({ theme }) => ({ - backgroundColor: theme.palette.primary.main, - color: theme.palette.background.paper, -})); - -const ExistingFlagContainer = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(3), - height: '100%', -})); - -const SuccessContainer = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - - fontSize: theme.spacing(1.75), - fontWeight: 'bold', - backgroundColor: theme.palette.success.light, - borderRadius: theme.shape.borderRadiusLarge, - padding: theme.spacing(2, 2, 2, 2), -})); - -export const WelcomeToProject = ({ - projectId, - setConnectSdkOpen, -}: IWelcomeToProjectProps) => { - const { project, refetch } = useProjectOverview(projectId); - const isFirstFlagCreated = - project.onboardingStatus.status === 'first-flag-created'; - - return ( - - - - Welcome to your project - - - Complete the steps below to start working with this project - - - - - {project.onboardingStatus.status === - 'first-flag-created' ? ( - - ) : ( - - )} - - - - 2 - Connect an SDK - - - Your project is not yet connected to any SDK. To start - using your feature flag, connect an SDK to the project. - - { - setConnectSdkOpen(true); - }} - maxWidth='200px' - projectId={projectId} - Icon={Add} - disabled={!isFirstFlagCreated} - permission={CREATE_FEATURE} - > - Connect SDK - - - - - ); -}; - -const CreateFlag = ({ projectId }: ICreateFlagProps) => { - const { refetch } = useProjectOverview(projectId); - return ( - <> - - 1 - Create a feature flag - - -
The project currently holds no feature flags.
-
Create one to get started.
-
- - - ); -}; - -const ExistingFlag = () => { - return ( - - - - Create a feature flag - - - - Congratulations! You have created your first flag - - - Click into the flag below to customize the flag further - - - - ); -}; diff --git a/frontend/src/component/project/ProjectCard/LegacyProjectOwners/LegacyProjectOwners.tsx b/frontend/src/component/project/ProjectCard/LegacyProjectOwners/LegacyProjectOwners.tsx deleted file mode 100644 index 3f9d22864b8e..000000000000 --- a/frontend/src/component/project/ProjectCard/LegacyProjectOwners/LegacyProjectOwners.tsx +++ /dev/null @@ -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 = ({ owners = [] }) => { - const ownersMap = useOwnersMap(); - const users = owners.map(ownersMap); - - return ( - - - - {owners.length === 1 ? 'Owner' : 'Owners'} - - - - {users[0]?.name}} - elseShow={
} - /> - - ); -}; diff --git a/frontend/src/component/project/ProjectCard/ProjectCardFooter/ProjectCardFooter.tsx b/frontend/src/component/project/ProjectCard/ProjectCardFooter/ProjectCardFooter.tsx index 8c286ddb1e8e..3ed959960000 100644 --- a/frontend/src/component/project/ProjectCard/ProjectCardFooter/ProjectCardFooter.tsx +++ b/frontend/src/component/project/ProjectCard/ProjectCardFooter/ProjectCardFooter.tsx @@ -2,12 +2,9 @@ import type React from 'react'; import type { FC } from 'react'; import { Box, styled } from '@mui/material'; import { + ProjectOwners, type IProjectOwnersProps, - ProjectOwners as LegacyProjectOwners, -} from '../LegacyProjectOwners/LegacyProjectOwners'; -import { ProjectOwners } from './ProjectOwners/ProjectOwners'; -import { useUiFlag } from 'hooks/useUiFlag'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +} from './ProjectOwners/ProjectOwners'; interface IProjectCardFooterProps { id?: string; @@ -31,20 +28,13 @@ const StyledFooter = styled(Box)<{ disabled: boolean }>( ); export const ProjectCardFooter: FC = ({ - id, children, owners, disabled = false, }) => { - const projectListImprovementsEnabled = useUiFlag('projectListImprovements'); - return ( - } - elseShow={} - /> + {children} ); diff --git a/frontend/src/component/project/ProjectCard/ProjectModeBadge/ProjectModeBadge.tsx b/frontend/src/component/project/ProjectCard/ProjectModeBadge/ProjectModeBadge.tsx index d2796b265748..92bc99ef36f0 100644 --- a/frontend/src/component/project/ProjectCard/ProjectModeBadge/ProjectModeBadge.tsx +++ b/frontend/src/component/project/ProjectCard/ProjectModeBadge/ProjectModeBadge.tsx @@ -1,11 +1,7 @@ import type { FC } from 'react'; -import LockIcon from '@mui/icons-material/Lock'; import ProtectedProjectIcon from '@mui/icons-material/LockOutlined'; -import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import PrivateProjectIcon from '@mui/icons-material/VisibilityOffOutlined'; import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip'; -import { Badge } from 'component/common/Badge/Badge'; -import { useUiFlag } from 'hooks/useUiFlag'; import { styled } from '@mui/material'; interface IProjectModeBadgeProps { @@ -19,50 +15,28 @@ const StyledIcon = styled('div')(({ theme }) => ({ })); export const ProjectModeBadge: FC = ({ mode }) => { - const projectListImprovementsEnabled = useUiFlag('projectListImprovements'); - if (mode === 'private') { - if (projectListImprovementsEnabled) { - return ( - - - - - - ); - } return ( - } /> + + + ); } if (mode === 'protected') { - if (projectListImprovementsEnabled) { - return ( - - - - - - ); - } return ( - } /> + + + ); } diff --git a/frontend/src/component/project/ProjectList/ArchiveProjectList.tsx b/frontend/src/component/project/ProjectList/ArchiveProjectList.tsx index 84c3897f9044..21bfa988fd40 100644 --- a/frontend/src/component/project/ProjectList/ArchiveProjectList.tsx +++ b/frontend/src/component/project/ProjectList/ArchiveProjectList.tsx @@ -140,7 +140,6 @@ export const ArchiveProjectList: FC = () => { ({ - maxWidth: '500px', - marginBottom: theme.spacing(2), -})); - -const StyledContainer = styled('div')(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - gap: theme.spacing(4), -})); - -type PageQueryType = Partial>; - -interface ICreateButtonData { - disabled: boolean; - tooltip?: Omit; - 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: ( - - ), - sx: { maxWidth: '320px' }, - variant: 'custom', - }, - endIcon: ( - } - lightmode={} - /> - ), - }; - } 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 ( - <> - setOpenCreateDialog(true)} - maxWidth='700px' - permission={CREATE_PROJECT} - disabled={createButtonData.disabled || loading} - tooltipProps={createButtonData.tooltip} - data-testid={NAVIGATE_TO_CREATE_PROJECT} - > - New project - - 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 ( - - ); - }; - - return ( - - - - - - } - /> - <> - - Archived projects - - - - - - - } - > - - } - /> - - } - > - - ( - - )} - /> - - - - - - ); -}; diff --git a/frontend/src/component/project/ProjectList/ProjectGroup.tsx b/frontend/src/component/project/ProjectList/ProjectGroup.tsx index 001666e51fbc..f07f0ddb850e 100644 --- a/frontend/src/component/project/ProjectList/ProjectGroup.tsx +++ b/frontend/src/component/project/ProjectList/ProjectGroup.tsx @@ -1,13 +1,11 @@ import type { ComponentType, ReactNode } from 'react'; 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 { ProjectSchema } from 'openapi'; import loadingData from './loadingData'; import { TablePlaceholder } from 'component/common/Table'; import { styled, Typography } from '@mui/material'; -import { useUiFlag } from 'hooks/useUiFlag'; import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext'; import { flexColumn } from 'themes/themeStyles'; @@ -52,10 +50,6 @@ type ProjectGroupProps = { HeaderActions?: ReactNode; projects: ProjectSchema[]; loading: boolean; - /** - * @deprecated remove with projectListImprovements - */ - searchValue?: string; placeholder?: string; ProjectCardComponent?: ComponentType; link?: boolean; @@ -67,15 +61,11 @@ export const ProjectGroup = ({ HeaderActions, projects, loading, - searchValue, placeholder = 'No projects available.', ProjectCardComponent, link = true, }: ProjectGroupProps) => { - const projectListImprovementsEnabled = useUiFlag('projectListImprovements'); - const ProjectCard = - ProjectCardComponent ?? - (projectListImprovementsEnabled ? NewProjectCard : LegacyProjectCard); + const ProjectCard = ProjectCardComponent ?? NewProjectCard; const { searchQuery } = useSearchHighlightContext(); return ( @@ -91,10 +81,7 @@ export const ProjectGroup = ({ } /> {sectionSubtitle} @@ -108,11 +95,11 @@ export const ProjectGroup = ({ condition={projects.length < 1 && !loading} show={ 0} + condition={searchQuery?.length > 0} show={ No projects found matching “ - {searchValue || searchQuery} + {searchQuery} ” } diff --git a/frontend/src/component/project/ProjectList/ProjectList.tsx b/frontend/src/component/project/ProjectList/ProjectList.tsx index 801f59039f03..cd6ecadd93f3 100644 --- a/frontend/src/component/project/ProjectList/ProjectList.tsx +++ b/frontend/src/component/project/ProjectList/ProjectList.tsx @@ -1,4 +1,4 @@ -import { type FC, useCallback } from 'react'; +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'; @@ -9,11 +9,9 @@ import theme from 'themes/theme'; import { Search } from 'component/common/Search/Search'; import { useProfile } from 'hooks/api/getters/useProfile/useProfile'; import { ProjectGroup } from './ProjectGroup'; -import { useUiFlag } from 'hooks/useUiFlag'; import { ProjectsListSort } from './ProjectsListSort/ProjectsListSort'; import { useProjectsListState } from './hooks/useProjectsListState'; import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext'; -import { ProjectList as LegacyProjectList } from './LegacyProjectList'; import { ProjectCreationButton } from './ProjectCreationButton/ProjectCreationButton'; import { useGroupedProjects } from './hooks/useGroupedProjects'; import { useProjectsSearchAndSort } from './hooks/useProjectsSearchAndSort'; @@ -30,7 +28,7 @@ const StyledContainer = styled('div')(({ theme }) => ({ gap: theme.spacing(6), })); -const NewProjectList = () => { +export const ProjectList = () => { const { projects, loading, error, refetch } = useProjects(); const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); @@ -140,13 +138,3 @@ const NewProjectList = () => { ); }; - -export const ProjectList: FC = () => { - const projectListImprovementsEnabled = useUiFlag('projectListImprovements'); - - if (projectListImprovementsEnabled) { - return ; - } - - return ; -}; diff --git a/frontend/src/interfaces/uiConfig.ts b/frontend/src/interfaces/uiConfig.ts index 784192cf63a6..837999b05eb0 100644 --- a/frontend/src/interfaces/uiConfig.ts +++ b/frontend/src/interfaces/uiConfig.ts @@ -86,7 +86,6 @@ export type UiFlags = { enableLegacyVariants?: boolean; navigationSidebar?: boolean; flagCreator?: boolean; - projectListImprovements?: boolean; onboardingUI?: boolean; eventTimeline?: boolean; personalDashboardUI?: boolean; diff --git a/src/lib/types/experimental.ts b/src/lib/types/experimental.ts index 864639592743..bf245a5c1df5 100644 --- a/src/lib/types/experimental.ts +++ b/src/lib/types/experimental.ts @@ -56,7 +56,6 @@ export type IFlagKey = | 'extendedMetrics' | 'removeUnsafeInlineStyleSrc' | 'originMiddleware' - | 'projectListImprovements' | 'addonUsageMetrics' | 'onboardingMetrics' | 'onboardingUI' @@ -279,10 +278,6 @@ const flags: IFlags = { process.env.UNLEASH_EXPERIMENTAL_ORIGIN_MIDDLEWARE, false, ), - projectListImprovements: parseEnvVarBoolean( - process.env.UNLEASH_EXPERIMENTAL_PROJECT_LIST_IMPROVEMENTS, - false, - ), addonUsageMetrics: parseEnvVarBoolean( process.env.UNLEASH_EXPERIMENTAL_ADDON_USAGE_METRICS, false, diff --git a/src/server-dev.ts b/src/server-dev.ts index f44dfccbfd1e..3517154721a7 100644 --- a/src/server-dev.ts +++ b/src/server-dev.ts @@ -51,7 +51,6 @@ process.nextTick(async () => { enableLegacyVariants: false, extendedMetrics: true, originMiddleware: true, - projectListImprovements: true, addonUsageMetrics: true, onboardingMetrics: true, onboardingUI: true,