From 9c82e48dcf0b54d9322b8d704ae517166c123174 Mon Sep 17 00:00:00 2001 From: Oleg Vavilov Date: Mon, 2 Feb 2026 20:21:12 +0300 Subject: [PATCH 1/2] Events UI #3309 Added links to event list from project and user details pages --- frontend/src/locale/en.json | 3 + .../src/pages/Events/List/hooks/useFilters.ts | 66 ++++++++++++------- frontend/src/pages/Events/List/index.tsx | 17 +++-- frontend/src/pages/Project/Details/index.tsx | 19 +++++- frontend/src/pages/User/Details/index.tsx | 13 +++- 5 files changed, 86 insertions(+), 32 deletions(-) diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index e11541edba..b8b2d0c35b 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -182,6 +182,7 @@ "repositories": "Repositories", "runs": "Runs", "tags": "Tags", + "events": "Project events", "settings": "Settings", "join": "Join", "leave_confirm_title": "Leave project", @@ -695,6 +696,8 @@ "account_settings": "User settings", "settings": "Settings", "projects": "Projects", + "events": "User events", + "activity": "User activity", "create": { "page_title": "Create user", "error_notification": "Create user error", diff --git a/frontend/src/pages/Events/List/hooks/useFilters.ts b/frontend/src/pages/Events/List/hooks/useFilters.ts index 6a82b3a654..14c245f374 100644 --- a/frontend/src/pages/Events/List/hooks/useFilters.ts +++ b/frontend/src/pages/Events/List/hooks/useFilters.ts @@ -1,5 +1,6 @@ import { useMemo, useState } from 'react'; import { useSearchParams } from 'react-router-dom'; +import { omit } from 'lodash'; import type { PropertyFilterProps } from 'components'; @@ -77,8 +78,8 @@ const targetTypes = [ export const useFilters = () => { const [searchParams, setSearchParams] = useSearchParams(); - const { data: projectsData } = useGetProjectsQuery({}); - const { data: usersData } = useGetUserListQuery({}); + const { data: projectsData, isLoading: isLoadingProjects } = useGetProjectsQuery({}); + const { data: usersData, isLoading: isLoadingUsers } = useGetUserListQuery({}); const [propertyFilterQuery, setPropertyFilterQuery] = useState(() => requestParamsToTokens({ searchParams, filterKeys }), @@ -243,51 +244,65 @@ export const useFilters = () => { arrayFieldKeys: multipleChoiseKeys, }); + const targetProjects = params[filterKeys.TARGET_PROJECTS] + ?.map((name: string) => projectsData?.data?.find(({ project_name }) => project_name === name)?.['project_id']) + .filter(Boolean); + + const withInProjects = params[filterKeys.WITHIN_PROJECTS] + ?.map((name: string) => projectsData?.data?.find(({ project_name }) => project_name === name)?.['project_id']) + .filter(Boolean); + + const targetUsers = params[filterKeys.TARGET_USERS] + ?.map((name: string) => usersData?.data?.find(({ username }) => username === name)?.['id']) + .filter(Boolean); + + const actors = params[filterKeys.ACTORS] + ?.map((name: string) => usersData?.data?.find(({ username }) => username === name)?.['id']) + .filter(Boolean); + + const includeTargetTypes = params[filterKeys.INCLUDE_TARGET_TYPES] + ?.map((selectedLabel: string) => targetTypes?.find(({ label }) => label === selectedLabel)?.['value']) + .filter(Boolean); + const mappedFields = { - ...(params[filterKeys.TARGET_PROJECTS] && Array.isArray(params[filterKeys.TARGET_PROJECTS]) + ...(targetProjects?.length ? { - [filterKeys.TARGET_PROJECTS]: params[filterKeys.TARGET_PROJECTS]?.map( - (name: string) => - projectsData?.data?.find(({ project_name }) => project_name === name)?.['project_id'], - ), + [filterKeys.TARGET_PROJECTS]: targetProjects, } : {}), - ...(params[filterKeys.WITHIN_PROJECTS] && Array.isArray(params[filterKeys.WITHIN_PROJECTS]) + ...(withInProjects?.length ? { - [filterKeys.WITHIN_PROJECTS]: params[filterKeys.WITHIN_PROJECTS]?.map( - (name: string) => - projectsData?.data?.find(({ project_name }) => project_name === name)?.['project_id'], - ), + [filterKeys.WITHIN_PROJECTS]: withInProjects, } : {}), - ...(params[filterKeys.TARGET_USERS] && Array.isArray(params[filterKeys.TARGET_USERS]) + ...(targetUsers?.length ? { - [filterKeys.TARGET_USERS]: params[filterKeys.TARGET_USERS]?.map( - (name: string) => usersData?.data?.find(({ username }) => username === name)?.['id'], - ), + [filterKeys.TARGET_USERS]: targetUsers, } : {}), - ...(params[filterKeys.ACTORS] && Array.isArray(params[filterKeys.ACTORS]) + ...(actors?.length ? { - [filterKeys.ACTORS]: params[filterKeys.ACTORS]?.map( - (name: string) => usersData?.data?.find(({ username }) => username === name)?.['id'], - ), + [filterKeys.ACTORS]: actors, } : {}), - ...(params[filterKeys.INCLUDE_TARGET_TYPES] && Array.isArray(params[filterKeys.INCLUDE_TARGET_TYPES]) + ...(includeTargetTypes?.length ? { - [filterKeys.INCLUDE_TARGET_TYPES]: params[filterKeys.INCLUDE_TARGET_TYPES]?.map( - (selectedLabel: string) => targetTypes?.find(({ label }) => label === selectedLabel)?.['value'], - ), + [filterKeys.INCLUDE_TARGET_TYPES]: includeTargetTypes, } : {}), }; return { - ...params, + ...omit(params, [ + filterKeys.TARGET_PROJECTS, + filterKeys.WITHIN_PROJECTS, + filterKeys.TARGET_USERS, + filterKeys.ACTORS, + filterKeys.INCLUDE_TARGET_TYPES, + ]), ...mappedFields, } as Partial; }, [propertyFilterQuery, usersData, projectsData]); @@ -299,5 +314,6 @@ export const useFilters = () => { onChangePropertyFilter, filteringOptions, filteringProperties, + isLoadingFilters: isLoadingProjects || isLoadingUsers, } as const; }; diff --git a/frontend/src/pages/Events/List/index.tsx b/frontend/src/pages/Events/List/index.tsx index fcf979d554..cfb681b3e5 100644 --- a/frontend/src/pages/Events/List/index.tsx +++ b/frontend/src/pages/Events/List/index.tsx @@ -24,12 +24,19 @@ export const EventList = () => { }, ]); - const { filteringRequestParams, propertyFilterQuery, onChangePropertyFilter, filteringOptions, filteringProperties } = - useFilters(); + const { + filteringRequestParams, + propertyFilterQuery, + onChangePropertyFilter, + filteringOptions, + filteringProperties, + isLoadingFilters, + } = useFilters(); const { data, isLoading, refreshList, isLoadingMore } = useInfiniteScroll({ useLazyQuery: useLazyGetAllEventsQuery, args: { ...filteringRequestParams, limit: DEFAULT_TABLE_PAGE_SIZE }, + skip: isLoadingFilters, getPaginationParams: (lastEvent) => ({ prev_recorded_at: lastEvent.recorded_at, @@ -47,13 +54,15 @@ export const EventList = () => { const { columns } = useColumnsDefinitions(); + const loading = isLoadingFilters || isLoading; + return ( {
-