Skip to content

Commit

Permalink
feat(projectHistoryLogs): add action label and review all action item…
Browse files Browse the repository at this point in the history
…s and texts TASK-1371 (#5354)

### 📣 Summary
This PR adds labels to all action items and display the new labels in
the filter selection.
Also, all the existing items and texts were reviewed and updated based
on [the actions
list](https://www.notion.so/kobotoolbox/Write-code-for-rendering-all-possible-activity-messages-in-the-UI-1287e515f65480868bbcdc19c085920f?pvs=4#1287e515f654808a83cce66d13abde6c)


### 📖 Description
- A new label property was added to all items in the
`AUDIT_ACTION_TYPES`
- This new property is now being used as the label for the filter
selection items
- The filter selection box was enlarged from 150px to 280px (initially
suggested new size was of 250px, but it was needed to make it even
larger to fit all the existing labels)
- All the items from `AuditActions` enum and all the texts from
`AUDIT_ACTION_TYPES` were reviewed and updated based on [the actions
list](https://www.notion.so/kobotoolbox/Write-code-for-rendering-all-possible-activity-messages-in-the-UI-1287e515f65480868bbcdc19c085920f?pvs=4#1287e515f654808a83cce66d13abde6c)
- Transferring a project and modifying permissions are special cases
where more than 1 username is used in the message. A fix for that with
the current metadata was added.

### 👀 Preview steps
1. ℹ️ have an account and a project
2. Have the activity logs feature flag on with:
`?ff_activityLogsEnabled=true`
3. Transfer a project to another user
4. Navigate to the project's Settings > Activity
5. 🟢 The transfer should be displayed in the activity log
6. 🟢 The destination username should be properly displayed
7. Change the access permission of an user
8. 🟢 The permission change should be displayed in the activity log
9. 🟢 The username who had the permission changes should be displayed in
the log
10. All other logged actions should be displayed in the list with the
proper text
  • Loading branch information
pauloamorimbr authored Dec 13, 2024
1 parent 3927d40 commit bc51652
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 57 deletions.
92 changes: 46 additions & 46 deletions jsapp/js/components/activity/activity.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum AuditActions {
'add-media' = 'add-media',
'allow-anonymous-submissions' = 'allow-anonymous-submissions',
'archive' = 'archive',
'clone-permissions' = 'clone-permissions',
'connect-project' = 'connect-project',
'delete-media' = 'delete-media',
'delete-service' = 'delete-service',
Expand All @@ -32,170 +33,167 @@ export enum AuditActions {
'update-name' = 'update-name',
'update-settings' = 'update-settings',
'update-qa' = 'update-qa',

// The keys below are not present in the BE code
// and may need to be removed or updated.
// See: /kpi/kobo/apps/audit_log/views.py
'update-form' = 'update-form',
'add-user' = 'add-user',
'remove-user' = 'remove-user',
'update-permission' = 'update-permission',
'make-public' = 'make-public',
'share-public' = 'share-public',
}

type AuditActionTypes = {
[P in AuditActions]: {
name: AuditActions;
label: string;
message: string;
};
};

export const AUDIT_ACTION_TYPES: AuditActionTypes = {
'add-media': {
name: AuditActions['add-media'],
label: t('add media attachment'),
message: t('##username## added a media attachment'),
},
'allow-anonymous-submissions': {
name: AuditActions['allow-anonymous-submissions'],
message: t('##username## allowed anonymous submissions'),
label: t('enable anonymous submissions'),
message: t('##username## enabled anonymous submissions'),
},
'archive': {
name: AuditActions['archive'],
label: t('archive project'),
message: t('##username## archived project'),
},
'clone-permissions': {
name: AuditActions['clone-permissions'],
label: t('clone permissions'),
message: t('##username## cloned permissions from another project'),
},
'connect-project': {
name: AuditActions['connect-project'],
label: t('connect project data'),
message: t('##username## connected project data with another project'),
},
'delete-media': {
name: AuditActions['delete-media'],
label: t('remove media attachment'),
message: t('##username## removed a media attachment'),
},
'delete-service': {
name: AuditActions['delete-service'],
label: t('delete a REST service'),
message: t('##username## deleted a REST service'),
},
'deploy': {
name: AuditActions['deploy'],
label: t('deploy project'),
message: t('##username## deployed project'),
},
'disable-sharing': {
name: AuditActions['disable-sharing'],
label: t('disable data sharing'),
message: t('##username## disabled data sharing'),
},
'disallow-anonymous-submissions': {
name: AuditActions['disallow-anonymous-submissions'],
label: t('disable anonymous submissions'),
message: t('##username## disallowed anonymous submissions'),
},
'disconnect-project': {
name: AuditActions['disconnect-project'],
label: t('disconnect project'),
message: t('##username## disconnected project from another project'),
},
'enable-sharing': {
name: AuditActions['enable-sharing'],
label: t('enable data sharing'),
message: t('##username## enabled data sharing'),
},
'export': {
name: AuditActions['export'],
label: t('export data'),
message: t('##username## exported data'),
},
'modify-imported-fields': {
name: AuditActions['modify-imported-fields'],
label: t('change imported fields'),
message: t('##username## changed imported fields from another project'),
},
'modify-service': {
name: AuditActions['modify-service'],
label: t('modify a REST service'),
message: t('##username## modified a REST service'),
},
'modify-sharing': {
name: AuditActions['modify-sharing'],
label: t('modify data sharing'),
message: t('##username## modified data sharing'),
},
'modify-user-permissions': {
name: AuditActions['modify-user-permissions'],
message: t('##username## modified user permissions'),
label: t('update permissions'),
message: t('##username## updated permissions of ##username2##'),
},
'redeploy': {
name: AuditActions['redeploy'],
label: t('redeploy project'),
message: t('##username## redeployed project'),
},
'register-service': {
name: AuditActions['register-service'],
label: t('register a new REST service'),
message: t('##username## registered a new REST service'),
},
'replace-form': {
name: AuditActions['replace-form'],
label: t('upload new form'),
message: t('##username## uploaded a new form'),
},
'share-data-publicly': {
name: AuditActions['share-data-publicly'],
label: t('share data publicly'),
message: t('##username## shared data publicly'),
},
'share-form-publicly': {
name: AuditActions['share-form-publicly'],
message: t('##username## shared form publicly'),
label: t('make project public'),
message: t('##username## made the project publicly accessible'),
},
'transfer': {
name: AuditActions['transfer'],
label: t('transfer project ownership'),
message: t('##username## transferred project ownership to ##username2##'),
},
'unarchive': {
name: AuditActions['unarchive'],
label: t('unarchive project'),
message: t('##username## unarchived project'),
},
'unshare-data-publicly': {
name: AuditActions['unshare-data-publicly'],
message: t('##username## unshared data publicly'),
label: t('disable sharing data publicly'),
message: t('##username## disabled sharing data publicly'),
},
'unshare-form-publicly': {
name: AuditActions['unshare-form-publicly'],
message: t('##username## unshared form publicly'),
label: t('disable making project public'),
message: t('##username## disabled making project publicly accessible'),
},
'update-content': {
name: AuditActions['update-content'],
message: t('##username## updated content'),
label: t('edit form'),
message: t('##username## edited the form in the form builder'),
},
'update-name': {
name: AuditActions['update-name'],
label: t('change name'),
message: t('##username## changed project name'),
},
'update-settings': {
name: AuditActions['update-settings'],
label: t('update settings'),
message: t('##username## updated project settings'),
},
'update-qa': {
name: AuditActions['update-qa'],
label: t('modify qualitative analysis questions'),
message: t('##username## modified qualitative analysis questions'),
},

// The keys below are not present in the BE code
// and may need to be removed or updated.
// See: /kpi/kobo/apps/audit_log/views.py
'update-form': {
name: AuditActions['update-form'],
message: t('##username## edited the form in the form builder'),
},
'add-user': {
name: AuditActions['add-user'],
message: t('##username## added ##username2## to project'),
},
'remove-user': {
name: AuditActions['remove-user'],
message: t('##username## removed ##username2## from project'),
},
'update-permission': {
name: AuditActions['update-permission'],
message: t('##username## updated permissions of ##username2##'),
},
'make-public': {
name: AuditActions['make-public'],
message: t('##username## made the project publicly accessible'),
},
'share-public': {
name: AuditActions['share-public'],
message: t('##username## shared data publicly'),
},
};

export const FALLBACK_MESSAGE = '##username## did action ##action##';
Expand Down Expand Up @@ -239,7 +237,9 @@ export interface ActivityLogsItem {
latest_deployed_version_id?: string;
latest_version_id?: string;
version_uid?: string;
second_user?: string;
// a lot of more optional metadata props…
username?: string;
permissions?: {
username: string;
};
};
}
20 changes: 13 additions & 7 deletions jsapp/js/components/activity/activityLogs.query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {keepPreviousData, useQuery} from '@tanstack/react-query';
import type {FailResponse, PaginatedResponse} from 'js/dataInterface';
import {AuditActions, type ActivityLogsItem} from './activity.constants';
import {
AUDIT_ACTION_TYPES,
AuditActions,
type ActivityLogsItem,
} from './activity.constants';
import {QueryKeys} from 'js/query/queryKeys';
import {fetchGet} from 'jsapp/js/api';
import {endpoints} from 'jsapp/js/api.endpoints';
Expand Down Expand Up @@ -48,12 +52,14 @@ const getActivityLogs = async ({
*
*/
const getFilterOptions = async () =>
(Object.keys(AuditActions) as Array<keyof typeof AuditActions>).sort().map((value) => {
return {
label: AuditActions[value],
value,
};
});
(Object.keys(AuditActions) as Array<keyof typeof AuditActions>)
.sort()
.map((value) => {
return {
label: AUDIT_ACTION_TYPES[value].label,
value,
};
});

/**
* Starts the exporting process of the activity logs.
Expand Down
13 changes: 10 additions & 3 deletions jsapp/js/components/activity/activityMessage.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,16 @@ export function ActivityMessage(props: {data: ActivityLogsItem}) {
message = message
.replace('##username##', `<strong>${props.data.username}</strong>`)
.replace('##action##', props.data.action);
// We only replace it if metadata is provided.
if (props.data.metadata.second_user) {
message = message.replace('##username2##', `<strong>${props.data.metadata.second_user}</strong>`);

// For some actions we need to replace extra placeholders
// We will only replace the placeholders if the data is present in the metadata
// If metadata is missing we leave the ##username2## placeholder on purpose
// so that it is clear that the data is missing
if (props.data.metadata.username) {
message = message.replace('##username2##', `<strong>${props.data.metadata.username}</strong>`);
}
if (props.data.metadata.permissions?.username) {
message = message.replace('##username2##', `<strong>${props.data.metadata.permissions.username}</strong>`);
}

return (
Expand Down
2 changes: 1 addition & 1 deletion jsapp/js/components/activity/formActivity.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
}

.filterSelect {
width: 150px;
width: 280px;
}

.tableContainer {
Expand Down

0 comments on commit bc51652

Please sign in to comment.