diff --git a/.changeset/silent-zoos-notice.md b/.changeset/silent-zoos-notice.md new file mode 100644 index 0000000000000..4490e8d3c610e --- /dev/null +++ b/.changeset/silent-zoos-notice.md @@ -0,0 +1,6 @@ +--- +"@rocket.chat/meteor": minor +"@rocket.chat/i18n": minor +--- + +Adds 2 new buttons to the App Logs Filters, "Expand all" and "Refresh" diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogs.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogs.tsx index 81b620dc237b6..d47e7e68bd9ea 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogs.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogs.tsx @@ -1,5 +1,6 @@ +import type { ILogItem } from '@rocket.chat/core-typings'; import { Box, Pagination } from '@rocket.chat/fuselage'; -import { useMemo, type ReactElement } from 'react'; +import { useEffect, useMemo, useReducer, type ReactElement } from 'react'; import { useTranslation } from 'react-i18next'; import AppLogsItem from './AppLogsItem'; @@ -13,6 +14,25 @@ import { usePagination } from '../../../../../components/GenericTable/hooks/useP import AccordionLoading from '../../../components/AccordionLoading'; import { useLogs } from '../../../hooks/useLogs'; +function expandedReducer( + expandedStates: { id: string; expanded: boolean }[], + action: { type: 'update'; id: string; expanded: boolean } | { type: 'expand-all' } | { type: 'reset'; logs: ILogItem[] }, +) { + switch (action.type) { + case 'update': + return expandedStates.map((state) => (state.id === action.id ? { ...state, expanded: action.expanded } : state)); + + case 'expand-all': + return expandedStates.map((state) => ({ ...state, expanded: true })); + + case 'reset': + return action.logs.map((log) => ({ id: log._id, expanded: false })); + + default: + return expandedStates; + } +} + const AppLogs = ({ id }: { id: string }): ReactElement => { const { t } = useTranslation(); @@ -22,7 +42,13 @@ const AppLogs = ({ id }: { id: string }): ReactElement => { const { current, itemsPerPage, setItemsPerPage: onSetItemsPerPage, setCurrent: onSetCurrent, ...paginationProps } = usePagination(); - const { data, isSuccess, isError, error, isFetching } = useLogs({ + const [expandedStates, dispatch] = useReducer(expandedReducer, []); + + const handleExpand = ({ id, expanded }: { id: string; expanded: boolean }) => dispatch({ id, expanded, type: 'update' }); + + const handleExpandAll = () => dispatch({ type: 'expand-all' }); + + const { data, isSuccess, isError, error, refetch, isFetching } = useLogs({ appId: id, current, itemsPerPage, @@ -33,6 +59,12 @@ const AppLogs = ({ id }: { id: string }): ReactElement => { ...(endTime && endDate && { endDate: new Date(`${endDate}T${endTime}`).toISOString() }), }); + useEffect(() => { + if (isSuccess) { + dispatch({ type: 'reset', logs: data.logs }); + } + }, [data, isSuccess]); + const parsedError = useMemo(() => { if (error) { // TODO: Check why tanstack expects a default Error but we return {error: string} @@ -47,15 +79,29 @@ const AppLogs = ({ id }: { id: string }): ReactElement => { return ( <> - + handleExpandAll()} + refetchLogs={() => refetch()} + /> {isFetching && } {isError && } {!isFetching && isSuccess && data?.logs?.length === 0 && } {!isFetching && isSuccess && data?.logs?.length > 0 && ( - - {data?.logs?.map((log, index) => )} + + {data?.logs?.map((log, index) => ( + state.id === log._id)?.expanded || false} + onExpand={handleExpand} + key={`${index}-${log._createdAt}`} + {...log} + /> + ))} )} diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx index 7bb6f9b65a04c..5d2fa63ca27e5 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/AppLogsItem.tsx @@ -1,6 +1,6 @@ import type { ILogItem } from '@rocket.chat/core-typings'; import { Box, Divider } from '@rocket.chat/fuselage'; -import { useRef, useState } from 'react'; +import { useRef } from 'react'; import { useTranslation } from 'react-i18next'; import AppLogsItemEntry from './AppLogsItemEntry'; @@ -11,11 +11,12 @@ import { useFormatDateAndTime } from '../../../../../hooks/useFormatDateAndTime' export type AppLogsItemProps = { regionId: string; + expanded: boolean; + onExpand: ({ id }: { id: string; expanded: boolean }) => void; } & ILogItem; -const AppLogsItem = ({ regionId, ...props }: AppLogsItemProps) => { +const AppLogsItem = ({ regionId, expanded, onExpand, ...props }: AppLogsItemProps) => { const { t } = useTranslation(); - const [expanded, setExpanded] = useState(false); const title = ( <> {props.entries.map(({ severity, timestamp, caller, args }, index) => { @@ -33,7 +34,7 @@ const AppLogsItem = ({ regionId, ...props }: AppLogsItemProps) => { ); const handleClick = () => { - setExpanded(!expanded); + onExpand({ id: regionId, expanded: !expanded }); }; const anchorRef = useRef(null); diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.stories.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.stories.tsx index 09ae4a97e3a42..0c02a79c3b384 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.stories.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.stories.tsx @@ -1,5 +1,6 @@ import { Box } from '@rocket.chat/fuselage'; import { mockAppRoot } from '@rocket.chat/mock-providers'; +import { action } from '@storybook/addon-actions'; import type { Meta } from '@storybook/react'; import { FormProvider } from 'react-hook-form'; @@ -33,4 +34,6 @@ export default { }, } satisfies Meta; -export const Default = () => ; +export const Default = () => ( + +); diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.tsx index 703e959c5e2d1..211c37e711308 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.tsx +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppLogsFilter.tsx @@ -3,7 +3,7 @@ import { useRouter, useSetModal } from '@rocket.chat/ui-contexts'; import { Controller } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import CompactFilterOptions from './AppsLogsFilterOptionsCompact'; +import CompactFilterOptions from './CompactFilterOptions'; import { EventFilterSelect } from './EventFilterSelect'; import { InstanceFilterSelect } from './InstanceFilterSelect'; import { SeverityFilterSelect } from './SeverityFilterSelect'; @@ -14,11 +14,13 @@ import { ExportLogsModal } from './ExportLogsModal'; type AppsLogsFilterProps = { appId: string; - isLoading?: boolean; + expandAll: () => void; + refetchLogs: () => void; + isLoading: boolean; noResults?: boolean; }; -export const AppLogsFilter = ({ appId, isLoading = false, noResults = false }: AppsLogsFilterProps) => { +export const AppLogsFilter = ({ appId, expandAll, refetchLogs, isLoading, noResults = false }: AppsLogsFilterProps) => { const { t } = useTranslation(); const { control, getValues } = useAppLogsFilterFormContext(); @@ -37,6 +39,11 @@ export const AppLogsFilter = ({ appId, isLoading = false, noResults = false }: A ); }; + const openAllLogs = () => expandAll(); + + const refreshLogs = () => { + refetchLogs(); + }; const openExportModal = () => { setModal( setModal(null)} filterValues={getValues()} />); }; @@ -83,6 +90,22 @@ export const AppLogsFilter = ({ appId, isLoading = false, noResults = false }: A } /> )} + {!compactMode && ( + + )} + {!compactMode && ( + refreshLogs()} + /> + )} {!compactMode && ( )} - {compactMode && } + {compactMode && ( + + )} ); }; diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppsLogsFilterOptionsCompact.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppsLogsFilterOptionsCompact.tsx deleted file mode 100644 index 8b163b92092b5..0000000000000 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/AppsLogsFilterOptionsCompact.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Box, Icon, Menu } from '@rocket.chat/fuselage'; -import { useTranslation } from 'react-i18next'; - -type CompactFilterOptionsProps = { - handleExportLogs: () => void; - isLoading: boolean; -}; - -const CompactFilterOptions = ({ handleExportLogs, ...props }: CompactFilterOptionsProps) => { - const { t } = useTranslation(); - - const menuOptions = { - exportLogs: { - label: ( - - - {t('Export')} - - ), - action: handleExportLogs, - }, - }; - return ; -}; - -export default CompactFilterOptions; diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/CompactFilterOptions.tsx b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/CompactFilterOptions.tsx new file mode 100644 index 0000000000000..b0479681974c9 --- /dev/null +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/CompactFilterOptions.tsx @@ -0,0 +1,47 @@ +import { Box, Icon, Menu } from '@rocket.chat/fuselage'; +import { useTranslation } from 'react-i18next'; + +type CompactFilterOptionsProps = { + onExpandAll: () => void; + onRefreshLogs: () => void; + onExportLogs: () => void; + isLoading: boolean; +}; + +const CompactFilterOptions = ({ onExportLogs, onExpandAll, onRefreshLogs, isLoading, ...props }: CompactFilterOptionsProps) => { + const { t } = useTranslation(); + + const menuOptions = { + exportLogs: { + label: ( + + + {t('Export')} + + ), + action: onExportLogs, + }, + expandAll: { + label: ( + + + {t('Expand_all')} + + ), + action: onExpandAll, + }, + refreshLogs: { + label: ( + + + {t('Refresh_logs')} + + ), + action: onRefreshLogs, + disabled: isLoading, + }, + }; + return ; +}; + +export default CompactFilterOptions; diff --git a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/__snapshots__/AppLogsFilterExpanded.spec.tsx.snap b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/__snapshots__/AppLogsFilterExpanded.spec.tsx.snap index c2d86bd0912c5..9ef55418e6ff4 100644 --- a/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/__snapshots__/AppLogsFilterExpanded.spec.tsx.snap +++ b/apps/meteor/client/views/marketplace/AppDetailsPage/tabs/AppLogs/Filters/__snapshots__/AppLogsFilterExpanded.spec.tsx.snap @@ -204,6 +204,34 @@ exports[`renders AppLogsItem without crashing 1`] = ` + +