@burdenoff/microfe-workspaces 2026.510.50 → 2026.511.1

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 (69) hide show
  1. package/dist/generated/wspace-operations.d.ts +91 -0
  2. package/dist/generated/wspace-operations.d.ts.map +1 -1
  3. package/dist/generated/wspace-operations.js +79 -51
  4. package/dist/generated/wspace-operations.js.map +1 -1
  5. package/dist/hooks/useMemberMutations.d.ts.map +1 -1
  6. package/dist/hooks/useMemberMutations.js +141 -60
  7. package/dist/hooks/useMemberMutations.js.map +1 -1
  8. package/dist/hooks/useProjectMutations.d.ts.map +1 -1
  9. package/dist/hooks/useProjectMutations.js +84 -44
  10. package/dist/hooks/useProjectMutations.js.map +1 -1
  11. package/dist/hooks/useWorkspaceMutations.d.ts.map +1 -1
  12. package/dist/hooks/useWorkspaceMutations.js +64 -29
  13. package/dist/hooks/useWorkspaceMutations.js.map +1 -1
  14. package/dist/hooks/useWorkspacesEventEmitter.d.ts +5 -1
  15. package/dist/hooks/useWorkspacesEventEmitter.d.ts.map +1 -1
  16. package/dist/hooks/useWorkspacesEventEmitter.js +8 -7
  17. package/dist/hooks/useWorkspacesEventEmitter.js.map +1 -1
  18. package/dist/hooks/useWorkspacesPageView.d.ts +27 -0
  19. package/dist/hooks/useWorkspacesPageView.d.ts.map +1 -0
  20. package/dist/hooks/useWorkspacesPageView.js +29 -0
  21. package/dist/hooks/useWorkspacesPageView.js.map +1 -0
  22. package/dist/pages/ActivityListPage.d.ts.map +1 -1
  23. package/dist/pages/ActivityListPage.js +59 -56
  24. package/dist/pages/ActivityListPage.js.map +1 -1
  25. package/dist/pages/CreateWorkspacePage.d.ts.map +1 -1
  26. package/dist/pages/CreateWorkspacePage.js +104 -104
  27. package/dist/pages/CreateWorkspacePage.js.map +1 -1
  28. package/dist/pages/InviteAcceptancePage.d.ts.map +1 -1
  29. package/dist/pages/InviteAcceptancePage.js +197 -216
  30. package/dist/pages/InviteAcceptancePage.js.map +1 -1
  31. package/dist/pages/MembersListPage.d.ts.map +1 -1
  32. package/dist/pages/MembersListPage.js +142 -138
  33. package/dist/pages/MembersListPage.js.map +1 -1
  34. package/dist/pages/ProjectDetailPage.d.ts.map +1 -1
  35. package/dist/pages/ProjectDetailPage.js +181 -176
  36. package/dist/pages/ProjectDetailPage.js.map +1 -1
  37. package/dist/pages/ProjectsListPage.d.ts.map +1 -1
  38. package/dist/pages/ProjectsListPage.js +175 -171
  39. package/dist/pages/ProjectsListPage.js.map +1 -1
  40. package/dist/pages/WorkspaceDetailPage.d.ts.map +1 -1
  41. package/dist/pages/WorkspaceDetailPage.js +104 -101
  42. package/dist/pages/WorkspaceDetailPage.js.map +1 -1
  43. package/dist/pages/WorkspaceSettingsPage.d.ts.map +1 -1
  44. package/dist/pages/WorkspaceSettingsPage.js +182 -137
  45. package/dist/pages/WorkspaceSettingsPage.js.map +1 -1
  46. package/dist/pages/WorkspacesListPage.d.ts.map +1 -1
  47. package/dist/pages/WorkspacesListPage.js +77 -77
  48. package/dist/pages/WorkspacesListPage.js.map +1 -1
  49. package/dist/pages/dashboard/DashboardCustomizer.d.ts.map +1 -1
  50. package/dist/pages/dashboard/DashboardCustomizer.js +53 -55
  51. package/dist/pages/dashboard/DashboardCustomizer.js.map +1 -1
  52. package/dist/pages/dashboard/DashboardGrid.d.ts.map +1 -1
  53. package/dist/pages/dashboard/DashboardGrid.js +33 -36
  54. package/dist/pages/dashboard/DashboardGrid.js.map +1 -1
  55. package/dist/pages/dashboard/DashboardPage.d.ts.map +1 -1
  56. package/dist/pages/dashboard/DashboardPage.js +67 -65
  57. package/dist/pages/dashboard/DashboardPage.js.map +1 -1
  58. package/dist/pages/dashboard/WidgetWrapper.d.ts.map +1 -1
  59. package/dist/pages/dashboard/WidgetWrapper.js +3 -6
  60. package/dist/pages/dashboard/WidgetWrapper.js.map +1 -1
  61. package/dist/utils/i18n.d.ts +13 -0
  62. package/dist/utils/i18n.d.ts.map +1 -0
  63. package/dist/utils/i18n.js +12 -0
  64. package/dist/utils/i18n.js.map +1 -0
  65. package/dist/utils/telemetryError.d.ts +2 -0
  66. package/dist/utils/telemetryError.d.ts.map +1 -0
  67. package/dist/utils/telemetryError.js +28 -0
  68. package/dist/utils/telemetryError.js.map +1 -0
  69. package/package.json +9 -4
@@ -1,54 +1,51 @@
1
- import { WelcomeWidget as e } from "./widgets/WelcomeWidget.js";
2
- import { QuickActionsWidget as t } from "./widgets/QuickActionsWidget.js";
3
- import { WorkspacesWidget as n } from "./widgets/WorkspacesWidget.js";
4
- import { ProjectsWidget as r } from "./widgets/ProjectsWidget.js";
5
- import { RecentActivityWidget as i } from "./widgets/RecentActivityWidget.js";
6
- import { UpcomingEventsWidget as a } from "./widgets/UpcomingEventsWidget.js";
7
- import { WorkflowStatsWidget as o } from "./widgets/WorkflowStatsWidget.js";
8
- import { TagCloudWidget as s } from "./widgets/TagCloudWidget.js";
9
- import { StorageWidget as c } from "./widgets/StorageWidget.js";
10
- import { GroupsWidget as l } from "./widgets/GroupsWidget.js";
11
- import { MembersWidget as u } from "./widgets/MembersWidget.js";
12
- import { SystemHealthWidget as d } from "./widgets/SystemHealthWidget.js";
13
- import { TipsWidget as f } from "./widgets/TipsWidget.js";
14
- import { useCallback as p } from "react";
1
+ import { tWithFallback as e } from "../../utils/i18n.js";
2
+ import { WelcomeWidget as t } from "./widgets/WelcomeWidget.js";
3
+ import { QuickActionsWidget as n } from "./widgets/QuickActionsWidget.js";
4
+ import { WorkspacesWidget as r } from "./widgets/WorkspacesWidget.js";
5
+ import { ProjectsWidget as i } from "./widgets/ProjectsWidget.js";
6
+ import { RecentActivityWidget as a } from "./widgets/RecentActivityWidget.js";
7
+ import { UpcomingEventsWidget as o } from "./widgets/UpcomingEventsWidget.js";
8
+ import { WorkflowStatsWidget as s } from "./widgets/WorkflowStatsWidget.js";
9
+ import { TagCloudWidget as c } from "./widgets/TagCloudWidget.js";
10
+ import { StorageWidget as l } from "./widgets/StorageWidget.js";
11
+ import { GroupsWidget as u } from "./widgets/GroupsWidget.js";
12
+ import { MembersWidget as d } from "./widgets/MembersWidget.js";
13
+ import { SystemHealthWidget as f } from "./widgets/SystemHealthWidget.js";
14
+ import { TipsWidget as p } from "./widgets/TipsWidget.js";
15
15
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
16
16
  import { useI18n as g } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
