From d6e722b7b33465d6fbcd4fe4e61d7cf247c12384 Mon Sep 17 00:00:00 2001 From: Jaanus Sellin Date: Wed, 6 Nov 2024 12:00:42 +0200 Subject: [PATCH] feat: activity chart polish (#8665) ![image](https://github.com/user-attachments/assets/a97f5745-1300-473e-80af-54f0cfc985e1) --- .../Project/ProjectStatus/ProjectActivity.tsx | 37 ++++++++++--------- src/lib/features/events/event-store.ts | 7 +++- .../project-status/project-status-service.ts | 2 +- src/lib/types/stores/event-store.ts | 4 +- src/test/fixtures/fake-event-store.ts | 4 +- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/frontend/src/component/project/Project/ProjectStatus/ProjectActivity.tsx b/frontend/src/component/project/Project/ProjectStatus/ProjectActivity.tsx index 5bbb6d5f476c..7bce045736bc 100644 --- a/frontend/src/component/project/Project/ProjectStatus/ProjectActivity.tsx +++ b/frontend/src/component/project/Project/ProjectStatus/ProjectActivity.tsx @@ -5,22 +5,25 @@ import type { ProjectActivitySchema } from '../../../../openapi'; import { styled, Tooltip } from '@mui/material'; const StyledContainer = styled('div')(({ theme }) => ({ - gap: theme.spacing(1), + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + alignItems: 'center', + gap: theme.spacing(2), })); +const TitleContainer = styled('h4')({ + margin: 0, + width: '100%', +}); + type Output = { date: string; count: number; level: number }; export function transformData(inputData: ProjectActivitySchema): Output[] { - const resultMap: Record = {}; - - // Step 1: Count the occurrences of each date - inputData.forEach((item) => { - const formattedDate = new Date(item.date).toISOString().split('T')[0]; - resultMap[formattedDate] = (resultMap[formattedDate] || 0) + 1; - }); + const countArray = inputData.map((item) => item.count); // Step 2: Get all counts, sort them, and find the cut-off values for percentiles - const counts = Object.values(resultMap).sort((a, b) => a - b); + const counts = Object.values(countArray).sort((a, b) => a - b); const percentile = (percent: number) => { const index = Math.floor((percent / 100) * counts.length); @@ -43,13 +46,13 @@ export function transformData(inputData: ProjectActivitySchema): Output[] { }; // Step 4: Convert the map back to an array and assign levels - return Object.entries(resultMap) - .map(([date, count]) => ({ + return inputData + .map(({ date, count }) => ({ date, count, level: calculateLevel(count), })) - .reverse(); // Optional: reverse the order if needed + .reverse(); } export const ProjectActivity = () => { @@ -64,10 +67,10 @@ export const ProjectActivity = () => { const levelledData = transformData(data.activityCountByDate); return ( - + <> {data.activityCountByDate.length > 0 ? ( - <> - Activity in project + + Activity in project { )} /> - + ) : ( No activity )} - + ); }; diff --git a/src/lib/features/events/event-store.ts b/src/lib/features/events/event-store.ts index 8b522f30bf8b..5be33de1bda5 100644 --- a/src/lib/features/events/event-store.ts +++ b/src/lib/features/events/event-store.ts @@ -409,7 +409,7 @@ class EventStore implements IEventStore { })); } - async getProjectEventActivity( + async getProjectRecentEventActivity( project: string, ): Promise { const result = await this.db('events') @@ -418,6 +418,11 @@ class EventStore implements IEventStore { ) .count('* AS count') .where('project', project) + .andWhere( + 'created_at', + '>=', + this.db.raw("NOW() - INTERVAL '1 year'"), + ) .groupBy(this.db.raw("TO_CHAR(created_at::date, 'YYYY-MM-DD')")) .orderBy('date', 'asc'); diff --git a/src/lib/features/project-status/project-status-service.ts b/src/lib/features/project-status/project-status-service.ts index 47352ca3e031..4603c6905f63 100644 --- a/src/lib/features/project-status/project-status-service.ts +++ b/src/lib/features/project-status/project-status-service.ts @@ -22,7 +22,7 @@ export class ProjectStatusService { ), }, activityCountByDate: - await this.eventStore.getProjectEventActivity(projectId), + await this.eventStore.getProjectRecentEventActivity(projectId), }; } } diff --git a/src/lib/types/stores/event-store.ts b/src/lib/types/stores/event-store.ts index aada71d1dea3..3cd13e255bfe 100644 --- a/src/lib/types/stores/event-store.ts +++ b/src/lib/types/stores/event-store.ts @@ -47,5 +47,7 @@ export interface IEventStore queryCount(operations: IQueryOperations[]): Promise; setCreatedByUserId(batchSize: number): Promise; getEventCreators(): Promise>; - getProjectEventActivity(project: string): Promise; + getProjectRecentEventActivity( + project: string, + ): Promise; } diff --git a/src/test/fixtures/fake-event-store.ts b/src/test/fixtures/fake-event-store.ts index ea4b63438bf4..db17fa148666 100644 --- a/src/test/fixtures/fake-event-store.ts +++ b/src/test/fixtures/fake-event-store.ts @@ -18,7 +18,9 @@ class FakeEventStore implements IEventStore { this.events = []; } - getProjectEventActivity(project: string): Promise { + getProjectRecentEventActivity( + project: string, + ): Promise { throw new Error('Method not implemented.'); }