mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
feat: add filter dropdowns to event log pages (#7711)
Adds placeholder filter buttons (that don't work at all) yet to the three event logs. Flag logs get to choose to and from dates, created by, and event type. Project logs get all that flag logs get + a filter for flag. The global log gets all project log filters + a project filter. There's still work to be done to add data to createdBy, eventType, to hook it up to the API, and to finalize the layout, but I wanted to get a rough outline in to iterate on later. The eventType icon will also need to be decided on. ![image](https://github.com/user-attachments/assets/06a65301-9cc5-45ed-b753-2b9235d64ea6)
This commit is contained in:
parent
cab18d2881
commit
7db42453b1
@ -12,6 +12,9 @@ import { ConditionallyRender } from 'component/common/ConditionallyRender/Condit
|
||||
import { useOnVisible } from 'hooks/useOnVisible';
|
||||
import type { IEvent } from 'interfaces/event';
|
||||
import { styled } from '@mui/system';
|
||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||
import { useUiFlag } from 'hooks/useUiFlag';
|
||||
import { EventLogFilters } from './EventLogFilters';
|
||||
|
||||
interface IEventLogProps {
|
||||
title: string;
|
||||
@ -37,6 +40,8 @@ export const EventLog = ({ title, project, feature }: IEventLogProps) => {
|
||||
const fetchNextPageRef = useOnVisible<HTMLDivElement>(fetchNextPage);
|
||||
const { eventSettings, setEventSettings } = useEventSettings();
|
||||
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const { isEnterprise } = useUiConfig();
|
||||
const showFilters = useUiFlag('newEventSearch');
|
||||
|
||||
// Cache the previous search results so that we can show those while
|
||||
// fetching new results for a new search query in the background.
|
||||
@ -62,6 +67,7 @@ export const EventLog = ({ title, project, feature }: IEventLogProps) => {
|
||||
/>
|
||||
);
|
||||
|
||||
const logType = project ? 'project' : feature ? 'flag' : 'global';
|
||||
const count = events?.length || 0;
|
||||
const totalCount = totalEvents || 0;
|
||||
const countText = `${count} of ${totalCount}`;
|
||||
@ -82,6 +88,10 @@ export const EventLog = ({ title, project, feature }: IEventLogProps) => {
|
||||
</PageHeader>
|
||||
}
|
||||
>
|
||||
<ConditionallyRender
|
||||
condition={isEnterprise() && showFilters}
|
||||
show={<EventLogFilters logType={logType} />}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(cache && cache.length === 0)}
|
||||
show={<p>No events found.</p>}
|
||||
|
148
frontend/src/component/events/EventLog/EventLogFilters.tsx
Normal file
148
frontend/src/component/events/EventLog/EventLogFilters.tsx
Normal file
@ -0,0 +1,148 @@
|
||||
import { useState, useEffect, type FC } from 'react';
|
||||
import { Filters, type IFilterItem } from 'component/filter/Filters/Filters';
|
||||
import useProjects from 'hooks/api/getters/useProjects/useProjects';
|
||||
import { useFeatureSearch } from 'hooks/api/getters/useFeatureSearch/useFeatureSearch';
|
||||
|
||||
const flagLogFilters: IFilterItem[] = [
|
||||
{
|
||||
label: 'Date From',
|
||||
icon: 'today',
|
||||
options: [],
|
||||
filterKey: 'from',
|
||||
dateOperators: ['IS'],
|
||||
},
|
||||
{
|
||||
label: 'Date To',
|
||||
icon: 'today',
|
||||
options: [],
|
||||
filterKey: 'to',
|
||||
dateOperators: ['IS'],
|
||||
},
|
||||
{
|
||||
// todo fill this in with actual values
|
||||
label: 'Created by',
|
||||
icon: 'person',
|
||||
options: [],
|
||||
filterKey: 'createdBy',
|
||||
singularOperators: ['IS'],
|
||||
pluralOperators: ['IS_ANY_OF'],
|
||||
},
|
||||
{
|
||||
// todo fill this in with actual values
|
||||
label: 'Event type',
|
||||
icon: 'announcement',
|
||||
options: [],
|
||||
filterKey: 'eventType',
|
||||
singularOperators: ['IS'],
|
||||
pluralOperators: ['IS_ANY_OF'],
|
||||
},
|
||||
];
|
||||
|
||||
export const FlagLogFilters = () => {
|
||||
return (
|
||||
<Filters
|
||||
availableFilters={flagLogFilters}
|
||||
state={{}}
|
||||
onChange={(v) => console.log(v)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const useProjectLogFilters = () => {
|
||||
const [availableFilters, setAvailableFilters] = useState<IFilterItem[]>([]);
|
||||
|
||||
const { features } = useFeatureSearch({ project: 'default' });
|
||||
|
||||
useEffect(() => {
|
||||
const flagOptions = (features || []).map((flag) => ({
|
||||
label: flag.name,
|
||||
value: flag.name,
|
||||
}));
|
||||
|
||||
const availableFilters: IFilterItem[] = [
|
||||
...flagLogFilters,
|
||||
{
|
||||
label: 'Feature Flag',
|
||||
icon: 'flag',
|
||||
options: flagOptions,
|
||||
filterKey: 'flag',
|
||||
singularOperators: ['IS'],
|
||||
pluralOperators: ['IS_ANY_OF'],
|
||||
},
|
||||
];
|
||||
|
||||
setAvailableFilters(availableFilters);
|
||||
}, [JSON.stringify(features)]);
|
||||
|
||||
return availableFilters;
|
||||
};
|
||||
|
||||
export const ProjectLogFilters = () => {
|
||||
const availableFilters = useProjectLogFilters();
|
||||
|
||||
return (
|
||||
<Filters
|
||||
availableFilters={availableFilters}
|
||||
state={{}}
|
||||
onChange={(v) => console.log(v)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const GlobalLogFilters = () => {
|
||||
const projectFilters = useProjectLogFilters();
|
||||
const { projects } = useProjects();
|
||||
|
||||
const [availableFilters, setAvailableFilters] = useState<IFilterItem[]>([]);
|
||||
useEffect(() => {
|
||||
const projectOptions = (projects || []).map((project) => ({
|
||||
label: project.name,
|
||||
value: project.id,
|
||||
}));
|
||||
|
||||
const hasMultipleProjects = projectOptions.length > 1;
|
||||
|
||||
const availableFilters: IFilterItem[] = [
|
||||
...projectFilters,
|
||||
...(hasMultipleProjects
|
||||
? ([
|
||||
{
|
||||
label: 'Project',
|
||||
icon: 'topic',
|
||||
options: projectOptions,
|
||||
filterKey: 'project',
|
||||
singularOperators: ['IS'],
|
||||
pluralOperators: ['IS_ANY_OF'],
|
||||
},
|
||||
] as IFilterItem[])
|
||||
: []),
|
||||
];
|
||||
|
||||
setAvailableFilters(availableFilters);
|
||||
}, [JSON.stringify(projectFilters), JSON.stringify(projects)]);
|
||||
|
||||
return (
|
||||
<Filters
|
||||
availableFilters={availableFilters}
|
||||
state={{}}
|
||||
onChange={(v) => console.log(v)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
type EventLogFiltersProps = {
|
||||
logType: 'flag' | 'project' | 'global';
|
||||
};
|
||||
export const EventLogFilters: FC<EventLogFiltersProps> = (
|
||||
{ logType },
|
||||
// {state, onChange,} // these are to fill in later to make the filters work
|
||||
) => {
|
||||
switch (logType) {
|
||||
case 'flag':
|
||||
return <FlagLogFilters />;
|
||||
case 'project':
|
||||
return <ProjectLogFilters />;
|
||||
case 'global':
|
||||
return <GlobalLogFilters />;
|
||||
}
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
import { useEffect, useState, type VFC } from 'react';
|
||||
import { type FC, useEffect, useState } from 'react';
|
||||
import { Box, Icon, styled } from '@mui/material';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import { AddFilterButton } from '../AddFilterButton';
|
||||
@ -57,7 +57,7 @@ const StyledIcon = styled(Icon)(({ theme }) => ({
|
||||
},
|
||||
}));
|
||||
|
||||
export const Filters: VFC<IFilterProps> = ({
|
||||
export const Filters: FC<IFilterProps> = ({
|
||||
state,
|
||||
onChange,
|
||||
availableFilters,
|
||||
|
Loading…
Reference in New Issue
Block a user