From c6146396959a00a3f5c2fe88123bcb7f392bec7d Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Wed, 12 Feb 2025 18:35:33 +0200 Subject: [PATCH] POC/Provisioning: Update recent jobs table (#100506) * Sync: Remove redundant API call * Update recent jobs real time * Format --- .../app/features/provisioning/RecentJobs.tsx | 19 ++++-------- .../features/provisioning/SyncRepository.tsx | 9 +----- public/app/features/provisioning/hooks.ts | 31 +++++++++++++++++++ 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/public/app/features/provisioning/RecentJobs.tsx b/public/app/features/provisioning/RecentJobs.tsx index 20e82b2f931..ceed8ebe607 100644 --- a/public/app/features/provisioning/RecentJobs.tsx +++ b/public/app/features/provisioning/RecentJobs.tsx @@ -1,8 +1,9 @@ import { useMemo } from 'react'; -import { Spinner, Alert, Badge, InteractiveTable, Button, Card, Box, Stack, Icon, Text } from '@grafana/ui'; +import { Spinner, Alert, Badge, InteractiveTable, Card, Box, Stack, Icon, Text } from '@grafana/ui'; -import { Repository, JobResourceSummary, useListJobQuery, Job, SyncStatus } from './api'; +import { Repository, JobResourceSummary, Job, SyncStatus } from './api'; +import { useRepositoryJobs } from './hooks'; import { formatTimestamp } from './utils/time'; interface Props { @@ -166,10 +167,7 @@ function EmptyState() { } export function RecentJobs({ repo }: Props) { - const name = repo.metadata?.name; - const query = useListJobQuery({ labelSelector: `repository=${name}` }); - const items = query?.data?.items ?? []; - + const [items, query] = useRepositoryJobs({ name: repo.metadata?.name, watch: true }); const jobColumns = useMemo(() => getJobColumns(), []); if (query.isLoading) { @@ -187,21 +185,16 @@ export function RecentJobs({ repo }: Props) { return ( Recent jobs - - - {!items?.length ? ( ) : ( item.metadata?.resourceVersion || ''} renderExpandedRow={(row) => } - pageSize={30} /> )} diff --git a/public/app/features/provisioning/SyncRepository.tsx b/public/app/features/provisioning/SyncRepository.tsx index 8cc2714db5d..ba835f6eb1d 100644 --- a/public/app/features/provisioning/SyncRepository.tsx +++ b/public/app/features/provisioning/SyncRepository.tsx @@ -5,9 +5,7 @@ import { AppEvents } from '@grafana/data'; import { getAppEvents } from '@grafana/runtime'; import { Button, ConfirmModal } from '@grafana/ui'; -import { Loader } from '../plugins/admin/components/Loader'; - -import { Repository, useCreateRepositorySyncMutation, useListRepositoryQuery } from './api'; +import { Repository, useCreateRepositorySyncMutation } from './api'; import { PROVISIONING_URL } from './constants'; interface Props { @@ -15,7 +13,6 @@ interface Props { } export function SyncRepository({ repository }: Props) { - const query = useListRepositoryQuery({}); const [syncResource, syncQuery] = useCreateRepositorySyncMutation(); const [isModalOpen, setIsModalOpen] = useState(false); const navigate = useNavigate(); @@ -44,10 +41,6 @@ export function SyncRepository({ repository }: Props) { setIsModalOpen(false); }; - if (query.isLoading) { - return ; - } - const isHealthy = Boolean(repository.status?.health.healthy); return ( diff --git a/public/app/features/provisioning/hooks.ts b/public/app/features/provisioning/hooks.ts index a48b3162c0f..ae052bfe41b 100644 --- a/public/app/features/provisioning/hooks.ts +++ b/public/app/features/provisioning/hooks.ts @@ -15,6 +15,8 @@ import { useListRepositoryQuery, useReplaceRepositoryFilesWithPathMutation, useReplaceRepositoryMutation, + useListJobQuery, + Job, } from './api'; export function useCreateOrUpdateRepository(name?: string) { @@ -112,3 +114,32 @@ export const useGetResourceRepository = ({ name, folderUid }: GetResourceReposit return items.find((repo) => repo.metadata?.name === repoName); }; + +interface RepositoryJobsArgs { + name?: string; + watch?: boolean; +} + +export function useRepositoryJobs({ name, watch = true }: RepositoryJobsArgs = {}): [ + Job[] | undefined, + ReturnType, +] { + const query = useListJobQuery( + name + ? { + labelSelector: `repository=${name}`, + watch, + } + : skipToken + ); + + const collator = new Intl.Collator(undefined, { numeric: true }); + + const sortedItems = query.data?.items?.slice().sort((a, b) => { + const aTime = a.metadata?.creationTimestamp ?? ''; + const bTime = b.metadata?.creationTimestamp ?? ''; + return collator.compare(bTime, aTime); // Reverse order for newest first + }); + + return [sortedItems, query]; +}