From 09b9c1b3d9b3d482acedf47955bb111cc8ff0d07 Mon Sep 17 00:00:00 2001 From: LADsy8 Date: Tue, 7 Jul 2026 22:15:18 -0400 Subject: [PATCH 01/10] test for me for my machine --- hihi.tsx | 1 + 1 file changed, 1 insertion(+) create mode 100644 hihi.tsx diff --git a/hihi.tsx b/hihi.tsx new file mode 100644 index 0000000..7c96369 --- /dev/null +++ b/hihi.tsx @@ -0,0 +1 @@ +dunsadnsandjsandjsandjasnj: wq; From 2cb351a7a03fc8a09ec1c6b6116530a0677b3232 Mon Sep 17 00:00:00 2001 From: LADsy8 Date: Tue, 7 Jul 2026 22:25:31 -0400 Subject: [PATCH 02/10] feat: *NOT FINISHED* the projects wont load anymore, probably broke a line in one of the project GET --- apps/api/internal/handler/analytics.go | 99 ++++++++++++++ apps/api/internal/router/router.go | 14 +- apps/web/src/pages/AnalyticsWorkItemsPage.tsx | 126 +++++++++--------- 3 files changed, 177 insertions(+), 62 deletions(-) create mode 100644 apps/api/internal/handler/analytics.go diff --git a/apps/api/internal/handler/analytics.go b/apps/api/internal/handler/analytics.go new file mode 100644 index 0000000..449e6f4 --- /dev/null +++ b/apps/api/internal/handler/analytics.go @@ -0,0 +1,99 @@ +package handler + +import ( + "encoding/csv" + "fmt" + "log/slog" + "net/http" + "time" + + "github.com/gin-gonic/gin" + "gorm.io/gorm" +) + +type AnalyticsHandler struct { + DB *gorm.DB + Log *slog.Logger +} + +type AnalyticsResponse struct { + ByState map[string]int64 `json:"by_state"` + ByPriority map[string]int64 `json:"by_priority"` +} + +func (h *AnalyticsHandler) GetWorkspaceAnalytics(c *gin.Context) { + slug := c.Param("slug") + + var stateResults []struct { + State string + Count int64 + } + if err := h.DB.Table("issues").Select("state, count(*) as count").Where("workspace_slug = ?", slug).Group("state").Scan(&stateResults).Error; err != nil { + h.Log.Error("failed to fetch workspace state analytics", "error", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"}) + return + } + + byState := make(map[string]int64) + for _, r := range stateResults { + byState[r.State] = r.Count + } + + c.JSON(http.StatusOK, AnalyticsResponse{ + ByState: byState, + ByPriority: map[string]int64{"high": 3, "medium": 8, "low": 12}, // Exemple statique à lier à votre DB + }) +} + +func (h *AnalyticsHandler) GetProjectAnalytics(c *gin.Context) { + projectID := c.Param("projectID") + + var stateResults []struct { + State string + Count int64 + } + if err := h.DB.Table("issues").Select("state, count(*) as count").Where("project_id = ?", projectID).Group("state").Scan(&stateResults).Error; err != nil { + h.Log.Error("failed to fetch project analytics", "error", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"}) + return + } + + byState := make(map[string]int64) + for _, r := range stateResults { + byState[r.State] = r.Count + } + + c.JSON(http.StatusOK, AnalyticsResponse{ByState: byState}) +} + +func (h *AnalyticsHandler) ExportWorkspaceCSV(c *gin.Context) { + slug := c.Param("slug") + filename := fmt.Sprintf("workspace-%s-analytics-%s.csv", slug, time.Now().Format("2006-01-02")) + + c.Header("Content-Description", "File Transfer") + c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename)) + c.Header("Content-Type", "text/csv") + c.Header("Content-Transfer-Encoding", "binary") + + writer := csv.NewWriter(c.Writer) + defer writer.Flush() + + _ = writer.Write([]string{"Issue ID", "Title", "State", "Priority"}) + + _ = writer.Write([]string{"ISSUE-1", "Fix login bug", "In Progress", "High"}) + _ = writer.Write([]string{"ISSUE-2", "Setup Docker environment", "Done", "Medium"}) +} + +func (h *AnalyticsHandler) ExportProjectCSV(c *gin.Context) { + projectID := c.Param("projectID") + filename := fmt.Sprintf("project-%s-analytics-%s.csv", projectID, time.Now().Format("2006-01-02")) + + c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename)) + c.Header("Content-Type", "text/csv") + + writer := csv.NewWriter(c.Writer) + defer writer.Flush() + + _ = writer.Write([]string{"Project Issue ID", "Title", "State"}) + _ = writer.Write([]string{"PROJ-101", "Implement analytics endpoints", "In Progress"}) +} diff --git a/apps/api/internal/router/router.go b/apps/api/internal/router/router.go index 7ceca58..70b014f 100644 --- a/apps/api/internal/router/router.go +++ b/apps/api/internal/router/router.go @@ -221,6 +221,12 @@ func New(cfg Config) *gin.Engine { Queue: cfg.Queue, AppBaseURL: appBaseURL, } + + analyticsHandler := &handler.AnalyticsHandler{ + DB: cfg.DB, + Log: cfg.Log, + } + projectHandler := &handler.ProjectHandler{Project: projectSvc, State: stateSvc} favoriteHandler := &handler.FavoriteHandler{Project: projectSvc, Favorites: userFavoriteStore} stateHandler := &handler.StateHandler{State: stateSvc} @@ -360,6 +366,12 @@ func New(cfg Config) *gin.Engine { api.POST("/workspaces/:slug/projects/:projectId/issues-bulk/delete/", issueHandler.BulkDelete) api.POST("/workspaces/:slug/projects/:projectId/issues-bulk/reorder/", issueHandler.BulkReorder) + api.GET("/workspaces/:slug/analytics/", analyticsHandler.GetWorkspaceAnalytics) + api.GET("/workspaces/:slug/analytics/export/", analyticsHandler.ExportWorkspaceCSV) + + api.GET("/workspaces/:slug/projects/:projectId/analytics", analyticsHandler.GetProjectAnalytics) + api.GET("/workspaces/:slug/projects/:projectId/analytics/export", analyticsHandler.ExportProjectCSV) + api.GET("/workspaces/:slug/projects/:projectId/cycles/", cycleHandler.List) api.POST("/workspaces/:slug/projects/:projectId/cycles/", cycleHandler.Create) api.GET("/workspaces/:slug/projects/:projectId/cycles/:cycleId/", cycleHandler.Get) @@ -372,9 +384,7 @@ func New(cfg Config) *gin.Engine { api.GET("/workspaces/:slug/projects/:projectId/cycles/:cycleId/cycle-progress/", cycleHandler.Progress) api.GET("/workspaces/:slug/projects/:projectId/cycles/:cycleId/analytics", cycleHandler.Analytics) - api.GET("/workspaces/:slug/projects/:projectId/modules/", moduleHandler.List) api.POST("/workspaces/:slug/projects/:projectId/modules/", moduleHandler.Create) - api.GET("/workspaces/:slug/projects/:projectId/modules/:moduleId/", moduleHandler.Get) api.PATCH("/workspaces/:slug/projects/:projectId/modules/:moduleId/", moduleHandler.Update) api.DELETE("/workspaces/:slug/projects/:projectId/modules/:moduleId/", moduleHandler.Delete) api.GET("/workspaces/:slug/projects/:projectId/modules/:moduleId/issues/", moduleHandler.ListIssues) diff --git a/apps/web/src/pages/AnalyticsWorkItemsPage.tsx b/apps/web/src/pages/AnalyticsWorkItemsPage.tsx index f5ef51f..7c753c1 100644 --- a/apps/web/src/pages/AnalyticsWorkItemsPage.tsx +++ b/apps/web/src/pages/AnalyticsWorkItemsPage.tsx @@ -1,5 +1,5 @@ -import { useEffect, useState } from 'react'; -import { Link, useParams } from 'react-router-dom'; +import { useEffect, useState } from "react"; +import { Link, useParams } from "react-router-dom"; import { LineChart, Line, @@ -10,18 +10,18 @@ import { ResponsiveContainer, BarChart, Bar, -} from 'recharts'; -import { workspaceService } from '../services/workspaceService'; -import { projectService } from '../services/projectService'; -import { issueService } from '../services/issueService'; -import { stateService } from '../services/stateService'; -import { useDocumentTitle } from '../hooks/useDocumentTitle'; +} from "recharts"; +import { workspaceService } from "../services/workspaceService"; +import { projectService } from "../services/projectService"; +import { issueService } from "../services/issueService"; +import { stateService } from "../services/stateService"; +import { useDocumentTitle } from "../hooks/useDocumentTitle"; import type { WorkspaceApiResponse, ProjectApiResponse, IssueApiResponse, StateApiResponse, -} from '../api/types'; +} from "../api/types"; const IconSearch = () => ( ([]); const [loading, setLoading] = useState(true); - useDocumentTitle('Analytics'); + useDocumentTitle("Analytics"); useEffect(() => { if (!workspaceSlug) { @@ -153,17 +153,17 @@ export function AnalyticsWorkItemsPage() { }, [workspaceSlug]); const getStateName = (stateId: string | null | undefined) => - stateId ? (states.find((s) => s.id === stateId)?.name ?? stateId) : '—'; + stateId ? (states.find((s) => s.id === stateId)?.name ?? stateId) : "—"; - const backlogCount = issues.filter((i) => getStateName(i.state_id) === 'Backlog').length; - const startedCount = issues.filter((i) => getStateName(i.state_id) === 'In Progress').length; - const unstartedCount = issues.filter((i) => getStateName(i.state_id) === 'Todo').length; - const completedCount = issues.filter((i) => getStateName(i.state_id) === 'Done').length; + const backlogCount = issues.filter((i) => getStateName(i.state_id) === "Backlog").length; + const startedCount = issues.filter((i) => getStateName(i.state_id) === "In Progress").length; + const unstartedCount = issues.filter((i) => getStateName(i.state_id) === "Todo").length; + const completedCount = issues.filter((i) => getStateName(i.state_id) === "Done").length; const priorityCounts = issues.reduce>((acc, i) => { const p = - !i.priority || i.priority === 'none' - ? 'None' + !i.priority || i.priority === "none" + ? "None" : i.priority.charAt(0).toUpperCase() + i.priority.slice(1); acc[p] = (acc[p] ?? 0) + 1; return acc; @@ -173,7 +173,7 @@ export function AnalyticsWorkItemsPage() { count, })); - const doneStateIds = new Set(states.filter((s) => s.name === 'Done').map((s) => s.id)); + const doneStateIds = new Set(states.filter((s) => s.name === "Done").map((s) => s.id)); const createdByDate = issues.reduce>((acc, i) => { const d = i.created_at.slice(0, 10); acc[d] = (acc[d] ?? 0) + 1; @@ -192,11 +192,11 @@ export function AnalyticsWorkItemsPage() { const createdResolvedData = allDates.length > 0 ? allDates.map((dateStr) => { - const d = new Date(dateStr + 'T12:00:00Z'); - const label = d.toLocaleDateString('en-US', { - month: 'short', - day: '2-digit', - year: 'numeric', + const d = new Date(dateStr + "T12:00:00Z"); + const label = d.toLocaleDateString("en-US", { + month: "short", + day: "2-digit", + year: "numeric", }); return { date: label, @@ -207,10 +207,10 @@ export function AnalyticsWorkItemsPage() { }) : [ { - date: new Date().toLocaleDateString('en-US', { - month: 'short', - day: '2-digit', - year: 'numeric', + date: new Date().toLocaleDateString("en-US", { + month: "short", + day: "2-digit", + year: "numeric", }), dateKey: new Date().toISOString().slice(0, 10), created: 0, @@ -222,10 +222,10 @@ export function AnalyticsWorkItemsPage() { const projIssues = issues.filter((i) => i.project_id === p.id); return { project: p, - backlog: projIssues.filter((i) => getStateName(i.state_id) === 'Backlog').length, - started: projIssues.filter((i) => getStateName(i.state_id) === 'In Progress').length, - unstarted: projIssues.filter((i) => getStateName(i.state_id) === 'Todo').length, - completed: projIssues.filter((i) => getStateName(i.state_id) === 'Done').length, + backlog: projIssues.filter((i) => getStateName(i.state_id) === "Backlog").length, + started: projIssues.filter((i) => getStateName(i.state_id) === "In Progress").length, + unstarted: projIssues.filter((i) => getStateName(i.state_id) === "Todo").length, + completed: projIssues.filter((i) => getStateName(i.state_id) === "Done").length, cancelled: 0, }; }); @@ -304,29 +304,29 @@ export function AnalyticsWorkItemsPage() { /> @@ -401,29 +401,29 @@ export function AnalyticsWorkItemsPage() { /> @@ -439,7 +439,7 @@ export function AnalyticsWorkItemsPage() {

{priorityRows.length} Priority - {priorityRows.length !== 1 ? 'ies' : ''} + {priorityRows.length !== 1 ? "ies" : ""}

@@ -447,6 +447,9 @@ export function AnalyticsWorkItemsPage() {
- - - - - + - {projectRows.map(({ project, backlog, started, unstarted, completed, cancelled }) => ( + {projects.map((project) => ( - - - - - + ))} @@ -532,4 +440,4 @@ export function AnalyticsWorkItemsPage() { ); -} +} \ No newline at end of file From 5b0c44267f5acd17a85d74c71a10898c52f7d6ed Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 14 Jul 2026 13:00:56 -0400 Subject: [PATCH 05/10] beginning a branch --- apps/web/src/pages/AnalyticsWorkItemsPage.tsx | 153 +----------------- 1 file changed, 1 insertion(+), 152 deletions(-) diff --git a/apps/web/src/pages/AnalyticsWorkItemsPage.tsx b/apps/web/src/pages/AnalyticsWorkItemsPage.tsx index 62efe20..b01e0ca 100644 --- a/apps/web/src/pages/AnalyticsWorkItemsPage.tsx +++ b/apps/web/src/pages/AnalyticsWorkItemsPage.tsx @@ -1,11 +1,5 @@ -<<<<<<< HEAD import { useEffect, useState } from "react"; import { Link, useParams } from "react-router-dom"; -======= -import { useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Link, useParams } from 'react-router-dom'; ->>>>>>> refs/remotes/origin/main import { LineChart, Line, @@ -26,7 +20,7 @@ interface AnalyticsResponse { by_state: Record; by_priority: Record; } - +6 const IconSearch = () => ( (null); const [loading, setLoading] = useState(true); -<<<<<<< HEAD useDocumentTitle("Analytics"); -======= - useDocumentTitle(t('analytics.documentTitle', 'Analytics')); ->>>>>>> refs/remotes/origin/main useEffect(() => { if (!workspaceSlug) { @@ -130,64 +120,9 @@ export function AnalyticsWorkItemsPage() { if (cancelled) return; setWorkspace(w); -<<<<<<< HEAD projectService.list(workspaceSlug) .then((projs) => { if (!cancelled && projs) setProjects(projs); -======= - const getStateName = (stateId: string | null | undefined) => - stateId ? (states.find((s) => s.id === stateId)?.name ?? stateId) : '—'; - - const backlogCount = issues.filter((i) => getStateName(i.state_id) === 'Backlog').length; - const startedCount = issues.filter((i) => getStateName(i.state_id) === 'In Progress').length; - const unstartedCount = issues.filter((i) => getStateName(i.state_id) === 'Todo').length; - const completedCount = issues.filter((i) => getStateName(i.state_id) === 'Done').length; - - const priorityCounts = issues.reduce>((acc, i) => { - const p = - !i.priority || i.priority === 'none' - ? t('common.none', 'None') - : i.priority.charAt(0).toUpperCase() + i.priority.slice(1); - acc[p] = (acc[p] ?? 0) + 1; - return acc; - }, {}); - const priorityRows = Object.entries(priorityCounts).map(([priority, count]) => ({ - priority, - count, - })); - - const doneStateIds = new Set(states.filter((s) => s.name === 'Done').map((s) => s.id)); - const createdByDate = issues.reduce>((acc, i) => { - const d = i.created_at.slice(0, 10); - acc[d] = (acc[d] ?? 0) + 1; - return acc; - }, {}); - const resolvedByDate = issues - .filter((i) => i.state_id && doneStateIds.has(i.state_id)) - .reduce>((acc, i) => { - const d = i.updated_at.slice(0, 10); - acc[d] = (acc[d] ?? 0) + 1; - return acc; - }, {}); - const allDates = Array.from( - new Set([...Object.keys(createdByDate), ...Object.keys(resolvedByDate)]), - ).sort(); - const createdResolvedData = - allDates.length > 0 - ? allDates.map((dateStr) => { - const d = new Date(dateStr + 'T12:00:00Z'); - const label = d.toLocaleDateString('en-US', { - month: 'short', - day: '2-digit', - year: 'numeric', - }); - return { - date: label, - dateKey: dateStr, - created: createdByDate[dateStr] ?? 0, - resolved: resolvedByDate[dateStr] ?? 0, - }; ->>>>>>> refs/remotes/origin/main }) .catch((err) => console.error("Erreur projets:", err)); @@ -254,25 +189,11 @@ export function AnalyticsWorkItemsPage() {
{/* Tabs */}
-<<<<<<< HEAD Overview Work items -======= - - {t('analytics.overview', 'Overview')} - - - {t('analytics.workItems', 'Work items')} ->>>>>>> refs/remotes/origin/main
@@ -283,15 +204,8 @@ export function AnalyticsWorkItemsPage() { {/* KPIs */}
-<<<<<<< HEAD

Total Work items

{totalIssues}

-======= -

- {t('analytics.totalWorkItems', 'Total Work items')} -

-

{issues.length}

->>>>>>> refs/remotes/origin/main

@@ -342,13 +256,8 @@ export function AnalyticsWorkItemsPage() { tickLine={{ stroke: "var(--border-subtle)" }} axisLine={{ stroke: "var(--border-subtle)" }} label={{ -<<<<<<< HEAD value: "DATE", position: "insideBottom", -======= - value: t('analytics.axisDate', 'DATE'), - position: 'insideBottom', ->>>>>>> refs/remotes/origin/main offset: -4, fill: "var(--txt-tertiary)", fontSize: 11, @@ -359,11 +268,7 @@ export function AnalyticsWorkItemsPage() { tickLine={{ stroke: "var(--border-subtle)" }} axisLine={{ stroke: "var(--border-subtle)" }} label={{ -<<<<<<< HEAD value: "NO. OF WORK ITEMS", -======= - value: t('analytics.axisNoOfWorkItems', 'NO. OF WORK ITEMS'), ->>>>>>> refs/remotes/origin/main angle: -90, position: "insideLeft", fill: "var(--txt-tertiary)", @@ -451,13 +356,8 @@ export function AnalyticsWorkItemsPage() { tickLine={{ stroke: "var(--border-subtle)" }} axisLine={{ stroke: "var(--border-subtle)" }} label={{ -<<<<<<< HEAD value: "PRIORITY", position: "insideBottom", -======= - value: t('analytics.axisPriority', 'PRIORITY'), - position: 'insideBottom', ->>>>>>> refs/remotes/origin/main offset: -4, fill: "var(--txt-tertiary)", fontSize: 11, @@ -468,11 +368,7 @@ export function AnalyticsWorkItemsPage() { tickLine={{ stroke: "var(--border-subtle)" }} axisLine={{ stroke: "var(--border-subtle)" }} label={{ -<<<<<<< HEAD value: "NO. OF WORK ITEM", -======= - value: t('analytics.axisNoOfWorkItem', 'NO. OF WORK ITEM'), ->>>>>>> refs/remotes/origin/main angle: -90, position: "insideLeft", fill: "var(--txt-tertiary)", @@ -492,17 +388,7 @@ export function AnalyticsWorkItemsPage() {

-<<<<<<< HEAD

{priorityRows.length} Priorities

-======= -

- {priorityRows.length} {t('analytics.priority', 'Priority')} - {priorityRows.length !== 1 ? t('analytics.prioritySuffixPlural', 'ies') : ''} -

- - - ->>>>>>> refs/remotes/origin/main
->>>>>>> refs/remotes/origin/main
ProjectBacklogStartedUnstartedCompletedCancelledActions
- - - + {project.name}
{backlog}{started}{unstarted}{completed}{cancelled} + {/* Le bouton export possède désormais le project.id valide grâce à la boucle map */} + +
-<<<<<<< HEAD -======= - - - - - - ->>>>>>> refs/remotes/origin/main From 5d6b90412046b87ceca2ee76f61620adb83fb01a Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 14 Jul 2026 13:00:58 -0400 Subject: [PATCH 06/10] test --- apps/web/package-lock.json | 577 ++++++++++++++++--------------------- 1 file changed, 255 insertions(+), 322 deletions(-) diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json index d74cf4a..44a6d89 100644 --- a/apps/web/package-lock.json +++ b/apps/web/package-lock.json @@ -95,7 +95,6 @@ "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.7", @@ -315,13 +314,12 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], - "license": "MIT", "optional": true, "os": [ "aix" @@ -331,13 +329,12 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], - "license": "MIT", "optional": true, "os": [ "android" @@ -347,13 +344,12 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "android" @@ -363,13 +359,12 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "android" @@ -379,13 +374,12 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "darwin" @@ -395,13 +389,12 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "darwin" @@ -411,13 +404,12 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -427,13 +419,12 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -443,13 +434,12 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -459,13 +449,12 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -475,13 +464,12 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -491,13 +479,12 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -507,13 +494,12 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -523,13 +509,12 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -539,13 +524,12 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -555,13 +539,12 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -571,13 +554,12 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "linux" @@ -587,13 +569,12 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -603,13 +584,12 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -619,13 +599,12 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -635,13 +614,12 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -651,13 +629,12 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "openharmony" @@ -667,13 +644,12 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "sunos" @@ -683,13 +659,12 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -699,13 +674,12 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -715,13 +689,12 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], - "license": "MIT", "optional": true, "os": [ "win32" @@ -901,7 +874,6 @@ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.5.tgz", "integrity": "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==", "license": "MIT", - "peer": true, "dependencies": { "@floating-ui/core": "^1.7.4", "@floating-ui/utils": "^0.2.10" @@ -2161,7 +2133,6 @@ "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-3.22.3.tgz", "integrity": "sha512-Dv9MKK5BDWCF0N2l6/Pxv3JNCce2kwuWf2cKMBc2bEetx0Pn6o7zlFmSxMvYK4UtG1Tw9Yg/ZHi6QOFWK0Zm9Q==", "license": "MIT", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -2423,7 +2394,6 @@ "resolved": "https://registry.npmjs.org/@tiptap/extension-list/-/extension-list-3.22.3.tgz", "integrity": "sha512-rqvv/dtqwbX+8KnPv0eMYp6PnBcuhPMol5cv1GlS8Nq/Cxt68EWGUHBuTFesw+hdnRQLmKwzoO1DlRn7PhxYRQ==", "license": "MIT", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -2531,7 +2501,6 @@ "resolved": "https://registry.npmjs.org/@tiptap/extension-table/-/extension-table-3.22.3.tgz", "integrity": "sha512-inbQSusJad7H0T++L1APg/anfL5d15cNGp2YG3vwo6TQr71nn2c9pepvmz3xuAIt8eygZDRba+4GT/COP1f9QA==", "license": "MIT", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -2637,7 +2606,6 @@ "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-3.22.3.tgz", "integrity": "sha512-JKmWAogM/LX9ZJmXJQalpcR77wWVtVXdRFgvHGsFomW9WFhZqcnIEDWR2sbpZHWtu8dml6eBQGhdLppJmxeFfA==", "license": "MIT", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -2664,7 +2632,6 @@ "resolved": "https://registry.npmjs.org/@tiptap/extensions/-/extensions-3.22.3.tgz", "integrity": "sha512-s5eiMq0m5N6N+W7dU6rd60KgZyyCD7FvtPNNswISfPr12EQwJBfbjWwTqd0UKNzA4fNrhQEERXnzORkykttPeA==", "license": "MIT", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -2679,7 +2646,6 @@ "resolved": "https://registry.npmjs.org/@tiptap/pm/-/pm-3.22.3.tgz", "integrity": "sha512-NjfWjZuvrqmpICT+GZWNIjtOdhPyqFKDMtQy7tsQ5rErM9L2ZQdy/+T/BKSO1JdTeBhdg9OP+0yfsqoYp2aT6A==", "license": "MIT", - "peer": true, "dependencies": { "prosemirror-changeset": "^2.3.0", "prosemirror-collab": "^1.3.1", @@ -2773,7 +2739,6 @@ "resolved": "https://registry.npmjs.org/@tiptap/suggestion/-/suggestion-3.22.3.tgz", "integrity": "sha512-m2c+5gDj2vW7UI1J4JHCKehQUVE12qBhgF+DC+WEWUU8ZrFNf5OEYWQHDNsopa5RRpilfKfhPNbMtXgvGOsk6g==", "license": "MIT", - "peer": true, "funding": { "type": "github", "url": "https://github.com/sponsors/ueberdosis" @@ -2894,7 +2859,6 @@ "integrity": "sha512-oH72nZRfDv9lADUBSo104Aq7gPHpQZc4BTx38r9xf9pg5LfP6EzSyH2n7qFmmxRQXh7YlUXODcYsg6PuTDSxGg==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2904,7 +2868,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2914,7 +2877,6 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2984,7 +2946,6 @@ "integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/types": "8.55.0", @@ -3232,7 +3193,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3568,7 +3528,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.38", "caniuse-lite": "^1.0.30001799", @@ -4257,11 +4216,10 @@ ] }, "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -4269,32 +4227,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/escalade": { @@ -4325,7 +4283,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -5141,7 +5098,6 @@ } ], "license": "MIT", - "peer": true, "peerDependencies": { "typescript": "^5 || ^6 || ^7" }, @@ -5161,49 +5117,47 @@ } }, "node_modules/i18next-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/i18next-parser/-/i18next-parser-9.0.2.tgz", - "integrity": "sha512-Q1yTZljBp1DcVAQD7LxduEqFRpjIeZc+5VnQ+gU8qG9WvY3U5rqK0IVONRWNtngh3orb197bfy1Sz4wlwcplxg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/i18next-parser/-/i18next-parser-9.4.0.tgz", + "integrity": "sha512-SLQJGDj/baBIB9ALmJVXSOXWh3Zn9+wH7J2IuQ4rvx8yuQYpUWitmt8cHFjj6FExjgr8dHfd1SGeQgkowXDO1Q==", "deprecated": "Project is deprecated, use i18next-cli instead", "dev": true, - "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.2", + "@babel/runtime": "^7.25.0", "broccoli-plugin": "^4.0.7", "cheerio": "^1.0.0", - "colors": "1.4.0", - "commander": "~12.1.0", + "colors": "^1.4.0", + "commander": "^12.1.0", "eol": "^0.9.1", - "esbuild": "^0.23.0", - "fs-extra": "^11.1.0", + "esbuild": "^0.25.0", + "fs-extra": "^11.2.0", "gulp-sort": "^2.0.0", - "i18next": "^23.5.1", - "js-yaml": "4.1.0", - "lilconfig": "^3.0.0", - "rsvp": "^4.8.2", + "i18next": "^23.5.1 || ^24.2.0", + "js-yaml": "^4.1.0", + "lilconfig": "^3.1.3", + "rsvp": "^4.8.5", "sort-keys": "^5.0.0", "typescript": "^5.0.4", - "vinyl": "~3.0.0", + "vinyl": "^3.0.0", "vinyl-fs": "^4.0.0" }, "bin": { "i18next": "bin/cli.js" }, "engines": { - "node": ">=18.0.0 || >=20.0.0 || >=22.0.0", + "node": "^18.0.0 || ^20.0.0 || ^22.0.0", "npm": ">=6", "yarn": ">=1" } }, "node_modules/i18next-parser/node_modules/@esbuild/aix-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", - "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "aix" @@ -5213,14 +5167,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/android-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", - "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -5230,14 +5183,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/android-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", - "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -5247,14 +5199,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/android-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", - "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" @@ -5264,14 +5215,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/darwin-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", - "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5281,14 +5231,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/darwin-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", - "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" @@ -5298,14 +5247,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", - "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -5315,14 +5263,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/freebsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", - "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "freebsd" @@ -5332,14 +5279,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/linux-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", - "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5349,14 +5295,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/linux-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", - "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5366,14 +5311,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/linux-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", - "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5383,14 +5327,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/linux-loong64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", - "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5400,14 +5343,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/linux-mips64el": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", - "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5417,14 +5359,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/linux-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", - "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5434,14 +5375,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/linux-riscv64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", - "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5451,14 +5391,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/linux-s390x": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", - "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5468,14 +5407,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/linux-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", - "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" @@ -5484,15 +5422,30 @@ "node": ">=18" } }, + "node_modules/i18next-parser/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/i18next-parser/node_modules/@esbuild/netbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", - "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "netbsd" @@ -5502,14 +5455,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", - "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -5519,14 +5471,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/openbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", - "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "openbsd" @@ -5535,15 +5486,30 @@ "node": ">=18" } }, + "node_modules/i18next-parser/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/i18next-parser/node_modules/@esbuild/sunos-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", - "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "sunos" @@ -5553,14 +5519,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/win32-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", - "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5570,14 +5535,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/win32-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", - "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5587,14 +5551,13 @@ } }, "node_modules/i18next-parser/node_modules/@esbuild/win32-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", - "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -5604,12 +5567,11 @@ } }, "node_modules/i18next-parser/node_modules/esbuild": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", - "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, - "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -5617,30 +5579,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.1", - "@esbuild/android-arm": "0.23.1", - "@esbuild/android-arm64": "0.23.1", - "@esbuild/android-x64": "0.23.1", - "@esbuild/darwin-arm64": "0.23.1", - "@esbuild/darwin-x64": "0.23.1", - "@esbuild/freebsd-arm64": "0.23.1", - "@esbuild/freebsd-x64": "0.23.1", - "@esbuild/linux-arm": "0.23.1", - "@esbuild/linux-arm64": "0.23.1", - "@esbuild/linux-ia32": "0.23.1", - "@esbuild/linux-loong64": "0.23.1", - "@esbuild/linux-mips64el": "0.23.1", - "@esbuild/linux-ppc64": "0.23.1", - "@esbuild/linux-riscv64": "0.23.1", - "@esbuild/linux-s390x": "0.23.1", - "@esbuild/linux-x64": "0.23.1", - "@esbuild/netbsd-x64": "0.23.1", - "@esbuild/openbsd-arm64": "0.23.1", - "@esbuild/openbsd-x64": "0.23.1", - "@esbuild/sunos-x64": "0.23.1", - "@esbuild/win32-arm64": "0.23.1", - "@esbuild/win32-ia32": "0.23.1", - "@esbuild/win32-x64": "0.23.1" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/i18next-parser/node_modules/i18next": { @@ -5667,19 +5631,6 @@ "@babel/runtime": "^7.23.2" } }, - "node_modules/i18next-parser/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -6785,7 +6736,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -6976,7 +6926,6 @@ "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.4.tgz", "integrity": "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA==", "license": "MIT", - "peer": true, "dependencies": { "orderedmap": "^2.0.0" } @@ -7006,7 +6955,6 @@ "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.4.tgz", "integrity": "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==", "license": "MIT", - "peer": true, "dependencies": { "prosemirror-model": "^1.0.0", "prosemirror-transform": "^1.0.0", @@ -7055,7 +7003,6 @@ "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.41.6.tgz", "integrity": "sha512-mxpcDG4hNQa/CPtzxjdlir5bJFDlm0/x5nGBbStB2BWX+XOQ9M8ekEG+ojqB5BcVu2Rc80/jssCMZzSstJuSYg==", "license": "MIT", - "peer": true, "dependencies": { "prosemirror-model": "^1.20.0", "prosemirror-state": "^1.0.0", @@ -7171,7 +7118,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -7181,7 +7127,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -7228,7 +7173,6 @@ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", "license": "MIT", - "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -7335,8 +7279,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -7903,7 +7846,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8147,17 +8089,9 @@ } }, "node_modules/vite": { -<<<<<<< HEAD "version": "7.3.6", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", -======= - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", - "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", - "license": "MIT", - "peer": true, ->>>>>>> refs/remotes/origin/main "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", @@ -8446,7 +8380,6 @@ "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "dev": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } From cada36886cc51dba157369c267678491235a236b Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 14 Jul 2026 14:13:33 -0400 Subject: [PATCH 07/10] Feat: Repaired my project not found error --- apps/api/internal/router/router.go | 2 +- apps/web/src/pages/AnalyticsWorkItemsPage.tsx | 7 ++- apps/web/src/pages/IssueListPage.tsx | 57 +++++++++++-------- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/apps/api/internal/router/router.go b/apps/api/internal/router/router.go index e977ee9..14aa6dc 100644 --- a/apps/api/internal/router/router.go +++ b/apps/api/internal/router/router.go @@ -6,7 +6,7 @@ import ( "time" "github.com/Devlaner/devlane/api/internal/auth" - "github.com/Devlaner/devlane/api/internal/github" + gh "github.com/Devlaner/devlane/api/internal/github" "github.com/Devlaner/devlane/api/internal/handler" "github.com/Devlaner/devlane/api/internal/middleware" "github.com/Devlaner/devlane/api/internal/minio" diff --git a/apps/web/src/pages/AnalyticsWorkItemsPage.tsx b/apps/web/src/pages/AnalyticsWorkItemsPage.tsx index b01e0ca..953ad9f 100644 --- a/apps/web/src/pages/AnalyticsWorkItemsPage.tsx +++ b/apps/web/src/pages/AnalyticsWorkItemsPage.tsx @@ -1,4 +1,5 @@ import { useEffect, useState } from "react"; +import { useTranslation } from 'react-i18next'; import { Link, useParams } from "react-router-dom"; import { LineChart, @@ -108,12 +109,12 @@ export function AnalyticsWorkItemsPage() { useEffect(() => { if (!workspaceSlug) { // eslint-disable-next-line react-hooks/set-state-in-effect -- intentional: reset loading when no slug (kept for future use) + setLoading(false); return; } let cancelled = false; setLoading(true); - workspaceService .getBySlug(workspaceSlug) .then((w) => { @@ -127,7 +128,9 @@ export function AnalyticsWorkItemsPage() { .catch((err) => console.error("Erreur projets:", err)); fetch(`/api/workspaces/${workspaceSlug}/analytics`) + .then((res) => { + console.log("after fetch") if (!res.ok) { throw new Error(`Code erreur serveur Go : ${res.status}`); } @@ -392,7 +395,7 @@ export function AnalyticsWorkItemsPage() {
Project Actions - {t('analytics.colProject', 'Project')} - - {t('analytics.colBacklog', 'Backlog')} - - {t('analytics.colStarted', 'Started')} - - {t('analytics.colUnstarted', 'Unstarted')} - - {t('analytics.colCompleted', 'Completed')} - - {t('analytics.colCancelled', 'Cancelled')} -
- - @@ -416,8 +481,8 @@ export function AnalyticsWorkItemsPage() { {priorityRows.map(({ priority, count }) => ( - - + + ))} @@ -436,27 +501,30 @@ export function AnalyticsWorkItemsPage() {
+ {t('analytics.priority', 'Priority')} + {t('analytics.count', 'Count')}
{priority}{count}{priority}{count}
- - + + {projects.map((project) => ( - - From 50db92656a2dde31edb0c389f4defc97330c91e6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 14 Jul 2026 16:07:41 -0400 Subject: [PATCH 09/10] Feat: finished the issue i think --- apps/web/src/pages/AnalyticsWorkItemsPage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/src/pages/AnalyticsWorkItemsPage.tsx b/apps/web/src/pages/AnalyticsWorkItemsPage.tsx index 1243027..333da89 100644 --- a/apps/web/src/pages/AnalyticsWorkItemsPage.tsx +++ b/apps/web/src/pages/AnalyticsWorkItemsPage.tsx @@ -239,9 +239,9 @@ export function AnalyticsWorkItemsPage() { const totalIssues = backlogCount + startedCount + unstartedCount + completedCount; const priorityRows = Object.entries(analytics?.by_priority ?? {}).map(([priority, count]) => ({ - priority: priority.charAt(0).toUpperCase() + priority.slice(1), - count, - })); + priority: priority ? priority.charAt(0).toUpperCase() + priority.slice(1) : "None", + count, +})); const createdResolvedData: any[] = []; From 112424c76630272b2e232c21fe1b3a6a1263bfe9 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 14 Jul 2026 16:51:13 -0400 Subject: [PATCH 10/10] Feat: added the response type of assignee and label, but there are not present in the database.. :( --- apps/api/internal/handler/analytics.go | 168 +++++++++++++++++++++---- 1 file changed, 143 insertions(+), 25 deletions(-) diff --git a/apps/api/internal/handler/analytics.go b/apps/api/internal/handler/analytics.go index edb371e..a1c64cc 100644 --- a/apps/api/internal/handler/analytics.go +++ b/apps/api/internal/handler/analytics.go @@ -19,21 +19,23 @@ type AnalyticsHandler struct { type AnalyticsResponse struct { ByState map[string]int64 `json:"by_state"` ByPriority map[string]int64 `json:"by_priority"` + ByAssignee map[string]int64 `json:"by_assignee"` + ByLabel map[string]int64 `json:"by_label"` } func (h *AnalyticsHandler) GetWorkspaceAnalytics(c *gin.Context) { slug := c.Param("slug") + // 1. Counts by State var stateResults []struct { State string Count int64 } - err := h.DB.Table("issues"). Select("states.name as state, count(issues.id) as count"). Joins("INNER JOIN states ON issues.state_id = states.id"). Joins("INNER JOIN workspaces ON issues.workspace_id = workspaces.id"). - Where("workspaces.slug = ? AND issues.deleted_at IS NULL AND workspaces.deleted_at IS NULL", slug). + Where("workspaces.slug = ? AND issues.deleted_at IS NULL AND workspaces.deleted_at IS NULL AND states.deleted_at IS NULL", slug). Group("states.name"). Scan(&stateResults).Error @@ -48,6 +50,7 @@ func (h *AnalyticsHandler) GetWorkspaceAnalytics(c *gin.Context) { byState[r.State] = r.Count } + // 2. Counts by Priority var priorityResults []struct { Priority string Count int64 @@ -70,24 +73,75 @@ func (h *AnalyticsHandler) GetWorkspaceAnalytics(c *gin.Context) { byPriority[r.Priority] = r.Count } + // 3. Counts by Assignee (Many-to-Many via issue_assignees) + var assigneeResults []struct { + Email string + Count int64 + } + err = h.DB.Table("issue_assignees"). + Select("users.email as email, count(issue_assignees.issue_id) as count"). + Joins("INNER JOIN users ON issue_assignees.user_id = users.id"). + Joins("INNER JOIN issues ON issue_assignees.issue_id = issues.id"). + Joins("INNER JOIN workspaces ON issues.workspace_id = workspaces.id"). + Where("workspaces.slug = ? AND issues.deleted_at IS NULL AND workspaces.deleted_at IS NULL", slug). + Group("users.email"). + Scan(&assigneeResults).Error + + byAssignee := make(map[string]int64) + if err == nil { + for _, r := range assigneeResults { + byAssignee[r.Email] = r.Count + } + } else { + h.Log.Warn("failed to fetch workspace assignee analytics", "error", err) + } + + // 4. Counts by Label (Many-to-Many via issue_labels) + var labelResults []struct { + Label string + Count int64 + } + err = h.DB.Table("issue_labels"). + Select("labels.name as label, count(issue_labels.issue_id) as count"). + Joins("INNER JOIN labels ON issue_labels.label_id = labels.id"). + Joins("INNER JOIN issues ON issue_labels.issue_id = issues.id"). + Joins("INNER JOIN workspaces ON issues.workspace_id = workspaces.id"). + Where("workspaces.slug = ? AND issues.deleted_at IS NULL AND workspaces.deleted_at IS NULL AND labels.deleted_at IS NULL", slug). + Group("labels.name"). + Scan(&labelResults).Error + + byLabel := make(map[string]int64) + if err == nil { + for _, r := range labelResults { + byLabel[r.Label] = r.Count + } + } else { + h.Log.Warn("failed to fetch workspace label analytics", "error", err) + } + c.JSON(http.StatusOK, AnalyticsResponse{ ByState: byState, ByPriority: byPriority, + ByAssignee: byAssignee, + ByLabel: byLabel, }) } func (h *AnalyticsHandler) GetProjectAnalytics(c *gin.Context) { - projectID := c.Param("projectID") + projectID := c.Param("projectId") + if projectID == "" { + projectID = c.Param("projectID") + } + // 1. Project Counts by State var stateResults []struct { State string Count int64 } - err := h.DB.Table("issues"). Select("states.name as state, count(issues.id) as count"). Joins("INNER JOIN states ON issues.state_id = states.id"). - Where("issues.project_id = ? AND issues.deleted_at IS NULL", projectID). + Where("issues.project_id = ? AND issues.deleted_at IS NULL AND states.deleted_at IS NULL", projectID). Group("states.name"). Scan(&stateResults).Error @@ -102,39 +156,101 @@ func (h *AnalyticsHandler) GetProjectAnalytics(c *gin.Context) { byState[r.State] = r.Count } - c.JSON(http.StatusOK, AnalyticsResponse{ByState: byState}) + // 2. Project Counts by Priority + var priorityResults []struct { + Priority string + Count int64 + } + err = h.DB.Table("issues"). + Select("issues.priority, count(issues.id) as count"). + Where("issues.project_id = ? AND issues.deleted_at IS NULL AND issues.priority IS NOT NULL AND issues.priority != ''", projectID). + Group("issues.priority"). + Scan(&priorityResults).Error + + byPriority := make(map[string]int64) + if err == nil { + for _, r := range priorityResults { + byPriority[r.Priority] = r.Count + } + } + + // 3. Project Counts by Assignee + var assigneeResults []struct { + Email string + Count int64 + } + err = h.DB.Table("issue_assignees"). + Select("users.email as email, count(issue_assignees.issue_id) as count"). + Joins("INNER JOIN users ON issue_assignees.user_id = users.id"). + Joins("INNER JOIN issues ON issue_assignees.issue_id = issues.id"). + Where("issues.project_id = ? AND issues.deleted_at IS NULL", projectID). + Group("users.email"). + Scan(&assigneeResults).Error + + byAssignee := make(map[string]int64) + if err == nil { + for _, r := range assigneeResults { + byAssignee[r.Email] = r.Count + } + } + + // 4. Project Counts by Label + var labelResults []struct { + Label string + Count int64 + } + err = h.DB.Table("issue_labels"). + Select("labels.name as label, count(issue_labels.issue_id) as count"). + Joins("INNER JOIN labels ON issue_labels.label_id = labels.id"). + Joins("INNER JOIN issues ON issue_labels.issue_id = issues.id"). + Where("issues.project_id = ? AND issues.deleted_at IS NULL AND labels.deleted_at IS NULL", projectID). + Group("labels.name"). + Scan(&labelResults).Error + + byLabel := make(map[string]int64) + if err == nil { + for _, r := range labelResults { + byLabel[r.Label] = r.Count + } + } + + c.JSON(http.StatusOK, AnalyticsResponse{ + ByState: byState, + ByPriority: byPriority, + ByAssignee: byAssignee, + ByLabel: byLabel, + }) } func (h *AnalyticsHandler) ExportWorkspaceCSV(c *gin.Context) { slug := c.Param("slug") - filename := fmt.Sprintf("workspace-%s-analytics-%s.csv", slug, time.Now().Format("2006-01-02")) - - c.Header("Content-Description", "File Transfer") - c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename)) - c.Header("Content-Type", "text/csv") - c.Header("Content-Transfer-Encoding", "binary") var issues []struct { ID string - Name string // CHANGED: Changed Title to Name to match schema column 'name' + Name string State string Priority string } - // CHANGED: Querying issues.name instead of issues.title err := h.DB.Table("issues"). Select("issues.id, issues.name, states.name as state, issues.priority"). Joins("INNER JOIN states ON issues.state_id = states.id"). Joins("INNER JOIN workspaces ON issues.workspace_id = workspaces.id"). - Where("workspaces.slug = ? AND issues.deleted_at IS NULL AND workspaces.deleted_at IS NULL", slug). + Where("workspaces.slug = ? AND issues.deleted_at IS NULL AND workspaces.deleted_at IS NULL AND states.deleted_at IS NULL", slug). Scan(&issues).Error if err != nil { h.Log.Error("failed to fetch workspace issues for CSV export", "error", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate CSV"}) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch workspace data"}) return } + filename := fmt.Sprintf("workspace-%s-analytics-%s.csv", slug, time.Now().Format("2006-01-02")) + c.Header("Content-Description", "File Transfer") + c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) + c.Header("Content-Type", "text/csv") + c.Header("Content-Transfer-Encoding", "binary") + writer := csv.NewWriter(c.Writer) defer writer.Flush() @@ -151,31 +267,33 @@ func (h *AnalyticsHandler) ExportWorkspaceCSV(c *gin.Context) { } func (h *AnalyticsHandler) ExportProjectCSV(c *gin.Context) { - projectID := c.Param("projectID") - filename := fmt.Sprintf("project-%s-analytics-%s.csv", projectID, time.Now().Format("2006-01-02")) - - c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename)) - c.Header("Content-Type", "text/csv") + projectID := c.Param("projectId") + if projectID == "" { + projectID = c.Param("projectID") + } var issues []struct { ID string - Name string // CHANGED: Changed Title to Name to match schema column 'name' + Name string State string } - // CHANGED: Querying issues.name instead of issues.title err := h.DB.Table("issues"). Select("issues.id, issues.name, states.name as state"). Joins("INNER JOIN states ON issues.state_id = states.id"). - Where("issues.project_id = ? AND issues.deleted_at IS NULL", projectID). + Where("issues.project_id = ? AND issues.deleted_at IS NULL AND states.deleted_at IS NULL", projectID). Scan(&issues).Error if err != nil { h.Log.Error("failed to fetch project issues for CSV export", "error", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate CSV"}) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch project data"}) return } + filename := fmt.Sprintf("project-%s-analytics-%s.csv", projectID, time.Now().Format("2006-01-02")) + c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) + c.Header("Content-Type", "text/csv") + writer := csv.NewWriter(c.Writer) defer writer.Flush()
ProjectActionsProjectActions
+
{project.name}
- {/* Le bouton export possède désormais le project.id valide grâce à la boucle map */} +