From ad9d87c913fd3f45907bf2da0aa70d439e4463cf Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Tue, 8 Oct 2024 14:31:43 +0200 Subject: [PATCH 01/20] Chore: add placeholders --- .../personalDashboard/PersonalDashboard.tsx | 191 +++++++++++++----- 1 file changed, 135 insertions(+), 56 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index d0f4747e14c3..e490ade9055e 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -1,5 +1,6 @@ import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser'; import { + Accordion, Button, IconButton, Link, @@ -106,14 +107,23 @@ const useDashboardState = ( projects: PersonalDashboardSchemaProjectsItem[], flags: PersonalDashboardSchemaFlagsItem[], ) => { + type SectionState = 'expanded' | 'collapsed'; type State = { activeProject: string | undefined; activeFlag: PersonalDashboardSchemaFlagsItem | undefined; + sections: { + projects: { state: SectionState }; + flags: { state: SectionState }; + }; }; - const defaultState = { + const defaultState: State = { activeProject: undefined, activeFlag: undefined, + sections: { + projects: { state: 'expanded' as const }, + flags: { state: 'expanded' as const }, + }, }; const [state, setState] = useLocalStorageState( @@ -135,6 +145,7 @@ const useDashboardState = ( if (setDefaultFlag || setDefaultProject) { setState({ + ...state, activeFlag: setDefaultFlag ? flags[0] : state.activeFlag, activeProject: setDefaultProject ? projects[0].id @@ -159,11 +170,27 @@ const useDashboardState = ( }); }; + const toggleSectionState = (section: keyof State['sections']) => { + setState({ + ...state, + sections: { + ...state.sections, + [section]: { + state: + state.sections[section].state === 'expanded' + ? 'collapsed' + : 'expanded', + }, + }, + }); + }; + return { activeFlag, setActiveFlag, activeProject, setActiveProject, + toggleSectionState, }; }; @@ -182,6 +209,34 @@ const ViewKeyConceptsButton = styled(Button)(({ theme }) => ({ margin: 0, })); +const SectionAccordion = styled(Accordion)(({ theme }) => ({ + border: `1px solid ${theme.palette.divider}`, + borderRadius: theme.shape.borderRadiusMedium, + backgroundColor: theme.palette.background.elevation1, + boxShadow: 'none', + margin: 0, + '& .expanded': { + '&:before': { + opacity: '0 !important', + }, + }, +})); + +const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ + border: 'none', + padding: theme.spacing(0.5, 3), + '&:hover .valuesExpandLabel': { + textDecoration: 'underline', + }, +})); + +const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ + borderTop: `1px dashed ${theme.palette.divider}`, + display: 'flex', + flexDirection: 'column', + padding: 0, +})); + export const PersonalDashboard = () => { const { user } = useAuthUser(); @@ -195,8 +250,13 @@ export const PersonalDashboard = () => { const projects = personalDashboard?.projects || []; - const { activeProject, setActiveProject, activeFlag, setActiveFlag } = - useDashboardState(projects, personalDashboard?.flags ?? []); + const { + activeProject, + setActiveProject, + activeFlag, + setActiveFlag, + toggleSectionState, + } = useDashboardState(projects, personalDashboard?.flags ?? []); const [welcomeDialog, setWelcomeDialog] = useLocalStorageState< 'open' | 'closed' @@ -257,61 +317,80 @@ export const PersonalDashboard = () => { /> )} - - - - My feature flags - - - {activeFlag ? ( - - ) : null} - - - {personalDashboard && - personalDashboard.flags.length > 0 ? ( - + + My feature flags + + + + + - {personalDashboard.flags.map((flag) => ( - setActiveFlag(flag)} + + My feature flags + + + + {activeFlag ? ( + - ))} - - ) : ( - - You have not created or favorited any feature - flags. Once you do, they will show up here. - - )} - - - - {activeFlag ? ( - - ) : ( - - )} - - - + ) : null} + + + {personalDashboard && + personalDashboard.flags.length > 0 ? ( + + {personalDashboard.flags.map((flag) => ( + + setActiveFlag(flag) + } + /> + ))} + + ) : ( + + You have not created or favorited any + feature flags. Once you do, they will + show up here. + + )} + + + + {activeFlag ? ( + + ) : ( + + )} + + + + + setWelcomeDialog('closed')} From ff8442cf82732f98a34d9009b68f6f5cb8952104 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Tue, 8 Oct 2024 15:08:46 +0200 Subject: [PATCH 02/20] feat: sketch out switch to accordions --- .../ContentGridNoProjects.tsx | 6 - .../src/component/personalDashboard/Grid.tsx | 3 - .../personalDashboard/MyProjects.tsx | 3 - .../personalDashboard/PersonalDashboard.tsx | 133 ++++++++++-------- 4 files changed, 76 insertions(+), 69 deletions(-) diff --git a/frontend/src/component/personalDashboard/ContentGridNoProjects.tsx b/frontend/src/component/personalDashboard/ContentGridNoProjects.tsx index 6273fe65a0aa..02f791203a80 100644 --- a/frontend/src/component/personalDashboard/ContentGridNoProjects.tsx +++ b/frontend/src/component/personalDashboard/ContentGridNoProjects.tsx @@ -108,12 +108,6 @@ export const ContentGridNoProjects: React.FC = ({ owners, admins }) => { return ( - - My projects - - - Potential next steps - diff --git a/frontend/src/component/personalDashboard/Grid.tsx b/frontend/src/component/personalDashboard/Grid.tsx index 2038a36d9166..bce36d2e0581 100644 --- a/frontend/src/component/personalDashboard/Grid.tsx +++ b/frontend/src/component/personalDashboard/Grid.tsx @@ -10,7 +10,6 @@ const ContentGrid = styled('article')(({ theme }) => { backgroundColor: theme.palette.divider, borderRadius: `${theme.shape.borderRadiusLarge}px`, overflow: 'hidden', - border: `0.5px solid ${theme.palette.divider}`, gap: `1px`, display: 'flex', flexFlow: 'column nowrap', @@ -41,7 +40,6 @@ export const ProjectGrid = styled(ContentGrid)( gridTemplateColumns: '1fr 1fr 1fr', display: 'grid', gridTemplateAreas: ` - "header header header" "projects box1 box2" ". owners owners" `, @@ -53,7 +51,6 @@ export const FlagGrid = styled(ContentGrid)( gridTemplateColumns: '1fr 1fr 1fr', display: 'grid', gridTemplateAreas: ` - "title lifecycle lifecycle" "flags chart chart" `, }), diff --git a/frontend/src/component/personalDashboard/MyProjects.tsx b/frontend/src/component/personalDashboard/MyProjects.tsx index 32ac8cb7cbe7..451fa1b14797 100644 --- a/frontend/src/component/personalDashboard/MyProjects.tsx +++ b/frontend/src/component/personalDashboard/MyProjects.tsx @@ -189,9 +189,6 @@ export const MyProjects = forwardRef< return ( - - My projects - ({ marginBottom: theme.spacing(4), @@ -190,6 +191,7 @@ const useDashboardState = ( setActiveFlag, activeProject, setActiveProject, + sectionState: state.sections, toggleSectionState, }; }; @@ -212,28 +214,21 @@ const ViewKeyConceptsButton = styled(Button)(({ theme }) => ({ const SectionAccordion = styled(Accordion)(({ theme }) => ({ border: `1px solid ${theme.palette.divider}`, borderRadius: theme.shape.borderRadiusMedium, - backgroundColor: theme.palette.background.elevation1, + backgroundColor: theme.palette.background.paper, boxShadow: 'none', - margin: 0, - '& .expanded': { - '&:before': { - opacity: '0 !important', - }, - }, })); const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ border: 'none', - padding: theme.spacing(0.5, 3), - '&:hover .valuesExpandLabel': { - textDecoration: 'underline', + padding: theme.spacing(2, 4), + margin: 0, + '&>*': { + margin: '0 !important', }, })); const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ - borderTop: `1px dashed ${theme.palette.divider}`, - display: 'flex', - flexDirection: 'column', + borderTop: `1px solid ${theme.palette.divider}`, padding: 0, })); @@ -256,6 +251,7 @@ export const PersonalDashboard = () => { activeFlag, setActiveFlag, toggleSectionState, + sectionState, } = useDashboardState(projects, personalDashboard?.flags ?? []); const [welcomeDialog, setWelcomeDialog] = useLocalStorageState< @@ -299,54 +295,77 @@ export const PersonalDashboard = () => { - {noProjects && personalDashboard ? ( - - ) : ( - toggleSectionState('projects')} + > + } - /> - )} + > + My projects + + + {noProjects && personalDashboard ? ( + + ) : ( + + )} + + - - + toggleSectionState('projects')} + > + + } + > My feature flags - - - - My feature flags - - - - {activeFlag ? ( - - ) : null} - + + { + // + // + // My feature flags + // + // + // + // {activeFlag ? ( + // + // ) : null} + // + } {personalDashboard && personalDashboard.flags.length > 0 ? ( From 471b970b924fe8c86ac6bf6f3630739a235e882b Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 08:53:05 +0200 Subject: [PATCH 03/20] feat: save state --- .../personalDashboard/PersonalDashboard.tsx | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index bb4104eb3241..fd756dac5b0b 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -144,15 +144,14 @@ const useDashboardState = ( (project) => project.id === state.activeProject, )); - if (setDefaultFlag || setDefaultProject) { - setState({ - ...state, - activeFlag: setDefaultFlag ? flags[0] : state.activeFlag, - activeProject: setDefaultProject - ? projects[0].id - : state.activeProject, - }); - } + setState({ + ...defaultState, + ...state, + activeFlag: setDefaultFlag ? flags[0] : state.activeFlag, + activeProject: setDefaultProject + ? projects[0].id + : state.activeProject, + }); }); const { activeFlag, activeProject } = state; @@ -216,6 +215,12 @@ const SectionAccordion = styled(Accordion)(({ theme }) => ({ borderRadius: theme.shape.borderRadiusMedium, backgroundColor: theme.palette.background.paper, boxShadow: 'none', + + '& .expanded': { + '&:before': { + opacity: '0 !important', + }, + }, })); const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ @@ -225,10 +230,10 @@ const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ '&>*': { margin: '0 !important', }, + borderBottom: `1px solid ${theme.palette.divider}`, })); const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ - borderTop: `1px solid ${theme.palette.divider}`, padding: 0, })); @@ -296,13 +301,16 @@ export const PersonalDashboard = () => { toggleSectionState('projects')} > } + id='projects-panel-header' + aria-controls='projects-panel-content' > My projects @@ -328,13 +336,15 @@ export const PersonalDashboard = () => { toggleSectionState('projects')} + expanded={!(sectionState?.flags.state === 'collapsed')} + onChange={() => toggleSectionState('flags')} > } + id='flags-panel-header' + aria-controls='flags-panel-content' > My feature flags From cbcf2fcc5c65eed9592946beb8784043a80edbbc Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 08:55:34 +0200 Subject: [PATCH 04/20] feat: space content --- .../component/personalDashboard/PersonalDashboard.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index fd756dac5b0b..7eb0b699eede 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -237,6 +237,11 @@ const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ padding: 0, })); +const MainContent = styled('div')(({ theme }) => ({ + display: 'flex', + gap: theme.spacing(2), +})); + export const PersonalDashboard = () => { const { user } = useAuthUser(); @@ -282,7 +287,7 @@ export const PersonalDashboard = () => { ); return ( -
+ Welcome {name} @@ -424,7 +429,7 @@ export const PersonalDashboard = () => { open={welcomeDialog === 'open'} onClose={() => setWelcomeDialog('closed')} /> -
+ ); }; From 233dfe1841985daf6ead06206c4bdd8776d91fb8 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 08:55:43 +0200 Subject: [PATCH 05/20] feat: remove code --- .../personalDashboard/PersonalDashboard.tsx | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 7eb0b699eede..52797dc06c2a 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -356,31 +356,6 @@ export const PersonalDashboard = () => { - { - // - // - // My feature flags - // - // - // - // {activeFlag ? ( - // - // ) : null} - // - } {personalDashboard && personalDashboard.flags.length > 0 ? ( From 8dfe06f0f7c9d2fe6f69984e7fa9856a99e6b025 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 08:56:57 +0200 Subject: [PATCH 06/20] feat: fix some layout issues --- frontend/src/component/personalDashboard/PersonalDashboard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 52797dc06c2a..4349fb022eab 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -201,7 +201,6 @@ const WelcomeSection = styled('div')(({ theme }) => ({ gap: theme.spacing(1), flexFlow: 'row wrap', alignItems: 'baseline', - marginBottom: theme.spacing(2), })); const ViewKeyConceptsButton = styled(Button)(({ theme }) => ({ @@ -239,6 +238,7 @@ const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ const MainContent = styled('div')(({ theme }) => ({ display: 'flex', + flexDirection: 'column', gap: theme.spacing(2), })); From 797b96bda1cde26dde9be7005aa1187bb3487ae7 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 09:17:09 +0200 Subject: [PATCH 07/20] feat: animation trickery --- .../personalDashboard/PersonalDashboard.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 4349fb022eab..c73eec983c67 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -214,12 +214,20 @@ const SectionAccordion = styled(Accordion)(({ theme }) => ({ borderRadius: theme.shape.borderRadiusMedium, backgroundColor: theme.palette.background.paper, boxShadow: 'none', - '& .expanded': { '&:before': { opacity: '0 !important', }, }, + + // add a top border to the region when the accordion is collapsed. + // This retains the border between the summary and the region + // during the collapsing animation + "[aria-expanded='false']+.MuiCollapse-root .MuiAccordion-region": { + borderTop: `1px solid ${theme.palette.divider}`, + }, + + overflow: 'hidden', })); const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ @@ -229,7 +237,10 @@ const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ '&>*': { margin: '0 !important', }, - borderBottom: `1px solid ${theme.palette.divider}`, + "&[aria-expanded='true']": { + // only add the border when it's open + borderBottom: `1px solid ${theme.palette.divider}`, + }, })); const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ From 426bfdcf40bc78486e2668710f4e26353a07b3ff Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 09:37:30 +0200 Subject: [PATCH 08/20] feat: make headers thinner --- .../src/component/personalDashboard/PersonalDashboard.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index c73eec983c67..2ea21560dfb9 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -328,7 +328,9 @@ export const PersonalDashboard = () => { id='projects-panel-header' aria-controls='projects-panel-content' > - My projects + + My projects +
{noProjects && personalDashboard ? ( @@ -362,7 +364,9 @@ export const PersonalDashboard = () => { id='flags-panel-header' aria-controls='flags-panel-content' > - My feature flags + + My feature flags + From 3c76be9973c41826b86aad871151ce2eebe48212 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 09:54:53 +0200 Subject: [PATCH 09/20] Chore: clean up unused code --- .../personalDashboard/PersonalDashboard.tsx | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 2ea21560dfb9..85e6db689909 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -35,12 +35,6 @@ import { import { ContentGridNoProjects } from './ContentGridNoProjects'; import ExpandMore from '@mui/icons-material/ExpandMore'; -const ScreenExplanation = styled('div')(({ theme }) => ({ - marginBottom: theme.spacing(4), - display: 'flex', - alignItems: 'center', -})); - export const StyledCardTitle = styled('div')<{ lines?: number }>( ({ theme, lines = 2 }) => ({ fontWeight: theme.typography.fontWeightRegular, @@ -203,11 +197,11 @@ const WelcomeSection = styled('div')(({ theme }) => ({ alignItems: 'baseline', })); -const ViewKeyConceptsButton = styled(Button)(({ theme }) => ({ +const ViewKeyConceptsButton = styled(Button)({ fontWeight: 'normal', padding: 0, margin: 0, -})); +}); const SectionAccordion = styled(Accordion)(({ theme }) => ({ border: `1px solid ${theme.palette.divider}`, @@ -243,9 +237,9 @@ const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ }, })); -const StyledAccordionDetails = styled(AccordionDetails)(({ theme }) => ({ +const StyledAccordionDetails = styled(AccordionDetails)({ padding: 0, -})); +}); const MainContent = styled('div')(({ theme }) => ({ display: 'flex', @@ -258,11 +252,7 @@ export const PersonalDashboard = () => { const name = user?.name; - const { - personalDashboard, - refetch: refetchDashboard, - loading: personalDashboardLoading, - } = usePersonalDashboard(); + const { personalDashboard } = usePersonalDashboard(); const projects = personalDashboard?.projects || []; @@ -279,17 +269,11 @@ export const PersonalDashboard = () => { 'open' | 'closed' >('welcome-dialog:v1', 'open'); - const { - personalDashboardProjectDetails, - loading: loadingDetails, - error: detailsError, - } = usePersonalDashboardProjectDetails(activeProject); + const { personalDashboardProjectDetails, error: detailsError } = + usePersonalDashboardProjectDetails(activeProject); const activeProjectStage = personalDashboardProjectDetails?.onboardingStatus.status ?? 'loading'; - const setupIncomplete = - activeProjectStage === 'onboarding-started' || - activeProjectStage === 'first-flag-created'; const noProjects = projects.length === 0; From 2bf659c9fd54a72f0f616ef402de33a60d34d681 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 10:18:07 +0200 Subject: [PATCH 10/20] feat: fix misaligned line in usage metrics --- .../FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx b/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx index 5ebdafc6d566..2510467f700c 100644 --- a/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureEnvironmentSeen/FeatureEnvironmentSeen.tsx @@ -74,6 +74,11 @@ const TooltipContainer: FC<{ ); }; +const LineBox = styled(Box)({ + display: 'grid', + placeItems: 'center', +}); + export const FeatureEnvironmentSeen = ({ featureLastSeen, environments, @@ -91,9 +96,9 @@ export const FeatureEnvironmentSeen = ({ tooltip='No usage reported from connected applications' > - + - + ); From f61ecc83519600ffdda2eda54865b84d02fad7de Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 10:18:40 +0200 Subject: [PATCH 11/20] feat: allow styling flag exposure box --- .../FeatureOverview/FeatureLifecycle/FlagExposure.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure.tsx index e02f41922153..5b53229e52e0 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure.tsx @@ -12,7 +12,8 @@ export const FlagExposure: FC<{ project: string; flagName: string; onArchive: () => void; -}> = ({ project, flagName, onArchive }) => { + className?: string; +}> = ({ project, flagName, onArchive, className }) => { const { feature, refetchFeature } = useFeature(project, flagName); const lastSeenEnvironments: ILastSeenEnvironments[] = feature.environments?.map((env) => ({ @@ -27,7 +28,7 @@ export const FlagExposure: FC<{ useState(false); return ( - + Date: Wed, 9 Oct 2024 10:21:40 +0200 Subject: [PATCH 12/20] feat: move exposure into chart component --- .../personalDashboard/FlagMetricsChart.tsx | 19 +++++++++++++++---- .../personalDashboard/PersonalDashboard.tsx | 8 ++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/frontend/src/component/personalDashboard/FlagMetricsChart.tsx b/frontend/src/component/personalDashboard/FlagMetricsChart.tsx index 2b1a8b8bbf36..4c7eb9ef60bf 100644 --- a/frontend/src/component/personalDashboard/FlagMetricsChart.tsx +++ b/frontend/src/component/personalDashboard/FlagMetricsChart.tsx @@ -23,6 +23,7 @@ import { createPlaceholderBarChartOptions, } from './createChartOptions'; import { useFeature } from 'hooks/api/getters/useFeature/useFeature'; +import { FlagExposure } from 'component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FlagExposure'; const defaultYes = [ 45_000_000, 28_000_000, 28_000_000, 25_000_000, 50_000_000, 27_000_000, @@ -156,16 +157,21 @@ const EnvironmentSelect: FC<{ ); }; -const MetricsSelectors = styled(Box)(({ theme }) => ({ +const ExposureAndSelectors = styled(Box)(({ theme }) => ({ display: 'flex', justifyContent: 'flex-end', gap: theme.spacing(2), mb: theme.spacing(6), })); +const StyledExposure = styled(FlagExposure)({ + alignItems: 'center', +}); + export const FlagMetricsChart: FC<{ flag: { name: string; project: string }; -}> = ({ flag }) => { + onArchive: () => void; +}> = ({ flag, onArchive }) => { const [hoursBack, setHoursBack] = useState(48); const { environment, setEnvironment, activeEnvironments } = @@ -177,7 +183,12 @@ export const FlagMetricsChart: FC<{ return ( <> - + + {environment ? ( - + {noData ? ( diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 85e6db689909..b672099fe08c 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -252,7 +252,8 @@ export const PersonalDashboard = () => { const name = user?.name; - const { personalDashboard } = usePersonalDashboard(); + const { personalDashboard, refetch: refetchDashboard } = + usePersonalDashboard(); const projects = personalDashboard?.projects || []; @@ -390,7 +391,10 @@ export const PersonalDashboard = () => { {activeFlag ? ( - + ) : ( )} From 2e845ff2b6d78bf8d8a78f82ee4e197c52facdc2 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 13:38:55 +0200 Subject: [PATCH 13/20] feat: use boolean flags for section expansion --- .../personalDashboard/PersonalDashboard.tsx | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index b672099fe08c..49d083792dba 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -102,23 +102,18 @@ const useDashboardState = ( projects: PersonalDashboardSchemaProjectsItem[], flags: PersonalDashboardSchemaFlagsItem[], ) => { - type SectionState = 'expanded' | 'collapsed'; type State = { activeProject: string | undefined; activeFlag: PersonalDashboardSchemaFlagsItem | undefined; - sections: { - projects: { state: SectionState }; - flags: { state: SectionState }; - }; + expandProjects: boolean; + expandFlags: boolean; }; const defaultState: State = { activeProject: undefined, activeFlag: undefined, - sections: { - projects: { state: 'expanded' as const }, - flags: { state: 'expanded' as const }, - }, + expandProjects: true, + expandFlags: true, }; const [state, setState] = useLocalStorageState( @@ -164,18 +159,11 @@ const useDashboardState = ( }); }; - const toggleSectionState = (section: keyof State['sections']) => { + const toggleSectionState = (section: 'flags' | 'projects') => { + const property = section === 'flags' ? 'expandFlags' : 'expandProjects'; setState({ ...state, - sections: { - ...state.sections, - [section]: { - state: - state.sections[section].state === 'expanded' - ? 'collapsed' - : 'expanded', - }, - }, + [property]: !(state[property] ?? true), }); }; @@ -184,7 +172,8 @@ const useDashboardState = ( setActiveFlag, activeProject, setActiveProject, - sectionState: state.sections, + expandFlags: state.expandFlags, + expandProjects: state.expandProjects, toggleSectionState, }; }; @@ -263,7 +252,8 @@ export const PersonalDashboard = () => { activeFlag, setActiveFlag, toggleSectionState, - sectionState, + expandFlags, + expandProjects, } = useDashboardState(projects, personalDashboard?.flags ?? []); const [welcomeDialog, setWelcomeDialog] = useLocalStorageState< @@ -303,7 +293,7 @@ export const PersonalDashboard = () => { toggleSectionState('projects')} > { toggleSectionState('flags')} > Date: Wed, 9 Oct 2024 13:51:09 +0200 Subject: [PATCH 14/20] feat: add comment --- .../component/personalDashboard/PersonalDashboard.test.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.test.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.test.tsx index 0be437d6512f..88a4abbde1ae 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.test.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.test.tsx @@ -114,7 +114,9 @@ const setupNewProject = () => { }); }; -// @ts-ignore +// @ts-expect-error The return type here isn't correct, but it's not +// an issue for the tests. We just need to override it because it's +// not implemented in jsdom. HTMLCanvasElement.prototype.getContext = () => {}; //scrollIntoView is not implemented in jsdom From 53451964b812eaddae9d377c147eb9d530461887 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 13:51:18 +0200 Subject: [PATCH 15/20] feat: don't use important --- .../src/component/personalDashboard/PersonalDashboard.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 49d083792dba..80540318afb9 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -217,8 +217,9 @@ const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ border: 'none', padding: theme.spacing(2, 4), margin: 0, - '&>*': { - margin: '0 !important', + // increase specificity to override the default margin + '&>.MuiAccordionSummary-content.MuiAccordionSummary-content': { + margin: '0', }, "&[aria-expanded='true']": { // only add the border when it's open From c70e8fe44129c477e3da82e86b024b34a0fc2224 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 14:01:38 +0200 Subject: [PATCH 16/20] feat: update state handling --- .../personalDashboard/PersonalDashboard.tsx | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 80540318afb9..9f233245c804 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -121,11 +121,21 @@ const useDashboardState = ( defaultState, ); + const setPartialState = (newState: Partial) => + setState({ ...defaultState, ...state, ...newState }); + useEffect(() => { const setDefaultFlag = flags.length && (!state.activeFlag || !flags.some((flag) => flag.name === state.activeFlag?.name)); + + if (setDefaultFlag) { + setPartialState({ + activeFlag: flags[0], + }); + } + const setDefaultProject = projects.length && (!state.activeProject || @@ -133,36 +143,30 @@ const useDashboardState = ( (project) => project.id === state.activeProject, )); - setState({ - ...defaultState, - ...state, - activeFlag: setDefaultFlag ? flags[0] : state.activeFlag, - activeProject: setDefaultProject - ? projects[0].id - : state.activeProject, - }); + if (setDefaultProject) { + setPartialState({ + activeProject: projects[0].id, + }); + } }); const { activeFlag, activeProject } = state; const setActiveFlag = (flag: PersonalDashboardSchemaFlagsItem) => { - setState({ - ...state, + setPartialState({ activeFlag: flag, }); }; const setActiveProject = (projectId: string) => { - setState({ - ...state, + setPartialState({ activeProject: projectId, }); }; const toggleSectionState = (section: 'flags' | 'projects') => { const property = section === 'flags' ? 'expandFlags' : 'expandProjects'; - setState({ - ...state, + setPartialState({ [property]: !(state[property] ?? true), }); }; @@ -172,8 +176,8 @@ const useDashboardState = ( setActiveFlag, activeProject, setActiveProject, - expandFlags: state.expandFlags, - expandProjects: state.expandProjects, + expandFlags: state.expandFlags ?? true, + expandProjects: state.expandProjects ?? true, toggleSectionState, }; }; From ee18e24437e005097fdd346e63226e4c8daf7c86 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 14:03:33 +0200 Subject: [PATCH 17/20] feat: fix test --- .../src/component/personalDashboard/PersonalDashboard.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.test.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.test.tsx index 88a4abbde1ae..b276d497df8e 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.test.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.test.tsx @@ -136,7 +136,7 @@ test('Render personal dashboard for a long running project', async () => { await screen.findByText('projectName'); await screen.findByText('10'); // members await screen.findByText('100'); // features - await screen.findByText('80%'); // health + await screen.findAllByText('80%'); // health await screen.findByText('Project health'); await screen.findByText('70%'); // avg health past window From 4041547a957fef8bf5e2b7e625c13286c88bd6eb Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 14:05:39 +0200 Subject: [PATCH 18/20] feat: use dependencies in useEffect --- .../src/component/personalDashboard/PersonalDashboard.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 9f233245c804..c89b1a2d629a 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -148,7 +148,11 @@ const useDashboardState = ( activeProject: projects[0].id, }); } - }); + }, [ + JSON.stringify(projects, null, 2), + JSON.stringify(flags, null, 2), + JSON.stringify(state, null, 2), + ]); const { activeFlag, activeProject } = state; From e290350258ca42f3a11e5e7715e8b2faf747fc43 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 14:06:01 +0200 Subject: [PATCH 19/20] Chore: rename method --- .../personalDashboard/PersonalDashboard.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index c89b1a2d629a..5103424e44a9 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -121,7 +121,7 @@ const useDashboardState = ( defaultState, ); - const setPartialState = (newState: Partial) => + const updateState = (newState: Partial) => setState({ ...defaultState, ...state, ...newState }); useEffect(() => { @@ -131,7 +131,7 @@ const useDashboardState = ( !flags.some((flag) => flag.name === state.activeFlag?.name)); if (setDefaultFlag) { - setPartialState({ + updateState({ activeFlag: flags[0], }); } @@ -144,7 +144,7 @@ const useDashboardState = ( )); if (setDefaultProject) { - setPartialState({ + updateState({ activeProject: projects[0].id, }); } @@ -157,20 +157,20 @@ const useDashboardState = ( const { activeFlag, activeProject } = state; const setActiveFlag = (flag: PersonalDashboardSchemaFlagsItem) => { - setPartialState({ + updateState({ activeFlag: flag, }); }; const setActiveProject = (projectId: string) => { - setPartialState({ + updateState({ activeProject: projectId, }); }; const toggleSectionState = (section: 'flags' | 'projects') => { const property = section === 'flags' ? 'expandFlags' : 'expandProjects'; - setPartialState({ + updateState({ [property]: !(state[property] ?? true), }); }; From e9679bfa23b91f6748e34cde32c8f207cfcf690f Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Wed, 9 Oct 2024 14:10:46 +0200 Subject: [PATCH 20/20] feat: rejig logic to only update state once inside the hook --- .../personalDashboard/PersonalDashboard.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/frontend/src/component/personalDashboard/PersonalDashboard.tsx b/frontend/src/component/personalDashboard/PersonalDashboard.tsx index 5103424e44a9..d5ba350b8d3c 100644 --- a/frontend/src/component/personalDashboard/PersonalDashboard.tsx +++ b/frontend/src/component/personalDashboard/PersonalDashboard.tsx @@ -98,6 +98,7 @@ const FlagListItem: FC<{ ); }; +// todo: move into own file const useDashboardState = ( projects: PersonalDashboardSchemaProjectsItem[], flags: PersonalDashboardSchemaFlagsItem[], @@ -125,15 +126,14 @@ const useDashboardState = ( setState({ ...defaultState, ...state, ...newState }); useEffect(() => { + const updates: Partial = {}; const setDefaultFlag = flags.length && (!state.activeFlag || !flags.some((flag) => flag.name === state.activeFlag?.name)); if (setDefaultFlag) { - updateState({ - activeFlag: flags[0], - }); + updates.activeFlag = flags[0]; } const setDefaultProject = @@ -144,9 +144,11 @@ const useDashboardState = ( )); if (setDefaultProject) { - updateState({ - activeProject: projects[0].id, - }); + updates.activeProject = projects[0].id; + } + + if (Object.keys(updates).length) { + updateState(updates); } }, [ JSON.stringify(projects, null, 2),