Skip to content

Commit

Permalink
refactor: split EventLog into separate components and hook up new Eve…
Browse files Browse the repository at this point in the history
…nt search (#7777)

Hooks up the new Event search and filtering capabilities to the new
Event Log component. In doing so, it also splits the existing EventLog
component into two: `LegacyEventLog` and `NewEventLog`. The naming is
probably temporary, as the old EventLog isn't really legacy yet. But we
can rename them later.

The other half of #7768 .
  • Loading branch information
thomasheartman authored Aug 7, 2024
1 parent d4069f2 commit d70c279
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 53 deletions.
161 changes: 118 additions & 43 deletions frontend/src/component/events/EventLog/EventLog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useUiFlag } from 'hooks/useUiFlag';
import { EventLogFilters } from './EventLogFilters';
import type { EventSchema } from 'openapi';
import { useEventLogSearch } from './useEventLogSearch';

interface IEventLogProps {
title: string;
Expand All @@ -41,7 +42,98 @@ const EventResultWrapper = styled('div')(({ theme }) => ({
gap: theme.spacing(1),
}));

export const EventLog = ({ title, project, feature }: IEventLogProps) => {
const NewEventLog = ({ title, project, feature }: IEventLogProps) => {
const { events, total, loading, tableState, setTableState, filterState } =
useEventLogSearch(
project
? { type: 'project', projectId: project }
: feature
? { type: 'flag', flagName: feature }
: { type: 'global' },
);

const setSearchValue = (query = '') => {
setTableState({ query });
};
const { eventSettings, setEventSettings } = useEventSettings();
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));

const onShowData = () => {
setEventSettings((prev) => ({ showData: !prev.showData }));
};

const searchInputField = (
<Search
onChange={setSearchValue}
initialValue={tableState.query || ''}
debounceTime={500}
/>
);

const showDataSwitch = (
<FormControlLabel
label='Full events'
control={
<Switch
checked={eventSettings.showData}
onChange={onShowData}
color='primary'
/>
}
/>
);

const resultComponent = () => {
if (loading) {
return <p>Loading...</p>;
} else if (events.length === 0) {
return <p>No events found.</p>;
} else {
return (
<StyledEventsList>
{events.map((entry) => (
<ConditionallyRender
key={entry.id}
condition={eventSettings.showData}
show={() => <EventJson entry={entry} />}
elseShow={() => <EventCard entry={entry} />}
/>
))}
</StyledEventsList>
);
}
};

return (
<PageContent
bodyClass={'no-padding'}
header={
<PageHeader
title={`${title} (${total})`}
actions={
<>
{showDataSwitch}
{!isSmallScreen && searchInputField}
</>
}
>
{isSmallScreen && searchInputField}
</PageHeader>
}
>
<EventResultWrapper>
<StyledFilters
logType={project ? 'project' : feature ? 'flag' : 'global'}
state={filterState}
onChange={setTableState}
/>
{resultComponent()}
</EventResultWrapper>
</PageContent>
);
};

