@burdenoff/microfe-workspaces 2026.625.5 → 2026.626.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/pages/ActivityListPage.js +94 -90
  2. package/dist/pages/ActivityListPage.js.map +1 -1
  3. package/dist/pages/CreateWorkspacePage.js +68 -63
  4. package/dist/pages/CreateWorkspacePage.js.map +1 -1
  5. package/dist/pages/InviteAcceptancePage.js +101 -96
  6. package/dist/pages/InviteAcceptancePage.js.map +1 -1
  7. package/dist/pages/MembersListPage.js +185 -184
  8. package/dist/pages/MembersListPage.js.map +1 -1
  9. package/dist/pages/PendingInvitesPage.js +70 -68
  10. package/dist/pages/PendingInvitesPage.js.map +1 -1
  11. package/dist/pages/ProjectDetailPage.js +119 -78
  12. package/dist/pages/ProjectDetailPage.js.map +1 -1
  13. package/dist/pages/ProjectMembersPage.js +105 -104
  14. package/dist/pages/ProjectMembersPage.js.map +1 -1
  15. package/dist/pages/ProjectsListPage.js +158 -157
  16. package/dist/pages/ProjectsListPage.js.map +1 -1
  17. package/dist/pages/WorkspaceDetailPage.js +236 -198
  18. package/dist/pages/WorkspaceDetailPage.js.map +1 -1
  19. package/dist/pages/WorkspaceInvitePage.js +341 -300
  20. package/dist/pages/WorkspaceInvitePage.js.map +1 -1
  21. package/dist/pages/WorkspaceSettingsPage.js +87 -85
  22. package/dist/pages/WorkspaceSettingsPage.js.map +1 -1
  23. package/dist/pages/WorkspacesListPage.js +122 -121
  24. package/dist/pages/WorkspacesListPage.js.map +1 -1
  25. package/dist/pages/dashboard/DashboardPage.js +55 -51
  26. package/dist/pages/dashboard/DashboardPage.js.map +1 -1
  27. package/dist/pages/dashboard/widgets/GroupsWidget.js +16 -17
  28. package/dist/pages/dashboard/widgets/GroupsWidget.js.map +1 -1
  29. package/dist/pages/dashboard/widgets/TagCloudWidget.js +18 -19
  30. package/dist/pages/dashboard/widgets/TagCloudWidget.js.map +1 -1
  31. package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js +10 -11
  32. package/dist/pages/dashboard/widgets/WorkflowStatsWidget.js.map +1 -1
  33. package/package.json +2 -2
@@ -7,16 +7,16 @@ import { DashboardCustomizer as c } from "./DashboardCustomizer.js";
7
7
  import { useCallback as l, useMemo as u, useState as d } from "react";
8
8
  import { AlertCircle as f, Loader2 as p, RefreshCw as m, Settings2 as h } from "lucide-react";
9
9
  import { jsx as g, jsxs as _ } from "react/jsx-runtime";
10
- import { Button as v } from "@burdenoff/fe-libs/ui";
11
- import { useI18n as y } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
10
+ import { Button as v, PagePurpose as y } from "@burdenoff/fe-libs/ui";
11
+ import { useI18n as b } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
12
12
  //#region src/pages/dashboard/DashboardPage.tsx
