From bc516521f37600b4bbf4b93dbd0d4ba3437f7b11 Mon Sep 17 00:00:00 2001 From: Paulo Amorim Date: Fri, 13 Dec 2024 10:57:00 -0300 Subject: [PATCH] feat(projectHistoryLogs): add action label and review all action items and texts TASK-1371 (#5354) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### πŸ“£ 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 --- .../components/activity/activity.constants.ts | 92 +++++++++---------- .../components/activity/activityLogs.query.ts | 20 ++-- .../activity/activityMessage.component.tsx | 13 ++- .../activity/formActivity.module.scss | 2 +- 4 files changed, 70 insertions(+), 57 deletions(-) diff --git a/jsapp/js/components/activity/activity.constants.ts b/jsapp/js/components/activity/activity.constants.ts index b59918ead5..87eb1b5422 100644 --- a/jsapp/js/components/activity/activity.constants.ts +++ b/jsapp/js/components/activity/activity.constants.ts @@ -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', @@ -32,21 +33,12 @@ 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; }; }; @@ -54,148 +46,154 @@ type AuditActionTypes = { 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##'; @@ -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; + }; }; } diff --git a/jsapp/js/components/activity/activityLogs.query.ts b/jsapp/js/components/activity/activityLogs.query.ts index 4ddfa6ee9a..1fa51b9fa4 100644 --- a/jsapp/js/components/activity/activityLogs.query.ts +++ b/jsapp/js/components/activity/activityLogs.query.ts @@ -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'; @@ -48,12 +52,14 @@ const getActivityLogs = async ({ * */ const getFilterOptions = async () => - (Object.keys(AuditActions) as Array).sort().map((value) => { - return { - label: AuditActions[value], - value, - }; - }); + (Object.keys(AuditActions) as Array) + .sort() + .map((value) => { + return { + label: AUDIT_ACTION_TYPES[value].label, + value, + }; + }); /** * Starts the exporting process of the activity logs. diff --git a/jsapp/js/components/activity/activityMessage.component.tsx b/jsapp/js/components/activity/activityMessage.component.tsx index d930d3c056..d084726cfb 100644 --- a/jsapp/js/components/activity/activityMessage.component.tsx +++ b/jsapp/js/components/activity/activityMessage.component.tsx @@ -16,9 +16,16 @@ export function ActivityMessage(props: {data: ActivityLogsItem}) { message = message .replace('##username##', `${props.data.username}`) .replace('##action##', props.data.action); - // We only replace it if metadata is provided. - if (props.data.metadata.second_user) { - message = message.replace('##username2##', `${props.data.metadata.second_user}`); + + // 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##', `${props.data.metadata.username}`); + } + if (props.data.metadata.permissions?.username) { + message = message.replace('##username2##', `${props.data.metadata.permissions.username}`); } return ( diff --git a/jsapp/js/components/activity/formActivity.module.scss b/jsapp/js/components/activity/formActivity.module.scss index e8d7cb1ae2..7e53c5f5f1 100644 --- a/jsapp/js/components/activity/formActivity.module.scss +++ b/jsapp/js/components/activity/formActivity.module.scss @@ -29,7 +29,7 @@ } .filterSelect { - width: 150px; + width: 280px; } .tableContainer {