17
17
  //#region src/pages/dashboard/DashboardGrid.tsx
18
18
  var _ = {
19
- welcome: e,
20
- quickActions: t,
21
- workspaces: n,
22
- projects: r,
23
- activity: i,
24
- calendar: a,
25
- workflows: o,
26
- tags: s,
27
- storage: c,
28
- groups: l,
29
- members: u,
30
- systemHealth: d,
31
- tips: f
19
+ welcome: t,
20
+ quickActions: n,
21
+ workspaces: r,
22
+ projects: i,
23
+ activity: a,
24
+ calendar: o,
25
+ workflows: s,
26
+ tags: c,
27
+ storage: l,
28
+ groups: u,
29
+ members: d,
30
+ systemHealth: f,
31
+ tips: p
32
32
  };
33
- function v({ widgets: e, ...t }) {
34
- let { t: n } = g(), r = p((e, t) => {
35
- let r = n(e);
36
- return r === e ? t : r;
37
- }, [n]), i = e.filter((e) => e.enabled).sort((e, t) => e.order - t.order);
33
+ function v({ widgets: t, ...n }) {
34
+ let { t: r } = g(), i = t.filter((e) => e.enabled).sort((e, t) => e.order - t.order);
38
35
  return i.length === 0 ? /* @__PURE__ */ h("div", {
39
36
  className: "text-center py-12",
40
37
  children: [/* @__PURE__ */ m("p", {
41
38
  className: "text-lg text-muted-foreground",
42
- children: r("dashboardGrid.noWidgetsEnabled", "No widgets enabled")
39
+ children: e(r, "dashboardGrid.noWidgetsEnabled", "No widgets enabled")
43
40
  }), /* @__PURE__ */ m("p", {
44
41
  className: "text-sm text-muted-foreground mt-1",
45
- children: r("dashboardGrid.noWidgetsHint", "Click \"Customize\" to add widgets to your dashboard")
42
+ children: e(r, "dashboardGrid.noWidgetsHint", "Click \"Customize\" to add widgets to your dashboard")
46
43
  })]
47
44
  }) : /* @__PURE__ */ m("div", {
48
45
  className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4",
49
46
  children: i.map((e) => {
50
- let n = _[e.widgetId];
51
- return n ? /* @__PURE__ */ m(n, { ...t }, e.widgetId) : null;
47
+ let t = _[e.widgetId];
48
+ return t ? /* @__PURE__ */ m(t, { ...n }, e.widgetId) : null;
52
49
  })
53
50
  });
54
51
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardGrid.js","names":[],"sources":["../../../src/pages/dashboard/DashboardGrid.tsx"],"sourcesContent":["/**\n * DashboardGrid — Renders the configured widgets in a responsive grid.\n */\nimport { useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { WidgetConfig, WidgetProps } from './types';\nimport { WIDGET_DEFINITIONS } from './config';\n\n// Widget components\nimport { WelcomeWidget } from './widgets/WelcomeWidget';\nimport { QuickActionsWidget } from './widgets/QuickActionsWidget';\nimport { WorkspacesWidget } from './widgets/WorkspacesWidget';\nimport { ProjectsWidget } from './widgets/ProjectsWidget';\nimport { RecentActivityWidget } from './widgets/RecentActivityWidget';\nimport { UpcomingEventsWidget } from './widgets/UpcomingEventsWidget';\nimport { WorkflowStatsWidget } from './widgets/WorkflowStatsWidget';\nimport { TagCloudWidget } from './widgets/TagCloudWidget';\nimport { StorageWidget } from './widgets/StorageWidget';\nimport { GroupsWidget } from './widgets/GroupsWidget';\nimport { MembersWidget } from './widgets/MembersWidget';\nimport { SystemHealthWidget } from './widgets/SystemHealthWidget';\nimport { TipsWidget } from './widgets/TipsWidget';\n\n// Widget component registry\nconst WIDGET_COMPONENTS: Record<string, React.FC<WidgetProps>> = {\n welcome: WelcomeWidget,\n quickActions: QuickActionsWidget,\n workspaces: WorkspacesWidget,\n projects: ProjectsWidget,\n activity: RecentActivityWidget,\n calendar: UpcomingEventsWidget,\n workflows: WorkflowStatsWidget,\n tags: TagCloudWidget,\n storage: StorageWidget,\n groups: GroupsWidget,\n members: MembersWidget,\n systemHealth: SystemHealthWidget,\n tips: TipsWidget,\n};\n\ninterface DashboardGridProps extends WidgetProps {\n widgets: WidgetConfig[];\n}\n\nexport function DashboardGrid({ widgets, ...widgetProps }: DashboardGridProps) {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const enabledWidgets = widgets.filter((w) => w.enabled).sort((a, b) => a.order - b.order);\n\n if (enabledWidgets.length === 0) {\n return (\n <div className=\"text-center py-12\">\n <p className=\"text-lg text-muted-foreground\">\n {tr('dashboardGrid.noWidgetsEnabled', 'No widgets enabled')}\n </p>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tr('dashboardGrid.noWidgetsHint', 'Click \"Customize\" to add widgets to your dashboard')}\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {enabledWidgets.map((widgetConfig) => {\n const Component = WIDGET_COMPONENTS[widgetConfig.widgetId];\n if (!Component) return null;\n\n return <Component key={widgetConfig.widgetId} {...widgetProps} />;\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAwBA,IAAM,IAA2D;CAC/D,SAAS;CACT,cAAc;CACd,YAAY;CACZ,UAAU;CACV,UAAU;CACV,UAAU;CACV,WAAW;CACX,MAAM;CACN,SAAS;CACT,QAAQ;CACR,SAAS;CACT,cAAc;CACd,MAAM;CACP;AAMD,SAAgB,EAAc,EAAE,YAAS,GAAG,KAAmC;CAC7E,IAAM,EAAE,SAAM,GAAS,EACjB,IAAK,GACR,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAE,CACJ,EAEK,IAAiB,EAAQ,QAAQ,MAAM,EAAE,QAAQ,CAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AAezF,QAbI,EAAe,WAAW,IAE1B,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,KAAD;GAAG,WAAU;aACV,EAAG,kCAAkC,qBAAqB;GACzD,CAAA,EACJ,kBAAC,KAAD;GAAG,WAAU;aACV,EAAG,+BAA+B,uDAAqD;GACtF,CAAA,CACA;MAKR,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAe,KAAK,MAAiB;GACpC,IAAM,IAAY,EAAkB,EAAa;AAGjD,UAFK,IAEE,kBAAC,GAAD,EAAuC,GAAI,GAAe,EAA1C,EAAa,SAA6B,GAF1C;IAGvB;EACE,CAAA"}
1
+ {"version":3,"file":"DashboardGrid.js","names":[],"sources":["../../../src/pages/dashboard/DashboardGrid.tsx"],"sourcesContent":["/**\n * DashboardGrid — Renders the configured widgets in a responsive grid.\n */\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../../utils/i18n';\nimport type { WidgetConfig, WidgetProps } from './types';\nimport { WIDGET_DEFINITIONS } from './config';\n\n// Widget components\nimport { WelcomeWidget } from './widgets/WelcomeWidget';\nimport { QuickActionsWidget } from './widgets/QuickActionsWidget';\nimport { WorkspacesWidget } from './widgets/WorkspacesWidget';\nimport { ProjectsWidget } from './widgets/ProjectsWidget';\nimport { RecentActivityWidget } from './widgets/RecentActivityWidget';\nimport { UpcomingEventsWidget } from './widgets/UpcomingEventsWidget';\nimport { WorkflowStatsWidget } from './widgets/WorkflowStatsWidget';\nimport { TagCloudWidget } from './widgets/TagCloudWidget';\nimport { StorageWidget } from './widgets/StorageWidget';\nimport { GroupsWidget } from './widgets/GroupsWidget';\nimport { MembersWidget } from './widgets/MembersWidget';\nimport { SystemHealthWidget } from './widgets/SystemHealthWidget';\nimport { TipsWidget } from './widgets/TipsWidget';\n\n// Widget component registry\nconst WIDGET_COMPONENTS: Record<string, React.FC<WidgetProps>> = {\n welcome: WelcomeWidget,\n quickActions: QuickActionsWidget,\n workspaces: WorkspacesWidget,\n projects: ProjectsWidget,\n activity: RecentActivityWidget,\n calendar: UpcomingEventsWidget,\n workflows: WorkflowStatsWidget,\n tags: TagCloudWidget,\n storage: StorageWidget,\n groups: GroupsWidget,\n members: MembersWidget,\n systemHealth: SystemHealthWidget,\n tips: TipsWidget,\n};\n\ninterface DashboardGridProps extends WidgetProps {\n widgets: WidgetConfig[];\n}\n\nexport function DashboardGrid({ widgets, ...widgetProps }: DashboardGridProps) {\n const { t } = useI18n();\n\n const enabledWidgets = widgets.filter((w) => w.enabled).sort((a, b) => a.order - b.order);\n\n if (enabledWidgets.length === 0) {\n return (\n <div className=\"text-center py-12\">\n <p className=\"text-lg text-muted-foreground\">\n {tWithFallback(t, 'dashboardGrid.noWidgetsEnabled', 'No widgets enabled')}\n </p>\n <p className=\"text-sm text-muted-foreground mt-1\">\n {tWithFallback(\n t,\n 'dashboardGrid.noWidgetsHint',\n 'Click \"Customize\" to add widgets to your dashboard'\n )}\n </p>\n </div>\n );\n }\n\n return (\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4\">\n {enabledWidgets.map((widgetConfig) => {\n const Component = WIDGET_COMPONENTS[widgetConfig.widgetId];\n if (!Component) return null;\n\n return <Component key={widgetConfig.widgetId} {...widgetProps} />;\n })}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAwBA,IAAM,IAA2D;CAC/D,SAAS;CACT,cAAc;CACd,YAAY;CACZ,UAAU;CACV,UAAU;CACV,UAAU;CACV,WAAW;CACX,MAAM;CACN,SAAS;CACT,QAAQ;CACR,SAAS;CACT,cAAc;CACd,MAAM;CACP;AAMD,SAAgB,EAAc,EAAE,YAAS,GAAG,KAAmC;CAC7E,IAAM,EAAE,SAAM,GAAS,EAEjB,IAAiB,EAAQ,QAAQ,MAAM,EAAE,QAAQ,CAAC,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;AAmBzF,QAjBI,EAAe,WAAW,IAE1B,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,KAAD;GAAG,WAAU;aACV,EAAc,GAAG,kCAAkC,qBAAqB;GACvE,CAAA,EACJ,kBAAC,KAAD;GAAG,WAAU;aACV,EACC,GACA,+BACA,uDACD;GACC,CAAA,CACA;MAKR,kBAAC,OAAD;EAAK,WAAU;YACZ,EAAe,KAAK,MAAiB;GACpC,IAAM,IAAY,EAAkB,EAAa;AAGjD,UAFK,IAEE,kBAAC,GAAD,EAAuC,GAAI,GAAe,EAA1C,EAAa,SAA6B,GAF1C;IAGvB;EACE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/DashboardPage.tsx"],"names":[],"mappings":"AAiCA,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,IAAI,CAAC;CACV;AAED,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,kBAAkB,2CA+JrF"}
1
+ {"version":3,"file":"DashboardPage.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/DashboardPage.tsx"],"names":[],"mappings":"AAkCA,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,IAAI,CAAC;CACV;AAED,wBAAgB,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,kBAAkB,2CAgKrF"}
@@ -1,20 +1,22 @@
1
- import { useGlobalDashboardData as e, useProjectsDashboardData as t, useWorkspaceDashboardData as n } from "./hooks/useDashboardData.js";
2
- import { useUpdateDashboardPreferences as r } from "./hooks/useDashboardPreferences.js";
3
- import { DashboardGrid as i } from "./DashboardGrid.js";
4
- import { getEffectiveWidgets as a } from "./config.js";
5
- import { DashboardCustomizer as o } from "./DashboardCustomizer.js";
6
- import { useCallback as s, useMemo as c, useState as l } from "react";
7
- import { AlertCircle as u, Loader2 as d, RefreshCw as f, Settings2 as p } from "lucide-react";
8
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
9
- import { Button as g } from "@burdenoff/fe-libs/ui";
10
- import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
1
+ import { useWorkspacesPageView as e } from "../../hooks/useWorkspacesPageView.js";
2
+ import { useGlobalDashboardData as t, useProjectsDashboardData as n, useWorkspaceDashboardData as r } from "./hooks/useDashboardData.js";
3
+ import { useUpdateDashboardPreferences as i } from "./hooks/useDashboardPreferences.js";
4
+ import { DashboardGrid as a } from "./DashboardGrid.js";
5
+ import { getEffectiveWidgets as o } from "./config.js";
6
+ import { DashboardCustomizer as s } from "./DashboardCustomizer.js";
7
+ import { useCallback as c, useMemo as l, useState as u } from "react";
8
+ import { AlertCircle as d, Loader2 as f, RefreshCw as p, Settings2 as m } from "lucide-react";
9
+ import { jsx as h, jsxs as g } from "react/jsx-runtime";
10
+ import { Button as _ } from "@burdenoff/fe-libs/ui";
11
+ import { useI18n as v } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
11
12
  //#region src/pages/dashboard/DashboardPage.tsx
12
- function v({ navigate: v, authToken: y, currentUser: b }) {
13
- let { t: x } = _(), S = (e, t) => {
14
- let n = x(e);
13
+ function y({ navigate: y, authToken: b, currentUser: x }) {
14
+ e("workspaces.dashboard");
15
+ let { t: S } = v(), C = (e, t) => {
16
+ let n = S(e);
15
17
  return n === e ? t : n;
16
- }, [C, w] = l(!1), { data: T, isLoading: E, error: D, refetch: O } = n(y), { data: k, isLoading: A, error: j, refetch: M } = e(y), { data: N, isLoading: P, refetch: F } = t(y), I = r(y), L = E || A || P, R = c(() => !T && !k && !N ? null : {
17
- ...T ?? {
18
+ }, [w, T] = u(!1), { data: E, isLoading: D, error: O, refetch: k } = r(b), { data: A, isLoading: j, error: M, refetch: N } = t(b), { data: P, isLoading: F, refetch: I } = n(b), L = i(b), R = D || j || F, z = l(() => !E && !A && !P ? null : {
19
+ ...E ?? {
18
20
  workspaces: {
19
21
  items: [],
20
22
  total: 0
@@ -36,101 +38,101 @@ function v({ navigate: v, authToken: y, currentUser: b }) {
36
38
  workflowStats: null,
37
39
  storageUsage: null
38
40
  },
39
- workspaces: k?.workspaces ?? {
41
+ workspaces: A?.workspaces ?? {
40
42
  items: [],
41
43
  total: 0
42
44
  },
43
- projects: N ?? {
45
+ projects: P ?? {
44
46
  items: [],
45
47
  total: 0
46
48
  }
47
49
  }, [
48
- T,
49
- k,
50
- N
51
- ]), z = k?.dashboardPreferences, B = c(() => a(z?.widgets ?? null), [z]), V = s(() => {
52
- O(), M(), F();
50
+ E,
51
+ A,
52
+ P
53
+ ]), B = A?.dashboardPreferences, V = l(() => o(B?.widgets ?? null), [B]), H = c(() => {
54
+ k(), N(), I();
53
55
  }, [
54
- O,
55
- M,
56
- F
57
- ]), H = s(async (e) => {
58
- await I.mutateAsync(e);
59
- }, [I]), U = D || j;
60
- return /* @__PURE__ */ h("div", {
56
+ k,
57
+ N,
58
+ I
59
+ ]), U = c(async (e) => {
60
+ await L.mutateAsync(e);
61
+ }, [L]), W = O || M;
62
+ return /* @__PURE__ */ g("div", {
61
63
  className: "min-h-[calc(100vh-8rem)] p-4 md:p-6 bg-bg-canvas",
62
64
  "data-tour": "main-content",
63
65
  children: [
64
- /* @__PURE__ */ h("div", {
66
+ /* @__PURE__ */ g("div", {
65
67
  className: "flex flex-wrap items-center justify-between gap-4 mb-6",
66
- children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h1", {
68
+ children: [/* @__PURE__ */ g("div", { children: [/* @__PURE__ */ h("h1", {
67
69
  className: "text-xl font-bold text-text-primary",
68
- children: S("dashboard.title", "Dashboard")
69
- }), /* @__PURE__ */ m("p", {
70
+ children: C("dashboard.title", "Dashboard")
71
+ }), /* @__PURE__ */ h("p", {
70
72
  className: "text-sm text-muted-foreground mt-0.5",
71
- children: S("dashboard.subtitle", "Your workspace overview at a glance")
72
- })] }), /* @__PURE__ */ h("div", {
73
+ children: C("dashboard.subtitle", "Your workspace overview at a glance")
74
+ })] }), /* @__PURE__ */ g("div", {
73
75
  className: "flex flex-wrap items-center gap-2",
74
76
  "data-tour": "quick-actions",
75
- children: [/* @__PURE__ */ h(g, {
77
+ children: [/* @__PURE__ */ g(_, {
76
78
  variant: "outline",
77
79
  size: "sm",
78
- onClick: V,
79
- disabled: L,
80
+ onClick: H,
81
+ disabled: R,
80
82
  className: "text-xs",
81
- children: [L ? /* @__PURE__ */ m(d, { className: "h-3.5 w-3.5 sm:mr-1.5 animate-spin" }) : /* @__PURE__ */ m(f, { className: "h-3.5 w-3.5 sm:mr-1.5" }), /* @__PURE__ */ m("span", {
83
+ children: [R ? /* @__PURE__ */ h(f, { className: "h-3.5 w-3.5 sm:mr-1.5 animate-spin" }) : /* @__PURE__ */ h(p, { className: "h-3.5 w-3.5 sm:mr-1.5" }), /* @__PURE__ */ h("span", {
82
84
  className: "hidden sm:inline",
83
- children: S("dashboard.refresh", "Refresh")
85
+ children: C("dashboard.refresh", "Refresh")
84
86
  })]
85
- }), /* @__PURE__ */ h(g, {
87
+ }), /* @__PURE__ */ g(_, {
86
88
  variant: "outline",
87
89
  size: "sm",
88
- onClick: () => w(!0),
90
+ onClick: () => T(!0),
89
91
  className: "text-xs",
90
- children: [/* @__PURE__ */ m(p, { className: "h-3.5 w-3.5 sm:mr-1.5" }), /* @__PURE__ */ m("span", {
92
+ children: [/* @__PURE__ */ h(m, { className: "h-3.5 w-3.5 sm:mr-1.5" }), /* @__PURE__ */ h("span", {
91
93
  className: "hidden sm:inline",
92
- children: S("dashboard.customize", "Customize")
94
+ children: C("dashboard.customize", "Customize")
93
95
  })]
94
96
  })]
95
97
  })]
96
98
  }),
97
- U && /* @__PURE__ */ h("div", {
99
+ W && /* @__PURE__ */ g("div", {
98
100
  className: "mb-4 p-3 bg-destructive/10 border border-destructive/20 rounded-lg flex items-center gap-2",
99
- children: [/* @__PURE__ */ m(u, { className: "h-4 w-4 text-destructive shrink-0" }), /* @__PURE__ */ h("p", {
101
+ children: [/* @__PURE__ */ h(d, { className: "h-4 w-4 text-destructive shrink-0" }), /* @__PURE__ */ g("p", {
100
102
  className: "text-sm text-destructive",
101
103
  children: [
102
- S("dashboard.error.partialData", "Some data may be unavailable."),
104
+ C("dashboard.error.partialData", "Some data may be unavailable."),
103
105
  " ",
104
- D ? S("dashboard.error.workspaceDown", "Workspace services may be down.") : "",
106
+ O ? C("dashboard.error.workspaceDown", "Workspace services may be down.") : "",
105
107
  " ",
106
- j ? S("dashboard.error.globalDown", "Global services may be down.") : "",
108
+ M ? C("dashboard.error.globalDown", "Global services may be down.") : "",
107
109
  " ",
108
- /* @__PURE__ */ m("button", {
110
+ /* @__PURE__ */ h("button", {
109
111
  className: "underline font-medium hover:text-destructive/80",
110
- onClick: V,
111
- children: S("dashboard.error.tryRefreshing", "Try refreshing")
112
+ onClick: H,
113
+ children: C("dashboard.error.tryRefreshing", "Try refreshing")
112
114
  })
113
115
  ]
114
116
  })]
115
117
  }),
116
- /* @__PURE__ */ m(i, {
117
- widgets: B,
118
- workspaceData: R,
119
- globalData: k ?? null,
120
- isLoading: L,
121
- navigate: v
118
+ /* @__PURE__ */ h(a, {
119
+ widgets: V,
120
+ workspaceData: z,
121
+ globalData: A ?? null,
122
+ isLoading: R,
123
+ navigate: y
122
124
  }),
123
- /* @__PURE__ */ m(o, {
124
- open: C,
125
- onOpenChange: w,
126
- widgets: B,
127
- onSave: H,
128
- isSaving: I.isPending
125
+ /* @__PURE__ */ h(s, {
126
+ open: w,
127
+ onOpenChange: T,
128
+ widgets: V,
129
+ onSave: U,
130
+ isSaving: L.isPending
129
131
  })
130
132
  ]
131
133
  });
132
134
  }
133
135
  //#endregion
134
- export { v as DashboardPage };
136
+ export { y as DashboardPage };
135
137
 
136
138
  //# 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, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { Settings2, RefreshCw, Loader2, AlertCircle } from 'lucide-react';\nimport {\n useWorkspaceDashboardData,\n useGlobalDashboardData,\n useProjectsDashboardData,\n} from './hooks/useDashboardData';\nimport { useUpdateDashboardPreferences } from './hooks/useDashboardPreferences';\nimport { DashboardGrid } from './DashboardGrid';\nimport { DashboardCustomizer } from './DashboardCustomizer';\nimport { getEffectiveWidgets, DEFAULT_DASHBOARD_WIDGETS } from './config';\nimport type { WidgetConfig, DashboardPreferences } from './types';\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\nexport function DashboardPage({ navigate, authToken, currentUser }: DashboardPageProps) {\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 updatePrefs = useUpdateDashboardPreferences(authToken);\n\n const isLoading = wsLoading || globalLoading || projectsLoading;\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) 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 };\n }, [workspaceData, globalData, projectsData]);\n\n // ─── Widget Configuration ─────────────────────────────────────────────────\n const savedPrefs = globalData?.dashboardPreferences;\n const widgets = useMemo(() => getEffectiveWidgets(savedPrefs?.widgets ?? null), [savedPrefs]);\n\n // ─── Handlers ─────────────────────────────────────────────────────────────\n const handleRefresh = useCallback(() => {\n refetchWs();\n refetchGlobal();\n refetchProjects();\n }, [refetchWs, refetchGlobal, refetchProjects]);\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-muted-foreground 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=\"h-3.5 w-3.5 sm:mr-1.5 animate-spin\" />\n ) : (\n <RefreshCw className=\"h-3.5 w-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=\"h-3.5 w-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-destructive/10 border border-destructive/20 rounded-lg flex items-center gap-2\">\n <AlertCircle className=\"h-4 w-4 text-destructive shrink-0\" />\n <p className=\"text-sm text-destructive\">\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 className=\"underline font-medium hover:text-destructive/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 />\n\n {/* Customizer */}\n <DashboardCustomizer\n open={customizerOpen}\n onOpenChange={setCustomizerOpen}\n widgets={widgets}\n onSave={handleSaveWidgets}\n isSaving={updatePrefs.isPending}\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, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { Settings2, RefreshCw, Loader2, AlertCircle } from 'lucide-react';\nimport {\n useWorkspaceDashboardData,\n useGlobalDashboardData,\n useProjectsDashboardData,\n} from './hooks/useDashboardData';\nimport { useUpdateDashboardPreferences } from './hooks/useDashboardPreferences';\nimport { DashboardGrid } from './DashboardGrid';\nimport { DashboardCustomizer } from './DashboardCustomizer';\nimport { getEffectiveWidgets, DEFAULT_DASHBOARD_WIDGETS } from './config';\nimport type { WidgetConfig, DashboardPreferences } 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\nexport function DashboardPage({ navigate, authToken, currentUser }: 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 updatePrefs = useUpdateDashboardPreferences(authToken);\n\n const isLoading = wsLoading || globalLoading || projectsLoading;\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) 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 };\n }, [workspaceData, globalData, projectsData]);\n\n // ─── Widget Configuration ─────────────────────────────────────────────────\n const savedPrefs = globalData?.dashboardPreferences;\n const widgets = useMemo(() => getEffectiveWidgets(savedPrefs?.widgets ?? null), [savedPrefs]);\n\n // ─── Handlers ─────────────────────────────────────────────────────────────\n const handleRefresh = useCallback(() => {\n refetchWs();\n refetchGlobal();\n refetchProjects();\n }, [refetchWs, refetchGlobal, refetchProjects]);\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-muted-foreground 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=\"h-3.5 w-3.5 sm:mr-1.5 animate-spin\" />\n ) : (\n <RefreshCw className=\"h-3.5 w-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=\"h-3.5 w-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-destructive/10 border border-destructive/20 rounded-lg flex items-center gap-2\">\n <AlertCircle className=\"h-4 w-4 text-destructive shrink-0\" />\n <p className=\"text-sm text-destructive\">\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 className=\"underline font-medium hover:text-destructive/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 />\n\n {/* Customizer */}\n <DashboardCustomizer\n open={customizerOpen}\n onOpenChange={setCustomizerOpen}\n widgets={widgets}\n onSave={handleSaveWidgets}\n isSaving={updatePrefs.isPending}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetWrapper.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/WidgetWrapper.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,SAAS,EAAe,MAAM,OAAO,CAAC;AAKpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA2DD,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,KAAK,EACL,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,SAAc,GACf,EAAE,kBAAkB,2CA2BpB"}
1
+ {"version":3,"file":"WidgetWrapper.d.ts","sourceRoot":"","sources":["../../../src/pages/dashboard/WidgetWrapper.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoDD,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,IAAI,EACJ,IAAI,EACJ,SAAS,EACT,KAAK,EACL,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,SAAc,GACf,EAAE,kBAAkB,2CA2BpB"}
@@ -1,4 +1,4 @@
1
- import { useCallback as e } from "react";
1
+ import { tWithFallback as e } from "../../utils/i18n.js";
2
2
  import { AlertCircle as t, WifiOff as n } from "lucide-react";
3
3
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
4
4
  import { Card as a, CardContent as o, CardHeader as s, CardTitle as c, Skeleton as l } from "@burdenoff/fe-libs/ui";
@@ -36,10 +36,7 @@ function p({ message: e }) {
36
36
  });
37
37
  }
38
38
  function m() {
39
- let { t } = u(), a = e((e, n) => {
40
- let r = t(e);
41
- return r === e ? n : r;
42
- }, [t]);
39
+ let { t } = u();
43
40
  return /* @__PURE__ */ i("div", {
44
41
  className: "flex flex-col items-center justify-center py-6 text-center",
45
42
  children: [/* @__PURE__ */ r("div", {
@@ -47,7 +44,7 @@ function m() {
47
44
  children: /* @__PURE__ */ r(n, { className: "h-5 w-5 text-muted-foreground" })
48
45
  }), /* @__PURE__ */ r("p", {
49
46
  className: "text-sm text-muted-foreground",
50
- children: a("widgetWrapper.serviceUnavailable", "Service unavailable")
47
+ children: e(t, "widgetWrapper.serviceUnavailable", "Service unavailable")
51
48
  })]
52
49
  });
53
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetWrapper.js","names":[],"sources":["../../../src/pages/dashboard/WidgetWrapper.tsx"],"sourcesContent":["/**\n * WidgetWrapper — Common wrapper for all dashboard widgets.\n *\n * Provides consistent card styling, loading skeleton, error state,\n * and unavailable state.\n */\nimport { type ReactNode, useCallback } from 'react';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { Skeleton } from '@burdenoff/fe-libs/ui';\nimport { AlertCircle, WifiOff } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { WidgetSize } from './types';\n\ninterface WidgetWrapperProps {\n title: string;\n icon?: ReactNode;\n size: WidgetSize;\n isLoading?: boolean;\n error?: string | null;\n unavailable?: boolean;\n headerAction?: ReactNode;\n children: ReactNode;\n className?: string;\n}\n\nfunction getColSpan(size: WidgetSize): string {\n switch (size) {\n case 'large':\n return 'col-span-1 sm:col-span-2 lg:col-span-3';\n case 'medium':\n return 'col-span-1 sm:col-span-2 lg:col-span-2 xl:col-span-2 2xl:col-span-1';\n case 'small':\n return 'col-span-1';\n default:\n return 'col-span-1';\n }\n}\n\nfunction LoadingSkeleton() {\n return (\n <div className=\"space-y-3 p-1\">\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-20 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n );\n}\n\nfunction ErrorState({ message }: { message: string }) {\n return (\n <div className=\"flex flex-col items-center justify-center py-6 text-center\">\n <div className=\"rounded-full bg-destructive/10 p-2 mb-2\">\n <AlertCircle className=\"h-5 w-5 text-destructive\" />\n </div>\n <p className=\"text-sm text-muted-foreground\">{message}</p>\n </div>\n );\n}\n\nfunction UnavailableState() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n return (\n <div className=\"flex flex-col items-center justify-center py-6 text-center\">\n <div className=\"rounded-full bg-muted p-2 mb-2\">\n <WifiOff className=\"h-5 w-5 text-muted-foreground\" />\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {tr('widgetWrapper.serviceUnavailable', 'Service unavailable')}\n </p>\n </div>\n );\n}\n\nexport function WidgetWrapper({\n title,\n icon,\n size,\n isLoading,\n error,\n unavailable,\n headerAction,\n children,\n className = '',\n}: WidgetWrapperProps) {\n const colSpan = getColSpan(size);\n\n return (\n <Card\n className={`${colSpan} transition-all duration-200 hover:shadow-md border border-border-default bg-bg-surface ${className}`}\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2 space-y-0\">\n <CardTitle className=\"text-sm font-semibold text-text-primary flex items-center gap-2\">\n {icon}\n {title}\n </CardTitle>\n {headerAction}\n </CardHeader>\n <CardContent className=\"pt-0\">\n {isLoading ? (\n <LoadingSkeleton />\n ) : error ? (\n <ErrorState message={error} />\n ) : unavailable ? (\n <UnavailableState />\n ) : (\n children\n )}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":";;;;;;AAyBA,SAAS,EAAW,GAA0B;AAC5C,SAAQ,GAAR;EACE,KAAK,QACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,IAAkB;AACzB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GAClC,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GAClC,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA;GACpC,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GAC9B;;;AAIV,SAAS,EAAW,EAAE,cAAgC;AACpD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,EAAa,WAAU,4BAA6B,CAAA;GAChD,CAAA,EACN,kBAAC,KAAD;GAAG,WAAU;aAAiC;GAAY,CAAA,CACtD;;;AAIV,SAAS,IAAmB;CAC1B,IAAM,EAAE,MAAM,GAAS,EACjB,IAAK,GACR,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAE,CACJ;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,EAAS,WAAU,iCAAkC,CAAA;GACjD,CAAA,EACN,kBAAC,KAAD;GAAG,WAAU;aACV,EAAG,oCAAoC,sBAAsB;GAC5D,CAAA,CACA;;;AAIV,SAAgB,EAAc,EAC5B,UACA,SACA,SACA,cACA,UACA,gBACA,iBACA,aACA,eAAY,MACS;AAGrB,QACE,kBAAC,GAAD;EACE,WAAW,GAJC,EAAW,EAAK,CAIN,0FAA0F;YADlH,CAGE,kBAAC,GAAD;GAAY,WAAU;aAAtB,CACE,kBAAC,GAAD;IAAW,WAAU;cAArB,CACG,GACA,EACS;OACX,EACU;MACb,kBAAC,GAAD;GAAa,WAAU;aACpB,IACC,kBAAC,GAAD,EAAmB,CAAA,GACjB,IACF,kBAAC,GAAD,EAAY,SAAS,GAAS,CAAA,GAC5B,IACF,kBAAC,GAAD,EAAoB,CAAA,GAEpB;GAEU,CAAA,CACT"}
1
+ {"version":3,"file":"WidgetWrapper.js","names":[],"sources":["../../../src/pages/dashboard/WidgetWrapper.tsx"],"sourcesContent":["/**\n * WidgetWrapper — Common wrapper for all dashboard widgets.\n *\n * Provides consistent card styling, loading skeleton, error state,\n * and unavailable state.\n */\nimport { type ReactNode } from 'react';\nimport { Card, CardContent, CardHeader, CardTitle } from '@burdenoff/fe-libs/ui';\nimport { Skeleton } from '@burdenoff/fe-libs/ui';\nimport { AlertCircle, WifiOff } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { tWithFallback } from '../../utils/i18n';\nimport type { WidgetSize } from './types';\n\ninterface WidgetWrapperProps {\n title: string;\n icon?: ReactNode;\n size: WidgetSize;\n isLoading?: boolean;\n error?: string | null;\n unavailable?: boolean;\n headerAction?: ReactNode;\n children: ReactNode;\n className?: string;\n}\n\nfunction getColSpan(size: WidgetSize): string {\n switch (size) {\n case 'large':\n return 'col-span-1 sm:col-span-2 lg:col-span-3';\n case 'medium':\n return 'col-span-1 sm:col-span-2 lg:col-span-2 xl:col-span-2 2xl:col-span-1';\n case 'small':\n return 'col-span-1';\n default:\n return 'col-span-1';\n }\n}\n\nfunction LoadingSkeleton() {\n return (\n <div className=\"space-y-3 p-1\">\n <Skeleton className=\"h-4 w-3/4\" />\n <Skeleton className=\"h-4 w-1/2\" />\n <Skeleton className=\"h-20 w-full\" />\n <Skeleton className=\"h-4 w-2/3\" />\n </div>\n );\n}\n\nfunction ErrorState({ message }: { message: string }) {\n return (\n <div className=\"flex flex-col items-center justify-center py-6 text-center\">\n <div className=\"rounded-full bg-destructive/10 p-2 mb-2\">\n <AlertCircle className=\"h-5 w-5 text-destructive\" />\n </div>\n <p className=\"text-sm text-muted-foreground\">{message}</p>\n </div>\n );\n}\n\nfunction UnavailableState() {\n const { t } = useI18n();\n\n return (\n <div className=\"flex flex-col items-center justify-center py-6 text-center\">\n <div className=\"rounded-full bg-muted p-2 mb-2\">\n <WifiOff className=\"h-5 w-5 text-muted-foreground\" />\n </div>\n <p className=\"text-sm text-muted-foreground\">\n {tWithFallback(t, 'widgetWrapper.serviceUnavailable', 'Service unavailable')}\n </p>\n </div>\n );\n}\n\nexport function WidgetWrapper({\n title,\n icon,\n size,\n isLoading,\n error,\n unavailable,\n headerAction,\n children,\n className = '',\n}: WidgetWrapperProps) {\n const colSpan = getColSpan(size);\n\n return (\n <Card\n className={`${colSpan} transition-all duration-200 hover:shadow-md border border-border-default bg-bg-surface ${className}`}\n >\n <CardHeader className=\"flex flex-row items-center justify-between pb-2 space-y-0\">\n <CardTitle className=\"text-sm font-semibold text-text-primary flex items-center gap-2\">\n {icon}\n {title}\n </CardTitle>\n {headerAction}\n </CardHeader>\n <CardContent className=\"pt-0\">\n {isLoading ? (\n <LoadingSkeleton />\n ) : error ? (\n <ErrorState message={error} />\n ) : unavailable ? (\n <UnavailableState />\n ) : (\n children\n )}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":";;;;;;AA0BA,SAAS,EAAW,GAA0B;AAC5C,SAAQ,GAAR;EACE,KAAK,QACH,QAAO;EACT,KAAK,SACH,QAAO;EACT,KAAK,QACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,IAAkB;AACzB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GAClC,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GAClC,kBAAC,GAAD,EAAU,WAAU,eAAgB,CAAA;GACpC,kBAAC,GAAD,EAAU,WAAU,aAAc,CAAA;GAC9B;;;AAIV,SAAS,EAAW,EAAE,cAAgC;AACpD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,EAAa,WAAU,4BAA6B,CAAA;GAChD,CAAA,EACN,kBAAC,KAAD;GAAG,WAAU;aAAiC;GAAY,CAAA,CACtD;;;AAIV,SAAS,IAAmB;CAC1B,IAAM,EAAE,MAAM,GAAS;AAEvB,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,OAAD;GAAK,WAAU;aACb,kBAAC,GAAD,EAAS,WAAU,iCAAkC,CAAA;GACjD,CAAA,EACN,kBAAC,KAAD;GAAG,WAAU;aACV,EAAc,GAAG,oCAAoC,sBAAsB;GAC1E,CAAA,CACA;;;AAIV,SAAgB,EAAc,EAC5B,UACA,SACA,SACA,cACA,UACA,gBACA,iBACA,aACA,eAAY,MACS;AAGrB,QACE,kBAAC,GAAD;EACE,WAAW,GAJC,EAAW,EAAK,CAIN,0FAA0F;YADlH,CAGE,kBAAC,GAAD;GAAY,WAAU;aAAtB,CACE,kBAAC,GAAD;IAAW,WAAU;cAArB,CACG,GACA,EACS;OACX,EACU;MACb,kBAAC,GAAD;GAAa,WAAU;aACpB,IACC,kBAAC,GAAD,EAAmB,CAAA,GACjB,IACF,kBAAC,GAAD,EAAY,SAAS,GAAS,CAAA,GAC5B,IACF,kBAAC,GAAD,EAAoB,CAAA,GAEpB;GAEU,CAAA,CACT"}
@@ -0,0 +1,13 @@
1
+ import { I18nContextValue } from '@burdenoff/fe-libs/shared/providers/shell';
2
+
3
+ type TranslationParams = Record<string, string | number>;
4
+ /**
5
+ * Translate `key` and fall back to `fallback` when the i18n provider
6
+ * returns the key itself (the convention shell's `useI18n().t(...)` uses
7
+ * to indicate a missing translation). Optional `params` are forwarded to
8
+ * the translator and also used for `{name}` style interpolation in the
9
+ * fallback string.
10
+ */
11
+ export declare function tWithFallback(t: I18nContextValue['t'], key: string, fallback: string, params?: TranslationParams): string;
12
+ export {};
13
+ //# sourceMappingURL=i18n.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/utils/i18n.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAElF,KAAK,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEzD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,gBAAgB,CAAC,GAAG,CAAC,EACxB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,iBAAiB,GACzB,MAAM,CAUR"}
@@ -0,0 +1,12 @@
1
+ //#region src/utils/i18n.ts
2
+ function e(e, t, n, r) {
3
+ let i = e(t, r);
4
+ return i === t ? r ? n.replace(/\{(\w+)\}/g, (e, t) => {
5
+ let n = r[t];
6
+ return n === void 0 ? e : String(n);
7
+ }) : n : i;
8
+ }
9
+ //#endregion
10
+ export { e as tWithFallback };
11
+
12
+ //# sourceMappingURL=i18n.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"i18n.js","names":[],"sources":["../../src/utils/i18n.ts"],"sourcesContent":["import type { I18nContextValue } from '@burdenoff/fe-libs/shared/providers/shell';\n\ntype TranslationParams = Record<string, string | number>;\n\n/**\n * Translate `key` and fall back to `fallback` when the i18n provider\n * returns the key itself (the convention shell's `useI18n().t(...)` uses\n * to indicate a missing translation). Optional `params` are forwarded to\n * the translator and also used for `{name}` style interpolation in the\n * fallback string.\n */\nexport function tWithFallback(\n t: I18nContextValue['t'],\n key: string,\n fallback: string,\n params?: TranslationParams\n): string {\n const translated = t(key, params);\n if (translated !== key) {\n return translated;\n }\n if (!params) return fallback;\n return fallback.replace(/\\{(\\w+)\\}/g, (match, name: string) => {\n const value = params[name];\n return value === undefined ? match : String(value);\n });\n}\n"],"mappings":";AAWA,SAAgB,EACd,GACA,GACA,GACA,GACQ;CACR,IAAM,IAAa,EAAE,GAAK,EAAO;AAKjC,QAJI,MAAe,IAGd,IACE,EAAS,QAAQ,eAAe,GAAO,MAAiB;EAC7D,IAAM,IAAQ,EAAO;AACrB,SAAO,MAAU,KAAA,IAAY,IAAQ,OAAO,EAAM;GAClD,GAJkB,IAFX"}
@@ -0,0 +1,2 @@
1
+ export declare function safeTelemetryError(err: unknown): string;
2
+ //# sourceMappingURL=telemetryError.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetryError.d.ts","sourceRoot":"","sources":["../../src/utils/telemetryError.ts"],"names":[],"mappings":"AAwDA,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAIvD"}
@@ -0,0 +1,28 @@
1
+ //#region src/utils/telemetryError.ts
2
+ var e = 200;
3
+ function t(e) {
4
+ if (typeof e != "object" || !e) return !1;
5
+ let t = e;
6
+ if (typeof t.message != "string") return !1;
7
+ let n = Array.isArray(t.graphQLErrors), r = t.networkError instanceof Error;
8
+ return n || r;
9
+ }
10
+ function n(e) {
11
+ if (e == null) return "An unknown error occurred";
12
+ if (t(e)) {
13
+ if (e.graphQLErrors && e.graphQLErrors.length > 0) {
14
+ let t = e.graphQLErrors.map((e) => typeof e?.message == "string" ? e.message : "").filter((e) => e.length > 0);
15
+ if (t.length > 0) return t.join(", ");
16
+ }
17
+ return e.networkError ? "Network error. Please check your connection." : e.message;
18
+ }
19
+ return e instanceof Error ? e.message : typeof e == "string" ? e : String(e);
20
+ }
21
+ function r(t) {
22
+ let r = n(t);
23
+ return r.length <= e ? r : `${r.slice(0, e - 1)}…`;
24
+ }
25
+ //#endregion
26
+ export { r as safeTelemetryError };
27
+
28
+ //# sourceMappingURL=telemetryError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetryError.js","names":[],"sources":["../../src/utils/telemetryError.ts"],"sourcesContent":["/**\n * Build a payload-safe error string for the event bus / OtelBrowserSink.\n *\n * Apollo errors expose a `graphQLErrors[*].message` array — these are the\n * server-sanitized messages. For native Errors and arbitrary throws we fall\n * back to `.message` / String coercion. Everything is capped at 200 chars\n * so stack frames or SQL fragments that slip through don't end up in audit\n * sinks. Keep in sync with SRE guide §7.\n *\n * Trust assumption: server error messages are assumed sanitized. Callers\n * MUST NOT pass raw user input through this helper — its job is to bound\n * the size and shape, not to scrub PII.\n */\nconst MAX_TELEMETRY_ERROR_LEN = 200;\n\ninterface ApolloErrorLike {\n graphQLErrors?: Array<{ message: string }>;\n networkError?: Error & { statusCode?: number };\n message: string;\n}\n\nfunction isApolloErrorLike(err: unknown): err is ApolloErrorLike {\n if (typeof err !== 'object' || err === null) return false;\n const e = err as Record<string, unknown>;\n // Must look like an Apollo error in shape, not just key-presence:\n // - `graphQLErrors`, when present, must be an array (null / wrong-type\n // versions of the property silently passed the old guard).\n // - `networkError`, when present, must be an Error instance.\n // - `message` must be a string (Apollo always sets one).\n if (typeof e['message'] !== 'string') return false;\n const hasArrayGqlErrors = Array.isArray(e['graphQLErrors']);\n const hasErrorNetwork = e['networkError'] instanceof Error;\n return hasArrayGqlErrors || hasErrorNetwork;\n}\n\nfunction rawMessage(err: unknown): string {\n if (err == null) return 'An unknown error occurred';\n if (isApolloErrorLike(err)) {\n if (err.graphQLErrors && err.graphQLErrors.length > 0) {\n // Filter out anything without a string message — wrong-shape entries\n // would otherwise stringify to \"undefined\" and dilute the output.\n const messages = err.graphQLErrors\n .map((e) => (typeof e?.message === 'string' ? e.message : ''))\n .filter((m) => m.length > 0);\n if (messages.length > 0) return messages.join(', ');\n }\n if (err.networkError) {\n return 'Network error. Please check your connection.';\n }\n return err.message;\n }\n if (err instanceof Error) return err.message;\n if (typeof err === 'string') return err;\n return String(err);\n}\n\nexport function safeTelemetryError(err: unknown): string {\n const msg = rawMessage(err);\n if (msg.length <= MAX_TELEMETRY_ERROR_LEN) return msg;\n return `${msg.slice(0, MAX_TELEMETRY_ERROR_LEN - 1)}…`;\n}\n"],"mappings":";AAaA,IAAM,IAA0B;AAQhC,SAAS,EAAkB,GAAsC;AAC/D,KAAI,OAAO,KAAQ,aAAY,EAAc,QAAO;CACpD,IAAM,IAAI;AAMV,KAAI,OAAO,EAAE,WAAe,SAAU,QAAO;CAC7C,IAAM,IAAoB,MAAM,QAAQ,EAAE,cAAiB,EACrD,IAAkB,EAAE,wBAA2B;AACrD,QAAO,KAAqB;;AAG9B,SAAS,EAAW,GAAsB;AACxC,KAAI,KAAO,KAAM,QAAO;AACxB,KAAI,EAAkB,EAAI,EAAE;AAC1B,MAAI,EAAI,iBAAiB,EAAI,cAAc,SAAS,GAAG;GAGrD,IAAM,IAAW,EAAI,cAClB,KAAK,MAAO,OAAO,GAAG,WAAY,WAAW,EAAE,UAAU,GAAI,CAC7D,QAAQ,MAAM,EAAE,SAAS,EAAE;AAC9B,OAAI,EAAS,SAAS,EAAG,QAAO,EAAS,KAAK,KAAK;;AAKrD,SAHI,EAAI,eACC,iDAEF,EAAI;;AAIb,QAFI,aAAe,QAAc,EAAI,UACjC,OAAO,KAAQ,WAAiB,IAC7B,OAAO,EAAI;;AAGpB,SAAgB,EAAmB,GAAsB;CACvD,IAAM,IAAM,EAAW,EAAI;AAE3B,QADI,EAAI,UAAU,IAAgC,IAC3C,GAAG,EAAI,MAAM,GAAG,IAA0B,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-workspaces",
3
- "version": "2026.510.50",
3
+ "version": "2026.511.1",
4
4
  "description": "Workspaces microfrontend for Burdenoff products",
5
5
  "type": "module",
6
6
  "files": [
@@ -29,7 +29,10 @@
29
29
  "format": "prettier --write \"src/**/*.{ts,tsx}\"",
30
30
  "format:check": "prettier --check \"src/**/*.{ts,tsx}\"",
31
31
  "type:check": "tsc --noEmit",
32
- "sanity": "bun run codegen && bun run lint:sanity && bun run format && bun run type:check && bun run build",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest",
34
+ "test:coverage": "vitest run --coverage",
35
+ "sanity": "bun run codegen && bun run lint:sanity && bun run format && bun run type:check && bun run build && bun run test",
33
36
  "schema:pull": "graphql-codegen --project schema-wspace && graphql-codegen --project schema-global",
34
37
  "codegen": "graphql-codegen --project wspace && graphql-codegen --project global",
35
38
  "codegen:all": "bun run schema:pull && bun run codegen",
@@ -41,7 +44,7 @@
41
44
  },
42
45
  "dependencies": {
43
46
  "@apollo/client": "^4.0.11",
44
- "@burdenoff/fe-libs": "2026.507.125",
47
+ "@burdenoff/fe-libs": "2026.511.2",
45
48
  "@iconify/react": "^6.0.2",
46
49
  "@radix-ui/react-icons": "^1.3.2",
47
50
  "@tanstack/react-query": "^5.62.13",
@@ -82,7 +85,9 @@
82
85
  "typescript": "^5.9.0",
83
86
  "typescript-eslint": "^8.46.0",
84
87
  "vite": "8.0.8",
85
- "vite-plugin-dts": "3.9.1"
88
+ "vite-plugin-dts": "3.9.1",
89
+ "vitest": "^3.2.4",
90
+ "@vitest/coverage-v8": "^3.2.4"
86
91
  },
87
92
  "peerDependencies": {
88
93
  "@apollo/client": "^4.0.11",