-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add an ActivityLogOverview Components
- Loading branch information
1 parent
0efc387
commit 0ae7510
Showing
6 changed files
with
430 additions
and
0 deletions.
There are no files selected for viewing
149 changes: 149 additions & 0 deletions
149
assets/js/common/ActivityLogOverview/ActivityLogOverview.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import React from 'react'; | ||
import { format } from 'date-fns'; | ||
import Table from '@common/Table'; | ||
|
||
import { | ||
ACTIVITY_TYPES, | ||
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'; | ||
|
||
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 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 'Unrecognized resource'; | ||
} | ||
}; | ||
|
||
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 from "${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 'Unrecognized activity'; | ||
} | ||
}; | ||
|
||
const activityLogTableConfig = { | ||
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) => ( | ||
<span aria-label="activity-log-type"> | ||
{ACTIVITY_TYPES.includes(type) | ||
? activityTypesLabels[type] | ||
: 'Unknown'} | ||
</span> | ||
), | ||
}, | ||
{ | ||
title: 'Resource', | ||
key: 'metadata', | ||
render: (_, activityLogEntry) => ( | ||
<span aria-label="activity-log-resource"> | ||
{toResource(activityLogEntry)} | ||
</span> | ||
), | ||
}, | ||
{ | ||
title: 'User', | ||
key: 'actor', | ||
}, | ||
{ | ||
title: 'Message', | ||
key: 'metadata', | ||
render: (_, activityLogEntry) => toMessage(activityLogEntry), | ||
}, | ||
], | ||
collapsibleDetailRenderer: ({ metadata }) => ( | ||
<pre>{JSON.stringify(metadata, null, 2)}</pre> | ||
), | ||
}; | ||
|
||
export default function ActivityLogOverview({ activityLog }) { | ||
return <Table config={activityLogTableConfig} data={activityLog} />; | ||
} |
27 changes: 27 additions & 0 deletions
27
assets/js/common/ActivityLogOverview/ActivityLogOverview.stories.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { activityLogEntryFactory } from '@lib/test-utils/factories/activityLog'; | ||
import ActivityLogOverview from './ActivityLogOverview'; | ||
|
||
export default { | ||
title: 'Components/ActivityLogOverview', | ||
component: ActivityLogOverview, | ||
argTypes: { | ||
activityLog: { | ||
description: 'List of the activity log entries', | ||
control: { | ||
type: 'array', | ||
}, | ||
}, | ||
}, | ||
}; | ||
|
||
export const Default = { | ||
args: { | ||
activityLog: activityLogEntryFactory.buildList(20), | ||
}, | ||
}; | ||
|
||
export const Empty = { | ||
args: { | ||
activityLog: [], | ||
}, | ||
}; |
178 changes: 178 additions & 0 deletions
178
assets/js/common/ActivityLogOverview/ActivityLogOverview.test.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
import React from 'react'; | ||
import { render, screen } from '@testing-library/react'; | ||
import { | ||
activityLogEntryFactory, | ||
taggingMetadataFactory, | ||
untaggingMetadataFactory, | ||
} from '@lib/test-utils/factories/activityLog'; | ||
import { | ||
LOGIN_ATTEMPT, | ||
RESOURCE_TAGGING, | ||
RESOURCE_UNTAGGING, | ||
API_KEY_GENERATION, | ||
CHANGING_SUMA_SETTINGS, | ||
CLEARING_SUMA_SETTINGS, | ||
SAVING_SUMA_SETTINGS, | ||
CLUSTER_CHECKS_EXECUTION_REQUEST, | ||
PROFILE_UPDATE, | ||
USER_CREATION, | ||
USER_DELETION, | ||
USER_MODIFICATION, | ||
} from '@lib/model/activityLog'; | ||
import '@testing-library/jest-dom'; | ||
|
||
import ActivityLogOverview from '.'; | ||
|
||
describe('Activity Log Overview', () => { | ||
it('should render an empty activity log', () => { | ||
render(<ActivityLogOverview activityLog={[]} />); | ||
|
||
expect(screen.getByText('No data available')).toBeVisible(); | ||
}); | ||
|
||
const scenarios = [ | ||
{ | ||
name: LOGIN_ATTEMPT, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'admin', | ||
type: LOGIN_ATTEMPT, | ||
}), | ||
expectedEventType: 'Login Attempt', | ||
expectedResource: 'Application', | ||
expectedUser: 'admin', | ||
}, | ||
{ | ||
name: RESOURCE_TAGGING, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'foo', | ||
type: RESOURCE_TAGGING, | ||
metadata: taggingMetadataFactory.build({ | ||
resource_type: 'host', | ||
}), | ||
}), | ||
expectedEventType: 'Tag Added', | ||
expectedResource: 'Host', | ||
expectedUser: 'foo', | ||
}, | ||
{ | ||
name: RESOURCE_UNTAGGING, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'bar', | ||
type: RESOURCE_UNTAGGING, | ||
metadata: untaggingMetadataFactory.build({ | ||
resource_type: 'cluster', | ||
}), | ||
}), | ||
expectedEventType: 'Tag Removed', | ||
expectedResource: 'Cluster', | ||
expectedUser: 'bar', | ||
}, | ||
{ | ||
name: API_KEY_GENERATION, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'baz', | ||
type: API_KEY_GENERATION, | ||
}), | ||
expectedEventType: 'API Key Generated', | ||
expectedResource: 'API Key', | ||
expectedUser: 'baz', | ||
}, | ||
{ | ||
name: SAVING_SUMA_SETTINGS, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'user-1', | ||
type: SAVING_SUMA_SETTINGS, | ||
}), | ||
expectedEventType: 'SUMA Settings Saved', | ||
expectedResource: 'SUMA Settings', | ||
expectedUser: 'user-1', | ||
}, | ||
{ | ||
name: CHANGING_SUMA_SETTINGS, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'user-2', | ||
type: CHANGING_SUMA_SETTINGS, | ||
}), | ||
expectedEventType: 'SUMA Settings Changed', | ||
expectedResource: 'SUMA Settings', | ||
expectedUser: 'user-2', | ||
}, | ||
{ | ||
name: CLEARING_SUMA_SETTINGS, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'user-3', | ||
type: CLEARING_SUMA_SETTINGS, | ||
}), | ||
expectedEventType: 'SUMA Settings Cleared', | ||
expectedResource: 'SUMA Settings', | ||
expectedUser: 'user-3', | ||
}, | ||
{ | ||
name: USER_CREATION, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'user-4', | ||
type: USER_CREATION, | ||
}), | ||
expectedEventType: 'User Created', | ||
expectedResource: 'User', | ||
expectedUser: 'user-4', | ||
}, | ||
{ | ||
name: USER_MODIFICATION, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'user-5', | ||
type: USER_MODIFICATION, | ||
}), | ||
expectedEventType: 'User Modified', | ||
expectedResource: 'User', | ||
expectedUser: 'user-5', | ||
}, | ||
{ | ||
name: USER_DELETION, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'user-6', | ||
type: USER_DELETION, | ||
}), | ||
expectedEventType: 'User Deleted', | ||
expectedResource: 'User', | ||
expectedUser: 'user-6', | ||
}, | ||
{ | ||
name: PROFILE_UPDATE, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'user-7', | ||
type: PROFILE_UPDATE, | ||
}), | ||
expectedEventType: 'Profile Updated', | ||
expectedResource: 'Profile', | ||
expectedUser: 'user-7', | ||
}, | ||
{ | ||
name: CLUSTER_CHECKS_EXECUTION_REQUEST, | ||
entry: activityLogEntryFactory.build({ | ||
actor: 'user-8', | ||
type: CLUSTER_CHECKS_EXECUTION_REQUEST, | ||
}), | ||
expectedEventType: 'Checks Execution Requested', | ||
expectedResource: 'Cluster Checks', | ||
expectedUser: 'user-8', | ||
}, | ||
]; | ||
|
||
it.each(scenarios)( | ||
'should render log entry for activity `$name`', | ||
({ entry, expectedEventType, expectedResource, expectedUser }) => { | ||
render(<ActivityLogOverview activityLog={[entry]} />); | ||
|
||
const eventType = screen.getByLabelText('activity-log-type'); | ||
expect(eventType).toBeVisible(); | ||
expect(eventType).toHaveTextContent(expectedEventType); | ||
|
||
const resource = screen.getByLabelText('activity-log-resource'); | ||
expect(resource).toBeVisible(); | ||
expect(resource).toHaveTextContent(expectedResource); | ||
|
||
expect(screen.getByText(expectedUser)).toBeVisible(); | ||
} | ||
); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import ActivityLogOverview from './ActivityLogOverview'; | ||
|
||
export default ActivityLogOverview; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
export const LOGIN_ATTEMPT = 'login_attempt'; | ||
export const RESOURCE_TAGGING = 'resource_tagging'; | ||
export const RESOURCE_UNTAGGING = 'resource_untagging'; | ||
export const API_KEY_GENERATION = 'api_key_generation'; | ||
export const SAVING_SUMA_SETTINGS = 'saving_suma_settings'; | ||
export const CHANGING_SUMA_SETTINGS = 'changing_suma_settings'; | ||
export const CLEARING_SUMA_SETTINGS = 'clearing_suma_settings'; | ||
export const USER_CREATION = 'user_creation'; | ||
export const USER_MODIFICATION = 'user_modification'; | ||
export const USER_DELETION = 'user_deletion'; | ||
export const PROFILE_UPDATE = 'profile_update'; | ||
export const CLUSTER_CHECKS_EXECUTION_REQUEST = | ||
'cluster_checks_execution_request'; | ||
|
||
export const ACTIVITY_TYPES = [ | ||
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, | ||
]; |
Oops, something went wrong.