feat(user-activity): enhance user activity logs with additional data and improved queries

- Added optional fields for project color, task status, and status color in IUserRecentTask and IUserTimeLoggedTask interfaces.
- Optimized SQL queries to include team filtering and additional data such as project color and task status.
- Updated frontend components to support new data fields and improved styling for better user experience.
- Enhanced dark mode detection and styling in task activity lists.
- Implemented refetching of data on tab change in the user activity feed.
This commit is contained in:
chamikaJ
2025-07-14 13:26:28 +05:30
parent 2a7019c64c
commit 61461bb776
11 changed files with 466 additions and 117 deletions

View File

@@ -16,6 +16,9 @@ interface IUserRecentTask {
project_name: string;
last_activity_at: string;
activity_count: number;
project_color?: string;
task_status?: string;
status_color?: string;
}
interface IUserTimeLoggedTask {
@@ -27,6 +30,11 @@ interface IUserTimeLoggedTask {
total_time_logged_string: string;
last_logged_at: string;
logged_by_timer: boolean;
project_color?: string;
task_status?: string;
status_color?: string;
log_entries_count?: number;
estimated_time?: number;
}
export default class UserActivityLogsController extends WorklenzControllerBase {
@@ -36,23 +44,30 @@ export default class UserActivityLogsController extends WorklenzControllerBase {
return res.status(401).send(new ServerResponse(false, null, "Unauthorized"));
}
const { id: userId } = req.user;
const { id: userId, team_id: teamId } = req.user;
const { offset = 0, limit = 10 } = req.query;
// Optimized query with better performance and team filtering
const q = `
SELECT tal.id, tal.task_id, t.name AS task_name, tal.project_id, p.name AS project_name,
tal.attribute_type, tal.log_type, tal.old_value, tal.new_value,
tal.prev_string, tal.next_string, tal.created_at AS last_activity_at,
(SELECT COUNT(*) FROM task_activity_logs WHERE task_id = tal.task_id AND user_id = $1) AS activity_count
SELECT DISTINCT tal.task_id, t.name AS task_name, tal.project_id, p.name AS project_name,
MAX(tal.created_at) AS last_activity_at,
COUNT(DISTINCT tal.id) AS activity_count,
p.color_code AS project_color,
(SELECT name FROM task_statuses WHERE id = t.status_id) AS task_status,
(SELECT color_code
FROM sys_task_status_categories
WHERE id = (SELECT category_id FROM task_statuses WHERE id = t.status_id)) AS status_color
FROM task_activity_logs tal
JOIN tasks t ON tal.task_id = t.id
JOIN projects p ON tal.project_id = p.id
WHERE tal.user_id = $1
ORDER BY tal.created_at DESC
LIMIT $2 OFFSET $3;
INNER JOIN tasks t ON tal.task_id = t.id AND t.archived = FALSE
INNER JOIN projects p ON tal.project_id = p.id AND p.team_id = $1
WHERE tal.user_id = $2
AND tal.created_at >= NOW() - INTERVAL '30 days'
GROUP BY tal.task_id, t.name, tal.project_id, p.name, p.color_code, t.status_id
ORDER BY MAX(tal.created_at) DESC
LIMIT $3 OFFSET $4;
`;
const result = await db.query(q, [userId, limit, offset]);
const result = await db.query(q, [teamId, userId, limit, offset]);
const tasks: IUserRecentTask[] = result.rows;
return res.status(200).send(new ServerResponse(true, tasks));
@@ -64,29 +79,38 @@ export default class UserActivityLogsController extends WorklenzControllerBase {
return res.status(401).send(new ServerResponse(false, null, "Unauthorized"));
}
const { id: userId } = req.user;
const { id: userId, team_id: teamId } = req.user;
const { offset = 0, limit = 10 } = req.query;
// Optimized query with better performance, team filtering, and useful additional data
const q = `
SELECT twl.task_id, t.name AS task_name, t.project_id, p.name AS project_name,
SUM(twl.time_spent) AS total_time_logged,
MAX(twl.created_at) AS last_logged_at,
MAX(twl.logged_by_timer) AS logged_by_timer
SUM(twl.time_spent) AS total_time_logged,
MAX(twl.created_at) AS last_logged_at,
MAX(twl.logged_by_timer::int)::boolean AS logged_by_timer,
p.color_code AS project_color,
(SELECT name FROM task_statuses WHERE id = t.status_id) AS task_status,
(SELECT color_code
FROM sys_task_status_categories
WHERE id = (SELECT category_id FROM task_statuses WHERE id = t.status_id)) AS status_color,
COUNT(DISTINCT twl.id) AS log_entries_count,
(t.total_minutes * 60) AS estimated_time
FROM task_work_log twl
JOIN tasks t ON twl.task_id = t.id
JOIN projects p ON t.project_id = p.id
WHERE twl.user_id = $1
GROUP BY twl.task_id, t.name, t.project_id, p.name
INNER JOIN tasks t ON twl.task_id = t.id AND t.archived = FALSE
INNER JOIN projects p ON t.project_id = p.id AND p.team_id = $1
WHERE twl.user_id = $2
AND twl.created_at >= NOW() - INTERVAL '90 days'
GROUP BY twl.task_id, t.name, t.project_id, p.name, p.color_code, t.status_id, t.total_minutes
HAVING SUM(twl.time_spent) > 0
ORDER BY MAX(twl.created_at) DESC
LIMIT $2 OFFSET $3;
LIMIT $3 OFFSET $4;
`;
const result = await db.query(q, [userId, limit, offset]);
const result = await db.query(q, [teamId, userId, limit, offset]);
const tasks: IUserTimeLoggedTask[] = result.rows.map(task => ({
...task,
total_time_logged_string: formatDuration(moment.duration(task.total_time_logged, "seconds")),
})
);
}));
return res.status(200).send(new ServerResponse(true, tasks));
}