13
- function b({ navigate: b, authToken: x, currentUser: S, productId: C = "workspaces" }) {
13
+ function x({ navigate: x, authToken: S, currentUser: C, productId: w = "workspaces" }) {
14
14
  e("workspaces.dashboard");
15
- let { t: w } = y(), T = (e, t) => {
16
- let n = w(e);
15
+ let { t: T } = b(), E = (e, t) => {
16
+ let n = T(e);
17
17
  return n === e ? t : n;
18
- }, [E, D] = d(!1), { data: O, isLoading: k, error: A, refetch: j } = i(x), { data: M, isLoading: N, error: P, refetch: F } = t(x), { data: I, isLoading: L, refetch: R } = n(x), z = C === "vibecontrols", { data: B, isLoading: V, refetch: H } = r(x, z), U = a(x), W = k || N || L || V, G = u(() => !O && !M && !I && !B ? null : {
19
- ...O ?? {
18
+ }, [D, O] = d(!1), { data: k, isLoading: A, error: j, refetch: M } = i(S), { data: N, isLoading: P, error: F, refetch: I } = t(S), { data: L, isLoading: R, refetch: z } = n(S), B = w === "vibecontrols", { data: V, isLoading: H, refetch: U } = r(S, B), W = a(S), G = A || P || R || H, K = u(() => !k && !N && !L && !V ? null : {
19
+ ...k ?? {
20
20
  workspaces: {
21
21
  items: [],
22
22
  total: 0
@@ -38,33 +38,33 @@ function b({ navigate: b, authToken: x, currentUser: S, productId: C = "workspac
38
38
  workflowStats: null,
39
39
  storageUsage: null
40
40
  },
41
- workspaces: M?.workspaces ?? {
41
+ workspaces: N?.workspaces ?? {
42
42
  items: [],
43
43
  total: 0
44
44
  },
45
- projects: I ?? {
45
+ projects: L ?? {
46
46
  items: [],
47
47
  total: 0
48
48
  },
49
- recentVibes: B?.recentVibes,
50
- activeSessions: B?.activeSessions,
51
- agentFleet: B?.agentFleet ?? null
49
+ recentVibes: V?.recentVibes,
50
+ activeSessions: V?.activeSessions,
51
+ agentFleet: V?.agentFleet ?? null
52
+ }, [
53
+ k,
54
+ N,
55
+ L,
56
+ V
57
+ ]), q = N?.dashboardPreferences, J = u(() => o(q?.widgets ?? null, w), [q, w]), Y = l(() => {
58
+ M(), I(), z(), B && U();
52
59
  }, [
53
- O,
54
60
  M,
55
61
  I,
62
+ z,
63
+ U,
56
64
  B
57
- ]), K = M?.dashboardPreferences, q = u(() => o(K?.widgets ?? null, C), [K, C]), J = l(() => {
58
- j(), F(), R(), z && H();
59
- }, [
60
- j,
61
- F,
62
- R,
63
- H,
64
- z
65
- ]), Y = l(async (e) => {
66
- await U.mutateAsync(e);
67
- }, [U]), X = A || P;
65
+ ]), X = l(async (e) => {
66
+ await W.mutateAsync(e);
67
+ }, [W]), Z = j || F;
68
68
  return /* @__PURE__ */ _("div", {
69
69
  className: "min-h-[calc(100vh-8rem)] p-4 md:p-6 bg-bg-canvas",
70
70
  "data-tour": "main-content",
@@ -73,75 +73,79 @@ function b({ navigate: b, authToken: x, currentUser: S, productId: C = "workspac
73
73
  className: "flex flex-wrap items-center justify-between gap-4 mb-6",
74
74
  children: [/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("h1", {
75
75
  className: "text-xl font-bold text-text-primary",
76
- children: T("dashboard.title", "Dashboard")
76
+ children: E("dashboard.title", "Dashboard")
77
77
  }), /* @__PURE__ */ g("p", {
78
78
  className: "text-sm text-text-secondary mt-0.5",
79
- children: T("dashboard.subtitle", "Your workspace overview at a glance")
79
+ children: E("dashboard.subtitle", "Your workspace overview at a glance")
80
80
  })] }), /* @__PURE__ */ _("div", {
81
81
  className: "flex flex-wrap items-center gap-2",
82
82
  "data-tour": "quick-actions",
83
83
  children: [/* @__PURE__ */ _(v, {
84
84
  variant: "outline",
85
85
  size: "sm",
86
- onClick: J,
87
- disabled: W,
86
+ onClick: Y,
87
+ disabled: G,
88
88
  className: "text-xs",
89
- children: [W ? /* @__PURE__ */ g(p, { className: "size-3.5 sm:mr-1.5 animate-spin" }) : /* @__PURE__ */ g(m, { className: "size-3.5 sm:mr-1.5" }), /* @__PURE__ */ g("span", {
89
+ children: [G ? /* @__PURE__ */ g(p, { className: "size-3.5 sm:mr-1.5 animate-spin" }) : /* @__PURE__ */ g(m, { className: "size-3.5 sm:mr-1.5" }), /* @__PURE__ */ g("span", {
90
90
  className: "hidden sm:inline",
91
- children: T("dashboard.refresh", "Refresh")
91
+ children: E("dashboard.refresh", "Refresh")
92
92
  })]
93
93
  }), /* @__PURE__ */ _(v, {
94
94
  variant: "outline",
95
95
  size: "sm",
96
- onClick: () => D(!0),
96
+ onClick: () => O(!0),
97
97
  className: "text-xs",
98
98
  children: [/* @__PURE__ */ g(h, { className: "size-3.5 sm:mr-1.5" }), /* @__PURE__ */ g("span", {
99
99
  className: "hidden sm:inline",
100
- children: T("dashboard.customize", "Customize")
100
+ children: E("dashboard.customize", "Customize")
101
101
  })]
102
102
  })]
103
103
  })]
104
104
  }),
105
- X && /* @__PURE__ */ _("div", {
105
+ /* @__PURE__ */ g(y, {
106
+ className: "mb-6 -mt-2",
107
+ children: E("dashboard.purpose", "This is your home base — a single glance across everything that matters: your workspaces and projects, recent activity, upcoming events and live status. Use Customize to choose which cards appear and how they are arranged, and click any card to dive into the full view.")
108
+ }),
109
+ Z && /* @__PURE__ */ _("div", {
106
110
  className: "mb-4 p-3 bg-status-error-bg/10 border border-status-error-border/20 rounded-lg flex items-center gap-2",
107
111
  children: [/* @__PURE__ */ g(f, { className: "size-4 text-status-error-text shrink-0" }), /* @__PURE__ */ _("p", {
108
112
  className: "text-sm text-status-error-text",
109
113
  children: [
110
- T("dashboard.error.partialData", "Some data may be unavailable."),
114
+ E("dashboard.error.partialData", "Some data may be unavailable."),
111
115
  " ",
112
- A ? T("dashboard.error.workspaceDown", "Workspace services may be down.") : "",
116
+ j ? E("dashboard.error.workspaceDown", "Workspace services may be down.") : "",
113
117
  " ",
114
- P ? T("dashboard.error.globalDown", "Global services may be down.") : "",
118
+ F ? E("dashboard.error.globalDown", "Global services may be down.") : "",
115
119
  " ",
116
120
  /* @__PURE__ */ g("button", {
117
121
  type: "button",
118
122
  className: "underline font-medium hover:text-status-error-text/80",
119
- onClick: J,
120
- children: T("dashboard.error.tryRefreshing", "Try refreshing")
123
+ onClick: Y,
124
+ children: E("dashboard.error.tryRefreshing", "Try refreshing")
121
125
  })
122
126
  ]
123
127
  })]
124
128
  }),
125
129
  /* @__PURE__ */ g(s, {
126
- widgets: q,
127
- workspaceData: G,
128
- globalData: M ?? null,
129
- isLoading: W,
130
- navigate: b,
131
- productId: C
130
+ widgets: J,
131
+ workspaceData: K,
132
+ globalData: N ?? null,
133
+ isLoading: G,
134
+ navigate: x,
135
+ productId: w
132
136
  }),
133
137
  /* @__PURE__ */ g(c, {
134
- open: E,
135
- onOpenChange: D,
136
- widgets: q,
137
- onSave: Y,
138
- isSaving: U.isPending,
139
- productId: C
138
+ open: D,
139
+ onOpenChange: O,
140
+ widgets: J,
141
+ onSave: X,
142
+ isSaving: W.isPending,
143
+ productId: w
140
144
  })
141
145
  ]
142
146
  });
143
147
  }
144
148
  //#endregion
145
- export { b as DashboardPage };
149
+ export { x as DashboardPage };
146
150
 
147
151
  //# sourceMappingURL=DashboardPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["/**\n * DashboardPage — Comprehensive workspace dashboard.\n *\n * This is the main dashboard component exported from microfe-workspaces.\n * It fetches data from both workspace and global gateways, manages widget\n * layout preferences, and renders a customizable grid of widgets.\n *\n * Props:\n * - navigate: Shell navigation function\n * - authToken: Current user's auth token\n * - currentUser: Basic user info from shell\n *\n * Data Flow:\n * 1. Two parallel queries: workspace gateway + global gateway\n * 2. Global query returns user preferences (dashboard layout)\n * 3. Widget layout falls back to defaults if no preferences saved\n * 4. Data is passed as props to individual widgets\n */\nimport { useState, useMemo, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { Settings2, RefreshCw, Loader2, AlertCircle } from 'lucide-react';\nimport {\n useWorkspaceDashboardData,\n useGlobalDashboardData,\n useProjectsDashboardData,\n useVibecontrolsDashboardData,\n} from './hooks/useDashboardData';\nimport { useUpdateDashboardPreferences } from './hooks/useDashboardPreferences';\nimport { DashboardGrid } from './DashboardGrid';\nimport { DashboardCustomizer } from './DashboardCustomizer';\nimport { getEffectiveWidgets } from './config';\nimport type { WidgetConfig } from './types';\nimport { useWorkspacesPageView } from '../../hooks/useWorkspacesPageView';\n\ninterface DashboardPageProps {\n navigate: (path: string) => void;\n authToken?: string | null;\n currentUser?: {\n id: string;\n email: string;\n firstName?: string;\n lastName?: string;\n name?: string;\n } | null;\n /**\n * Host product identifier ('workspaces', 'vibecontrols', etc.). Drives\n * which widgets appear in the registry + default layout. Defaults to\n * 'workspaces' for legacy callers.\n */\n productId?: string;\n}\n\nexport function DashboardPage({\n navigate,\n authToken,\n currentUser: _currentUser,\n productId = 'workspaces',\n}: DashboardPageProps) {\n useWorkspacesPageView('workspaces.dashboard');\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [customizerOpen, setCustomizerOpen] = useState(false);\n\n // ─── Data Fetching ────────────────────────────────────────────────────────\n const {\n data: workspaceData,\n isLoading: wsLoading,\n error: wsError,\n refetch: refetchWs,\n } = useWorkspaceDashboardData(authToken);\n\n const {\n data: globalData,\n isLoading: globalLoading,\n error: globalError,\n refetch: refetchGlobal,\n } = useGlobalDashboardData(authToken);\n\n const {\n data: projectsData,\n isLoading: projectsLoading,\n refetch: refetchProjects,\n } = useProjectsDashboardData(authToken);\n\n const isVibecontrols = productId === 'vibecontrols';\n const {\n data: vibecontrolsData,\n isLoading: vibecontrolsLoading,\n refetch: refetchVibecontrols,\n } = useVibecontrolsDashboardData(authToken, isVibecontrols);\n\n const updatePrefs = useUpdateDashboardPreferences(authToken);\n\n const isLoading = wsLoading || globalLoading || projectsLoading || vibecontrolsLoading;\n\n // ─── Merge data ───────────────────────────────────────────────────────────\n // Workspace/org stats come from the global tenant service (globalData),\n // while workspace-scoped features (activity, calendar, tags, etc.) come\n // from the workspace gateway (workspaceData). Merge them so widgets\n // reading workspaceData.workspaces see the real tenant data.\n const mergedWorkspaceData = useMemo(() => {\n if (!workspaceData && !globalData && !projectsData && !vibecontrolsData) return null;\n return {\n ...(workspaceData ?? {\n workspaces: { items: [], total: 0 },\n projects: { items: [], total: 0 },\n recentActivities: [],\n upcomingEvents: [],\n tags: { items: [], total: 0 },\n groups: { items: [], totalCount: 0 },\n workflowStats: null,\n storageUsage: null,\n }),\n // Override with real workspace/org data from the global gateway\n workspaces: globalData?.workspaces ?? { items: [], total: 0 },\n // Override with real project data from the separate projects query\n // (fetched independently to avoid being poisoned by other subgraph errors)\n projects: projectsData ?? { items: [], total: 0 },\n // VibeControls-only data; undefined for other products\n recentVibes: vibecontrolsData?.recentVibes,\n activeSessions: vibecontrolsData?.activeSessions,\n agentFleet: vibecontrolsData?.agentFleet ?? null,\n };\n }, [workspaceData, globalData, projectsData, vibecontrolsData]);\n\n // ─── Widget Configuration ─────────────────────────────────────────────────\n const savedPrefs = globalData?.dashboardPreferences;\n const widgets = useMemo(\n () => getEffectiveWidgets(savedPrefs?.widgets ?? null, productId),\n [savedPrefs, productId]\n );\n\n // ─── Handlers ─────────────────────────────────────────────────────────────\n const handleRefresh = useCallback(() => {\n refetchWs();\n refetchGlobal();\n refetchProjects();\n if (isVibecontrols) refetchVibecontrols();\n }, [refetchWs, refetchGlobal, refetchProjects, refetchVibecontrols, isVibecontrols]);\n\n const handleSaveWidgets = useCallback(\n async (newWidgets: WidgetConfig[]) => {\n await updatePrefs.mutateAsync(newWidgets);\n },\n [updatePrefs]\n );\n\n // ─── Error Banner ─────────────────────────────────────────────────────────\n const hasError = wsError || globalError;\n\n return (\n <div className=\"min-h-[calc(100vh-8rem)] p-4 md:p-6 bg-bg-canvas\" data-tour=\"main-content\">\n {/* Header */}\n <div className=\"flex flex-wrap items-center justify-between gap-4 mb-6\">\n <div>\n <h1 className=\"text-xl font-bold text-text-primary\">\n {tr('dashboard.title', 'Dashboard')}\n </h1>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n {tr('dashboard.subtitle', 'Your workspace overview at a glance')}\n </p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\" data-tour=\"quick-actions\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleRefresh}\n disabled={isLoading}\n className=\"text-xs\"\n >\n {isLoading ? (\n <Loader2 className=\"size-3.5 sm:mr-1.5 animate-spin\" />\n ) : (\n <RefreshCw className=\"size-3.5 sm:mr-1.5\" />\n )}\n <span className=\"hidden sm:inline\">{tr('dashboard.refresh', 'Refresh')}</span>\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setCustomizerOpen(true)}\n className=\"text-xs\"\n >\n <Settings2 className=\"size-3.5 sm:mr-1.5\" />\n <span className=\"hidden sm:inline\">{tr('dashboard.customize', 'Customize')}</span>\n </Button>\n </div>\n </div>\n\n {/* Error Banner */}\n {hasError && (\n <div className=\"mb-4 p-3 bg-status-error-bg/10 border border-status-error-border/20 rounded-lg flex items-center gap-2\">\n <AlertCircle className=\"size-4 text-status-error-text shrink-0\" />\n <p className=\"text-sm text-status-error-text\">\n {tr('dashboard.error.partialData', 'Some data may be unavailable.')}{' '}\n {wsError ? tr('dashboard.error.workspaceDown', 'Workspace services may be down.') : ''}{' '}\n {globalError ? tr('dashboard.error.globalDown', 'Global services may be down.') : ''}{' '}\n <button\n type=\"button\"\n className=\"underline font-medium hover:text-status-error-text/80\"\n onClick={handleRefresh}\n >\n {tr('dashboard.error.tryRefreshing', 'Try refreshing')}\n </button>\n </p>\n </div>\n )}\n\n {/* Widget Grid */}\n {/* Merge workspace/org data from the global query into workspaceData\n so widgets that read workspaceData.workspaces see the real data\n from the global tenant service. */}\n <DashboardGrid\n widgets={widgets}\n workspaceData={mergedWorkspaceData}\n globalData={globalData ?? null}\n isLoading={isLoading}\n navigate={navigate}\n productId={productId}\n />\n\n {/* Customizer */}\n <DashboardCustomizer\n open={customizerOpen}\n onOpenChange={setCustomizerOpen}\n widgets={widgets}\n onSave={handleSaveWidgets}\n isSaving={updatePrefs.isPending}\n productId={productId}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../src/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["/**\n * DashboardPage — Comprehensive workspace dashboard.\n *\n * This is the main dashboard component exported from microfe-workspaces.\n * It fetches data from both workspace and global gateways, manages widget\n * layout preferences, and renders a customizable grid of widgets.\n *\n * Props:\n * - navigate: Shell navigation function\n * - authToken: Current user's auth token\n * - currentUser: Basic user info from shell\n *\n * Data Flow:\n * 1. Two parallel queries: workspace gateway + global gateway\n * 2. Global query returns user preferences (dashboard layout)\n * 3. Widget layout falls back to defaults if no preferences saved\n * 4. Data is passed as props to individual widgets\n */\nimport { useState, useMemo, useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Button, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { Settings2, RefreshCw, Loader2, AlertCircle } from 'lucide-react';\nimport {\n useWorkspaceDashboardData,\n useGlobalDashboardData,\n useProjectsDashboardData,\n useVibecontrolsDashboardData,\n} from './hooks/useDashboardData';\nimport { useUpdateDashboardPreferences } from './hooks/useDashboardPreferences';\nimport { DashboardGrid } from './DashboardGrid';\nimport { DashboardCustomizer } from './DashboardCustomizer';\nimport { getEffectiveWidgets } from './config';\nimport type { WidgetConfig } from './types';\nimport { useWorkspacesPageView } from '../../hooks/useWorkspacesPageView';\n\ninterface DashboardPageProps {\n navigate: (path: string) => void;\n authToken?: string | null;\n currentUser?: {\n id: string;\n email: string;\n firstName?: string;\n lastName?: string;\n name?: string;\n } | null;\n /**\n * Host product identifier ('workspaces', 'vibecontrols', etc.). Drives\n * which widgets appear in the registry + default layout. Defaults to\n * 'workspaces' for legacy callers.\n */\n productId?: string;\n}\n\nexport function DashboardPage({\n navigate,\n authToken,\n currentUser: _currentUser,\n productId = 'workspaces',\n}: DashboardPageProps) {\n useWorkspacesPageView('workspaces.dashboard');\n const { t } = useI18n();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n const [customizerOpen, setCustomizerOpen] = useState(false);\n\n // ─── Data Fetching ────────────────────────────────────────────────────────\n const {\n data: workspaceData,\n isLoading: wsLoading,\n error: wsError,\n refetch: refetchWs,\n } = useWorkspaceDashboardData(authToken);\n\n const {\n data: globalData,\n isLoading: globalLoading,\n error: globalError,\n refetch: refetchGlobal,\n } = useGlobalDashboardData(authToken);\n\n const {\n data: projectsData,\n isLoading: projectsLoading,\n refetch: refetchProjects,\n } = useProjectsDashboardData(authToken);\n\n const isVibecontrols = productId === 'vibecontrols';\n const {\n data: vibecontrolsData,\n isLoading: vibecontrolsLoading,\n refetch: refetchVibecontrols,\n } = useVibecontrolsDashboardData(authToken, isVibecontrols);\n\n const updatePrefs = useUpdateDashboardPreferences(authToken);\n\n const isLoading = wsLoading || globalLoading || projectsLoading || vibecontrolsLoading;\n\n // ─── Merge data ───────────────────────────────────────────────────────────\n // Workspace/org stats come from the global tenant service (globalData),\n // while workspace-scoped features (activity, calendar, tags, etc.) come\n // from the workspace gateway (workspaceData). Merge them so widgets\n // reading workspaceData.workspaces see the real tenant data.\n const mergedWorkspaceData = useMemo(() => {\n if (!workspaceData && !globalData && !projectsData && !vibecontrolsData) return null;\n return {\n ...(workspaceData ?? {\n workspaces: { items: [], total: 0 },\n projects: { items: [], total: 0 },\n recentActivities: [],\n upcomingEvents: [],\n tags: { items: [], total: 0 },\n groups: { items: [], totalCount: 0 },\n workflowStats: null,\n storageUsage: null,\n }),\n // Override with real workspace/org data from the global gateway\n workspaces: globalData?.workspaces ?? { items: [], total: 0 },\n // Override with real project data from the separate projects query\n // (fetched independently to avoid being poisoned by other subgraph errors)\n projects: projectsData ?? { items: [], total: 0 },\n // VibeControls-only data; undefined for other products\n recentVibes: vibecontrolsData?.recentVibes,\n activeSessions: vibecontrolsData?.activeSessions,\n agentFleet: vibecontrolsData?.agentFleet ?? null,\n };\n }, [workspaceData, globalData, projectsData, vibecontrolsData]);\n\n // ─── Widget Configuration ─────────────────────────────────────────────────\n const savedPrefs = globalData?.dashboardPreferences;\n const widgets = useMemo(\n () => getEffectiveWidgets(savedPrefs?.widgets ?? null, productId),\n [savedPrefs, productId]\n );\n\n // ─── Handlers ─────────────────────────────────────────────────────────────\n const handleRefresh = useCallback(() => {\n refetchWs();\n refetchGlobal();\n refetchProjects();\n if (isVibecontrols) refetchVibecontrols();\n }, [refetchWs, refetchGlobal, refetchProjects, refetchVibecontrols, isVibecontrols]);\n\n const handleSaveWidgets = useCallback(\n async (newWidgets: WidgetConfig[]) => {\n await updatePrefs.mutateAsync(newWidgets);\n },\n [updatePrefs]\n );\n\n // ─── Error Banner ─────────────────────────────────────────────────────────\n const hasError = wsError || globalError;\n\n return (\n <div className=\"min-h-[calc(100vh-8rem)] p-4 md:p-6 bg-bg-canvas\" data-tour=\"main-content\">\n {/* Header */}\n <div className=\"flex flex-wrap items-center justify-between gap-4 mb-6\">\n <div>\n <h1 className=\"text-xl font-bold text-text-primary\">\n {tr('dashboard.title', 'Dashboard')}\n </h1>\n <p className=\"text-sm text-text-secondary mt-0.5\">\n {tr('dashboard.subtitle', 'Your workspace overview at a glance')}\n </p>\n </div>\n <div className=\"flex flex-wrap items-center gap-2\" data-tour=\"quick-actions\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleRefresh}\n disabled={isLoading}\n className=\"text-xs\"\n >\n {isLoading ? (\n <Loader2 className=\"size-3.5 sm:mr-1.5 animate-spin\" />\n ) : (\n <RefreshCw className=\"size-3.5 sm:mr-1.5\" />\n )}\n <span className=\"hidden sm:inline\">{tr('dashboard.refresh', 'Refresh')}</span>\n </Button>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setCustomizerOpen(true)}\n className=\"text-xs\"\n >\n <Settings2 className=\"size-3.5 sm:mr-1.5\" />\n <span className=\"hidden sm:inline\">{tr('dashboard.customize', 'Customize')}</span>\n </Button>\n </div>\n </div>\n\n <PagePurpose className=\"mb-6 -mt-2\">\n {tr(\n 'dashboard.purpose',\n 'This is your home base — a single glance across everything that matters: your workspaces and projects, recent activity, upcoming events and live status. Use Customize to choose which cards appear and how they are arranged, and click any card to dive into the full view.'\n )}\n </PagePurpose>\n\n {/* Error Banner */}\n {hasError && (\n <div className=\"mb-4 p-3 bg-status-error-bg/10 border border-status-error-border/20 rounded-lg flex items-center gap-2\">\n <AlertCircle className=\"size-4 text-status-error-text shrink-0\" />\n <p className=\"text-sm text-status-error-text\">\n {tr('dashboard.error.partialData', 'Some data may be unavailable.')}{' '}\n {wsError ? tr('dashboard.error.workspaceDown', 'Workspace services may be down.') : ''}{' '}\n {globalError ? tr('dashboard.error.globalDown', 'Global services may be down.') : ''}{' '}\n <button\n type=\"button\"\n className=\"underline font-medium hover:text-status-error-text/80\"\n onClick={handleRefresh}\n >\n {tr('dashboard.error.tryRefreshing', 'Try refreshing')}\n </button>\n </p>\n </div>\n )}\n\n {/* Widget Grid */}\n {/* Merge workspace/org data from the global query into workspaceData\n so widgets that read workspaceData.workspaces see the real data\n from the global tenant service. */}\n <DashboardGrid\n widgets={widgets}\n workspaceData={mergedWorkspaceData}\n globalData={globalData ?? null}\n isLoading={isLoading}\n navigate={navigate}\n productId={productId}\n />\n\n {/* Customizer */}\n <DashboardCustomizer\n open={customizerOpen}\n onOpenChange={setCustomizerOpen}\n widgets={widgets}\n onSave={handleSaveWidgets}\n isSaving={updatePrefs.isPending}\n productId={productId}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,35 +1,34 @@
1
1
  import { WidgetWrapper as e } from "../WidgetWrapper.js";
2
2
  import { ArrowRight as t, Users as n } from "lucide-react";
3
3
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
- import { Button as a } from "@burdenoff/fe-libs/ui";
4
+ import { Button as a, IllustratedEmptyState as o } from "@burdenoff/fe-libs/ui";
5
5
  //#region src/pages/dashboard/widgets/GroupsWidget.tsx
6
- function o({ workspaceData: o, isLoading: s, navigate: c }) {
7
- let l = o?.groups.items ?? [], u = o?.groups.totalCount ?? 0;
6
+ function s({ workspaceData: s, isLoading: c, navigate: l }) {
7
+ let u = s?.groups.items ?? [], d = s?.groups.totalCount ?? 0;
8
8
  return /* @__PURE__ */ r(e, {
9
9
  title: "Groups",
10
10
  icon: /* @__PURE__ */ r(n, { className: "size-4" }),
11
11
  size: "small",
12
- isLoading: s,
13
- unavailable: !o,
12
+ isLoading: c,
13
+ unavailable: !s,
14
14
  headerAction: /* @__PURE__ */ r(a, {
15
15
  variant: "ghost",
16
16
  size: "sm",
17
17
  className: "text-xs",
18
- onClick: () => c("/groups"),
18
+ onClick: () => l("/groups"),
19
19
  children: /* @__PURE__ */ r(t, { className: "size-3" })
20
20
  }),
21
- children: l.length === 0 ? /* @__PURE__ */ r("div", {
22
- className: "text-center py-3",
23
- children: /* @__PURE__ */ r("p", {
24
- className: "text-xs text-text-secondary",
25
- children: "No groups yet"
26
- })
21
+ children: u.length === 0 ? /* @__PURE__ */ r(o, {
22
+ illustration: "empty-people",
23
+ title: "No groups yet",
24
+ description: "Groups bundle members together so you can manage and mention them as one.",
25
+ className: "py-4"
27
26
  }) : /* @__PURE__ */ i("div", {
28
27
  className: "space-y-1.5",
29
- children: [l.slice(0, 4).map((e) => /* @__PURE__ */ i("button", {
28
+ children: [u.slice(0, 4).map((e) => /* @__PURE__ */ i("button", {
30
29
  type: "button",
31
30
  className: "w-full flex items-center gap-2 p-1.5 rounded hover:bg-accent/5 cursor-pointer transition-colors text-left",
32
- onClick: () => c("/groups"),
31
+ onClick: () => l("/groups"),
33
32
  children: [/* @__PURE__ */ r("div", {
34
33
  className: "size-7 rounded-full bg-accent-purple-subtle text-accent-purple flex items-center justify-center text-xs font-bold shrink-0",
35
34
  children: e.name.charAt(0).toUpperCase()
@@ -43,11 +42,11 @@ function o({ workspaceData: o, isLoading: s, navigate: c }) {
43
42
  children: e.description
44
43
  })]
45
44
  })]
46
- }, e.id)), u > 4 && /* @__PURE__ */ i("p", {
45
+ }, e.id)), d > 4 && /* @__PURE__ */ i("p", {
47
46
  className: "text-[11px] text-text-secondary text-center",
48
47
  children: [
49
48
  "+",
50
- u - 4,
49
+ d - 4,
51
50
  " more groups"
52
51
  ]
53
52
  })]
@@ -55,6 +54,6 @@ function o({ workspaceData: o, isLoading: s, navigate: c }) {
55
54
  });
56
55
  }
57
56
  //#endregion
58
- export { o as GroupsWidget };
57
+ export { s as GroupsWidget };
59
58
 
60
59
  //# sourceMappingURL=GroupsWidget.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"GroupsWidget.js","names":[],"sources":["../../../../src/pages/dashboard/widgets/GroupsWidget.tsx"],"sourcesContent":["import { Users, ArrowRight } from 'lucide-react';\nimport { Button } from '@burdenoff/fe-libs/ui';\nimport { WidgetWrapper } from '../WidgetWrapper';\nimport type { WidgetProps } from '../types';\n\nexport function GroupsWidget({ workspaceData, isLoading, navigate }: WidgetProps) {\n const groups = workspaceData?.groups.items ?? [];\n const total = workspaceData?.groups.totalCount ?? 0;\n\n return (\n <WidgetWrapper\n title=\"Groups\"\n icon={<Users className=\"size-4\" />}\n size=\"small\"\n isLoading={isLoading}\n unavailable={!workspaceData}\n headerAction={\n <Button variant=\"ghost\" size=\"sm\" className=\"text-xs\" onClick={() => navigate('/groups')}>\n <ArrowRight className=\"size-3\" />\n </Button>\n }\n >\n {groups.length === 0 ? (\n <div className=\"text-center py-3\">\n <p className=\"text-xs text-text-secondary\">No groups yet</p>\n </div>\n ) : (\n <div className=\"space-y-1.5\">\n {groups.slice(0, 4).map((group) => (\n <button\n key={group.id}\n type=\"button\"\n className=\"w-full flex items-center gap-2 p-1.5 rounded hover:bg-accent/5 cursor-pointer transition-colors text-left\"\n onClick={() => navigate('/groups')}\n >\n <div className=\"size-7 rounded-full bg-accent-purple-subtle text-accent-purple flex items-center justify-center text-xs font-bold shrink-0\">\n {group.name.charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{group.name}</p>\n {group.description && (\n <p className=\"text-[11px] text-text-secondary truncate\">{group.description}</p>\n )}\n </div>\n </button>\n ))}\n {total > 4 && (\n <p className=\"text-[11px] text-text-secondary text-center\">+{total - 4} more groups</p>\n )}\n </div>\n )}\n </WidgetWrapper>\n );\n}\n"],"mappings":";;;;;AAKA,SAAgB,EAAa,EAAE,kBAAe,cAAW,eAAyB;CAChF,IAAM,IAAS,GAAe,OAAO,SAAS,EAAE,EAC1C,IAAQ,GAAe,OAAO,cAAc;AAElD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,MAAM,kBAAC,GAAD,EAAO,WAAU,UAAW,CAAA;EAClC,MAAK;EACM;EACX,aAAa,CAAC;EACd,cACE,kBAAC,GAAD;GAAQ,SAAQ;GAAQ,MAAK;GAAK,WAAU;GAAU,eAAe,EAAS,UAAU;aACtF,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;GAC1B,CAAA;YAGV,EAAO,WAAW,IACjB,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAAiB,CAAA;GACxD,CAAA,GAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAO,MAAM,GAAG,EAAE,CAAC,KAAK,MACvB,kBAAC,UAAD;IAEE,MAAK;IACL,WAAU;IACV,eAAe,EAAS,UAAU;cAJpC,CAME,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAM,KAAK,OAAO,EAAE,CAAC,aAAa;KAC/B,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAkD,EAAM;MAAS,CAAA,EAC7E,EAAM,eACL,kBAAC,KAAD;MAAG,WAAU;gBAA4C,EAAM;MAAgB,CAAA,CAE7E;OACC;MAdF,EAAM,GAcJ,CACT,EACD,IAAQ,KACP,kBAAC,KAAD;IAAG,WAAU;cAAb;KAA2D;KAAE,IAAQ;KAAE;KAAgB;MAErF;;EAEM,CAAA"}
1
+ {"version":3,"file":"GroupsWidget.js","names":[],"sources":["../../../../src/pages/dashboard/widgets/GroupsWidget.tsx"],"sourcesContent":["import { Users, ArrowRight } from 'lucide-react';\nimport { Button, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { WidgetWrapper } from '../WidgetWrapper';\nimport type { WidgetProps } from '../types';\n\nexport function GroupsWidget({ workspaceData, isLoading, navigate }: WidgetProps) {\n const groups = workspaceData?.groups.items ?? [];\n const total = workspaceData?.groups.totalCount ?? 0;\n\n return (\n <WidgetWrapper\n title=\"Groups\"\n icon={<Users className=\"size-4\" />}\n size=\"small\"\n isLoading={isLoading}\n unavailable={!workspaceData}\n headerAction={\n <Button variant=\"ghost\" size=\"sm\" className=\"text-xs\" onClick={() => navigate('/groups')}>\n <ArrowRight className=\"size-3\" />\n </Button>\n }\n >\n {groups.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title=\"No groups yet\"\n description=\"Groups bundle members together so you can manage and mention them as one.\"\n className=\"py-4\"\n />\n ) : (\n <div className=\"space-y-1.5\">\n {groups.slice(0, 4).map((group) => (\n <button\n key={group.id}\n type=\"button\"\n className=\"w-full flex items-center gap-2 p-1.5 rounded hover:bg-accent/5 cursor-pointer transition-colors text-left\"\n onClick={() => navigate('/groups')}\n >\n <div className=\"size-7 rounded-full bg-accent-purple-subtle text-accent-purple flex items-center justify-center text-xs font-bold shrink-0\">\n {group.name.charAt(0).toUpperCase()}\n </div>\n <div className=\"min-w-0\">\n <p className=\"text-sm font-medium text-text-primary truncate\">{group.name}</p>\n {group.description && (\n <p className=\"text-[11px] text-text-secondary truncate\">{group.description}</p>\n )}\n </div>\n </button>\n ))}\n {total > 4 && (\n <p className=\"text-[11px] text-text-secondary text-center\">+{total - 4} more groups</p>\n )}\n </div>\n )}\n </WidgetWrapper>\n );\n}\n"],"mappings":";;;;;AAKA,SAAgB,EAAa,EAAE,kBAAe,cAAW,eAAyB;CAChF,IAAM,IAAS,GAAe,OAAO,SAAS,EAAE,EAC1C,IAAQ,GAAe,OAAO,cAAc;AAElD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,MAAM,kBAAC,GAAD,EAAO,WAAU,UAAW,CAAA;EAClC,MAAK;EACM;EACX,aAAa,CAAC;EACd,cACE,kBAAC,GAAD;GAAQ,SAAQ;GAAQ,MAAK;GAAK,WAAU;GAAU,eAAe,EAAS,UAAU;aACtF,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;GAC1B,CAAA;YAGV,EAAO,WAAW,IACjB,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,WAAU;GACV,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aAAf,CACG,EAAO,MAAM,GAAG,EAAE,CAAC,KAAK,MACvB,kBAAC,UAAD;IAEE,MAAK;IACL,WAAU;IACV,eAAe,EAAS,UAAU;cAJpC,CAME,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAM,KAAK,OAAO,EAAE,CAAC,aAAa;KAC/B,CAAA,EACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBAAkD,EAAM;MAAS,CAAA,EAC7E,EAAM,eACL,kBAAC,KAAD;MAAG,WAAU;gBAA4C,EAAM;MAAgB,CAAA,CAE7E;OACC;MAdF,EAAM,GAcJ,CACT,EACD,IAAQ,KACP,kBAAC,KAAD;IAAG,WAAU;cAAb;KAA2D;KAAE,IAAQ;KAAE;KAAgB;MAErF;;EAEM,CAAA"}
@@ -1,9 +1,9 @@
1
1
  import { WidgetWrapper as e } from "../WidgetWrapper.js";
2
2
  import { ArrowRight as t, Tags as n } from "lucide-react";
3
3
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
- import { Badge as a, Button as o } from "@burdenoff/fe-libs/ui";
4
+ import { Badge as a, Button as o, IllustratedEmptyState as s } from "@burdenoff/fe-libs/ui";
5
5
  //#region src/pages/dashboard/widgets/TagCloudWidget.tsx
6
- var s = [
6
+ var c = [
7
7
  "bg-status-info-bg-subtle text-status-info-text border-border-default",
8
8
  "bg-status-success-bg-subtle text-status-success-text border-border-default",
9
9
  "bg-accent-purple-subtle text-accent-purple border-border-default",
@@ -13,42 +13,41 @@ var s = [
13
13
  "bg-accent-orange-subtle text-accent-orange border-border-default",
14
14
  "bg-accent-rose-subtle text-accent-rose border-border-default"
15
15
  ];
16
- function c({ workspaceData: c, isLoading: l, navigate: u }) {
17
- let d = c?.tags.items ?? [], f = c?.tags.total ?? 0;
16
+ function l({ workspaceData: l, isLoading: u, navigate: d }) {
17
+ let f = l?.tags.items ?? [], p = l?.tags.total ?? 0;
18
18
  return /* @__PURE__ */ r(e, {
19
19
  title: "Tags",
20
20
  icon: /* @__PURE__ */ r(n, { className: "size-4" }),
21
21
  size: "small",
22
- isLoading: l,
23
- unavailable: !c,
22
+ isLoading: u,
23
+ unavailable: !l,
24
24
  headerAction: /* @__PURE__ */ r(o, {
25
25
  variant: "ghost",
26
26
  size: "sm",
27
27
  className: "text-xs",
28
- onClick: () => u("/tags"),
28
+ onClick: () => d("/tags"),
29
29
  children: /* @__PURE__ */ r(t, { className: "size-3" })
30
30
  }),
31
- children: d.length === 0 ? /* @__PURE__ */ r("div", {
32
- className: "text-center py-3",
33
- children: /* @__PURE__ */ r("p", {
34
- className: "text-xs text-text-secondary",
35
- children: "No tags created yet"
36
- })
31
+ children: f.length === 0 ? /* @__PURE__ */ r(s, {
32
+ illustration: "empty-generic",
33
+ title: "No tags created yet",
34
+ description: "Tags help you label and filter projects and content across the workspace.",
35
+ className: "py-4"
37
36
  }) : /* @__PURE__ */ i("div", {
38
37
  className: "space-y-2",
39
38
  children: [/* @__PURE__ */ r("div", {
40
39
  className: "flex flex-wrap gap-1.5",
41
- children: d.slice(0, 12).map((e, t) => /* @__PURE__ */ r(a, {
40
+ children: f.slice(0, 12).map((e, t) => /* @__PURE__ */ r(a, {
42
41
  variant: "outline",
43
- className: `text-[11px] cursor-pointer hover:opacity-80 transition-opacity ${s[t % s.length]}`,
44
- onClick: () => u("/tags"),
42
+ className: `text-[11px] cursor-pointer hover:opacity-80 transition-opacity ${c[t % c.length]}`,
43
+ onClick: () => d("/tags"),
45
44
  children: e.label
46
45
  }, e.id))
47
- }), f > 12 && /* @__PURE__ */ i("p", {
46
+ }), p > 12 && /* @__PURE__ */ i("p", {
48
47
  className: "text-[11px] text-text-secondary text-center",
49
48
  children: [
50
49
  "+",
51
- f - 12,
50
+ p - 12,
52
51
  " more tags"
53
52
  ]
54
53
  })]
@@ -56,6 +55,6 @@ function c({ workspaceData: c, isLoading: l, navigate: u }) {
56
55
  });
57
56
  }
58
57
  //#endregion
59
- export { c as TagCloudWidget };
58
+ export { l as TagCloudWidget };
60
59
 
61
60
  //# sourceMappingURL=TagCloudWidget.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TagCloudWidget.js","names":[],"sources":["../../../../src/pages/dashboard/widgets/TagCloudWidget.tsx"],"sourcesContent":["import { Tags, ArrowRight } from 'lucide-react';\nimport { Badge, Button } from '@burdenoff/fe-libs/ui';\nimport { WidgetWrapper } from '../WidgetWrapper';\nimport type { WidgetProps } from '../types';\n\nconst tagColors = [\n 'bg-status-info-bg-subtle text-status-info-text border-border-default',\n 'bg-status-success-bg-subtle text-status-success-text border-border-default',\n 'bg-accent-purple-subtle text-accent-purple border-border-default',\n 'bg-status-warning-bg-subtle text-status-warning-text border-border-default',\n 'bg-accent-pink-subtle text-accent-pink border-border-default',\n 'bg-accent-cyan-subtle text-accent-cyan border-border-default',\n 'bg-accent-orange-subtle text-accent-orange border-border-default',\n 'bg-accent-rose-subtle text-accent-rose border-border-default',\n];\n\nexport function TagCloudWidget({ workspaceData, isLoading, navigate }: WidgetProps) {\n const tags = workspaceData?.tags.items ?? [];\n const total = workspaceData?.tags.total ?? 0;\n\n return (\n <WidgetWrapper\n title=\"Tags\"\n icon={<Tags className=\"size-4\" />}\n size=\"small\"\n isLoading={isLoading}\n unavailable={!workspaceData}\n headerAction={\n <Button variant=\"ghost\" size=\"sm\" className=\"text-xs\" onClick={() => navigate('/tags')}>\n <ArrowRight className=\"size-3\" />\n </Button>\n }\n >\n {tags.length === 0 ? (\n <div className=\"text-center py-3\">\n <p className=\"text-xs text-text-secondary\">No tags created yet</p>\n </div>\n ) : (\n <div className=\"space-y-2\">\n <div className=\"flex flex-wrap gap-1.5\">\n {tags.slice(0, 12).map((tag, idx) => (\n <Badge\n key={tag.id}\n variant=\"outline\"\n className={`text-[11px] cursor-pointer hover:opacity-80 transition-opacity ${tagColors[idx % tagColors.length]}`}\n onClick={() => navigate('/tags')}\n >\n {tag.label}\n </Badge>\n ))}\n </div>\n {total > 12 && (\n <p className=\"text-[11px] text-text-secondary text-center\">+{total - 12} more tags</p>\n )}\n </div>\n )}\n </WidgetWrapper>\n );\n}\n"],"mappings":";;;;;AAKA,IAAM,IAAY;CAChB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAgB,EAAe,EAAE,kBAAe,cAAW,eAAyB;CAClF,IAAM,IAAO,GAAe,KAAK,SAAS,EAAE,EACtC,IAAQ,GAAe,KAAK,SAAS;AAE3C,QACE,kBAAC,GAAD;EACE,OAAM;EACN,MAAM,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA;EACjC,MAAK;EACM;EACX,aAAa,CAAC;EACd,cACE,kBAAC,GAAD;GAAQ,SAAQ;GAAQ,MAAK;GAAK,WAAU;GAAU,eAAe,EAAS,QAAQ;aACpF,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;GAC1B,CAAA;YAGV,EAAK,WAAW,IACf,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAAuB,CAAA;GAC9D,CAAA,GAEN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAK,MAAM,GAAG,GAAG,CAAC,KAAK,GAAK,MAC3B,kBAAC,GAAD;KAEE,SAAQ;KACR,WAAW,kEAAkE,EAAU,IAAM,EAAU;KACvG,eAAe,EAAS,QAAQ;eAE/B,EAAI;KACC,EAND,EAAI,GAMH,CACR;IACE,CAAA,EACL,IAAQ,MACP,kBAAC,KAAD;IAAG,WAAU;cAAb;KAA2D;KAAE,IAAQ;KAAG;KAAc;MAEpF;;EAEM,CAAA"}
1
+ {"version":3,"file":"TagCloudWidget.js","names":[],"sources":["../../../../src/pages/dashboard/widgets/TagCloudWidget.tsx"],"sourcesContent":["import { Tags, ArrowRight } from 'lucide-react';\nimport { Badge, Button, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { WidgetWrapper } from '../WidgetWrapper';\nimport type { WidgetProps } from '../types';\n\nconst tagColors = [\n 'bg-status-info-bg-subtle text-status-info-text border-border-default',\n 'bg-status-success-bg-subtle text-status-success-text border-border-default',\n 'bg-accent-purple-subtle text-accent-purple border-border-default',\n 'bg-status-warning-bg-subtle text-status-warning-text border-border-default',\n 'bg-accent-pink-subtle text-accent-pink border-border-default',\n 'bg-accent-cyan-subtle text-accent-cyan border-border-default',\n 'bg-accent-orange-subtle text-accent-orange border-border-default',\n 'bg-accent-rose-subtle text-accent-rose border-border-default',\n];\n\nexport function TagCloudWidget({ workspaceData, isLoading, navigate }: WidgetProps) {\n const tags = workspaceData?.tags.items ?? [];\n const total = workspaceData?.tags.total ?? 0;\n\n return (\n <WidgetWrapper\n title=\"Tags\"\n icon={<Tags className=\"size-4\" />}\n size=\"small\"\n isLoading={isLoading}\n unavailable={!workspaceData}\n headerAction={\n <Button variant=\"ghost\" size=\"sm\" className=\"text-xs\" onClick={() => navigate('/tags')}>\n <ArrowRight className=\"size-3\" />\n </Button>\n }\n >\n {tags.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No tags created yet\"\n description=\"Tags help you label and filter projects and content across the workspace.\"\n className=\"py-4\"\n />\n ) : (\n <div className=\"space-y-2\">\n <div className=\"flex flex-wrap gap-1.5\">\n {tags.slice(0, 12).map((tag, idx) => (\n <Badge\n key={tag.id}\n variant=\"outline\"\n className={`text-[11px] cursor-pointer hover:opacity-80 transition-opacity ${tagColors[idx % tagColors.length]}`}\n onClick={() => navigate('/tags')}\n >\n {tag.label}\n </Badge>\n ))}\n </div>\n {total > 12 && (\n <p className=\"text-[11px] text-text-secondary text-center\">+{total - 12} more tags</p>\n )}\n </div>\n )}\n </WidgetWrapper>\n );\n}\n"],"mappings":";;;;;AAKA,IAAM,IAAY;CAChB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,SAAgB,EAAe,EAAE,kBAAe,cAAW,eAAyB;CAClF,IAAM,IAAO,GAAe,KAAK,SAAS,EAAE,EACtC,IAAQ,GAAe,KAAK,SAAS;AAE3C,QACE,kBAAC,GAAD;EACE,OAAM;EACN,MAAM,kBAAC,GAAD,EAAM,WAAU,UAAW,CAAA;EACjC,MAAK;EACM;EACX,aAAa,CAAC;EACd,cACE,kBAAC,GAAD;GAAQ,SAAQ;GAAQ,MAAK;GAAK,WAAU;GAAU,eAAe,EAAS,QAAQ;aACpF,kBAAC,GAAD,EAAY,WAAU,UAAW,CAAA;GAC1B,CAAA;YAGV,EAAK,WAAW,IACf,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,WAAU;GACV,CAAA,GAEF,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAK,MAAM,GAAG,GAAG,CAAC,KAAK,GAAK,MAC3B,kBAAC,GAAD;KAEE,SAAQ;KACR,WAAW,kEAAkE,EAAU,IAAM,EAAU;KACvG,eAAe,EAAS,QAAQ;eAE/B,EAAI;KACC,EAND,EAAI,GAMH,CACR;IACE,CAAA,EACL,IAAQ,MACP,kBAAC,KAAD;IAAG,WAAU;cAAb;KAA2D;KAAE,IAAQ;KAAG;KAAc;MAEpF;;EAEM,CAAA"}
@@ -1,9 +1,9 @@
1
1
  import { WidgetWrapper as e } from "../WidgetWrapper.js";
2
2
  import { ArrowRight as t, CheckCircle2 as n, GitBranch as r, Pause as i, Play as a, XCircle as o } from "lucide-react";
3
3
  import { jsx as s, jsxs as c } from "react/jsx-runtime";
4
- import { Badge as l, Button as u } from "@burdenoff/fe-libs/ui";
4
+ import { Badge as l, Button as u, IllustratedEmptyState as d } from "@burdenoff/fe-libs/ui";
5
5
  //#region src/pages/dashboard/widgets/WorkflowStatsWidget.tsx
6
- var d = {
6
+ var f = {
7
7
  RUNNING: {
8
8
  icon: a,
9
9
  color: "text-accent-blue"
@@ -21,7 +21,7 @@ var d = {
21
21
  color: "text-status-warning-text"
22
22
  }
23
23
  };
24
- function f({ workspaceData: n, isLoading: i, navigate: a }) {
24
+ function p({ workspaceData: n, isLoading: i, navigate: a }) {
25
25
  let o = n?.workflowStats;
26
26
  return /* @__PURE__ */ s(e, {
27
27
  title: "Workflows",
@@ -65,7 +65,7 @@ function f({ workspaceData: n, isLoading: i, navigate: a }) {
65
65
  className: "text-xs font-medium text-text-secondary uppercase tracking-wider",
66
66
  children: "Recent Runs"
67
67
  }), o.recentRuns.slice(0, 3).map((e) => {
68
- let t = d[e.status] || d.RUNNING, n = t.icon;
68
+ let t = f[e.status] || f.RUNNING, n = t.icon;
69
69
  return /* @__PURE__ */ c("div", {
70
70
  className: "flex items-center justify-between p-1.5 rounded hover:bg-accent/5 transition-colors",
71
71
  children: [/* @__PURE__ */ c("div", {
@@ -82,16 +82,15 @@ function f({ workspaceData: n, isLoading: i, navigate: a }) {
82
82
  }, e.id);
83
83
  })]
84
84
  })]
85
- }) : /* @__PURE__ */ s("div", {
86
- className: "text-center py-4",
87
- children: /* @__PURE__ */ s("p", {
88
- className: "text-sm text-text-secondary",
89
- children: "No workflow data available"
90
- })
85
+ }) : /* @__PURE__ */ s(d, {
86
+ illustration: "empty-data",
87
+ title: "No workflow data available",
88
+ description: "Once you run automations, their status and counts will appear here.",
89
+ className: "py-4"
91
90
  })
92
91
  });
93
92
  }
94
93
  //#endregion
95
- export { f as WorkflowStatsWidget };
94
+ export { p as WorkflowStatsWidget };
96
95
 
97
96
  //# sourceMappingURL=WorkflowStatsWidget.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WorkflowStatsWidget.js","names":[],"sources":["../../../../src/pages/dashboard/widgets/WorkflowStatsWidget.tsx"],"sourcesContent":["import { GitBranch, ArrowRight, Play, Pause, CheckCircle2, XCircle } from 'lucide-react';\nimport { Badge, Button } from '@burdenoff/fe-libs/ui';\nimport { WidgetWrapper } from '../WidgetWrapper';\nimport type { WidgetProps } from '../types';\n\nconst runStatusIcons: Record<string, { icon: typeof Play; color: string }> = {\n RUNNING: { icon: Play, color: 'text-accent-blue' },\n COMPLETED: { icon: CheckCircle2, color: 'text-status-success-text' },\n FAILED: { icon: XCircle, color: 'text-status-error-text' },\n PAUSED: { icon: Pause, color: 'text-status-warning-text' },\n};\n\nexport function WorkflowStatsWidget({ workspaceData, isLoading, navigate }: WidgetProps) {\n const stats = workspaceData?.workflowStats;\n\n return (\n <WidgetWrapper\n title=\"Workflows\"\n icon={<GitBranch className=\"size-4\" />}\n size=\"medium\"\n isLoading={isLoading}\n unavailable={!workspaceData}\n headerAction={\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-xs\"\n onClick={() => navigate('/workflows')}\n >\n View all <ArrowRight className=\"ml-1 size-3\" />\n </Button>\n }\n >\n {!stats ? (\n <div className=\"text-center py-4\">\n <p className=\"text-sm text-text-secondary\">No workflow data available</p>\n </div>\n ) : (\n <div className=\"space-y-3\">\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"rounded-lg bg-bg-canvas p-3 border border-border-default text-center\">\n <p className=\"text-2xl font-bold text-text-primary tabular-nums\">\n {stats.activeWorkflowsCount}\n </p>\n <p className=\"text-xs text-text-secondary\">Active</p>\n </div>\n <div className=\"rounded-lg bg-bg-canvas p-3 border border-border-default text-center\">\n <p className=\"text-2xl font-bold text-text-primary tabular-nums\">\n {stats.archivedWorkflowsCount}\n </p>\n <p className=\"text-xs text-text-secondary\">Archived</p>\n </div>\n </div>\n {stats.recentRuns.length > 0 && (\n <div className=\"space-y-1.5\">\n <p className=\"text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Recent Runs\n </p>\n {stats.recentRuns.slice(0, 3).map((run) => {\n const statusInfo = runStatusIcons[run.status] || runStatusIcons.RUNNING;\n const StatusIcon = statusInfo.icon;\n return (\n <div\n key={run.id}\n className=\"flex items-center justify-between p-1.5 rounded hover:bg-accent/5 transition-colors\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <StatusIcon className={`size-3.5 ${statusInfo.color}`} />\n <span className=\"text-sm text-text-primary truncate\">{run.workflowKey}</span>\n </div>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {run.status}\n </Badge>\n </div>\n );\n })}\n </div>\n )}\n </div>\n )}\n </WidgetWrapper>\n );\n}\n"],"mappings":";;;;;AAKA,IAAM,IAAuE;CAC3E,SAAS;EAAE,MAAM;EAAM,OAAO;EAAoB;CAClD,WAAW;EAAE,MAAM;EAAc,OAAO;EAA4B;CACpE,QAAQ;EAAE,MAAM;EAAS,OAAO;EAA0B;CAC1D,QAAQ;EAAE,MAAM;EAAO,OAAO;EAA4B;CAC3D;AAED,SAAgB,EAAoB,EAAE,kBAAe,cAAW,eAAyB;CACvF,IAAM,IAAQ,GAAe;AAE7B,QACE,kBAAC,GAAD;EACE,OAAM;EACN,MAAM,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA;EACtC,MAAK;EACM;EACX,aAAa,CAAC;EACd,cACE,kBAAC,GAAD;GACE,SAAQ;GACR,MAAK;GACL,WAAU;GACV,eAAe,EAAS,aAAa;aAJvC,CAKC,aACU,kBAAC,GAAD,EAAY,WAAU,eAAgB,CAAA,CACxC;;YAGT,IAKA,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAM;MACL,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAAU,CAAA,CACjD;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAM;MACL,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAAY,CAAA,CACnD;OACF;OACL,EAAM,WAAW,SAAS,KACzB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eAAmE;KAE5E,CAAA,EACH,EAAM,WAAW,MAAM,GAAG,EAAE,CAAC,KAAK,MAAQ;KACzC,IAAM,IAAa,EAAe,EAAI,WAAW,EAAe,SAC1D,IAAa,EAAW;AAC9B,YACE,kBAAC,OAAD;MAEE,WAAU;gBAFZ,CAIE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAY,WAAW,YAAY,EAAW,SAAW,CAAA,EACzD,kBAAC,QAAD;QAAM,WAAU;kBAAsC,EAAI;QAAmB,CAAA,CACzE;UACN,kBAAC,GAAD;OAAO,SAAQ;OAAU,WAAU;iBAChC,EAAI;OACC,CAAA,CACJ;QAVC,EAAI,GAUL;MAER,CACE;MAEJ;OA5CN,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,KAAD;IAAG,WAAU;cAA8B;IAA8B,CAAA;GACrE,CAAA;EA4CM,CAAA"}
1
+ {"version":3,"file":"WorkflowStatsWidget.js","names":[],"sources":["../../../../src/pages/dashboard/widgets/WorkflowStatsWidget.tsx"],"sourcesContent":["import { GitBranch, ArrowRight, Play, Pause, CheckCircle2, XCircle } from 'lucide-react';\nimport { Badge, Button, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\nimport { WidgetWrapper } from '../WidgetWrapper';\nimport type { WidgetProps } from '../types';\n\nconst runStatusIcons: Record<string, { icon: typeof Play; color: string }> = {\n RUNNING: { icon: Play, color: 'text-accent-blue' },\n COMPLETED: { icon: CheckCircle2, color: 'text-status-success-text' },\n FAILED: { icon: XCircle, color: 'text-status-error-text' },\n PAUSED: { icon: Pause, color: 'text-status-warning-text' },\n};\n\nexport function WorkflowStatsWidget({ workspaceData, isLoading, navigate }: WidgetProps) {\n const stats = workspaceData?.workflowStats;\n\n return (\n <WidgetWrapper\n title=\"Workflows\"\n icon={<GitBranch className=\"size-4\" />}\n size=\"medium\"\n isLoading={isLoading}\n unavailable={!workspaceData}\n headerAction={\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"text-xs\"\n onClick={() => navigate('/workflows')}\n >\n View all <ArrowRight className=\"ml-1 size-3\" />\n </Button>\n }\n >\n {!stats ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No workflow data available\"\n description=\"Once you run automations, their status and counts will appear here.\"\n className=\"py-4\"\n />\n ) : (\n <div className=\"space-y-3\">\n <div className=\"grid grid-cols-2 gap-3\">\n <div className=\"rounded-lg bg-bg-canvas p-3 border border-border-default text-center\">\n <p className=\"text-2xl font-bold text-text-primary tabular-nums\">\n {stats.activeWorkflowsCount}\n </p>\n <p className=\"text-xs text-text-secondary\">Active</p>\n </div>\n <div className=\"rounded-lg bg-bg-canvas p-3 border border-border-default text-center\">\n <p className=\"text-2xl font-bold text-text-primary tabular-nums\">\n {stats.archivedWorkflowsCount}\n </p>\n <p className=\"text-xs text-text-secondary\">Archived</p>\n </div>\n </div>\n {stats.recentRuns.length > 0 && (\n <div className=\"space-y-1.5\">\n <p className=\"text-xs font-medium text-text-secondary uppercase tracking-wider\">\n Recent Runs\n </p>\n {stats.recentRuns.slice(0, 3).map((run) => {\n const statusInfo = runStatusIcons[run.status] || runStatusIcons.RUNNING;\n const StatusIcon = statusInfo.icon;\n return (\n <div\n key={run.id}\n className=\"flex items-center justify-between p-1.5 rounded hover:bg-accent/5 transition-colors\"\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <StatusIcon className={`size-3.5 ${statusInfo.color}`} />\n <span className=\"text-sm text-text-primary truncate\">{run.workflowKey}</span>\n </div>\n <Badge variant=\"outline\" className=\"text-[10px]\">\n {run.status}\n </Badge>\n </div>\n );\n })}\n </div>\n )}\n </div>\n )}\n </WidgetWrapper>\n );\n}\n"],"mappings":";;;;;AAKA,IAAM,IAAuE;CAC3E,SAAS;EAAE,MAAM;EAAM,OAAO;EAAoB;CAClD,WAAW;EAAE,MAAM;EAAc,OAAO;EAA4B;CACpE,QAAQ;EAAE,MAAM;EAAS,OAAO;EAA0B;CAC1D,QAAQ;EAAE,MAAM;EAAO,OAAO;EAA4B;CAC3D;AAED,SAAgB,EAAoB,EAAE,kBAAe,cAAW,eAAyB;CACvF,IAAM,IAAQ,GAAe;AAE7B,QACE,kBAAC,GAAD;EACE,OAAM;EACN,MAAM,kBAAC,GAAD,EAAW,WAAU,UAAW,CAAA;EACtC,MAAK;EACM;EACX,aAAa,CAAC;EACd,cACE,kBAAC,GAAD;GACE,SAAQ;GACR,MAAK;GACL,WAAU;GACV,eAAe,EAAS,aAAa;aAJvC,CAKC,aACU,kBAAC,GAAD,EAAY,WAAU,eAAgB,CAAA,CACxC;;YAGT,IAQA,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAM;MACL,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAAU,CAAA,CACjD;QACN,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,KAAD;MAAG,WAAU;gBACV,EAAM;MACL,CAAA,EACJ,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAAY,CAAA,CACnD;OACF;OACL,EAAM,WAAW,SAAS,KACzB,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,KAAD;KAAG,WAAU;eAAmE;KAE5E,CAAA,EACH,EAAM,WAAW,MAAM,GAAG,EAAE,CAAC,KAAK,MAAQ;KACzC,IAAM,IAAa,EAAe,EAAI,WAAW,EAAe,SAC1D,IAAa,EAAW;AAC9B,YACE,kBAAC,OAAD;MAEE,WAAU;gBAFZ,CAIE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAY,WAAW,YAAY,EAAW,SAAW,CAAA,EACzD,kBAAC,QAAD;QAAM,WAAU;kBAAsC,EAAI;QAAmB,CAAA,CACzE;UACN,kBAAC,GAAD;OAAO,SAAQ;OAAU,WAAU;iBAChC,EAAI;OACC,CAAA,CACJ;QAVC,EAAI,GAUL;MAER,CACE;MAEJ;OA/CN,kBAAC,GAAD;GACE,cAAa;GACb,OAAM;GACN,aAAY;GACZ,WAAU;GACV,CAAA;EA4CU,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-workspaces",
3
- "version": "2026.625.5",
3
+ "version": "2026.626.2",
4
4
  "description": "Workspaces microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "files": [
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@apollo/client": "^4.0.11",
47
- "@burdenoff/fe-libs": "2026.625.3",
47
+ "@burdenoff/fe-libs": "2026.625.5",
48
48
  "@radix-ui/react-icons": "^1.3.2",
49
49
  "@tanstack/react-query": "^5.62.13",
50
50
  "axios": "^1.15.2",