1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

feat: move timeline to panel (#9243)

Moves the event timeline to the personal dashboard from the header when
the `frontendHeaderRedesign` flag is active.

When the flag is active, it also:
- hides the event timeline and corresponding button in the header
- renders the environment selector next to the time selector instead of
at the other end of the header


![image](https://github.com/user-attachments/assets/cccd8f07-d42a-4180-807f-20937019442d)

---------

Co-authored-by: Nuno Góis <github@nunogois.com>
This commit is contained in:
Thomas Heartman 2025-02-06 14:55:59 +01:00 committed by GitHub
parent 54e4fd2190
commit 56c9584bb6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 131 additions and 50 deletions

View File

@ -12,8 +12,9 @@ import { timeSpanOptions } from '../EventTimelineProvider';
import CloseIcon from '@mui/icons-material/Close';
import { useEventTimelineContext } from '../EventTimelineContext';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { EventTimelineHeaderTip } from './EventTimelineHeaderTip';
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
import { EventTimelineHeaderTip } from './EventTimelineHeaderTip';
import { useUiFlag } from 'hooks/useUiFlag';
const StyledCol = styled('div')(({ theme }) => ({
display: 'flex',
@ -49,6 +50,7 @@ export const EventTimelineHeader = ({
const { timeSpan, environment, setOpen, setTimeSpan, setEnvironment } =
useEventTimelineContext();
const { environments } = useEnvironments();
const frontendHeaderRefactor = useUiFlag('frontendHeaderRedesign');
const activeEnvironments = useMemo(
() => environments.filter(({ enabled }) => enabled),
@ -65,6 +67,33 @@ export const EventTimelineHeader = ({
}
}, [activeEnvironments]);
const EnvironmentFilter = () => (
<ConditionallyRender
condition={Boolean(environment) && environments.length > 0}
show={() => (
<StyledFilter
select
size='small'
variant='outlined'
value={environment!.name}
onChange={(e) =>
setEnvironment(
environments.find(
({ name }) => name === e.target.value,
) || environments[0],
)
}
>
{environments.map(({ name }) => (
<MenuItem key={name} value={name}>
{name}
</MenuItem>
))}
</StyledFilter>
)}
/>
);
return (
<>
<StyledCol>
@ -92,50 +121,30 @@ export const EventTimelineHeader = ({
</MenuItem>
))}
</StyledFilter>
{frontendHeaderRefactor && <EnvironmentFilter />}
</StyledCol>
<EventTimelineHeaderTip />
<StyledCol>
<ConditionallyRender
condition={Boolean(environment) && environments.length > 0}
show={() => (
<StyledFilter
select
{!frontendHeaderRefactor && (
<StyledCol>
<EventTimelineHeaderTip />
<EnvironmentFilter />
<Tooltip title='Hide event timeline' arrow>
<IconButton
aria-label='close'
size='small'
variant='outlined'
value={environment!.name}
onChange={(e) =>
setEnvironment(
environments.find(
({ name }) => name === e.target.value,
) || environments[0],
)
}
onClick={() => {
trackEvent('event-timeline', {
props: {
eventType: 'close',
},
});
setOpen(false);
}}
>
{environments.map(({ name }) => (
<MenuItem key={name} value={name}>
{name}
</MenuItem>
))}
</StyledFilter>
)}
/>
<Tooltip title='Hide event timeline' arrow>
<IconButton
aria-label='close'
size='small'
onClick={() => {
trackEvent('event-timeline', {
props: {
eventType: 'close',
},
});
setOpen(false);
}}
>
<CloseIcon />
</IconButton>
</Tooltip>
</StyledCol>
<CloseIcon />
</IconButton>
</Tooltip>
</StyledCol>
)}
</>
);
};

View File

@ -150,7 +150,10 @@ export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
show={<Header />}
/>
<MainLayoutEventTimeline />
<ConditionallyRender
condition={!frontendHeaderRedesign}
show={<MainLayoutEventTimeline />}
/>
<MainLayoutContent>
<SkipNavTarget />

View File

@ -199,7 +199,10 @@ const Header = () => {
<StyledNav>
<StyledUserContainer>
<CommandBar />
<HeaderEventTimelineButton />
<ConditionallyRender
condition={!frontendHeaderRedesign}
show={<HeaderEventTimelineButton />}
/>
<InviteLinkButton />
<Tooltip
title={

View File

@ -23,6 +23,10 @@ import { fromPersonalDashboardProjectDetailsOutput } from './RemoteData';
import { useEffect } from 'react';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { InfoSection } from './InfoSection';
import { EventTimeline } from 'component/events/EventTimeline/EventTimeline';
import { AccordionContent } from './SharedComponents';
import { Link } from 'react-router-dom';
import { useUiFlag } from 'hooks/useUiFlag';
const WelcomeSection = styled('div')(({ theme }) => ({
display: 'flex',
@ -109,6 +113,7 @@ export const PersonalDashboard = () => {
const { splash } = useAuthSplash();
const { isOss } = useUiConfig();
const name = user?.name || '';
const showTimelinePanel = useUiFlag('frontendHeaderRedesign');
usePageTitle(name ? `Dashboard: ${name}` : 'Dashboard');
@ -125,8 +130,11 @@ export const PersonalDashboard = () => {
toggleSectionState,
expandFlags,
expandProjects,
expandTimeline,
} = useDashboardState(projects, personalDashboard?.flags ?? []);
const signalsLink = '/integrations/signals';
const [welcomeDialog, setWelcomeDialog] = useLocalStorageState<
'open' | 'closed'
>(
@ -175,6 +183,49 @@ export const PersonalDashboard = () => {
</ViewKeyConceptsButton>
</WelcomeSection>
{showTimelinePanel && (
<SectionAccordion
disableGutters
expanded={expandTimeline ?? false}
onChange={() => toggleSectionState('timeline')}
>
<StyledAccordionSummary
expandIcon={
<ExpandMore titleAccess='Toggle timeline section' />
}
id='timeline-panel-header'
aria-controls='timeline-panel-content'
>
<AccordionSummaryText>
<AccordionSummaryHeader>
Timeline of events
</AccordionSummaryHeader>
<AccordionSummarySubtitle>
Overview of recent activities across all
projects in Unleash. Make debugging easier and{' '}
<Link
to={signalsLink}
onClick={() => {
trackEvent('event-timeline', {
props: {
eventType: 'signals clicked',
},
});
}}
>
include external signals
</Link>{' '}
to get a fuller overview.
</AccordionSummarySubtitle>
</AccordionSummaryText>
</StyledAccordionSummary>
<StyledAccordionDetails>
<AccordionContent>
<EventTimeline />
</AccordionContent>
</StyledAccordionDetails>
</SectionAccordion>
)}
<SectionAccordion
disableGutters
expanded={expandProjects ?? true}

View File

@ -1,5 +1,4 @@
import { Box, List, styled } from '@mui/material';
import type { Theme } from '@mui/material/styles/createTheme';
import { Box, List, type Theme, styled } from '@mui/material';
export const ContentGridContainer = styled('div')({
containerType: 'inline-size',
@ -57,10 +56,13 @@ export const FlagGrid = styled(ContentGrid)(
}),
);
export const GridItem = styled('div', {
export const AccordionContent = styled('div')(({ theme }) => ({
padding: theme.spacing(2, 4),
}));
export const GridItem = styled(AccordionContent, {
shouldForwardProp: (prop) => !['gridArea'].includes(prop.toString()),
})<{ gridArea: string }>(({ theme, gridArea }) => ({
padding: theme.spacing(2, 4),
maxHeight: '100%',
overflowY: 'auto',
gridArea,

View File

@ -14,6 +14,7 @@ export const useDashboardState = (
activeFlag: PersonalDashboardSchemaFlagsItem | undefined;
expandProjects: boolean;
expandFlags: boolean;
expandTimeline: boolean;
};
const defaultState: State = {
@ -21,6 +22,7 @@ export const useDashboardState = (
activeFlag: undefined,
expandProjects: true,
expandFlags: true,
expandTimeline: false,
};
const [state, setState] = useLocalStorageState<State>(
@ -76,8 +78,18 @@ export const useDashboardState = (
});
};
const toggleSectionState = (section: 'flags' | 'projects') => {
const property = section === 'flags' ? 'expandFlags' : 'expandProjects';
const toggleSectionState = (section: 'flags' | 'projects' | 'timeline') => {
const getProperty = () => {
switch (section) {
case 'flags':
return 'expandFlags';
case 'projects':
return 'expandProjects';
case 'timeline':
return 'expandTimeline';
}
};
const property = getProperty();
updateState({
[property]: !(state[property] ?? true),
});
@ -90,6 +102,7 @@ export const useDashboardState = (
setActiveProject,
expandFlags: state.expandFlags ?? true,
expandProjects: state.expandProjects ?? true,
expandTimeline: state.expandTimeline ?? false,
toggleSectionState,
};
};