feat(M3): Dashboard-Builder — Edit-Modus, Drag&Drop, Palette, Tabs (#361)
- DashboardBuilder: @dnd-kit 12-Spalten-Flow-Grid (seed-konsistent), View/Edit-Schalter, Resize, Tab-Verwaltung, Dashboard-CRUD + Set-Default, Dirty-Save - MiniAppHost ersetzt DashboardWidgetLoader (lazy Registry + settings-Props); Palette nur renderbare Apps (component-Filter) - WidgetSettingsForm generisch aus settings_schema; Bestands-Widgets settings-fähig (RecentContacts: limit) - api/miniapps.ts + api/dashboards.ts (TanStack-Query-Hooks, documents.ts-Muster) - Dashboard.tsx = Builder-Host (StatCards/SystemMetrics bleiben bis M4); Legacy-Grid/Loader gelöscht, Geister-Test ersetzt - Tests: Builder 13/13, Page 11/11, i18n de/en, tsc clean, build OK
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StatCard } from '@/components/shared/StatCard';
|
||||
import { ActivityFeed, ActivityItem } from '@/components/shared/ActivityFeed';
|
||||
import { DashboardGrid } from '@/components/dashboard/DashboardGrid';
|
||||
import { DashboardBuilder } from '@/components/dashboard/DashboardBuilder';
|
||||
import { useUnifiedContacts, useAuditLog } from '@/api/hooks';
|
||||
import { useDashboardWidgets } from '@/api/dashboard';
|
||||
import { useSystemDashboard } from '@/api/systemDashboard';
|
||||
import { useAuthStore } from '@/store/authStore';
|
||||
import { formatDateTime } from '@/utils/date';
|
||||
@@ -14,7 +13,6 @@ export function DashboardPage() {
|
||||
const { data: companiesData } = useUnifiedContacts(1, 1, undefined, 'company');
|
||||
const { data: contactsData } = useUnifiedContacts(1, 1, undefined, 'person');
|
||||
const { data: auditData, isError: auditError } = useAuditLog(1, 5);
|
||||
const { data: widgetsData, isError: widgetsError } = useDashboardWidgets();
|
||||
const { data: systemData } = useSystemDashboard();
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const isAdmin = user?.is_system_admin ?? false;
|
||||
@@ -49,12 +47,15 @@ export function DashboardPage() {
|
||||
avatarUrl: null,
|
||||
}));
|
||||
|
||||
const widgets = widgetsData?.items ?? [];
|
||||
|
||||
return (
|
||||
<div className="p-6 max-w-7xl mx-auto" data-testid="dashboard-page">
|
||||
<h1 className="text-2xl font-bold text-secondary-900 mb-6">{t('dashboard.title')}</h1>
|
||||
|
||||
{/* Personal dashboard builder (Phase M3) — replaces the old plugin widget grid */}
|
||||
<div className="mb-10">
|
||||
<DashboardBuilder />
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
||||
<StatCard
|
||||
label={t('dashboard.totalCompanies')}
|
||||
@@ -78,7 +79,7 @@ export function DashboardPage() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* System Metrics (Admin only) — I-DASH, I-COST, I-USE */}
|
||||
{/* System Metrics (Admin only) — I-DASH, I-COST, I-USE (M4: becomes system MiniApp) */}
|
||||
{isAdmin && systemData && (
|
||||
<div className="mb-8">
|
||||
<h2 className="text-lg font-semibold text-secondary-800 mb-4">{t('dashboard.systemMetrics', 'System Status')}</h2>
|
||||
@@ -144,18 +145,6 @@ export function DashboardPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Dynamic Plugin Widgets */}
|
||||
{widgetsError ? (
|
||||
<p className="text-sm text-secondary-500 mb-6" data-testid="dashboard-widgets-unavailable">
|
||||
{t('dashboard.widgetsUnavailable')}
|
||||
</p>
|
||||
) : widgets.length > 0 ? (
|
||||
<div className="mb-8">
|
||||
<h2 className="text-lg font-semibold text-secondary-800 mb-4">{t('dashboard.widgets')}</h2>
|
||||
<DashboardGrid widgets={widgets} />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{auditError ? (
|
||||
<p className="text-sm text-secondary-500" data-testid="activity-unavailable">
|
||||
{t('dashboard.activityUnavailable')}
|
||||
|
||||
Reference in New Issue
Block a user