mirror of
https://github.com/portainer/portainer.git
synced 2025-08-05 22:05:23 +02:00
refactor(kube): events datatable react migration [EE-6450] (#11583)
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
Co-authored-by: testa113 <testa113>
This commit is contained in:
parent
c15789eb73
commit
bb61e73464
24 changed files with 233 additions and 306 deletions
|
@ -8,7 +8,7 @@ import { Tab, WidgetTabs, findSelectedTabIndex } from '@@/Widget/WidgetTabs';
|
|||
import { Icon } from '@@/Icon';
|
||||
import { Badge } from '@@/Badge';
|
||||
|
||||
import { EventsDatatable } from '../../components/KubernetesEventsDatatable';
|
||||
import { EventsDatatable } from '../../components/EventsDatatable';
|
||||
|
||||
import {
|
||||
PlacementsDatatable,
|
||||
|
|
|
@ -2,6 +2,7 @@ import { useCurrentStateAndParams } from '@uirouter/react';
|
|||
import { useMemo } from 'react';
|
||||
|
||||
import { createStore } from '@/react/kubernetes/datatables/default-kube-datatable-store';
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
|
||||
import { useTableState } from '@@/datatables/useTableState';
|
||||
|
||||
|
@ -10,9 +11,9 @@ import {
|
|||
useApplicationPods,
|
||||
useApplicationServices,
|
||||
} from '../application.queries';
|
||||
import { EventsDatatable } from '../../components/KubernetesEventsDatatable';
|
||||
|
||||
import { useNamespaceEventsQuery } from './useNamespaceEventsQuery';
|
||||
import { EventsDatatable } from '../../components/EventsDatatable';
|
||||
import { useEvents } from '../../queries/useEvents';
|
||||
import { AppKind } from '../types';
|
||||
|
||||
const storageKey = 'k8sAppEventsDatatable';
|
||||
const settingsStore = createStore(storageKey, { id: 'Date', desc: true });
|
||||
|
@ -23,41 +24,73 @@ export function ApplicationEventsDatatable() {
|
|||
params: {
|
||||
namespace,
|
||||
name,
|
||||
'resource-type': resourceType,
|
||||
'resource-type': appKind,
|
||||
endpointId: environmentId,
|
||||
},
|
||||
} = useCurrentStateAndParams();
|
||||
|
||||
const { relatedEvents, isInitialLoading } = useApplicationEvents(
|
||||
environmentId,
|
||||
namespace,
|
||||
name,
|
||||
appKind,
|
||||
{
|
||||
autoRefreshRate: tableState.autoRefreshRate,
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<EventsDatatable
|
||||
dataset={relatedEvents}
|
||||
tableState={tableState}
|
||||
isLoading={isInitialLoading}
|
||||
data-cy="k8sAppDetail-eventsTable"
|
||||
noWidget
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function useApplicationEvents(
|
||||
environmentId: EnvironmentId,
|
||||
namespace: string,
|
||||
name: string,
|
||||
appKind?: AppKind,
|
||||
options?: { autoRefreshRate?: number; yaml?: boolean }
|
||||
) {
|
||||
const { data: application, ...applicationQuery } = useApplication(
|
||||
environmentId,
|
||||
namespace,
|
||||
name,
|
||||
resourceType
|
||||
appKind
|
||||
);
|
||||
const { data: services, ...servicesQuery } = useApplicationServices(
|
||||
const servicesQuery = useApplicationServices(
|
||||
environmentId,
|
||||
namespace,
|
||||
name,
|
||||
application
|
||||
);
|
||||
const { data: pods, ...podsQuery } = useApplicationPods(
|
||||
const podsQuery = useApplicationPods(
|
||||
environmentId,
|
||||
namespace,
|
||||
name,
|
||||
application
|
||||
);
|
||||
const { data: events, ...eventsQuery } = useNamespaceEventsQuery(
|
||||
environmentId,
|
||||
|
||||
const { data: events, ...eventsQuery } = useEvents(environmentId, {
|
||||
namespace,
|
||||
{
|
||||
autoRefreshRate: tableState.autoRefreshRate * 1000,
|
||||
}
|
||||
);
|
||||
queryOptions: {
|
||||
autoRefreshRate: options?.autoRefreshRate
|
||||
? options.autoRefreshRate * 1000
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
|
||||
// related events are events that have the application id, or the id of a service or pod from the application
|
||||
const relatedEvents = useMemo(() => {
|
||||
const serviceIds = services?.map((service) => service?.metadata?.uid);
|
||||
const podIds = pods?.map((pod) => pod?.metadata?.uid);
|
||||
const serviceIds = servicesQuery.data?.map(
|
||||
(service) => service?.metadata?.uid
|
||||
);
|
||||
const podIds = podsQuery.data?.map((pod) => pod?.metadata?.uid);
|
||||
return (
|
||||
events?.filter(
|
||||
(event) =>
|
||||
|
@ -66,20 +99,13 @@ export function ApplicationEventsDatatable() {
|
|||
podIds?.includes(event.involvedObject.uid)
|
||||
) || []
|
||||
);
|
||||
}, [application?.metadata?.uid, events, pods, services]);
|
||||
}, [application?.metadata?.uid, events, podsQuery.data, servicesQuery.data]);
|
||||
|
||||
return (
|
||||
<EventsDatatable
|
||||
dataset={relatedEvents}
|
||||
tableState={tableState}
|
||||
isLoading={
|
||||
applicationQuery.isLoading ||
|
||||
eventsQuery.isLoading ||
|
||||
servicesQuery.isLoading ||
|
||||
podsQuery.isLoading
|
||||
}
|
||||
data-cy="k8sAppDetail-eventsTable"
|
||||
noWidget
|
||||
/>
|
||||
);
|
||||
const isInitialLoading =
|
||||
applicationQuery.isInitialLoading ||
|
||||
servicesQuery.isInitialLoading ||
|
||||
podsQuery.isInitialLoading ||
|
||||
eventsQuery.isInitialLoading;
|
||||
|
||||
return { relatedEvents, isInitialLoading };
|
||||
}
|
||||
|
|
|
@ -10,8 +10,7 @@ import {
|
|||
useApplicationPods,
|
||||
useApplicationServices,
|
||||
} from '../application.queries';
|
||||
|
||||
import { useNamespaceEventsQuery } from './useNamespaceEventsQuery';
|
||||
import { useEvents } from '../../queries/useEvents';
|
||||
|
||||
const storageKey = 'k8sAppEventsDatatable';
|
||||
const settingsStore = createStore(storageKey, { id: 'Date', desc: true });
|
||||
|
@ -49,13 +48,12 @@ export function useApplicationEventsTableData() {
|
|||
name,
|
||||
application
|
||||
);
|
||||
const { data: events, ...eventsQuery } = useNamespaceEventsQuery(
|
||||
environmentId,
|
||||
const { data: events, ...eventsQuery } = useEvents(environmentId, {
|
||||
namespace,
|
||||
{
|
||||
queryOptions: {
|
||||
autoRefreshRate: appEventsTableState.autoRefreshRate * 1000,
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
// related events are events that have the application id, or the id of a service or pod from the application
|
||||
const appEventsData = useMemo(() => {
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
import { EventList } from 'kubernetes-types/core/v1';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import axios from '@/portainer/services/axios';
|
||||
import { withError } from '@/react-tools/react-query';
|
||||
|
||||
import { parseKubernetesAxiosError } from '../../axiosError';
|
||||
|
||||
async function getNamespaceEvents(
|
||||
environmentId: EnvironmentId,
|
||||
namespace: string,
|
||||
labelSelector?: string
|
||||
) {
|
||||
try {
|
||||
const { data } = await axios.get<EventList>(
|
||||
`/endpoints/${environmentId}/kubernetes/api/v1/namespaces/${namespace}/events`,
|
||||
{
|
||||
params: {
|
||||
labelSelector,
|
||||
},
|
||||
}
|
||||
);
|
||||
return data.items;
|
||||
} catch (e) {
|
||||
throw parseKubernetesAxiosError(e, 'Unable to retrieve events');
|
||||
}
|
||||
}
|
||||
|
||||
export function useNamespaceEventsQuery(
|
||||
environmentId: EnvironmentId,
|
||||
namespace: string,
|
||||
options?: { autoRefreshRate?: number },
|
||||
labelSelector?: string
|
||||
) {
|
||||
return useQuery(
|
||||
[
|
||||
'environments',
|
||||
environmentId,
|
||||
'kubernetes',
|
||||
'events',
|
||||
namespace,
|
||||
labelSelector,
|
||||
],
|
||||
() => getNamespaceEvents(environmentId, namespace, labelSelector),
|
||||
{
|
||||
...withError('Unable to retrieve events'),
|
||||
refetchInterval() {
|
||||
return options?.autoRefreshRate ?? false;
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
import { useCurrentStateAndParams } from '@uirouter/react';
|
||||
|
||||
import { useKubeStore } from '@/react/kubernetes/datatables/default-kube-datatable-store';
|
||||
import { useEvents } from '@/react/kubernetes/queries/useEvents';
|
||||
import { EventsDatatable } from '@/react/kubernetes/components/EventsDatatable';
|
||||
|
||||
type Props = {
|
||||
storageKey: string;
|
||||
/** if undefined, all resources for the namespace (or cluster are returned) */
|
||||
resourceId?: string;
|
||||
/** if undefined, events are fetched for the cluster */
|
||||
namespace?: string;
|
||||
};
|
||||
|
||||
/** ResourceEventsDatatable returns the EventsDatatable for all events that relate to a specific resource id */
|
||||
export function ResourceEventsDatatable({
|
||||
storageKey,
|
||||
resourceId,
|
||||
namespace,
|
||||
}: Props) {
|
||||
const tableState = useKubeStore(storageKey, {
|
||||
id: 'Date',
|
||||
desc: true,
|
||||
});
|
||||
|
||||
const {
|
||||
params: { endpointId },
|
||||
} = useCurrentStateAndParams();
|
||||
|
||||
const params = resourceId
|
||||
? { fieldSelector: `involvedObject.uid=${resourceId}` }
|
||||
: {};
|
||||
const resourceEventsQuery = useEvents(endpointId, {
|
||||
namespace,
|
||||
params,
|
||||
queryOptions: {
|
||||
autoRefreshRate: tableState.autoRefreshRate
|
||||
? tableState.autoRefreshRate * 1000
|
||||
: undefined,
|
||||
},
|
||||
});
|
||||
const nodeEvents = resourceEventsQuery.data || [];
|
||||
|
||||
return (
|
||||
<EventsDatatable
|
||||
dataset={nodeEvents}
|
||||
tableState={tableState}
|
||||
isLoading={resourceEventsQuery.isLoading}
|
||||
data-cy="k8sNodeDetail-eventsTable"
|
||||
noWidget
|
||||
/>
|
||||
);
|
||||
}
|
5
app/react/kubernetes/queries/query-keys.ts
Normal file
5
app/react/kubernetes/queries/query-keys.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
/** Kubernetes environment base query keys */
|
||||
export const queryKeys = {
|
||||
base: (environmentId: number) =>
|
||||
['environments', environmentId, 'kubernetes'] as const,
|
||||
};
|
86
app/react/kubernetes/queries/useEvents.ts
Normal file
86
app/react/kubernetes/queries/useEvents.ts
Normal file
|
@ -0,0 +1,86 @@
|
|||
import { EventList } from 'kubernetes-types/core/v1';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||
import axios from '@/portainer/services/axios';
|
||||
import { withError } from '@/react-tools/react-query';
|
||||
|
||||
import { parseKubernetesAxiosError } from '../axiosError';
|
||||
|
||||
import { queryKeys as environmentQueryKeys } from './query-keys';
|
||||
|
||||
type RequestOptions = {
|
||||
/** if undefined, events are fetched at the cluster scope */
|
||||
namespace?: string;
|
||||
params?: {
|
||||
/** https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors */
|
||||
labelSelector?: string;
|
||||
/** https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors */
|
||||
fieldSelector?: string;
|
||||
};
|
||||
};
|
||||
|
||||
const queryKeys = {
|
||||
base: (environmentId: number, { namespace, params }: RequestOptions) => {
|
||||
if (namespace) {
|
||||
return [
|
||||
...environmentQueryKeys.base(environmentId),
|
||||
'events',
|
||||
namespace,
|
||||
params,
|
||||
] as const;
|
||||
}
|
||||
return [
|
||||
...environmentQueryKeys.base(environmentId),
|
||||
'events',
|
||||
params,
|
||||
] as const;
|
||||
},
|
||||
};
|
||||
|
||||
async function getEvents(
|
||||
environmentId: EnvironmentId,
|
||||
options?: RequestOptions
|
||||
) {
|
||||
const { namespace, params } = options ?? {};
|
||||
try {
|
||||
const { data } = await axios.get<EventList>(
|
||||
buildUrl(environmentId, namespace),
|
||||
{
|
||||
params,
|
||||
}
|
||||
);
|
||||
return data.items;
|
||||
} catch (e) {
|
||||
throw parseKubernetesAxiosError(e, 'Unable to retrieve events');
|
||||
}
|
||||
}
|
||||
|
||||
type QueryOptions = {
|
||||
queryOptions?: {
|
||||
autoRefreshRate?: number;
|
||||
};
|
||||
} & RequestOptions;
|
||||
|
||||
export function useEvents(
|
||||
environmentId: EnvironmentId,
|
||||
options?: QueryOptions
|
||||
) {
|
||||
const { queryOptions, params, namespace } = options ?? {};
|
||||
return useQuery(
|
||||
queryKeys.base(environmentId, { params, namespace }),
|
||||
() => getEvents(environmentId, { params, namespace }),
|
||||
{
|
||||
...withError('Unable to retrieve events'),
|
||||
refetchInterval() {
|
||||
return queryOptions?.autoRefreshRate ?? false;
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function buildUrl(environmentId: EnvironmentId, namespace?: string) {
|
||||
return namespace
|
||||
? `/endpoints/${environmentId}/kubernetes/api/v1/namespaces/${namespace}/events`
|
||||
: `/endpoints/${environmentId}/kubernetes/api/v1/events`;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue