From e462527103a2ce79dd8189f6a42fed406a550975 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Wed, 28 May 2025 14:42:26 +0530 Subject: [PATCH 01/19] chore: added code split for the analytics store --- web/ce/store/analytics-v2.store.ts | 12 ++++++++++++ web/core/hooks/store/use-analytics-v2.ts | 2 +- web/core/store/analytics-v2.store.ts | 6 +++--- web/core/store/root.store.ts | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 web/ce/store/analytics-v2.store.ts diff --git a/web/ce/store/analytics-v2.store.ts b/web/ce/store/analytics-v2.store.ts new file mode 100644 index 00000000000..3a02dc1311f --- /dev/null +++ b/web/ce/store/analytics-v2.store.ts @@ -0,0 +1,12 @@ +import { BaseAnalyticsStoreV2, IBaseAnalyticsStoreV2 } from "@/store/analytics-v2.store"; + +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface IAnalyticsStoreV2 extends IBaseAnalyticsStoreV2 { + //observables +} + +export class AnalyticsStoreV2 extends BaseAnalyticsStoreV2 { + constructor() { + super(); + } +} diff --git a/web/core/hooks/store/use-analytics-v2.ts b/web/core/hooks/store/use-analytics-v2.ts index c8c13ba6130..7b2d8f248fb 100644 --- a/web/core/hooks/store/use-analytics-v2.ts +++ b/web/core/hooks/store/use-analytics-v2.ts @@ -2,7 +2,7 @@ import { useContext } from "react"; // mobx store import { StoreContext } from "@/lib/store-context"; // types -import { IAnalyticsStoreV2 } from "@/store/analytics-v2.store"; +import { IAnalyticsStoreV2 } from "@/plane-web/store/analytics-v2.store"; export const useAnalyticsV2 = (): IAnalyticsStoreV2 => { const context = useContext(StoreContext); diff --git a/web/core/store/analytics-v2.store.ts b/web/core/store/analytics-v2.store.ts index 97582577ace..393616beed2 100644 --- a/web/core/store/analytics-v2.store.ts +++ b/web/core/store/analytics-v2.store.ts @@ -5,7 +5,7 @@ import { CoreRootStore } from "./root.store"; type DurationType = (typeof ANALYTICS_V2_DURATION_FILTER_OPTIONS)[number]["value"]; -export interface IAnalyticsStoreV2 { +export interface IBaseAnalyticsStoreV2 { //observables currentTab: TAnalyticsTabsV2Base; selectedProjects: string[]; @@ -25,7 +25,7 @@ export interface IAnalyticsStoreV2 { updateIsPeekView: (isPeekView: boolean) => void; } -export class AnalyticsStoreV2 implements IAnalyticsStoreV2 { +export abstract class BaseAnalyticsStoreV2 implements IBaseAnalyticsStoreV2 { //observables currentTab: TAnalyticsTabsV2Base = "overview"; selectedProjects: string[] = []; @@ -38,7 +38,7 @@ export class AnalyticsStoreV2 implements IAnalyticsStoreV2 { // observables currentTab: observable.ref, selectedDuration: observable.ref, - selectedProjects: observable.ref, + selectedProjects: observable, selectedCycle: observable.ref, selectedModule: observable.ref, isPeekView: observable.ref, diff --git a/web/core/store/root.store.ts b/web/core/store/root.store.ts index 2aef8d030c0..090f18f017d 100644 --- a/web/core/store/root.store.ts +++ b/web/core/store/root.store.ts @@ -2,11 +2,11 @@ import { enableStaticRendering } from "mobx-react"; // plane imports import { FALLBACK_LANGUAGE, LANGUAGE_STORAGE_KEY } from "@plane/i18n"; // plane web store +import { AnalyticsStoreV2, IAnalyticsStoreV2 } from "@/plane-web/store/analytics-v2.store"; import { CommandPaletteStore, ICommandPaletteStore } from "@/plane-web/store/command-palette.store"; import { RootStore } from "@/plane-web/store/root.store"; import { IStateStore, StateStore } from "@/plane-web/store/state.store"; // stores -import { IAnalyticsStoreV2, AnalyticsStoreV2 } from "./analytics-v2.store"; import { CycleStore, ICycleStore } from "./cycle.store"; import { CycleFilterStore, ICycleFilterStore } from "./cycle_filter.store"; import { DashboardStore, IDashboardStore } from "./dashboard.store"; From e4fb074797ab1186c3cb9efb528045e8add02601 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 29 May 2025 01:30:17 +0530 Subject: [PATCH 02/19] chore: done some refactor --- packages/constants/src/analytics-v2/common.ts | 101 ++++++++++++++--- .../i18n/src/locales/cs/translations.json | 11 +- .../i18n/src/locales/de/translations.json | 11 +- .../i18n/src/locales/en/translations.json | 15 +-- .../i18n/src/locales/es/translations.json | 11 +- .../i18n/src/locales/fr/translations.json | 11 +- .../i18n/src/locales/id/translations.json | 11 +- .../i18n/src/locales/it/translations.json | 11 +- .../i18n/src/locales/ja/translations.json | 11 +- .../i18n/src/locales/ko/translations.json | 11 +- .../i18n/src/locales/pl/translations.json | 11 +- .../i18n/src/locales/pt-BR/translations.json | 11 +- .../i18n/src/locales/ro/translations.json | 11 +- .../i18n/src/locales/ru/translations.json | 11 +- .../i18n/src/locales/sk/translations.json | 11 +- .../i18n/src/locales/tr-TR/translations.json | 11 +- .../i18n/src/locales/ua/translations.json | 11 +- .../i18n/src/locales/vi-VN/translations.json | 11 +- .../i18n/src/locales/zh-CN/translations.json | 11 +- .../i18n/src/locales/zh-TW/translations.json | 11 +- .../analytics-v2/total-insights.tsx | 103 ++++++++++-------- .../workspace/sidebar/projects-list-item.tsx | 7 +- web/core/store/analytics-v2.store.ts | 2 +- 23 files changed, 262 insertions(+), 164 deletions(-) diff --git a/packages/constants/src/analytics-v2/common.ts b/packages/constants/src/analytics-v2/common.ts index 6eab3ab2966..673cb628132 100644 --- a/packages/constants/src/analytics-v2/common.ts +++ b/packages/constants/src/analytics-v2/common.ts @@ -1,23 +1,96 @@ import { TAnalyticsTabsV2Base } from "@plane/types"; import { ChartXAxisProperty, ChartYAxisMetric } from "../chart"; -export const insightsFields: Record = { +export interface IInsightField { + key: string; + i18nKey: string; + i18nProps?: { + entity?: string; + entityPlural?: string; + [key: string]: any; + }; +} + +export const insightsFields: Record = { overview: [ - "total_users", - "total_admins", - "total_members", - "total_guests", - "total_projects", - "total_work_items", - "total_cycles", - "total_intake", + { + key: "total_users", + i18nKey: "workspace_analytics.total", + i18nProps: { + entity: "Users", + }, + }, + { + key: "total_admins", + i18nKey: "workspace_analytics.total", + i18nProps: { + entity: "Admins", + }, + }, + { + key: "total_members", + i18nKey: "workspace_analytics.total", + i18nProps: { + entity: "Members", + }, + }, + { + key: "total_guests", + i18nKey: "workspace_analytics.total", + i18nProps: { + entity: "Guests", + }, + }, + { + key: "total_projects", + i18nKey: "workspace_analytics.total", + i18nProps: { + entity: "Projects", + }, + }, + { + key: "total_work_items", + i18nKey: "workspace_analytics.total", + i18nProps: { + entity: "work items", + }, + }, + { + key: "total_cycles", + i18nKey: "workspace_analytics.total", + i18nProps: { + entity: "Cycles", + }, + }, + { + key: "total_intake", + i18nKey: "workspace_analytics.total", + i18nProps: { + entity: "Intake", + }, + }, ], "work-items": [ - "total_work_items", - "started_work_items", - "backlog_work_items", - "un_started_work_items", - "completed_work_items", + { + key: "total_work_items", + i18nKey: "workspace_analytics.total", + }, + { + key: "started_work_items", + i18nKey: "workspace_analytics.started_work_items", + }, + { + key: "backlog_work_items", + i18nKey: "workspace_analytics.backlog_work_items", + }, + { + key: "un_started_work_items", + i18nKey: "workspace_analytics.un_started_work_items", + }, + { + key: "completed_work_items", + i18nKey: "workspace_analytics.completed_work_items", + }, ], }; diff --git a/packages/i18n/src/locales/cs/translations.json b/packages/i18n/src/locales/cs/translations.json index 28109cd9d26..894a544f6b6 100644 --- a/packages/i18n/src/locales/cs/translations.json +++ b/packages/i18n/src/locales/cs/translations.json @@ -1341,21 +1341,22 @@ }, "created_vs_resolved": "Vytvořeno vs Vyřešeno", "customized_insights": "Přizpůsobené přehledy", - "backlog_work_items": "Pracovní položky v backlogu", + "backlog_work_items": "Backlog {entity}", "active_projects": "Aktivní projekty", "trend_on_charts": "Trend na grafech", "all_projects": "Všechny projekty", "summary_of_projects": "Souhrn projektů", "project_insights": "Přehled projektu", - "started_work_items": "Zahájené pracovní položky", - "total_work_items": "Celkový počet pracovních položek", + "started_work_items": "Zahájené {entity}", + "total_work_items": "Celkový počet {entity}", "total_projects": "Celkový počet projektů", "total_admins": "Celkový počet administrátorů", "total_users": "Celkový počet uživatelů", "total_intake": "Celkový příjem", - "un_started_work_items": "Nezahájené pracovní položky", + "un_started_work_items": "Nezahájené {entity}", "total_guests": "Celkový počet hostů", - "completed_work_items": "Dokončené pracovní položky" + "completed_work_items": "Dokončené {entity}", + "total": "Celkový počet {entity}" }, "workspace_projects": { "label": "{count, plural, one {Projekt} few {Projekty} other {Projektů}}", diff --git a/packages/i18n/src/locales/de/translations.json b/packages/i18n/src/locales/de/translations.json index 1cc37072872..4533a118bd0 100644 --- a/packages/i18n/src/locales/de/translations.json +++ b/packages/i18n/src/locales/de/translations.json @@ -1341,21 +1341,22 @@ }, "created_vs_resolved": "Erstellt vs Gelöst", "customized_insights": "Individuelle Einblicke", - "backlog_work_items": "Backlog-Arbeitselemente", + "backlog_work_items": "Backlog-{entity}", "active_projects": "Aktive Projekte", "trend_on_charts": "Trend in Diagrammen", "all_projects": "Alle Projekte", "summary_of_projects": "Projektübersicht", "project_insights": "Projekteinblicke", - "started_work_items": "Begonnene Arbeitselemente", - "total_work_items": "Gesamte Arbeitselemente", + "started_work_items": "Begonnene {entity}", + "total_work_items": "Gesamte {entity}", "total_projects": "Gesamtprojekte", "total_admins": "Gesamtanzahl der Admins", "total_users": "Gesamtanzahl der Benutzer", "total_intake": "Gesamteinnahmen", - "un_started_work_items": "Nicht begonnene Arbeitselemente", + "un_started_work_items": "Nicht begonnene {entity}", "total_guests": "Gesamtanzahl der Gäste", - "completed_work_items": "Abgeschlossene Arbeitselemente" + "completed_work_items": "Abgeschlossene {entity}", + "total": "Gesamte {entity}" }, "workspace_projects": { "label": "{count, plural, one {Projekt} few {Projekte} other {Projekte}}", diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index ead40fd1e53..54f9540411d 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -1161,16 +1161,11 @@ } } }, - "total_work_items": "Total work items", - "started_work_items": "Started work items", - "backlog_work_items": "Backlog work items", - "un_started_work_items": "Unstarted work items", - "completed_work_items": "Completed work items", - "total_guests": "Total Guests", - "total_intake": "Total Intake", - "total_users": "Total Users", - "total_admins": "Total Admins", - "total_projects": "Total Projects", + "total": "Total {entity}", + "started_work_items": "Started {entity}", + "backlog_work_items": "Backlog {entity}", + "un_started_work_items": "Unstarted {entity}", + "completed_work_items": "Completed {entity}", "project_insights": "Project Insights", "summary_of_projects": "Summary of Projects", "all_projects": "All Projects", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 94f1819a48d..963ab0d5333 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -1344,21 +1344,22 @@ }, "created_vs_resolved": "Creado vs Resuelto", "customized_insights": "Información personalizada", - "backlog_work_items": "Elementos de trabajo en backlog", + "backlog_work_items": "{entity} en backlog", "active_projects": "Proyectos activos", "trend_on_charts": "Tendencia en gráficos", "all_projects": "Todos los proyectos", "summary_of_projects": "Resumen de proyectos", "project_insights": "Información del proyecto", - "started_work_items": "Elementos de trabajo iniciados", - "total_work_items": "Total de elementos de trabajo", + "started_work_items": "{entity} iniciados", + "total_work_items": "Total de {entity}", "total_projects": "Total de proyectos", "total_admins": "Total de administradores", "total_users": "Total de usuarios", "total_intake": "Ingreso total", - "un_started_work_items": "Elementos de trabajo no iniciados", + "un_started_work_items": "{entity} no iniciados", "total_guests": "Total de invitados", - "completed_work_items": "Elementos de trabajo completados" + "completed_work_items": "{entity} completados", + "total": "Total de {entity}" }, "workspace_projects": { "label": "{count, plural, one {Proyecto} other {Proyectos}}", diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 4f356f1491e..b793a905227 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -1342,21 +1342,22 @@ }, "created_vs_resolved": "Créé vs Résolu", "customized_insights": "Informations personnalisées", - "backlog_work_items": "Éléments de travail en backlog", + "backlog_work_items": "{entity} en backlog", "active_projects": "Projets actifs", "trend_on_charts": "Tendance sur les graphiques", "all_projects": "Tous les projets", "summary_of_projects": "Résumé des projets", "project_insights": "Aperçus du projet", - "started_work_items": "Éléments de travail commencés", - "total_work_items": "Total des éléments de travail", + "started_work_items": "{entity} commencés", + "total_work_items": "Total des {entity}", "total_projects": "Total des projets", "total_admins": "Total des administrateurs", "total_users": "Nombre total d'utilisateurs", "total_intake": "Revenu total", - "un_started_work_items": "Éléments de travail non commencés", + "un_started_work_items": "{entity} non commencés", "total_guests": "Nombre total d'invités", - "completed_work_items": "Éléments de travail terminés" + "completed_work_items": "{entity} terminés", + "total": "Total des {entity}" }, "workspace_projects": { "label": "{count, plural, one {Projet} other {Projets}}", diff --git a/packages/i18n/src/locales/id/translations.json b/packages/i18n/src/locales/id/translations.json index 20b683c65fe..8d84ca58976 100644 --- a/packages/i18n/src/locales/id/translations.json +++ b/packages/i18n/src/locales/id/translations.json @@ -1341,21 +1341,22 @@ }, "created_vs_resolved": "Dibuat vs Diselesaikan", "customized_insights": "Wawasan yang Disesuaikan", - "backlog_work_items": "Item pekerjaan backlog", + "backlog_work_items": "{entity} backlog", "active_projects": "Proyek Aktif", "trend_on_charts": "Tren pada grafik", "all_projects": "Semua Proyek", "summary_of_projects": "Ringkasan Proyek", "project_insights": "Wawasan Proyek", - "started_work_items": "Item pekerjaan yang telah dimulai", - "total_work_items": "Total item pekerjaan", + "started_work_items": "{entity} yang telah dimulai", + "total_work_items": "Total {entity}", "total_projects": "Total Proyek", "total_admins": "Total Admin", "total_users": "Total Pengguna", "total_intake": "Total Pemasukan", - "un_started_work_items": "Item pekerjaan yang belum dimulai", + "un_started_work_items": "{entity} yang belum dimulai", "total_guests": "Total Tamu", - "completed_work_items": "Item pekerjaan yang telah selesai" + "completed_work_items": "{entity} yang telah selesai", + "total": "Total {entity}" }, "workspace_projects": { "label": "{count, plural, one {Proyek} other {Proyek}}", diff --git a/packages/i18n/src/locales/it/translations.json b/packages/i18n/src/locales/it/translations.json index 5534d885c10..b9af24add6e 100644 --- a/packages/i18n/src/locales/it/translations.json +++ b/packages/i18n/src/locales/it/translations.json @@ -1340,21 +1340,22 @@ }, "created_vs_resolved": "Creato vs Risolto", "customized_insights": "Approfondimenti personalizzati", - "backlog_work_items": "Elementi di lavoro nel backlog", + "backlog_work_items": "{entity} nel backlog", "active_projects": "Progetti attivi", "trend_on_charts": "Tendenza nei grafici", "all_projects": "Tutti i progetti", "summary_of_projects": "Riepilogo dei progetti", "project_insights": "Approfondimenti sul progetto", - "started_work_items": "Elementi di lavoro iniziati", - "total_work_items": "Totale elementi di lavoro", + "started_work_items": "{entity} iniziati", + "total_work_items": "Totale {entity}", "total_projects": "Progetti totali", "total_admins": "Totale amministratori", "total_users": "Totale utenti", "total_intake": "Entrate totali", - "un_started_work_items": "Elementi di lavoro non avviati", + "un_started_work_items": "{entity} non avviati", "total_guests": "Totale ospiti", - "completed_work_items": "Elementi di lavoro completati" + "completed_work_items": "{entity} completati", + "total": "Totale {entity}" }, "workspace_projects": { "label": "{count, plural, one {Progetto} other {Progetti}}", diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index a6f36a65b5f..f6321b4a5a2 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -1342,21 +1342,22 @@ }, "created_vs_resolved": "作成 vs 解決", "customized_insights": "カスタマイズされたインサイト", - "backlog_work_items": "バックログの作業項目", + "backlog_work_items": "バックログの{entity}", "active_projects": "アクティブなプロジェクト", "trend_on_charts": "グラフの傾向", "all_projects": "すべてのプロジェクト", "summary_of_projects": "プロジェクトの概要", "project_insights": "プロジェクトのインサイト", - "started_work_items": "開始された作業項目", - "total_work_items": "作業項目の合計", + "started_work_items": "開始された{entity}", + "total_work_items": "{entity}の合計", "total_projects": "プロジェクト合計", "total_admins": "管理者の合計", "total_users": "ユーザー総数", "total_intake": "総収入", - "un_started_work_items": "未開始の作業項目", + "un_started_work_items": "未開始の{entity}", "total_guests": "ゲストの合計", - "completed_work_items": "完了した作業項目" + "completed_work_items": "完了した{entity}", + "total": "{entity}の合計" }, "workspace_projects": { "label": "{count, plural, one {プロジェクト} other {プロジェクト}}", diff --git a/packages/i18n/src/locales/ko/translations.json b/packages/i18n/src/locales/ko/translations.json index 2858d729cb4..1d82a91d512 100644 --- a/packages/i18n/src/locales/ko/translations.json +++ b/packages/i18n/src/locales/ko/translations.json @@ -1343,21 +1343,22 @@ }, "created_vs_resolved": "생성됨 vs 해결됨", "customized_insights": "맞춤형 인사이트", - "backlog_work_items": "백로그 작업 항목", + "backlog_work_items": "백로그 {entity}", "active_projects": "활성 프로젝트", "trend_on_charts": "차트의 추세", "all_projects": "모든 프로젝트", "summary_of_projects": "프로젝트 요약", "project_insights": "프로젝트 인사이트", - "started_work_items": "시작된 작업 항목", - "total_work_items": "총 작업 항목", + "started_work_items": "시작된 {entity}", + "total_work_items": "총 {entity}", "total_projects": "총 프로젝트 수", "total_admins": "총 관리자 수", "total_users": "총 사용자 수", "total_intake": "총 수입", - "un_started_work_items": "시작되지 않은 작업 항목", + "un_started_work_items": "시작되지 않은 {entity}", "total_guests": "총 게스트 수", - "completed_work_items": "완료된 작업 항목" + "completed_work_items": "완료된 {entity}", + "total": "총 {entity}" }, "workspace_projects": { "label": "{count, plural, one {프로젝트} other {프로젝트}}", diff --git a/packages/i18n/src/locales/pl/translations.json b/packages/i18n/src/locales/pl/translations.json index d11005833fd..7ffca2379cf 100644 --- a/packages/i18n/src/locales/pl/translations.json +++ b/packages/i18n/src/locales/pl/translations.json @@ -1343,21 +1343,22 @@ }, "created_vs_resolved": "Utworzone vs Rozwiązane", "customized_insights": "Dostosowane informacje", - "backlog_work_items": "Elementy pracy w backlogu", + "backlog_work_items": "{entity} w backlogu", "active_projects": "Aktywne projekty", "trend_on_charts": "Trend na wykresach", "all_projects": "Wszystkie projekty", "summary_of_projects": "Podsumowanie projektów", "project_insights": "Wgląd w projekt", - "started_work_items": "Rozpoczęte elementy pracy", - "total_work_items": "Łączna liczba elementów pracy", + "started_work_items": "Rozpoczęte {entity}", + "total_work_items": "Łączna liczba {entity}", "total_projects": "Łączna liczba projektów", "total_admins": "Łączna liczba administratorów", "total_users": "Łączna liczba użytkowników", "total_intake": "Całkowity dochód", - "un_started_work_items": "Nierozpoczęte elementy pracy", + "un_started_work_items": "Nierozpoczęte {entity}", "total_guests": "Łączna liczba gości", - "completed_work_items": "Ukończone elementy pracy" + "completed_work_items": "Ukończone {entity}", + "total": "Łączna liczba {entity}" }, "workspace_projects": { "label": "{count, plural, one {Projekt} few {Projekty} other {Projektów}}", diff --git a/packages/i18n/src/locales/pt-BR/translations.json b/packages/i18n/src/locales/pt-BR/translations.json index de630da9745..274238d56cc 100644 --- a/packages/i18n/src/locales/pt-BR/translations.json +++ b/packages/i18n/src/locales/pt-BR/translations.json @@ -1343,21 +1343,22 @@ }, "created_vs_resolved": "Criado vs Resolvido", "customized_insights": "Insights personalizados", - "backlog_work_items": "Itens de trabalho no backlog", + "backlog_work_items": "{entity} no backlog", "active_projects": "Projetos ativos", "trend_on_charts": "Tendência nos gráficos", "all_projects": "Todos os projetos", "summary_of_projects": "Resumo dos projetos", "project_insights": "Insights do projeto", - "started_work_items": "Itens de trabalho iniciados", - "total_work_items": "Total de itens de trabalho", + "started_work_items": "{entity} iniciados", + "total_work_items": "Total de {entity}", "total_projects": "Total de projetos", "total_admins": "Total de administradores", "total_users": "Total de usuários", "total_intake": "Receita total", - "un_started_work_items": "Itens de trabalho não iniciados", + "un_started_work_items": "{entity} não iniciados", "total_guests": "Total de convidados", - "completed_work_items": "Itens de trabalho concluídos" + "completed_work_items": "{entity} concluídos", + "total": "Total de {entity}" }, "workspace_projects": { "label": "{count, plural, one {Projeto} other {Projetos}}", diff --git a/packages/i18n/src/locales/ro/translations.json b/packages/i18n/src/locales/ro/translations.json index f60a4881b55..9b0f840c889 100644 --- a/packages/i18n/src/locales/ro/translations.json +++ b/packages/i18n/src/locales/ro/translations.json @@ -1341,21 +1341,22 @@ }, "created_vs_resolved": "Creat vs Rezolvat", "customized_insights": "Perspective personalizate", - "backlog_work_items": "Elemente de lucru din backlog", + "backlog_work_items": "{entity} din backlog", "active_projects": "Proiecte active", "trend_on_charts": "Tendință în grafice", "all_projects": "Toate proiectele", "summary_of_projects": "Sumarul proiectelor", "project_insights": "Informații despre proiect", - "started_work_items": "Elemente de lucru începute", - "total_work_items": "Totalul elementelor de lucru", + "started_work_items": "{entity} începute", + "total_work_items": "Totalul {entity}", "total_projects": "Total proiecte", "total_admins": "Total administratori", "total_users": "Total utilizatori", "total_intake": "Venit total", - "un_started_work_items": "Elemente de lucru neîncepute", + "un_started_work_items": "{entity} neîncepute", "total_guests": "Total invitați", - "completed_work_items": "Elemente de lucru finalizate" + "completed_work_items": "{entity} finalizate", + "total": "Totalul {entity}" }, "workspace_projects": { "label": "{count, plural, one {Proiect} other {Proiecte}}", diff --git a/packages/i18n/src/locales/ru/translations.json b/packages/i18n/src/locales/ru/translations.json index 564716529d2..f3a65fbcd4f 100644 --- a/packages/i18n/src/locales/ru/translations.json +++ b/packages/i18n/src/locales/ru/translations.json @@ -1343,21 +1343,22 @@ }, "created_vs_resolved": "Создано vs Решено", "customized_insights": "Индивидуальные аналитические данные", - "backlog_work_items": "Элементы работы в бэклоге", + "backlog_work_items": "{entity} в бэклоге", "active_projects": "Активные проекты", "trend_on_charts": "Тренд на графиках", "all_projects": "Все проекты", "summary_of_projects": "Сводка по проектам", "project_insights": "Аналитика проекта", - "started_work_items": "Начатые рабочие элементы", - "total_work_items": "Общее количество рабочих элементов", + "started_work_items": "Начатые {entity}", + "total_work_items": "Общее количество {entity}", "total_projects": "Всего проектов", "total_admins": "Всего администраторов", "total_users": "Всего пользователей", "total_intake": "Общий доход", - "un_started_work_items": "Не начатые рабочие элементы", + "un_started_work_items": "Не начатые {entity}", "total_guests": "Всего гостей", - "completed_work_items": "Завершённые рабочие элементы" + "completed_work_items": "Завершённые {entity}", + "total": "Общее количество {entity}" }, "workspace_projects": { "label": "{count, plural, one {Проект} other {Проекты}}", diff --git a/packages/i18n/src/locales/sk/translations.json b/packages/i18n/src/locales/sk/translations.json index 60f2c21ca86..12962ba62bd 100644 --- a/packages/i18n/src/locales/sk/translations.json +++ b/packages/i18n/src/locales/sk/translations.json @@ -1343,21 +1343,22 @@ }, "created_vs_resolved": "Vytvorené vs Vyriešené", "customized_insights": "Prispôsobené prehľady", - "backlog_work_items": "Pracovné položky v backlogu", + "backlog_work_items": "{entity} v backlogu", "active_projects": "Aktívne projekty", "trend_on_charts": "Trend na grafoch", "all_projects": "Všetky projekty", "summary_of_projects": "Súhrn projektov", "project_insights": "Prehľad projektu", - "started_work_items": "Spustené pracovné položky", - "total_work_items": "Celkový počet pracovných položiek", + "started_work_items": "Spustené {entity}", + "total_work_items": "Celkový počet {entity}", "total_projects": "Celkový počet projektov", "total_admins": "Celkový počet administrátorov", "total_users": "Celkový počet používateľov", "total_intake": "Celkový príjem", - "un_started_work_items": "Nespustené pracovné položky", + "un_started_work_items": "Nespustené {entity}", "total_guests": "Celkový počet hostí", - "completed_work_items": "Dokončené pracovné položky" + "completed_work_items": "Dokončené {entity}", + "total": "Celkový počet {entity}" }, "workspace_projects": { "label": "{count, plural, one {Projekt} few {Projekty} other {Projektov}}", diff --git a/packages/i18n/src/locales/tr-TR/translations.json b/packages/i18n/src/locales/tr-TR/translations.json index cec11a99217..718d142c66e 100644 --- a/packages/i18n/src/locales/tr-TR/translations.json +++ b/packages/i18n/src/locales/tr-TR/translations.json @@ -1344,21 +1344,22 @@ }, "created_vs_resolved": "Oluşturulan vs Çözülen", "customized_insights": "Özelleştirilmiş İçgörüler", - "backlog_work_items": "Backlog iş öğeleri", + "backlog_work_items": "Backlog {entity}", "active_projects": "Aktif Projeler", "trend_on_charts": "Grafiklerdeki eğilim", "all_projects": "Tüm Projeler", "summary_of_projects": "Projelerin Özeti", "project_insights": "Proje İçgörüleri", - "started_work_items": "Başlatılan iş öğeleri", - "total_work_items": "Toplam iş öğesi", + "started_work_items": "Başlatılan {entity}", + "total_work_items": "Toplam {entity}", "total_projects": "Toplam Proje", "total_admins": "Toplam Yönetici", "total_users": "Toplam Kullanıcı", "total_intake": "Toplam Gelir", - "un_started_work_items": "Başlanmamış iş öğeleri", + "un_started_work_items": "Başlanmamış {entity}", "total_guests": "Toplam Misafir", - "completed_work_items": "Tamamlanmış iş öğeleri" + "completed_work_items": "Tamamlanmış {entity}", + "total": "Toplam {entity}" }, "workspace_projects": { "label": "{count, plural, one {Proje} other {Projeler}}", diff --git a/packages/i18n/src/locales/ua/translations.json b/packages/i18n/src/locales/ua/translations.json index 2a82df68f5e..659ef7fe1cf 100644 --- a/packages/i18n/src/locales/ua/translations.json +++ b/packages/i18n/src/locales/ua/translations.json @@ -1343,21 +1343,22 @@ }, "created_vs_resolved": "Створено vs Вирішено", "customized_insights": "Персоналізовані аналітичні дані", - "backlog_work_items": "Робочі елементи у беклозі", + "backlog_work_items": "{entity} у беклозі", "active_projects": "Активні проєкти", "trend_on_charts": "Тенденція на графіках", "all_projects": "Усі проєкти", "summary_of_projects": "Зведення проєктів", "project_insights": "Аналітика проєкту", - "started_work_items": "Розпочаті робочі елементи", - "total_work_items": "Усього робочих елементів", + "started_work_items": "Розпочаті {entity}", + "total_work_items": "Усього {entity}", "total_projects": "Усього проєктів", "total_admins": "Усього адміністраторів", "total_users": "Усього користувачів", "total_intake": "Загальний дохід", - "un_started_work_items": "Нерозпочаті робочі елементи", + "un_started_work_items": "Нерозпочаті {entity}", "total_guests": "Усього гостей", - "completed_work_items": "Завершені робочі елементи" + "completed_work_items": "Завершені {entity}", + "total": "Усього {entity}" }, "workspace_projects": { "label": "{count, plural, one {Проєкт} few {Проєкти} other {Проєктів}}", diff --git a/packages/i18n/src/locales/vi-VN/translations.json b/packages/i18n/src/locales/vi-VN/translations.json index 418d96ac43e..46dff9834f7 100644 --- a/packages/i18n/src/locales/vi-VN/translations.json +++ b/packages/i18n/src/locales/vi-VN/translations.json @@ -1342,21 +1342,22 @@ }, "created_vs_resolved": "Đã tạo vs Đã giải quyết", "customized_insights": "Thông tin chi tiết tùy chỉnh", - "backlog_work_items": "Các hạng mục công việc tồn đọng", + "backlog_work_items": "{entity} tồn đọng", "active_projects": "Dự án đang hoạt động", "trend_on_charts": "Xu hướng trên biểu đồ", "all_projects": "Tất cả dự án", "summary_of_projects": "Tóm tắt dự án", "project_insights": "Thông tin chi tiết dự án", - "started_work_items": "Hạng mục công việc đã bắt đầu", - "total_work_items": "Tổng số hạng mục công việc", + "started_work_items": "{entity} đã bắt đầu", + "total_work_items": "Tổng số {entity}", "total_projects": "Tổng số dự án", "total_admins": "Tổng số quản trị viên", "total_users": "Tổng số người dùng", "total_intake": "Tổng thu", - "un_started_work_items": "Hạng mục công việc chưa bắt đầu", + "un_started_work_items": "{entity} chưa bắt đầu", "total_guests": "Tổng số khách", - "completed_work_items": "Hạng mục công việc đã hoàn thành" + "completed_work_items": "{entity} đã hoàn thành", + "total": "Tổng số {entity}" }, "workspace_projects": { "label": "{count, plural, one {dự án} other {dự án}}", diff --git a/packages/i18n/src/locales/zh-CN/translations.json b/packages/i18n/src/locales/zh-CN/translations.json index 8f8ca2d26fa..35f016e362c 100644 --- a/packages/i18n/src/locales/zh-CN/translations.json +++ b/packages/i18n/src/locales/zh-CN/translations.json @@ -1342,21 +1342,22 @@ }, "created_vs_resolved": "已创建 vs 已解决", "customized_insights": "自定义洞察", - "backlog_work_items": "待办工作项", + "backlog_work_items": "待办的{entity}", "active_projects": "活跃项目", "trend_on_charts": "图表趋势", "all_projects": "所有项目", "summary_of_projects": "项目概览", "project_insights": "项目洞察", - "started_work_items": "已开始的工作项", - "total_work_items": "工作项总数", + "started_work_items": "已开始的{entity}", + "total_work_items": "{entity}总数", "total_projects": "项目总数", "total_admins": "管理员总数", "total_users": "用户总数", "total_intake": "总收入", - "un_started_work_items": "未开始的工作项", + "un_started_work_items": "未开始的{entity}", "total_guests": "访客总数", - "completed_work_items": "已完成的工作项" + "completed_work_items": "已完成的{entity}", + "total": "{entity}总数" }, "workspace_projects": { "label": "{count, plural, one {项目} other {项目}}", diff --git a/packages/i18n/src/locales/zh-TW/translations.json b/packages/i18n/src/locales/zh-TW/translations.json index 472ba631c1d..87d12e63462 100644 --- a/packages/i18n/src/locales/zh-TW/translations.json +++ b/packages/i18n/src/locales/zh-TW/translations.json @@ -1343,21 +1343,22 @@ }, "created_vs_resolved": "已建立 vs 已解決", "customized_insights": "自訂化洞察", - "backlog_work_items": "待辦工作項目", + "backlog_work_items": "待辦的{entity}", "active_projects": "啟用中的專案", "trend_on_charts": "圖表趨勢", "all_projects": "所有專案", "summary_of_projects": "專案摘要", "project_insights": "專案洞察", - "started_work_items": "已開始的工作項目", - "total_work_items": "工作項目總數", + "started_work_items": "已開始的{entity}", + "total_work_items": "{entity}總數", "total_projects": "專案總數", "total_admins": "管理員總數", "total_users": "使用者總數", "total_intake": "總收入", - "un_started_work_items": "未開始的工作項目", + "un_started_work_items": "未開始的{entity}", "total_guests": "訪客總數", - "completed_work_items": "已完成的工作項目" + "completed_work_items": "已完成的{entity}", + "total": "{entity}總數" }, "workspace_projects": { "label": "{count, plural, one {專案} other {專案}}", diff --git a/web/core/components/analytics-v2/total-insights.tsx b/web/core/components/analytics-v2/total-insights.tsx index 5fc8b2239eb..915e9fb8b4b 100644 --- a/web/core/components/analytics-v2/total-insights.tsx +++ b/web/core/components/analytics-v2/total-insights.tsx @@ -2,7 +2,7 @@ import { observer } from "mobx-react-lite"; import { useParams } from "next/navigation"; import useSWR from "swr"; -import { insightsFields } from "@plane/constants"; +import { EIssuesStoreType, insightsFields } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { IAnalyticsResponseV2, TAnalyticsTabsV2Base } from "@plane/types"; //hooks @@ -15,52 +15,59 @@ import InsightCard from "./insight-card"; const analyticsV2Service = new AnalyticsV2Service(); -const TotalInsights: React.FC<{ analyticsType: TAnalyticsTabsV2Base; peekView?: boolean }> = observer( - ({ analyticsType, peekView }) => { - const params = useParams(); - const workspaceSlug = params.workspaceSlug.toString(); - const { t } = useTranslation(); - const { selectedDuration, selectedProjects, selectedDurationLabel, selectedCycle, selectedModule, isPeekView } = - useAnalyticsV2(); - - const { data: totalInsightsData, isLoading } = useSWR( - `total-insights-${analyticsType}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, - () => - analyticsV2Service.getAdvanceAnalytics( - workspaceSlug, - analyticsType, - { - // date_filter: selectedDuration, - ...(selectedProjects?.length > 0 ? { project_ids: selectedProjects.join(",") } : {}), - ...(selectedCycle ? { cycle_id: selectedCycle } : {}), - ...(selectedModule ? { module_id: selectedModule } : {}), - }, - isPeekView - ) - ); - return ( -
- {insightsFields[analyticsType]?.map((item: string) => ( - - ))} -
- ); - } -); +const TotalInsights: React.FC<{ + analyticsType: TAnalyticsTabsV2Base; + peekView?: boolean; + storeType?: EIssuesStoreType; +}> = observer(({ analyticsType, peekView, storeType = EIssuesStoreType.PROJECT }) => { + const params = useParams(); + const workspaceSlug = params.workspaceSlug.toString(); + const { t } = useTranslation(); + const { selectedDuration, selectedProjects, selectedDurationLabel, selectedCycle, selectedModule, isPeekView } = + useAnalyticsV2(); + const { data: totalInsightsData, isLoading } = useSWR( + `total-insights-${analyticsType}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, + () => + analyticsV2Service.getAdvanceAnalytics( + workspaceSlug, + analyticsType, + { + // date_filter: selectedDuration, + ...(selectedProjects?.length > 0 ? { project_ids: selectedProjects.join(",") } : {}), + ...(selectedCycle ? { cycle_id: selectedCycle } : {}), + ...(selectedModule ? { module_id: selectedModule } : {}), + }, + isPeekView + ) + ); + return ( +
+ {insightsFields[analyticsType]?.map((item) => ( + + ))} +
+ ); +}); export default TotalInsights; diff --git a/web/core/components/workspace/sidebar/projects-list-item.tsx b/web/core/components/workspace/sidebar/projects-list-item.tsx index 40b1f2be17b..6d1cf7d330e 100644 --- a/web/core/components/workspace/sidebar/projects-list-item.tsx +++ b/web/core/components/workspace/sidebar/projects-list-item.tsx @@ -362,7 +362,12 @@ export const SidebarProjectsListItem: React.FC = observer((props) => { )} - + { + console.log("clicked settings"); + setIsMenuActive(false); + }} + >
diff --git a/web/core/store/analytics-v2.store.ts b/web/core/store/analytics-v2.store.ts index 393616beed2..37d153deb16 100644 --- a/web/core/store/analytics-v2.store.ts +++ b/web/core/store/analytics-v2.store.ts @@ -1,5 +1,5 @@ import { action, computed, makeObservable, observable, runInAction } from "mobx"; -import { ANALYTICS_V2_DURATION_FILTER_OPTIONS } from "@plane/constants"; +import { ANALYTICS_V2_DURATION_FILTER_OPTIONS, EIssuesStoreType } from "@plane/constants"; import { TAnalyticsTabsV2Base } from "@plane/types"; import { CoreRootStore } from "./root.store"; From 14c65207cbe7299f71b60fb44ce2ee5b2c8c8920 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 29 May 2025 01:45:37 +0530 Subject: [PATCH 03/19] refactor: update entity keys in analytics and translations --- packages/constants/src/analytics-v2/common.ts | 16 ++++++++-------- packages/i18n/src/locales/en/translations.json | 3 +++ .../components/analytics-v2/total-insights.tsx | 5 ++++- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/constants/src/analytics-v2/common.ts b/packages/constants/src/analytics-v2/common.ts index 673cb628132..5d1c4cad1f1 100644 --- a/packages/constants/src/analytics-v2/common.ts +++ b/packages/constants/src/analytics-v2/common.ts @@ -17,56 +17,56 @@ export const insightsFields: Record = { key: "total_users", i18nKey: "workspace_analytics.total", i18nProps: { - entity: "Users", + entity: "common.users", }, }, { key: "total_admins", i18nKey: "workspace_analytics.total", i18nProps: { - entity: "Admins", + entity: "common.admins", }, }, { key: "total_members", i18nKey: "workspace_analytics.total", i18nProps: { - entity: "Members", + entity: "common.members", }, }, { key: "total_guests", i18nKey: "workspace_analytics.total", i18nProps: { - entity: "Guests", + entity: "common.guests", }, }, { key: "total_projects", i18nKey: "workspace_analytics.total", i18nProps: { - entity: "Projects", + entity: "common.projects", }, }, { key: "total_work_items", i18nKey: "workspace_analytics.total", i18nProps: { - entity: "work items", + entity: "common.work_items", }, }, { key: "total_cycles", i18nKey: "workspace_analytics.total", i18nProps: { - entity: "Cycles", + entity: "common.cycles", }, }, { key: "total_intake", i18nKey: "workspace_analytics.total", i18nProps: { - entity: "Intake", + entity: "sidebar.intake", }, }, ], diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 54f9540411d..be207561781 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -469,6 +469,9 @@ "modules": "Modules", "labels": "Labels", "label": "Label", + "admins": "Admins", + "users": "Users", + "guests": "Guests", "assignees": "Assignees", "assignee": "Assignee", "created_by": "Created by", diff --git a/web/core/components/analytics-v2/total-insights.tsx b/web/core/components/analytics-v2/total-insights.tsx index 915e9fb8b4b..667bcea741c 100644 --- a/web/core/components/analytics-v2/total-insights.tsx +++ b/web/core/components/analytics-v2/total-insights.tsx @@ -61,7 +61,10 @@ const TotalInsights: React.FC<{ ? storeType === EIssuesStoreType.EPIC ? t(item.i18nKey, { entity: t("common.epics") }) : t(item.i18nKey, { entity: t("common.work_items") }) - : t(item.i18nKey, { ...item.i18nProps }) + : t(item.i18nKey, { + ...item.i18nProps, + entity: item.i18nProps?.entity && t(item.i18nProps?.entity), + }) } versus={selectedDurationLabel} /> From b0b2901a165463cd66ae216a9fa002778648a319 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 29 May 2025 01:45:55 +0530 Subject: [PATCH 04/19] chore: updated the translations --- packages/i18n/src/locales/cs/translations.json | 5 ++++- packages/i18n/src/locales/de/translations.json | 5 ++++- packages/i18n/src/locales/es/translations.json | 5 ++++- packages/i18n/src/locales/fr/translations.json | 5 ++++- packages/i18n/src/locales/id/translations.json | 5 ++++- packages/i18n/src/locales/it/translations.json | 5 ++++- packages/i18n/src/locales/ja/translations.json | 5 ++++- packages/i18n/src/locales/ko/translations.json | 5 ++++- packages/i18n/src/locales/pl/translations.json | 5 ++++- packages/i18n/src/locales/pt-BR/translations.json | 5 ++++- packages/i18n/src/locales/ro/translations.json | 5 ++++- packages/i18n/src/locales/ru/translations.json | 5 ++++- packages/i18n/src/locales/sk/translations.json | 5 ++++- packages/i18n/src/locales/tr-TR/translations.json | 5 ++++- packages/i18n/src/locales/ua/translations.json | 5 ++++- packages/i18n/src/locales/vi-VN/translations.json | 5 ++++- packages/i18n/src/locales/zh-CN/translations.json | 5 ++++- packages/i18n/src/locales/zh-TW/translations.json | 5 ++++- 18 files changed, 72 insertions(+), 18 deletions(-) diff --git a/packages/i18n/src/locales/cs/translations.json b/packages/i18n/src/locales/cs/translations.json index 894a544f6b6..831c0354c62 100644 --- a/packages/i18n/src/locales/cs/translations.json +++ b/packages/i18n/src/locales/cs/translations.json @@ -865,7 +865,10 @@ "view": "Pohled", "deactivated_user": "Deaktivovaný uživatel", "apply": "Použít", - "applying": "Používání" + "applying": "Používání", + "users": "Uživatelé", + "admins": "Administrátoři", + "guests": "Hosté" }, "chart": { "x_axis": "Osa X", diff --git a/packages/i18n/src/locales/de/translations.json b/packages/i18n/src/locales/de/translations.json index 4533a118bd0..eddf1b38fbc 100644 --- a/packages/i18n/src/locales/de/translations.json +++ b/packages/i18n/src/locales/de/translations.json @@ -865,7 +865,10 @@ "view": "Ansicht", "deactivated_user": "Deaktivierter Benutzer", "apply": "Anwenden", - "applying": "Wird angewendet" + "applying": "Wird angewendet", + "users": "Benutzer", + "admins": "Administratoren", + "guests": "Gäste" }, "chart": { "x_axis": "X-Achse", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 963ab0d5333..bbb92bd6345 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -868,7 +868,10 @@ "view": "Ver", "deactivated_user": "Usuario desactivado", "apply": "Aplicar", - "applying": "Aplicando" + "applying": "Aplicando", + "users": "Usuarios", + "admins": "Administradores", + "guests": "Invitados" }, "chart": { "x_axis": "Eje X", diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index b793a905227..66201e4389c 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -866,7 +866,10 @@ "view": "Afficher", "deactivated_user": "Utilisateur désactivé", "apply": "Appliquer", - "applying": "Application" + "applying": "Application", + "users": "Utilisateurs", + "admins": "Administrateurs", + "guests": "Invités" }, "chart": { "x_axis": "Axe X", diff --git a/packages/i18n/src/locales/id/translations.json b/packages/i18n/src/locales/id/translations.json index 8d84ca58976..e987502fd89 100644 --- a/packages/i18n/src/locales/id/translations.json +++ b/packages/i18n/src/locales/id/translations.json @@ -865,7 +865,10 @@ "view": "Lihat", "deactivated_user": "Pengguna dinonaktifkan", "apply": "Terapkan", - "applying": "Terapkan" + "applying": "Terapkan", + "users": "Pengguna", + "admins": "Admin", + "guests": "Tamu" }, "chart": { "x_axis": "Sumbu-X", diff --git a/packages/i18n/src/locales/it/translations.json b/packages/i18n/src/locales/it/translations.json index b9af24add6e..235bff2ca22 100644 --- a/packages/i18n/src/locales/it/translations.json +++ b/packages/i18n/src/locales/it/translations.json @@ -864,7 +864,10 @@ "view": "Visualizza", "deactivated_user": "Utente disattivato", "apply": "Applica", - "applying": "Applicazione" + "applying": "Applicazione", + "users": "Utenti", + "admins": "Amministratori", + "guests": "Ospiti" }, "chart": { "x_axis": "Asse X", diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index f6321b4a5a2..bb8571f62b6 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -866,7 +866,10 @@ "view": "ビュー", "deactivated_user": "無効化されたユーザー", "apply": "適用", - "applying": "適用中" + "applying": "適用中", + "users": "ユーザー", + "admins": "管理者", + "guests": "ゲスト" }, "chart": { "x_axis": "エックス アクシス", diff --git a/packages/i18n/src/locales/ko/translations.json b/packages/i18n/src/locales/ko/translations.json index 1d82a91d512..6ed73370128 100644 --- a/packages/i18n/src/locales/ko/translations.json +++ b/packages/i18n/src/locales/ko/translations.json @@ -867,7 +867,10 @@ "view": "보기", "deactivated_user": "비활성화된 사용자", "apply": "적용", - "applying": "적용 중" + "applying": "적용 중", + "users": "사용자", + "admins": "관리자", + "guests": "게스트" }, "chart": { "x_axis": "X축", diff --git a/packages/i18n/src/locales/pl/translations.json b/packages/i18n/src/locales/pl/translations.json index 7ffca2379cf..95eebbfdd2c 100644 --- a/packages/i18n/src/locales/pl/translations.json +++ b/packages/i18n/src/locales/pl/translations.json @@ -867,7 +867,10 @@ "view": "Widok", "deactivated_user": "Dezaktywowany użytkownik", "apply": "Zastosuj", - "applying": "Zastosowanie" + "applying": "Zastosowanie", + "users": "Użytkownicy", + "admins": "Administratorzy", + "guests": "Goście" }, "chart": { "x_axis": "Oś X", diff --git a/packages/i18n/src/locales/pt-BR/translations.json b/packages/i18n/src/locales/pt-BR/translations.json index 274238d56cc..cf783d8f060 100644 --- a/packages/i18n/src/locales/pt-BR/translations.json +++ b/packages/i18n/src/locales/pt-BR/translations.json @@ -867,7 +867,10 @@ "view": "Visualizar", "deactivated_user": "Usuário desativado", "apply": "Aplicar", - "applying": "Aplicando" + "applying": "Aplicando", + "users": "Usuários", + "admins": "Administradores", + "guests": "Convidados" }, "chart": { "x_axis": "Eixo X", diff --git a/packages/i18n/src/locales/ro/translations.json b/packages/i18n/src/locales/ro/translations.json index 9b0f840c889..925c20a965d 100644 --- a/packages/i18n/src/locales/ro/translations.json +++ b/packages/i18n/src/locales/ro/translations.json @@ -865,7 +865,10 @@ "view": "Vizualizează", "deactivated_user": "Utilizator dezactivat", "apply": "Aplică", - "applying": "Aplicând" + "applying": "Aplicând", + "users": "Utilizatori", + "admins": "Administratori", + "guests": "Invitați" }, "chart": { "x_axis": "axa-X", diff --git a/packages/i18n/src/locales/ru/translations.json b/packages/i18n/src/locales/ru/translations.json index f3a65fbcd4f..2048ec392b3 100644 --- a/packages/i18n/src/locales/ru/translations.json +++ b/packages/i18n/src/locales/ru/translations.json @@ -867,7 +867,10 @@ "view": "Просмотр", "deactivated_user": "Деактивированный пользователь", "apply": "Применить", - "applying": "Применение" + "applying": "Применение", + "users": "Пользователи", + "admins": "Администраторы", + "guests": "Гости" }, "chart": { "x_axis": "Ось X", diff --git a/packages/i18n/src/locales/sk/translations.json b/packages/i18n/src/locales/sk/translations.json index 12962ba62bd..0e3944e6200 100644 --- a/packages/i18n/src/locales/sk/translations.json +++ b/packages/i18n/src/locales/sk/translations.json @@ -867,7 +867,10 @@ "view": "Zobraziť", "deactivated_user": "Deaktivovaný používateľ", "apply": "Použiť", - "applying": "Používanie" + "applying": "Používanie", + "users": "Používatelia", + "admins": "Administrátori", + "guests": "Hostia" }, "chart": { "x_axis": "Os X", diff --git a/packages/i18n/src/locales/tr-TR/translations.json b/packages/i18n/src/locales/tr-TR/translations.json index 718d142c66e..e0ea85ab98a 100644 --- a/packages/i18n/src/locales/tr-TR/translations.json +++ b/packages/i18n/src/locales/tr-TR/translations.json @@ -868,7 +868,10 @@ "view": "Görünüm", "deactivated_user": "Devre dışı bırakılmış kullanıcı", "apply": "Uygula", - "applying": "Uygulanıyor" + "applying": "Uygulanıyor", + "users": "Kullanıcılar", + "admins": "Yöneticiler", + "guests": "Misafirler" }, "chart": { "x_axis": "X ekseni", diff --git a/packages/i18n/src/locales/ua/translations.json b/packages/i18n/src/locales/ua/translations.json index 659ef7fe1cf..341e7a7b4b2 100644 --- a/packages/i18n/src/locales/ua/translations.json +++ b/packages/i18n/src/locales/ua/translations.json @@ -867,7 +867,10 @@ "view": "Подання", "deactivated_user": "Деактивований користувач", "apply": "Застосувати", - "applying": "Застосовується" + "applying": "Застосовується", + "users": "Користувачі", + "admins": "Адміністратори", + "guests": "Гості" }, "chart": { "x_axis": "Вісь X", diff --git a/packages/i18n/src/locales/vi-VN/translations.json b/packages/i18n/src/locales/vi-VN/translations.json index 46dff9834f7..e20bc963e2e 100644 --- a/packages/i18n/src/locales/vi-VN/translations.json +++ b/packages/i18n/src/locales/vi-VN/translations.json @@ -866,7 +866,10 @@ "view": "Xem", "deactivated_user": "Người dùng bị vô hiệu hóa", "apply": "Áp dụng", - "applying": "Đang áp dụng" + "applying": "Đang áp dụng", + "users": "Người dùng", + "admins": "Quản trị viên", + "guests": "Khách" }, "chart": { "x_axis": "Trục X", diff --git a/packages/i18n/src/locales/zh-CN/translations.json b/packages/i18n/src/locales/zh-CN/translations.json index 35f016e362c..0b90d0789c8 100644 --- a/packages/i18n/src/locales/zh-CN/translations.json +++ b/packages/i18n/src/locales/zh-CN/translations.json @@ -866,7 +866,10 @@ "view": "查看", "deactivated_user": "已停用用户", "apply": "应用", - "applying": "应用中" + "applying": "应用中", + "users": "用户", + "admins": "管理员", + "guests": "访客" }, "chart": { "x_axis": "X轴", diff --git a/packages/i18n/src/locales/zh-TW/translations.json b/packages/i18n/src/locales/zh-TW/translations.json index 87d12e63462..58862894795 100644 --- a/packages/i18n/src/locales/zh-TW/translations.json +++ b/packages/i18n/src/locales/zh-TW/translations.json @@ -867,7 +867,10 @@ "view": "檢視", "deactivated_user": "已停用用戶", "apply": "應用", - "applying": "應用中" + "applying": "應用中", + "users": "使用者", + "admins": "管理員", + "guests": "訪客" }, "chart": { "x_axis": "X 軸", From 94bc7237a68d3e4d352839da716ad4843db6610e Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 29 May 2025 13:52:42 +0530 Subject: [PATCH 05/19] refactor: simplify AnalyticsStoreV2 class by removing unnecessary constructor --- web/ce/store/analytics-v2.store.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/web/ce/store/analytics-v2.store.ts b/web/ce/store/analytics-v2.store.ts index 3a02dc1311f..b1fcb7df08a 100644 --- a/web/ce/store/analytics-v2.store.ts +++ b/web/ce/store/analytics-v2.store.ts @@ -5,8 +5,4 @@ export interface IAnalyticsStoreV2 extends IBaseAnalyticsStoreV2 { //observables } -export class AnalyticsStoreV2 extends BaseAnalyticsStoreV2 { - constructor() { - super(); - } -} +export class AnalyticsStoreV2 extends BaseAnalyticsStoreV2 {} From 1eb250c99021466f467d79bd4b88dd84ed9773f6 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 29 May 2025 14:23:26 +0530 Subject: [PATCH 06/19] feat: add AnalyticsStoreV2 class and interface for enhanced analytics functionality --- web/ee/store/analytics-v2.store.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 web/ee/store/analytics-v2.store.ts diff --git a/web/ee/store/analytics-v2.store.ts b/web/ee/store/analytics-v2.store.ts new file mode 100644 index 00000000000..b1fcb7df08a --- /dev/null +++ b/web/ee/store/analytics-v2.store.ts @@ -0,0 +1,8 @@ +import { BaseAnalyticsStoreV2, IBaseAnalyticsStoreV2 } from "@/store/analytics-v2.store"; + +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface IAnalyticsStoreV2 extends IBaseAnalyticsStoreV2 { + //observables +} + +export class AnalyticsStoreV2 extends BaseAnalyticsStoreV2 {} From 06e39d7f715eb8a05302713320cd532c21a7192a Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 29 May 2025 14:35:57 +0530 Subject: [PATCH 07/19] feat: enhance WorkItemsModal and analytics store with isEpic functionality --- .../analytics-v2/work-items/modal/index.tsx | 12 +++++++++--- web/core/components/issues/filters.tsx | 1 + web/core/store/analytics-v2.store.ts | 12 +++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/web/core/components/analytics-v2/work-items/modal/index.tsx b/web/core/components/analytics-v2/work-items/modal/index.tsx index c30c2687d5b..95b8f18409b 100644 --- a/web/core/components/analytics-v2/work-items/modal/index.tsx +++ b/web/core/components/analytics-v2/work-items/modal/index.tsx @@ -1,8 +1,9 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { observer } from "mobx-react"; import { Dialog, Transition } from "@headlessui/react"; // plane package imports import { ICycle, IModule, IProject } from "@plane/types"; +import { useAnalyticsV2 } from "@/hooks/store"; // plane web components import { WorkItemsModalMainContent } from "./content"; import { WorkItemsModalHeader } from "./header"; @@ -13,17 +14,22 @@ type Props = { projectDetails?: IProject | undefined; cycleDetails?: ICycle | undefined; moduleDetails?: IModule | undefined; + isEpic?: boolean; }; export const WorkItemsModal: React.FC = observer((props) => { - const { isOpen, onClose, projectDetails, moduleDetails, cycleDetails } = props; - + const { isOpen, onClose, projectDetails, moduleDetails, cycleDetails, isEpic } = props; + const { updateIsEpic } = useAnalyticsV2(); const [fullScreen, setFullScreen] = useState(false); const handleClose = () => { onClose(); }; + useEffect(() => { + updateIsEpic(isEpic ?? false); + }, [isEpic, updateIsEpic]); + return ( diff --git a/web/core/components/issues/filters.tsx b/web/core/components/issues/filters.tsx index a50afe50ebc..3f759d0d145 100644 --- a/web/core/components/issues/filters.tsx +++ b/web/core/components/issues/filters.tsx @@ -102,6 +102,7 @@ const HeaderFilters = observer((props: Props) => { isOpen={analyticsModal} onClose={() => setAnalyticsModal(false)} projectDetails={currentProjectDetails ?? undefined} + isEpic={storeType === EIssuesStoreType.EPIC} /> void; updateSelectedModule: (module: string) => void; updateIsPeekView: (isPeekView: boolean) => void; + updateIsEpic: (isEpic: boolean) => void; } export abstract class BaseAnalyticsStoreV2 implements IBaseAnalyticsStoreV2 { @@ -33,6 +34,7 @@ export abstract class BaseAnalyticsStoreV2 implements IBaseAnalyticsStoreV2 { selectedCycle: string = ""; selectedModule: string = ""; isPeekView: boolean = false; + isEpic: boolean = false; constructor() { makeObservable(this, { // observables @@ -42,6 +44,7 @@ export abstract class BaseAnalyticsStoreV2 implements IBaseAnalyticsStoreV2 { selectedCycle: observable.ref, selectedModule: observable.ref, isPeekView: observable.ref, + isEpic: observable.ref, // computed selectedDurationLabel: computed, // actions @@ -50,6 +53,7 @@ export abstract class BaseAnalyticsStoreV2 implements IBaseAnalyticsStoreV2 { updateSelectedCycle: action, updateSelectedModule: action, updateIsPeekView: action, + updateIsEpic: action, }); } @@ -96,4 +100,10 @@ export abstract class BaseAnalyticsStoreV2 implements IBaseAnalyticsStoreV2 { this.isPeekView = isPeekView; }); }; + + updateIsEpic = (isEpic: boolean) => { + runInAction(() => { + this.isEpic = isEpic; + }); + }; } From aabc9a0acecd1afcfb2544d58e15511983419cba Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 29 May 2025 14:39:57 +0530 Subject: [PATCH 08/19] feat: integrate isEpic state into TotalInsights and WorkItemsModal components --- .../components/analytics-v2/total-insights.tsx | 16 +++++++++++----- .../analytics-v2/work-items/modal/content.tsx | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/web/core/components/analytics-v2/total-insights.tsx b/web/core/components/analytics-v2/total-insights.tsx index 667bcea741c..6b88bbc6dd5 100644 --- a/web/core/components/analytics-v2/total-insights.tsx +++ b/web/core/components/analytics-v2/total-insights.tsx @@ -18,13 +18,19 @@ const analyticsV2Service = new AnalyticsV2Service(); const TotalInsights: React.FC<{ analyticsType: TAnalyticsTabsV2Base; peekView?: boolean; - storeType?: EIssuesStoreType; -}> = observer(({ analyticsType, peekView, storeType = EIssuesStoreType.PROJECT }) => { +}> = observer(({ analyticsType, peekView }) => { const params = useParams(); const workspaceSlug = params.workspaceSlug.toString(); const { t } = useTranslation(); - const { selectedDuration, selectedProjects, selectedDurationLabel, selectedCycle, selectedModule, isPeekView } = - useAnalyticsV2(); + const { + selectedDuration, + selectedProjects, + selectedDurationLabel, + selectedCycle, + selectedModule, + isPeekView, + isEpic, + } = useAnalyticsV2(); const { data: totalInsightsData, isLoading } = useSWR( `total-insights-${analyticsType}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, () => @@ -58,7 +64,7 @@ const TotalInsights: React.FC<{ data={totalInsightsData?.[item.key]} label={ analyticsType === "work-items" - ? storeType === EIssuesStoreType.EPIC + ? isEpic ? t(item.i18nKey, { entity: t("common.epics") }) : t(item.i18nKey, { entity: t("common.work_items") }) : t(item.i18nKey, { diff --git a/web/core/components/analytics-v2/work-items/modal/content.tsx b/web/core/components/analytics-v2/work-items/modal/content.tsx index 62b3c24bacc..a6aceaeab16 100644 --- a/web/core/components/analytics-v2/work-items/modal/content.tsx +++ b/web/core/components/analytics-v2/work-items/modal/content.tsx @@ -17,11 +17,13 @@ type Props = { projectDetails: IProject | undefined; cycleDetails: ICycle | undefined; moduleDetails: IModule | undefined; + isEpic?: boolean; }; export const WorkItemsModalMainContent: React.FC = observer((props) => { - const { projectDetails, cycleDetails, moduleDetails, fullScreen } = props; - const { updateSelectedProjects, updateSelectedCycle, updateSelectedModule, updateIsPeekView } = useAnalyticsV2(); + const { projectDetails, cycleDetails, moduleDetails, fullScreen, isEpic } = props; + const { updateSelectedProjects, updateSelectedCycle, updateSelectedModule, updateIsPeekView, updateIsEpic } = + useAnalyticsV2(); const [isModalConfigured, setIsModalConfigured] = useState(false); useEffect(() => { @@ -41,6 +43,11 @@ export const WorkItemsModalMainContent: React.FC = observer((props) => { if (moduleDetails?.id) { updateSelectedModule(moduleDetails.id); } + + if (isEpic) { + updateIsEpic(true); + } + setIsModalConfigured(true); // Cleanup fields @@ -49,6 +56,7 @@ export const WorkItemsModalMainContent: React.FC = observer((props) => { updateSelectedCycle(""); updateSelectedModule(""); updateIsPeekView(false); + updateIsEpic(false); }; }, [ projectDetails?.id, @@ -57,6 +65,8 @@ export const WorkItemsModalMainContent: React.FC = observer((props) => { updateSelectedProjects, updateSelectedCycle, updateSelectedModule, + isEpic, + updateIsEpic, updateIsPeekView, ]); From 55e54f64ee9443ca17435693c8cd9310da39b787 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 29 May 2025 14:40:08 +0530 Subject: [PATCH 09/19] refactor: remove isEpic state from WorkItemsModalMainContent component --- .../analytics-v2/work-items/modal/content.tsx | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/web/core/components/analytics-v2/work-items/modal/content.tsx b/web/core/components/analytics-v2/work-items/modal/content.tsx index a6aceaeab16..62b3c24bacc 100644 --- a/web/core/components/analytics-v2/work-items/modal/content.tsx +++ b/web/core/components/analytics-v2/work-items/modal/content.tsx @@ -17,13 +17,11 @@ type Props = { projectDetails: IProject | undefined; cycleDetails: ICycle | undefined; moduleDetails: IModule | undefined; - isEpic?: boolean; }; export const WorkItemsModalMainContent: React.FC = observer((props) => { - const { projectDetails, cycleDetails, moduleDetails, fullScreen, isEpic } = props; - const { updateSelectedProjects, updateSelectedCycle, updateSelectedModule, updateIsPeekView, updateIsEpic } = - useAnalyticsV2(); + const { projectDetails, cycleDetails, moduleDetails, fullScreen } = props; + const { updateSelectedProjects, updateSelectedCycle, updateSelectedModule, updateIsPeekView } = useAnalyticsV2(); const [isModalConfigured, setIsModalConfigured] = useState(false); useEffect(() => { @@ -43,11 +41,6 @@ export const WorkItemsModalMainContent: React.FC = observer((props) => { if (moduleDetails?.id) { updateSelectedModule(moduleDetails.id); } - - if (isEpic) { - updateIsEpic(true); - } - setIsModalConfigured(true); // Cleanup fields @@ -56,7 +49,6 @@ export const WorkItemsModalMainContent: React.FC = observer((props) => { updateSelectedCycle(""); updateSelectedModule(""); updateIsPeekView(false); - updateIsEpic(false); }; }, [ projectDetails?.id, @@ -65,8 +57,6 @@ export const WorkItemsModalMainContent: React.FC = observer((props) => { updateSelectedProjects, updateSelectedCycle, updateSelectedModule, - isEpic, - updateIsEpic, updateIsPeekView, ]); From 64934bc17389db973e1675fe213cab4a8cb3c9a8 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Mon, 2 Jun 2025 13:47:34 +0530 Subject: [PATCH 10/19] refactor: removed old analytics components and related services --- packages/constants/src/analytics.ts | 81 ------- packages/constants/src/index.ts | 1 - .../src/analytics/analytics.service.ts | 93 -------- packages/services/src/analytics/index.ts | 1 - packages/services/src/index.ts | 1 - packages/types/src/analytics.d.ts | 116 ---------- .../modules/(detail)/mobile-header.tsx | 1 - .../custom-analytics/custom-analytics.tsx | 94 -------- .../custom-analytics/graph/custom-tooltip.tsx | 73 ------ .../custom-analytics/graph/index.tsx | 136 ----------- .../analytics/custom-analytics/index.ts | 7 - .../custom-analytics/main-content.tsx | 85 ------- .../analytics/custom-analytics/select-bar.tsx | 94 -------- .../custom-analytics/select/index.ts | 4 - .../custom-analytics/select/project.tsx | 52 ----- .../custom-analytics/select/segment.tsx | 45 ---- .../custom-analytics/select/x-axis.tsx | 40 ---- .../custom-analytics/select/y-axis.tsx | 58 ----- .../custom-analytics/sidebar/index.ts | 3 - .../sidebar/projects-list.tsx | 89 -------- .../sidebar/sidebar-header.tsx | 104 --------- .../custom-analytics/sidebar/sidebar.tsx | 212 ------------------ .../analytics/custom-analytics/table.tsx | 106 --------- web/core/components/analytics/index.ts | 3 - web/core/components/analytics/old-page.tsx | 107 --------- .../analytics/project-modal/header.tsx | 37 --- .../analytics/project-modal/index.ts | 3 - .../analytics/project-modal/main-content.tsx | 57 ----- .../analytics/project-modal/modal.tsx | 71 ------ .../analytics/scope-and-demand/demand.tsx | 58 ----- .../analytics/scope-and-demand/index.ts | 5 - .../scope-and-demand/leaderboard.tsx | 69 ------ .../scope-and-demand/scope-and-demand.tsx | 115 ---------- .../analytics/scope-and-demand/scope.tsx | 99 -------- .../scope-and-demand/year-wise-issues.tsx | 64 ------ web/core/components/issues/filters.tsx | 1 - web/core/constants/fetch-keys.ts | 10 +- web/core/services/analytics.service.ts | 63 ------ web/helpers/analytics.helper.ts | 152 ------------- 39 files changed, 1 insertion(+), 2409 deletions(-) delete mode 100644 packages/constants/src/analytics.ts delete mode 100644 packages/services/src/analytics/analytics.service.ts delete mode 100644 packages/services/src/analytics/index.ts delete mode 100644 packages/types/src/analytics.d.ts delete mode 100644 web/core/components/analytics/custom-analytics/custom-analytics.tsx delete mode 100644 web/core/components/analytics/custom-analytics/graph/custom-tooltip.tsx delete mode 100644 web/core/components/analytics/custom-analytics/graph/index.tsx delete mode 100644 web/core/components/analytics/custom-analytics/index.ts delete mode 100644 web/core/components/analytics/custom-analytics/main-content.tsx delete mode 100644 web/core/components/analytics/custom-analytics/select-bar.tsx delete mode 100644 web/core/components/analytics/custom-analytics/select/index.ts delete mode 100644 web/core/components/analytics/custom-analytics/select/project.tsx delete mode 100644 web/core/components/analytics/custom-analytics/select/segment.tsx delete mode 100644 web/core/components/analytics/custom-analytics/select/x-axis.tsx delete mode 100644 web/core/components/analytics/custom-analytics/select/y-axis.tsx delete mode 100644 web/core/components/analytics/custom-analytics/sidebar/index.ts delete mode 100644 web/core/components/analytics/custom-analytics/sidebar/projects-list.tsx delete mode 100644 web/core/components/analytics/custom-analytics/sidebar/sidebar-header.tsx delete mode 100644 web/core/components/analytics/custom-analytics/sidebar/sidebar.tsx delete mode 100644 web/core/components/analytics/custom-analytics/table.tsx delete mode 100644 web/core/components/analytics/index.ts delete mode 100644 web/core/components/analytics/old-page.tsx delete mode 100644 web/core/components/analytics/project-modal/header.tsx delete mode 100644 web/core/components/analytics/project-modal/index.ts delete mode 100644 web/core/components/analytics/project-modal/main-content.tsx delete mode 100644 web/core/components/analytics/project-modal/modal.tsx delete mode 100644 web/core/components/analytics/scope-and-demand/demand.tsx delete mode 100644 web/core/components/analytics/scope-and-demand/index.ts delete mode 100644 web/core/components/analytics/scope-and-demand/leaderboard.tsx delete mode 100644 web/core/components/analytics/scope-and-demand/scope-and-demand.tsx delete mode 100644 web/core/components/analytics/scope-and-demand/scope.tsx delete mode 100644 web/core/components/analytics/scope-and-demand/year-wise-issues.tsx delete mode 100644 web/core/services/analytics.service.ts delete mode 100644 web/helpers/analytics.helper.ts diff --git a/packages/constants/src/analytics.ts b/packages/constants/src/analytics.ts deleted file mode 100644 index 6c8211ae0ab..00000000000 --- a/packages/constants/src/analytics.ts +++ /dev/null @@ -1,81 +0,0 @@ -// types -import { TXAxisValues, TYAxisValues } from "@plane/types"; - -export const ANALYTICS_TABS = [ - { - key: "scope_and_demand", - i18n_title: "workspace_analytics.tabs.scope_and_demand", - }, - { key: "custom", i18n_title: "workspace_analytics.tabs.custom" }, -]; - -export const ANALYTICS_X_AXIS_VALUES: { value: TXAxisValues; label: string }[] = - [ - { - value: "state_id", - label: "State name", - }, - { - value: "state__group", - label: "State group", - }, - { - value: "priority", - label: "Priority", - }, - { - value: "labels__id", - label: "Label", - }, - { - value: "assignees__id", - label: "Assignee", - }, - { - value: "estimate_point__value", - label: "Estimate point", - }, - { - value: "issue_cycle__cycle_id", - label: "Cycle", - }, - { - value: "issue_module__module_id", - label: "Module", - }, - { - value: "completed_at", - label: "Completed date", - }, - { - value: "target_date", - label: "Due date", - }, - { - value: "start_date", - label: "Start date", - }, - { - value: "created_at", - label: "Created date", - }, - ]; - -export const ANALYTICS_Y_AXIS_VALUES: { value: TYAxisValues; label: string }[] = - [ - { - value: "issue_count", - label: "Work item Count", - }, - { - value: "estimate", - label: "Estimate", - }, - ]; - -export const ANALYTICS_DATE_KEYS = [ - "completed_at", - "target_date", - "start_date", - "created_at", -]; diff --git a/packages/constants/src/index.ts b/packages/constants/src/index.ts index 58b51ed723a..d6c28234c38 100644 --- a/packages/constants/src/index.ts +++ b/packages/constants/src/index.ts @@ -1,5 +1,4 @@ export * from "./ai"; -export * from "./analytics"; export * from "./auth"; export * from "./chart"; export * from "./endpoints"; diff --git a/packages/services/src/analytics/analytics.service.ts b/packages/services/src/analytics/analytics.service.ts deleted file mode 100644 index c012fd26f47..00000000000 --- a/packages/services/src/analytics/analytics.service.ts +++ /dev/null @@ -1,93 +0,0 @@ -// constants -import { API_BASE_URL } from "@plane/constants"; -// types -import { - IAnalyticsParams, - IAnalyticsResponse, - IDefaultAnalyticsResponse, - IExportAnalyticsFormData, - ISaveAnalyticsFormData, -} from "@plane/types"; -// services -import { APIService } from "../api.service"; - -export class AnalyticsService extends APIService { - constructor(BASE_URL?: string) { - super(BASE_URL || API_BASE_URL); - } - - /** - * Retrieves analytics data for a specific workspace - * @param {string} workspaceSlug - The unique identifier for the workspace - * @param {IAnalyticsParams} params - Parameters for filtering analytics data - * @param {string|number} [params.project] - Optional project identifier that will be converted to string - * @returns {Promise} The analytics data for the workspace - * @throws {Error} Throws response data if the request fails - */ - async getAnalytics(workspaceSlug: string, params: IAnalyticsParams): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/analytics/`, { - params: { - ...params, - project: params?.project ? params.project.toString() : null, - }, - }) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - /** - * Retrieves default analytics data for a workspace - * @param {string} workspaceSlug - The unique identifier for the workspace - * @param {Partial} [params] - Optional parameters for filtering default analytics - * @param {string|number} [params.project] - Optional project identifier that will be converted to string - * @returns {Promise} The default analytics data - * @throws {Error} Throws response data if the request fails - */ - async getDefaultAnalytics( - workspaceSlug: string, - params?: Partial - ): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/default-analytics/`, { - params: { - ...params, - project: params?.project ? params.project.toString() : null, - }, - }) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - /** - * Saves analytics view configuration for a workspace - * @param {string} workspaceSlug - The unique identifier for the workspace - * @param {ISaveAnalyticsFormData} data - The analytics configuration data to save - * @returns {Promise} The response from saving the analytics view - * @throws {Error} Throws response data if the request fails - */ - async save(workspaceSlug: string, data: ISaveAnalyticsFormData): Promise { - return this.post(`/api/workspaces/${workspaceSlug}/analytic-view/`, data) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - /** - * Exports analytics data for a workspace - * @param {string} workspaceSlug - The unique identifier for the workspace - * @param {IExportAnalyticsFormData} data - Configuration for the analytics export - * @returns {Promise} The exported analytics data - * @throws {Error} Throws response data if the request fails - */ - async export(workspaceSlug: string, data: IExportAnalyticsFormData): Promise { - return this.post(`/api/workspaces/${workspaceSlug}/export-analytics/`, data) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } -} diff --git a/packages/services/src/analytics/index.ts b/packages/services/src/analytics/index.ts deleted file mode 100644 index 7655bd44242..00000000000 --- a/packages/services/src/analytics/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./analytics.service"; diff --git a/packages/services/src/index.ts b/packages/services/src/index.ts index 3c49084628a..b1f966840dc 100644 --- a/packages/services/src/index.ts +++ b/packages/services/src/index.ts @@ -1,5 +1,4 @@ export * from "./ai"; -export * from "./analytics"; export * from "./developer"; export * from "./auth"; export * from "./cycle"; diff --git a/packages/types/src/analytics.d.ts b/packages/types/src/analytics.d.ts deleted file mode 100644 index ec417e73fe3..00000000000 --- a/packages/types/src/analytics.d.ts +++ /dev/null @@ -1,116 +0,0 @@ -export interface IAnalyticsResponse { - total: number; - distribution: IAnalyticsData; - extras: { - assignee_details: IAnalyticsAssigneeDetails[]; - cycle_details: IAnalyticsCycleDetails[]; - label_details: IAnalyticsLabelDetails[]; - module_details: IAnalyticsModuleDetails[]; - state_details: IAnalyticsStateDetails[]; - }; -} - -export interface IAnalyticsData { - [key: string]: { - dimension: string | null; - segment?: string; - count?: number; - estimate?: number | null; - }[]; -} - -export interface IAnalyticsAssigneeDetails { - assignees__avatar_url: string | null; - assignees__display_name: string | null; - assignees__first_name: string; - assignees__id: string | null; - assignees__last_name: string; -} - -export interface IAnalyticsCycleDetails { - issue_cycle__cycle__name: string | null; - issue_cycle__cycle_id: string | null; -} - -export interface IAnalyticsLabelDetails { - labels__color: string | null; - labels__id: string | null; - labels__name: string | null; -} - -export interface IAnalyticsModuleDetails { - issue_module__module__name: string | null; - issue_module__module_id: string | null; -} - -export interface IAnalyticsStateDetails { - state__color: string; - state__name: string; - state_id: string; -} - -export type TXAxisValues = - | "state_id" - | "state__group" - | "labels__id" - | "assignees__id" - | "estimate_point__value" - | "issue_cycle__cycle_id" - | "issue_module__module_id" - | "priority" - | "start_date" - | "target_date" - | "created_at" - | "completed_at"; - -export type TYAxisValues = "issue_count" | "estimate"; - -export interface IAnalyticsParams { - x_axis: TXAxisValues; - y_axis: TYAxisValues; - segment?: TXAxisValues | null; - project?: string[] | null; - cycle?: string | null; - module?: string | null; -} - -export interface ISaveAnalyticsFormData { - name: string; - description: string; - query_dict: IExportAnalyticsFormData; -} -export interface IExportAnalyticsFormData { - x_axis: TXAxisValues; - y_axis: TYAxisValues; - segment?: TXAxisValues | null; - project?: string[]; -} - -export interface IDefaultAnalyticsUser { - assignees__avatar_url: string | null; - assignees__first_name: string; - assignees__last_name: string; - assignees__display_name: string; - assignees__id: string; - count: number; -} - -export interface IDefaultAnalyticsResponse { - issue_completed_month_wise: { month: number; count: number }[]; - most_issue_closed_user: IDefaultAnalyticsUser[]; - most_issue_created_user: { - created_by__avatar_url: string | null; - created_by__first_name: string; - created_by__last_name: string; - created_by__display_name: string; - created_by__id: string; - count: number; - }[]; - open_estimate_sum: number; - open_issues: number; - open_issues_classified: { state_group: string; state_count: number }[]; - pending_issue_user: IDefaultAnalyticsUser[]; - total_estimate_sum: number; - total_issues: number; - total_issues_classified: { state_group: string; state_count: number }[]; -} diff --git a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/mobile-header.tsx b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/mobile-header.tsx index 741fe3b5391..59e09e3d06b 100644 --- a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/mobile-header.tsx +++ b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/mobile-header.tsx @@ -20,7 +20,6 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption // ui import { CustomMenu } from "@plane/ui"; // components -import { ProjectAnalyticsModal } from "@/components/analytics"; import { WorkItemsModal } from "@/components/analytics-v2/work-items/modal"; import { DisplayFiltersSelection, diff --git a/web/core/components/analytics/custom-analytics/custom-analytics.tsx b/web/core/components/analytics/custom-analytics/custom-analytics.tsx deleted file mode 100644 index bb801616fcb..00000000000 --- a/web/core/components/analytics/custom-analytics/custom-analytics.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { useEffect } from "react"; -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -import { useForm } from "react-hook-form"; -import useSWR from "swr"; -import { IAnalyticsParams } from "@plane/types"; -// services -// components -import { CustomAnalyticsSelectBar, CustomAnalyticsMainContent, CustomAnalyticsSidebar } from "@/components/analytics"; -// types -// fetch-keys -import { ANALYTICS } from "@/constants/fetch-keys"; -import { cn } from "@/helpers/common.helper"; -import { useAppTheme } from "@/hooks/store"; -import { hideFloatingBot, showFloatingBot } from "@/plane-web/helpers/pi-chat.helper"; -import { AnalyticsService } from "@/services/analytics.service"; - -type Props = { - additionalParams?: Partial; - fullScreen: boolean; -}; - -const defaultValues: IAnalyticsParams = { - x_axis: "priority", - y_axis: "issue_count", - segment: null, - project: null, -}; - -const analyticsService = new AnalyticsService(); - -export const CustomAnalytics: React.FC = observer((props) => { - const { additionalParams, fullScreen } = props; - - const { workspaceSlug, projectId } = useParams(); - - const { control, watch, setValue } = useForm({ defaultValues }); - - const params: IAnalyticsParams = { - x_axis: watch("x_axis"), - y_axis: watch("y_axis"), - segment: watch("segment"), - project: projectId ? [projectId.toString()] : watch("project"), - ...additionalParams, - }; - - const { data: analytics, error: analyticsError } = useSWR( - workspaceSlug ? ANALYTICS(workspaceSlug.toString(), params) : null, - workspaceSlug ? () => analyticsService.getAnalytics(workspaceSlug.toString(), params) : null - ); - - const { workspaceAnalyticsSidebarCollapsed } = useAppTheme(); - - const isProjectLevel = projectId ? true : false; - - useEffect(() => { - hideFloatingBot(); - return () => { - showFloatingBot(); - }; - }, []); - - return ( -
-
- - -
- -
- -
-
- ); -}); diff --git a/web/core/components/analytics/custom-analytics/graph/custom-tooltip.tsx b/web/core/components/analytics/custom-analytics/graph/custom-tooltip.tsx deleted file mode 100644 index 853c541e717..00000000000 --- a/web/core/components/analytics/custom-analytics/graph/custom-tooltip.tsx +++ /dev/null @@ -1,73 +0,0 @@ -// nivo -import { BarTooltipProps } from "@nivo/bar"; -// plane imports -import { ANALYTICS_DATE_KEYS } from "@plane/constants"; -import { IAnalyticsParams, IAnalyticsResponse } from "@plane/types"; -// helpers -import { renderMonthAndYear } from "@/helpers/analytics.helper"; - -type Props = { - datum: BarTooltipProps; - analytics: IAnalyticsResponse; - params: IAnalyticsParams; -}; - -export const CustomTooltip: React.FC = ({ datum, analytics, params }) => { - let tooltipValue: string | number = ""; - - const renderAssigneeName = (assigneeId: string): string => { - const assignee = analytics.extras.assignee_details.find((a) => a.assignees__id === assigneeId); - - if (!assignee) return "No assignee"; - - return assignee.assignees__display_name || "No assignee"; - }; - - if (params.segment) { - if (ANALYTICS_DATE_KEYS.includes(params.segment)) tooltipValue = renderMonthAndYear(datum.id); - else if (params.segment === "labels__id") { - const label = analytics.extras.label_details.find((l) => l.labels__id === datum.id); - tooltipValue = label && label.labels__name ? label.labels__name : "None"; - } else if (params.segment === "state_id") { - const state = analytics.extras.state_details.find((s) => s.state_id === datum.id); - tooltipValue = state && state.state__name ? state.state__name : "None"; - } else if (params.segment === "issue_cycle__cycle_id") { - const cycle = analytics.extras.cycle_details.find((c) => c.issue_cycle__cycle_id === datum.id); - tooltipValue = cycle && cycle.issue_cycle__cycle__name ? cycle.issue_cycle__cycle__name : "None"; - } else if (params.segment === "issue_module__module_id") { - const selectedModule = analytics.extras.module_details.find((m) => m.issue_module__module_id === datum.id); - tooltipValue = - selectedModule && selectedModule.issue_module__module__name - ? selectedModule.issue_module__module__name - : "None"; - } else tooltipValue = datum.id; - } else { - if (ANALYTICS_DATE_KEYS.includes(params.x_axis)) tooltipValue = datum.indexValue; - else tooltipValue = datum.id === "count" ? "Work item count" : "Estimate"; - } - - return ( -
- - - {params.segment === "assignees__id" ? renderAssigneeName(tooltipValue.toString()) : tooltipValue}: - - {datum.value} -
- ); -}; diff --git a/web/core/components/analytics/custom-analytics/graph/index.tsx b/web/core/components/analytics/custom-analytics/graph/index.tsx deleted file mode 100644 index 87627bba373..00000000000 --- a/web/core/components/analytics/custom-analytics/graph/index.tsx +++ /dev/null @@ -1,136 +0,0 @@ -"use client"; - -// nivo -import { BarDatum } from "@nivo/bar"; -// components -import { IAnalyticsParams, IAnalyticsResponse } from "@plane/types"; -import { Tooltip } from "@plane/ui"; -// ui -import { BarGraph } from "@/components/ui"; -// helpers -import { generateBarColor, generateDisplayName, renderChartDynamicLabel } from "@/helpers/analytics.helper"; -import { findStringWithMostCharacters } from "@/helpers/array.helper"; -import { getFileURL } from "@/helpers/file.helper"; -// types -import { CustomTooltip } from "./custom-tooltip"; - -type Props = { - analytics: IAnalyticsResponse; - barGraphData: { - data: BarDatum[]; - xAxisKeys: string[]; - }; - params: IAnalyticsParams; - yAxisKey: "count" | "estimate"; - fullScreen: boolean; -}; - -export const AnalyticsGraph: React.FC = ({ analytics, barGraphData, params, yAxisKey, fullScreen }) => { - const generateYAxisTickValues = () => { - if (!analytics) return []; - - let data: number[] = []; - - if (params.segment) - // find the total no of work items in each segment - data = Object.keys(analytics.distribution).map((segment) => { - let totalSegmentIssues = 0; - - analytics.distribution[segment].map((s) => { - totalSegmentIssues += s[yAxisKey] as number; - }); - - return totalSegmentIssues; - }); - else data = barGraphData.data.map((d) => d[yAxisKey] as number); - - return data; - }; - - const longestXAxisLabel = findStringWithMostCharacters(barGraphData.data.map((d) => `${d.name}`)); - - return ( - - generateBarColor( - params.segment ? `${datum.id}` : `${datum.indexValue}`, - analytics, - params, - params.segment ? "segment" : "x_axis" - ) - } - customYAxisTickValues={generateYAxisTickValues()} - tooltip={(datum) => } - height={fullScreen ? "400px" : "300px"} - margin={{ - right: 20, - bottom: params.x_axis === "assignees__id" ? 50 : renderChartDynamicLabel(longestXAxisLabel)?.length * 5 + 20, - }} - axisBottom={{ - tickSize: 0, - tickPadding: 10, - tickRotation: barGraphData.data.length > 7 ? -45 : 0, - renderTick: - params.x_axis === "assignees__id" - ? (datum) => { - const assignee = analytics.extras.assignee_details?.find((a) => a?.assignees__id === datum?.value); - - if (assignee?.assignees__avatar_url && assignee?.assignees__avatar_url !== "") - return ( - - - - - - ); - else - return ( - - - - - {params.x_axis === "assignees__id" - ? datum.value && datum.value !== "None" - ? generateDisplayName(datum.value, analytics, params, "x_axis")[0].toUpperCase() - : "?" - : datum.value && datum.value !== "None" - ? `${datum.value}`.toUpperCase()[0] - : "?"} - - - - ); - } - : (datum) => ( - - - 7 ? "end" : "middle"}`} - fontSize={10} - fill="rgb(var(--color-text-200))" - className={`${barGraphData.data.length > 7 ? "-rotate-45" : ""}`} - > - {renderChartDynamicLabel(generateDisplayName(datum.value, analytics, params, "x_axis"))?.label} - - - - ), - }} - theme={{ - axis: {}, - }} - /> - ); -}; diff --git a/web/core/components/analytics/custom-analytics/index.ts b/web/core/components/analytics/custom-analytics/index.ts deleted file mode 100644 index 9cb0ddd5b07..00000000000 --- a/web/core/components/analytics/custom-analytics/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from "./graph"; -export * from "./select"; -export * from "./custom-analytics"; -export * from "./main-content"; -export * from "./select-bar"; -export * from "./sidebar"; -export * from "./table"; diff --git a/web/core/components/analytics/custom-analytics/main-content.tsx b/web/core/components/analytics/custom-analytics/main-content.tsx deleted file mode 100644 index b990c53bc76..00000000000 --- a/web/core/components/analytics/custom-analytics/main-content.tsx +++ /dev/null @@ -1,85 +0,0 @@ -"use client"; - -import { useParams } from "next/navigation"; -import { mutate } from "swr"; -// types -import { IAnalyticsParams, IAnalyticsResponse } from "@plane/types"; -// ui -import { Button, Loader } from "@plane/ui"; -// components -import { AnalyticsGraph, AnalyticsTable } from "@/components/analytics"; -// fetch-keys -import { ANALYTICS } from "@/constants/fetch-keys"; -// helpers -import { convertResponseToBarGraphData } from "@/helpers/analytics.helper"; - -type Props = { - analytics: IAnalyticsResponse | undefined; - error: any; - fullScreen: boolean; - params: IAnalyticsParams; -}; - -export const CustomAnalyticsMainContent: React.FC = (props) => { - const { analytics, error, fullScreen, params } = props; - - const { workspaceSlug } = useParams(); - - const yAxisKey = params.y_axis === "issue_count" ? "count" : "estimate"; - const barGraphData = convertResponseToBarGraphData(analytics?.distribution, params); - - return ( - <> - {!error ? ( - analytics ? ( - analytics.total > 0 ? ( -
- - -
- ) : ( -
-
-

No matching work items found. Try changing the parameters.

-
-
- ) - ) : ( - - - - - - - - - - ) - ) : ( -
-
-

There was some error in fetching the data.

-
- -
-
-
- )} - - ); -}; diff --git a/web/core/components/analytics/custom-analytics/select-bar.tsx b/web/core/components/analytics/custom-analytics/select-bar.tsx deleted file mode 100644 index 27cfad236c1..00000000000 --- a/web/core/components/analytics/custom-analytics/select-bar.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { observer } from "mobx-react"; -import { Control, Controller, UseFormSetValue } from "react-hook-form"; -// plane imports -import { ANALYTICS_X_AXIS_VALUES } from "@plane/constants"; -import { IAnalyticsParams } from "@plane/types"; -import { Row } from "@plane/ui"; -// components -import { SelectProject, SelectSegment, SelectXAxis, SelectYAxis } from "@/components/analytics"; -// hooks -import { useProject } from "@/hooks/store"; - -type Props = { - control: Control; - setValue: UseFormSetValue; - params: IAnalyticsParams; - fullScreen: boolean; - isProjectLevel: boolean; -}; - -export const CustomAnalyticsSelectBar: React.FC = observer((props) => { - const { control, setValue, params, fullScreen, isProjectLevel } = props; - - const { workspaceProjectIds: workspaceProjectIds, currentProjectDetails } = useProject(); - - const analyticsOptions = isProjectLevel - ? ANALYTICS_X_AXIS_VALUES.filter((v) => { - if (v.value === "issue_cycle__cycle_id" && !currentProjectDetails?.cycle_view) return false; - if (v.value === "issue_module__module_id" && !currentProjectDetails?.module_view) return false; - return true; - }) - : ANALYTICS_X_AXIS_VALUES; - - return ( - - {!isProjectLevel && ( -
-
Project
- ( - - )} - /> -
- )} -
-
Measure (y-axis)
- } - /> -
-
-
Dimension (x-axis)
- ( - { - if (params.segment === val) setValue("segment", null); - - onChange(val); - }} - params={params} - analyticsOptions={analyticsOptions} - /> - )} - /> -
-
-
Group
- ( - - )} - /> -
-
- ); -}); diff --git a/web/core/components/analytics/custom-analytics/select/index.ts b/web/core/components/analytics/custom-analytics/select/index.ts deleted file mode 100644 index 0c89bd2ad42..00000000000 --- a/web/core/components/analytics/custom-analytics/select/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from "./project"; -export * from "./segment"; -export * from "./x-axis"; -export * from "./y-axis"; diff --git a/web/core/components/analytics/custom-analytics/select/project.tsx b/web/core/components/analytics/custom-analytics/select/project.tsx deleted file mode 100644 index 4038da4e1de..00000000000 --- a/web/core/components/analytics/custom-analytics/select/project.tsx +++ /dev/null @@ -1,52 +0,0 @@ -"use client"; - -import { observer } from "mobx-react"; -// hooks -import { CustomSearchSelect } from "@plane/ui"; -import { useProject } from "@/hooks/store"; -// ui - -type Props = { - value: string[] | undefined; - onChange: (val: string[] | null) => void; - projectIds: string[] | undefined; -}; - -export const SelectProject: React.FC = observer((props) => { - const { value, onChange, projectIds } = props; - const { getProjectById } = useProject(); - - const options = projectIds?.map((projectId) => { - const projectDetails = getProjectById(projectId); - - return { - value: projectDetails?.id, - query: `${projectDetails?.name} ${projectDetails?.identifier}`, - content: ( -
- {projectDetails?.identifier} - {projectDetails?.name} -
- ), - }; - }); - - return ( - onChange(val)} - options={options} - label={ -
- {value && value.length > 0 - ? projectIds - ?.filter((p) => value.includes(p)) - .map((p) => getProjectById(p)?.name) - .join(", ") - : "All projects"} -
- } - multiple - /> - ); -}); diff --git a/web/core/components/analytics/custom-analytics/select/segment.tsx b/web/core/components/analytics/custom-analytics/select/segment.tsx deleted file mode 100644 index ecaf0dc75e5..00000000000 --- a/web/core/components/analytics/custom-analytics/select/segment.tsx +++ /dev/null @@ -1,45 +0,0 @@ -"use client"; - -import { useParams } from "next/navigation"; -import { IAnalyticsParams, TXAxisValues } from "@plane/types"; -// ui -import { CustomSelect } from "@plane/ui"; - -type Props = { - value: TXAxisValues | null | undefined; - onChange: () => void; - params: IAnalyticsParams; - analyticsOptions: { value: TXAxisValues; label: string }[]; -}; - -export const SelectSegment: React.FC = ({ value, onChange, params, analyticsOptions }) => { - const { cycleId, moduleId } = useParams(); - - return ( - - {analyticsOptions.find((v) => v.value === value)?.label ?? ( - No value - )} - - } - onChange={onChange} - maxHeight="lg" - > - No value - {analyticsOptions.map((item) => { - if (params.x_axis === item.value) return null; - if (cycleId && item.value === "issue_cycle__cycle_id") return null; - if (moduleId && item.value === "issue_module__module_id") return null; - - return ( - - {item.label} - - ); - })} - - ); -}; diff --git a/web/core/components/analytics/custom-analytics/select/x-axis.tsx b/web/core/components/analytics/custom-analytics/select/x-axis.tsx deleted file mode 100644 index 032d4381fa7..00000000000 --- a/web/core/components/analytics/custom-analytics/select/x-axis.tsx +++ /dev/null @@ -1,40 +0,0 @@ -"use client"; - -import { useParams } from "next/navigation"; -import { IAnalyticsParams, TXAxisValues } from "@plane/types"; -// ui -import { CustomSelect } from "@plane/ui"; - -type Props = { - value: TXAxisValues; - onChange: (val: string) => void; - params: IAnalyticsParams; - analyticsOptions: { value: TXAxisValues; label: string }[]; -}; - -export const SelectXAxis: React.FC = (props) => { - const { value, onChange, params, analyticsOptions } = props; - - const { cycleId, moduleId } = useParams(); - - return ( - {analyticsOptions.find((v) => v.value === value)?.label}} - onChange={onChange} - maxHeight="lg" - > - {analyticsOptions.map((item) => { - if (params.segment === item.value) return null; - if (cycleId && item.value === "issue_cycle__cycle_id") return null; - if (moduleId && item.value === "issue_module__module_id") return null; - - return ( - - {item.label} - - ); - })} - - ); -}; diff --git a/web/core/components/analytics/custom-analytics/select/y-axis.tsx b/web/core/components/analytics/custom-analytics/select/y-axis.tsx deleted file mode 100644 index 42c9145e899..00000000000 --- a/web/core/components/analytics/custom-analytics/select/y-axis.tsx +++ /dev/null @@ -1,58 +0,0 @@ -"use client"; - -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -// plane imports -import { ANALYTICS_Y_AXIS_VALUES } from "@plane/constants"; -import { TYAxisValues } from "@plane/types"; -import { CustomSelect } from "@plane/ui"; -// hooks -import { useProjectEstimates } from "@/hooks/store"; -// plane web constants -import { EEstimateSystem } from "@/plane-web/constants/estimates"; - -type Props = { - value: TYAxisValues; - onChange: () => void; -}; - -export const SelectYAxis: React.FC = observer(({ value, onChange }) => { - // hooks - const { projectId } = useParams(); - const { areEstimateEnabledByProjectId, currentActiveEstimateId, estimateById } = useProjectEstimates(); - - const isEstimateEnabled = (analyticsOption: string) => { - if (analyticsOption === "estimate") { - if ( - projectId && - currentActiveEstimateId && - areEstimateEnabledByProjectId(projectId.toString()) && - estimateById(currentActiveEstimateId)?.type === EEstimateSystem.POINTS - ) { - return true; - } else { - return false; - } - } - - return true; - }; - - return ( - {ANALYTICS_Y_AXIS_VALUES.find((v) => v.value === value)?.label ?? "None"}} - onChange={onChange} - maxHeight="lg" - > - {ANALYTICS_Y_AXIS_VALUES.map( - (item) => - isEstimateEnabled(item.value) && ( - - {item.label} - - ) - )} - - ); -}); diff --git a/web/core/components/analytics/custom-analytics/sidebar/index.ts b/web/core/components/analytics/custom-analytics/sidebar/index.ts deleted file mode 100644 index db9adae856f..00000000000 --- a/web/core/components/analytics/custom-analytics/sidebar/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./projects-list"; -export * from "./sidebar-header"; -export * from "./sidebar"; diff --git a/web/core/components/analytics/custom-analytics/sidebar/projects-list.tsx b/web/core/components/analytics/custom-analytics/sidebar/projects-list.tsx deleted file mode 100644 index c07867378ad..00000000000 --- a/web/core/components/analytics/custom-analytics/sidebar/projects-list.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { observer } from "mobx-react"; -// icons -import { Contrast, LayoutGrid, Users, Loader as Spinner } from "lucide-react"; -// plane imports -import { useTranslation } from "@plane/i18n"; -import { Loader } from "@plane/ui"; -// components -import { Logo } from "@/components/common"; -// helpers -import { truncateText } from "@/helpers/string.helper"; -// hooks -import { useProject } from "@/hooks/store"; - -type Props = { - projectIds: string[]; - isLoading: boolean; - isUpdating: boolean; -}; - -export const CustomAnalyticsSidebarProjectsList: React.FC = observer((props) => { - const { projectIds, isLoading, isUpdating } = props; - // store hooks - const { getProjectById, getProjectAnalyticsCountById } = useProject(); - const { t } = useTranslation(); - - return ( -
-
-

{t("workspace_analytics.selected_projects")}

- {isUpdating && } -
-
- {projectIds.map((projectId) => { - const project = getProjectById(projectId); - const projectAnalyticsCount = getProjectAnalyticsCountById(projectId); - - if (!project) return; - - return ( -
-
-
- -
-
-

{truncateText(project.name, 20)}

- ({project.identifier}) -
-
-
- {isLoading ? ( - - - - - - ) : ( - <> -
-
- -
{t("workspace_analytics.total_members")}
-
- {projectAnalyticsCount?.total_members} -
-
-
- -
{t("workspace_analytics.total_cycles")}
-
- {projectAnalyticsCount?.total_cycles} -
-
-
- -
{t("workspace_analytics.total_modules")}
-
- {projectAnalyticsCount?.total_modules} -
- - )} -
-
- ); - })} -
-
- ); -}); diff --git a/web/core/components/analytics/custom-analytics/sidebar/sidebar-header.tsx b/web/core/components/analytics/custom-analytics/sidebar/sidebar-header.tsx deleted file mode 100644 index 707a149221b..00000000000 --- a/web/core/components/analytics/custom-analytics/sidebar/sidebar-header.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -// components -import { NETWORK_CHOICES } from "@plane/constants"; -import { useTranslation } from "@plane/i18n"; -import { Logo } from "@/components/common"; -// constants -// helpers -import { renderFormattedDate } from "@/helpers/date-time.helper"; -// hooks -import { useCycle, useMember, useModule, useProject } from "@/hooks/store"; - -export const CustomAnalyticsSidebarHeader = observer(() => { - const { projectId, cycleId, moduleId } = useParams(); - - const { getProjectById } = useProject(); - const { getCycleById } = useCycle(); - const { getModuleById } = useModule(); - const { getUserDetails } = useMember(); - const { t } = useTranslation(); - - const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined; - const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined; - const projectDetails = projectId ? getProjectById(projectId.toString()) : undefined; - const cycleOwnerDetails = cycleDetails ? getUserDetails(cycleDetails.owned_by_id) : undefined; - const moduleLeadDetails = moduleDetails && moduleDetails.lead_id ? getUserDetails(moduleDetails.lead_id) : undefined; - - return ( - <> - {projectId ? ( - cycleDetails ? ( -
-

Analytics for {cycleDetails.name}

-
-
-
Lead
- {cycleOwnerDetails?.display_name} -
-
-
Start Date
- - {cycleDetails.start_date && cycleDetails.start_date !== "" - ? renderFormattedDate(cycleDetails.start_date) - : "No start date"} - -
-
-
Target Date
- - {cycleDetails.end_date && cycleDetails.end_date !== "" - ? renderFormattedDate(cycleDetails.end_date) - : "No end date"} - -
-
-
- ) : moduleDetails ? ( -
-

Analytics for {moduleDetails.name}

-
-
-
Lead
- {moduleLeadDetails && {moduleLeadDetails?.display_name}} -
-
-
Start Date
- - {moduleDetails.start_date && moduleDetails.start_date !== "" - ? renderFormattedDate(moduleDetails.start_date) - : "No start date"} - -
-
-
Target Date
- - {moduleDetails.target_date && moduleDetails.target_date !== "" - ? renderFormattedDate(moduleDetails.target_date) - : "No end date"} - -
-
-
- ) : ( -
-
- {projectDetails && ( - - - - )} -

{projectDetails?.name}

-
-
-
-
Network
- {t(NETWORK_CHOICES.find((n) => n.key === projectDetails?.network)?.i18n_label ?? "")} -
-
-
- ) - ) : null} - - ); -}); diff --git a/web/core/components/analytics/custom-analytics/sidebar/sidebar.tsx b/web/core/components/analytics/custom-analytics/sidebar/sidebar.tsx deleted file mode 100644 index 5df139205a8..00000000000 --- a/web/core/components/analytics/custom-analytics/sidebar/sidebar.tsx +++ /dev/null @@ -1,212 +0,0 @@ -"use client"; - -import { useEffect } from "react"; -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -import useSWR, { mutate } from "swr"; -// icons -import { CalendarDays, Download, RefreshCw } from "lucide-react"; -// types -import { useTranslation } from "@plane/i18n"; -import { IAnalyticsParams, IAnalyticsResponse, IExportAnalyticsFormData, IWorkspace } from "@plane/types"; -// ui -import { Button, LayersIcon, TOAST_TYPE, setToast } from "@plane/ui"; -// components -import { CustomAnalyticsSidebarHeader, CustomAnalyticsSidebarProjectsList } from "@/components/analytics"; -// constants -import { ANALYTICS } from "@/constants/fetch-keys"; -// helpers -import { cn } from "@/helpers/common.helper"; -import { renderFormattedDate } from "@/helpers/date-time.helper"; -// hooks -import { useCycle, useModule, useProject, useWorkspace, useUser } from "@/hooks/store"; -// services -import { AnalyticsService } from "@/services/analytics.service"; - -type Props = { - analytics: IAnalyticsResponse | undefined; - params: IAnalyticsParams; - isProjectLevel: boolean; -}; - -const analyticsService = new AnalyticsService(); - -const PROJECT_ANALYTICS_COUNT_PARAMS = { - fields: "total_members,total_cycles,total_modules", -}; - -export const CustomAnalyticsSidebar: React.FC = observer((props) => { - const { analytics, params, isProjectLevel = false } = props; - // router - const { workspaceSlug, projectId, cycleId, moduleId } = useParams(); - // store hooks - const { data: currentUser } = useUser(); - const { workspaceProjectIds, getProjectById, fetchProjectAnalyticsCount } = useProject(); - const { getWorkspaceById } = useWorkspace(); - const { t } = useTranslation(); - const { fetchCycleDetails, getCycleById } = useCycle(); - const { fetchModuleDetails, getModuleById } = useModule(); - // fetch project analytics count - const { isLoading: isProjectAnalyticsLoading, isValidating: isProjectAnalyticsUpdating } = useSWR( - workspaceSlug ? ["projectAnalyticsCount", workspaceSlug] : null, - workspaceSlug ? () => fetchProjectAnalyticsCount(workspaceSlug.toString(), PROJECT_ANALYTICS_COUNT_PARAMS) : null - ); - - const projectDetails = projectId ? (getProjectById(projectId.toString()) ?? undefined) : undefined; - - const trackExportAnalytics = () => { - if (!currentUser) return; - - const eventPayload: any = { - workspaceSlug: workspaceSlug?.toString(), - params: { - x_axis: params.x_axis, - y_axis: params.y_axis, - group: params.segment, - project: params.project, - }, - }; - - if (projectDetails) { - const workspaceDetails = projectDetails.workspace as IWorkspace; - - eventPayload.workspaceId = workspaceDetails.id; - eventPayload.workspaceName = workspaceDetails.name; - eventPayload.projectId = projectDetails.id; - eventPayload.projectIdentifier = projectDetails.identifier; - eventPayload.projectName = projectDetails.name; - } - - if (cycleDetails || moduleDetails) { - const details = cycleDetails || moduleDetails; - - const currentProjectDetails = getProjectById(details?.project_id || ""); - const currentWorkspaceDetails = getWorkspaceById(details?.workspace_id || ""); - - eventPayload.workspaceId = details?.workspace_id; - eventPayload.workspaceName = currentWorkspaceDetails?.name; - eventPayload.projectId = details?.project_id; - eventPayload.projectIdentifier = currentProjectDetails?.identifier; - eventPayload.projectName = currentProjectDetails?.name; - } - - if (cycleDetails) { - eventPayload.cycleId = cycleDetails.id; - eventPayload.cycleName = cycleDetails.name; - } - - if (moduleDetails) { - eventPayload.moduleId = moduleDetails.id; - eventPayload.moduleName = moduleDetails.name; - } - }; - - const exportAnalytics = () => { - if (!workspaceSlug) return; - - const data: IExportAnalyticsFormData = { - x_axis: params.x_axis, - y_axis: params.y_axis, - }; - - if (params.segment) data.segment = params.segment; - if (params.project) data.project = params.project; - - analyticsService - .exportAnalytics(workspaceSlug.toString(), data) - .then((res) => { - setToast({ - type: TOAST_TYPE.SUCCESS, - title: "Success!", - message: res.message, - }); - - trackExportAnalytics(); - }) - .catch(() => - setToast({ - type: TOAST_TYPE.ERROR, - title: "Error!", - message: "There was some error in exporting the analytics. Please try again.", - }) - ); - }; - - const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined; - const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined; - - // fetch cycle details - useEffect(() => { - if (!workspaceSlug || !projectId || !cycleId || cycleDetails) return; - - fetchCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleId.toString()); - }, [cycleId, cycleDetails, fetchCycleDetails, projectId, workspaceSlug]); - - // fetch module details - useEffect(() => { - if (!workspaceSlug || !projectId || !moduleId || moduleDetails) return; - - fetchModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId.toString()); - }, [moduleId, moduleDetails, fetchModuleDetails, projectId, workspaceSlug]); - - const selectedProjects = params.project && params.project.length > 0 ? params.project : workspaceProjectIds; - - return ( -
-
-
- - {analytics ? analytics.total : "..."} -
{t("work_items")}
-
- {isProjectLevel && ( -
- - {renderFormattedDate( - (cycleId - ? cycleDetails?.created_at - : moduleId - ? moduleDetails?.created_at - : projectDetails?.created_at) ?? "" - )} -
- )} -
- -
- <> - {!isProjectLevel && selectedProjects && selectedProjects.length > 0 && ( - - )} - - -
- -
- - -
-
- ); -}); diff --git a/web/core/components/analytics/custom-analytics/table.tsx b/web/core/components/analytics/custom-analytics/table.tsx deleted file mode 100644 index fd580d7277d..00000000000 --- a/web/core/components/analytics/custom-analytics/table.tsx +++ /dev/null @@ -1,106 +0,0 @@ -"use client"; - -import { BarDatum } from "@nivo/bar"; -// plane package imports -import { ANALYTICS_X_AXIS_VALUES, ANALYTICS_Y_AXIS_VALUES } from "@plane/constants"; -import { IAnalyticsParams, IAnalyticsResponse, TIssuePriorities } from "@plane/types"; -import { PriorityIcon, Tooltip } from "@plane/ui"; -// helpers -import { generateBarColor, generateDisplayName, renderChartDynamicLabel } from "@/helpers/analytics.helper"; -import { cn } from "@/helpers/common.helper"; - -type Props = { - analytics: IAnalyticsResponse; - barGraphData: { - data: BarDatum[]; - xAxisKeys: string[]; - }; - params: IAnalyticsParams; - yAxisKey: "count" | "estimate"; -}; - -export const AnalyticsTable: React.FC = ({ analytics, barGraphData, params, yAxisKey }) => ( -
- - - - - {params.segment ? ( - barGraphData.xAxisKeys.map((key) => ( - - )) - ) : ( - - )} - - - - {barGraphData.data.map((item, index) => ( - - - {params.segment ? ( - barGraphData.xAxisKeys.map((key, index) => ( - - )) - ) : ( - - )} - - ))} - -
- {ANALYTICS_X_AXIS_VALUES.find((v) => v.value === params.x_axis)?.label} - -
- {params.segment === "priority" ? ( - - ) : ( - - )} - {renderChartDynamicLabel(generateDisplayName(key, analytics, params, "segment"))?.label} -
-
- {ANALYTICS_Y_AXIS_VALUES.find((v) => v.value === params.y_axis)?.label} -
-
-
- {params.x_axis === "priority" ? ( - - ) : ( -
- )} -
-
- -
- {generateDisplayName(`${item.name}`, analytics, params, "x_axis")} -
-
-
-
-
- {item[key] ?? 0} - {item[yAxisKey]}
-
-); diff --git a/web/core/components/analytics/index.ts b/web/core/components/analytics/index.ts deleted file mode 100644 index c5f76989085..00000000000 --- a/web/core/components/analytics/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./custom-analytics"; -export * from "./scope-and-demand"; -export * from "./project-modal"; diff --git a/web/core/components/analytics/old-page.tsx b/web/core/components/analytics/old-page.tsx deleted file mode 100644 index 719d6621431..00000000000 --- a/web/core/components/analytics/old-page.tsx +++ /dev/null @@ -1,107 +0,0 @@ -"use client"; - -import React, { Fragment } from "react"; -import { observer } from "mobx-react"; -import { useSearchParams } from "next/navigation"; -import { Tab } from "@headlessui/react"; -// plane package imports -import { ANALYTICS_TABS, EUserPermissionsLevel, EUserPermissions } from "@plane/constants"; -import { useTranslation } from "@plane/i18n"; -import { Header, EHeaderVariant } from "@plane/ui"; -// components -import { CustomAnalytics, ScopeAndDemand } from "@/components/analytics"; -import { PageHead } from "@/components/core"; -import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; -// hooks -import { useCommandPalette, useEventTracker, useProject, useUserPermissions, useWorkspace } from "@/hooks/store"; -import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; - -const OldAnalyticsPage = observer(() => { - const searchParams = useSearchParams(); - const analytics_tab = searchParams.get("analytics_tab"); - // plane imports - const { t } = useTranslation(); - // store hooks - const { toggleCreateProjectModal } = useCommandPalette(); - const { setTrackElement } = useEventTracker(); - const { workspaceProjectIds, loader } = useProject(); - const { currentWorkspace } = useWorkspace(); - const { allowPermissions } = useUserPermissions(); - // helper hooks - const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/analytics" }); - // derived values - const pageTitle = currentWorkspace?.name - ? t(`workspace_analytics.page_label`, { workspace: currentWorkspace?.name }) - : undefined; - - // permissions - const canPerformEmptyStateActions = allowPermissions( - [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - EUserPermissionsLevel.WORKSPACE - ); - - // TODO: refactor loader implementation - return ( - <> - - {workspaceProjectIds && ( - <> - {workspaceProjectIds.length > 0 || loader === "init-loader" ? ( -
- -
- - {ANALYTICS_TABS.map((tab) => ( - - {({ selected }) => ( - - )} - - ))} - -
- - - - - - - - -
-
- ) : ( - { - setTrackElement("Analytics empty state"); - toggleCreateProjectModal(true); - }} - disabled={!canPerformEmptyStateActions} - /> - } - /> - )} - - )} - - ); -}); - -export default OldAnalyticsPage; diff --git a/web/core/components/analytics/project-modal/header.tsx b/web/core/components/analytics/project-modal/header.tsx deleted file mode 100644 index 79d63ce3c0f..00000000000 --- a/web/core/components/analytics/project-modal/header.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { observer } from "mobx-react"; - -// icons -import { Expand, Shrink, X } from "lucide-react"; - -type Props = { - fullScreen: boolean; - handleClose: () => void; - setFullScreen: React.Dispatch>; - title: string; -}; - -export const ProjectAnalyticsModalHeader: React.FC = observer((props) => { - const { fullScreen, handleClose, setFullScreen, title } = props; - - return ( -
-

Analytics for {title}

-
- - -
-
- ); -}); diff --git a/web/core/components/analytics/project-modal/index.ts b/web/core/components/analytics/project-modal/index.ts deleted file mode 100644 index 70ca0260a4f..00000000000 --- a/web/core/components/analytics/project-modal/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./header"; -export * from "./main-content"; -export * from "./modal"; diff --git a/web/core/components/analytics/project-modal/main-content.tsx b/web/core/components/analytics/project-modal/main-content.tsx deleted file mode 100644 index cd3813f80cf..00000000000 --- a/web/core/components/analytics/project-modal/main-content.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React, { Fragment } from "react"; -import { observer } from "mobx-react"; -import { Tab } from "@headlessui/react"; -// plane package imports -import { ANALYTICS_TABS } from "@plane/constants"; -import { useTranslation } from "@plane/i18n"; -import { ICycle, IModule, IProject } from "@plane/types"; -// components -import { CustomAnalytics, ScopeAndDemand } from "@/components/analytics"; - -type Props = { - fullScreen: boolean; - cycleDetails: ICycle | undefined; - moduleDetails: IModule | undefined; - projectDetails: IProject | undefined; -}; - -export const ProjectAnalyticsModalMainContent: React.FC = observer((props) => { - const { fullScreen, cycleDetails, moduleDetails } = props; - const { t } = useTranslation(); - return ( - - - {ANALYTICS_TABS.map((tab) => ( - - {({ selected }) => ( - - )} - - ))} - - - - - - - - - - - ); -}); diff --git a/web/core/components/analytics/project-modal/modal.tsx b/web/core/components/analytics/project-modal/modal.tsx deleted file mode 100644 index fb45d6aa9dd..00000000000 --- a/web/core/components/analytics/project-modal/modal.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import React, { useState } from "react"; -import { observer } from "mobx-react"; -import { Dialog, Transition } from "@headlessui/react"; -import { ICycle, IModule, IProject } from "@plane/types"; - -// components -import { ProjectAnalyticsModalHeader, ProjectAnalyticsModalMainContent } from "@/components/analytics"; -// types - -type Props = { - isOpen: boolean; - onClose: () => void; - cycleDetails?: ICycle | undefined; - moduleDetails?: IModule | undefined; - projectDetails?: IProject | undefined; -}; - -export const ProjectAnalyticsModal: React.FC = observer((props) => { - const { isOpen, onClose, cycleDetails, moduleDetails, projectDetails } = props; - - const [fullScreen, setFullScreen] = useState(false); - - const handleClose = () => { - onClose(); - }; - - return ( - - - -
- -
-
- - -
-
-
-
-
-
-
- ); -}); diff --git a/web/core/components/analytics/scope-and-demand/demand.tsx b/web/core/components/analytics/scope-and-demand/demand.tsx deleted file mode 100644 index fefdc8fc6ee..00000000000 --- a/web/core/components/analytics/scope-and-demand/demand.tsx +++ /dev/null @@ -1,58 +0,0 @@ -// plane imports -import { STATE_GROUPS } from "@plane/constants"; -import { useTranslation } from "@plane/i18n"; -// types -import { IDefaultAnalyticsResponse, TStateGroups } from "@plane/types"; -// constants -import { Card } from "@plane/ui"; - -type Props = { - defaultAnalytics: IDefaultAnalyticsResponse; -}; - -export const AnalyticsDemand: React.FC = ({ defaultAnalytics }) => { - const { t } = useTranslation(); - - return ( - -
-

{t("workspace_analytics.open_tasks")}

-

{defaultAnalytics.open_issues}

-
-
- {defaultAnalytics?.open_issues_classified.map((group) => { - const percentage = ((group.state_count / defaultAnalytics.total_issues) * 100).toFixed(0); - - return ( -
-
-
- -
{group.state_group}
- - {group.state_count} - -
-

{percentage}%

-
-
-
-
-
- ); - })} -
- - ); -}; diff --git a/web/core/components/analytics/scope-and-demand/index.ts b/web/core/components/analytics/scope-and-demand/index.ts deleted file mode 100644 index ae756a961e2..00000000000 --- a/web/core/components/analytics/scope-and-demand/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./demand"; -export * from "./leaderboard"; -export * from "./scope-and-demand"; -export * from "./scope"; -export * from "./year-wise-issues"; diff --git a/web/core/components/analytics/scope-and-demand/leaderboard.tsx b/web/core/components/analytics/scope-and-demand/leaderboard.tsx deleted file mode 100644 index 76f96be4a27..00000000000 --- a/web/core/components/analytics/scope-and-demand/leaderboard.tsx +++ /dev/null @@ -1,69 +0,0 @@ -// plane ui -import { useTranslation } from "@plane/i18n"; -import { Card } from "@plane/ui"; -// components -import { ProfileEmptyState } from "@/components/ui"; -// helpers -import { getFileURL } from "@/helpers/file.helper"; -// image -import emptyUsers from "@/public/empty-state/empty_users.svg"; - -type Props = { - users: { - avatar_url: string | null; - display_name: string | null; - firstName: string; - lastName: string; - count: number; - id: string; - }[]; - title: string; - emptyStateMessage: string; - workspaceSlug: string; -}; - -export const AnalyticsLeaderBoard: React.FC = ({ users, title, emptyStateMessage, workspaceSlug }) => { - const { t } = useTranslation(); - return ( - -
{title}
- {users.length > 0 ? ( - - ) : ( -
- -
- )} -
- ); -}; diff --git a/web/core/components/analytics/scope-and-demand/scope-and-demand.tsx b/web/core/components/analytics/scope-and-demand/scope-and-demand.tsx deleted file mode 100644 index ae51727aa01..00000000000 --- a/web/core/components/analytics/scope-and-demand/scope-and-demand.tsx +++ /dev/null @@ -1,115 +0,0 @@ -"use client"; -import { useParams } from "next/navigation"; -import useSWR from "swr"; -// ui -import { useTranslation } from "@plane/i18n"; -import { Button, ContentWrapper, Loader } from "@plane/ui"; -// components -import { AnalyticsDemand, AnalyticsLeaderBoard, AnalyticsScope, AnalyticsYearWiseIssues } from "@/components/analytics"; -// fetch-keys -import { DEFAULT_ANALYTICS } from "@/constants/fetch-keys"; -// services -import { AnalyticsService } from "@/services/analytics.service"; - -type Props = { - fullScreen?: boolean; -}; - -// services -const analyticsService = new AnalyticsService(); - -export const ScopeAndDemand: React.FC = (props) => { - const { fullScreen = true } = props; - - const { workspaceSlug, projectId, cycleId, moduleId } = useParams(); - const { t } = useTranslation(); - - const isProjectLevel = projectId ? true : false; - - const params = isProjectLevel - ? { - project: projectId ? [projectId.toString()] : null, - cycle: cycleId ? cycleId.toString() : null, - module: moduleId ? moduleId.toString() : null, - } - : undefined; - - const { - data: defaultAnalytics, - error: defaultAnalyticsError, - mutate: mutateDefaultAnalytics, - } = useSWR( - workspaceSlug ? DEFAULT_ANALYTICS(workspaceSlug.toString(), params) : null, - workspaceSlug ? () => analyticsService.getDefaultAnalytics(workspaceSlug.toString(), params) : null - ); - - // scope data - const pendingIssues = defaultAnalytics?.pending_issue_user ?? []; - const pendingUnAssignedIssuesUser = pendingIssues?.find((issue) => issue.assignees__id === null); - const pendingAssignedIssues = pendingIssues?.filter((issue) => issue.assignees__id !== null); - - return ( - <> - {!defaultAnalyticsError ? ( - defaultAnalytics ? ( - -
- - - ({ - avatar_url: user?.created_by__avatar_url, - firstName: user?.created_by__first_name, - lastName: user?.created_by__last_name, - display_name: user?.created_by__display_name, - count: user?.count, - id: user?.created_by__id, - }))} - title={t("workspace_analytics.most_work_items_created.title")} - emptyStateMessage={t("workspace_analytics.most_work_items_created.empty_state")} - workspaceSlug={workspaceSlug?.toString() ?? ""} - /> - ({ - avatar_url: user?.assignees__avatar_url, - firstName: user?.assignees__first_name, - lastName: user?.assignees__last_name, - display_name: user?.assignees__display_name, - count: user?.count, - id: user?.assignees__id, - }))} - title={t("workspace_analytics.most_work_items_closed.title")} - emptyStateMessage={t("workspace_analytics.most_work_items_closed.empty_state")} - workspaceSlug={workspaceSlug?.toString() ?? ""} - /> -
- -
-
-
- ) : ( - - - - - - - ) - ) : ( -
-
-

{t("workspace_analytics.error")}

-
- -
-
-
- )} - - ); -}; diff --git a/web/core/components/analytics/scope-and-demand/scope.tsx b/web/core/components/analytics/scope-and-demand/scope.tsx deleted file mode 100644 index 13cd60d5661..00000000000 --- a/web/core/components/analytics/scope-and-demand/scope.tsx +++ /dev/null @@ -1,99 +0,0 @@ -// plane types -import { useTranslation } from "@plane/i18n"; -import { IDefaultAnalyticsUser } from "@plane/types"; -// plane ui -import { Card } from "@plane/ui"; -// components -import { BarGraph, ProfileEmptyState } from "@/components/ui"; -// helpers -import { getFileURL } from "@/helpers/file.helper"; -// image -import emptyBarGraph from "@/public/empty-state/empty_bar_graph.svg"; - -type Props = { - pendingUnAssignedIssuesUser: IDefaultAnalyticsUser | undefined; - pendingAssignedIssues: IDefaultAnalyticsUser[]; -}; - -export const AnalyticsScope: React.FC = ({ pendingUnAssignedIssuesUser, pendingAssignedIssues }) => { - const { t } = useTranslation(); - return ( - -
-
-
-
{t("workspace_analytics.pending_work_items.title")}
- {pendingUnAssignedIssuesUser && ( -
- {t("unassigned")}: {pendingUnAssignedIssuesUser.count} -
- )} -
- - {pendingAssignedIssues && pendingAssignedIssues.length > 0 ? ( - `#f97316`} - customYAxisTickValues={pendingAssignedIssues.map((d) => (d.count > 0 ? d.count : 50))} - tooltip={(datum) => { - const assignee = pendingAssignedIssues.find((a) => a.assignees__id === `${datum.indexValue}`); - - return ( -
- - {assignee ? assignee.assignees__display_name : "No assignee"}:{" "} - - {datum.value} -
- ); - }} - axisBottom={{ - renderTick: (datum) => { - const assignee = pendingAssignedIssues[datum.tickIndex] ?? ""; - - if (assignee && assignee?.assignees__avatar_url && assignee?.assignees__avatar_url !== "") - return ( - - - - ); - else - return ( - - - - {datum.value ? `${assignee.assignees__display_name}`.toUpperCase()[0] : "?"} - - - ); - }, - }} - margin={{ top: 20 }} - theme={{ - axis: {}, - }} - /> - ) : ( -
- -
- )} -
-
-
- ); -}; diff --git a/web/core/components/analytics/scope-and-demand/year-wise-issues.tsx b/web/core/components/analytics/scope-and-demand/year-wise-issues.tsx deleted file mode 100644 index 0f469db7022..00000000000 --- a/web/core/components/analytics/scope-and-demand/year-wise-issues.tsx +++ /dev/null @@ -1,64 +0,0 @@ -// ui -import { useTranslation } from "@plane/i18n"; -import { IDefaultAnalyticsResponse } from "@plane/types"; -import { Card } from "@plane/ui"; -import { LineGraph, ProfileEmptyState } from "@/components/ui"; -// image -import { MONTHS_LIST } from "@/constants/calendar"; -import emptyGraph from "@/public/empty-state/empty_graph.svg"; -// types -// constants - -type Props = { - defaultAnalytics: IDefaultAnalyticsResponse; -}; - -export const AnalyticsYearWiseIssues: React.FC = ({ defaultAnalytics }) => { - const { t } = useTranslation(); - return ( - -

{t("workspace_analytics.work_items_closed_in_a_year.title")}

- {defaultAnalytics.issue_completed_month_wise.length > 0 ? ( - ({ - x: t(month.shortTitle), - y: - defaultAnalytics.issue_completed_month_wise.find((data) => data.month === parseInt(index, 10)) - ?.count || 0, - })), - }, - ]} - customYAxisTickValues={defaultAnalytics.issue_completed_month_wise.map((data) => data.count)} - height="300px" - colors={(datum) => datum.color} - curve="monotoneX" - margin={{ top: 20 }} - enableSlices="x" - sliceTooltip={(datum) => ( -
- {datum.slice.points[0].data.yFormatted} - {t("workspace_analytics.work_items_closed_in")} - {datum.slice.points[0].data.xFormatted} -
- )} - theme={{ - background: "rgb(var(--color-background-100))", - }} - enableArea - /> - ) : ( -
- -
- )} -
- ); -}; diff --git a/web/core/components/issues/filters.tsx b/web/core/components/issues/filters.tsx index 3f759d0d145..22612a3f1d1 100644 --- a/web/core/components/issues/filters.tsx +++ b/web/core/components/issues/filters.tsx @@ -17,7 +17,6 @@ import { isIssueFilterActive } from "@/helpers/filter.helper"; import { useLabel, useProjectState, useMember, useIssues } from "@/hooks/store"; // plane web types import { TProject } from "@/plane-web/types"; -import { ProjectAnalyticsModal } from "../analytics"; import { WorkItemsModal } from "../analytics-v2/work-items/modal"; type Props = { diff --git a/web/core/constants/fetch-keys.ts b/web/core/constants/fetch-keys.ts index ec5de760f6f..d5bbf3ed65c 100644 --- a/web/core/constants/fetch-keys.ts +++ b/web/core/constants/fetch-keys.ts @@ -1,4 +1,4 @@ -import { IAnalyticsParams, IJiraMetadata } from "@plane/types"; +import { IJiraMetadata } from "@plane/types"; const paramsToKey = (params: any) => { const { @@ -237,14 +237,6 @@ export const MY_PAGES_LIST = (pageId: string) => `MY_PAGE_LIST_${pageId}`; export const ESTIMATES_LIST = (projectId: string) => `ESTIMATES_LIST_${projectId.toUpperCase()}`; export const ESTIMATE_DETAILS = (estimateId: string) => `ESTIMATE_DETAILS_${estimateId.toUpperCase()}`; -// analytics -export const ANALYTICS = (workspaceSlug: string, params: IAnalyticsParams) => - `ANALYTICS${workspaceSlug.toUpperCase()}_${params.x_axis}_${params.y_axis}_${ - params.segment - }_${params.project?.toString()}`; -export const DEFAULT_ANALYTICS = (workspaceSlug: string, params?: Partial) => - `DEFAULT_ANALYTICS_${workspaceSlug.toUpperCase()}_${params?.project?.toString()}_${params?.cycle}_${params?.module}`; - // profile export const USER_PROFILE_DATA = (workspaceSlug: string, userId: string) => `USER_PROFILE_ACTIVITY_${workspaceSlug.toUpperCase()}_${userId.toUpperCase()}`; diff --git a/web/core/services/analytics.service.ts b/web/core/services/analytics.service.ts deleted file mode 100644 index 991407d1656..00000000000 --- a/web/core/services/analytics.service.ts +++ /dev/null @@ -1,63 +0,0 @@ -// services -import { - IAnalyticsParams, - IAnalyticsResponse, - IDefaultAnalyticsResponse, - IExportAnalyticsFormData, - ISaveAnalyticsFormData, -} from "@plane/types"; -import { API_BASE_URL } from "@/helpers/common.helper"; -import { APIService } from "@/services/api.service"; -// types -// helpers - -export class AnalyticsService extends APIService { - constructor() { - super(API_BASE_URL); - } - - async getAnalytics(workspaceSlug: string, params: IAnalyticsParams): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/analytics/`, { - params: { - ...params, - project: params?.project ? params.project.toString() : null, - }, - }) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async getDefaultAnalytics( - workspaceSlug: string, - params?: Partial - ): Promise { - return this.get(`/api/workspaces/${workspaceSlug}/default-analytics/`, { - params: { - ...params, - project: params?.project ? params.project.toString() : null, - }, - }) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async saveAnalytics(workspaceSlug: string, data: ISaveAnalyticsFormData): Promise { - return this.post(`/api/workspaces/${workspaceSlug}/analytic-view/`, data) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } - - async exportAnalytics(workspaceSlug: string, data: IExportAnalyticsFormData): Promise { - return this.post(`/api/workspaces/${workspaceSlug}/export-analytics/`, data) - .then((response) => response?.data) - .catch((error) => { - throw error?.response?.data; - }); - } -} diff --git a/web/helpers/analytics.helper.ts b/web/helpers/analytics.helper.ts deleted file mode 100644 index cee4b40f352..00000000000 --- a/web/helpers/analytics.helper.ts +++ /dev/null @@ -1,152 +0,0 @@ -// nivo -import { BarDatum } from "@nivo/bar"; -// plane imports -import { ANALYTICS_DATE_KEYS, STATE_GROUPS } from "@plane/constants"; -import { IAnalyticsData, IAnalyticsParams, IAnalyticsResponse, TStateGroups } from "@plane/types"; -// constants -import { MONTHS_LIST } from "@/constants/calendar"; -// helpers -import { addSpaceIfCamelCase, capitalizeFirstLetter, generateRandomColor } from "@/helpers/string.helper"; - -export const convertResponseToBarGraphData = ( - response: IAnalyticsData | undefined, - params: IAnalyticsParams -): { data: BarDatum[]; xAxisKeys: string[] } => { - if (!response || !(typeof response === "object") || Object.keys(response).length === 0) - return { data: [], xAxisKeys: [] }; - - const data: BarDatum[] = []; - - let xAxisKeys: string[] = []; - const yAxisKey = params.y_axis === "issue_count" ? "count" : "estimate"; - - Object.keys(response).forEach((key) => { - const segments: { [key: string]: number } = {}; - - if (params.segment) { - response[key].map((item: any) => { - segments[item.segment ?? "None"] = item[yAxisKey] ?? 0; - - // store the segment in the xAxisKeys array - if (!xAxisKeys.includes(item.segment ?? "None")) xAxisKeys.push(item.segment ?? "None"); - }); - - data.push({ - name: ANALYTICS_DATE_KEYS.includes(params.x_axis) - ? renderMonthAndYear(key) - : params.x_axis === "priority" || params.x_axis === "state__group" - ? capitalizeFirstLetter(key) - : key, - ...segments, - }); - } else { - xAxisKeys = [yAxisKey]; - - const item = response[key][0]; - - data.push({ - name: ANALYTICS_DATE_KEYS.includes(params.x_axis) - ? renderMonthAndYear(item.dimension) - : params.x_axis === "priority" || params.x_axis === "state__group" - ? capitalizeFirstLetter(item.dimension ?? "None") - : (item.dimension ?? "None"), - [yAxisKey]: item[yAxisKey] ?? 0, - }); - } - }); - - return { data, xAxisKeys }; -}; - -export const generateBarColor = ( - value: string, - analytics: IAnalyticsResponse, - params: IAnalyticsParams, - type: "x_axis" | "segment" -): string => { - let color: string | undefined = generateRandomColor(value); - - if (!analytics) return color; - - if (params[type] === "state_id") - color = analytics?.extras.state_details.find((s) => s.state_id === value)?.state__color; - - if (params[type] === "labels__id") - color = analytics?.extras.label_details.find((l) => l.labels__id === value)?.labels__color ?? undefined; - - if (params[type] === "state__group") color = STATE_GROUPS[value.toLowerCase() as TStateGroups]?.color ?? undefined; - - if (params[type] === "priority") { - const priority = value.toLowerCase(); - - color = - priority === "urgent" - ? "#ef4444" - : priority === "high" - ? "#f97316" - : priority === "medium" - ? "#eab308" - : priority === "low" - ? "#22c55e" - : "#ced4da"; - } - - return color ?? generateRandomColor(value); -}; - -export const generateDisplayName = ( - value: string, - analytics: IAnalyticsResponse, - params: IAnalyticsParams, - type: "x_axis" | "segment" -): string => { - let displayName = addSpaceIfCamelCase(value); - - if (!analytics) return displayName; - - if (params[type] === "assignees__id") - displayName = - analytics?.extras.assignee_details.find((a) => a.assignees__id === value)?.assignees__display_name ?? - "No assignee"; - - if (params[type] === "issue_cycle__cycle_id") - displayName = - analytics?.extras.cycle_details.find((c) => c.issue_cycle__cycle_id === value)?.issue_cycle__cycle__name ?? - "None"; - - if (params[type] === "issue_module__module_id") - displayName = - analytics?.extras.module_details.find((m) => m.issue_module__module_id === value)?.issue_module__module__name ?? - "None"; - - if (params[type] === "labels__id") - displayName = analytics?.extras.label_details.find((l) => l.labels__id === value)?.labels__name ?? "None"; - - if (params[type] === "state_id") - displayName = analytics?.extras.state_details.find((s) => s.state_id === value)?.state__name ?? "None"; - - if (ANALYTICS_DATE_KEYS.includes(params.segment ?? "")) displayName = renderMonthAndYear(value); - - return displayName; -}; - -export const renderMonthAndYear = (date: string | number | null): string => { - if (!date || date === "") return ""; - - const monthNumber = parseInt(`${date}`.split("-")[1], 10); - const year = `${date}`.split("-")[0]; - - return (MONTHS_LIST[monthNumber]?.shortTitle || "None") + ` ${year ? year : ""}`; -}; - -export const MAX_CHART_LABEL_LENGTH = 15; -export const renderChartDynamicLabel = ( - label: string, - length: number = MAX_CHART_LABEL_LENGTH -): { label: string; length: number } => { - const currentLabel = label.substring(0, length); - return { - label: `${label.length > MAX_CHART_LABEL_LENGTH ? `${currentLabel.substring(0, MAX_CHART_LABEL_LENGTH - 3)}...` : currentLabel}`, - length: currentLabel.length, - }; -}; From 3934b4dbab1e7e154eb82a1d936956d11d28a288 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Mon, 2 Jun 2025 15:19:09 +0530 Subject: [PATCH 11/19] refactor: new analytics --- .../src/{analytics-v2 => analytics}/common.ts | 10 ++--- .../src/{analytics-v2 => analytics}/index.ts | 0 packages/constants/src/index.ts | 2 +- .../i18n/src/locales/cs/translations.json | 13 ------- .../i18n/src/locales/de/translations.json | 15 +------- .../i18n/src/locales/en/translations.json | 31 +++++----------- .../i18n/src/locales/es/translations.json | 13 ------- .../i18n/src/locales/fr/translations.json | 13 ------- .../i18n/src/locales/id/translations.json | 13 ------- .../i18n/src/locales/it/translations.json | 13 ------- .../i18n/src/locales/ja/translations.json | 13 ------- .../i18n/src/locales/ko/translations.json | 13 ------- .../i18n/src/locales/pl/translations.json | 13 ------- .../i18n/src/locales/pt-BR/translations.json | 13 ------- .../i18n/src/locales/ro/translations.json | 13 ------- .../i18n/src/locales/ru/translations.json | 13 ------- .../i18n/src/locales/sk/translations.json | 13 ------- .../i18n/src/locales/tr-TR/translations.json | 13 ------- .../i18n/src/locales/ua/translations.json | 13 ------- .../i18n/src/locales/vi-VN/translations.json | 13 ------- .../i18n/src/locales/zh-CN/translations.json | 13 ------- .../i18n/src/locales/zh-TW/translations.json | 13 ------- .../src/{analytics-v2.d.ts => analytics.d.ts} | 14 +++---- packages/types/src/index.d.ts | 2 +- .../(projects)/analytics/page.tsx | 4 +- .../[projectId]/cycles/(detail)/header.tsx | 2 +- .../cycles/(detail)/mobile-header.tsx | 2 +- .../issues/(list)/mobile-header.tsx | 2 +- .../[projectId]/modules/(detail)/header.tsx | 2 +- .../modules/(detail)/mobile-header.tsx | 2 +- web/ce/components/analytics-v2/tabs.ts | 11 ------ web/ce/components/analytics/tabs.ts | 11 ++++++ web/ce/store/analytics-v2.store.ts | 8 ---- web/ce/store/analytics.store.ts | 8 ++++ .../analytics-filter-actions.tsx | 4 +- .../analytics-section-wrapper.tsx | 0 .../analytics-wrapper.tsx | 0 .../empty-state.tsx | 6 +-- .../{analytics-v2 => analytics}/index.ts | 0 .../insight-card.tsx | 4 +- .../insight-table/data-table.tsx | 10 ++--- .../insight-table/index.ts | 0 .../insight-table/loader.tsx | 0 .../insight-table/root.tsx | 6 +-- .../{analytics-v2 => analytics}/loaders.tsx | 0 .../overview/active-project-item.tsx | 0 .../overview/active-projects.tsx | 4 +- .../overview/index.ts | 0 .../overview/project-insights.tsx | 33 +++++++++-------- .../overview/root.tsx | 0 .../select/analytics-params.tsx | 19 +++++----- .../select/duration.tsx | 8 ++-- .../select/project.tsx | 0 .../select/select-x-axis.tsx | 0 .../select/select-y-axis.tsx | 0 .../total-insights.tsx | 14 +++---- .../trend-piece.tsx | 0 .../work-items/created-vs-resolved.tsx | 35 ++++++++++-------- .../work-items/customized-insights.tsx | 10 ++--- .../work-items/index.ts | 0 .../work-items/modal/content.tsx | 4 +- .../work-items/modal/header.tsx | 0 .../work-items/modal/index.tsx | 4 +- .../work-items/priority-chart.tsx | 30 +++++++-------- .../work-items/root.tsx | 0 .../work-items/utils.ts | 0 .../work-items/workitems-insight-table.tsx | 10 ++--- web/core/components/issues/filters.tsx | 2 +- web/core/hooks/store/index.ts | 2 +- web/core/hooks/store/use-analytics-v2.ts | 11 ------ web/core/hooks/store/use-analytics.ts | 11 ++++++ ...ics-v2.service.ts => analytics.service.ts} | 31 +++++++--------- ...alytics-v2.store.ts => analytics.store.ts} | 16 ++++---- web/core/store/root.store.ts | 6 +-- web/ee/store/analytics-v2.store.ts | 8 ---- web/ee/store/analytics.store.ts | 8 ++++ .../empty-chart-area-dark.webp | Bin .../empty-chart-area-light.webp | Bin .../empty-chart-bar-dark.webp | Bin .../empty-chart-bar-light.webp | Bin .../empty-chart-radar-dark.webp | Bin .../empty-chart-radar-light.webp | Bin .../empty-grid-background-dark.webp | Bin .../empty-grid-background-light.webp | Bin .../empty-table-dark.webp | Bin .../empty-table-light.webp | Bin 86 files changed, 199 insertions(+), 444 deletions(-) rename packages/constants/src/{analytics-v2 => analytics}/common.ts (90%) rename packages/constants/src/{analytics-v2 => analytics}/index.ts (100%) rename packages/types/src/{analytics-v2.d.ts => analytics.d.ts} (73%) delete mode 100644 web/ce/components/analytics-v2/tabs.ts create mode 100644 web/ce/components/analytics/tabs.ts delete mode 100644 web/ce/store/analytics-v2.store.ts create mode 100644 web/ce/store/analytics.store.ts rename web/core/components/{analytics-v2 => analytics}/analytics-filter-actions.tsx (88%) rename web/core/components/{analytics-v2 => analytics}/analytics-section-wrapper.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/analytics-wrapper.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/empty-state.tsx (89%) rename web/core/components/{analytics-v2 => analytics}/index.ts (100%) rename web/core/components/{analytics-v2 => analytics}/insight-card.tsx (93%) rename web/core/components/{analytics-v2 => analytics}/insight-table/data-table.tsx (95%) rename web/core/components/{analytics-v2 => analytics}/insight-table/index.ts (100%) rename web/core/components/{analytics-v2 => analytics}/insight-table/loader.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/insight-table/root.tsx (90%) rename web/core/components/{analytics-v2 => analytics}/loaders.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/overview/active-project-item.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/overview/active-projects.tsx (93%) rename web/core/components/{analytics-v2 => analytics}/overview/index.ts (100%) rename web/core/components/{analytics-v2 => analytics}/overview/project-insights.tsx (80%) rename web/core/components/{analytics-v2 => analytics}/overview/root.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/select/analytics-params.tsx (80%) rename web/core/components/{analytics-v2 => analytics}/select/duration.tsx (76%) rename web/core/components/{analytics-v2 => analytics}/select/project.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/select/select-x-axis.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/select/select-y-axis.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/total-insights.tsx (85%) rename web/core/components/{analytics-v2 => analytics}/trend-piece.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/work-items/created-vs-resolved.tsx (77%) rename web/core/components/{analytics-v2 => analytics}/work-items/customized-insights.tsx (84%) rename web/core/components/{analytics-v2 => analytics}/work-items/index.ts (100%) rename web/core/components/{analytics-v2 => analytics}/work-items/modal/content.tsx (95%) rename web/core/components/{analytics-v2 => analytics}/work-items/modal/header.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/work-items/modal/index.tsx (96%) rename web/core/components/{analytics-v2 => analytics}/work-items/priority-chart.tsx (89%) rename web/core/components/{analytics-v2 => analytics}/work-items/root.tsx (100%) rename web/core/components/{analytics-v2 => analytics}/work-items/utils.ts (100%) rename web/core/components/{analytics-v2 => analytics}/work-items/workitems-insight-table.tsx (95%) delete mode 100644 web/core/hooks/store/use-analytics-v2.ts create mode 100644 web/core/hooks/store/use-analytics.ts rename web/core/services/{analytics-v2.service.ts => analytics.service.ts} (70%) rename web/core/store/{analytics-v2.store.ts => analytics.store.ts} (82%) delete mode 100644 web/ee/store/analytics-v2.store.ts create mode 100644 web/ee/store/analytics.store.ts rename web/public/empty-state/{analytics-v2 => analytics}/empty-chart-area-dark.webp (100%) rename web/public/empty-state/{analytics-v2 => analytics}/empty-chart-area-light.webp (100%) rename web/public/empty-state/{analytics-v2 => analytics}/empty-chart-bar-dark.webp (100%) rename web/public/empty-state/{analytics-v2 => analytics}/empty-chart-bar-light.webp (100%) rename web/public/empty-state/{analytics-v2 => analytics}/empty-chart-radar-dark.webp (100%) rename web/public/empty-state/{analytics-v2 => analytics}/empty-chart-radar-light.webp (100%) rename web/public/empty-state/{analytics-v2 => analytics}/empty-grid-background-dark.webp (100%) rename web/public/empty-state/{analytics-v2 => analytics}/empty-grid-background-light.webp (100%) rename web/public/empty-state/{analytics-v2 => analytics}/empty-table-dark.webp (100%) rename web/public/empty-state/{analytics-v2 => analytics}/empty-table-light.webp (100%) diff --git a/packages/constants/src/analytics-v2/common.ts b/packages/constants/src/analytics/common.ts similarity index 90% rename from packages/constants/src/analytics-v2/common.ts rename to packages/constants/src/analytics/common.ts index 5d1c4cad1f1..cf0624e9137 100644 --- a/packages/constants/src/analytics-v2/common.ts +++ b/packages/constants/src/analytics/common.ts @@ -1,4 +1,4 @@ -import { TAnalyticsTabsV2Base } from "@plane/types"; +import { TAnalyticsTabsBase } from "@plane/types"; import { ChartXAxisProperty, ChartYAxisMetric } from "../chart"; export interface IInsightField { @@ -11,7 +11,7 @@ export interface IInsightField { }; } -export const insightsFields: Record = { +export const insightsFields: Record = { overview: [ { key: "total_users", @@ -94,7 +94,7 @@ export const insightsFields: Record = { ], }; -export const ANALYTICS_V2_DURATION_FILTER_OPTIONS = [ +export const ANALYTICS_DURATION_FILTER_OPTIONS = [ { name: "Yesterday", value: "yesterday", @@ -113,7 +113,7 @@ export const ANALYTICS_V2_DURATION_FILTER_OPTIONS = [ }, ]; -export const ANALYTICS_V2_X_AXIS_VALUES: { value: ChartXAxisProperty; label: string }[] = [ +export const ANALYTICS_X_AXIS_VALUES: { value: ChartXAxisProperty; label: string }[] = [ { value: ChartXAxisProperty.STATES, label: "State name", @@ -164,7 +164,7 @@ export const ANALYTICS_V2_X_AXIS_VALUES: { value: ChartXAxisProperty; label: str }, ]; -export const ANALYTICS_V2_Y_AXIS_VALUES: { value: ChartYAxisMetric; label: string }[] = [ +export const ANALYTICS_Y_AXIS_VALUES: { value: ChartYAxisMetric; label: string }[] = [ { value: ChartYAxisMetric.WORK_ITEM_COUNT, label: "Work item", diff --git a/packages/constants/src/analytics-v2/index.ts b/packages/constants/src/analytics/index.ts similarity index 100% rename from packages/constants/src/analytics-v2/index.ts rename to packages/constants/src/analytics/index.ts diff --git a/packages/constants/src/index.ts b/packages/constants/src/index.ts index d6c28234c38..0f5610350c4 100644 --- a/packages/constants/src/index.ts +++ b/packages/constants/src/index.ts @@ -33,4 +33,4 @@ export * from "./emoji"; export * from "./subscription"; export * from "./settings"; export * from "./icon"; -export * from "./analytics-v2"; +export * from "./analytics"; diff --git a/packages/i18n/src/locales/cs/translations.json b/packages/i18n/src/locales/cs/translations.json index 0ffb1a58c53..3f4008590f3 100644 --- a/packages/i18n/src/locales/cs/translations.json +++ b/packages/i18n/src/locales/cs/translations.json @@ -1317,19 +1317,6 @@ "custom": "Vlastní analytika" }, "empty_state": { - "general": { - "title": "Sledujte pokrok, vytížení a alokace. Identifikujte trendy, odstraňte překážky a zrychlete práci", - "description": "Sledujte rozsah vs. poptávku, odhady a rozsah. Zjistěte výkonnost členů a týmů, zajistěte včasné dokončení projektů.", - "primary_button": { - "text": "Začněte první projekt", - "comic": { - "title": "Analytika funguje nejlépe s Cykly + Moduly", - "description": "Nejprve časově ohraničte práci do Cyklů a seskupte položky přesahující cyklus do Modulů. Najdete je v levém menu." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Pracovní položky přiřazené vám, rozdělené podle stavu, se zde zobrazí.", "title": "Zatím žádná data" diff --git a/packages/i18n/src/locales/de/translations.json b/packages/i18n/src/locales/de/translations.json index d53e8efeaf9..4bb1c4491c9 100644 --- a/packages/i18n/src/locales/de/translations.json +++ b/packages/i18n/src/locales/de/translations.json @@ -1317,19 +1317,6 @@ "custom": "Benutzerdefinierte Analysen" }, "empty_state": { - "general": { - "title": "Verfolgen Sie Fortschritt, Auslastung und Zuordnungen. Erkennen Sie Trends, entfernen Sie Blocker und beschleunigen Sie die Arbeit", - "description": "Behalten Sie Umfang vs. Nachfrage, Schätzungen und Umfang im Blick. Verfolgen Sie die Leistung von Mitgliedern und Teams, um sicherzustellen, dass Projekte pünktlich abgeschlossen werden.", - "primary_button": { - "text": "Erstes Projekt starten", - "comic": { - "title": "Analysen funktionieren am besten mit Zyklen + Modulen", - "description": "Begrenzen Sie zuerst Arbeit zeitlich in Zyklen und gruppieren Sie die übergreifenden Elemente in Module. Sie finden sie im linken Menü." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Ihnen zugewiesene Arbeitselemente, aufgeschlüsselt nach Status, werden hier angezeigt.", "title": "Noch keine Daten" @@ -2464,4 +2451,4 @@ "previously_edited_by": "Zuvor bearbeitet von", "edited_by": "Bearbeitet von" } -} +} \ No newline at end of file diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index bb5cfac69be..0f4ae6431e4 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -1159,19 +1159,6 @@ "scope_and_demand": "Scope and Demand", "custom": "Custom Analytics" }, - "empty_state": { - "general": { - "title": "Track progress, workloads, and allocations. Spot trends, remove blockers, and move work faster", - "description": "See scope versus demand, estimates, and scope creep. Get performance by team members and teams, and make sure your project runs on time.", - "primary_button": { - "text": "Start your first project", - "comic": { - "title": "Analytics works best with Cycles + Modules", - "description": "First, timebox your work items into Cycles and, if you can, group work items that span more than a cycle into Modules. Check out both on the left nav." - } - } - } - }, "total": "Total {entity}", "started_work_items": "Started {entity}", "backlog_work_items": "Backlog {entity}", @@ -1184,7 +1171,7 @@ "active_projects": "Active Projects", "customized_insights": "Customized Insights", "created_vs_resolved": "Created vs Resolved", - "empty_state_v2": { + "empty_state": { "project_insights": { "title": "No data yet", "description": "Work items assigned to you, broken down by state, will show up here." @@ -1308,23 +1295,23 @@ } }, "account_settings": { - "profile":{}, - "preferences":{ + "profile": {}, + "preferences": { "heading": "Preferences", "description": "Customize your app experience the way you work" }, - "notifications":{ + "notifications": { "heading": "Email notifications", - "description": "Stay in the loop on Work items you are subscribed to. Enable this to get notified." + "description": "Stay in the loop on Work items you are subscribed to. Enable this to get notified." }, - "security":{ + "security": { "heading": "Security" }, - "api_tokens":{ + "api_tokens": { "heading": "Personal Access Tokens", "description": "Generate secure API tokens to integrate your data with external systems and applications." }, - "activity":{ + "activity": { "heading": "Activity", "description": "Track your recent actions and changes across all projects and work items." } @@ -1396,7 +1383,7 @@ }, "billing_and_plans": { "heading": "Billing & Plans", - "description":"Choose your plan, manage subscriptions, and easily upgrade as your needs grow.", + "description": "Choose your plan, manage subscriptions, and easily upgrade as your needs grow.", "title": "Billing & Plans", "current_plan": "Current plan", "free_plan": "You are currently using the free plan", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 0fbe024949a..04ba05155a0 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -1320,19 +1320,6 @@ "custom": "Análisis Personalizado" }, "empty_state": { - "general": { - "title": "Rastrea el progreso, cargas de trabajo y asignaciones. Identifica tendencias, elimina bloqueos y mueve el trabajo más rápido", - "description": "Observa el alcance versus la demanda, estimaciones y el aumento del alcance. Obtén el rendimiento por miembros del equipo y equipos, y asegúrate de que tu proyecto se ejecute a tiempo.", - "primary_button": { - "text": "Inicia tu primer proyecto", - "comic": { - "title": "El análisis funciona mejor con Ciclos + Módulos", - "description": "Primero, organiza tus elementos de trabajo en Ciclos y, si puedes, agrupa los elementos de trabajo que abarcan más de un ciclo en Módulos. Revisa ambos en la navegación izquierda." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Los elementos de trabajo asignados a ti, desglosados por estado, aparecerán aquí.", "title": "Aún no hay datos" diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 65b7081ee65..bf1cefc7ba2 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -1318,19 +1318,6 @@ "custom": "Analytique Personnalisée" }, "empty_state": { - "general": { - "title": "Suivez les progrès, les charges de travail et les allocations. Repérez les tendances, supprimez les blocages et accélérez le travail", - "description": "Visualisez la portée par rapport à la demande, les estimations et l'augmentation de la portée. Obtenez les performances par membres de l'équipe et équipes, et assurez-vous que votre projet se déroule dans les délais.", - "primary_button": { - "text": "Commencez votre premier projet", - "comic": { - "title": "L'analytique fonctionne mieux avec les Cycles + Modules", - "description": "D'abord, planifiez vos éléments de travail dans des Cycles et, si possible, regroupez les éléments de travail qui s'étendent sur plus d'un cycle dans des Modules. Consultez les deux dans la navigation de gauche." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Les éléments de travail qui vous sont assignés, répartis par état, s'afficheront ici.", "title": "Pas encore de données" diff --git a/packages/i18n/src/locales/id/translations.json b/packages/i18n/src/locales/id/translations.json index cb75a09162b..ef886f48588 100644 --- a/packages/i18n/src/locales/id/translations.json +++ b/packages/i18n/src/locales/id/translations.json @@ -1317,19 +1317,6 @@ "custom": "Analitik Kustom" }, "empty_state": { - "general": { - "title": "Lacak kemajuan, beban kerja, dan alokasi. Temukan tren, hilangkan penghalang, dan percepat pekerjaan", - "description": "Lihat lingkup dibandingkan permintaan, perkiraan, dan lingkup cree. Dapatkan kinerja oleh anggota tim dan tim, dan pastikan proyek Anda berjalan tepat waktu.", - "primary_button": { - "text": "Mulai proyek pertama Anda", - "comic": { - "title": "Analitik bekerja terbaik dengan Siklus + Modul", - "description": "Pertama, bagi item kerja Anda ke dalam Siklus dan, jika memungkinkan, kelompokkan item kerja yang menjangkau lebih dari satu siklus ke dalam Modul. Lihat kedua fungsi pada navigasi kiri." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Item pekerjaan yang ditugaskan kepada Anda, dipecah berdasarkan status, akan muncul di sini.", "title": "Belum ada data" diff --git a/packages/i18n/src/locales/it/translations.json b/packages/i18n/src/locales/it/translations.json index b391583b7cd..1deafbe9e1a 100644 --- a/packages/i18n/src/locales/it/translations.json +++ b/packages/i18n/src/locales/it/translations.json @@ -1316,19 +1316,6 @@ "custom": "Analisi personalizzata" }, "empty_state": { - "general": { - "title": "Traccia il progresso, i carichi di lavoro e le assegnazioni. Individua tendenze, rimuovi gli ostacoli e accelera il lavoro", - "description": "Visualizza l'ambito rispetto alla domanda, le stime e il fenomeno del scope creep. Ottieni le prestazioni dei membri del team e dei team, e assicurati che il tuo progetto rispetti le scadenze.", - "primary_button": { - "text": "Inizia il tuo primo progetto", - "comic": { - "title": "Le analisi funzionano meglio con Cicli + Moduli", - "description": "Prima, definisci i tuoi elementi di lavoro in cicli e, se puoi, raggruppa quelli che si estendono per più di un ciclo in moduli. Dai un'occhiata ad entrambi nel menu di sinistra." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Gli elementi di lavoro assegnati a te, suddivisi per stato, verranno visualizzati qui.", "title": "Nessun dato disponibile" diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 1937925675b..3b623c728ae 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -1318,19 +1318,6 @@ "custom": "カスタムアナリティクス" }, "empty_state": { - "general": { - "title": "進捗、ワークロード、割り当てを追跡。傾向を把握し、ブロッカーを解消して、作業をより速く進めましょう", - "description": "スコープと需要、見積もり、スコープクリープを確認できます。チームメンバーとチームのパフォーマンスを把握し、プロジェクトが予定通りに進むようにします。", - "primary_button": { - "text": "最初のプロジェクトを開始", - "comic": { - "title": "アナリティクスはサイクル + モジュールで最も効果を発揮", - "description": "まず、作業項目をサイクルでタイムボックス化し、可能であれば、複数のサイクルにまたがる作業項目をモジュールにグループ化します。左のナビゲーションで両方を確認してください。" - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "あなたに割り当てられた作業項目は、ステータスごとに分類されてここに表示されます。", "title": "まだデータがありません" diff --git a/packages/i18n/src/locales/ko/translations.json b/packages/i18n/src/locales/ko/translations.json index 68e2020cebb..65f41021d3d 100644 --- a/packages/i18n/src/locales/ko/translations.json +++ b/packages/i18n/src/locales/ko/translations.json @@ -1319,19 +1319,6 @@ "custom": "맞춤형 분석" }, "empty_state": { - "general": { - "title": "진행 상황, 작업량 및 할당을 추적하세요. 트렌드를 파악하고, 차단 요소를 제거하며, 작업을 더 빠르게 진행하세요", - "description": "범위 대 수요, 추정치 및 범위 크리프를 확인하세요. 팀원과 팀의 성과를 확인하고 프로젝트가 제시간에 진행되도록 하세요.", - "primary_button": { - "text": "첫 번째 프로젝트 시작", - "comic": { - "title": "분석은 주기 + 모듈과 함께 작동합니다", - "description": "먼저 작업 항목을 주기로 시간 상자화하고, 주기를 초과하는 작업 항목을 모듈로 그룹화하세요. 왼쪽 탐색에서 둘 다 확인하세요." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "귀하에게 할당된 작업 항목이 상태별로 나누어 여기에 표시됩니다.", "title": "아직 데이터가 없습니다" diff --git a/packages/i18n/src/locales/pl/translations.json b/packages/i18n/src/locales/pl/translations.json index 5c0f144f5fb..817f2f22e9e 100644 --- a/packages/i18n/src/locales/pl/translations.json +++ b/packages/i18n/src/locales/pl/translations.json @@ -1319,19 +1319,6 @@ "custom": "Analizy niestandardowe" }, "empty_state": { - "general": { - "title": "Śledź postępy, obciążenie i alokacje. Identyfikuj trendy, usuwaj przeszkody i przyspieszaj pracę", - "description": "Obserwuj zakres vs. zapotrzebowanie, szacunki i zakres. Sprawdzaj wydajność członków i zespołów, upewnij się, że projekty kończą się na czas.", - "primary_button": { - "text": "Zacznij pierwszy projekt", - "comic": { - "title": "Analizy najlepiej działają z Cyklem + Modułami", - "description": "Najpierw ogranicz pracę w cyklach i grupuj zadania w modułach obejmujących wiele cykli. Znajdziesz je w menu po lewej." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Przypisane do Ciebie elementy pracy, podzielone według stanu, pojawią się tutaj.", "title": "Brak danych" diff --git a/packages/i18n/src/locales/pt-BR/translations.json b/packages/i18n/src/locales/pt-BR/translations.json index e6c7c2fdd66..da81730bf8c 100644 --- a/packages/i18n/src/locales/pt-BR/translations.json +++ b/packages/i18n/src/locales/pt-BR/translations.json @@ -1319,19 +1319,6 @@ "custom": "Análises Personalizadas" }, "empty_state": { - "general": { - "title": "Acompanhe o progresso, as cargas de trabalho e as alocações. Identifique tendências, remova bloqueadores e mova o trabalho mais rapidamente", - "description": "Veja o escopo versus a demanda, as estimativas e o aumento do escopo. Obtenha o desempenho por membros da equipe e equipes, e certifique-se de que seu projeto seja executado no prazo.", - "primary_button": { - "text": "Comece seu primeiro projeto", - "comic": { - "title": "A análise funciona melhor com Ciclos + Módulos", - "description": "Primeiro, coloque seus itens de trabalho em Ciclos e, se puder, agrupe os itens de trabalho que abrangem mais de um ciclo em Módulos. Confira ambos na navegação à esquerda." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Os itens de trabalho atribuídos a você, divididos por estado, aparecerão aqui.", "title": "Ainda não há dados" diff --git a/packages/i18n/src/locales/ro/translations.json b/packages/i18n/src/locales/ro/translations.json index 394a72ba343..2d36cbe5118 100644 --- a/packages/i18n/src/locales/ro/translations.json +++ b/packages/i18n/src/locales/ro/translations.json @@ -1317,19 +1317,6 @@ "custom": "Analitice personalizate" }, "empty_state": { - "general": { - "title": "Urmărește progresul, activitățile și alocările. Observă tendințele, elimină blocajele și accelerează munca", - "description": "Vezi raportul dintre activitățile asumate și cerere, estimările și eventualele extinderi neplanificate ale activităților asumate. Obține performanța pe membri și echipe și asigură-te că proiectul tău se încadrează în timp.", - "primary_button": { - "text": "Începe primul tău proiect", - "comic": { - "title": "Statisticile funcționează cel mai bine cu Cicluri + Module", - "description": "Mai întâi, încadrează-ți activitățile în Cicluri și, dacă poți, grupează-le pe cele care se întind pe mai multe cicluri în Module. Le găsești în meniul din stânga." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Elementele de lucru atribuite ție, împărțite pe stări, vor apărea aici.", "title": "Nu există date încă" diff --git a/packages/i18n/src/locales/ru/translations.json b/packages/i18n/src/locales/ru/translations.json index 96c7aca4557..d47a70d1c67 100644 --- a/packages/i18n/src/locales/ru/translations.json +++ b/packages/i18n/src/locales/ru/translations.json @@ -1319,19 +1319,6 @@ "custom": "Пользовательская аналитика" }, "empty_state": { - "general": { - "title": "Отслеживайте прогресс, загрузку и распределение ресурсов", - "description": "Анализируйте объёмы работ, оценивайте сроки и контролируйте выполнение проектов. Отслеживайте производительность команды и соблюдайте сроки.", - "primary_button": { - "text": "Начать первый проект", - "comic": { - "title": "Аналитика лучше всего работает с Циклами + Модулями", - "description": "Сначала группируйте рабочие элементы в Циклы, а при возможности - объединяйте рабочие элементы в Модули. Найдите оба раздела в левом меню." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Назначенные вам рабочие элементы, разбитые по статусам, появятся здесь.", "title": "Данных пока нет" diff --git a/packages/i18n/src/locales/sk/translations.json b/packages/i18n/src/locales/sk/translations.json index 0818db3ddca..775da7d6eb3 100644 --- a/packages/i18n/src/locales/sk/translations.json +++ b/packages/i18n/src/locales/sk/translations.json @@ -1319,19 +1319,6 @@ "custom": "Vlastná analytika" }, "empty_state": { - "general": { - "title": "Sledujte pokrok, vyťaženie a alokácie. Identifikujte trendy, odstráňte prekážky a zrýchlite prácu", - "description": "Sledujte rozsah vs. dopyt, odhady a rozsah. Zistite výkonnosť členov a tímov, zabezpečte včasné dokončenie projektov.", - "primary_button": { - "text": "Začnite prvý projekt", - "comic": { - "title": "Analytika funguje najlepšie s Cykly + Moduly", - "description": "Najprv časovo ohraničte prácu do cyklov a zoskupte položky presahujúce cyklus do modulov. Nájdete ich v ľavom menu." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Pracovné položky priradené vám, rozdelené podľa stavu, sa zobrazia tu.", "title": "Zatiaľ žiadne údaje" diff --git a/packages/i18n/src/locales/tr-TR/translations.json b/packages/i18n/src/locales/tr-TR/translations.json index 3e852c8c3bd..b1eab2f26a7 100644 --- a/packages/i18n/src/locales/tr-TR/translations.json +++ b/packages/i18n/src/locales/tr-TR/translations.json @@ -1320,19 +1320,6 @@ "custom": "Özel Analitik" }, "empty_state": { - "general": { - "title": "İlerlemeyi, iş yükünü ve tahsisatları izleyin. Eğilimleri tespit edin, engelleri kaldırın ve işleri hızlandırın", - "description": "Kapsam ve talep, tahminler ve kapsam genişlemesini görün. Takım üyeleri ve ekiplerin performansını izleyin ve projenizin zamanında ilerlemesini sağlayın.", - "primary_button": { - "text": "İlk projenizi başlatın", - "comic": { - "title": "Analitik Döngüler + Modüllerle en iyi şekilde çalışır", - "description": "Öncelikle, iş öğelerinizi Döngülere zamanlayın ve mümkünse, bir döngüden uzun süren iş öğelerini Modüllerde gruplayın. Her ikisini de sol gezintide bulabilirsiniz." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Size atanan iş öğeleri, duruma göre ayrılarak burada gösterilecektir.", "title": "Henüz veri yok" diff --git a/packages/i18n/src/locales/ua/translations.json b/packages/i18n/src/locales/ua/translations.json index c15c409e5d2..2d4550e69c1 100644 --- a/packages/i18n/src/locales/ua/translations.json +++ b/packages/i18n/src/locales/ua/translations.json @@ -1319,19 +1319,6 @@ "custom": "Користувацька аналітика" }, "empty_state": { - "general": { - "title": "Відстежуйте прогрес, навантаження й розподіл. Виявляйте тенденції, усувайте перешкоди й прискорюйте роботу", - "description": "Стежте за обсягом проти попиту, оцінками та обсягом. Визначайте ефективність учасників і команд, аби вчасно виконувати проєкти.", - "primary_button": { - "text": "Розпочніть перший проєкт", - "comic": { - "title": "Аналітика найкраще працює з Циклами + Модулями", - "description": "Спочатку обмежте роботу в часі через Цикли та згрупуйте робочі одиниці, які тривають довше, у Модулі. Все це в лівому меню." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Призначені вам робочі елементи, розбиті за станом, з’являться тут.", "title": "Ще немає даних" diff --git a/packages/i18n/src/locales/vi-VN/translations.json b/packages/i18n/src/locales/vi-VN/translations.json index 490f1236a97..c936480fbf3 100644 --- a/packages/i18n/src/locales/vi-VN/translations.json +++ b/packages/i18n/src/locales/vi-VN/translations.json @@ -1318,19 +1318,6 @@ "custom": "Phân tích tùy chỉnh" }, "empty_state": { - "general": { - "title": "Theo dõi tiến độ, khối lượng công việc và phân công. Khám phá xu hướng, loại bỏ rào cản và đẩy nhanh công việc", - "description": "Xem phạm vi so với nhu cầu, ước tính và mở rộng phạm vi. Nhận hiệu suất của thành viên nhóm và nhóm, đảm bảo dự án của bạn đúng tiến độ.", - "primary_button": { - "text": "Bắt đầu dự án đầu tiên của bạn", - "comic": { - "title": "Phân tích hoạt động tốt nhất trong chu kỳ + mô-đun", - "description": "Đầu tiên, giới hạn mục công việc của bạn trong chu kỳ và nếu có thể, nhóm mục công việc kéo dài nhiều chu kỳ thành mô-đun. Xem cả hai trong thanh điều hướng bên trái." - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "Các hạng mục công việc được giao cho bạn, phân loại theo trạng thái, sẽ hiển thị tại đây.", "title": "Chưa có dữ liệu" diff --git a/packages/i18n/src/locales/zh-CN/translations.json b/packages/i18n/src/locales/zh-CN/translations.json index f68a1473214..94cbd206884 100644 --- a/packages/i18n/src/locales/zh-CN/translations.json +++ b/packages/i18n/src/locales/zh-CN/translations.json @@ -1318,19 +1318,6 @@ "custom": "自定义分析" }, "empty_state": { - "general": { - "title": "跟踪进度、工作量和分配。发现趋势、消除障碍并加快工作进度", - "description": "查看范围与需求、估算和范围蔓延。获取团队成员和团队的表现,确保您的项目按时运行。", - "primary_button": { - "text": "开始您的第一个项目", - "comic": { - "title": "分析在周期 + 模块中效果最佳", - "description": "首先,将您的工作项限定在周期中,如果可能的话,将跨越多个周期的工作项分组到模块中。在左侧导航栏中查看这两项。" - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "分配给您的工作项将按状态分类显示在此处。", "title": "暂无数据" diff --git a/packages/i18n/src/locales/zh-TW/translations.json b/packages/i18n/src/locales/zh-TW/translations.json index e331073ac61..8885c25a258 100644 --- a/packages/i18n/src/locales/zh-TW/translations.json +++ b/packages/i18n/src/locales/zh-TW/translations.json @@ -1319,19 +1319,6 @@ "custom": "自訂分析" }, "empty_state": { - "general": { - "title": "追蹤進度、工作量和分配。發現趨勢、移除阻礙,加快工作進展", - "description": "檢視範圍與需求、評估和範圍擴展。取得團隊成員和團隊的績效,確保您的專案按時進行。", - "primary_button": { - "text": "開始您的第一個專案", - "comic": { - "title": "分析最適合搭配週期 + 模組使用", - "description": "首先,將您的工作事項時間區段到週期中,如果可以的話,將跨週期的工作事項分組到模組中。請檢視左側導覽列中的兩個功能。" - } - } - } - }, - "empty_state_v2": { "customized_insights": { "description": "指派給您的工作項目將依狀態分類顯示在此處。", "title": "尚無資料" diff --git a/packages/types/src/analytics-v2.d.ts b/packages/types/src/analytics.d.ts similarity index 73% rename from packages/types/src/analytics-v2.d.ts rename to packages/types/src/analytics.d.ts index 1a8652b70a3..7b8bc7f75ac 100644 --- a/packages/types/src/analytics-v2.d.ts +++ b/packages/types/src/analytics.d.ts @@ -1,21 +1,21 @@ import { ChartXAxisProperty, ChartYAxisMetric } from "@plane/constants"; import { TChartData } from "./charts"; -export type TAnalyticsTabsV2Base = "overview" | "work-items"; -export type TAnalyticsGraphsV2Base = "projects" | "work-items" | "custom-work-items"; +export type TAnalyticsTabsBase = "overview" | "work-items"; +export type TAnalyticsGraphsBase = "projects" | "work-items" | "custom-work-items"; // service types -export interface IAnalyticsResponseV2 { +export interface IAnalyticsResponse { [key: string]: any; } -export interface IAnalyticsResponseFieldsV2 { +export interface IAnalyticsResponseFields { count: number; filter_count: number; } -export interface IAnalyticsRadarEntityV2 { +export interface IAnalyticsRadarEntity { key: string; name: string; count: number; @@ -23,7 +23,7 @@ export interface IAnalyticsRadarEntityV2 { // chart types -export interface IChartResponseV2 { +export interface IChartResponse { schema: Record; data: TChartData[]; } @@ -48,7 +48,7 @@ export type AnalyticsTableDataMap = { "work-items": WorkItemInsightColumns; }; -export interface IAnalyticsV2Params { +export interface IAnalyticsParams { x_axis: ChartXAxisProperty; y_axis: ChartYAxisMetric; group_by?: ChartXAxisProperty; diff --git a/packages/types/src/index.d.ts b/packages/types/src/index.d.ts index 0ac656fc69f..9a6711421f1 100644 --- a/packages/types/src/index.d.ts +++ b/packages/types/src/index.d.ts @@ -43,4 +43,4 @@ export * from "./home"; export * from "./stickies"; export * from "./utils"; export * from "./payment"; -export * from "./analytics-v2"; \ No newline at end of file +export * from "./analytics"; diff --git a/web/app/(all)/[workspaceSlug]/(projects)/analytics/page.tsx b/web/app/(all)/[workspaceSlug]/(projects)/analytics/page.tsx index b4972363355..389a80a9018 100644 --- a/web/app/(all)/[workspaceSlug]/(projects)/analytics/page.tsx +++ b/web/app/(all)/[workspaceSlug]/(projects)/analytics/page.tsx @@ -8,13 +8,13 @@ import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { Tabs } from "@plane/ui"; // components -import AnalyticsFilterActions from "@/components/analytics-v2/analytics-filter-actions"; +import AnalyticsFilterActions from "@/components/analytics/analytics-filter-actions"; import { PageHead } from "@/components/core"; import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; // hooks import { useCommandPalette, useEventTracker, useProject, useUserPermissions, useWorkspace } from "@/hooks/store"; import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; -import { ANALYTICS_TABS } from "@/plane-web/components/analytics-v2/tabs"; +import { ANALYTICS_TABS } from "@/plane-web/components/analytics/tabs"; const AnalyticsPage = observer(() => { const router = useRouter(); diff --git a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/header.tsx b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/header.tsx index 07dd0fc4dfa..7d15cd22da5 100644 --- a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/header.tsx +++ b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/header.tsx @@ -27,7 +27,7 @@ import { // ui import { Breadcrumbs, Button, ContrastIcon, Tooltip, Header, CustomSearchSelect } from "@plane/ui"; // components -import { WorkItemsModal } from "@/components/analytics-v2/work-items/modal"; +import { WorkItemsModal } from "@/components/analytics/work-items/modal"; import { BreadcrumbLink, SwitcherLabel } from "@/components/common"; import { CycleQuickActions } from "@/components/cycles"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues"; diff --git a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/mobile-header.tsx b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/mobile-header.tsx index 4efa986b4d9..0494f5f33a4 100644 --- a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/mobile-header.tsx +++ b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/cycles/(detail)/mobile-header.tsx @@ -19,7 +19,7 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption // ui import { CustomMenu } from "@plane/ui"; // components -import { WorkItemsModal } from "@/components/analytics-v2/work-items/modal"; +import { WorkItemsModal } from "@/components/analytics/work-items/modal"; import { DisplayFiltersSelection, FilterSelection, FiltersDropdown, IssueLayoutIcon } from "@/components/issues"; // helpers import { isIssueFilterActive } from "@/helpers/filter.helper"; diff --git a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/issues/(list)/mobile-header.tsx b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/issues/(list)/mobile-header.tsx index a9777ce23d5..def0504628a 100644 --- a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/issues/(list)/mobile-header.tsx +++ b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/issues/(list)/mobile-header.tsx @@ -20,7 +20,7 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption // ui import { CustomMenu } from "@plane/ui"; // components -import { WorkItemsModal } from "@/components/analytics-v2/work-items/modal"; +import { WorkItemsModal } from "@/components/analytics/work-items/modal"; import { DisplayFiltersSelection, FilterSelection, diff --git a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx index 6830b5532d9..0fb2b138f49 100644 --- a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx +++ b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/header.tsx @@ -25,7 +25,7 @@ import { // ui import { Breadcrumbs, Button, DiceIcon, Tooltip, Header, CustomSearchSelect } from "@plane/ui"; // components -import { WorkItemsModal } from "@/components/analytics-v2/work-items/modal"; +import { WorkItemsModal } from "@/components/analytics/work-items/modal"; import { BreadcrumbLink, SwitcherLabel } from "@/components/common"; import { DisplayFiltersSelection, FiltersDropdown, FilterSelection, LayoutSelection } from "@/components/issues"; // helpers diff --git a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/mobile-header.tsx b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/mobile-header.tsx index 59e09e3d06b..0501f5527dd 100644 --- a/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/mobile-header.tsx +++ b/web/app/(all)/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/modules/(detail)/mobile-header.tsx @@ -20,7 +20,7 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption // ui import { CustomMenu } from "@plane/ui"; // components -import { WorkItemsModal } from "@/components/analytics-v2/work-items/modal"; +import { WorkItemsModal } from "@/components/analytics/work-items/modal"; import { DisplayFiltersSelection, FilterSelection, diff --git a/web/ce/components/analytics-v2/tabs.ts b/web/ce/components/analytics-v2/tabs.ts deleted file mode 100644 index 8390601eba3..00000000000 --- a/web/ce/components/analytics-v2/tabs.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { TAnalyticsTabsV2Base } from "@plane/types"; -import { Overview } from "@/components/analytics-v2/overview"; -import { WorkItems } from "@/components/analytics-v2/work-items"; -export const ANALYTICS_TABS: { - key: TAnalyticsTabsV2Base; - i18nKey: string; - content: React.FC; -}[] = [ - { key: "overview", i18nKey: "common.overview", content: Overview }, - { key: "work-items", i18nKey: "sidebar.work_items", content: WorkItems }, - ]; diff --git a/web/ce/components/analytics/tabs.ts b/web/ce/components/analytics/tabs.ts new file mode 100644 index 00000000000..6ce6daf8e7f --- /dev/null +++ b/web/ce/components/analytics/tabs.ts @@ -0,0 +1,11 @@ +import { TAnalyticsTabsBase } from "@plane/types"; +import { Overview } from "@/components/analytics/overview"; +import { WorkItems } from "@/components/analytics/work-items"; +export const ANALYTICS_TABS: { + key: TAnalyticsTabsBase; + i18nKey: string; + content: React.FC; +}[] = [ + { key: "overview", i18nKey: "common.overview", content: Overview }, + { key: "work-items", i18nKey: "sidebar.work_items", content: WorkItems }, +]; diff --git a/web/ce/store/analytics-v2.store.ts b/web/ce/store/analytics-v2.store.ts deleted file mode 100644 index b1fcb7df08a..00000000000 --- a/web/ce/store/analytics-v2.store.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { BaseAnalyticsStoreV2, IBaseAnalyticsStoreV2 } from "@/store/analytics-v2.store"; - -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface IAnalyticsStoreV2 extends IBaseAnalyticsStoreV2 { - //observables -} - -export class AnalyticsStoreV2 extends BaseAnalyticsStoreV2 {} diff --git a/web/ce/store/analytics.store.ts b/web/ce/store/analytics.store.ts new file mode 100644 index 00000000000..ef866f65a78 --- /dev/null +++ b/web/ce/store/analytics.store.ts @@ -0,0 +1,8 @@ +import { BaseAnalyticsStore, IBaseAnalyticsStore } from "@/store/analytics.store"; + +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface IAnalyticsStore extends IBaseAnalyticsStore { + //observables +} + +export class AnalyticsStore extends BaseAnalyticsStore {} diff --git a/web/core/components/analytics-v2/analytics-filter-actions.tsx b/web/core/components/analytics/analytics-filter-actions.tsx similarity index 88% rename from web/core/components/analytics-v2/analytics-filter-actions.tsx rename to web/core/components/analytics/analytics-filter-actions.tsx index aae166bf4f4..adfe7822b7e 100644 --- a/web/core/components/analytics-v2/analytics-filter-actions.tsx +++ b/web/core/components/analytics/analytics-filter-actions.tsx @@ -2,13 +2,13 @@ import { observer } from "mobx-react-lite"; // hooks import { useProject } from "@/hooks/store"; -import { useAnalyticsV2 } from "@/hooks/store/use-analytics-v2"; +import { useAnalytics } from "@/hooks/store/use-analytics"; // components import DurationDropdown from "./select/duration"; import { ProjectSelect } from "./select/project"; const AnalyticsFilterActions = observer(() => { - const { selectedProjects, selectedDuration, updateSelectedProjects, updateSelectedDuration } = useAnalyticsV2(); + const { selectedProjects, selectedDuration, updateSelectedProjects, updateSelectedDuration } = useAnalytics(); const { workspaceProjectIds } = useProject(); return (
diff --git a/web/core/components/analytics-v2/analytics-section-wrapper.tsx b/web/core/components/analytics/analytics-section-wrapper.tsx similarity index 100% rename from web/core/components/analytics-v2/analytics-section-wrapper.tsx rename to web/core/components/analytics/analytics-section-wrapper.tsx diff --git a/web/core/components/analytics-v2/analytics-wrapper.tsx b/web/core/components/analytics/analytics-wrapper.tsx similarity index 100% rename from web/core/components/analytics-v2/analytics-wrapper.tsx rename to web/core/components/analytics/analytics-wrapper.tsx diff --git a/web/core/components/analytics-v2/empty-state.tsx b/web/core/components/analytics/empty-state.tsx similarity index 89% rename from web/core/components/analytics-v2/empty-state.tsx rename to web/core/components/analytics/empty-state.tsx index 1a1ee86e821..5243e6c880b 100644 --- a/web/core/components/analytics-v2/empty-state.tsx +++ b/web/core/components/analytics/empty-state.tsx @@ -11,8 +11,8 @@ type Props = { className?: string; }; -const AnalyticsV2EmptyState = ({ title, description, assetPath, className }: Props) => { - const backgroundReolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics-v2/empty-grid-background" }); +const AnalyticsEmptyState = ({ title, description, assetPath, className }: Props) => { + const backgroundReolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics/empty-grid-background" }); return (
); }; -export default AnalyticsV2EmptyState; +export default AnalyticsEmptyState; diff --git a/web/core/components/analytics-v2/index.ts b/web/core/components/analytics/index.ts similarity index 100% rename from web/core/components/analytics-v2/index.ts rename to web/core/components/analytics/index.ts diff --git a/web/core/components/analytics-v2/insight-card.tsx b/web/core/components/analytics/insight-card.tsx similarity index 93% rename from web/core/components/analytics-v2/insight-card.tsx rename to web/core/components/analytics/insight-card.tsx index 2ce4c2fdc1c..739de6645c6 100644 --- a/web/core/components/analytics-v2/insight-card.tsx +++ b/web/core/components/analytics/insight-card.tsx @@ -1,12 +1,12 @@ // plane package imports import React, { useMemo } from "react"; -import { IAnalyticsResponseFieldsV2 } from "@plane/types"; +import { IAnalyticsResponseFields } from "@plane/types"; import { Loader } from "@plane/ui"; // components import TrendPiece from "./trend-piece"; export type InsightCardProps = { - data?: IAnalyticsResponseFieldsV2; + data?: IAnalyticsResponseFields; label: string; isLoading?: boolean; versus?: string | null; diff --git a/web/core/components/analytics-v2/insight-table/data-table.tsx b/web/core/components/analytics/insight-table/data-table.tsx similarity index 95% rename from web/core/components/analytics-v2/insight-table/data-table.tsx rename to web/core/components/analytics/insight-table/data-table.tsx index 61e02cb33f6..8a66c3caf2d 100644 --- a/web/core/components/analytics-v2/insight-table/data-table.tsx +++ b/web/core/components/analytics/insight-table/data-table.tsx @@ -23,7 +23,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@ import { cn } from "@plane/utils"; // plane web components import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; -import AnalyticsV2EmptyState from "../empty-state"; +import AnalyticsEmptyState from "../empty-state"; interface DataTableProps { columns: ColumnDef[]; @@ -40,7 +40,7 @@ export function DataTable({ columns, data, searchPlaceholder, act const { t } = useTranslation(); const inputRef = React.useRef(null); const [isSearchOpen, setIsSearchOpen] = React.useState(false); - const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics-v2/empty-table" }); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics/empty-table" }); const table = useReactTable({ data, @@ -155,9 +155,9 @@ export function DataTable({ columns, data, searchPlaceholder, act
- diff --git a/web/core/components/analytics-v2/insight-table/index.ts b/web/core/components/analytics/insight-table/index.ts similarity index 100% rename from web/core/components/analytics-v2/insight-table/index.ts rename to web/core/components/analytics/insight-table/index.ts diff --git a/web/core/components/analytics-v2/insight-table/loader.tsx b/web/core/components/analytics/insight-table/loader.tsx similarity index 100% rename from web/core/components/analytics-v2/insight-table/loader.tsx rename to web/core/components/analytics/insight-table/loader.tsx diff --git a/web/core/components/analytics-v2/insight-table/root.tsx b/web/core/components/analytics/insight-table/root.tsx similarity index 90% rename from web/core/components/analytics-v2/insight-table/root.tsx rename to web/core/components/analytics/insight-table/root.tsx index 1ee90c726aa..aab4a0f7797 100644 --- a/web/core/components/analytics-v2/insight-table/root.tsx +++ b/web/core/components/analytics/insight-table/root.tsx @@ -3,11 +3,11 @@ import { download, generateCsv, mkConfig } from "export-to-csv"; import { useParams } from "next/navigation"; import { Download } from "lucide-react"; import { useTranslation } from "@plane/i18n"; -import { AnalyticsTableDataMap, TAnalyticsTabsV2Base } from "@plane/types"; +import { AnalyticsTableDataMap, TAnalyticsTabsBase } from "@plane/types"; import { Button } from "@plane/ui"; import { DataTable } from "./data-table"; import { TableLoader } from "./loader"; -interface InsightTableProps> { +interface InsightTableProps> { analyticsType: T; data?: AnalyticsTableDataMap[T][]; isLoading?: boolean; @@ -16,7 +16,7 @@ interface InsightTableProps> headerText: string; } -export const InsightTable = >( +export const InsightTable = >( props: InsightTableProps ): React.ReactElement => { const { data, isLoading, columns, columnsLabels, headerText } = props; diff --git a/web/core/components/analytics-v2/loaders.tsx b/web/core/components/analytics/loaders.tsx similarity index 100% rename from web/core/components/analytics-v2/loaders.tsx rename to web/core/components/analytics/loaders.tsx diff --git a/web/core/components/analytics-v2/overview/active-project-item.tsx b/web/core/components/analytics/overview/active-project-item.tsx similarity index 100% rename from web/core/components/analytics-v2/overview/active-project-item.tsx rename to web/core/components/analytics/overview/active-project-item.tsx diff --git a/web/core/components/analytics-v2/overview/active-projects.tsx b/web/core/components/analytics/overview/active-projects.tsx similarity index 93% rename from web/core/components/analytics-v2/overview/active-projects.tsx rename to web/core/components/analytics/overview/active-projects.tsx index cb1e2ef693d..2bcc8e831de 100644 --- a/web/core/components/analytics-v2/overview/active-projects.tsx +++ b/web/core/components/analytics/overview/active-projects.tsx @@ -6,7 +6,7 @@ import useSWR from "swr"; import { useTranslation } from "@plane/i18n"; import { Loader } from "@plane/ui"; // plane web hooks -import { useAnalyticsV2, useProject } from "@/hooks/store"; +import { useAnalytics, useProject } from "@/hooks/store"; // plane web components import AnalyticsSectionWrapper from "../analytics-section-wrapper"; import ActiveProjectItem from "./active-project-item"; @@ -15,7 +15,7 @@ const ActiveProjects = observer(() => { const { t } = useTranslation(); const { fetchProjectAnalyticsCount } = useProject(); const { workspaceSlug } = useParams(); - const { selectedDurationLabel } = useAnalyticsV2(); + const { selectedDurationLabel } = useAnalytics(); const { data: projectAnalyticsCount, isLoading: isProjectAnalyticsCountLoading } = useSWR( workspaceSlug ? ["projectAnalyticsCount", workspaceSlug] : null, workspaceSlug diff --git a/web/core/components/analytics-v2/overview/index.ts b/web/core/components/analytics/overview/index.ts similarity index 100% rename from web/core/components/analytics-v2/overview/index.ts rename to web/core/components/analytics/overview/index.ts diff --git a/web/core/components/analytics-v2/overview/project-insights.tsx b/web/core/components/analytics/overview/project-insights.tsx similarity index 80% rename from web/core/components/analytics-v2/overview/project-insights.tsx rename to web/core/components/analytics/overview/project-insights.tsx index 9c8f829a14d..9844a4b4f8d 100644 --- a/web/core/components/analytics-v2/overview/project-insights.tsx +++ b/web/core/components/analytics/overview/project-insights.tsx @@ -6,13 +6,13 @@ import useSWR from "swr"; import { useTranslation } from "@plane/i18n"; import { TChartData } from "@plane/types"; // hooks -import { useAnalyticsV2 } from "@/hooks/store/use-analytics-v2"; +import { useAnalytics } from "@/hooks/store/use-analytics"; // services import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; -import { AnalyticsV2Service } from "@/services/analytics-v2.service"; +import { AnalyticsService } from "@/services/analytics.service"; // plane web components import AnalyticsSectionWrapper from "../analytics-section-wrapper"; -import AnalyticsV2EmptyState from "../empty-state"; +import AnalyticsEmptyState from "../empty-state"; import { ProjectInsightsLoader } from "../loaders"; const RadarChart = dynamic(() => @@ -21,25 +21,28 @@ const RadarChart = dynamic(() => })) ); -const analyticsV2Service = new AnalyticsV2Service(); +const analyticsService = new AnalyticsService(); const ProjectInsights = observer(() => { const params = useParams(); const { t } = useTranslation(); const workspaceSlug = params.workspaceSlug.toString(); const { selectedDuration, selectedDurationLabel, selectedProjects, selectedCycle, selectedModule, isPeekView } = - useAnalyticsV2(); - const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics-v2/empty-chart-radar" }); + useAnalytics(); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics/empty-chart-radar" }); const { data: projectInsightsData, isLoading: isLoadingProjectInsight } = useSWR( `radar-chart-${workspaceSlug}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, () => - analyticsV2Service.getAdvanceAnalyticsCharts[]>(workspaceSlug, "projects", { - // date_filter: selectedDuration, - ...(selectedProjects?.length > 0 && { project_ids: selectedProjects?.join(",") }), - ...(selectedCycle ? { cycle_id: selectedCycle } : {}), - ...(selectedModule ? { module_id: selectedModule } : {}), - }, + analyticsService.getAdvanceAnalyticsCharts[]>( + workspaceSlug, + "projects", + { + // date_filter: selectedDuration, + ...(selectedProjects?.length > 0 && { project_ids: selectedProjects?.join(",") }), + ...(selectedCycle ? { cycle_id: selectedCycle } : {}), + ...(selectedModule ? { module_id: selectedModule } : {}), + }, isPeekView ) ); @@ -53,9 +56,9 @@ const ProjectInsights = observer(() => { {isLoadingProjectInsight ? ( ) : projectInsightsData && projectInsightsData?.length == 0 ? ( - diff --git a/web/core/components/analytics-v2/overview/root.tsx b/web/core/components/analytics/overview/root.tsx similarity index 100% rename from web/core/components/analytics-v2/overview/root.tsx rename to web/core/components/analytics/overview/root.tsx diff --git a/web/core/components/analytics-v2/select/analytics-params.tsx b/web/core/components/analytics/select/analytics-params.tsx similarity index 80% rename from web/core/components/analytics-v2/select/analytics-params.tsx rename to web/core/components/analytics/select/analytics-params.tsx index 61a9d1b1f9e..f4ef0d9eb52 100644 --- a/web/core/components/analytics-v2/select/analytics-params.tsx +++ b/web/core/components/analytics/select/analytics-params.tsx @@ -3,31 +3,30 @@ import { observer } from "mobx-react"; import { Control, Controller, UseFormSetValue } from "react-hook-form"; import { Calendar, SlidersHorizontal } from "lucide-react"; // plane package imports -import { ANALYTICS_V2_X_AXIS_VALUES, ANALYTICS_V2_Y_AXIS_VALUES, ChartYAxisMetric } from "@plane/constants"; +import { ANALYTICS_X_AXIS_VALUES, ANALYTICS_Y_AXIS_VALUES, ChartYAxisMetric } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; -import { IAnalyticsV2Params } from "@plane/types"; +import { IAnalyticsParams } from "@plane/types"; import { cn } from "@plane/utils"; // plane web components -import { AnalyticsV2Service } from "@/services/analytics-v2.service"; import { SelectXAxis } from "./select-x-axis"; import { SelectYAxis } from "./select-y-axis"; type Props = { - control: Control; - setValue: UseFormSetValue; - params: IAnalyticsV2Params; + control: Control; + setValue: UseFormSetValue; + params: IAnalyticsParams; workspaceSlug: string; classNames?: string; }; -export const AnalyticsV2SelectParams: React.FC = observer((props) => { +export const AnalyticsSelectParams: React.FC = observer((props) => { const { control, params, classNames } = props; const xAxisOptions = useMemo( - () => ANALYTICS_V2_X_AXIS_VALUES.filter((option) => option.value !== params.group_by), + () => ANALYTICS_X_AXIS_VALUES.filter((option) => option.value !== params.group_by), [params.group_by] ); const groupByOptions = useMemo( - () => ANALYTICS_V2_X_AXIS_VALUES.filter((option) => option.value !== params.x_axis), + () => ANALYTICS_X_AXIS_VALUES.filter((option) => option.value !== params.x_axis), [params.x_axis] ); @@ -43,7 +42,7 @@ export const AnalyticsV2SelectParams: React.FC = observer((props) => { onChange={(val: ChartYAxisMetric | null) => { onChange(val); }} - options={ANALYTICS_V2_Y_AXIS_VALUES} + options={ANALYTICS_Y_AXIS_VALUES} hiddenOptions={[ChartYAxisMetric.ESTIMATE_POINT_COUNT]} /> )} diff --git a/web/core/components/analytics-v2/select/duration.tsx b/web/core/components/analytics/select/duration.tsx similarity index 76% rename from web/core/components/analytics-v2/select/duration.tsx rename to web/core/components/analytics/select/duration.tsx index de18ab2023f..5c99a61b0e9 100644 --- a/web/core/components/analytics-v2/select/duration.tsx +++ b/web/core/components/analytics/select/duration.tsx @@ -2,7 +2,7 @@ import React, { ReactNode } from "react"; import { Calendar } from "lucide-react"; // plane package imports -import { ANALYTICS_V2_DURATION_FILTER_OPTIONS } from "@plane/constants"; +import { ANALYTICS_DURATION_FILTER_OPTIONS } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { CustomSearchSelect } from "@plane/ui"; // types @@ -10,7 +10,7 @@ import { TDropdownProps } from "@/components/dropdowns/types"; type Props = TDropdownProps & { value: string | null; - onChange: (val: (typeof ANALYTICS_V2_DURATION_FILTER_OPTIONS)[number]["value"]) => void; + onChange: (val: (typeof ANALYTICS_DURATION_FILTER_OPTIONS)[number]["value"]) => void; //optional button?: ReactNode; dropdownArrow?: boolean; @@ -23,7 +23,7 @@ type Props = TDropdownProps & { function DurationDropdown({ placeholder = "Duration", onChange, value }: Props) { useTranslation(); - const options = ANALYTICS_V2_DURATION_FILTER_OPTIONS.map((option) => ({ + const options = ANALYTICS_DURATION_FILTER_OPTIONS.map((option) => ({ value: option.value, query: option.name, content: ( @@ -40,7 +40,7 @@ function DurationDropdown({ placeholder = "Duration", onChange, value }: Props) label={
- {value ? ANALYTICS_V2_DURATION_FILTER_OPTIONS.find((opt) => opt.value === value)?.name : placeholder} + {value ? ANALYTICS_DURATION_FILTER_OPTIONS.find((opt) => opt.value === value)?.name : placeholder}
} /> diff --git a/web/core/components/analytics-v2/select/project.tsx b/web/core/components/analytics/select/project.tsx similarity index 100% rename from web/core/components/analytics-v2/select/project.tsx rename to web/core/components/analytics/select/project.tsx diff --git a/web/core/components/analytics-v2/select/select-x-axis.tsx b/web/core/components/analytics/select/select-x-axis.tsx similarity index 100% rename from web/core/components/analytics-v2/select/select-x-axis.tsx rename to web/core/components/analytics/select/select-x-axis.tsx diff --git a/web/core/components/analytics-v2/select/select-y-axis.tsx b/web/core/components/analytics/select/select-y-axis.tsx similarity index 100% rename from web/core/components/analytics-v2/select/select-y-axis.tsx rename to web/core/components/analytics/select/select-y-axis.tsx diff --git a/web/core/components/analytics-v2/total-insights.tsx b/web/core/components/analytics/total-insights.tsx similarity index 85% rename from web/core/components/analytics-v2/total-insights.tsx rename to web/core/components/analytics/total-insights.tsx index 6b88bbc6dd5..4501ce2c339 100644 --- a/web/core/components/analytics-v2/total-insights.tsx +++ b/web/core/components/analytics/total-insights.tsx @@ -4,19 +4,19 @@ import { useParams } from "next/navigation"; import useSWR from "swr"; import { EIssuesStoreType, insightsFields } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; -import { IAnalyticsResponseV2, TAnalyticsTabsV2Base } from "@plane/types"; +import { IAnalyticsResponse, TAnalyticsTabsBase } from "@plane/types"; //hooks import { cn } from "@/helpers/common.helper"; -import { useAnalyticsV2 } from "@/hooks/store/use-analytics-v2"; +import { useAnalytics } from "@/hooks/store/use-analytics"; //services -import { AnalyticsV2Service } from "@/services/analytics-v2.service"; +import { AnalyticsService } from "@/services/analytics.service"; // plane web components import InsightCard from "./insight-card"; -const analyticsV2Service = new AnalyticsV2Service(); +const analyticsService = new AnalyticsService(); const TotalInsights: React.FC<{ - analyticsType: TAnalyticsTabsV2Base; + analyticsType: TAnalyticsTabsBase; peekView?: boolean; }> = observer(({ analyticsType, peekView }) => { const params = useParams(); @@ -30,11 +30,11 @@ const TotalInsights: React.FC<{ selectedModule, isPeekView, isEpic, - } = useAnalyticsV2(); + } = useAnalytics(); const { data: totalInsightsData, isLoading } = useSWR( `total-insights-${analyticsType}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, () => - analyticsV2Service.getAdvanceAnalytics( + analyticsService.getAdvanceAnalytics( workspaceSlug, analyticsType, { diff --git a/web/core/components/analytics-v2/trend-piece.tsx b/web/core/components/analytics/trend-piece.tsx similarity index 100% rename from web/core/components/analytics-v2/trend-piece.tsx rename to web/core/components/analytics/trend-piece.tsx diff --git a/web/core/components/analytics-v2/work-items/created-vs-resolved.tsx b/web/core/components/analytics/work-items/created-vs-resolved.tsx similarity index 77% rename from web/core/components/analytics-v2/work-items/created-vs-resolved.tsx rename to web/core/components/analytics/work-items/created-vs-resolved.tsx index 46f3faf54e4..9abd7055ffb 100644 --- a/web/core/components/analytics-v2/work-items/created-vs-resolved.tsx +++ b/web/core/components/analytics/work-items/created-vs-resolved.tsx @@ -5,35 +5,38 @@ import useSWR from "swr"; // plane package imports import { useTranslation } from "@plane/i18n"; import { AreaChart } from "@plane/propel/charts/area-chart"; -import { IChartResponseV2, TChartData } from "@plane/types"; +import { IChartResponse, TChartData } from "@plane/types"; import { renderFormattedDate } from "@plane/utils"; // hooks -import { useAnalyticsV2 } from "@/hooks/store/use-analytics-v2"; +import { useAnalytics } from "@/hooks/store/use-analytics"; // services import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; -import { AnalyticsV2Service } from "@/services/analytics-v2.service"; +import { AnalyticsService } from "@/services/analytics.service"; // plane web components import AnalyticsSectionWrapper from "../analytics-section-wrapper"; -import AnalyticsV2EmptyState from "../empty-state"; +import AnalyticsEmptyState from "../empty-state"; import { ChartLoader } from "../loaders"; -const analyticsV2Service = new AnalyticsV2Service(); +const analyticsService = new AnalyticsService(); const CreatedVsResolved = observer(() => { const { selectedDuration, selectedDurationLabel, selectedProjects, selectedCycle, selectedModule, isPeekView } = - useAnalyticsV2(); + useAnalytics(); const params = useParams(); const { t } = useTranslation(); const workspaceSlug = params.workspaceSlug.toString(); - const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics-v2/empty-chart-area" }); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics/empty-chart-area" }); const { data: createdVsResolvedData, isLoading: isCreatedVsResolvedLoading } = useSWR( `created-vs-resolved-${workspaceSlug}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, () => - analyticsV2Service.getAdvanceAnalyticsCharts(workspaceSlug, "work-items", { - // date_filter: selectedDuration, - ...(selectedProjects?.length > 0 && { project_ids: selectedProjects?.join(",") }), - ...(selectedCycle ? { cycle_id: selectedCycle } : {}), - ...(selectedModule ? { module_id: selectedModule } : {}), - }, + analyticsService.getAdvanceAnalyticsCharts( + workspaceSlug, + "work-items", + { + // date_filter: selectedDuration, + ...(selectedProjects?.length > 0 && { project_ids: selectedProjects?.join(",") }), + ...(selectedCycle ? { cycle_id: selectedCycle } : {}), + ...(selectedModule ? { module_id: selectedModule } : {}), + }, isPeekView ) ); @@ -110,9 +113,9 @@ const CreatedVsResolved = observer(() => { }} /> ) : ( - diff --git a/web/core/components/analytics-v2/work-items/customized-insights.tsx b/web/core/components/analytics/work-items/customized-insights.tsx similarity index 84% rename from web/core/components/analytics-v2/work-items/customized-insights.tsx rename to web/core/components/analytics/work-items/customized-insights.tsx index 86fea0c83b7..6574658227f 100644 --- a/web/core/components/analytics-v2/work-items/customized-insights.tsx +++ b/web/core/components/analytics/work-items/customized-insights.tsx @@ -4,14 +4,14 @@ import { useForm } from "react-hook-form"; // plane package imports import { ChartXAxisProperty, ChartYAxisMetric } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; -import { IAnalyticsV2Params } from "@plane/types"; +import { IAnalyticsParams } from "@plane/types"; import { cn } from "@plane/utils"; // plane web components import AnalyticsSectionWrapper from "../analytics-section-wrapper"; -import { AnalyticsV2SelectParams } from "../select/analytics-params"; +import { AnalyticsSelectParams } from "../select/analytics-params"; import PriorityChart from "./priority-chart"; -const defaultValues: IAnalyticsV2Params = { +const defaultValues: IAnalyticsParams = { x_axis: ChartXAxisProperty.PRIORITY, y_axis: ChartYAxisMetric.WORK_ITEM_COUNT, }; @@ -19,7 +19,7 @@ const defaultValues: IAnalyticsV2Params = { const CustomizedInsights = observer(({ peekView }: { peekView?: boolean }) => { const { t } = useTranslation(); const { workspaceSlug } = useParams(); - const { control, watch, setValue } = useForm({ + const { control, watch, setValue } = useForm({ defaultValues: { ...defaultValues, }, @@ -37,7 +37,7 @@ const CustomizedInsights = observer(({ peekView }: { peekView?: boolean }) => { className="col-span-1" headerClassName={cn(peekView ? "flex-col items-start" : "")} actions={ - = observer((props) => { const { projectDetails, cycleDetails, moduleDetails, fullScreen } = props; - const { updateSelectedProjects, updateSelectedCycle, updateSelectedModule, updateIsPeekView } = useAnalyticsV2(); + const { updateSelectedProjects, updateSelectedCycle, updateSelectedModule, updateIsPeekView } = useAnalytics(); const [isModalConfigured, setIsModalConfigured] = useState(false); useEffect(() => { diff --git a/web/core/components/analytics-v2/work-items/modal/header.tsx b/web/core/components/analytics/work-items/modal/header.tsx similarity index 100% rename from web/core/components/analytics-v2/work-items/modal/header.tsx rename to web/core/components/analytics/work-items/modal/header.tsx diff --git a/web/core/components/analytics-v2/work-items/modal/index.tsx b/web/core/components/analytics/work-items/modal/index.tsx similarity index 96% rename from web/core/components/analytics-v2/work-items/modal/index.tsx rename to web/core/components/analytics/work-items/modal/index.tsx index 95b8f18409b..292dc1be5e0 100644 --- a/web/core/components/analytics-v2/work-items/modal/index.tsx +++ b/web/core/components/analytics/work-items/modal/index.tsx @@ -3,7 +3,7 @@ import { observer } from "mobx-react"; import { Dialog, Transition } from "@headlessui/react"; // plane package imports import { ICycle, IModule, IProject } from "@plane/types"; -import { useAnalyticsV2 } from "@/hooks/store"; +import { useAnalytics } from "@/hooks/store"; // plane web components import { WorkItemsModalMainContent } from "./content"; import { WorkItemsModalHeader } from "./header"; @@ -19,7 +19,7 @@ type Props = { export const WorkItemsModal: React.FC = observer((props) => { const { isOpen, onClose, projectDetails, moduleDetails, cycleDetails, isEpic } = props; - const { updateIsEpic } = useAnalyticsV2(); + const { updateIsEpic } = useAnalytics(); const [fullScreen, setFullScreen] = useState(false); const handleClose = () => { diff --git a/web/core/components/analytics-v2/work-items/priority-chart.tsx b/web/core/components/analytics/work-items/priority-chart.tsx similarity index 89% rename from web/core/components/analytics-v2/work-items/priority-chart.tsx rename to web/core/components/analytics/work-items/priority-chart.tsx index 9d10c2b6add..020eaf8d391 100644 --- a/web/core/components/analytics-v2/work-items/priority-chart.tsx +++ b/web/core/components/analytics/work-items/priority-chart.tsx @@ -8,8 +8,8 @@ import useSWR from "swr"; // plane package imports import { Download } from "lucide-react"; import { - ANALYTICS_V2_X_AXIS_VALUES, - ANALYTICS_V2_Y_AXIS_VALUES, + ANALYTICS_X_AXIS_VALUES, + ANALYTICS_Y_AXIS_VALUES, CHART_COLOR_PALETTES, ChartXAxisDateGrouping, ChartXAxisProperty, @@ -18,17 +18,17 @@ import { } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { BarChart } from "@plane/propel/charts/bar-chart"; -import { IChartResponseV2 } from "@plane/types"; +import { IChartResponse } from "@plane/types"; import { TBarItem, TChart, TChartData, TChartDatum } from "@plane/types/src/charts"; // plane web components import { Button } from "@plane/ui"; import { generateExtendedColors, parseChartData } from "@/components/chart/utils"; // hooks import { useProjectState } from "@/hooks/store"; -import { useAnalyticsV2 } from "@/hooks/store/use-analytics-v2"; +import { useAnalytics } from "@/hooks/store/use-analytics"; import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; -import { AnalyticsV2Service } from "@/services/analytics-v2.service"; -import AnalyticsV2EmptyState from "../empty-state"; +import { AnalyticsService } from "@/services/analytics.service"; +import AnalyticsEmptyState from "../empty-state"; import { DataTable } from "../insight-table/data-table"; import { ChartLoader } from "../loaders"; import { generateBarColor } from "./utils"; @@ -40,13 +40,13 @@ interface Props { x_axis_date_grouping?: ChartXAxisDateGrouping; } -const analyticsV2Service = new AnalyticsV2Service(); +const analyticsService = new AnalyticsService(); const PriorityChart = observer((props: Props) => { const { x_axis, y_axis, group_by } = props; const { t } = useTranslation(); - const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics-v2/empty-chart-bar" }); + const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics/empty-chart-bar" }); // store hooks - const { selectedDuration, selectedProjects, selectedCycle, selectedModule, isPeekView } = useAnalyticsV2(); + const { selectedDuration, selectedProjects, selectedCycle, selectedModule, isPeekView } = useAnalytics(); const { workspaceStates } = useProjectState(); const { resolvedTheme } = useTheme(); // router @@ -57,7 +57,7 @@ const PriorityChart = observer((props: Props) => { `customized-insights-chart-${workspaceSlug}-${selectedDuration}- ${selectedProjects}-${selectedCycle}-${selectedModule}-${props.x_axis}-${props.y_axis}-${props.group_by}-${isPeekView}`, () => - analyticsV2Service.getAdvanceAnalyticsCharts( + analyticsService.getAdvanceAnalyticsCharts( workspaceSlug, "custom-work-items", { @@ -132,11 +132,11 @@ const PriorityChart = observer((props: Props) => { }, [chart_model, group_by, parsedData, resolvedTheme, workspaceStates, x_axis, y_axis]); const yAxisLabel = useMemo( - () => ANALYTICS_V2_Y_AXIS_VALUES.find((item) => item.value === props.y_axis)?.label ?? props.y_axis, + () => ANALYTICS_Y_AXIS_VALUES.find((item) => item.value === props.y_axis)?.label ?? props.y_axis, [props.y_axis] ); const xAxisLabel = useMemo( - () => ANALYTICS_V2_X_AXIS_VALUES.find((item) => item.value === props.x_axis)?.label ?? props.x_axis, + () => ANALYTICS_X_AXIS_VALUES.find((item) => item.value === props.x_axis)?.label ?? props.x_axis, [props.x_axis] ); @@ -237,9 +237,9 @@ const PriorityChart = observer((props: Props) => { /> ) : ( - diff --git a/web/core/components/analytics-v2/work-items/root.tsx b/web/core/components/analytics/work-items/root.tsx similarity index 100% rename from web/core/components/analytics-v2/work-items/root.tsx rename to web/core/components/analytics/work-items/root.tsx diff --git a/web/core/components/analytics-v2/work-items/utils.ts b/web/core/components/analytics/work-items/utils.ts similarity index 100% rename from web/core/components/analytics-v2/work-items/utils.ts rename to web/core/components/analytics/work-items/utils.ts diff --git a/web/core/components/analytics-v2/work-items/workitems-insight-table.tsx b/web/core/components/analytics/work-items/workitems-insight-table.tsx similarity index 95% rename from web/core/components/analytics-v2/work-items/workitems-insight-table.tsx rename to web/core/components/analytics/work-items/workitems-insight-table.tsx index 6dca7d92931..8facca27088 100644 --- a/web/core/components/analytics-v2/work-items/workitems-insight-table.tsx +++ b/web/core/components/analytics/work-items/workitems-insight-table.tsx @@ -12,13 +12,13 @@ import { Avatar } from "@plane/ui"; import { getFileURL } from "@plane/utils"; import { Logo } from "@/components/common/logo"; // hooks -import { useAnalyticsV2 } from "@/hooks/store/use-analytics-v2"; +import { useAnalytics } from "@/hooks/store/use-analytics"; import { useProject } from "@/hooks/store/use-project"; -import { AnalyticsV2Service } from "@/services/analytics-v2.service"; +import { AnalyticsService } from "@/services/analytics.service"; // plane web components import { InsightTable } from "../insight-table"; -const analyticsV2Service = new AnalyticsV2Service(); +const analyticsService = new AnalyticsService(); const WorkItemsInsightTable = observer(() => { // router @@ -27,11 +27,11 @@ const WorkItemsInsightTable = observer(() => { const { t } = useTranslation(); // store hooks const { getProjectById } = useProject(); - const { selectedDuration, selectedProjects, selectedCycle, selectedModule, isPeekView } = useAnalyticsV2(); + const { selectedDuration, selectedProjects, selectedCycle, selectedModule, isPeekView } = useAnalytics(); const { data: workItemsData, isLoading } = useSWR( `insights-table-work-items-${workspaceSlug}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, () => - analyticsV2Service.getAdvanceAnalyticsStats( + analyticsService.getAdvanceAnalyticsStats( workspaceSlug, "work-items", { diff --git a/web/core/components/issues/filters.tsx b/web/core/components/issues/filters.tsx index 22612a3f1d1..9ef8706eaed 100644 --- a/web/core/components/issues/filters.tsx +++ b/web/core/components/issues/filters.tsx @@ -17,7 +17,7 @@ import { isIssueFilterActive } from "@/helpers/filter.helper"; import { useLabel, useProjectState, useMember, useIssues } from "@/hooks/store"; // plane web types import { TProject } from "@/plane-web/types"; -import { WorkItemsModal } from "../analytics-v2/work-items/modal"; +import { WorkItemsModal } from "../analytics/work-items/modal"; type Props = { currentProjectDetails: TProject | undefined; diff --git a/web/core/hooks/store/index.ts b/web/core/hooks/store/index.ts index 6a1b91e5d0f..dfc104542a1 100644 --- a/web/core/hooks/store/index.ts +++ b/web/core/hooks/store/index.ts @@ -31,4 +31,4 @@ export * from "./use-workspace"; export * from "./user"; export * from "./use-transient"; export * from "./workspace-draft"; -export * from "./use-analytics-v2"; +export * from "./use-analytics"; diff --git a/web/core/hooks/store/use-analytics-v2.ts b/web/core/hooks/store/use-analytics-v2.ts deleted file mode 100644 index 7b2d8f248fb..00000000000 --- a/web/core/hooks/store/use-analytics-v2.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useContext } from "react"; -// mobx store -import { StoreContext } from "@/lib/store-context"; -// types -import { IAnalyticsStoreV2 } from "@/plane-web/store/analytics-v2.store"; - -export const useAnalyticsV2 = (): IAnalyticsStoreV2 => { - const context = useContext(StoreContext); - if (context === undefined) throw new Error("useAnalyticsV2 must be used within StoreProvider"); - return context.analyticsV2; -}; diff --git a/web/core/hooks/store/use-analytics.ts b/web/core/hooks/store/use-analytics.ts new file mode 100644 index 00000000000..a07af60ed7a --- /dev/null +++ b/web/core/hooks/store/use-analytics.ts @@ -0,0 +1,11 @@ +import { useContext } from "react"; +// mobx store +import { StoreContext } from "@/lib/store-context"; +// types +import { IAnalyticsStore } from "@/plane-web/store/analytics.store"; + +export const useAnalytics = (): IAnalyticsStore => { + const context = useContext(StoreContext); + if (context === undefined) throw new Error("useAnalytics must be used within StoreProvider"); + return context.analytics; +}; diff --git a/web/core/services/analytics-v2.service.ts b/web/core/services/analytics.service.ts similarity index 70% rename from web/core/services/analytics-v2.service.ts rename to web/core/services/analytics.service.ts index 05e1b78b728..400a616f347 100644 --- a/web/core/services/analytics-v2.service.ts +++ b/web/core/services/analytics.service.ts @@ -1,27 +1,24 @@ import { API_BASE_URL } from "@plane/constants"; -import { IAnalyticsResponseV2, TAnalyticsTabsV2Base, TAnalyticsGraphsV2Base } from "@plane/types"; +import { IAnalyticsResponse, TAnalyticsTabsBase, TAnalyticsGraphsBase } from "@plane/types"; import { APIService } from "./api.service"; -export class AnalyticsV2Service extends APIService { +export class AnalyticsService extends APIService { constructor() { super(API_BASE_URL); } - async getAdvanceAnalytics( + async getAdvanceAnalytics( workspaceSlug: string, - tab: TAnalyticsTabsV2Base, + tab: TAnalyticsTabsBase, params?: Record, isPeekView?: boolean ): Promise { - return this.get( - this.processUrl("advance-analytics", workspaceSlug, tab, params, isPeekView), - { - params: { - tab, - ...params, - }, - } - ) + return this.get(this.processUrl("advance-analytics", workspaceSlug, tab, params, isPeekView), { + params: { + tab, + ...params, + }, + }) .then((res) => res?.data) .catch((err) => { throw err?.response?.data; @@ -30,11 +27,11 @@ export class AnalyticsV2Service extends APIService { async getAdvanceAnalyticsStats( workspaceSlug: string, - tab: Exclude, + tab: Exclude, params?: Record, isPeekView?: boolean ): Promise { - const processedUrl = this.processUrl>( + const processedUrl = this.processUrl>( "advance-analytics-stats", workspaceSlug, tab, @@ -55,11 +52,11 @@ export class AnalyticsV2Service extends APIService { async getAdvanceAnalyticsCharts( workspaceSlug: string, - tab: TAnalyticsGraphsV2Base, + tab: TAnalyticsGraphsBase, params?: Record, isPeekView?: boolean ): Promise { - const processedUrl = this.processUrl( + const processedUrl = this.processUrl( "advance-analytics-charts", workspaceSlug, tab, diff --git a/web/core/store/analytics-v2.store.ts b/web/core/store/analytics.store.ts similarity index 82% rename from web/core/store/analytics-v2.store.ts rename to web/core/store/analytics.store.ts index 7db19495eea..a78c4971089 100644 --- a/web/core/store/analytics-v2.store.ts +++ b/web/core/store/analytics.store.ts @@ -1,13 +1,13 @@ import { action, computed, makeObservable, observable, runInAction } from "mobx"; -import { ANALYTICS_V2_DURATION_FILTER_OPTIONS, EIssuesStoreType } from "@plane/constants"; -import { TAnalyticsTabsV2Base } from "@plane/types"; +import { ANALYTICS_DURATION_FILTER_OPTIONS, EIssuesStoreType } from "@plane/constants"; +import { TAnalyticsTabsBase } from "@plane/types"; import { CoreRootStore } from "./root.store"; -type DurationType = (typeof ANALYTICS_V2_DURATION_FILTER_OPTIONS)[number]["value"]; +type DurationType = (typeof ANALYTICS_DURATION_FILTER_OPTIONS)[number]["value"]; -export interface IBaseAnalyticsStoreV2 { +export interface IBaseAnalyticsStore { //observables - currentTab: TAnalyticsTabsV2Base; + currentTab: TAnalyticsTabsBase; selectedProjects: string[]; selectedDuration: DurationType; selectedCycle: string; @@ -26,9 +26,9 @@ export interface IBaseAnalyticsStoreV2 { updateIsEpic: (isEpic: boolean) => void; } -export abstract class BaseAnalyticsStoreV2 implements IBaseAnalyticsStoreV2 { +export abstract class BaseAnalyticsStore implements IBaseAnalyticsStore { //observables - currentTab: TAnalyticsTabsV2Base = "overview"; + currentTab: TAnalyticsTabsBase = "overview"; selectedProjects: string[] = []; selectedDuration: DurationType = "last_30_days"; selectedCycle: string = ""; @@ -58,7 +58,7 @@ export abstract class BaseAnalyticsStoreV2 implements IBaseAnalyticsStoreV2 { } get selectedDurationLabel() { - return ANALYTICS_V2_DURATION_FILTER_OPTIONS.find((item) => item.value === this.selectedDuration)?.name ?? null; + return ANALYTICS_DURATION_FILTER_OPTIONS.find((item) => item.value === this.selectedDuration)?.name ?? null; } updateSelectedProjects = (projects: string[]) => { diff --git a/web/core/store/root.store.ts b/web/core/store/root.store.ts index 977b8760c44..e210754cc9b 100644 --- a/web/core/store/root.store.ts +++ b/web/core/store/root.store.ts @@ -2,7 +2,7 @@ import { enableStaticRendering } from "mobx-react"; // plane imports import { FALLBACK_LANGUAGE, LANGUAGE_STORAGE_KEY } from "@plane/i18n"; // plane web store -import { AnalyticsStoreV2, IAnalyticsStoreV2 } from "@/plane-web/store/analytics-v2.store"; +import { AnalyticsStore, IAnalyticsStore } from "@/plane-web/store/analytics.store"; import { CommandPaletteStore, ICommandPaletteStore } from "@/plane-web/store/command-palette.store"; import { RootStore } from "@/plane-web/store/root.store"; import { IStateStore, StateStore } from "@/plane-web/store/state.store"; @@ -50,7 +50,7 @@ export class CoreRootStore { state: IStateStore; label: ILabelStore; dashboard: IDashboardStore; - analyticsV2: IAnalyticsStoreV2; + analytics: IAnalyticsStore; projectPages: IProjectPageStore; router: IRouterStore; commandPalette: ICommandPaletteStore; @@ -96,7 +96,7 @@ export class CoreRootStore { this.transient = new TransientStore(); this.stickyStore = new StickyStore(); this.editorAssetStore = new EditorAssetStore(); - this.analyticsV2 = new AnalyticsStoreV2(); + this.analytics = new AnalyticsStore(); } resetOnSignOut() { diff --git a/web/ee/store/analytics-v2.store.ts b/web/ee/store/analytics-v2.store.ts deleted file mode 100644 index b1fcb7df08a..00000000000 --- a/web/ee/store/analytics-v2.store.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { BaseAnalyticsStoreV2, IBaseAnalyticsStoreV2 } from "@/store/analytics-v2.store"; - -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface IAnalyticsStoreV2 extends IBaseAnalyticsStoreV2 { - //observables -} - -export class AnalyticsStoreV2 extends BaseAnalyticsStoreV2 {} diff --git a/web/ee/store/analytics.store.ts b/web/ee/store/analytics.store.ts new file mode 100644 index 00000000000..ef866f65a78 --- /dev/null +++ b/web/ee/store/analytics.store.ts @@ -0,0 +1,8 @@ +import { BaseAnalyticsStore, IBaseAnalyticsStore } from "@/store/analytics.store"; + +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface IAnalyticsStore extends IBaseAnalyticsStore { + //observables +} + +export class AnalyticsStore extends BaseAnalyticsStore {} diff --git a/web/public/empty-state/analytics-v2/empty-chart-area-dark.webp b/web/public/empty-state/analytics/empty-chart-area-dark.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-chart-area-dark.webp rename to web/public/empty-state/analytics/empty-chart-area-dark.webp diff --git a/web/public/empty-state/analytics-v2/empty-chart-area-light.webp b/web/public/empty-state/analytics/empty-chart-area-light.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-chart-area-light.webp rename to web/public/empty-state/analytics/empty-chart-area-light.webp diff --git a/web/public/empty-state/analytics-v2/empty-chart-bar-dark.webp b/web/public/empty-state/analytics/empty-chart-bar-dark.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-chart-bar-dark.webp rename to web/public/empty-state/analytics/empty-chart-bar-dark.webp diff --git a/web/public/empty-state/analytics-v2/empty-chart-bar-light.webp b/web/public/empty-state/analytics/empty-chart-bar-light.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-chart-bar-light.webp rename to web/public/empty-state/analytics/empty-chart-bar-light.webp diff --git a/web/public/empty-state/analytics-v2/empty-chart-radar-dark.webp b/web/public/empty-state/analytics/empty-chart-radar-dark.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-chart-radar-dark.webp rename to web/public/empty-state/analytics/empty-chart-radar-dark.webp diff --git a/web/public/empty-state/analytics-v2/empty-chart-radar-light.webp b/web/public/empty-state/analytics/empty-chart-radar-light.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-chart-radar-light.webp rename to web/public/empty-state/analytics/empty-chart-radar-light.webp diff --git a/web/public/empty-state/analytics-v2/empty-grid-background-dark.webp b/web/public/empty-state/analytics/empty-grid-background-dark.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-grid-background-dark.webp rename to web/public/empty-state/analytics/empty-grid-background-dark.webp diff --git a/web/public/empty-state/analytics-v2/empty-grid-background-light.webp b/web/public/empty-state/analytics/empty-grid-background-light.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-grid-background-light.webp rename to web/public/empty-state/analytics/empty-grid-background-light.webp diff --git a/web/public/empty-state/analytics-v2/empty-table-dark.webp b/web/public/empty-state/analytics/empty-table-dark.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-table-dark.webp rename to web/public/empty-state/analytics/empty-table-dark.webp diff --git a/web/public/empty-state/analytics-v2/empty-table-light.webp b/web/public/empty-state/analytics/empty-table-light.webp similarity index 100% rename from web/public/empty-state/analytics-v2/empty-table-light.webp rename to web/public/empty-state/analytics/empty-table-light.webp From 1c8628a19e8cec1f463d12846b063a18bd31cac1 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Tue, 3 Jun 2025 16:01:02 +0530 Subject: [PATCH 12/19] refactor: removed all nivo chart dependencies --- .../cycles/analytics-sidebar/base.tsx | 10 - .../core/sidebar/progress-chart.tsx | 130 +++------ .../cycles/active-cycle/productivity.tsx | 12 +- .../dashboard/home-dashboard-widgets.tsx | 62 ----- web/core/components/dashboard/index.ts | 1 - .../components/dashboard/widgets/index.ts | 2 - .../dashboard/widgets/issues-by-priority.tsx | 112 -------- .../widgets/issues-by-state-group.tsx | 251 ------------------ web/core/components/graphs/index.ts | 1 - .../components/graphs/issues-by-priority.tsx | 169 ------------ .../analytics-sidebar/issue-progress.tsx | 10 - web/core/components/page-views/index.ts | 1 - .../page-views/workspace-dashboard.tsx | 118 -------- .../overview/priority-distribution/index.ts | 1 - .../priority-distribution/main-content.tsx | 31 --- .../priority-distribution.tsx | 35 --- web/core/components/ui/graphs/bar-graph.tsx | 49 ---- .../components/ui/graphs/calendar-graph.tsx | 34 --- web/core/components/ui/graphs/index.ts | 5 - web/core/components/ui/graphs/line-graph.tsx | 35 --- web/core/components/ui/graphs/pie-graph.tsx | 23 -- .../ui/graphs/scatter-plot-graph.tsx | 23 -- web/core/components/ui/graphs/types.d.ts | 8 - web/core/components/ui/index.ts | 1 - web/next.config.js | 6 - web/package.json | 9 +- 26 files changed, 39 insertions(+), 1100 deletions(-) delete mode 100644 web/core/components/dashboard/home-dashboard-widgets.tsx delete mode 100644 web/core/components/dashboard/widgets/issues-by-priority.tsx delete mode 100644 web/core/components/dashboard/widgets/issues-by-state-group.tsx delete mode 100644 web/core/components/graphs/index.ts delete mode 100644 web/core/components/graphs/issues-by-priority.tsx delete mode 100644 web/core/components/page-views/index.ts delete mode 100644 web/core/components/page-views/workspace-dashboard.tsx delete mode 100644 web/core/components/profile/overview/priority-distribution/index.ts delete mode 100644 web/core/components/profile/overview/priority-distribution/main-content.tsx delete mode 100644 web/core/components/profile/overview/priority-distribution/priority-distribution.tsx delete mode 100644 web/core/components/ui/graphs/bar-graph.tsx delete mode 100644 web/core/components/ui/graphs/calendar-graph.tsx delete mode 100644 web/core/components/ui/graphs/index.ts delete mode 100644 web/core/components/ui/graphs/line-graph.tsx delete mode 100644 web/core/components/ui/graphs/pie-graph.tsx delete mode 100644 web/core/components/ui/graphs/scatter-plot-graph.tsx delete mode 100644 web/core/components/ui/graphs/types.d.ts diff --git a/web/ce/components/cycles/analytics-sidebar/base.tsx b/web/ce/components/cycles/analytics-sidebar/base.tsx index 40f098a2d03..2d13a7b4b01 100644 --- a/web/ce/components/cycles/analytics-sidebar/base.tsx +++ b/web/ce/components/cycles/analytics-sidebar/base.tsx @@ -65,16 +65,6 @@ export const SidebarChart: FC = observer((props) => {
-
-
- - {t("ideal")} -
-
- - {t("current")} -
-
{cycleStartDate && cycleEndDate && completionChartDistributionData ? ( = ({ className = "", plotTitle = "work items", }) => { - const chartData = Object.keys(distribution ?? []).map((key) => ({ - currentDate: renderFormattedDateWithoutYear(key), - pending: distribution[key], + const chartData: TChartData[] = Object.keys(distribution ?? []).map((key, index) => ({ + name: renderFormattedDateWithoutYear(key), + current: distribution[key] ?? 0, + ideal: totalIssues * (1 - index / (Object.keys(distribution ?? []).length - 1)), })); - const generateXAxisTickValues = () => { - const start = getDate(startDate); - const end = getDate(endDate); - - let dates: Date[] = []; - if (start && end && isValid(start) && isValid(end)) { - dates = eachDayOfInterval({ start, end }); - } - - if (dates.length === 0) return []; - - const formattedDates = dates.map((d) => renderFormattedDateWithoutYear(d)); - const firstDate = formattedDates[0]; - const lastDate = formattedDates[formattedDates.length - 1]; - - if (formattedDates.length <= 2) return [firstDate, lastDate]; - - const middleDateIndex = Math.floor(formattedDates.length / 2); - const middleDate = formattedDates[middleDateIndex]; - - return [firstDate, middleDate, lastDate]; - }; - return (
- 0 - ? chartData.map((item, index) => ({ - index, - x: item.currentDate, - y: item.pending, - color: "#3F76FF", - })) - : [], - enableArea: true, + key: "current", + label: "Current Completed", + strokeColor: "#3F76FF", + fill: "#3F76FF33", + fillOpacity: 1, + showDot: true, + smoothCurves: true, + strokeOpacity: 1, + stackId: "bar-one", }, { - id: "ideal", - color: "#a9bbd0", - fill: "transparent", - data: - chartData.length > 0 - ? [ - { - x: chartData[0].currentDate, - y: totalIssues, - }, - { - x: chartData[chartData.length - 1].currentDate, - y: 0, - }, - ] - : [], + key: "ideal", + label: "Ideal Completion", + strokeColor: "#A9BBD0", + fill: "#A9BBD0", + fillOpacity: 0, + showDot: true, + smoothCurves: true, + strokeOpacity: 1, + stackId: "bar-two", }, ]} - layers={["grid", "markers", "areas", DashedLine, "slices", "points", "axes", "legends"]} - axisBottom={{ - tickValues: generateXAxisTickValues(), - }} - enablePoints={false} - enableArea - colors={(datum) => datum.color ?? "#3F76FF"} - customYAxisTickValues={[0, totalIssues]} - gridXValues={ - chartData.length > 0 ? chartData.map((item, index) => (index % 2 === 0 ? item.currentDate : "")) : undefined - } - enableSlices="x" - sliceTooltip={(datum) => ( -
- {datum.slice.points?.[1]?.data?.yFormatted ?? datum.slice.points[0].data.yFormatted} - {plotTitle} pending on - {datum.slice.points[0].data.xFormatted} -
- )} - theme={{ - background: "transparent", - axis: { - domain: { - line: { - stroke: "rgb(var(--color-border))", - strokeWidth: 1, - }, - }, + xAxis={{ key: "name", label: "Date" }} + yAxis={{ key: "current", label: "Current" }} + margin={{ bottom: 30 }} + className="h-[370px] w-full" + legend={{ + align: "center", + verticalAlign: "bottom", + layout: "horizontal", + wrapperStyles: { + marginTop: 20, }, }} /> diff --git a/web/core/components/cycles/active-cycle/productivity.tsx b/web/core/components/cycles/active-cycle/productivity.tsx index 613355c7eba..b3fb8e212e9 100644 --- a/web/core/components/cycles/active-cycle/productivity.tsx +++ b/web/core/components/cycles/active-cycle/productivity.tsx @@ -54,17 +54,7 @@ export const ActiveCycleProductivity: FC = observe {cycle.total_issues > 0 ? ( <>
-
-
-
- - {t("project_cycles.active_cycle.ideal")} -
-
- - {t("project_cycles.active_cycle.current")} -
-
+
{estimateType === "points" ? ( {`Pending points - ${cycle.backlog_estimate_points + cycle.unstarted_estimate_points + cycle.started_estimate_points}`} ) : ( diff --git a/web/core/components/dashboard/home-dashboard-widgets.tsx b/web/core/components/dashboard/home-dashboard-widgets.tsx deleted file mode 100644 index fe64278dc99..00000000000 --- a/web/core/components/dashboard/home-dashboard-widgets.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -// types -import { TWidgetKeys } from "@plane/types"; -// components -import { - AssignedIssuesWidget, - CreatedIssuesWidget, - IssuesByPriorityWidget, - IssuesByStateGroupWidget, - OverviewStatsWidget, - RecentActivityWidget, - RecentCollaboratorsWidget, - RecentProjectsWidget, - WidgetProps, -} from "@/components/dashboard"; -// hooks -import { useDashboard } from "@/hooks/store"; - -const WIDGETS_LIST: { - [key in TWidgetKeys]: { component: React.FC; fullWidth: boolean }; -} = { - overview_stats: { component: OverviewStatsWidget, fullWidth: true }, - assigned_issues: { component: AssignedIssuesWidget, fullWidth: false }, - created_issues: { component: CreatedIssuesWidget, fullWidth: false }, - issues_by_state_groups: { component: IssuesByStateGroupWidget, fullWidth: false }, - issues_by_priority: { component: IssuesByPriorityWidget, fullWidth: false }, - recent_activity: { component: RecentActivityWidget, fullWidth: false }, - recent_projects: { component: RecentProjectsWidget, fullWidth: false }, - recent_collaborators: { component: RecentCollaboratorsWidget, fullWidth: true }, -}; - -export const DashboardWidgets = observer(() => { - // router - const { workspaceSlug } = useParams(); - // store hooks - const { homeDashboardId, homeDashboardWidgets } = useDashboard(); - - const doesWidgetExist = (widgetKey: TWidgetKeys) => - Boolean(homeDashboardWidgets?.find((widget) => widget.key === widgetKey)); - - if (!workspaceSlug || !homeDashboardId) return null; - - return ( -
- {Object.entries(WIDGETS_LIST).map(([key, widget]) => { - const WidgetComponent = widget.component; - // if the widget doesn't exist, return null - if (!doesWidgetExist(key as TWidgetKeys)) return null; - // if the widget is full width, return it in a 2 column grid - if (widget.fullWidth) - return ( -
- -
- ); - else - return ; - })} -
- ); -}); diff --git a/web/core/components/dashboard/index.ts b/web/core/components/dashboard/index.ts index 129cdb69ea3..e88b1c701d9 100644 --- a/web/core/components/dashboard/index.ts +++ b/web/core/components/dashboard/index.ts @@ -1,3 +1,2 @@ export * from "./widgets"; -export * from "./home-dashboard-widgets"; export * from "./project-empty-state"; diff --git a/web/core/components/dashboard/widgets/index.ts b/web/core/components/dashboard/widgets/index.ts index 31fc645d410..e622d708f71 100644 --- a/web/core/components/dashboard/widgets/index.ts +++ b/web/core/components/dashboard/widgets/index.ts @@ -5,8 +5,6 @@ export * from "./issue-panels"; export * from "./loaders"; export * from "./assigned-issues"; export * from "./created-issues"; -export * from "./issues-by-priority"; -export * from "./issues-by-state-group"; export * from "./overview-stats"; export * from "./recent-activity"; export * from "./recent-collaborators"; diff --git a/web/core/components/dashboard/widgets/issues-by-priority.tsx b/web/core/components/dashboard/widgets/issues-by-priority.tsx deleted file mode 100644 index ac678812057..00000000000 --- a/web/core/components/dashboard/widgets/issues-by-priority.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { useEffect } from "react"; -import { observer } from "mobx-react"; -import Link from "next/link"; -// types -import { EDurationFilters } from "@plane/constants"; -import { TIssuesByPriorityWidgetFilters, TIssuesByPriorityWidgetResponse } from "@plane/types"; -// components -import { Card } from "@plane/ui"; -import { - DurationFilterDropdown, - IssuesByPriorityEmptyState, - WidgetLoader, - WidgetProps, -} from "@/components/dashboard/widgets"; -import { IssuesByPriorityGraph } from "@/components/graphs"; -// constants -// helpers -import { getCustomDates } from "@/helpers/dashboard.helper"; -// hooks -import { useDashboard } from "@/hooks/store"; -import { useAppRouter } from "@/hooks/use-app-router"; - -const WIDGET_KEY = "issues_by_priority"; - -export const IssuesByPriorityWidget: React.FC = observer((props) => { - const { dashboardId, workspaceSlug } = props; - // router - const router = useAppRouter(); - // store hooks - const { fetchWidgetStats, getWidgetDetails, getWidgetStats, updateDashboardWidgetFilters } = useDashboard(); - // derived values - const widgetDetails = getWidgetDetails(workspaceSlug, dashboardId, WIDGET_KEY); - const widgetStats = getWidgetStats(workspaceSlug, dashboardId, WIDGET_KEY); - const selectedDuration = widgetDetails?.widget_filters.duration ?? EDurationFilters.NONE; - const selectedCustomDates = widgetDetails?.widget_filters.custom_dates ?? []; - - const handleUpdateFilters = async (filters: Partial) => { - if (!widgetDetails) return; - - await updateDashboardWidgetFilters(workspaceSlug, dashboardId, widgetDetails.id, { - widgetKey: WIDGET_KEY, - filters, - }); - - const filterDates = getCustomDates( - filters.duration ?? selectedDuration, - filters.custom_dates ?? selectedCustomDates - ); - fetchWidgetStats(workspaceSlug, dashboardId, { - widget_key: WIDGET_KEY, - ...(filterDates.trim() !== "" ? { target_date: filterDates } : {}), - }); - }; - - useEffect(() => { - const filterDates = getCustomDates(selectedDuration, selectedCustomDates); - fetchWidgetStats(workspaceSlug, dashboardId, { - widget_key: WIDGET_KEY, - ...(filterDates.trim() !== "" ? { target_date: filterDates } : {}), - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - if (!widgetDetails || !widgetStats) return ; - - const totalCount = widgetStats.reduce((acc, item) => acc + item?.count, 0); - const chartData = widgetStats.map((item) => ({ - priority: item?.priority, - priority_count: item?.count, - })); - - return ( - -
- - Assigned by priority - - - handleUpdateFilters({ - duration: val, - ...(val === "custom" ? { custom_dates: customDates } : {}), - }) - } - /> -
- {totalCount > 0 ? ( -
-
- { - router.push( - `/${workspaceSlug}/workspace-views/assigned?priority=${`${datum.data.priority}`.toLowerCase()}` - ); - }} - /> -
-
- ) : ( -
- -
- )} -
- ); -}); diff --git a/web/core/components/dashboard/widgets/issues-by-state-group.tsx b/web/core/components/dashboard/widgets/issues-by-state-group.tsx deleted file mode 100644 index fec4204cfc3..00000000000 --- a/web/core/components/dashboard/widgets/issues-by-state-group.tsx +++ /dev/null @@ -1,251 +0,0 @@ -import { useEffect, useState } from "react"; -import { linearGradientDef } from "@nivo/core"; -import { observer } from "mobx-react"; -import Link from "next/link"; -// types -import { EDurationFilters, STATE_GROUPS } from "@plane/constants"; -import { TIssuesByStateGroupsWidgetFilters, TIssuesByStateGroupsWidgetResponse, TStateGroups } from "@plane/types"; -// components -import { Card } from "@plane/ui"; -import { - DurationFilterDropdown, - IssuesByStateGroupEmptyState, - WidgetLoader, - WidgetProps, -} from "@/components/dashboard/widgets"; -import { PieGraph } from "@/components/ui"; -// helpers -import { getCustomDates } from "@/helpers/dashboard.helper"; -// hooks -import { useDashboard } from "@/hooks/store"; -import { useAppRouter } from "@/hooks/use-app-router"; - -const WIDGET_KEY = "issues_by_state_groups"; - -export const STATE_GROUP_GRAPH_COLORS: Record = { - backlog: "#CDCED6", - unstarted: "#80838D", - started: "#FFC53D", - completed: "#3E9B4F", - cancelled: "#E5484D", -}; -// colors for work items by state group widget graph arcs -export const STATE_GROUP_GRAPH_GRADIENTS = [ - linearGradientDef("gradientBacklog", [ - { offset: 0, color: "#DEDEDE" }, - { offset: 100, color: "#BABABE" }, - ]), - linearGradientDef("gradientUnstarted", [ - { offset: 0, color: "#D4D4D4" }, - { offset: 100, color: "#878796" }, - ]), - linearGradientDef("gradientStarted", [ - { offset: 0, color: "#FFD300" }, - { offset: 100, color: "#FAE270" }, - ]), - linearGradientDef("gradientCompleted", [ - { offset: 0, color: "#0E8B1B" }, - { offset: 100, color: "#37CB46" }, - ]), - linearGradientDef("gradientCanceled", [ - { offset: 0, color: "#C90004" }, - { offset: 100, color: "#FF7679" }, - ]), -]; - -export const IssuesByStateGroupWidget: React.FC = observer((props) => { - const { dashboardId, workspaceSlug } = props; - // states - const [defaultStateGroup, setDefaultStateGroup] = useState(null); - const [activeStateGroup, setActiveStateGroup] = useState(null); - // router - const router = useAppRouter(); - // store hooks - const { fetchWidgetStats, getWidgetDetails, getWidgetStats, updateDashboardWidgetFilters } = useDashboard(); - // derived values - const widgetDetails = getWidgetDetails(workspaceSlug, dashboardId, WIDGET_KEY); - const widgetStats = getWidgetStats(workspaceSlug, dashboardId, WIDGET_KEY); - const selectedDuration = widgetDetails?.widget_filters.duration ?? EDurationFilters.NONE; - const selectedCustomDates = widgetDetails?.widget_filters.custom_dates ?? []; - - const handleUpdateFilters = async (filters: Partial) => { - if (!widgetDetails) return; - - await updateDashboardWidgetFilters(workspaceSlug, dashboardId, widgetDetails.id, { - widgetKey: WIDGET_KEY, - filters, - }); - - const filterDates = getCustomDates( - filters.duration ?? selectedDuration, - filters.custom_dates ?? selectedCustomDates - ); - fetchWidgetStats(workspaceSlug, dashboardId, { - widget_key: WIDGET_KEY, - ...(filterDates.trim() !== "" ? { target_date: filterDates } : {}), - }); - }; - - // fetch widget stats - useEffect(() => { - const filterDates = getCustomDates(selectedDuration, selectedCustomDates); - fetchWidgetStats(workspaceSlug, dashboardId, { - widget_key: WIDGET_KEY, - ...(filterDates.trim() !== "" ? { target_date: filterDates } : {}), - }); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - // set active group for center metric - useEffect(() => { - if (!widgetStats) return; - - const startedCount = widgetStats?.find((item) => item?.state === "started")?.count ?? 0; - const unStartedCount = widgetStats?.find((item) => item?.state === "unstarted")?.count ?? 0; - const backlogCount = widgetStats?.find((item) => item?.state === "backlog")?.count ?? 0; - const completedCount = widgetStats?.find((item) => item?.state === "completed")?.count ?? 0; - const canceledCount = widgetStats?.find((item) => item?.state === "cancelled")?.count ?? 0; - - const stateGroup = - startedCount > 0 - ? "started" - : unStartedCount > 0 - ? "unstarted" - : backlogCount > 0 - ? "backlog" - : completedCount > 0 - ? "completed" - : canceledCount > 0 - ? "cancelled" - : null; - - setActiveStateGroup(stateGroup); - setDefaultStateGroup(stateGroup); - }, [widgetStats]); - - if (!widgetDetails || !widgetStats) return ; - - const totalCount = widgetStats?.reduce((acc, item) => acc + item?.count, 0); - const chartData = widgetStats?.map((item) => ({ - color: STATE_GROUP_GRAPH_COLORS[item?.state as keyof typeof STATE_GROUP_GRAPH_COLORS], - id: item?.state, - label: item?.state, - value: (item?.count / totalCount) * 100, - })); - - const CenteredMetric = ({ dataWithArc, centerX, centerY }: any) => { - const data = dataWithArc?.find((datum: any) => datum?.id === activeStateGroup); - const percentage = chartData?.find((item) => item.id === activeStateGroup)?.value?.toFixed(0); - - return ( - - - {percentage}% - - - {data?.id} - - - ); - }; - - return ( - -
- - Assigned by state - - - handleUpdateFilters({ - duration: val, - ...(val === "custom" ? { custom_dates: customDates } : {}), - }) - } - /> -
- {totalCount > 0 ? ( -
-
-
- datum.data.color} - padAngle={1} - enableArcLinkLabels={false} - enableArcLabels={false} - activeOuterRadiusOffset={5} - tooltip={() => <>} - margin={{ - top: 0, - right: 5, - bottom: 0, - left: 5, - }} - defs={STATE_GROUP_GRAPH_GRADIENTS} - fill={Object.values(STATE_GROUPS).map((p) => ({ - match: { - id: p.key, - }, - id: `gradient${p.label}`, - }))} - onClick={(datum, e) => { - e.preventDefault(); - e.stopPropagation(); - router.push(`/${workspaceSlug}/workspace-views/assigned/?state_group=${datum.id}`); - }} - onMouseEnter={(datum) => setActiveStateGroup(datum.id as TStateGroups)} - onMouseLeave={() => setActiveStateGroup(defaultStateGroup)} - layers={["arcs", CenteredMetric]} - /> -
-
- {chartData.map((item) => ( -
-
-
- {item.label} -
- {item.value.toFixed(0)}% -
- ))} -
-
-
- ) : ( -
- -
- )} - - ); -}); diff --git a/web/core/components/graphs/index.ts b/web/core/components/graphs/index.ts deleted file mode 100644 index 305c3944ea4..00000000000 --- a/web/core/components/graphs/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./issues-by-priority"; diff --git a/web/core/components/graphs/issues-by-priority.tsx b/web/core/components/graphs/issues-by-priority.tsx deleted file mode 100644 index faed3709ec6..00000000000 --- a/web/core/components/graphs/issues-by-priority.tsx +++ /dev/null @@ -1,169 +0,0 @@ -import { ComputedDatum } from "@nivo/bar"; -import { Theme, linearGradientDef } from "@nivo/core"; -import { ISSUE_PRIORITIES } from "@plane/constants"; -// components -import { TIssuePriorities } from "@plane/types"; -import { BarGraph } from "@/components/ui"; -// helpers -import { capitalizeFirstLetter } from "@/helpers/string.helper"; - -// gradients for work items by priority widget graph bars -export const PRIORITY_GRAPH_GRADIENTS = [ - linearGradientDef( - "gradient_urgent", - [ - { offset: 0, color: "#A90408" }, - { offset: 100, color: "#DF4D51" }, - ], - { - x1: 1, - y1: 0, - x2: 0, - y2: 0, - } - ), - linearGradientDef( - "gradient_high", - [ - { offset: 0, color: "#FE6B00" }, - { offset: 100, color: "#FFAC88" }, - ], - { - x1: 1, - y1: 0, - x2: 0, - y2: 0, - } - ), - linearGradientDef( - "gradient_medium", - [ - { offset: 0, color: "#F5AC00" }, - { offset: 100, color: "#FFD675" }, - ], - { - x1: 1, - y1: 0, - x2: 0, - y2: 0, - } - ), - linearGradientDef( - "gradient_low", - [ - { offset: 0, color: "#1B46DE" }, - { offset: 100, color: "#4F9BF4" }, - ], - { - x1: 1, - y1: 0, - x2: 0, - y2: 0, - } - ), - linearGradientDef( - "gradient_none", - [ - { offset: 0, color: "#A0A1A9" }, - { offset: 100, color: "#B9BBC6" }, - ], - { - x1: 1, - y1: 0, - x2: 0, - y2: 0, - } - ), -]; - -type Props = { - borderRadius?: number; - data: { - priority: TIssuePriorities; - priority_count: number; - }[]; - height?: number; - onBarClick?: ( - datum: ComputedDatum & { - color: string; - } - ) => void; - padding?: number; - theme?: Theme; -}; - -const PRIORITY_TEXT_COLORS = { - urgent: "#CE2C31", - high: "#AB4800", - medium: "#AB6400", - low: "#1F2D5C", - none: "#60646C", -}; - -export const IssuesByPriorityGraph: React.FC = (props) => { - const { borderRadius = 8, data, height = 300, onBarClick, padding = 0.05, theme } = props; - - const chartData = data.map((priority) => ({ - priority: capitalizeFirstLetter(priority.priority), - value: priority.priority_count, - })); - - return ( - p.priority_count)} - axisBottom={{ - tickPadding: 8, - tickSize: 0, - }} - tooltip={(datum) => ( -
- - {datum.data.priority}: - {datum.value} -
- )} - colors={({ data }) => `url(#gradient${data.priority})`} - defs={PRIORITY_GRAPH_GRADIENTS} - fill={ISSUE_PRIORITIES.map((p) => ({ - match: { - id: p.key, - }, - id: `gradient_${p.key}`, - }))} - onClick={(datum) => { - if (onBarClick) onBarClick(datum); - }} - theme={{ - axis: { - domain: { - line: { - stroke: "transparent", - }, - }, - ticks: { - text: { - fontSize: 13, - }, - }, - }, - grid: { - line: { - stroke: "transparent", - }, - }, - ...theme, - }} - /> - ); -}; diff --git a/web/core/components/modules/analytics-sidebar/issue-progress.tsx b/web/core/components/modules/analytics-sidebar/issue-progress.tsx index a29334ff83f..c8237df79fa 100644 --- a/web/core/components/modules/analytics-sidebar/issue-progress.tsx +++ b/web/core/components/modules/analytics-sidebar/issue-progress.tsx @@ -211,16 +211,6 @@ export const ModuleAnalyticsProgress: FC = observer((p {/* progress burndown chart */}
-
-
- - {t("ideal")} -
-
- - {t("current")} -
-
{moduleStartDate && moduleEndDate && completionChartDistributionData && ( {plotType === "points" ? ( diff --git a/web/core/components/page-views/index.ts b/web/core/components/page-views/index.ts deleted file mode 100644 index 0491e8caf53..00000000000 --- a/web/core/components/page-views/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./workspace-dashboard"; diff --git a/web/core/components/page-views/workspace-dashboard.tsx b/web/core/components/page-views/workspace-dashboard.tsx deleted file mode 100644 index 19d3590b07f..00000000000 --- a/web/core/components/page-views/workspace-dashboard.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { useEffect } from "react"; -import { observer } from "mobx-react"; -import { useParams } from "next/navigation"; -// plane imports -import { EUserPermissionsLevel, PRODUCT_TOUR_COMPLETED, EUserPermissions } from "@plane/constants"; -import { useTranslation } from "@plane/i18n"; -import { ContentWrapper } from "@plane/ui"; -// components -import { DashboardWidgets } from "@/components/dashboard"; -import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; -import { IssuePeekOverview } from "@/components/issues"; -import { TourRoot } from "@/components/onboarding"; -import { UserGreetingsView } from "@/components/user"; -// constants -// helpers -import { cn } from "@/helpers/common.helper"; -// hooks -import { - useCommandPalette, - useUserProfile, - useEventTracker, - useDashboard, - useProject, - useUser, - useUserPermissions, -} from "@/hooks/store"; -import { useResolvedAssetPath } from "@/hooks/use-resolved-asset-path"; -import useSize from "@/hooks/use-window-size"; - -export const WorkspaceDashboardView = observer(() => { - // plane hooks - const { t } = useTranslation(); - // store hooks - const { captureEvent, setTrackElement } = useEventTracker(); - const { toggleCreateProjectModal } = useCommandPalette(); - const { workspaceSlug } = useParams(); - const { data: currentUser } = useUser(); - const { data: currentUserProfile, updateTourCompleted } = useUserProfile(); - const { homeDashboardId, fetchHomeDashboardWidgets } = useDashboard(); - const { joinedProjectIds, loader } = useProject(); - const { allowPermissions } = useUserPermissions(); - - // helper hooks - const [windowWidth] = useSize(); - const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/onboarding/dashboard" }); - - const handleTourCompleted = () => { - updateTourCompleted() - .then(() => { - captureEvent(PRODUCT_TOUR_COMPLETED, { - user_id: currentUser?.id, - state: "SUCCESS", - }); - }) - .catch((error) => { - console.error(error); - }); - }; - - // fetch home dashboard widgets on workspace change - useEffect(() => { - if (!workspaceSlug) return; - - fetchHomeDashboardWidgets(workspaceSlug?.toString()); - }, [fetchHomeDashboardWidgets, workspaceSlug]); - - const canPerformEmptyStateActions = allowPermissions( - [EUserPermissions.ADMIN, EUserPermissions.MEMBER], - EUserPermissionsLevel.WORKSPACE - ); - - // TODO: refactor loader implementation - return ( - <> - {currentUserProfile && !currentUserProfile.is_tour_completed && ( -
- -
- )} - {homeDashboardId && joinedProjectIds && ( - <> - {joinedProjectIds.length > 0 || loader === "init-loader" ? ( - <> - - = 768, - })} - > - {currentUser && } - - - - - ) : ( - { - setTrackElement("Dashboard empty state"); - toggleCreateProjectModal(true); - }} - disabled={!canPerformEmptyStateActions} - /> - } - /> - )} - - )} - - ); -}); diff --git a/web/core/components/profile/overview/priority-distribution/index.ts b/web/core/components/profile/overview/priority-distribution/index.ts deleted file mode 100644 index 64d81eb1244..00000000000 --- a/web/core/components/profile/overview/priority-distribution/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./priority-distribution"; diff --git a/web/core/components/profile/overview/priority-distribution/main-content.tsx b/web/core/components/profile/overview/priority-distribution/main-content.tsx deleted file mode 100644 index 5a4f64bcebd..00000000000 --- a/web/core/components/profile/overview/priority-distribution/main-content.tsx +++ /dev/null @@ -1,31 +0,0 @@ -// components -import { IUserPriorityDistribution } from "@plane/types"; -import { IssuesByPriorityGraph } from "@/components/graphs"; -import { ProfileEmptyState } from "@/components/ui"; -// assets -import emptyBarGraph from "@/public/empty-state/empty_bar_graph.svg"; -// types - -type Props = { - priorityDistribution: IUserPriorityDistribution[]; -}; - -export const PriorityDistributionContent: React.FC = (props) => { - const { priorityDistribution } = props; - - return ( -
- {priorityDistribution.length > 0 ? ( - - ) : ( -
- -
- )} -
- ); -}; diff --git a/web/core/components/profile/overview/priority-distribution/priority-distribution.tsx b/web/core/components/profile/overview/priority-distribution/priority-distribution.tsx deleted file mode 100644 index a7bca192bcc..00000000000 --- a/web/core/components/profile/overview/priority-distribution/priority-distribution.tsx +++ /dev/null @@ -1,35 +0,0 @@ -"use client"; - -// components -// ui -import { IUserPriorityDistribution } from "@plane/types"; -import { Loader } from "@plane/ui"; -// types -import { PriorityDistributionContent } from "./main-content"; - -type Props = { - priorityDistribution: IUserPriorityDistribution[] | undefined; -}; - -export const ProfilePriorityDistribution: React.FC = (props) => { - const { priorityDistribution } = props; - - return ( -
-

Work items by priority

- {priorityDistribution ? ( - - ) : ( -
- - - - - - - -
- )} -
- ); -}; diff --git a/web/core/components/ui/graphs/bar-graph.tsx b/web/core/components/ui/graphs/bar-graph.tsx deleted file mode 100644 index 1a724322e37..00000000000 --- a/web/core/components/ui/graphs/bar-graph.tsx +++ /dev/null @@ -1,49 +0,0 @@ -// nivo -import { ResponsiveBar, BarSvgProps } from "@nivo/bar"; -import { CHARTS_THEME, CHART_DEFAULT_MARGIN } from "@plane/constants"; -// helpers -import { generateYAxisTickValues } from "@/helpers/graph.helper"; -// types -import { TGraph } from "./types"; -// constants - -type Props = { - indexBy: string; - keys: string[]; - customYAxisTickValues?: number[]; -}; - -export const BarGraph: React.FC, "height" | "width">> = ({ - indexBy, - keys, - customYAxisTickValues, - height = "400px", - width = "100%", - margin, - theme, - ...rest -}) => ( -
- 7) ? 0.8 : 0.9} - axisLeft={{ - tickSize: 0, - tickPadding: 10, - tickValues: customYAxisTickValues ? generateYAxisTickValues(customYAxisTickValues) : undefined, - }} - axisBottom={{ - tickSize: 0, - tickPadding: 10, - tickRotation: rest.data.length > 7 ? -45 : 0, - }} - labelTextColor={{ from: "color", modifiers: [["darker", 1.6]] }} - theme={{ ...CHARTS_THEME, ...(theme ?? {}) }} - animate - enableLabel={rest.enableLabel ?? false} - {...rest} - /> -
-); diff --git a/web/core/components/ui/graphs/calendar-graph.tsx b/web/core/components/ui/graphs/calendar-graph.tsx deleted file mode 100644 index 5a63dd640da..00000000000 --- a/web/core/components/ui/graphs/calendar-graph.tsx +++ /dev/null @@ -1,34 +0,0 @@ -// nivo -import { ResponsiveCalendar, CalendarSvgProps } from "@nivo/calendar"; -// types -import { CHARTS_THEME, CHART_DEFAULT_MARGIN } from "@plane/constants"; -import { TGraph } from "./types"; -// constants - -export const CalendarGraph: React.FC> = ({ - height = "400px", - width = "100%", - margin, - theme, - ...rest -}) => ( -
- -
-); diff --git a/web/core/components/ui/graphs/index.ts b/web/core/components/ui/graphs/index.ts deleted file mode 100644 index 984bb642cf2..00000000000 --- a/web/core/components/ui/graphs/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./bar-graph"; -export * from "./calendar-graph"; -export * from "./line-graph"; -export * from "./pie-graph"; -export * from "./scatter-plot-graph"; diff --git a/web/core/components/ui/graphs/line-graph.tsx b/web/core/components/ui/graphs/line-graph.tsx deleted file mode 100644 index e04d7ea6c43..00000000000 --- a/web/core/components/ui/graphs/line-graph.tsx +++ /dev/null @@ -1,35 +0,0 @@ -// nivo -import { ResponsiveLine, LineSvgProps } from "@nivo/line"; -// helpers -import { CHARTS_THEME, CHART_DEFAULT_MARGIN } from "@plane/constants"; -import { generateYAxisTickValues } from "@/helpers/graph.helper"; -// types -import { TGraph } from "./types"; -// constants - -type Props = { - customYAxisTickValues?: number[]; -}; - -export const LineGraph: React.FC = ({ - customYAxisTickValues, - height = "400px", - width = "100%", - margin, - theme, - ...rest -}) => ( -
- -
-); diff --git a/web/core/components/ui/graphs/pie-graph.tsx b/web/core/components/ui/graphs/pie-graph.tsx deleted file mode 100644 index 64585974164..00000000000 --- a/web/core/components/ui/graphs/pie-graph.tsx +++ /dev/null @@ -1,23 +0,0 @@ -// nivo -import { PieSvgProps, ResponsivePie } from "@nivo/pie"; -// types -import { CHARTS_THEME, CHART_DEFAULT_MARGIN } from "@plane/constants"; -import { TGraph } from "./types"; -// constants - -export const PieGraph: React.FC, "height" | "width">> = ({ - height = "400px", - width = "100%", - margin, - theme, - ...rest -}) => ( -
- -
-); diff --git a/web/core/components/ui/graphs/scatter-plot-graph.tsx b/web/core/components/ui/graphs/scatter-plot-graph.tsx deleted file mode 100644 index e4a7d7fcc61..00000000000 --- a/web/core/components/ui/graphs/scatter-plot-graph.tsx +++ /dev/null @@ -1,23 +0,0 @@ -// nivo -import { ResponsiveScatterPlot, ScatterPlotSvgProps } from "@nivo/scatterplot"; -// types -import { CHARTS_THEME, CHART_DEFAULT_MARGIN } from "@plane/constants"; -import { TGraph } from "./types"; -// constants - -export const ScatterPlotGraph: React.FC, "height" | "width">> = ({ - height = "400px", - width = "100%", - margin, - theme, - ...rest -}) => ( -
- -
-); diff --git a/web/core/components/ui/graphs/types.d.ts b/web/core/components/ui/graphs/types.d.ts deleted file mode 100644 index c8646405cf0..00000000000 --- a/web/core/components/ui/graphs/types.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Theme, Margin } from "@nivo/core"; - -export type TGraph = { - height?: string; - width?: string; - margin?: Partial; - theme?: Theme; -}; diff --git a/web/core/components/ui/index.ts b/web/core/components/ui/index.ts index e441b896f25..35367be7ece 100644 --- a/web/core/components/ui/index.ts +++ b/web/core/components/ui/index.ts @@ -1,4 +1,3 @@ -export * from "./graphs"; export * from "./empty-space"; export * from "./labels-list"; export * from "./markdown-to-component"; diff --git a/web/next.config.js b/web/next.config.js index b7195885463..41ed049c558 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -24,12 +24,6 @@ const nextConfig = { "lucide-react", "date-fns", "@headlessui/react", - "@nivo/core", - "@nivo/bar", - "@nivo/line", - "@nivo/pie", - "@nivo/calendar", - "@nivo/scatterplot", "react-color", "react-day-picker", "react-dropzone", diff --git a/web/package.json b/web/package.json index 7eb12c8ac87..b23881e4937 100644 --- a/web/package.json +++ b/web/package.json @@ -22,13 +22,6 @@ "@blueprintjs/popover2": "^1.13.3", "@headlessui/react": "^1.7.3", "@intercom/messenger-js-sdk": "^0.0.12", - "@nivo/bar": "^0.88.0", - "@nivo/calendar": "^0.88.0", - "@nivo/core": "^0.88.0", - "@nivo/legends": "^0.88.0", - "@nivo/line": "^0.88.0", - "@nivo/pie": "^0.88.0", - "@nivo/scatterplot": "^0.88.0", "@plane/constants": "*", "@plane/editor": "*", "@plane/hooks": "*", @@ -93,4 +86,4 @@ "prettier": "^3.2.5", "typescript": "5.3.3" } -} +} \ No newline at end of file From df51adbefd3f5d4a72bc367425591d38c52405ad Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Tue, 3 Jun 2025 16:46:48 +0530 Subject: [PATCH 13/19] chore: resolved coderabbit comments --- .../cycles/analytics-sidebar/base.tsx | 2 - .../core/sidebar/progress-chart.tsx | 53 ++++--------------- .../cycles/active-cycle/productivity.tsx | 4 -- .../analytics-sidebar/issue-progress.tsx | 4 -- 4 files changed, 9 insertions(+), 54 deletions(-) diff --git a/web/ce/components/cycles/analytics-sidebar/base.tsx b/web/ce/components/cycles/analytics-sidebar/base.tsx index 2d13a7b4b01..881ab6ab315 100644 --- a/web/ce/components/cycles/analytics-sidebar/base.tsx +++ b/web/ce/components/cycles/analytics-sidebar/base.tsx @@ -69,8 +69,6 @@ export const SidebarChart: FC = observer((props) => { diff --git a/web/core/components/core/sidebar/progress-chart.tsx b/web/core/components/core/sidebar/progress-chart.tsx index 3a0b8b75308..e6317eeb9f0 100644 --- a/web/core/components/core/sidebar/progress-chart.tsx +++ b/web/core/components/core/sidebar/progress-chart.tsx @@ -1,55 +1,16 @@ import React from "react"; -import { eachDayOfInterval, isValid } from "date-fns"; import { AreaChart } from "@plane/propel/charts/area-chart"; import { TChartData, TModuleCompletionChartDistribution } from "@plane/types"; -// ui -// helpers -import { getDate, renderFormattedDateWithoutYear } from "@/helpers/date-time.helper"; -//types +import { renderFormattedDateWithoutYear } from "@/helpers/date-time.helper"; type Props = { distribution: TModuleCompletionChartDistribution; - startDate: string | Date; - endDate: string | Date; totalIssues: number; className?: string; plotTitle?: string; }; -const styleById = { - ideal: { - strokeDasharray: "6, 3", - strokeWidth: 1, - }, - default: { - strokeWidth: 1, - }, -}; - -const DashedLine = ({ series, lineGenerator, xScale, yScale }: any) => - series.map(({ id, data, color }: any) => ( - ({ - x: xScale(d.data.x), - y: yScale(d.data.y), - })) - )} - fill="none" - stroke={color ?? "#ddd"} - style={styleById[id as keyof typeof styleById] || styleById.default} - /> - )); - -const ProgressChart: React.FC = ({ - distribution, - startDate, - endDate, - totalIssues, - className = "", - plotTitle = "work items", -}) => { +const ProgressChart: React.FC = ({ distribution, totalIssues, className = "", plotTitle = "work items" }) => { const chartData: TChartData[] = Object.keys(distribution ?? []).map((key, index) => ({ name: renderFormattedDateWithoutYear(key), current: distribution[key] ?? 0, @@ -63,7 +24,7 @@ const ProgressChart: React.FC = ({ areas={[ { key: "current", - label: "Current Completed", + label: `Current ${plotTitle}`, strokeColor: "#3F76FF", fill: "#3F76FF33", fillOpacity: 1, @@ -74,7 +35,7 @@ const ProgressChart: React.FC = ({ }, { key: "ideal", - label: "Ideal Completion", + label: `Ideal ${plotTitle}`, strokeColor: "#A9BBD0", fill: "#A9BBD0", fillOpacity: 0, @@ -82,10 +43,14 @@ const ProgressChart: React.FC = ({ smoothCurves: true, strokeOpacity: 1, stackId: "bar-two", + style: { + strokeDasharray: "6, 3", + strokeWidth: 1, + }, }, ]} xAxis={{ key: "name", label: "Date" }} - yAxis={{ key: "current", label: "Current" }} + yAxis={{ key: "current", label: "Completion" }} margin={{ bottom: 30 }} className="h-[370px] w-full" legend={{ diff --git a/web/core/components/cycles/active-cycle/productivity.tsx b/web/core/components/cycles/active-cycle/productivity.tsx index b3fb8e212e9..f53e2ef8760 100644 --- a/web/core/components/cycles/active-cycle/productivity.tsx +++ b/web/core/components/cycles/active-cycle/productivity.tsx @@ -68,16 +68,12 @@ export const ActiveCycleProductivity: FC = observe {estimateType === "points" ? ( ) : ( diff --git a/web/core/components/modules/analytics-sidebar/issue-progress.tsx b/web/core/components/modules/analytics-sidebar/issue-progress.tsx index c8237df79fa..05950d285b5 100644 --- a/web/core/components/modules/analytics-sidebar/issue-progress.tsx +++ b/web/core/components/modules/analytics-sidebar/issue-progress.tsx @@ -216,16 +216,12 @@ export const ModuleAnalyticsProgress: FC = observer((p {plotType === "points" ? ( ) : ( From aeca79463d206c1ae1f3892c1f8eb06e49f81469 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Tue, 3 Jun 2025 17:26:51 +0530 Subject: [PATCH 14/19] fix: update processUrl to handle custom-work-items in peek view --- web/core/services/analytics.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/core/services/analytics.service.ts b/web/core/services/analytics.service.ts index 400a616f347..15024dbff44 100644 --- a/web/core/services/analytics.service.ts +++ b/web/core/services/analytics.service.ts @@ -78,12 +78,12 @@ export class AnalyticsService extends APIService { processUrl( endpoint: string, workspaceSlug: string, - tab: T, + tab: TAnalyticsGraphsBase | TAnalyticsTabsBase, params?: Record, isPeekView?: boolean ) { let processedUrl = `/api/workspaces/${workspaceSlug}`; - if (isPeekView && tab === "work-items") { + if (isPeekView && (tab === "work-items" || tab === "custom-work-items")) { const projectId = params?.project_ids.split(",")[0]; processedUrl += `/projects/${projectId}`; } From cf0c86c0baed6bcf6c89fc2a936bd51b5f88d47c Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Tue, 3 Jun 2025 18:15:36 +0530 Subject: [PATCH 15/19] feat: implement CSV export functionality in InsightTable component --- web/core/components/analytics/config.ts | 9 ++++++ .../analytics/insight-table/root.tsx | 32 ++----------------- .../work-items/workitems-insight-table.tsx | 21 +++++++++++- 3 files changed, 32 insertions(+), 30 deletions(-) create mode 100644 web/core/components/analytics/config.ts diff --git a/web/core/components/analytics/config.ts b/web/core/components/analytics/config.ts new file mode 100644 index 00000000000..5e297e908bf --- /dev/null +++ b/web/core/components/analytics/config.ts @@ -0,0 +1,9 @@ +import { mkConfig } from "export-to-csv"; + +export const csvConfig = (workspaceSlug: string) => + mkConfig({ + fieldSeparator: ",", + filename: `${workspaceSlug}-analytics`, + decimalSeparator: ".", + useKeysAsHeaders: true, + }); diff --git a/web/core/components/analytics/insight-table/root.tsx b/web/core/components/analytics/insight-table/root.tsx index aab4a0f7797..e87e970f03f 100644 --- a/web/core/components/analytics/insight-table/root.tsx +++ b/web/core/components/analytics/insight-table/root.tsx @@ -1,6 +1,4 @@ import { ColumnDef, Row, Table } from "@tanstack/react-table"; -import { download, generateCsv, mkConfig } from "export-to-csv"; -import { useParams } from "next/navigation"; import { Download } from "lucide-react"; import { useTranslation } from "@plane/i18n"; import { AnalyticsTableDataMap, TAnalyticsTabsBase } from "@plane/types"; @@ -14,42 +12,18 @@ interface InsightTableProps> { columns: ColumnDef[]; columnsLabels?: Record; headerText: string; + onExport?: (rows: Row[]) => void; } export const InsightTable = >( props: InsightTableProps ): React.ReactElement => { - const { data, isLoading, columns, columnsLabels, headerText } = props; - const params = useParams(); + const { data, isLoading, columns, headerText, onExport } = props; const { t } = useTranslation(); - const workspaceSlug = params.workspaceSlug.toString(); if (isLoading) { return ; } - const csvConfig = mkConfig({ - fieldSeparator: ",", - filename: `${workspaceSlug}-analytics`, - decimalSeparator: ".", - useKeysAsHeaders: true, - }); - - const exportCSV = (rows: Row[]) => { - const rowData: any = rows.map((row) => { - const { project_id, avatar_url, assignee_id, ...exportableData } = row.original; - return Object.fromEntries( - Object.entries(exportableData).map(([key, value]) => { - if (columnsLabels?.[key]) { - return [columnsLabels[key], value]; - } - return [key, value]; - }) - ); - }); - const csv = generateCsv(csvConfig)(rowData); - download(csvConfig)(csv); - }; - return (
{data ? ( @@ -61,7 +35,7 @@ export const InsightTable = >( diff --git a/web/core/components/analytics/work-items/workitems-insight-table.tsx b/web/core/components/analytics/work-items/workitems-insight-table.tsx index 8facca27088..b6821fe572c 100644 --- a/web/core/components/analytics/work-items/workitems-insight-table.tsx +++ b/web/core/components/analytics/work-items/workitems-insight-table.tsx @@ -1,5 +1,6 @@ import { useMemo } from "react"; import { ColumnDef, Row } from "@tanstack/react-table"; +import { download, generateCsv } from "export-to-csv"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; import useSWR from "swr"; @@ -16,6 +17,7 @@ import { useAnalytics } from "@/hooks/store/use-analytics"; import { useProject } from "@/hooks/store/use-project"; import { AnalyticsService } from "@/services/analytics.service"; // plane web components +import { csvConfig } from "../config"; import { InsightTable } from "../insight-table"; const analyticsService = new AnalyticsService(); @@ -44,7 +46,7 @@ const WorkItemsInsightTable = observer(() => { ) ); // derived values - const columnsLabels = useMemo( + const columnsLabels: Record = useMemo( () => ({ backlog_work_items: t("workspace_projects.state.backlog"), started_work_items: t("workspace_projects.state.started"), @@ -135,6 +137,22 @@ const WorkItemsInsightTable = observer(() => { [columnsLabels, getProjectById, isPeekView, t] ); + const exportCSV = (rows: Row[]) => { + const rowData: any = rows.map((row) => { + const { project_id, avatar_url, assignee_id, ...exportableData } = row.original; + return Object.fromEntries( + Object.entries(exportableData).map(([key, value]) => { + if (columnsLabels?.[key]) { + return [columnsLabels[key], value]; + } + return [key, value]; + }) + ); + }); + const csv = generateCsv(csvConfig(workspaceSlug))(rowData); + download(csvConfig(workspaceSlug))(csv); + }; + return ( analyticsType="work-items" @@ -143,6 +161,7 @@ const WorkItemsInsightTable = observer(() => { columns={columns} columnsLabels={columnsLabels} headerText={isPeekView ? columnsLabels["display_name"] : columnsLabels["project__name"]} + onExport={exportCSV} /> ); }); From 9292cee97b54185bdfeb10b24424f0c6cc0c6f25 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Tue, 3 Jun 2025 20:51:05 +0530 Subject: [PATCH 16/19] feat: enhance analytics service with filter parameters and improve data handling in InsightTable --- packages/types/src/analytics.d.ts | 5 ++ .../analytics/insight-table/root.tsx | 2 +- .../work-items/workitems-insight-table.tsx | 60 ++++++++++--------- web/core/services/analytics.service.ts | 19 ++++-- web/package.json | 2 +- 5 files changed, 52 insertions(+), 36 deletions(-) diff --git a/packages/types/src/analytics.d.ts b/packages/types/src/analytics.d.ts index 7b8bc7f75ac..d55d74f4f5d 100644 --- a/packages/types/src/analytics.d.ts +++ b/packages/types/src/analytics.d.ts @@ -3,6 +3,11 @@ import { TChartData } from "./charts"; export type TAnalyticsTabsBase = "overview" | "work-items"; export type TAnalyticsGraphsBase = "projects" | "work-items" | "custom-work-items"; +export type TAnalyticsFilterParams = { + project_ids?: string; + cycle_id?: string; + module_id?: string; +}; // service types diff --git a/web/core/components/analytics/insight-table/root.tsx b/web/core/components/analytics/insight-table/root.tsx index e87e970f03f..583db1b7a07 100644 --- a/web/core/components/analytics/insight-table/root.tsx +++ b/web/core/components/analytics/insight-table/root.tsx @@ -42,7 +42,7 @@ export const InsightTable = >( )} /> ) : ( -
No data
+
{t("common.no_data_yet")}
)}
); diff --git a/web/core/components/analytics/work-items/workitems-insight-table.tsx b/web/core/components/analytics/work-items/workitems-insight-table.tsx index b6821fe572c..c3adb4a93e5 100644 --- a/web/core/components/analytics/work-items/workitems-insight-table.tsx +++ b/web/core/components/analytics/work-items/workitems-insight-table.tsx @@ -1,4 +1,4 @@ -import { useMemo } from "react"; +import { useMemo, useCallback } from "react"; import { ColumnDef, Row } from "@tanstack/react-table"; import { download, generateCsv } from "export-to-csv"; import { observer } from "mobx-react"; @@ -46,18 +46,19 @@ const WorkItemsInsightTable = observer(() => { ) ); // derived values - const columnsLabels: Record = useMemo( - () => ({ - backlog_work_items: t("workspace_projects.state.backlog"), - started_work_items: t("workspace_projects.state.started"), - un_started_work_items: t("workspace_projects.state.unstarted"), - completed_work_items: t("workspace_projects.state.completed"), - cancelled_work_items: t("workspace_projects.state.cancelled"), - project__name: t("common.project"), - display_name: t("common.assignee"), - }), - [t] - ); + const columnsLabels: Record, string> = + useMemo( + () => ({ + backlog_work_items: t("workspace_projects.state.backlog"), + started_work_items: t("workspace_projects.state.started"), + un_started_work_items: t("workspace_projects.state.unstarted"), + completed_work_items: t("workspace_projects.state.completed"), + cancelled_work_items: t("workspace_projects.state.cancelled"), + project__name: t("common.project"), + display_name: t("common.assignee"), + }), + [t] + ); const columns = useMemo( () => [ @@ -137,21 +138,24 @@ const WorkItemsInsightTable = observer(() => { [columnsLabels, getProjectById, isPeekView, t] ); - const exportCSV = (rows: Row[]) => { - const rowData: any = rows.map((row) => { - const { project_id, avatar_url, assignee_id, ...exportableData } = row.original; - return Object.fromEntries( - Object.entries(exportableData).map(([key, value]) => { - if (columnsLabels?.[key]) { - return [columnsLabels[key], value]; - } - return [key, value]; - }) - ); - }); - const csv = generateCsv(csvConfig(workspaceSlug))(rowData); - download(csvConfig(workspaceSlug))(csv); - }; + const exportCSV = useCallback( + (rows: Row[]) => { + const rowData: any = rows.map((row) => { + const { project_id, avatar_url, assignee_id, ...exportableData } = row.original; + return Object.fromEntries( + Object.entries(exportableData).map(([key, value]) => { + if (columnsLabels?.[key as keyof typeof columnsLabels]) { + return [columnsLabels[key as keyof typeof columnsLabels], value]; + } + return [key, value]; + }) + ); + }); + const csv = generateCsv(csvConfig(workspaceSlug))(rowData); + download(csvConfig(workspaceSlug))(csv); + }, + [columnsLabels, workspaceSlug] + ); return ( diff --git a/web/core/services/analytics.service.ts b/web/core/services/analytics.service.ts index 15024dbff44..de8e489d3cb 100644 --- a/web/core/services/analytics.service.ts +++ b/web/core/services/analytics.service.ts @@ -1,5 +1,5 @@ import { API_BASE_URL } from "@plane/constants"; -import { IAnalyticsResponse, TAnalyticsTabsBase, TAnalyticsGraphsBase } from "@plane/types"; +import { IAnalyticsResponse, TAnalyticsTabsBase, TAnalyticsGraphsBase, TAnalyticsFilterParams } from "@plane/types"; import { APIService } from "./api.service"; export class AnalyticsService extends APIService { @@ -10,7 +10,7 @@ export class AnalyticsService extends APIService { async getAdvanceAnalytics( workspaceSlug: string, tab: TAnalyticsTabsBase, - params?: Record, + params?: TAnalyticsFilterParams, isPeekView?: boolean ): Promise { return this.get(this.processUrl("advance-analytics", workspaceSlug, tab, params, isPeekView), { @@ -28,7 +28,7 @@ export class AnalyticsService extends APIService { async getAdvanceAnalyticsStats( workspaceSlug: string, tab: Exclude, - params?: Record, + params?: TAnalyticsFilterParams, isPeekView?: boolean ): Promise { const processedUrl = this.processUrl>( @@ -53,7 +53,7 @@ export class AnalyticsService extends APIService { async getAdvanceAnalyticsCharts( workspaceSlug: string, tab: TAnalyticsGraphsBase, - params?: Record, + params?: TAnalyticsFilterParams, isPeekView?: boolean ): Promise { const processedUrl = this.processUrl( @@ -79,12 +79,19 @@ export class AnalyticsService extends APIService { endpoint: string, workspaceSlug: string, tab: TAnalyticsGraphsBase | TAnalyticsTabsBase, - params?: Record, + params?: TAnalyticsFilterParams, isPeekView?: boolean ) { let processedUrl = `/api/workspaces/${workspaceSlug}`; if (isPeekView && (tab === "work-items" || tab === "custom-work-items")) { - const projectId = params?.project_ids.split(",")[0]; + const projectIds = params?.project_ids; + if (typeof projectIds !== "string" || !projectIds.trim()) { + throw new Error("project_ids parameter is required for peek view of work items"); + } + const projectId = projectIds.split(",")[0]; + if (!projectId) { + throw new Error("Invalid project_ids format - no project ID found"); + } processedUrl += `/projects/${projectId}`; } return `${processedUrl}/${endpoint}`; diff --git a/web/package.json b/web/package.json index b23881e4937..6312f9f903b 100644 --- a/web/package.json +++ b/web/package.json @@ -86,4 +86,4 @@ "prettier": "^3.2.5", "typescript": "5.3.3" } -} \ No newline at end of file +} From a99f87dd732e368f1b4deb5b351489039259277a Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Wed, 4 Jun 2025 20:05:51 +0530 Subject: [PATCH 17/19] feat: add new translation keys for various statuses across multiple languages --- .../i18n/src/locales/cs/translations.json | 11 ++++- .../i18n/src/locales/de/translations.json | 11 ++++- .../i18n/src/locales/en/translations.json | 9 ++++ .../i18n/src/locales/es/translations.json | 11 ++++- .../i18n/src/locales/fr/translations.json | 11 ++++- .../i18n/src/locales/id/translations.json | 11 ++++- .../i18n/src/locales/it/translations.json | 11 ++++- .../i18n/src/locales/ja/translations.json | 11 ++++- .../i18n/src/locales/ko/translations.json | 11 ++++- .../i18n/src/locales/pl/translations.json | 11 ++++- .../i18n/src/locales/pt-BR/translations.json | 11 ++++- .../i18n/src/locales/ro/translations.json | 11 ++++- .../i18n/src/locales/ru/translations.json | 11 ++++- .../i18n/src/locales/sk/translations.json | 11 ++++- .../i18n/src/locales/tr-TR/translations.json | 11 ++++- .../i18n/src/locales/ua/translations.json | 11 ++++- .../i18n/src/locales/vi-VN/translations.json | 11 ++++- .../i18n/src/locales/zh-CN/translations.json | 11 ++++- .../i18n/src/locales/zh-TW/translations.json | 11 ++++- .../components/analytics/total-insights.tsx | 44 ++++++++++++++----- .../work-items/workitems-insight-table.tsx | 2 +- 21 files changed, 222 insertions(+), 31 deletions(-) diff --git a/packages/i18n/src/locales/cs/translations.json b/packages/i18n/src/locales/cs/translations.json index 0925821cc9b..c11e776cf16 100644 --- a/packages/i18n/src/locales/cs/translations.json +++ b/packages/i18n/src/locales/cs/translations.json @@ -869,7 +869,16 @@ "applying": "Používání", "users": "Uživatelé", "admins": "Administrátoři", - "guests": "Hosté" + "guests": "Hosté", + "on_track": "Na správné cestě", + "off_track": "Mimo plán", + "timeline": "Časová osa", + "completion": "Dokončení", + "upcoming": "Nadcházející", + "completed": "Dokončeno", + "in_progress": "Probíhá", + "planned": "Plánováno", + "paused": "Pozastaveno" }, "chart": { "x_axis": "Osa X", diff --git a/packages/i18n/src/locales/de/translations.json b/packages/i18n/src/locales/de/translations.json index b7908d06353..5ed6c045835 100644 --- a/packages/i18n/src/locales/de/translations.json +++ b/packages/i18n/src/locales/de/translations.json @@ -869,7 +869,16 @@ "applying": "Wird angewendet", "users": "Benutzer", "admins": "Administratoren", - "guests": "Gäste" + "guests": "Gäste", + "on_track": "Im Plan", + "off_track": "Außer Plan", + "timeline": "Zeitleiste", + "completion": "Fertigstellung", + "upcoming": "Bevorstehend", + "completed": "Abgeschlossen", + "in_progress": "In Bearbeitung", + "planned": "Geplant", + "paused": "Pausiert" }, "chart": { "x_axis": "X-Achse", diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 12c801e1e50..2f849116c76 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -615,6 +615,15 @@ "quarter": "Quarter", "press_for_commands": "Press '/' for commands", "click_to_add_description": "Click to add description", + "on_track": "On-Track", + "off_track": "Off-Track", + "timeline": "Timeline", + "completion": "Completion", + "upcoming": "Upcoming", + "completed": "Completed", + "in_progress": "In progress", + "planned": "Planned", + "paused": "Paused", "search": { "label": "Search", "placeholder": "Type to search", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index 04fb752e184..8ca0d28b354 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -872,7 +872,16 @@ "applying": "Aplicando", "users": "Usuarios", "admins": "Administradores", - "guests": "Invitados" + "guests": "Invitados", + "on_track": "En camino", + "off_track": "Fuera de camino", + "timeline": "Cronograma", + "completion": "Finalización", + "upcoming": "Próximo", + "completed": "Completado", + "in_progress": "En progreso", + "planned": "Planificado", + "paused": "Pausado" }, "chart": { "x_axis": "Eje X", diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 0d12af6845c..107214bdaaf 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -870,7 +870,16 @@ "applying": "Application", "users": "Utilisateurs", "admins": "Administrateurs", - "guests": "Invités" + "guests": "Invités", + "on_track": "Sur la bonne voie", + "off_track": "Hors de la bonne voie", + "timeline": "Chronologie", + "completion": "Achèvement", + "upcoming": "À venir", + "completed": "Terminé", + "in_progress": "En cours", + "planned": "Planifié", + "paused": "En pause" }, "chart": { "x_axis": "Axe X", diff --git a/packages/i18n/src/locales/id/translations.json b/packages/i18n/src/locales/id/translations.json index 7a7bb76bad7..74d7d5ab962 100644 --- a/packages/i18n/src/locales/id/translations.json +++ b/packages/i18n/src/locales/id/translations.json @@ -869,7 +869,16 @@ "applying": "Terapkan", "users": "Pengguna", "admins": "Admin", - "guests": "Tamu" + "guests": "Tamu", + "on_track": "Sesuai Jalur", + "off_track": "Menyimpang", + "timeline": "Linimasa", + "completion": "Penyelesaian", + "upcoming": "Mendatang", + "completed": "Selesai", + "in_progress": "Sedang berlangsung", + "planned": "Direncanakan", + "paused": "Dijedaikan" }, "chart": { "x_axis": "Sumbu-X", diff --git a/packages/i18n/src/locales/it/translations.json b/packages/i18n/src/locales/it/translations.json index 1422a3c84d3..b40a3c3d130 100644 --- a/packages/i18n/src/locales/it/translations.json +++ b/packages/i18n/src/locales/it/translations.json @@ -868,7 +868,16 @@ "applying": "Applicazione", "users": "Utenti", "admins": "Amministratori", - "guests": "Ospiti" + "guests": "Ospiti", + "on_track": "In linea", + "off_track": "Fuori rotta", + "timeline": "Cronologia", + "completion": "Completamento", + "upcoming": "In arrivo", + "completed": "Completato", + "in_progress": "In corso", + "planned": "Pianificato", + "paused": "In pausa" }, "chart": { "x_axis": "Asse X", diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 135ef16e1e0..88544a4919d 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -870,7 +870,16 @@ "applying": "適用中", "users": "ユーザー", "admins": "管理者", - "guests": "ゲスト" + "guests": "ゲスト", + "on_track": "順調", + "off_track": "遅れ", + "timeline": "タイムライン", + "completion": "完了", + "upcoming": "今後の予定", + "completed": "完了", + "in_progress": "進行中", + "planned": "計画済み", + "paused": "一時停止" }, "chart": { "x_axis": "エックス アクシス", diff --git a/packages/i18n/src/locales/ko/translations.json b/packages/i18n/src/locales/ko/translations.json index b8908849818..fd06447dca3 100644 --- a/packages/i18n/src/locales/ko/translations.json +++ b/packages/i18n/src/locales/ko/translations.json @@ -871,7 +871,16 @@ "applying": "적용 중", "users": "사용자", "admins": "관리자", - "guests": "게스트" + "guests": "게스트", + "on_track": "계획대로 진행 중", + "off_track": "계획 이탈", + "timeline": "타임라인", + "completion": "완료", + "upcoming": "예정된", + "completed": "완료됨", + "in_progress": "진행 중", + "planned": "계획된", + "paused": "일시 중지됨" }, "chart": { "x_axis": "X축", diff --git a/packages/i18n/src/locales/pl/translations.json b/packages/i18n/src/locales/pl/translations.json index 0e1a3183cc1..d3c41aa2c42 100644 --- a/packages/i18n/src/locales/pl/translations.json +++ b/packages/i18n/src/locales/pl/translations.json @@ -871,7 +871,16 @@ "applying": "Zastosowanie", "users": "Użytkownicy", "admins": "Administratorzy", - "guests": "Goście" + "guests": "Goście", + "on_track": "Na dobrej drodze", + "off_track": "Poza planem", + "timeline": "Oś czasu", + "completion": "Zakończenie", + "upcoming": "Nadchodzące", + "completed": "Zakończone", + "in_progress": "W trakcie", + "planned": "Zaplanowane", + "paused": "Wstrzymane" }, "chart": { "x_axis": "Oś X", diff --git a/packages/i18n/src/locales/pt-BR/translations.json b/packages/i18n/src/locales/pt-BR/translations.json index 9eca9358543..0ece4016fe4 100644 --- a/packages/i18n/src/locales/pt-BR/translations.json +++ b/packages/i18n/src/locales/pt-BR/translations.json @@ -871,7 +871,16 @@ "applying": "Aplicando", "users": "Usuários", "admins": "Administradores", - "guests": "Convidados" + "guests": "Convidados", + "on_track": "No caminho certo", + "off_track": "Fora do caminho", + "timeline": "Linha do tempo", + "completion": "Conclusão", + "upcoming": "Próximo", + "completed": "Concluído", + "in_progress": "Em andamento", + "planned": "Planejado", + "paused": "Pausado" }, "chart": { "x_axis": "Eixo X", diff --git a/packages/i18n/src/locales/ro/translations.json b/packages/i18n/src/locales/ro/translations.json index 5d8c96c0995..a70db8d6461 100644 --- a/packages/i18n/src/locales/ro/translations.json +++ b/packages/i18n/src/locales/ro/translations.json @@ -869,7 +869,16 @@ "applying": "Aplicând", "users": "Utilizatori", "admins": "Administratori", - "guests": "Invitați" + "guests": "Invitați", + "on_track": "Pe drumul cel bun", + "off_track": "În afara traiectoriei", + "timeline": "Cronologie", + "completion": "Finalizare", + "upcoming": "Viitor", + "completed": "Finalizat", + "in_progress": "În desfășurare", + "planned": "Planificat", + "paused": "Pauzat" }, "chart": { "x_axis": "axa-X", diff --git a/packages/i18n/src/locales/ru/translations.json b/packages/i18n/src/locales/ru/translations.json index 6e5a0586358..a2c57b09e36 100644 --- a/packages/i18n/src/locales/ru/translations.json +++ b/packages/i18n/src/locales/ru/translations.json @@ -871,7 +871,16 @@ "applying": "Применение", "users": "Пользователи", "admins": "Администраторы", - "guests": "Гости" + "guests": "Гости", + "on_track": "По плану", + "off_track": "Отклонение от плана", + "timeline": "Хронология", + "completion": "Завершение", + "upcoming": "Предстоящие", + "completed": "Завершено", + "in_progress": "В процессе", + "planned": "Запланировано", + "paused": "На паузе" }, "chart": { "x_axis": "Ось X", diff --git a/packages/i18n/src/locales/sk/translations.json b/packages/i18n/src/locales/sk/translations.json index 90966a2f79a..b9c74222098 100644 --- a/packages/i18n/src/locales/sk/translations.json +++ b/packages/i18n/src/locales/sk/translations.json @@ -871,7 +871,16 @@ "applying": "Používanie", "users": "Používatelia", "admins": "Administrátori", - "guests": "Hostia" + "guests": "Hostia", + "on_track": "Na správnej ceste", + "off_track": "Mimo plán", + "timeline": "Časová os", + "completion": "Dokončenie", + "upcoming": "Nadchádzajúce", + "completed": "Dokončené", + "in_progress": "Prebieha", + "planned": "Plánované", + "paused": "Pozastavené" }, "chart": { "x_axis": "Os X", diff --git a/packages/i18n/src/locales/tr-TR/translations.json b/packages/i18n/src/locales/tr-TR/translations.json index fd4bc585320..700ec684716 100644 --- a/packages/i18n/src/locales/tr-TR/translations.json +++ b/packages/i18n/src/locales/tr-TR/translations.json @@ -872,7 +872,16 @@ "applying": "Uygulanıyor", "users": "Kullanıcılar", "admins": "Yöneticiler", - "guests": "Misafirler" + "guests": "Misafirler", + "on_track": "Yolunda", + "off_track": "Yolunda değil", + "timeline": "Zaman çizelgesi", + "completion": "Tamamlama", + "upcoming": "Yaklaşan", + "completed": "Tamamlandı", + "in_progress": "Devam ediyor", + "planned": "Planlandı", + "paused": "Durduruldu" }, "chart": { "x_axis": "X ekseni", diff --git a/packages/i18n/src/locales/ua/translations.json b/packages/i18n/src/locales/ua/translations.json index d7018f3d2c7..252e9d748ed 100644 --- a/packages/i18n/src/locales/ua/translations.json +++ b/packages/i18n/src/locales/ua/translations.json @@ -871,7 +871,16 @@ "applying": "Застосовується", "users": "Користувачі", "admins": "Адміністратори", - "guests": "Гості" + "guests": "Гості", + "on_track": "У межах графіку", + "off_track": "Поза графіком", + "timeline": "Хронологія", + "completion": "Завершення", + "upcoming": "Майбутнє", + "completed": "Завершено", + "in_progress": "В процесі", + "planned": "Заплановано", + "paused": "Призупинено" }, "chart": { "x_axis": "Вісь X", diff --git a/packages/i18n/src/locales/vi-VN/translations.json b/packages/i18n/src/locales/vi-VN/translations.json index 22ca99e58b1..fe4039e4be4 100644 --- a/packages/i18n/src/locales/vi-VN/translations.json +++ b/packages/i18n/src/locales/vi-VN/translations.json @@ -870,7 +870,16 @@ "applying": "Đang áp dụng", "users": "Người dùng", "admins": "Quản trị viên", - "guests": "Khách" + "guests": "Khách", + "on_track": "Đúng tiến độ", + "off_track": "Chệch hướng", + "timeline": "Dòng thời gian", + "completion": "Hoàn thành", + "upcoming": "Sắp tới", + "completed": "Đã hoàn thành", + "in_progress": "Đang tiến hành", + "planned": "Đã lên kế hoạch", + "paused": "Tạm dừng" }, "chart": { "x_axis": "Trục X", diff --git a/packages/i18n/src/locales/zh-CN/translations.json b/packages/i18n/src/locales/zh-CN/translations.json index db1da9a8db5..1695b7b654f 100644 --- a/packages/i18n/src/locales/zh-CN/translations.json +++ b/packages/i18n/src/locales/zh-CN/translations.json @@ -870,7 +870,16 @@ "applying": "应用中", "users": "用户", "admins": "管理员", - "guests": "访客" + "guests": "访客", + "on_track": "进展顺利", + "off_track": "偏离轨道", + "timeline": "时间轴", + "completion": "完成", + "upcoming": "即将发生", + "completed": "已完成", + "in_progress": "进行中", + "planned": "已计划", + "paused": "暂停" }, "chart": { "x_axis": "X轴", diff --git a/packages/i18n/src/locales/zh-TW/translations.json b/packages/i18n/src/locales/zh-TW/translations.json index c87ddcd3a5a..763d02c3c79 100644 --- a/packages/i18n/src/locales/zh-TW/translations.json +++ b/packages/i18n/src/locales/zh-TW/translations.json @@ -871,7 +871,16 @@ "applying": "應用中", "users": "使用者", "admins": "管理員", - "guests": "訪客" + "guests": "訪客", + "on_track": "進展順利", + "off_track": "偏離軌道", + "timeline": "時間軸", + "completion": "完成", + "upcoming": "即將發生", + "completed": "已完成", + "in_progress": "進行中", + "planned": "已計劃", + "paused": "暫停" }, "chart": { "x_axis": "X 軸", diff --git a/web/core/components/analytics/total-insights.tsx b/web/core/components/analytics/total-insights.tsx index 4501ce2c339..fdb4a339211 100644 --- a/web/core/components/analytics/total-insights.tsx +++ b/web/core/components/analytics/total-insights.tsx @@ -2,7 +2,7 @@ import { observer } from "mobx-react-lite"; import { useParams } from "next/navigation"; import useSWR from "swr"; -import { EIssuesStoreType, insightsFields } from "@plane/constants"; +import { IInsightField, insightsFields } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; import { IAnalyticsResponse, TAnalyticsTabsBase } from "@plane/types"; //hooks @@ -15,6 +15,34 @@ import InsightCard from "./insight-card"; const analyticsService = new AnalyticsService(); +const getInsightLabel = ( + analyticsType: TAnalyticsTabsBase, + item: IInsightField, + isEpic: boolean | undefined, + t: (key: string, options?: any) => string +) => { + if (analyticsType === "work-items") { + return isEpic + ? t(item.i18nKey, { entity: t("common.epics") }) + : t(item.i18nKey, { entity: t("common.work_items") }); + } + + // Get the base translation with entity + const baseTranslation = t(item.i18nKey, { + ...item.i18nProps, + entity: item.i18nProps?.entity && t(item.i18nProps?.entity), + }); + + // Add prefix if available + const prefix = item.i18nProps?.prefix ? `${t(item.i18nProps.prefix)} ` : ""; + + // Add suffix if available + const suffix = item.i18nProps?.suffix ? ` ${t(item.i18nProps.suffix)}` : ""; + + // Combine prefix, base translation, and suffix + return `${prefix}${baseTranslation}${suffix}`; +}; + const TotalInsights: React.FC<{ analyticsType: TAnalyticsTabsBase; peekView?: boolean; @@ -42,6 +70,7 @@ const TotalInsights: React.FC<{ ...(selectedProjects?.length > 0 ? { project_ids: selectedProjects.join(",") } : {}), ...(selectedCycle ? { cycle_id: selectedCycle } : {}), ...(selectedModule ? { module_id: selectedModule } : {}), + ...(isEpic ? { epic: true } : {}), }, isPeekView ) @@ -51,7 +80,7 @@ const TotalInsights: React.FC<{ className={cn( "grid grid-cols-1 gap-8 sm:grid-cols-2 md:gap-10", !peekView - ? insightsFields[analyticsType].length % 5 === 0 + ? insightsFields[analyticsType]?.length % 5 === 0 ? "gap-10 lg:grid-cols-5" : "gap-8 lg:grid-cols-4" : "grid-cols-2" @@ -62,16 +91,7 @@ const TotalInsights: React.FC<{ key={`${analyticsType}-${item.key}`} isLoading={isLoading} data={totalInsightsData?.[item.key]} - label={ - analyticsType === "work-items" - ? isEpic - ? t(item.i18nKey, { entity: t("common.epics") }) - : t(item.i18nKey, { entity: t("common.work_items") }) - : t(item.i18nKey, { - ...item.i18nProps, - entity: item.i18nProps?.entity && t(item.i18nProps?.entity), - }) - } + label={getInsightLabel(analyticsType, item, isEpic, t)} versus={selectedDurationLabel} /> ))} diff --git a/web/core/components/analytics/work-items/workitems-insight-table.tsx b/web/core/components/analytics/work-items/workitems-insight-table.tsx index c3adb4a93e5..4d6136692fa 100644 --- a/web/core/components/analytics/work-items/workitems-insight-table.tsx +++ b/web/core/components/analytics/work-items/workitems-insight-table.tsx @@ -164,7 +164,7 @@ const WorkItemsInsightTable = observer(() => { isLoading={isLoading} columns={columns} columnsLabels={columnsLabels} - headerText={isPeekView ? columnsLabels["display_name"] : columnsLabels["project__name"]} + headerText={isPeekView ? t("common.assignee") : t("common.projects")} onExport={exportCSV} /> ); From cdb74666bad0c84406097e84d93dcb8080fee360 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 5 Jun 2025 13:58:24 +0530 Subject: [PATCH 18/19] [WEB-4246] fix: enhance analytics components to include 'isEpic' parameter for improved data fetching --- .../components/analytics/total-insights.tsx | 2 +- .../work-items/created-vs-resolved.tsx | 18 +++++++++++++----- .../analytics/work-items/priority-chart.tsx | 5 +++-- .../work-items/workitems-insight-table.tsx | 5 +++-- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/web/core/components/analytics/total-insights.tsx b/web/core/components/analytics/total-insights.tsx index fdb4a339211..61f3e7205b3 100644 --- a/web/core/components/analytics/total-insights.tsx +++ b/web/core/components/analytics/total-insights.tsx @@ -60,7 +60,7 @@ const TotalInsights: React.FC<{ isEpic, } = useAnalytics(); const { data: totalInsightsData, isLoading } = useSWR( - `total-insights-${analyticsType}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, + `total-insights-${analyticsType}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isEpic}`, () => analyticsService.getAdvanceAnalytics( workspaceSlug, diff --git a/web/core/components/analytics/work-items/created-vs-resolved.tsx b/web/core/components/analytics/work-items/created-vs-resolved.tsx index 9abd7055ffb..76215238d76 100644 --- a/web/core/components/analytics/work-items/created-vs-resolved.tsx +++ b/web/core/components/analytics/work-items/created-vs-resolved.tsx @@ -19,14 +19,21 @@ import { ChartLoader } from "../loaders"; const analyticsService = new AnalyticsService(); const CreatedVsResolved = observer(() => { - const { selectedDuration, selectedDurationLabel, selectedProjects, selectedCycle, selectedModule, isPeekView } = - useAnalytics(); + const { + selectedDuration, + selectedDurationLabel, + selectedProjects, + selectedCycle, + selectedModule, + isPeekView, + isEpic, + } = useAnalytics(); const params = useParams(); const { t } = useTranslation(); const workspaceSlug = params.workspaceSlug.toString(); const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics/empty-chart-area" }); const { data: createdVsResolvedData, isLoading: isCreatedVsResolvedLoading } = useSWR( - `created-vs-resolved-${workspaceSlug}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, + `created-vs-resolved-${workspaceSlug}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}-${isEpic}`, () => analyticsService.getAdvanceAnalyticsCharts( workspaceSlug, @@ -36,6 +43,7 @@ const CreatedVsResolved = observer(() => { ...(selectedProjects?.length > 0 && { project_ids: selectedProjects?.join(",") }), ...(selectedCycle ? { cycle_id: selectedCycle } : {}), ...(selectedModule ? { module_id: selectedModule } : {}), + ...(isEpic ? { epic: true } : {}), }, isPeekView ) @@ -92,11 +100,11 @@ const CreatedVsResolved = observer(() => { areas={areas} xAxis={{ key: "name", - label: "Date", + label: t("date"), }} yAxis={{ key: "count", - label: "Number of Issues", + label: t("no_of", { entity: t("work_items") }), offset: -30, dx: -22, }} diff --git a/web/core/components/analytics/work-items/priority-chart.tsx b/web/core/components/analytics/work-items/priority-chart.tsx index 020eaf8d391..78a05c2c788 100644 --- a/web/core/components/analytics/work-items/priority-chart.tsx +++ b/web/core/components/analytics/work-items/priority-chart.tsx @@ -46,7 +46,7 @@ const PriorityChart = observer((props: Props) => { const { t } = useTranslation(); const resolvedPath = useResolvedAssetPath({ basePath: "/empty-state/analytics/empty-chart-bar" }); // store hooks - const { selectedDuration, selectedProjects, selectedCycle, selectedModule, isPeekView } = useAnalytics(); + const { selectedDuration, selectedProjects, selectedCycle, selectedModule, isPeekView, isEpic } = useAnalytics(); const { workspaceStates } = useProjectState(); const { resolvedTheme } = useTheme(); // router @@ -55,7 +55,7 @@ const PriorityChart = observer((props: Props) => { const { data: priorityChartData, isLoading: priorityChartLoading } = useSWR( `customized-insights-chart-${workspaceSlug}-${selectedDuration}- - ${selectedProjects}-${selectedCycle}-${selectedModule}-${props.x_axis}-${props.y_axis}-${props.group_by}-${isPeekView}`, + ${selectedProjects}-${selectedCycle}-${selectedModule}-${props.x_axis}-${props.y_axis}-${props.group_by}-${isPeekView}-${isEpic}`, () => analyticsService.getAdvanceAnalyticsCharts( workspaceSlug, @@ -65,6 +65,7 @@ const PriorityChart = observer((props: Props) => { ...(selectedProjects?.length > 0 && { project_ids: selectedProjects?.join(",") }), ...(selectedCycle ? { cycle_id: selectedCycle } : {}), ...(selectedModule ? { module_id: selectedModule } : {}), + ...(isEpic ? { epic: true } : {}), ...props, }, isPeekView diff --git a/web/core/components/analytics/work-items/workitems-insight-table.tsx b/web/core/components/analytics/work-items/workitems-insight-table.tsx index 4d6136692fa..45e12b1e3b7 100644 --- a/web/core/components/analytics/work-items/workitems-insight-table.tsx +++ b/web/core/components/analytics/work-items/workitems-insight-table.tsx @@ -29,9 +29,9 @@ const WorkItemsInsightTable = observer(() => { const { t } = useTranslation(); // store hooks const { getProjectById } = useProject(); - const { selectedDuration, selectedProjects, selectedCycle, selectedModule, isPeekView } = useAnalytics(); + const { selectedDuration, selectedProjects, selectedCycle, selectedModule, isPeekView, isEpic } = useAnalytics(); const { data: workItemsData, isLoading } = useSWR( - `insights-table-work-items-${workspaceSlug}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}`, + `insights-table-work-items-${workspaceSlug}-${selectedDuration}-${selectedProjects}-${selectedCycle}-${selectedModule}-${isPeekView}-${isEpic}`, () => analyticsService.getAdvanceAnalyticsStats( workspaceSlug, @@ -41,6 +41,7 @@ const WorkItemsInsightTable = observer(() => { ...(selectedProjects?.length > 0 ? { project_ids: selectedProjects.join(",") } : {}), ...(selectedCycle ? { cycle_id: selectedCycle } : {}), ...(selectedModule ? { module_id: selectedModule } : {}), + ...(isEpic ? { epic: true } : {}), }, isPeekView ) From 4550382e0ff697c26807df7af38d1c6459cdfe81 Mon Sep 17 00:00:00 2001 From: JayashTripathy Date: Thu, 5 Jun 2025 16:01:34 +0530 Subject: [PATCH 19/19] chore: update yarn.lock to remove deprecated @nivo packages and clean up unused dependencies --- yarn.lock | 380 ++++++------------------------------------------------ 1 file changed, 36 insertions(+), 344 deletions(-) diff --git a/yarn.lock b/yarn.lock index ea131bb2b9b..29dd63adac8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1675,201 +1675,6 @@ resolved "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== -"@nivo/annotations@0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/annotations/-/annotations-0.88.0.tgz#96830d735331dea2b60e66ce3971ef43b45cca8c" - integrity sha512-NXE+1oIUn+EGWMQpnpeRMLgi2wyuzhGDoJQY4OUHissCUiNotid2oNQ/PXJwN0toiu+/j9SyhzI32xr70OPi7Q== - dependencies: - "@nivo/colors" "0.88.0" - "@nivo/core" "0.88.0" - "@react-spring/web" "9.4.5 || ^9.7.2" - lodash "^4.17.21" - -"@nivo/arcs@0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/arcs/-/arcs-0.88.0.tgz#0004aa612fd12eee5fd415ed257812b722bf5a10" - integrity sha512-q7MHxT71s/KKlDDtSJS4L9+/JIa5HPZZrDr3ZFECLnvp0TC1qzyFMtVevN2CsXopSTj8poN4uFXPWxYVXOq8vg== - dependencies: - "@nivo/colors" "0.88.0" - "@nivo/core" "0.88.0" - "@react-spring/web" "9.4.5 || ^9.7.2" - "@types/d3-shape" "^3.1.6" - d3-shape "^3.2.0" - -"@nivo/axes@0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/axes/-/axes-0.88.0.tgz#b773efb217fc0faedbb5f8bc458f4b78820e2761" - integrity sha512-jF7aIxzTNayV5cI1J/b9Q1FfpMBxTXGk3OwSigXMSfYWlliskDn2u0qGRLiYhuXFdQAWIp4oXsO1GcAQ0eRVdg== - dependencies: - "@nivo/core" "0.88.0" - "@nivo/scales" "0.88.0" - "@react-spring/web" "9.4.5 || ^9.7.2" - "@types/d3-format" "^1.4.1" - "@types/d3-time-format" "^2.3.1" - d3-format "^1.4.4" - d3-time-format "^3.0.0" - -"@nivo/bar@^0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/bar/-/bar-0.88.0.tgz#646f12233c0dc9f2507823bfe30a2f1d76ddae71" - integrity sha512-wckwuHWeCikxGvvdRfGL+dVFsUD9uHk1r9s7bWUfOD+p8BWhxtYqfXpHolEfgGg3UyPaHtpGA7P4zgE5vgo7gQ== - dependencies: - "@nivo/annotations" "0.88.0" - "@nivo/axes" "0.88.0" - "@nivo/colors" "0.88.0" - "@nivo/core" "0.88.0" - "@nivo/legends" "0.88.0" - "@nivo/scales" "0.88.0" - "@nivo/tooltip" "0.88.0" - "@react-spring/web" "9.4.5 || ^9.7.2" - "@types/d3-scale" "^4.0.8" - "@types/d3-shape" "^3.1.6" - d3-scale "^4.0.2" - d3-shape "^3.2.0" - lodash "^4.17.21" - -"@nivo/calendar@^0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/calendar/-/calendar-0.88.0.tgz#f09e8ab5332d8f9b18de87e95ca6a48013ac0606" - integrity sha512-sTpoaN5bNRwywRIVKAv7oo+/ZZjX0cjBcpbyFQZqXnEmFX8tEO55Rn/469zWDG776Gk7wHcuwmQfEIqwWM9PfQ== - dependencies: - "@nivo/core" "0.88.0" - "@nivo/legends" "0.88.0" - "@nivo/tooltip" "0.88.0" - "@types/d3-scale" "^4.0.8" - "@types/d3-time" "^1.0.10" - "@types/d3-time-format" "^3.0.0" - d3-scale "^4.0.2" - d3-time "^1.0.10" - d3-time-format "^3.0.0" - lodash "^4.17.21" - -"@nivo/colors@0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/colors/-/colors-0.88.0.tgz#2790ac0607381800270f2902e4d957e65e2cad70" - integrity sha512-IZ+leYIqAlo7dyLHmsQwujanfRgXyoQ5H7PU3RWLEn1PP0zxDKLgEjFEDADpDauuslh2Tx0L81GNkWR6QSP0Mw== - dependencies: - "@nivo/core" "0.88.0" - "@types/d3-color" "^3.0.0" - "@types/d3-scale" "^4.0.8" - "@types/d3-scale-chromatic" "^3.0.0" - "@types/prop-types" "^15.7.2" - d3-color "^3.1.0" - d3-scale "^4.0.2" - d3-scale-chromatic "^3.0.0" - lodash "^4.17.21" - prop-types "^15.7.2" - -"@nivo/core@0.88.0", "@nivo/core@^0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/core/-/core-0.88.0.tgz#ec79c7d63311473f15a463fd78274d9971a52848" - integrity sha512-XjUkA5MmwjLP38bdrJwn36Gj7T5SYMKD55LYQp/1nIJPdxqJ38dUfE4XyBDfIEgfP6yrHOihw3C63cUdnUBoiw== - dependencies: - "@nivo/tooltip" "0.88.0" - "@react-spring/web" "9.4.5 || ^9.7.2" - "@types/d3-shape" "^3.1.6" - d3-color "^3.1.0" - d3-format "^1.4.4" - d3-interpolate "^3.0.1" - d3-scale "^4.0.2" - d3-scale-chromatic "^3.0.0" - d3-shape "^3.2.0" - d3-time-format "^3.0.0" - lodash "^4.17.21" - prop-types "^15.7.2" - -"@nivo/legends@0.88.0", "@nivo/legends@^0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/legends/-/legends-0.88.0.tgz#a6007492048358a14bd061472a117ed34e7b0c81" - integrity sha512-d4DF9pHbD8LmGJlp/Gp1cF4e8y2wfQTcw3jVhbZj9zkb7ZWB7JfeF60VHRfbXNux9bjQ9U78/SssQqueVDPEmg== - dependencies: - "@nivo/colors" "0.88.0" - "@nivo/core" "0.88.0" - "@types/d3-scale" "^4.0.8" - d3-scale "^4.0.2" - -"@nivo/line@^0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/line/-/line-0.88.0.tgz#145b194f2c1bff2dd6071ab46fe114f9c4237811" - integrity sha512-hFTyZ3BdAZvq2HwdwMj2SJGUeodjEW+7DLtFMIIoVIxmjZlAs3z533HcJ9cJd3it928fDm8SF/rgHs0TztYf9Q== - dependencies: - "@nivo/annotations" "0.88.0" - "@nivo/axes" "0.88.0" - "@nivo/colors" "0.88.0" - "@nivo/core" "0.88.0" - "@nivo/legends" "0.88.0" - "@nivo/scales" "0.88.0" - "@nivo/tooltip" "0.88.0" - "@nivo/voronoi" "0.88.0" - "@react-spring/web" "9.4.5 || ^9.7.2" - d3-shape "^3.2.0" - -"@nivo/pie@^0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/pie/-/pie-0.88.0.tgz#628a608d077d9cfe850ffef1b16181482479e7c7" - integrity sha512-BE6dFWlGne1SnaEkFHNbg0sZBiwtcIqBFwmMRJ0F11SiKOzVeJyq3KiyY1I2ySSCx5VR1V8/MNBXzXFu3vJMAQ== - dependencies: - "@nivo/arcs" "0.88.0" - "@nivo/colors" "0.88.0" - "@nivo/core" "0.88.0" - "@nivo/legends" "0.88.0" - "@nivo/tooltip" "0.88.0" - "@types/d3-shape" "^3.1.6" - d3-shape "^3.2.0" - -"@nivo/scales@0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/scales/-/scales-0.88.0.tgz#c69110b5ab504debb80a5a01a7824780af241ffb" - integrity sha512-HbpxkQp6tHCltZ1yDGeqdLcaJl5ze54NPjurfGtx/Uq+H5IQoBd4Tln49bUar5CsFAMsXw8yF1HQvASr7I1SIA== - dependencies: - "@types/d3-scale" "^4.0.8" - "@types/d3-time" "^1.1.1" - "@types/d3-time-format" "^3.0.0" - d3-scale "^4.0.2" - d3-time "^1.0.11" - d3-time-format "^3.0.0" - lodash "^4.17.21" - -"@nivo/scatterplot@^0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/scatterplot/-/scatterplot-0.88.0.tgz#d6572986eee49e2da942c01be37f6fe189bf6506" - integrity sha512-kVUnBknVnX/+kAnOVl27wSrVrDAnYt7hyttss5jydBMzGidxK7vFBwRUFl5yrPGmEwpDSO8POvXjSF4M3XHzZA== - dependencies: - "@nivo/annotations" "0.88.0" - "@nivo/axes" "0.88.0" - "@nivo/colors" "0.88.0" - "@nivo/core" "0.88.0" - "@nivo/legends" "0.88.0" - "@nivo/scales" "0.88.0" - "@nivo/tooltip" "0.88.0" - "@nivo/voronoi" "0.88.0" - "@react-spring/web" "9.4.5 || ^9.7.2" - "@types/d3-scale" "^4.0.8" - "@types/d3-shape" "^3.1.6" - d3-scale "^4.0.2" - d3-shape "^3.2.0" - lodash "^4.17.21" - -"@nivo/tooltip@0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/tooltip/-/tooltip-0.88.0.tgz#b98348c0d617fea09c1bbddccc443c12ca697620" - integrity sha512-iEjVfQA8gumAzg/yUinjTwswygCkE5Iwuo8opwnrbpNIqMrleBV+EAKIgB0PrzepIoW8CFG/SJhoiRfbU8jhOw== - dependencies: - "@nivo/core" "0.88.0" - "@react-spring/web" "9.4.5 || ^9.7.2" - -"@nivo/voronoi@0.88.0": - version "0.88.0" - resolved "https://registry.npmjs.org/@nivo/voronoi/-/voronoi-0.88.0.tgz#029f984ccb6e72b415f398e1bd74c572960197ae" - integrity sha512-MyiNLvODthFoMjQ7Wjp693nogbTmVEx8Yn/7QkJhyPQbFyyA37TF/D1a/ox4h2OslXtP6K9QFN+42gB/zu7ixw== - dependencies: - "@nivo/core" "0.88.0" - "@nivo/tooltip" "0.88.0" - "@types/d3-delaunay" "^6.0.4" - "@types/d3-scale" "^4.0.8" - d3-delaunay "^6.0.4" - d3-scale "^4.0.2" - "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -2186,51 +1991,6 @@ resolved "https://registry.npmjs.org/@react-pdf/types/-/types-2.7.1.tgz#eb9f70be66b42c47f60c5afcc0af044ac48b98bf" integrity sha512-MyjR1u+6SclQ/Tx6NP3/yoYZw7reXgC4OHFOrdMh/zeZ+ezfdGyovB+jdmVQuMe7Fsh64v7PUkO5tnsXHyCFWQ== -"@react-spring/animated@~9.7.5": - version "9.7.5" - resolved "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.5.tgz#eb0373aaf99b879736b380c2829312dae3b05f28" - integrity sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg== - dependencies: - "@react-spring/shared" "~9.7.5" - "@react-spring/types" "~9.7.5" - -"@react-spring/core@~9.7.5": - version "9.7.5" - resolved "https://registry.npmjs.org/@react-spring/core/-/core-9.7.5.tgz#72159079f52c1c12813d78b52d4f17c0bf6411f7" - integrity sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w== - dependencies: - "@react-spring/animated" "~9.7.5" - "@react-spring/shared" "~9.7.5" - "@react-spring/types" "~9.7.5" - -"@react-spring/rafz@~9.7.5": - version "9.7.5" - resolved "https://registry.npmjs.org/@react-spring/rafz/-/rafz-9.7.5.tgz#ee7959676e7b5d6a3813e8c17d5e50df98b95df9" - integrity sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw== - -"@react-spring/shared@~9.7.5": - version "9.7.5" - resolved "https://registry.npmjs.org/@react-spring/shared/-/shared-9.7.5.tgz#6d513622df6ad750bbbd4dedb4ca0a653ec92073" - integrity sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw== - dependencies: - "@react-spring/rafz" "~9.7.5" - "@react-spring/types" "~9.7.5" - -"@react-spring/types@~9.7.5": - version "9.7.5" - resolved "https://registry.npmjs.org/@react-spring/types/-/types-9.7.5.tgz#e5dd180f3ed985b44fd2cd2f32aa9203752ef3e8" - integrity sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g== - -"@react-spring/web@9.4.5 || ^9.7.2": - version "9.7.5" - resolved "https://registry.npmjs.org/@react-spring/web/-/web-9.7.5.tgz#7d7782560b3a6fb9066b52824690da738605de80" - integrity sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ== - dependencies: - "@react-spring/animated" "~9.7.5" - "@react-spring/core" "~9.7.5" - "@react-spring/shared" "~9.7.5" - "@react-spring/types" "~9.7.5" - "@remirror/core-constants@3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz#96fdb89d25c62e7b6a5d08caf0ce5114370e3b8f" @@ -3210,26 +2970,16 @@ resolved "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5" integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg== -"@types/d3-color@*", "@types/d3-color@^3.0.0": +"@types/d3-color@*": version "3.1.3" resolved "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2" integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A== -"@types/d3-delaunay@^6.0.4": - version "6.0.4" - resolved "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz#185c1a80cc807fdda2a3fe960f7c11c4a27952e1" - integrity sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw== - "@types/d3-ease@^3.0.0": version "3.0.2" resolved "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b" integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA== -"@types/d3-format@^1.4.1": - version "1.4.5" - resolved "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.4.5.tgz#6392303c2ca3c287c3a1a2046455cd0a0bd50bbe" - integrity sha512-mLxrC1MSWupOSncXN/HOlWUAAIffAEBaI4+PKy2uMPsKe4FNZlk7qrbTjmzJXITQQqBHivaks4Td18azgqnotA== - "@types/d3-interpolate@^3.0.1": version "3.0.4" resolved "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c" @@ -3242,45 +2992,25 @@ resolved "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz#f632b380c3aca1dba8e34aa049bcd6a4af23df8a" integrity sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg== -"@types/d3-scale-chromatic@^3.0.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#dc6d4f9a98376f18ea50bad6c39537f1b5463c39" - integrity sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ== - -"@types/d3-scale@^4.0.2", "@types/d3-scale@^4.0.8": +"@types/d3-scale@^4.0.2": version "4.0.9" resolved "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz#57a2f707242e6fe1de81ad7bfcccaaf606179afb" integrity sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw== dependencies: "@types/d3-time" "*" -"@types/d3-shape@^3.1.0", "@types/d3-shape@^3.1.6": +"@types/d3-shape@^3.1.0": version "3.1.7" resolved "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz#2b7b423dc2dfe69c8c93596e673e37443348c555" integrity sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg== dependencies: "@types/d3-path" "*" -"@types/d3-time-format@^2.3.1": - version "2.3.4" - resolved "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.3.4.tgz#544af5184df8b3fc4d9b42b14058789acee2905e" - integrity sha512-xdDXbpVO74EvadI3UDxjxTdR6QIxm1FKzEA/+F8tL4GWWUg/hgvBqf6chql64U5A9ZUGWo7pEu4eNlyLwbKdhg== - -"@types/d3-time-format@^3.0.0": - version "3.0.4" - resolved "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-3.0.4.tgz#f972bdd7be1048184577cf235a44721a78c6bb4b" - integrity sha512-or9DiDnYI1h38J9hxKEsw513+KVuFbEVhl7qdxcaudoiqWWepapUen+2vAriFGexr6W5+P4l9+HJrB39GG+oRg== - "@types/d3-time@*", "@types/d3-time@^3.0.0": version "3.0.4" resolved "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz#8472feecd639691450dd8000eb33edd444e1323f" integrity sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g== -"@types/d3-time@^1.0.10", "@types/d3-time@^1.1.1": - version "1.1.4" - resolved "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.1.4.tgz#20da4b75c537a940e7319b75717c67a2e499515a" - integrity sha512-JIvy2HjRInE+TXOmIGN5LCmeO0hkFZx5f9FZ7kiN+D+YTcc8pptsiLiuHsvwxwC7VVKmJ2ExHUgNlAiV7vQM9g== - "@types/d3-timer@^3.0.0": version "3.0.2" resolved "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70" @@ -3533,7 +3263,7 @@ resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== -"@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.12", "@types/prop-types@^15.7.2": +"@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.12": version "15.7.14" resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz#1433419d73b2a7ebfc6918dcefd2ec0d5cd698f2" integrity sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ== @@ -5193,13 +4923,6 @@ csstype@^3.0.2, csstype@^3.1.3: resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -d3-array@2: - version "2.12.1" - resolved "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" - integrity sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ== - dependencies: - internmap "^1.0.0" - "d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6: version "3.2.4" resolved "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" @@ -5207,18 +4930,11 @@ d3-array@2: dependencies: internmap "1 - 2" -"d3-color@1 - 3", d3-color@^3.1.0: +"d3-color@1 - 3": version "3.1.0" resolved "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== -d3-delaunay@^6.0.4: - version "6.0.4" - resolved "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz#98169038733a0a5babbeda55054f795bb9e4a58b" - integrity sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A== - dependencies: - delaunator "5" - d3-ease@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" @@ -5229,12 +4945,7 @@ d3-ease@^3.0.1: resolved "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== -d3-format@^1.4.4: - version "1.4.5" - resolved "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4" - integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ== - -"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1: +"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== @@ -5246,14 +4957,6 @@ d3-path@^3.1.0: resolved "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== -d3-scale-chromatic@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz#34c39da298b23c20e02f1a4b239bd0f22e7f1314" - integrity sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ== - dependencies: - d3-color "1 - 3" - d3-interpolate "1 - 3" - d3-scale@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" @@ -5265,7 +4968,7 @@ d3-scale@^4.0.2: d3-time "2.1.1 - 3" d3-time-format "2 - 4" -d3-shape@^3.1.0, d3-shape@^3.2.0: +d3-shape@^3.1.0: version "3.2.0" resolved "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== @@ -5279,20 +4982,6 @@ d3-shape@^3.1.0, d3-shape@^3.2.0: dependencies: d3-time "1 - 3" -d3-time-format@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz#df8056c83659e01f20ac5da5fdeae7c08d5f1bb6" - integrity sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag== - dependencies: - d3-time "1 - 2" - -"d3-time@1 - 2": - version "2.1.1" - resolved "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz#e9d8a8a88691f4548e68ca085e5ff956724a6682" - integrity sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ== - dependencies: - d3-array "2" - "d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0: version "3.1.0" resolved "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" @@ -5300,11 +4989,6 @@ d3-time-format@^3.0.0: dependencies: d3-array "2 - 3" -d3-time@^1.0.10, d3-time@^1.0.11: - version "1.1.0" - resolved "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1" - integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA== - d3-timer@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" @@ -5477,13 +5161,6 @@ define-properties@^1.1.3, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -delaunator@5: - version "5.0.1" - resolved "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz#39032b08053923e924d6094fe2cde1a99cc51278" - integrity sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw== - dependencies: - robust-predicates "^3.0.2" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -7185,11 +6862,6 @@ internal-slot@^1.1.0: resolved "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== -internmap@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz#0017cc8a3b99605f0302f2b198d272e015e5df95" - integrity sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw== - intl-messageformat@^10.7.11: version "10.7.15" resolved "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.15.tgz#5cdc62139ef39ece1b083db32dae4d1c9fa5b627" @@ -9277,7 +8949,7 @@ process@^0.11.10: resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: +prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -10077,11 +9749,6 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -robust-predicates@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771" - integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== - rollup@^4.34.8: version "4.41.1" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.41.1.tgz#46ddc1b33cf1b0baa99320d3b0b4973dc2253b6a" @@ -10572,7 +10239,16 @@ streamx@^2.15.0, streamx@^2.21.0: optionalDependencies: bare-events "^2.2.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10665,7 +10341,14 @@ string_decoder@^1.1.1, string_decoder@^1.3.0: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11883,7 +11566,16 @@ word-wrap@^1.2.5: resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==