POC/Provisioning: Update recent jobs table (#100506)

* Sync: Remove redundant API call

* Update recent jobs real time

* Format
This commit is contained in:
Alex Khomenko
2025-02-12 17:35:33 +01:00
committed by GitHub
parent 0f382ea04f
commit c614639695
3 changed files with 38 additions and 21 deletions
@@ -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 (
<Card>
<Card.Heading>Recent jobs</Card.Heading>
<Card.Actions>
<Button icon="sync" variant="secondary" onClick={query.refetch} disabled={query.isFetching}>
Refresh
</Button>
</Card.Actions>
<Card.Description>
{!items?.length ? (
<EmptyState />
) : (
<InteractiveTable
data={items.slice(0, 10)}
key={items?.length}
data={items.slice(0, 20)}
columns={jobColumns}
getRowId={(item) => item.metadata?.resourceVersion || ''}
renderExpandedRow={(row) => <ExpandedRow row={row} />}
pageSize={30}
/>
)}
</Card.Description>
@@ -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 <Loader />;
}
const isHealthy = Boolean(repository.status?.health.healthy);
return (
+31
View File
@@ -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<typeof useListJobQuery>,
] {
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];
}