Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ const AppDetailsPage = ({ id }: AppDetailsPageProps): ReactElement => {
</Page>
{compactMode && contextualBar === 'filter-logs' && (
<FormProvider {...logsFilterFormMethods}>
<AppLogsFilterContextualBar onClose={handleReturnToLogs} />
<AppLogsFilterContextualBar appId={id} onClose={handleReturnToLogs} />
</FormProvider>
)}
</Page>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Box, Pagination } from '@rocket.chat/fuselage';
import { useDebouncedValue } from '@rocket.chat/fuselage-hooks';
import { useMemo, type ReactElement } from 'react';
import { useTranslation } from 'react-i18next';

Expand All @@ -23,15 +22,13 @@ const AppLogs = ({ id }: { id: string }): ReactElement => {

const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination();

const debouncedEvent = useDebouncedValue(event, 500);

const { data, isSuccess, isError, error, isFetching } = useLogs({
appId: id,
current,
itemsPerPage,
...(instance !== 'all' && { instanceId: instance }),
...(severity !== 'all' && { logLevel: severity }),
method: debouncedEvent,
...(event !== 'all' && { method: event }),
...(startTime && startDate && { startDate: new Date(`${startDate}T${startTime}`).toISOString() }),
...(endTime && endDate && { endDate: new Date(`${endDate}T${endTime}`).toISOString() }),
});
Expand All @@ -50,14 +47,14 @@ const AppLogs = ({ id }: { id: string }): ReactElement => {
return (
<>
<Box pb={16}>
<AppLogsFilter noResults={isFetching || !isSuccess || data?.logs?.length === 0} isLoading={isFetching} />
<AppLogsFilter appId={id} noResults={isFetching || !isSuccess || data?.logs?.length === 0} isLoading={isFetching} />
</Box>
{isFetching && <AccordionLoading />}
{isError && <GenericError title={parsedError} />}
{!isFetching && isSuccess && data?.logs?.length === 0 && <GenericNoResults />}
{!isFetching && isSuccess && data?.logs?.length > 0 && (
<CustomScrollbars>
<CollapsiblePanel aria-busy={isFetching || event !== debouncedEvent} width='100%' alignSelf='center'>
<CollapsiblePanel aria-busy={isFetching} width='100%' alignSelf='center'>
{data?.logs?.map((log, index) => <AppLogsItem regionId={log._id} key={`${index}-${log._createdAt}`} {...log} />)}
</CollapsiblePanel>
</CustomScrollbars>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ export default {
args: {},
decorators: [
mockAppRoot()
// @ts-expect-error The endpoint is to be merged in https://github.com/RocketChat/Rocket.Chat/pull/36245
.withEndpoint('GET', '/apps/logs/instanceIds', () => ({
.withEndpoint('GET', '/apps/:id/logs/distinctValues', () => ({
success: true,
instanceIds: ['instance-1', 'instance-2', 'instance-3'],
methods: ['method-1', 'method-2', 'method-3'],
}))
.buildStoryDecorator(),
(fn) => {
Expand All @@ -33,4 +33,4 @@ export default {
},
} satisfies Meta<typeof AppLogsFilter>;

export const Default = () => <AppLogsFilter />;
export const Default = () => <AppLogsFilter appId='app-id' />;
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Box, Button, Icon, IconButton, Label, Palette, TextInput } from '@rocket.chat/fuselage';
import { Box, Button, IconButton, Label } from '@rocket.chat/fuselage';
import { useRouter, useSetModal } from '@rocket.chat/ui-contexts';
import { Controller } from 'react-hook-form';
import { useTranslation } from 'react-i18next';

import CompactFilterOptions from './AppsLogsFilterOptionsCompact';
import { EventFilterSelect } from './EventFilterSelect';
import { InstanceFilterSelect } from './InstanceFilterSelect';
import { SeverityFilterSelect } from './SeverityFilterSelect';
import { TimeFilterSelect } from './TimeFilterSelect';
Expand All @@ -12,11 +13,12 @@ import { useAppLogsFilterFormContext } from '../useAppLogsFilterForm';
import { ExportLogsModal } from './ExportLogsModal';

type AppsLogsFilterProps = {
appId: string;
isLoading?: boolean;
noResults?: boolean;
};

export const AppLogsFilter = ({ isLoading = false, noResults = false }: AppsLogsFilterProps) => {
export const AppLogsFilter = ({ appId, isLoading = false, noResults = false }: AppsLogsFilterProps) => {
const { t } = useTranslation();

const { control, getValues } = useAppLogsFilterFormContext();
Expand Down Expand Up @@ -44,17 +46,13 @@ export const AppLogsFilter = ({ isLoading = false, noResults = false }: AppsLogs
return (
<Box display='flex' flexDirection='row' width='full' flexWrap='wrap' alignContent='flex-end'>
<Box display='flex' flexDirection='column' mie={10} flexGrow={1}>
<Label htmlFor='eventFilter'>{t('Event')}</Label>
<Label id='eventFilterLabel' htmlFor='eventFilter'>
{t('Event')}
</Label>
<Controller
control={control}
name='event'
render={({ field }) => (
<TextInput
addon={<Icon color={Palette.text['font-secondary-info']} name='magnifier' size={20} />}
id='eventFilter'
{...field}
/>
)}
render={({ field }) => <EventFilterSelect appId={appId} aria-labelledby='eventFilterLabel' id='eventFilter' {...field} />}
/>
</Box>
{!compactMode && (
Expand All @@ -73,7 +71,9 @@ export const AppLogsFilter = ({ isLoading = false, noResults = false }: AppsLogs
<Controller
control={control}
name='instance'
render={({ field }) => <InstanceFilterSelect aria-labelledby='instanceFilterLabel' id='instanceFilter' {...field} />}
render={({ field }) => (
<InstanceFilterSelect appId={appId} aria-labelledby='instanceFilterLabel' id='instanceFilter' {...field} />
)}
/>
</Box>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ test.each(testCases)(`renders AppLogsItem without crashing`, async (_storyname,
test.each(testCases)('AppLogsItem should have no a11y violations', async (_storyname, Story) => {
const { container } = render(<Story />, { wrapper: mockAppRoot().build() });

const results = await axe(container);
/**
** Disable 'nested-interactive' rule because our `Select` component is still not a11y compliant
**/
const results = await axe(container, { rules: { 'nested-interactive': { enabled: false } } });

expect(results).toHaveNoViolations();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ export default {
args: {},
decorators: [
mockAppRoot()
// @ts-expect-error The endpoint is to be merged in https://github.com/RocketChat/Rocket.Chat/pull/36245
.withEndpoint('GET', '/apps/logs/instanceIds', () => ({
.withEndpoint('GET', '/apps/:id/logs/distinctValues', () => ({
success: true,
instanceIds: ['instance-1', 'instance-2', 'instance-3'],
methods: ['method-1', 'method-2', 'method-3'],
}))
.buildStoryDecorator(),
(fn) => {
Expand All @@ -33,4 +33,4 @@ export default {
},
} satisfies Meta<typeof AppLogsFilterContextualBar>;

export const Default = () => <AppLogsFilterContextualBar onClose={action('onClose')} />;
export const Default = () => <AppLogsFilterContextualBar appId='app-id' onClose={action('onClose')} />;
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ import {
import { useAppLogsFilterFormContext } from '../useAppLogsFilterForm';

type AppLogsFilterContextualBarProps = {
appId: string;
onClose: () => void;
};

export const AppLogsFilterContextualBar = ({ onClose = () => undefined }: AppLogsFilterContextualBarProps) => {
export const AppLogsFilterContextualBar = ({ appId, onClose = () => undefined }: AppLogsFilterContextualBarProps) => {
const { t } = useTranslation();

const { control } = useAppLogsFilterFormContext();
Expand Down Expand Up @@ -54,7 +55,9 @@ export const AppLogsFilterContextualBar = ({ onClose = () => undefined }: AppLog
<Controller
control={control}
name='instance'
render={({ field }) => <InstanceFilterSelect aria-labelledby='instanceFilterLabel' id='instanceFilter' {...field} />}
render={({ field }) => (
<InstanceFilterSelect appId={appId} aria-labelledby='instanceFilterLabel' id='instanceFilter' {...field} />
)}
/>
</Box>
<Box display='flex' flexDirection='column' mie={10} flexGrow={1}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { SelectOption } from '@rocket.chat/fuselage';
import { InputBoxSkeleton, Select } from '@rocket.chat/fuselage';
import type { ComponentProps } from 'react';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { useLogsDistinctValues } from '../../../../hooks/useLogsDistinctValues';

type EventFilterSelectProps = Omit<ComponentProps<typeof Select>, 'options'> & { appId: string };

export const EventFilterSelect = ({ appId, ...props }: EventFilterSelectProps) => {
const { t } = useTranslation();

const { data, isPending } = useLogsDistinctValues(appId);

const options: SelectOption[] = useMemo(() => {
const mappedData: [string, string][] = data?.methods?.map((id: string) => [id, id]) || [];
return [['all', t('All')], ...mappedData];
}, [data, t]);

if (isPending) {
return <InputBoxSkeleton aria-labelledby={props['aria-labelledby']} aria-busy />;
}

return <Select options={options} {...props} />;
};
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
import type { SelectOption } from '@rocket.chat/fuselage';
import { InputBoxSkeleton, Select } from '@rocket.chat/fuselage';
import { useEndpoint } from '@rocket.chat/ui-contexts';
import { useQuery } from '@tanstack/react-query';
import type { ComponentProps } from 'react';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';

type InstanceFilterSelectProps = Omit<ComponentProps<typeof Select>, 'options'>;
import { useLogsDistinctValues } from '../../../../hooks/useLogsDistinctValues';

export const InstanceFilterSelect = ({ ...props }: InstanceFilterSelectProps) => {
type InstanceFilterSelectProps = Omit<ComponentProps<typeof Select>, 'options'> & { appId: string };

export const InstanceFilterSelect = ({ appId, ...props }: InstanceFilterSelectProps) => {
const { t } = useTranslation();
// @ts-expect-error The endpoint is to be merged in https://github.com/RocketChat/Rocket.Chat/pull/36245
const getOptions = useEndpoint('GET', '/apps/logs/instanceIds');

const { data, isPending } = useQuery({
queryKey: ['app-logs-filter-instances'],
// @ts-expect-error The endpoint is to be merged in https://github.com/RocketChat/Rocket.Chat/pull/36245
queryFn: async () => getOptions(),
});
const { data, isPending } = useLogsDistinctValues(appId);

const options: SelectOption[] = useMemo(() => {
// @ts-expect-error The endpoint is to be merged in https://github.com/RocketChat/Rocket.Chat/pull/36245
const mappedData: [string, string][] = data?.instanceIds?.map((id: string) => [id, id]) || [];
return [['all', t('All')], ...mappedData];
}, [data, t]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,19 @@ exports[`renders AppLogsItem without crashing 1`] = `
<label
class="rcx-box rcx-box--full rcx-label"
for="eventFilter"
id="eventFilterLabel"
>
Event
</label>
<label
class="rcx-box rcx-box--full rcx-label rcx-box rcx-box--full rcx-box--animated rcx-input-box__wrapper"
<div
aria-busy="true"
aria-labelledby="eventFilterLabel"
class="rcx-box rcx-box--full rcx-skeleton__input"
>
<input
class="rcx-box rcx-box--full rcx-box--animated rcx-input-box--undecorated rcx-input-box--type-text rcx-input-box"
id="eventFilter"
name="event"
size="1"
type="text"
value=""
/>
<span
class="rcx-box rcx-box--full rcx-input-box__addon"
>
<i
aria-hidden="true"
class="rcx-box rcx-box--full rcx-icon--name-magnifier rcx-icon rcx-css-1bepdyv"
>
</i>
</span>
</label>
class="rcx-skeleton rcx-skeleton--text rcx-css-1qcz93u"
/>
</div>
</div>
<button
class="rcx-box rcx-box--full rcx-button--secondary rcx-button rcx-css-qv9v2f"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,19 @@ exports[`renders AppLogsItem without crashing 1`] = `
<label
class="rcx-box rcx-box--full rcx-label"
for="eventFilter"
id="eventFilterLabel"
>
Event
</label>
<label
class="rcx-box rcx-box--full rcx-label rcx-box rcx-box--full rcx-box--animated rcx-input-box__wrapper"
<div
aria-busy="true"
aria-labelledby="eventFilterLabel"
class="rcx-box rcx-box--full rcx-skeleton__input"
>
<input
class="rcx-box rcx-box--full rcx-box--animated rcx-input-box--undecorated rcx-input-box--type-text rcx-input-box"
id="eventFilter"
name="event"
size="1"
type="text"
value=""
/>
<span
class="rcx-box rcx-box--full rcx-input-box__addon"
>
<i
aria-hidden="true"
class="rcx-box rcx-box--full rcx-icon--name-magnifier rcx-icon rcx-css-1bepdyv"
>
</i>
</span>
</label>
class="rcx-skeleton rcx-skeleton--text rcx-css-1qcz93u"
/>
</div>
</div>
<div
class="rcx-box rcx-box--full rcx-css-1rfw4fq"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ export type AppLogsFilterFormData = {
};

export const useAppLogsFilterForm = () =>
useForm<AppLogsFilterFormData>({ defaultValues: { severity: 'all', instance: 'all', timeFilter: 'all' } });
useForm<AppLogsFilterFormData>({ defaultValues: { severity: 'all', instance: 'all', timeFilter: 'all', event: 'all' } });

export const useAppLogsFilterFormContext = () => useFormContext<AppLogsFilterFormData>();
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { OperationResult } from '@rocket.chat/rest-typings';
import { useEndpoint } from '@rocket.chat/ui-contexts';
import type { UseQueryResult } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';

export const useLogsDistinctValues = (appId: string): UseQueryResult<OperationResult<'GET', '/apps/:id/logs/distinctValues'>> => {
const getValues = useEndpoint('GET', '/apps/:id/logs/distinctValues', { id: appId });

return useQuery({
queryKey: ['app-logs-filter-distinct-values', appId],
queryFn: async () => getValues(),
});
};
Loading
Loading