mirror of https://github.com/portainer/portainer
refactor(docker/events): migrate list view to react [EE-2228] (#11581)
parent
9797201c2a
commit
33ce841040
|
@ -188,8 +188,7 @@ angular.module('portainer.docker', ['portainer.app', reactModule]).config([
|
||||||
url: '/events',
|
url: '/events',
|
||||||
views: {
|
views: {
|
||||||
'content@': {
|
'content@': {
|
||||||
templateUrl: './views/events/events.html',
|
component: 'eventsListView',
|
||||||
controller: 'EventsController',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { r2a } from '@/react-tools/react2angular';
|
||||||
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
import { withCurrentUser } from '@/react-tools/withCurrentUser';
|
||||||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||||
import { DashboardView } from '@/react/docker/DashboardView/DashboardView';
|
import { DashboardView } from '@/react/docker/DashboardView/DashboardView';
|
||||||
|
import { ListView } from '@/react/docker/events/ListView';
|
||||||
|
|
||||||
import { containersModule } from './containers';
|
import { containersModule } from './containers';
|
||||||
|
|
||||||
|
@ -14,6 +15,7 @@ export const viewsModule = angular
|
||||||
'dockerDashboardView',
|
'dockerDashboardView',
|
||||||
r2a(withUIRouter(withCurrentUser(DashboardView)), [])
|
r2a(withUIRouter(withCurrentUser(DashboardView)), [])
|
||||||
)
|
)
|
||||||
|
.component('eventsListView', r2a(withUIRouter(withCurrentUser(ListView)), []))
|
||||||
.component(
|
.component(
|
||||||
'networkDetailsView',
|
'networkDetailsView',
|
||||||
r2a(withUIRouter(withCurrentUser(NetworksItemView)), [])
|
r2a(withUIRouter(withCurrentUser(NetworksItemView)), [])
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import { ping } from '@/react/docker/proxy/queries/usePing';
|
import { ping } from '@/react/docker/proxy/queries/usePing';
|
||||||
import { getInfo } from '@/react/docker/proxy/queries/useInfo';
|
import { getInfo } from '@/react/docker/proxy/queries/useInfo';
|
||||||
import { getVersion } from '@/react/docker/proxy/queries/useVersion';
|
import { getVersion } from '@/react/docker/proxy/queries/useVersion';
|
||||||
import { getEvents } from '@/react/docker/proxy/queries/useEvents';
|
|
||||||
import { EventViewModel } from '../models/event';
|
|
||||||
|
|
||||||
angular.module('portainer.docker').factory('SystemService', SystemServiceFactory);
|
angular.module('portainer.docker').factory('SystemService', SystemServiceFactory);
|
||||||
|
|
||||||
|
@ -14,15 +12,5 @@ function SystemServiceFactory(AngularToReact) {
|
||||||
info: useAxios(injectEnvironmentId(getInfo)), // dashboard + docker host view + docker host browser + swarm inspect views + stateManager (update endpoint state)
|
info: useAxios(injectEnvironmentId(getInfo)), // dashboard + docker host view + docker host browser + swarm inspect views + stateManager (update endpoint state)
|
||||||
ping: useAxios(ping), // docker/__module onEnter abstract /docker subpath
|
ping: useAxios(ping), // docker/__module onEnter abstract /docker subpath
|
||||||
version: useAxios(injectEnvironmentId(getVersion)), // docker host view + swarm inspect view + stateManager (update endpoint state)
|
version: useAxios(injectEnvironmentId(getVersion)), // docker host view + swarm inspect view + stateManager (update endpoint state)
|
||||||
events: useAxios(injectEnvironmentId(eventsAngularJS)), // events list
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {EnvironmentId} environmentId Injected
|
|
||||||
* @param {{since: string; until: string;}} param1
|
|
||||||
*/
|
|
||||||
async function eventsAngularJS(environmentId, { since, until }) {
|
|
||||||
const data = await getEvents(environmentId, { since, until });
|
|
||||||
return data.map((e) => new EventViewModel(e));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<page-header title="'Event list'" breadcrumbs="['Events']" reload="true"> </page-header>
|
|
||||||
|
|
||||||
<docker-events-datatable dataset="events"></docker-events-datatable>
|
|
|
@ -1,23 +0,0 @@
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
angular.module('portainer.docker').controller('EventsController', [
|
|
||||||
'$scope',
|
|
||||||
'Notifications',
|
|
||||||
'SystemService',
|
|
||||||
function ($scope, Notifications, SystemService) {
|
|
||||||
function initView() {
|
|
||||||
const since = moment().subtract(24, 'hour').unix();
|
|
||||||
const until = moment().unix();
|
|
||||||
|
|
||||||
SystemService.events({ since, until })
|
|
||||||
.then(function success(data) {
|
|
||||||
$scope.events = data;
|
|
||||||
})
|
|
||||||
.catch(function error(err) {
|
|
||||||
Notifications.error('Failure', err, 'Unable to load events');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
initView();
|
|
||||||
},
|
|
||||||
]);
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { createColumnHelper } from '@tanstack/react-table';
|
import { createColumnHelper } from '@tanstack/react-table';
|
||||||
import { Clock } from 'lucide-react';
|
import { Clock } from 'lucide-react';
|
||||||
|
import { EventMessage } from 'docker-types/generated/1.41';
|
||||||
|
|
||||||
import { isoDateFromTimestamp } from '@/portainer/filters/filters';
|
import { isoDateFromTimestamp } from '@/portainer/filters/filters';
|
||||||
|
|
||||||
|
@ -7,26 +8,22 @@ import { Datatable } from '@@/datatables';
|
||||||
import { createPersistedStore } from '@@/datatables/types';
|
import { createPersistedStore } from '@@/datatables/types';
|
||||||
import { useTableState } from '@@/datatables/useTableState';
|
import { useTableState } from '@@/datatables/useTableState';
|
||||||
|
|
||||||
type DockerEvent = {
|
import { createEventDetails } from './model';
|
||||||
Time: number;
|
|
||||||
Type: string;
|
|
||||||
Details: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<DockerEvent>();
|
const columnHelper = createColumnHelper<EventMessage>();
|
||||||
|
|
||||||
export const columns = [
|
export const columns = [
|
||||||
columnHelper.accessor('Time', {
|
columnHelper.accessor('time', {
|
||||||
header: 'Date',
|
header: 'Date',
|
||||||
cell: ({ getValue }) => {
|
cell: ({ getValue }) => {
|
||||||
const value = getValue();
|
const value = getValue();
|
||||||
return isoDateFromTimestamp(value);
|
return isoDateFromTimestamp(value);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('Type', {
|
columnHelper.accessor((c) => c.Type, {
|
||||||
header: 'Type',
|
header: 'Type',
|
||||||
}),
|
}),
|
||||||
columnHelper.accessor('Details', {
|
columnHelper.accessor((c) => createEventDetails(c), {
|
||||||
header: 'Details',
|
header: 'Details',
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
@ -37,12 +34,17 @@ const settingsStore = createPersistedStore(tableKey, {
|
||||||
desc: true,
|
desc: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function EventsDatatable({ dataset }: { dataset: Array<DockerEvent> }) {
|
export function EventsDatatable({
|
||||||
|
dataset,
|
||||||
|
}: {
|
||||||
|
dataset?: Array<EventMessage>;
|
||||||
|
}) {
|
||||||
const tableState = useTableState(settingsStore, tableKey);
|
const tableState = useTableState(settingsStore, tableKey);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Datatable
|
<Datatable
|
||||||
dataset={dataset ?? []}
|
dataset={dataset ?? []}
|
||||||
|
isLoading={!dataset}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
settingsManager={tableState}
|
settingsManager={tableState}
|
||||||
title="Events"
|
title="Events"
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { useState } from 'react';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||||
|
|
||||||
|
import { PageHeader } from '@@/PageHeader';
|
||||||
|
|
||||||
|
import { useEvents } from '../proxy/queries/useEvents';
|
||||||
|
|
||||||
|
import { EventsDatatable } from './EventsDatatables';
|
||||||
|
|
||||||
|
export function ListView() {
|
||||||
|
const { since, until } = useDateRange();
|
||||||
|
const envId = useEnvironmentId();
|
||||||
|
const eventsQuery = useEvents(envId, { params: { since, until } });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<PageHeader title="Event list" breadcrumbs="Events" reload />
|
||||||
|
|
||||||
|
<EventsDatatable dataset={eventsQuery.data} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useDateRange() {
|
||||||
|
return useState(() => {
|
||||||
|
const since = moment().subtract(24, 'hour').unix();
|
||||||
|
const until = moment().unix();
|
||||||
|
|
||||||
|
return { since, until };
|
||||||
|
})[0];
|
||||||
|
}
|
|
@ -87,7 +87,7 @@ const templates: EventToTemplateMap = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function createEventDetails(event: EventMessage) {
|
export function createEventDetails(event: EventMessage) {
|
||||||
const eventType = event.Type ?? '';
|
const eventType = event.Type ?? '';
|
||||||
|
|
||||||
// An action can be `action:extra`
|
// An action can be `action:extra`
|
||||||
|
@ -118,17 +118,3 @@ function createEventDetails(event: EventMessage) {
|
||||||
|
|
||||||
return details + extra;
|
return details + extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class EventViewModel {
|
|
||||||
Time: EventMessage['time'];
|
|
||||||
|
|
||||||
Type: EventMessage['Type'];
|
|
||||||
|
|
||||||
Details: string;
|
|
||||||
|
|
||||||
constructor(data: EventMessage) {
|
|
||||||
this.Time = data.time;
|
|
||||||
this.Type = data.Type;
|
|
||||||
this.Details = createEventDetails(data);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
export type DockerEvent = {
|
||||||
|
Time: number;
|
||||||
|
Type: string;
|
||||||
|
Details: string;
|
||||||
|
};
|
|
@ -3,4 +3,6 @@ import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
export const queryKeys = {
|
export const queryKeys = {
|
||||||
base: (environmentId: EnvironmentId) =>
|
base: (environmentId: EnvironmentId) =>
|
||||||
[environmentId, 'docker', 'proxy'] as const,
|
[environmentId, 'docker', 'proxy'] as const,
|
||||||
|
events: (environmentId: EnvironmentId, params?: object) =>
|
||||||
|
[...queryKeys.base(environmentId), 'events', params] as const,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { EventMessage } from 'docker-types/generated/1.41';
|
import { EventMessage } from 'docker-types/generated/1.41';
|
||||||
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
|
||||||
import axios, {
|
import axios, {
|
||||||
jsonObjectsToArrayHandler,
|
jsonObjectsToArrayHandler,
|
||||||
|
@ -7,16 +8,26 @@ import axios, {
|
||||||
import { EnvironmentId } from '@/react/portainer/environments/types';
|
import { EnvironmentId } from '@/react/portainer/environments/types';
|
||||||
|
|
||||||
import { buildDockerProxyUrl } from './buildDockerProxyUrl';
|
import { buildDockerProxyUrl } from './buildDockerProxyUrl';
|
||||||
|
import { queryKeys } from './query-keys';
|
||||||
|
|
||||||
|
type Params = { since?: number; until?: number };
|
||||||
|
|
||||||
|
export function useEvents(
|
||||||
|
environmentId: EnvironmentId,
|
||||||
|
{ params }: { params?: Params } = {}
|
||||||
|
) {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: [...queryKeys.events(environmentId, params)],
|
||||||
|
queryFn: () => getEvents(environmentId, params),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw docker API proxy
|
* Raw docker API proxy
|
||||||
* @param environmentId
|
|
||||||
* @param param1
|
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
export async function getEvents(
|
export async function getEvents(
|
||||||
environmentId: EnvironmentId,
|
environmentId: EnvironmentId,
|
||||||
{ since, until }: { since: string; until: string }
|
{ since, until }: Params = {}
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.get<EventMessage[]>(
|
const { data } = await axios.get<EventMessage[]>(
|
||||||
|
|
Loading…
Reference in New Issue