From 432c498330c98ce77b0117746ef8d833ad989141 Mon Sep 17 00:00:00 2001 From: busya Date: Wed, 17 Jun 2026 14:01:15 +0300 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20DashboardDataGrid=20=E2=80=94?= =?UTF-8?q?=20configurable=20grid=20component?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate dashboard grid patterns into a single reusable component with opt-in features: selection, sorting, filtering, pagination, loading skeleton, empty state, and bulk actions snippet. - Add Dashboard.DataGrid component with () state management - Replace DashboardGrid usage in migration page (removes Validate/Git/Status columns) - Deprecate DashboardGrid (no longer used by any active route) - Update RepositoryDashboardGrid header with consolidation rationale - Add 14 vitest tests covering all features and edge cases Strategy B consolidation: migration page now uses clean grid with only Title + Last Modified columns. DashboardGrid marked @DEPRECATED. RepositoryDashboardGrid noted as future consolidation candidate. --- .../dashboard/DashboardDataGrid.svelte | 323 ++++++++++++++++++ .../components/dashboard/DashboardGrid.svelte | 7 +- .../dashboard/RepositoryDashboardGrid.svelte | 19 +- .../__tests__/DashboardDataGrid.test.ts | 256 ++++++++++++++ frontend/src/routes/migration/+page.svelte | 24 +- 5 files changed, 609 insertions(+), 20 deletions(-) create mode 100644 frontend/src/lib/components/dashboard/DashboardDataGrid.svelte create mode 100644 frontend/src/lib/components/dashboard/__tests__/DashboardDataGrid.test.ts diff --git a/frontend/src/lib/components/dashboard/DashboardDataGrid.svelte b/frontend/src/lib/components/dashboard/DashboardDataGrid.svelte new file mode 100644 index 000000000..92d545e87 --- /dev/null +++ b/frontend/src/lib/components/dashboard/DashboardDataGrid.svelte @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + {#if filterable} +
+ +
+ {/if} + + + {#if selectable && selectedIds.length > 0 && children} +
+ {@render children()} +
+ {/if} + + + {#if loading} +
+
+ {#each Array(loadingRows) as _} +
+ {#if selectable} +
+ {/if} + {#each columns as col} +
+ {/each} +
+ {/each} +
+ + + {:else if !loading && displayData.length === 0} +
+ + + +

{emptyText || $t.common?.no_data || "No items"}

+
+ + + {:else} +
+ + + + {#if selectable} + + {/if} + {#each columns as col (col.key)} + + {/each} + + + + {#each displayData as item (item[keyField])} + + {#if selectable} + + {/if} + {#each columns as col (col.key)} + + {/each} + + {/each} + +
+ handleSelectAll((e.target as HTMLInputElement).checked)} + class="h-4 w-4 text-primary border-border-strong rounded focus-visible:ring-primary-ring" + aria-label="Select all" + /> + handleSort(col.key) : undefined} + aria-sort={col.sortable && sortColumn === col.key ? (sortDirection === 'asc' ? 'ascending' : 'descending') : undefined} + > + {col.label} + {#if col.sortable} + {#if sortColumn === col.key} + {sortDirection === "asc" ? "↑" : "↓"} + {:else} + + {/if} + {/if} +
+ handleSelectionChange(item[keyField], (e.target as HTMLInputElement).checked)} + class="h-4 w-4 text-primary border-border-strong rounded focus-visible:ring-primary-ring" + /> + + {col.render ? col.render(item) : item[col.key]} +
+
+ + + {#if paginated && sortedData.length > 0} +
+
+ {($t.dashboard?.showing ?? "") + .replace("{start}", String(page * pageSize + 1)) + .replace("{end}", String(Math.min((page + 1) * pageSize, totalCount))) + .replace("{total}", String(totalCount))} +
+
+ + +
+
+ {/if} + {/if} +
+ + + diff --git a/frontend/src/lib/components/dashboard/DashboardGrid.svelte b/frontend/src/lib/components/dashboard/DashboardGrid.svelte index 8fbb080bc..e1ea785be 100644 --- a/frontend/src/lib/components/dashboard/DashboardGrid.svelte +++ b/frontend/src/lib/components/dashboard/DashboardGrid.svelte @@ -1,14 +1,17 @@ - + diff --git a/frontend/src/lib/components/dashboard/RepositoryDashboardGrid.svelte b/frontend/src/lib/components/dashboard/RepositoryDashboardGrid.svelte index 78b862223..4fdd6eca0 100644 --- a/frontend/src/lib/components/dashboard/RepositoryDashboardGrid.svelte +++ b/frontend/src/lib/components/dashboard/RepositoryDashboardGrid.svelte @@ -1,15 +1,12 @@ - + - + - + + + + +