From 7d20fc01a7a99e106579ab154ef3a0e54d27a85c Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Fri, 11 Dec 2020 14:05:41 +0100 Subject: [PATCH 1/3] initial version of the events tab --- package.json | 1 + src/events/EventsSection.tsx | 88 ++++++++++++++++++++++++++++++++++-- src/events/messages.json | 10 +++- yarn.lock | 5 ++ 4 files changed, 100 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b01d02b5a8..871cc52ec1 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "i18next": "^19.6.2", "keycloak-admin": "1.14.2", "lodash": "^4.17.20", + "moment": "^2.29.1", "react": "^16.8.5", "react-dom": "^16.8.5", "react-hook-form": "^6.8.2", diff --git a/src/events/EventsSection.tsx b/src/events/EventsSection.tsx index 27e937679d..ef95f536e9 100644 --- a/src/events/EventsSection.tsx +++ b/src/events/EventsSection.tsx @@ -1,10 +1,92 @@ -import { PageSection } from "@patternfly/react-core"; -import React from "react"; +import React, { useContext, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { + Button, + Label, + PageSection, + ToolbarItem, +} from "@patternfly/react-core"; +import moment from "moment"; +import EventRepresentation from "keycloak-admin/lib/defs/eventRepresentation"; + +import { useAdminClient } from "../context/auth/AdminClient"; +import { ViewHeader } from "../components/view-header/ViewHeader"; +import { DataList } from "../components/table-toolbar/DataList"; +import { RealmContext } from "../context/realm-context/RealmContext"; +import { InfoCircleIcon } from "@patternfly/react-icons"; export const EventsSection = () => { + const { t } = useTranslation("events"); + const adminClient = useAdminClient(); + const { realm } = useContext(RealmContext); + const [key, setKey] = useState(""); + const refresh = () => setKey(`${new Date().getTime()}`); + + const loader = async (first?: number, max?: number, search?: string) => { + const params = { + first: first!, + max: max!, + realm, + }; + if (search) { + console.log("how to search?", search); + } + return await adminClient.realms.findEvents({ ...params }); + }; + + const StatusRow = (event: EventRepresentation) => { + return ( + <> + + + ); + }; + return ( <> - The Events Page + + + + + + + + } + columns={[ + { + name: "time", + displayKey: "events:time", + cellRenderer: (row) => moment(row.time).fromNow(), + }, + { + name: "userId", + displayKey: "events:user", + }, + { + name: "type", + displayKey: "events:eventType", + cellRenderer: StatusRow, + }, + { + name: "ipAddress", + displayKey: "events:ipAddress", + }, + { + name: "clientId", + displayKey: "events:client", + }, + ]} + /> + ); }; diff --git a/src/events/messages.json b/src/events/messages.json index 9224d1f2f4..3e551f0238 100644 --- a/src/events/messages.json +++ b/src/events/messages.json @@ -1,5 +1,13 @@ { "events": { - "title": "Events" + "title": "Events", + "eventExplain": "If you want to configure user events, Admin events or Event listeners, please enter Event configs page realm settings to configure.", + "searchForEvent": "Search user event", + "refresh": "Refresh", + "time": "Time", + "user": "User", + "eventType": "Event type", + "ipAddress": "IP address", + "client": "Client" } } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 3103d6c579..027058bbbf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14020,6 +14020,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +moment@^2.29.1: + version "2.29.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" + integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + moo@^0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" From 6b962577ba82e6df3ff29aa538bd527fc39413e9 Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Fri, 11 Dec 2020 15:48:39 +0100 Subject: [PATCH 2/3] added admin events tab --- src/events/AdminEvents.tsx | 147 +++++++++++++++++++++++++++++++++++ src/events/EventsSection.tsx | 106 ++++++++++++++++--------- src/events/messages.json | 13 +++- 3 files changed, 227 insertions(+), 39 deletions(-) create mode 100644 src/events/AdminEvents.tsx diff --git a/src/events/AdminEvents.tsx b/src/events/AdminEvents.tsx new file mode 100644 index 0000000000..457d90dd06 --- /dev/null +++ b/src/events/AdminEvents.tsx @@ -0,0 +1,147 @@ +import React, { ReactNode, useContext, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { + Button, + Modal, + ModalVariant, + ToolbarItem, +} from "@patternfly/react-core"; +import moment from "moment"; + +import { useAdminClient } from "../context/auth/AdminClient"; +import { DataList } from "../components/table-toolbar/DataList"; +import { RealmContext } from "../context/realm-context/RealmContext"; +import { + Table, + TableBody, + TableHeader, + TableVariant, +} from "@patternfly/react-table"; +import AdminEventRepresentation from "keycloak-admin/lib/defs/adminEventRepresentation"; +import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; + +type DisplayDialogProps = { + titleKey: string; + onClose: () => void; + children: ReactNode; +}; + +const DisplayDialog = ({ titleKey, onClose, children }: DisplayDialogProps) => { + const { t } = useTranslation("events"); + return ( + + {children} + + ); +}; + +export const AdminEvents = () => { + const { t } = useTranslation("events"); + const adminClient = useAdminClient(); + const { realm } = useContext(RealmContext); + + const [key, setKey] = useState(""); + const refresh = () => setKey(`${new Date().getTime()}`); + + const [authEvent, setAuthEvent] = useState(); + const [representationEvent, setRepresentationEvent] = useState< + AdminEventRepresentation + >(); + + const loader = async (first?: number, max?: number, search?: string) => { + const params = { + first: first!, + max: max!, + realm, + }; + if (search) { + console.log("how to search?", search); + } + return await adminClient.realms.findAdminEvents({ ...params }); + }; + + return ( + <> + {authEvent && ( + setAuthEvent(undefined)}> + + + +
+
+ )} + {representationEvent && ( + setRepresentationEvent(undefined)} + > + some json from the changed values + + )} + + + + + + } + actions={[ + { + title: t("auth"), + onRowClick: (event) => setAuthEvent(event), + }, + { + title: t("representation"), + onRowClick: (event) => setRepresentationEvent(event), + }, + ]} + columns={[ + { + name: "time", + displayKey: "events:time", + cellRenderer: (row) => moment(row.time).fromNow(), + }, + { + name: "resourcePath", + displayKey: "events:resourcePath", + }, + { + name: "resourceType", + displayKey: "events:resourceType", + }, + { + name: "operationType", + displayKey: "events:operationType", + }, + { + name: "", + displayKey: "events:user", + cellRenderer: (event) => event.authDetails?.userId, + }, + ]} + emptyState={ + + } + /> + + ); +}; diff --git a/src/events/EventsSection.tsx b/src/events/EventsSection.tsx index ef95f536e9..972a4ffcd5 100644 --- a/src/events/EventsSection.tsx +++ b/src/events/EventsSection.tsx @@ -4,6 +4,9 @@ import { Button, Label, PageSection, + Tab, + Tabs, + TabTitleText, ToolbarItem, } from "@patternfly/react-core"; import moment from "moment"; @@ -14,11 +17,15 @@ import { ViewHeader } from "../components/view-header/ViewHeader"; import { DataList } from "../components/table-toolbar/DataList"; import { RealmContext } from "../context/realm-context/RealmContext"; import { InfoCircleIcon } from "@patternfly/react-icons"; +import { AdminEvents } from "./AdminEvents"; +import { ListEmptyState } from "../components/list-empty-state/ListEmptyState"; export const EventsSection = () => { const { t } = useTranslation("events"); const adminClient = useAdminClient(); const { realm } = useContext(RealmContext); + + const [activeTab, setActiveTab] = useState(0); const [key, setKey] = useState(""); const refresh = () => setKey(`${new Date().getTime()}`); @@ -48,44 +55,67 @@ export const EventsSection = () => { <> - - - - - - } - columns={[ - { - name: "time", - displayKey: "events:time", - cellRenderer: (row) => moment(row.time).fromNow(), - }, - { - name: "userId", - displayKey: "events:user", - }, - { - name: "type", - displayKey: "events:eventType", - cellRenderer: StatusRow, - }, - { - name: "ipAddress", - displayKey: "events:ipAddress", - }, - { - name: "clientId", - displayKey: "events:client", - }, - ]} - /> + setActiveTab(key as number)} + isBox + > + {t("userEvents")}} + > + + + + + + } + columns={[ + { + name: "time", + displayKey: "events:time", + cellRenderer: (row) => moment(row.time).fromNow(), + }, + { + name: "userId", + displayKey: "events:user", + }, + { + name: "type", + displayKey: "events:eventType", + cellRenderer: StatusRow, + }, + { + name: "ipAddress", + displayKey: "events:ipAddress", + }, + { + name: "clientId", + displayKey: "events:client", + }, + ]} + emptyState={ + + } + /> + + {t("adminEvents")}} + > + + + ); diff --git a/src/events/messages.json b/src/events/messages.json index 3e551f0238..6e2d3ae11b 100644 --- a/src/events/messages.json +++ b/src/events/messages.json @@ -2,12 +2,23 @@ "events": { "title": "Events", "eventExplain": "If you want to configure user events, Admin events or Event listeners, please enter Event configs page realm settings to configure.", + "userEvents": "User events", + "adminEvents": "Admin events", "searchForEvent": "Search user event", "refresh": "Refresh", + "emptyEvents": "No events logged", + "emptyEventsInstructions": "Configure event logging in the realm settings", "time": "Time", "user": "User", "eventType": "Event type", "ipAddress": "IP address", - "client": "Client" + "client": "Client", + "resourcePath": "Resource path", + "resourceType": "Resource type", + "operationType": "Operation type", + "auth": "Auth", + "attribute": "Attribute", + "value": "Value", + "representation": "Representation" } } \ No newline at end of file From 78d65f934c40d6df9ffde93043327280f42d4ad5 Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Fri, 11 Dec 2020 18:25:54 +0100 Subject: [PATCH 3/3] fixed id --- src/events/AdminEvents.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/events/AdminEvents.tsx b/src/events/AdminEvents.tsx index 457d90dd06..b55d03ce5d 100644 --- a/src/events/AdminEvents.tsx +++ b/src/events/AdminEvents.tsx @@ -92,7 +92,7 @@ export const AdminEvents = () => { key={key} loader={loader} isPaginated - ariaLabelKey="events:title" + ariaLabelKey="events:adminEvents" searchPlaceholderKey="events:searchForEvent" toolbarItem={ <>