export const LegacyEventLog = ({ title, project, feature }: IEventLogProps) => {
const [query, setQuery] = useState('');
const { events, totalEvents, fetchNextPage } = useLegacyEventSearch(
project,
Expand All @@ -51,8 +143,6 @@ 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') && isEnterprise();

// Cache the previous search results so that we can show those while
// fetching new results for a new search query in the background.
Expand Down Expand Up @@ -82,33 +172,8 @@ export const EventLog = ({ title, project, feature }: IEventLogProps) => {
const totalCount = totalEvents || 0;
const countText = `${count} of ${totalCount}`;

const EventResults = (
<>
<ConditionallyRender
condition={Boolean(cache && cache.length === 0)}
show={<p>No events found.</p>}
/>
<ConditionallyRender
condition={Boolean(cache && cache.length > 0)}
show={
<StyledEventsList>
{cache?.map((entry) => (
<ConditionallyRender
key={entry.id}
condition={eventSettings.showData}
show={() => <EventJson entry={entry} />}
elseShow={() => <EventCard entry={entry} />}
/>
))}
</StyledEventsList>
}
/>
</>
);

return (
<PageContent
bodyClass={showFilters ? 'no-padding' : ''}
header={
<PageHeader
title={`${title} (${countText})`}
Expand All @@ -124,25 +189,35 @@ export const EventLog = ({ title, project, feature }: IEventLogProps) => {
}
>
<ConditionallyRender
condition={showFilters}
condition={Boolean(cache && cache.length === 0)}
show={<p>No events found.</p>}
/>
<ConditionallyRender
condition={Boolean(cache && cache.length > 0)}
show={
<EventResultWrapper>
<StyledFilters
logType={
project
? 'project'
: feature
? 'flag'
: 'global'
}
/>
{EventResults}
</EventResultWrapper>
<StyledEventsList>
{cache?.map((entry) => (
<ConditionallyRender
key={entry.id}
condition={eventSettings.showData}
show={() => <EventJson entry={entry} />}
elseShow={() => <EventCard entry={entry} />}
/>
))}
</StyledEventsList>
}
elseShow={EventResults}
/>

<div ref={fetchNextPageRef} />
</PageContent>
);
};

export const EventLog = (props: IEventLogProps) => {
const { isEnterprise } = useUiConfig();
const showFilters = useUiFlag('newEventSearch') && isEnterprise();
if (showFilters) {
return <NewEventLog {...props} />;
} else {
return <LegacyEventLog {...props} />;
}
};
27 changes: 17 additions & 10 deletions frontend/src/component/events/EventLog/EventLogFilters.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { useState, useEffect, type FC } from 'react';
import { Filters, type IFilterItem } from 'component/filter/Filters/Filters';
import {
type FilterItemParamHolder,
Filters,
type IFilterItem,
} from 'component/filter/Filters/Filters';
import useProjects from 'hooks/api/getters/useProjects/useProjects';
import { useFeatureSearch } from 'hooks/api/getters/useFeatureSearch/useFeatureSearch';
import { EventSchemaType } from 'openapi';
Expand Down Expand Up @@ -30,14 +34,13 @@ const sharedFilters: IFilterItem[] = [
pluralOperators: ['IS_ANY_OF'],
},
{
// todo fill this in with actual values
label: 'Event type',
icon: 'announcement',
options: Object.entries(EventSchemaType).map(([key, value]) => ({
label: key,
value: value,
})),
filterKey: 'eventType',
filterKey: 'type',
singularOperators: ['IS'],
pluralOperators: ['IS_ANY_OF'],
},
Expand All @@ -46,11 +49,15 @@ const sharedFilters: IFilterItem[] = [
type EventLogFiltersProps = {
logType: 'flag' | 'project' | 'global';
className?: string;
state: FilterItemParamHolder;
onChange: (value: FilterItemParamHolder) => void;
};
export const EventLogFilters: FC<EventLogFiltersProps> = (
{ logType, className },
// {state, onChange,} // these are to fill in later to make the filters work
) => {
export const EventLogFilters: FC<EventLogFiltersProps> = ({
logType,
className,
state,
onChange,
}) => {
const { projects } = useProjects();
const { features } = useFeatureSearch({});

Expand Down Expand Up @@ -90,7 +97,7 @@ export const EventLogFilters: FC<EventLogFiltersProps> = (
label: 'Feature Flag',
icon: 'flag',
options: flagOptions,
filterKey: 'flag',
filterKey: 'feature',
singularOperators: ['IS'],
pluralOperators: ['IS_ANY_OF'],
},
Expand All @@ -105,8 +112,8 @@ export const EventLogFilters: FC<EventLogFiltersProps> = (
<Filters
className={className}
availableFilters={availableFilters}
state={{}}
onChange={(v) => console.log(v)}
state={state}
onChange={onChange}
/>
);
};

0 comments on commit d70c279

Please sign in to comment.