mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-31 13:47:02 +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 CloseIcon from '@mui/icons-material/Close';
|
||||||
import { useEventTimelineContext } from '../EventTimelineContext';
|
import { useEventTimelineContext } from '../EventTimelineContext';
|
||||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
||||||
import { EventTimelineHeaderTip } from './EventTimelineHeaderTip';
|
|
||||||
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
|
import { HelpIcon } from 'component/common/HelpIcon/HelpIcon';
|
||||||
|
import { EventTimelineHeaderTip } from './EventTimelineHeaderTip';
|
||||||
|
import { useUiFlag } from 'hooks/useUiFlag';
|
||||||
|
|
||||||
const StyledCol = styled('div')(({ theme }) => ({
|
const StyledCol = styled('div')(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -49,6 +50,7 @@ export const EventTimelineHeader = ({
|
|||||||
const { timeSpan, environment, setOpen, setTimeSpan, setEnvironment } =
|
const { timeSpan, environment, setOpen, setTimeSpan, setEnvironment } =
|
||||||
useEventTimelineContext();
|
useEventTimelineContext();
|
||||||
const { environments } = useEnvironments();
|
const { environments } = useEnvironments();
|
||||||
|
const frontendHeaderRefactor = useUiFlag('frontendHeaderRedesign');
|
||||||
|
|
||||||
const activeEnvironments = useMemo(
|
const activeEnvironments = useMemo(
|
||||||
() => environments.filter(({ enabled }) => enabled),
|
() => environments.filter(({ enabled }) => enabled),
|
||||||
@ -65,6 +67,33 @@ export const EventTimelineHeader = ({
|
|||||||
}
|
}
|
||||||
}, [activeEnvironments]);
|
}, [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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledCol>
|
<StyledCol>
|
||||||
@ -92,50 +121,30 @@ export const EventTimelineHeader = ({
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</StyledFilter>
|
</StyledFilter>
|
||||||
|
{frontendHeaderRefactor && <EnvironmentFilter />}
|
||||||
</StyledCol>
|
</StyledCol>
|
||||||
<EventTimelineHeaderTip />
|
{!frontendHeaderRefactor && (
|
||||||
<StyledCol>
|
<StyledCol>
|
||||||
<ConditionallyRender
|
<EventTimelineHeaderTip />
|
||||||
condition={Boolean(environment) && environments.length > 0}
|
<EnvironmentFilter />
|
||||||
show={() => (
|
<Tooltip title='Hide event timeline' arrow>
|
||||||
<StyledFilter
|
<IconButton
|
||||||
select
|
aria-label='close'
|
||||||
size='small'
|
size='small'
|
||||||
variant='outlined'
|
onClick={() => {
|
||||||
value={environment!.name}
|
trackEvent('event-timeline', {
|
||||||
onChange={(e) =>
|
props: {
|
||||||
setEnvironment(
|
eventType: 'close',
|
||||||
environments.find(
|
},
|
||||||
({ name }) => name === e.target.value,
|
});
|
||||||
) || environments[0],
|
setOpen(false);
|
||||||
)
|
}}
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{environments.map(({ name }) => (
|
<CloseIcon />
|
||||||
<MenuItem key={name} value={name}>
|
</IconButton>
|
||||||
{name}
|
</Tooltip>
|
||||||
</MenuItem>
|
</StyledCol>
|
||||||
))}
|
)}
|
||||||
</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>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -150,7 +150,10 @@ export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
|
|||||||
show={<Header />}
|
show={<Header />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MainLayoutEventTimeline />
|
<ConditionallyRender
|
||||||
|
condition={!frontendHeaderRedesign}
|
||||||
|
show={<MainLayoutEventTimeline />}
|
||||||
|
/>
|
||||||
|
|
||||||
<MainLayoutContent>
|
<MainLayoutContent>
|
||||||
<SkipNavTarget />
|
<SkipNavTarget />
|
||||||
|
@ -199,7 +199,10 @@ const Header = () => {
|
|||||||
<StyledNav>
|
<StyledNav>
|
||||||
<StyledUserContainer>
|
<StyledUserContainer>
|
||||||
<CommandBar />
|
<CommandBar />
|
||||||
<HeaderEventTimelineButton />
|
<ConditionallyRender
|
||||||
|
condition={!frontendHeaderRedesign}
|
||||||
|
show={<HeaderEventTimelineButton />}
|
||||||
|
/>
|
||||||
<InviteLinkButton />
|
<InviteLinkButton />
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
|
@ -23,6 +23,10 @@ import { fromPersonalDashboardProjectDetailsOutput } from './RemoteData';
|
|||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import { InfoSection } from './InfoSection';
|
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 }) => ({
|
const WelcomeSection = styled('div')(({ theme }) => ({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -109,6 +113,7 @@ export const PersonalDashboard = () => {
|
|||||||
const { splash } = useAuthSplash();
|
const { splash } = useAuthSplash();
|
||||||
const { isOss } = useUiConfig();
|
const { isOss } = useUiConfig();
|
||||||
const name = user?.name || '';
|
const name = user?.name || '';
|
||||||
|
const showTimelinePanel = useUiFlag('frontendHeaderRedesign');
|
||||||
|
|
||||||
usePageTitle(name ? `Dashboard: ${name}` : 'Dashboard');
|
usePageTitle(name ? `Dashboard: ${name}` : 'Dashboard');
|
||||||
|
|
||||||
@ -125,8 +130,11 @@ export const PersonalDashboard = () => {
|
|||||||
toggleSectionState,
|
toggleSectionState,
|
||||||
expandFlags,
|
expandFlags,
|
||||||
expandProjects,
|
expandProjects,
|
||||||
|
expandTimeline,
|
||||||
} = useDashboardState(projects, personalDashboard?.flags ?? []);
|
} = useDashboardState(projects, personalDashboard?.flags ?? []);
|
||||||
|
|
||||||
|
const signalsLink = '/integrations/signals';
|
||||||
|
|
||||||
const [welcomeDialog, setWelcomeDialog] = useLocalStorageState<
|
const [welcomeDialog, setWelcomeDialog] = useLocalStorageState<
|
||||||
'open' | 'closed'
|
'open' | 'closed'
|
||||||
>(
|
>(
|
||||||
@ -175,6 +183,49 @@ export const PersonalDashboard = () => {
|
|||||||
</ViewKeyConceptsButton>
|
</ViewKeyConceptsButton>
|
||||||
</WelcomeSection>
|
</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
|
<SectionAccordion
|
||||||
disableGutters
|
disableGutters
|
||||||
expanded={expandProjects ?? true}
|
expanded={expandProjects ?? true}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Box, List, styled } from '@mui/material';
|
import { Box, List, type Theme, styled } from '@mui/material';
|
||||||
import type { Theme } from '@mui/material/styles/createTheme';
|
|
||||||
|
|
||||||
export const ContentGridContainer = styled('div')({
|
export const ContentGridContainer = styled('div')({
|
||||||
containerType: 'inline-size',
|
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()),
|
shouldForwardProp: (prop) => !['gridArea'].includes(prop.toString()),
|
||||||
})<{ gridArea: string }>(({ theme, gridArea }) => ({
|
})<{ gridArea: string }>(({ theme, gridArea }) => ({
|
||||||
padding: theme.spacing(2, 4),
|
|
||||||
maxHeight: '100%',
|
maxHeight: '100%',
|
||||||
overflowY: 'auto',
|
overflowY: 'auto',
|
||||||
gridArea,
|
gridArea,
|
||||||
|
@ -14,6 +14,7 @@ export const useDashboardState = (
|
|||||||
activeFlag: PersonalDashboardSchemaFlagsItem | undefined;
|
activeFlag: PersonalDashboardSchemaFlagsItem | undefined;
|
||||||
expandProjects: boolean;
|
expandProjects: boolean;
|
||||||
expandFlags: boolean;
|
expandFlags: boolean;
|
||||||
|
expandTimeline: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultState: State = {
|
const defaultState: State = {
|
||||||
@ -21,6 +22,7 @@ export const useDashboardState = (
|
|||||||
activeFlag: undefined,
|
activeFlag: undefined,
|
||||||
expandProjects: true,
|
expandProjects: true,
|
||||||
expandFlags: true,
|
expandFlags: true,
|
||||||
|
expandTimeline: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const [state, setState] = useLocalStorageState<State>(
|
const [state, setState] = useLocalStorageState<State>(
|
||||||
@ -76,8 +78,18 @@ export const useDashboardState = (
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleSectionState = (section: 'flags' | 'projects') => {
|
const toggleSectionState = (section: 'flags' | 'projects' | 'timeline') => {
|
||||||
const property = section === 'flags' ? 'expandFlags' : 'expandProjects';
|
const getProperty = () => {
|
||||||
|
switch (section) {
|
||||||
|
case 'flags':
|
||||||
|
return 'expandFlags';
|
||||||
|
case 'projects':
|
||||||
|
return 'expandProjects';
|
||||||
|
case 'timeline':
|
||||||
|
return 'expandTimeline';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const property = getProperty();
|
||||||
updateState({
|
updateState({
|
||||||
[property]: !(state[property] ?? true),
|
[property]: !(state[property] ?? true),
|
||||||
});
|
});
|
||||||
@ -90,6 +102,7 @@ export const useDashboardState = (
|
|||||||
setActiveProject,
|
setActiveProject,
|
||||||
expandFlags: state.expandFlags ?? true,
|
expandFlags: state.expandFlags ?? true,
|
||||||
expandProjects: state.expandProjects ?? true,
|
expandProjects: state.expandProjects ?? true,
|
||||||
|
expandTimeline: state.expandTimeline ?? false,
|
||||||
toggleSectionState,
|
toggleSectionState,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user