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  --------- Co-authored-by: Nuno Góis <github@nunogois.com>
This commit is contained in:
parent
54e4fd2190
commit
56c9584bb6
@ -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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -150,7 +150,10 @@ export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
|
||||
show={<Header />}
|
||||
/>
|
||||
|
||||
<MainLayoutEventTimeline />
|
||||
<ConditionallyRender
|
||||
condition={!frontendHeaderRedesign}
|
||||
show={<MainLayoutEventTimeline />}
|
||||
/>
|
||||
|
||||
<MainLayoutContent>
|
||||
<SkipNavTarget />
|
||||
|
@ -199,7 +199,10 @@ const Header = () => {
|
||||
<StyledNav>
|
||||
<StyledUserContainer>
|
||||
<CommandBar />
|
||||
<HeaderEventTimelineButton />
|
||||
<ConditionallyRender
|
||||
condition={!frontendHeaderRedesign}
|
||||
show={<HeaderEventTimelineButton />}
|
||||
/>
|
||||
<InviteLinkButton />
|
||||
<Tooltip
|
||||
title={
|
||||
|
@ -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}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user