Skip to content

Commit

Permalink
Activity log overview (#2769)
Browse files Browse the repository at this point in the history
* Add an ActivityLogOverview Components

* Add support for level in the model

* Add ActivityLogDetailModal component

* Adjust ActivityLogOverview component

* Fix prop usage

* Iconify log level

* Default to level info
  • Loading branch information
nelsonkopliku authored Jul 22, 2024
1 parent 85705da commit 8521b49
Show file tree
Hide file tree
Showing 10 changed files with 906 additions and 0 deletions.
140 changes: 140 additions & 0 deletions assets/js/common/ActivityLogDetailsModal/ActivityLogDetailModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import React from 'react';
import { noop } from 'lodash';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';

import Button from '@common/Button';
import Modal from '@common/Modal';
import ListView from '@common/ListView';

import {
API_KEY_GENERATION,
CHANGING_SUMA_SETTINGS,
CLEARING_SUMA_SETTINGS,
CLUSTER_CHECKS_EXECUTION_REQUEST,
LOGIN_ATTEMPT,
PROFILE_UPDATE,
RESOURCE_TAGGING,
RESOURCE_UNTAGGING,
SAVING_SUMA_SETTINGS,
USER_CREATION,
USER_DELETION,
USER_MODIFICATION,
} from '@lib/model/activityLog';
import classNames from 'classnames';

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 resourceTypesLabels = {
host: 'Host',
cluster: 'Cluster',
database: 'Database',
sap_system: 'SAP System',
};

const keys = ['id', 'type', 'resource', 'user', 'message', 'time', 'metadata'];

const keyToLabel = {
id: 'ID',
type: 'Activity Type',
resource: 'Resource',
user: 'User',
time: 'Created at',
message: 'Message',
metadata: 'Data',
};

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] ??
'Unable to determine 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 'Unrecognized resource';
}
};

const renderMetadata = (metadata) => (
<ReactMarkdown className="markdown text-sm" remarkPlugins={[remarkGfm]}>
{`\`\`\`json\n${JSON.stringify(metadata, null, 2)}\n\`\`\``}
</ReactMarkdown>
);

const renderType = (type) => activityTypesLabels[type] ?? type;

const renderResource = (entry) => (
<span aria-label="activity-log-resource">{toResource(entry)}</span>
);

const keyRenderers = {
metadata: renderMetadata,
type: renderType,
resource: renderResource,
};

function ActivityLogDetailModal({ open = false, entry, onClose = noop }) {
const data = keys.map((key) => ({
title: keyToLabel[key] || key,
content: key === 'resource' ? entry : entry[key],
render: keyRenderers[key] || undefined,
className: classNames('col-span-5', {
'text-gray-500': key !== 'metadata',
}),
}));

return (
<Modal
className="!w-3/4 !max-w-3xl"
title="Activity Details"
open={open}
onClose={onClose}
>
<ListView
titleClassName="col-span-2 text-gray-500"
className="text-sm"
orientation="horizontal"
data={data}
/>
<div className="flex flex-row w-24 space-x-2 mt-3">
<Button type="primary-white" className="w-1/2" onClick={onClose}>
Close
</Button>
</div>
</Modal>
);
}

export default ActivityLogDetailModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { action } from '@storybook/addon-actions';
import {
activityLogEntryFactory,
taggingMetadataFactory,
} from '@lib/test-utils/factories/activityLog';
import { RESOURCE_TAGGING } from '@lib/model/activityLog';
import { toRenderedEntry } from '@common/ActivityLogOverview/ActivityLogOverview';
import ActivityLogDetailModal from '.';

export default {
title: 'Components/ActivityLogDetailModal',
component: ActivityLogDetailModal,
argTypes: {
open: {
description: 'Whether the dialog is open or not',
control: {
type: 'boolean',
},
},
entry: {
description: 'An Avtivity Log entry.',
control: {
type: 'object',
},
},
onClose: {
description: 'Callback when the Cancel button is clicked',
control: { type: 'function' },
},
},
};

export const Default = {
args: {
open: false,
entry: toRenderedEntry(activityLogEntryFactory.build()),
onClose: action('cancel clicked'),
},
};

export const UnknwonActivityType = {
args: {
...Default.args,
entry: toRenderedEntry(activityLogEntryFactory.build({ type: 'foo_bar' })),
},
};

export const UnknwonResourceType = {
args: {
...Default.args,
entry: toRenderedEntry(
activityLogEntryFactory.build({
type: RESOURCE_TAGGING,
metadata: taggingMetadataFactory.build({ resource_type: 'foo_bar' }),
})
),
},
};
Loading

0 comments on commit 8521b49

Please sign in to comment.