1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-18 00:19:49 +01:00

fix: align event log filter buttons ()

Fixes an issue where the filter buttons were both too far down and too
far to the right.

The issue was that the wrapper body imposed a pretty substantial bit
of padding. However, the filter buttons already came with their own
bit of padding. The result of this was alignment issues.

To fix it I have:
- opened the `Filters` component up to be styled with styled components

And conditionally (when isEnterprise and the flag is on):
- set the page body to have no padding.
- added a wrapper with padding around the event search results for 

This feels a little messy to me, but I also think that because it's
still in heavy development, it might change later. I'd be happy to have
suggestions forbetter implementations.

What makes this extra tricky is that the top padding differs depending
on whether you have the filters there or not, so I couldn't find a way
to just remove that component and be done with it. I may very well have
missed somehing, though.

Before:

![image](https://github.com/user-attachments/assets/1552d1ec-2c14-450f-9ce8-8e74389f11a1)

After: 

![image](https://github.com/user-attachments/assets/d58b6fe5-437f-4488-bf01-cabfef669e2e)
This commit is contained in:
Thomas Heartman 2024-08-02 11:09:55 +02:00 committed by GitHub
parent 643cfeb5bb
commit 2d0fb765f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 71 additions and 31 deletions
frontend/src/component
events/EventLog
filter/Filters

View File

@ -30,6 +30,17 @@ const StyledEventsList = styled('ul')(({ theme }) => ({
gap: theme.spacing(2), gap: theme.spacing(2),
})); }));
const StyledFilters = styled(EventLogFilters)({
padding: 0,
});
const EventResultWrapper = styled('div')(({ theme }) => ({
padding: theme.spacing(2, 4, 4, 4),
display: 'flex',
flexFlow: 'column',
gap: theme.spacing(1),
}));
export const EventLog = ({ title, project, feature }: IEventLogProps) => { export const EventLog = ({ title, project, feature }: IEventLogProps) => {
const [query, setQuery] = useState(''); const [query, setQuery] = useState('');
const { events, totalEvents, fetchNextPage } = useEventSearch( const { events, totalEvents, fetchNextPage } = useEventSearch(
@ -41,7 +52,7 @@ export const EventLog = ({ title, project, feature }: IEventLogProps) => {
const { eventSettings, setEventSettings } = useEventSettings(); const { eventSettings, setEventSettings } = useEventSettings();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md')); const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
const { isEnterprise } = useUiConfig(); const { isEnterprise } = useUiConfig();
const showFilters = useUiFlag('newEventSearch'); const showFilters = useUiFlag('newEventSearch') && isEnterprise();
// Cache the previous search results so that we can show those while // Cache the previous search results so that we can show those while
// fetching new results for a new search query in the background. // fetching new results for a new search query in the background.
@ -67,31 +78,12 @@ export const EventLog = ({ title, project, feature }: IEventLogProps) => {
/> />
); );
const logType = project ? 'project' : feature ? 'flag' : 'global';
const count = events?.length || 0; const count = events?.length || 0;
const totalCount = totalEvents || 0; const totalCount = totalEvents || 0;
const countText = `${count} of ${totalCount}`; const countText = `${count} of ${totalCount}`;
return ( const EventResults = (
<PageContent <>
header={
<PageHeader
title={`${title} (${countText})`}
actions={
<>
{showDataSwitch}
{!isSmallScreen && searchInputField}
</>
}
>
{isSmallScreen && searchInputField}
</PageHeader>
}
>
<ConditionallyRender
condition={isEnterprise() && showFilters}
show={<EventLogFilters logType={logType} />}
/>
<ConditionallyRender <ConditionallyRender
condition={Boolean(cache && cache.length === 0)} condition={Boolean(cache && cache.length === 0)}
show={<p>No events found.</p>} show={<p>No events found.</p>}
@ -111,6 +103,45 @@ export const EventLog = ({ title, project, feature }: IEventLogProps) => {
</StyledEventsList> </StyledEventsList>
} }
/> />
</>
);
return (
<PageContent
bodyClass={showFilters ? 'no-padding' : ''}
header={
<PageHeader
title={`${title} (${countText})`}
actions={
<>
{showDataSwitch}
{!isSmallScreen && searchInputField}
</>
}
>
{isSmallScreen && searchInputField}
</PageHeader>
}
>
<ConditionallyRender
condition={showFilters}
show={
<EventResultWrapper>
<StyledFilters
logType={
project
? 'project'
: feature
? 'flag'
: 'global'
}
/>
{EventResults}
</EventResultWrapper>
}
elseShow={EventResults}
/>
<div ref={fetchNextPageRef} /> <div ref={fetchNextPageRef} />
</PageContent> </PageContent>
); );

View File

@ -4,6 +4,10 @@ import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { useFeatureSearch } from 'hooks/api/getters/useFeatureSearch/useFeatureSearch'; import { useFeatureSearch } from 'hooks/api/getters/useFeatureSearch/useFeatureSearch';
import { EventSchemaType } from 'openapi'; import { EventSchemaType } from 'openapi';
type FilterProps = {
className?: string;
};
const flagLogFilters: IFilterItem[] = [ const flagLogFilters: IFilterItem[] = [
{ {
label: 'Date From', label: 'Date From',
@ -42,9 +46,10 @@ const flagLogFilters: IFilterItem[] = [
}, },
]; ];
export const FlagLogFilters = () => { export const FlagLogFilters: FC<FilterProps> = ({ className }) => {
return ( return (
<Filters <Filters
className={className}
availableFilters={flagLogFilters} availableFilters={flagLogFilters}
state={{}} state={{}}
onChange={(v) => console.log(v)} onChange={(v) => console.log(v)}
@ -81,11 +86,12 @@ const useProjectLogFilters = () => {
return availableFilters; return availableFilters;
}; };
export const ProjectLogFilters = () => { export const ProjectLogFilters: FC<FilterProps> = ({ className }) => {
const availableFilters = useProjectLogFilters(); const availableFilters = useProjectLogFilters();
return ( return (
<Filters <Filters
className={className}
availableFilters={availableFilters} availableFilters={availableFilters}
state={{}} state={{}}
onChange={(v) => console.log(v)} onChange={(v) => console.log(v)}
@ -93,7 +99,7 @@ export const ProjectLogFilters = () => {
); );
}; };
export const GlobalLogFilters = () => { export const GlobalLogFilters: FC<FilterProps> = ({ className }) => {
const projectFilters = useProjectLogFilters(); const projectFilters = useProjectLogFilters();
const { projects } = useProjects(); const { projects } = useProjects();
@ -127,6 +133,7 @@ export const GlobalLogFilters = () => {
return ( return (
<Filters <Filters
className={className}
availableFilters={availableFilters} availableFilters={availableFilters}
state={{}} state={{}}
onChange={(v) => console.log(v)} onChange={(v) => console.log(v)}
@ -136,17 +143,17 @@ export const GlobalLogFilters = () => {
type EventLogFiltersProps = { type EventLogFiltersProps = {
logType: 'flag' | 'project' | 'global'; logType: 'flag' | 'project' | 'global';
}; } & FilterProps;
export const EventLogFilters: FC<EventLogFiltersProps> = ( export const EventLogFilters: FC<EventLogFiltersProps> = (
{ logType }, { logType, ...props },
// {state, onChange,} // these are to fill in later to make the filters work // {state, onChange,} // these are to fill in later to make the filters work
) => { ) => {
switch (logType) { switch (logType) {
case 'flag': case 'flag':
return <FlagLogFilters />; return <FlagLogFilters {...props} />;
case 'project': case 'project':
return <ProjectLogFilters />; return <ProjectLogFilters {...props} />;
case 'global': case 'global':
return <GlobalLogFilters />; return <GlobalLogFilters {...props} />;
} }
}; };

View File

@ -21,6 +21,7 @@ interface IFilterProps {
state: FilterItemParamHolder; state: FilterItemParamHolder;
onChange: (value: FilterItemParamHolder) => void; onChange: (value: FilterItemParamHolder) => void;
availableFilters: IFilterItem[]; availableFilters: IFilterItem[];
className?: string;
} }
type IBaseFilterItem = { type IBaseFilterItem = {
@ -61,6 +62,7 @@ export const Filters: FC<IFilterProps> = ({
state, state,
onChange, onChange,
availableFilters, availableFilters,
className,
}) => { }) => {
const [unselectedFilters, setUnselectedFilters] = useState<string[]>([]); const [unselectedFilters, setUnselectedFilters] = useState<string[]>([]);
const [selectedFilters, setSelectedFilters] = useState<string[]>([]); const [selectedFilters, setSelectedFilters] = useState<string[]>([]);
@ -115,7 +117,7 @@ export const Filters: FC<IFilterProps> = ({
const hasAvailableFilters = unselectedFilters.length > 0; const hasAvailableFilters = unselectedFilters.length > 0;
return ( return (
<StyledBox> <StyledBox className={className}>
{selectedFilters.map((selectedFilter) => { {selectedFilters.map((selectedFilter) => {
const filter = availableFilters.find( const filter = availableFilters.find(
(filter) => filter.label === selectedFilter, (filter) => filter.label === selectedFilter,