From fa2bb1b2ca17903c3d8de4d64e0d7a86c69fe3a2 Mon Sep 17 00:00:00 2001 From: Nelson Kopliku Date: Wed, 17 Jul 2024 13:35:16 +0200 Subject: [PATCH] wip --- .../ActivityLogOverview.jsx | 5 + assets/js/common/ActivityLogOverview/index.js | 3 + assets/js/lib/api/activityLogs.js | 3 + .../pages/ActivityLogPage/ActivityLogPage.jsx | 200 ++++++++++++++++++ assets/js/pages/ActivityLogPage/index.js | 3 + assets/js/pages/Layout/Layout.jsx | 6 + assets/js/trento.jsx | 5 + 7 files changed, 225 insertions(+) create mode 100644 assets/js/common/ActivityLogOverview/ActivityLogOverview.jsx create mode 100644 assets/js/common/ActivityLogOverview/index.js create mode 100644 assets/js/lib/api/activityLogs.js create mode 100644 assets/js/pages/ActivityLogPage/ActivityLogPage.jsx create mode 100644 assets/js/pages/ActivityLogPage/index.js diff --git a/assets/js/common/ActivityLogOverview/ActivityLogOverview.jsx b/assets/js/common/ActivityLogOverview/ActivityLogOverview.jsx new file mode 100644 index 0000000000..7453144560 --- /dev/null +++ b/assets/js/common/ActivityLogOverview/ActivityLogOverview.jsx @@ -0,0 +1,5 @@ +import React, { useState, useEffect } from 'react'; + +export default function ActivityLogOverview() { + return
ActivityLogOverview
; +} diff --git a/assets/js/common/ActivityLogOverview/index.js b/assets/js/common/ActivityLogOverview/index.js new file mode 100644 index 0000000000..9c66b43746 --- /dev/null +++ b/assets/js/common/ActivityLogOverview/index.js @@ -0,0 +1,3 @@ +import ActivityLogOverview from './ActivityLogOverview'; + +export default ActivityLogOverview; diff --git a/assets/js/lib/api/activityLogs.js b/assets/js/lib/api/activityLogs.js new file mode 100644 index 0000000000..8a69fb9135 --- /dev/null +++ b/assets/js/lib/api/activityLogs.js @@ -0,0 +1,3 @@ +import { networkClient } from '@lib/network'; + +export const getActivityLog = () => networkClient.get(`/activity_log`); diff --git a/assets/js/pages/ActivityLogPage/ActivityLogPage.jsx b/assets/js/pages/ActivityLogPage/ActivityLogPage.jsx new file mode 100644 index 0000000000..c201e4b467 --- /dev/null +++ b/assets/js/pages/ActivityLogPage/ActivityLogPage.jsx @@ -0,0 +1,200 @@ +import React, { useState, useEffect } from 'react'; + +import { logError } from '@lib/log'; + +import Table from '@common/Table'; +import { getActivityLog } from '../../lib/api/activityLogs'; +import ActivityLogOverview from '../../common/ActivityLogOverview/ActivityLogOverview'; +import { format } from 'date-fns'; + +// @type activity_type :: +// :login_attempt +// | :resource_tagging +// | :resource_untagging +// | :api_key_generation +// | :saving_suma_settings +// | :changing_suma_settings +// | :clearing_suma_settings +// | :user_creation +// | :user_modification +// | :user_deletion +// | :profile_update +// | :cluster_checks_execution_request + +const LOGIN_ATTEMPT = 'login_attempt'; +const RESOURCE_TAGGING = 'resource_tagging'; +const RESOURCE_UNTAGGING = 'resource_untagging'; +const API_KEY_GENERATION = 'api_key_generation'; +const SAVING_SUMA_SETTINGS = 'saving_suma_settings'; +const CHANGING_SUMA_SETTINGS = 'changing_suma_settings'; +const CLEARING_SUMA_SETTINGS = 'clearing_suma_settings'; +const USER_CREATION = 'user_creation'; +const USER_MODIFICATION = 'user_modification'; +const USER_DELETION = 'user_deletion'; +const PROFILE_UPDATE = 'profile_update'; +const CLUSTER_CHECKS_EXECUTION_REQUEST = 'cluster_checks_execution_request'; + +const taggingActivities = [RESOURCE_TAGGING, RESOURCE_UNTAGGING]; + +const activityTypes = [ + LOGIN_ATTEMPT, + ...taggingActivities, + API_KEY_GENERATION, + SAVING_SUMA_SETTINGS, + CHANGING_SUMA_SETTINGS, + CLEARING_SUMA_SETTINGS, + USER_CREATION, + USER_MODIFICATION, + USER_DELETION, + PROFILE_UPDATE, + CLUSTER_CHECKS_EXECUTION_REQUEST, +]; + +const activityTypesLabels = { + [LOGIN_ATTEMPT]: 'Login Attempt', + [RESOURCE_TAGGING]: 'Tag Added', + [RESOURCE_UNTAGGING]: 'Tag Removed', + [API_KEY_GENERATION]: 'API Key Generated', + [SAVING_SUMA_SETTINGS]: 'SUMA Settings Saved', + [CHANGING_SUMA_SETTINGS]: 'SUMA Settings Changed', + [CLEARING_SUMA_SETTINGS]: 'SUMA Settings Cleared', + [USER_CREATION]: 'User Created', + [USER_MODIFICATION]: 'User Modified', + [USER_DELETION]: 'User Deleted', + [PROFILE_UPDATE]: 'Profile Updated', + [CLUSTER_CHECKS_EXECUTION_REQUEST]: 'Checks Execution Requested', +}; + +const resourceTypes = ['host', 'cluster', 'database', 'sap_system']; + +const resourceTypesLabels = { + host: 'Host', + cluster: 'Cluster', + database: 'Database', + sap_system: 'SAP System', +}; + +const toResource = (activityLogEntry) => { + const { metadata, type } = activityLogEntry; + switch (type) { + case LOGIN_ATTEMPT: + return 'Application'; + case RESOURCE_TAGGING: + case RESOURCE_UNTAGGING: + return resourceTypesLabels[metadata.resource_type]; + case USER_CREATION: + case USER_MODIFICATION: + case USER_DELETION: + return 'User'; + case PROFILE_UPDATE: + return 'Profile'; + case SAVING_SUMA_SETTINGS: + case CHANGING_SUMA_SETTINGS: + case CLEARING_SUMA_SETTINGS: + return 'SUMA Settings'; + case API_KEY_GENERATION: + return 'API Key'; + case CLUSTER_CHECKS_EXECUTION_REQUEST: + return 'Cluster Checks'; + + default: + return 'AAA'; + } +}; + +const toMessage = (activityLogEntry) => { + const { metadata, type } = activityLogEntry; + + switch (type) { + case LOGIN_ATTEMPT: + return metadata?.reason ? 'Login failed' : 'User logged in'; + case RESOURCE_TAGGING: + return `Tag "${metadata.added_tag}" added to "${metadata.resource_id}"`; + case RESOURCE_UNTAGGING: + return `Tag "${metadata.removed_tag}" removed to "${metadata.resource_id}"`; + case USER_CREATION: + return 'User was created'; + + case USER_MODIFICATION: + return 'User was modified'; + + case USER_DELETION: + return 'User was deleted'; + case PROFILE_UPDATE: + return 'User modified profile'; + + case SAVING_SUMA_SETTINGS: + return 'SUMA Settings was saved'; + + case CHANGING_SUMA_SETTINGS: + return 'SUMA Settings was changed'; + + case CLEARING_SUMA_SETTINGS: + return 'SUMA Settings was cleared'; + + case API_KEY_GENERATION: + return 'API Key was generated'; + + case CLUSTER_CHECKS_EXECUTION_REQUEST: + return 'Checks execution requested for cluster'; + + default: + return 'AAA'; + } +}; + +export default function ActivityLogPage() { + const [activityLog, setActivityLog] = useState([]); + // const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + getActivityLog() + .then((response) => { + setActivityLog(response.data); + // setIsLoading(false); + }) + .catch((e) => logError(e)); + }, []); + + const config = { + pagination: true, + usePadding: false, + columns: [ + { + title: 'Time', + key: 'occurred_on', + render: (time) => format(time, 'yyyy-MM-dd HH:mm:ss'), + }, + { + title: 'Event Type', + key: 'type', + render: (type) => + activityTypes.includes(type) ? activityTypesLabels[type] : 'Unknown', + }, + { + title: 'Resource', + key: 'metadata', + render: (_, activityLogEntry) => toResource(activityLogEntry), + }, + { + title: 'User', + key: 'actor', + }, + { + title: 'Message', + key: 'metadata', + render: (_, activityLogEntry) => toMessage(activityLogEntry), + }, + ], + collapsibleDetailRenderer: (logEntry) => { + return
{JSON.stringify(logEntry, null, 2)}
; + }, + }; + + return ( + <> + + + + ); +} diff --git a/assets/js/pages/ActivityLogPage/index.js b/assets/js/pages/ActivityLogPage/index.js new file mode 100644 index 0000000000..896206b0e2 --- /dev/null +++ b/assets/js/pages/ActivityLogPage/index.js @@ -0,0 +1,3 @@ +import ActivityLogPage from './ActivityLogPage'; + +export default ActivityLogPage; diff --git a/assets/js/pages/Layout/Layout.jsx b/assets/js/pages/Layout/Layout.jsx index 7d5153433d..a2ba6bf4e7 100644 --- a/assets/js/pages/Layout/Layout.jsx +++ b/assets/js/pages/Layout/Layout.jsx @@ -18,6 +18,7 @@ import { EOS_KEYBOARD_DOUBLE_ARROW_LEFT, EOS_KEYBOARD_DOUBLE_ARROW_RIGHT, EOS_SUPERVISED_USER_CIRCLE_OUTLINED, + EOS_ASSIGNMENT, } from 'eos-icons-react'; import TrentoLogo from '@static/trento-logo-stacked.svg'; @@ -59,6 +60,11 @@ const navigation = [ icon: EOS_SUPERVISED_USER_CIRCLE_OUTLINED, permittedFor: ['all:users'], }, + { + name: 'Activity Log', + href: '/activity_log', + icon: EOS_ASSIGNMENT, + }, { name: 'Settings', href: '/settings', diff --git a/assets/js/trento.jsx b/assets/js/trento.jsx index 9189533692..4c21597476 100644 --- a/assets/js/trento.jsx +++ b/assets/js/trento.jsx @@ -40,6 +40,7 @@ import SettingsPage from '@pages/SettingsPage'; import SomethingWentWrong from '@pages/SomethingWentWrong'; import UsersPage, { CreateUserPage, EditUserPage } from '@pages/Users'; import ProfilePage from '@pages/Profile'; +import ActivityLogPage from '@pages/ActivityLogPage'; import { profile } from '@lib/auth'; import { networkClient } from '@lib/network'; @@ -113,6 +114,10 @@ const createRouter = ({ getUser }) => path="hosts/:hostID/patches/:advisoryID" element={} /> + } + />