diff --git a/frontend/src/component/personalDashboard/ContentGridNoProjects.tsx b/frontend/src/component/personalDashboard/ContentGridNoProjects.tsx index 4a1f68c60562..95cf9b6fbfba 100644 --- a/frontend/src/component/personalDashboard/ContentGridNoProjects.tsx +++ b/frontend/src/component/personalDashboard/ContentGridNoProjects.tsx @@ -66,6 +66,44 @@ type Props = { admins: PersonalDashboardSchemaAdminsItem[]; }; +export const AdminListRendered: React.FC> = ({ + admins, +}) => { + return ( + + {admins.length ? ( + <> +

+ Your Unleash administrator + {admins.length > 1 ? 's are' : ' is'}: +

+ + {admins.map((admin) => { + return ( + + + + {admin.name || + admin.username || + admin.email} + + + ); + })} + + + ) : ( +

You have no Unleash administrators to contact.

+ )} +
+ ); +}; + export const ContentGridNoProjects: React.FC = ({ owners, admins }) => { return ( @@ -98,40 +136,7 @@ export const ContentGridNoProjects: React.FC = ({ owners, admins }) => { 1 Contact Unleash admin - - {admins.length ? ( - <> -

- Your Unleash administrator - {admins.length > 1 ? 's are' : ' is'}: -

- - {admins.map((admin) => { - return ( - - - - {admin.name || - admin.username || - admin.email} - - - ); - })} - - - ) : ( -

- You have no Unleash administrators to - contact. -

- )} -
+ diff --git a/frontend/src/component/personalDashboard/MyProjects.tsx b/frontend/src/component/personalDashboard/MyProjects.tsx index 4b664221a4ab..469329b40841 100644 --- a/frontend/src/component/personalDashboard/MyProjects.tsx +++ b/frontend/src/component/personalDashboard/MyProjects.tsx @@ -14,10 +14,11 @@ import { ProjectSetupComplete } from './ProjectSetupComplete'; import { ConnectSDK, CreateFlag, ExistingFlag } from './ConnectSDK'; import { LatestProjectEvents } from './LatestProjectEvents'; import { RoleAndOwnerInfo } from './RoleAndOwnerInfo'; -import { useEffect, useRef, type FC } from 'react'; +import { forwardRef, useEffect, useRef, type FC } from 'react'; import { StyledCardTitle } from './PersonalDashboard'; import type { PersonalDashboardProjectDetailsSchema, + PersonalDashboardSchemaAdminsItem, PersonalDashboardSchemaProjectsItem, } from '../../openapi'; import { @@ -29,6 +30,7 @@ import { GridItem, SpacedGridItem, } from './Grid'; +import { ContactAdmins, DataError } from './ProjectDetailsError'; const ActiveProjectDetails: FC<{ project: PersonalDashboardSchemaProjectsItem; @@ -108,98 +110,141 @@ const ProjectListItem: FC<{ ); }; -export const MyProjects: FC<{ - projects: PersonalDashboardSchemaProjectsItem[]; - personalDashboardProjectDetails?: PersonalDashboardProjectDetailsSchema; - activeProject: string; - setActiveProject: (project: string) => void; -}> = ({ - projects, - personalDashboardProjectDetails, - setActiveProject, - activeProject, -}) => { - const activeProjectStage = - personalDashboardProjectDetails?.onboardingStatus.status ?? 'loading'; - const setupIncomplete = - activeProjectStage === 'onboarding-started' || - activeProjectStage === 'first-flag-created'; +export const MyProjects = forwardRef< + HTMLDivElement, + { + projects: PersonalDashboardSchemaProjectsItem[]; + personalDashboardProjectDetails?: PersonalDashboardProjectDetailsSchema; + activeProject: string; + setActiveProject: (project: string) => void; + admins: PersonalDashboardSchemaAdminsItem[]; + } +>( + ( + { + projects, + personalDashboardProjectDetails, + setActiveProject, + activeProject, + admins, + }, + ref, + ) => { + const activeProjectStage = + personalDashboardProjectDetails?.onboardingStatus.status ?? + 'loading'; + const setupIncomplete = + activeProjectStage === 'onboarding-started' || + activeProjectStage === 'first-flag-created'; - return ( - - - - My projects - - - {setupIncomplete ? ( - Setup incomplete - ) : null} - - - { + if (error) { + return ; + } + + if ( + activeProjectStage === 'onboarded' && + personalDashboardProjectDetails + ) { + return ( + + ); + } else if ( + activeProjectStage === 'onboarding-started' || + activeProjectStage === 'loading' + ) { + return ; + } else if (activeProjectStage === 'first-flag-created') { + return ; + } + }; + + const box2Content = () => { + if (error) { + return ; + } + + if ( + activeProjectStage === 'onboarded' && + personalDashboardProjectDetails + ) { + return ( + + ); + } + + if (setupIncomplete || activeProjectStage === 'loading') { + return ; + } + }; + + return ( + + + + My projects + + - {projects.map((project) => { - return ( + {setupIncomplete ? ( + Setup incomplete + ) : null} + {error ? ( + Setup state unknown + ) : null} + + + + {projects.map((project) => ( setActiveProject(project.id)} /> - ); - })} - - - - {activeProjectStage === 'onboarded' && - personalDashboardProjectDetails ? ( - - ) : null} - {activeProjectStage === 'onboarding-started' || - activeProjectStage === 'loading' ? ( - - ) : null} - {activeProjectStage === 'first-flag-created' ? ( - - ) : null} - - - {activeProjectStage === 'onboarded' && - personalDashboardProjectDetails ? ( - - ) : null} - {setupIncomplete || activeProjectStage === 'loading' ? ( - - ) : null} - - - - {personalDashboardProjectDetails ? ( + ))} + + + + {box1Content()} + + + {box2Content()} + + + role.name, - )} - owners={personalDashboardProjectDetails.owners} + roles={ + personalDashboardProjectDetails?.roles.map( + (role) => role.name, + ) ?? [] + } + owners={ + personalDashboardProjectDetails?.owners ?? [ + { ownerType: 'user', name: '?' }, + ] + } /> - ) : null} - - - - ); -}; + + +
+ ); + }, +); diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index a8bc0cf41b74..7f6e713a5b96 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -55,7 +55,6 @@ export const StyledCardTitle = styled('div')<{ lines?: number }>( wordBreak: 'break-word', }), ); - const FlagListItem: FC<{ flag: { name: string; project: string; type: string }; selected: boolean; @@ -167,7 +166,6 @@ const useDashboardState = ( setActiveProject, }; }; - export const PersonalDashboard = () => { const { user } = useAuthUser(); @@ -188,8 +186,11 @@ export const PersonalDashboard = () => { 'open' | 'closed' >('welcome-dialog:v1', 'open'); - const { personalDashboardProjectDetails, loading: loadingDetails } = - usePersonalDashboardProjectDetails(activeProject); + const { + personalDashboardProjectDetails, + loading: loadingDetails, + error: detailsError, + } = usePersonalDashboardProjectDetails(activeProject); const activeProjectStage = personalDashboardProjectDetails?.onboardingStatus.status ?? 'loading'; @@ -199,10 +200,12 @@ export const PersonalDashboard = () => { const noProjects = projects.length === 0; - const projectStageRef = useLoading(activeProjectStage === 'loading'); + const projectStageRef = useLoading( + !detailsError && activeProjectStage === 'loading', + ); return ( -
+
Welcome {name} @@ -235,6 +238,8 @@ export const PersonalDashboard = () => { /> ) : ( ({ + display: 'flex', + flexDirection: 'row', + gap: theme.spacing(2), + alignItems: 'center', + fontSize: theme.spacing(1.75), + fontWeight: 'bold', +})); + +const ActionBox = styled('div')(({ theme }) => ({ + flexBasis: '50%', + padding: theme.spacing(4, 2), + display: 'flex', + gap: theme.spacing(3), + flexDirection: 'column', +})); + +export const DataError: FC<{ project: string }> = ({ project }) => { + return ( + + + Couldn't fetch data for project "{project}". + + +

+ The API request to get data for this project returned with an + error. +

+

+ This may be due to an intermittent error or it may be due to + issues with the project's id ("{project}"). You can try + reloading to see if that helps. +

+
+ ); +}; + +export const ContactAdmins: FC<{ + admins: PersonalDashboardSchemaAdminsItem[]; +}> = ({ admins }) => { + return ( + + + Consider contacting one of your Unleash admins for help. + + + + ); +};