@burdenoff/microfe-planmagnet 2026.1001.6 → 2026.1001.8

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 (94) hide show
  1. package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
  2. package/dist/planmagnet/PlanMagnetRoutes.js +10 -6
  3. package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
  4. package/dist/planmagnet/automation/automationRuleTypes.d.ts +31 -19
  5. package/dist/planmagnet/automation/automationRuleTypes.d.ts.map +1 -1
  6. package/dist/planmagnet/automation/automationRuleTypes.js +4 -8
  7. package/dist/planmagnet/automation/automationRuleTypes.js.map +1 -1
  8. package/dist/planmagnet/controls/FeatureControls.d.ts +18 -1
  9. package/dist/planmagnet/controls/FeatureControls.d.ts.map +1 -1
  10. package/dist/planmagnet/controls/FeatureControls.js +259 -202
  11. package/dist/planmagnet/controls/FeatureControls.js.map +1 -1
  12. package/dist/planmagnet/controls/FeedbackControls.d.ts +70 -0
  13. package/dist/planmagnet/controls/FeedbackControls.d.ts.map +1 -0
  14. package/dist/planmagnet/controls/FeedbackControls.js +153 -0
  15. package/dist/planmagnet/controls/FeedbackControls.js.map +1 -0
  16. package/dist/planmagnet/controls/SyncControls.d.ts.map +1 -1
  17. package/dist/planmagnet/controls/SyncControls.js +1 -0
  18. package/dist/planmagnet/controls/SyncControls.js.map +1 -1
  19. package/dist/planmagnet/controls/WebhookSubscriptionControls.d.ts +47 -0
  20. package/dist/planmagnet/controls/WebhookSubscriptionControls.d.ts.map +1 -0
  21. package/dist/planmagnet/controls/WebhookSubscriptionControls.js +542 -0
  22. package/dist/planmagnet/controls/WebhookSubscriptionControls.js.map +1 -0
  23. package/dist/planmagnet/dashboards/DashboardUI.js +7 -7
  24. package/dist/planmagnet/dashboards/cards/RiskSeverityCard.js +4 -4
  25. package/dist/planmagnet/forecast/DeliveryForecastCard.js +8 -8
  26. package/dist/planmagnet/forecast/ProjectOutlookCard.js +10 -10
  27. package/dist/planmagnet/forecast/ProjectRiskSummaryCard.js +9 -9
  28. package/dist/planmagnet/forecast/ResourceForecastCard.js +6 -6
  29. package/dist/planmagnet/hooks/useLiveRefresh.d.ts +33 -2
  30. package/dist/planmagnet/hooks/useLiveRefresh.d.ts.map +1 -1
  31. package/dist/planmagnet/hooks/useLiveRefresh.js +71 -42
  32. package/dist/planmagnet/hooks/useLiveRefresh.js.map +1 -1
  33. package/dist/planmagnet/integrations/syncTypes.d.ts +2 -1
  34. package/dist/planmagnet/integrations/syncTypes.d.ts.map +1 -1
  35. package/dist/planmagnet/integrations/syncTypes.js +19 -9
  36. package/dist/planmagnet/integrations/syncTypes.js.map +1 -1
  37. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +8 -8
  38. package/dist/planmagnet/pages/DashboardDashboardPagePage.js +23 -23
  39. package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
  40. package/dist/planmagnet/pages/DocsDocDetailPagePage.js +340 -248
  41. package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
  42. package/dist/planmagnet/pages/IntegrationsSyncDetailPagePage.d.ts.map +1 -1
  43. package/dist/planmagnet/pages/IntegrationsSyncDetailPagePage.js +172 -167
  44. package/dist/planmagnet/pages/IntegrationsSyncDetailPagePage.js.map +1 -1
  45. package/dist/planmagnet/pages/IntegrationsSyncsPagePage.d.ts.map +1 -1
  46. package/dist/planmagnet/pages/IntegrationsSyncsPagePage.js +92 -83
  47. package/dist/planmagnet/pages/IntegrationsSyncsPagePage.js.map +1 -1
  48. package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.d.ts +2 -0
  49. package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.d.ts.map +1 -0
  50. package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.js +175 -0
  51. package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.js.map +1 -0
  52. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
  53. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +151 -126
  54. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
  55. package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
  56. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +136 -129
  57. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
  58. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
  59. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +149 -119
  60. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
  61. package/dist/planmagnet/pages/ProductsProductsPagePage.js +13 -13
  62. package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.d.ts.map +1 -1
  63. package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js +153 -117
  64. package/dist/planmagnet/pages/ProductsRoadmapAnalyticsPagePage.js.map +1 -1
  65. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.d.ts.map +1 -1
  66. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js +173 -138
  67. package/dist/planmagnet/pages/ProductsRoadmapDetailPagePage.js.map +1 -1
  68. package/dist/planmagnet/pages/ProjectsAtRiskPagePage.js +9 -9
  69. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +8 -8
  70. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +12 -12
  71. package/dist/planmagnet/pages/ReportsReportsPagePage.js +23 -23
  72. package/dist/planmagnet/pages/TasksMyDashboardPagePage.js +18 -18
  73. package/dist/planmagnet/pages/TasksMyWorkPagePage.js +10 -10
  74. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js +5 -5
  75. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +8 -8
  76. package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js +6 -6
  77. package/dist/planmagnet/pages/analytics/MetricsCard.js +6 -6
  78. package/dist/planmagnet/pages/analytics/QualityMetricsCard.js +6 -6
  79. package/dist/planmagnet/pages/analytics/SprintDeliveryCards.js +8 -8
  80. package/dist/planmagnet/pages/analytics/StatusFlowCard.js +7 -7
  81. package/dist/planmagnet/pages/analytics/ThroughputCard.js +7 -7
  82. package/dist/planmagnet/pages/analytics/WorkBreakdownCard.js +7 -7
  83. package/dist/planmagnet/people/People.d.ts +14 -0
  84. package/dist/planmagnet/people/People.d.ts.map +1 -1
  85. package/dist/planmagnet/people/People.js +36 -22
  86. package/dist/planmagnet/people/People.js.map +1 -1
  87. package/dist/planmagnet/roadmaps/RoadmapNowNextLater.d.ts.map +1 -1
  88. package/dist/planmagnet/roadmaps/RoadmapNowNextLater.js +171 -153
  89. package/dist/planmagnet/roadmaps/RoadmapNowNextLater.js.map +1 -1
  90. package/dist/planmagnet/webhooks/webhookTypes.d.ts +54 -0
  91. package/dist/planmagnet/webhooks/webhookTypes.d.ts.map +1 -0
  92. package/dist/planmagnet/webhooks/webhookTypes.js +17 -0
  93. package/dist/planmagnet/webhooks/webhookTypes.js.map +1 -0
  94. package/package.json +1 -1
@@ -3,8 +3,8 @@ import { Timer as i, Wallet as a } from "lucide-react";
3
3
  import { gql as o } from "@apollo/client";
4
4
  import { useQuery as s } from "@apollo/client/react";
5
5
  import { jsx as c, jsxs as l } from "react/jsx-runtime";
6
- import { useI18n as u } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
- import { Card as d, CardContent as f, CardHeader as p, CardTitle as m } from "@burdenoff/fe-libs/ui";
6
+ import { Card as u, CardContent as d, CardHeader as f, CardTitle as p } from "@burdenoff/fe-libs/ui";
7
+ import { useI18n as m } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
8
8
  //#region src/planmagnet/pages/analytics/DeliveryHealthCards.tsx
9
9
  var h = o`
10
10
  query GetProjectCycleTime(
@@ -79,7 +79,7 @@ function v({ label: e, value: t, hint: n }) {
79
79
  });
80
80
  }
81
81
  function y({ workspaceId: e, projectId: t, startDate: n, endDate: r }) {
82
- let { t: a } = u(), { data: o, loading: g, error: y } = s(h, {
82
+ let { t: a } = m(), { data: o, loading: g, error: y } = s(h, {
83
83
  variables: {
84
84
  workspaceId: e,
85
85
  projectId: t,
@@ -88,13 +88,13 @@ function y({ workspaceId: e, projectId: t, startDate: n, endDate: r }) {
88
88
  },
89
89
  skip: !e || !t
90
90
  }), b = o?.planmagnetCycleTime, x = [...b?.items ?? []].sort((e, t) => t.cycleTimeHours - e.cycleTimeHours).slice(0, 5);
91
- return /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ l(p, { children: [/* @__PURE__ */ l(m, {
91
+ return /* @__PURE__ */ l(u, { children: [/* @__PURE__ */ l(f, { children: [/* @__PURE__ */ l(p, {
92
92
  className: "flex items-center gap-2",
93
93
  children: [/* @__PURE__ */ c(i, { className: "h-4 w-4" }), a("planmagnet.analytics.cycleTime.title", "Cycle time")]
94
94
  }), /* @__PURE__ */ c("p", {
95
95
  className: "text-xs text-muted-foreground",
96
96
  children: a("planmagnet.analytics.cycleTime.subtitle", "From first moving to In Progress (or creation) to Done, for the selected project.")
97
- })] }), /* @__PURE__ */ c(f, { children: t ? g ? /* @__PURE__ */ c("p", {
97
+ })] }), /* @__PURE__ */ c(d, { children: t ? g ? /* @__PURE__ */ c("p", {
98
98
  className: "text-sm text-muted-foreground",
99
99
  children: a("planmagnet.analytics.loading", "Loading…")
100
100
  }) : y ? /* @__PURE__ */ l("p", {
@@ -171,7 +171,7 @@ function y({ workspaceId: e, projectId: t, startDate: n, endDate: r }) {
171
171
  }) })] });
172
172
  }
173
173
  function b({ workspaceId: i, projectId: o }) {
174
- let { t: h } = u(), { data: _, loading: v, error: y } = s(g, {
174
+ let { t: h } = m(), { data: _, loading: v, error: y } = s(g, {
175
175
  variables: {
176
176
  workspaceId: i,
177
177
  filter: o ? { projectId: o } : void 0
@@ -183,7 +183,7 @@ function b({ workspaceId: i, projectId: o }) {
183
183
  "near-limit": h("planmagnet.analytics.budget.nearLimit", "Near limit"),
184
184
  "over-budget": h("planmagnet.analytics.budget.over", "Over budget")
185
185
  };
186
- return /* @__PURE__ */ l(d, { children: [/* @__PURE__ */ l(p, { children: [/* @__PURE__ */ l(m, {
186
+ return /* @__PURE__ */ l(u, { children: [/* @__PURE__ */ l(f, { children: [/* @__PURE__ */ l(p, {
187
187
  className: "flex items-center gap-2",
188
188
  children: [/* @__PURE__ */ c(a, { className: "h-4 w-4" }), h("planmagnet.analytics.budget.title", "Budget performance")]
189
189
  }), /* @__PURE__ */ c("p", {
@@ -192,7 +192,7 @@ function b({ workspaceId: i, projectId: o }) {
192
192
  shown: b.length,
193
193
  total: x
194
194
  }) : o ? h("planmagnet.analytics.budget.subtitleProject", "Spent against plan, per budget, for the selected project.") : h("planmagnet.analytics.budget.subtitle", "Spent against plan, per budget, across the workspace.")
195
- })] }), /* @__PURE__ */ c(f, { children: v ? /* @__PURE__ */ c("p", {
195
+ })] }), /* @__PURE__ */ c(d, { children: v ? /* @__PURE__ */ c("p", {
196
196
  className: "text-sm text-muted-foreground",
197
197
  children: h("planmagnet.analytics.loading", "Loading…")
198
198
  }) : y ? /* @__PURE__ */ l("p", {
@@ -3,8 +3,8 @@ import { Info as t, Target as n } from "lucide-react";
3
3
  import { gql as r } from "@apollo/client";
4
4
  import { useQuery as i } from "@apollo/client/react";
5
5
  import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
- import { useI18n as s } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
- import { Card as c, CardContent as l, CardHeader as u, CardTitle as d } from "@burdenoff/fe-libs/ui";
6
+ import { Card as s, CardContent as c, CardHeader as l, CardTitle as u } from "@burdenoff/fe-libs/ui";
7
+ import { useI18n as d } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
8
8
  //#region src/planmagnet/pages/analytics/DeliveryKpisCard.tsx
9
9
  var f = r`
10
10
  query GetAnalyticsDeliveryKpis(
@@ -71,7 +71,7 @@ function p({ label: e, onTime: t, total: n, withoutPlan: r, rate: i, noPlanNoun:
71
71
  });
72
72
  }
73
73
  function m({ workspaceId: r, projectId: m, startDate: h, endDate: g }) {
74
- let { t: _ } = s(), { data: v, loading: y, error: b } = i(f, {
74
+ let { t: _ } = d(), { data: v, loading: y, error: b } = i(f, {
75
75
  variables: {
76
76
  workspaceId: r,
77
77
  projectId: m,
@@ -80,15 +80,15 @@ function m({ workspaceId: r, projectId: m, startDate: h, endDate: g }) {
80
80
  },
81
81
  skip: !r
82
82
  }), x = v?.planmagnetDeliveryKpis, S = x?.scopeAdherence, C = S?.adherenceRate == null ? null : Math.round(S.adherenceRate * 100);
83
- return /* @__PURE__ */ o(c, {
83
+ return /* @__PURE__ */ o(s, {
84
84
  "data-testid": "delivery-card",
85
- children: [/* @__PURE__ */ o(u, { children: [/* @__PURE__ */ o(d, {
85
+ children: [/* @__PURE__ */ o(l, { children: [/* @__PURE__ */ o(u, {
86
86
  className: "flex items-center gap-2",
87
87
  children: [/* @__PURE__ */ a(n, { className: "h-4 w-4" }), _("planmagnet.analytics.delivery.kpiTitle", "Delivery")]
88
88
  }), /* @__PURE__ */ a("p", {
89
89
  className: "text-xs text-muted-foreground",
90
90
  children: _("planmagnet.analytics.delivery.kpiSubtitle", "On-time delivery and scope adherence, for sprints/releases/milestones completed in the selected range.")
91
- })] }), /* @__PURE__ */ a(l, { children: y ? /* @__PURE__ */ a("p", {
91
+ })] }), /* @__PURE__ */ a(c, { children: y ? /* @__PURE__ */ a("p", {
92
92
  className: "text-sm text-muted-foreground",
93
93
  children: _("planmagnet.analytics.loading", "Loading…")
94
94
  }) : b ? /* @__PURE__ */ o("p", {
@@ -3,8 +3,8 @@ import { Activity as n, Info as r } from "lucide-react";
3
3
  import { gql as i } from "@apollo/client";
4
4
  import { useQuery as a } from "@apollo/client/react";
5
5
  import { jsx as o, jsxs as s } from "react/jsx-runtime";
6
- import { useI18n as c } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
- import { Card as l, CardContent as u, CardHeader as d, CardTitle as f } from "@burdenoff/fe-libs/ui";
6
+ import { Card as c, CardContent as l, CardHeader as u, CardTitle as d } from "@burdenoff/fe-libs/ui";
7
+ import { useI18n as f } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
8
8
  //#region src/planmagnet/pages/analytics/MetricsCard.tsx
9
9
  var p = i`
10
10
  query GetWorkspaceMetrics($workspaceId: ID!, $timeRange: PlanmagnetTimeRangeInput) {
@@ -69,7 +69,7 @@ function v({ metric: t }) {
69
69
  });
70
70
  }
71
71
  function y({ workspaceId: e, projectId: t, startDate: i, endDate: h }) {
72
- let { t: g } = c(), _ = {
72
+ let { t: g } = f(), _ = {
73
73
  startDate: i,
74
74
  endDate: h
75
75
  }, { data: y, loading: b, error: x } = a(p, {
@@ -86,15 +86,15 @@ function y({ workspaceId: e, projectId: t, startDate: i, endDate: h }) {
86
86
  },
87
87
  skip: !e || !t
88
88
  }), T = y?.planmagnetMetrics ?? [], E = S?.planmagnetAnalytics.projectMetrics ?? [], D = S?.planmagnetAnalytics.teamMetrics ?? [], O = [...E, ...D];
89
- return /* @__PURE__ */ s(l, {
89
+ return /* @__PURE__ */ s(c, {
90
90
  "data-testid": "metrics-card",
91
- children: [/* @__PURE__ */ s(d, { children: [/* @__PURE__ */ s(f, {
91
+ children: [/* @__PURE__ */ s(u, { children: [/* @__PURE__ */ s(d, {
92
92
  className: "flex items-center gap-2",
93
93
  children: [/* @__PURE__ */ o(n, { className: "h-4 w-4" }), g("planmagnet.analytics.metrics.title", "Metrics")]
94
94
  }), /* @__PURE__ */ o("p", {
95
95
  className: "text-xs text-muted-foreground",
96
96
  children: g("planmagnet.analytics.metrics.subtitle", "Workspace-wide KPIs, plus the selected project's own metrics, composed from the queries above into one generic shape.")
97
- })] }), /* @__PURE__ */ s(u, {
97
+ })] }), /* @__PURE__ */ s(l, {
98
98
  className: "space-y-4",
99
99
  children: [
100
100
  /* @__PURE__ */ s("div", { children: [/* @__PURE__ */ o("h3", {
@@ -12,8 +12,8 @@ import { Bug as d } from "lucide-react";
12
12
  import { gql as f } from "@apollo/client";
13
13
  import { useQuery as p } from "@apollo/client/react";
14
14
  import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
15
- import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
16
- import { Card as v, CardContent as y, CardHeader as b, CardTitle as x } from "@burdenoff/fe-libs/ui";
15
+ import { Card as _, CardContent as v, CardHeader as y, CardTitle as b } from "@burdenoff/fe-libs/ui";
16
+ import { useI18n as x } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
17
17
  //#region src/planmagnet/pages/analytics/QualityMetricsCard.tsx
18
18
  var S = f`
19
19
  query GetAnalyticsQualityMetrics(
@@ -56,7 +56,7 @@ var S = f`
56
56
  NONE: "var(--color-chart-axis)"
57
57
  };
58
58
  function T({ workspaceId: f, projectId: T, startDate: E, endDate: D }) {
59
- let { t: O } = _(), { data: k, loading: A, error: j } = p(S, {
59
+ let { t: O } = x(), { data: k, loading: A, error: j } = p(S, {
60
60
  variables: {
61
61
  workspaceId: f,
62
62
  projectId: T,
@@ -69,15 +69,15 @@ function T({ workspaceId: f, projectId: T, startDate: E, endDate: D }) {
69
69
  count: N.get(e) ?? 0,
70
70
  fill: w[e]
71
71
  }));
72
- return /* @__PURE__ */ g(v, {
72
+ return /* @__PURE__ */ g(_, {
73
73
  "data-testid": "quality-card",
74
- children: [/* @__PURE__ */ g(b, { children: [/* @__PURE__ */ g(x, {
74
+ children: [/* @__PURE__ */ g(y, { children: [/* @__PURE__ */ g(b, {
75
75
  className: "flex items-center gap-2",
76
76
  children: [/* @__PURE__ */ h(d, { className: "h-4 w-4" }), O("planmagnet.analytics.quality.title", "Quality")]
77
77
  }), /* @__PURE__ */ h("p", {
78
78
  className: "text-xs text-muted-foreground",
79
79
  children: T ? O("planmagnet.analytics.quality.subtitleProject", "Bug and quality-gate activity for the selected project, in the selected range.") : O("planmagnet.analytics.quality.subtitle", "Bug and quality-gate activity across the workspace, in the selected range.")
80
- })] }), /* @__PURE__ */ h(y, { children: A ? /* @__PURE__ */ h("p", {
80
+ })] }), /* @__PURE__ */ h(v, { children: A ? /* @__PURE__ */ h("p", {
81
81
  className: "text-sm text-muted-foreground",
82
82
  children: O("planmagnet.analytics.loading", "Loading…")
83
83
  }) : j ? /* @__PURE__ */ g("p", {
@@ -14,8 +14,8 @@ import { BarChart3 as f, TrendingUp as p } from "lucide-react";
14
14
  import { gql as m } from "@apollo/client";
15
15
  import { useQuery as h } from "@apollo/client/react";
16
16
  import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
17
- import { useI18n as y } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
18
- import { Card as b, CardContent as x, CardHeader as S, CardTitle as C } from "@burdenoff/fe-libs/ui";
17
+ import { Card as y, CardContent as b, CardHeader as x, CardTitle as S } from "@burdenoff/fe-libs/ui";
18
+ import { useI18n as C } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
19
19
  //#region src/planmagnet/pages/analytics/SprintDeliveryCards.tsx
20
20
  var w = m`
21
21
  query DashboardSprintBurndown($workspaceId: ID!, $sprintId: ID!) {
@@ -60,7 +60,7 @@ function E(e) {
60
60
  return `${t.getUTCMonth() + 1}/${t.getUTCDate()}`;
61
61
  }
62
62
  function D({ workspaceId: r, sprintId: i }) {
63
- let { t: a } = y(), { data: d, loading: p, error: m } = h(w, {
63
+ let { t: a } = C(), { data: d, loading: p, error: m } = h(w, {
64
64
  variables: {
65
65
  workspaceId: r,
66
66
  sprintId: i
@@ -71,13 +71,13 @@ function D({ workspaceId: r, sprintId: i }) {
71
71
  remaining: e.remainingPoints,
72
72
  completed: e.completedPoints
73
73
  }));
74
- return /* @__PURE__ */ v(b, { children: [/* @__PURE__ */ v(S, { children: [/* @__PURE__ */ v(C, {
74
+ return /* @__PURE__ */ v(y, { children: [/* @__PURE__ */ v(x, { children: [/* @__PURE__ */ v(S, {
75
75
  className: "flex items-center gap-2",
76
76
  children: [/* @__PURE__ */ _(f, { className: "h-4 w-4" }), a("planmagnet.dashboards.burndown.title", "Sprint burndown")]
77
77
  }), /* @__PURE__ */ _("p", {
78
78
  className: "text-xs text-muted-foreground",
79
79
  children: a("planmagnet.dashboards.burndown.subtitle", "Remaining vs. completed story points, by day of the sprint.")
80
- })] }), /* @__PURE__ */ _(x, { children: i ? p && !d ? /* @__PURE__ */ _("p", {
80
+ })] }), /* @__PURE__ */ _(b, { children: i ? p && !d ? /* @__PURE__ */ _("p", {
81
81
  className: "text-sm text-muted-foreground",
82
82
  children: a("planmagnet.dashboards.loading", "Loading…")
83
83
  }) : m ? /* @__PURE__ */ v("p", {
@@ -135,7 +135,7 @@ function D({ workspaceId: r, sprintId: i }) {
135
135
  }) })] });
136
136
  }
137
137
  function O({ workspaceId: s, projectId: u, trailingSprintCount: f = 6 }) {
138
- let { t: m } = y(), { data: w, loading: E, error: D } = h(T, {
138
+ let { t: m } = C(), { data: w, loading: E, error: D } = h(T, {
139
139
  variables: {
140
140
  workspaceId: s,
141
141
  projectId: u,
@@ -147,13 +147,13 @@ function O({ workspaceId: s, projectId: u, trailingSprintCount: f = 6 }) {
147
147
  completed: e.completedPoints,
148
148
  planned: e.plannedPoints ?? void 0
149
149
  })) ?? [], A = O ? Math.round(O.averageVelocity) : 0, j = O ? Math.round(O.forecastNextSprintPoints) : 0, M = O?.forecastRange ?? null, N = O?.insufficientHistory ?? !1;
150
- return /* @__PURE__ */ v(b, { children: [/* @__PURE__ */ v(S, { children: [/* @__PURE__ */ v(C, {
150
+ return /* @__PURE__ */ v(y, { children: [/* @__PURE__ */ v(x, { children: [/* @__PURE__ */ v(S, {
151
151
  className: "flex items-center gap-2",
152
152
  children: [/* @__PURE__ */ _(p, { className: "h-4 w-4" }), m("planmagnet.dashboards.velocity.title", "Sprint velocity")]
153
153
  }), /* @__PURE__ */ _("p", {
154
154
  className: "text-xs text-muted-foreground",
155
155
  children: m("planmagnet.dashboards.velocity.subtitle", "Completed story points per sprint, across the trailing {{count}} completed sprints.", { count: f })
156
- })] }), /* @__PURE__ */ _(x, { children: u ? E && !w ? /* @__PURE__ */ _("p", {
156
+ })] }), /* @__PURE__ */ _(b, { children: u ? E && !w ? /* @__PURE__ */ _("p", {
157
157
  className: "text-sm text-muted-foreground",
158
158
  children: m("planmagnet.dashboards.loading", "Loading…")
159
159
  }) : D ? /* @__PURE__ */ v("p", {
@@ -9,8 +9,8 @@ import { Workflow as c } from "lucide-react";
9
9
  import { gql as l } from "@apollo/client";
10
10
  import { useQuery as u } from "@apollo/client/react";
11
11
  import { jsx as d, jsxs as f } from "react/jsx-runtime";
12
- import { useI18n as p } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
13
- import { Card as m, CardContent as h, CardHeader as g, CardTitle as _ } from "@burdenoff/fe-libs/ui";
12
+ import { Card as p, CardContent as m, CardHeader as h, CardTitle as g } from "@burdenoff/fe-libs/ui";
13
+ import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
14
14
  //#region src/planmagnet/pages/analytics/StatusFlowCard.tsx
15
15
  var v = l`
16
16
  query GetAnalyticsStatusFlow(
@@ -93,7 +93,7 @@ function w({ sourceX: e, sourceY: t, targetX: n, targetY: r, sourceControlX: i,
93
93
  });
94
94
  }
95
95
  function T({ workspaceId: i, projectId: o, startDate: l, endDate: b }) {
96
- let { t: T } = p(), E = s(() => x(l, b), [l, b]), { data: D, loading: O, error: k } = u(v, {
96
+ let { t: T } = _(), E = s(() => x(l, b), [l, b]), { data: D, loading: O, error: k } = u(v, {
97
97
  variables: {
98
98
  workspaceId: i,
99
99
  projectId: o,
@@ -102,10 +102,10 @@ function T({ workspaceId: i, projectId: o, startDate: l, endDate: b }) {
102
102
  },
103
103
  skip: !i || !o
104
104
  }), A = D?.planmagnetStatusFlow ?? [], { nodes: j, links: M } = S(A), N = [...A].sort((e, t) => t.count - e.count);
105
- return /* @__PURE__ */ f(m, {
105
+ return /* @__PURE__ */ f(p, {
106
106
  "data-testid": "status-flow-card",
107
- children: [/* @__PURE__ */ f(g, { children: [
108
- /* @__PURE__ */ f(_, {
107
+ children: [/* @__PURE__ */ f(h, { children: [
108
+ /* @__PURE__ */ f(g, {
109
109
  className: "flex items-center gap-2",
110
110
  children: [/* @__PURE__ */ d(c, { className: "h-4 w-4" }), T("planmagnet.analytics.statusFlow.title", "Status flow")]
111
111
  }),
@@ -120,7 +120,7 @@ function T({ workspaceId: i, projectId: o, startDate: l, endDate: b }) {
120
120
  from: E.from.slice(0, 10)
121
121
  })
122
122
  })
123
- ] }), /* @__PURE__ */ d(h, { children: o ? O && !D ? /* @__PURE__ */ d("div", {
123
+ ] }), /* @__PURE__ */ d(m, { children: o ? O && !D ? /* @__PURE__ */ d("div", {
124
124
  className: "flex justify-center py-12",
125
125
  children: /* @__PURE__ */ d("div", { className: "animate-spin h-6 w-6 border-2 border-primary border-t-transparent rounded-full" })
126
126
  }) : k ? /* @__PURE__ */ d("p", {
@@ -11,8 +11,8 @@ import { BarChart3 as l } from "lucide-react";
11
11
  import { gql as u } from "@apollo/client";
12
12
  import { useQuery as d } from "@apollo/client/react";
13
13
  import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
14
- import { useI18n as h } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
15
- import { Card as g, CardContent as _, CardHeader as v, CardTitle as y } from "@burdenoff/fe-libs/ui";
14
+ import { Card as h, CardContent as g, CardHeader as _, CardTitle as v } from "@burdenoff/fe-libs/ui";
15
+ import { useI18n as y } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
16
16
  //#region src/planmagnet/pages/analytics/ThroughputCard.tsx
17
17
  var b = u`
18
18
  query GetAnalyticsThroughput(
@@ -43,7 +43,7 @@ function x(e) {
43
43
  return `${t.getUTCMonth() + 1}/${t.getUTCDate()}`;
44
44
  }
45
45
  function S({ workspaceId: u, projectId: S, startDate: C, endDate: w }) {
46
- let { t: T } = h(), [E, D] = c("WEEK"), { data: O, loading: k, error: A } = d(b, {
46
+ let { t: T } = y(), [E, D] = c("WEEK"), { data: O, loading: k, error: A } = d(b, {
47
47
  variables: {
48
48
  workspaceId: u,
49
49
  projectId: S,
@@ -57,11 +57,11 @@ function S({ workspaceId: u, projectId: S, startDate: C, endDate: w }) {
57
57
  count: e.completedCount,
58
58
  points: e.completedPoints
59
59
  })), N = j.reduce((e, t) => e + t.completedCount, 0), P = j.reduce((e, t) => e + t.completedPoints, 0);
60
- return /* @__PURE__ */ m(g, {
60
+ return /* @__PURE__ */ m(h, {
61
61
  "data-testid": "analytics-throughput",
62
- children: [/* @__PURE__ */ m(v, { children: [/* @__PURE__ */ m("div", {
62
+ children: [/* @__PURE__ */ m(_, { children: [/* @__PURE__ */ m("div", {
63
63
  className: "flex flex-wrap items-center justify-between gap-2",
64
- children: [/* @__PURE__ */ m(y, {
64
+ children: [/* @__PURE__ */ m(v, {
65
65
  className: "flex items-center gap-2",
66
66
  children: [/* @__PURE__ */ p(l, { className: "h-4 w-4" }), T("planmagnet.analytics.throughput.title", "Throughput")]
67
67
  }), /* @__PURE__ */ p("div", {
@@ -80,7 +80,7 @@ function S({ workspaceId: u, projectId: S, startDate: C, endDate: w }) {
80
80
  }), /* @__PURE__ */ p("p", {
81
81
  className: "text-xs text-muted-foreground",
82
82
  children: T("planmagnet.analytics.throughput.subtitle", "Work items completed per {{bucket}}, in the selected range.", { bucket: E === "DAY" ? T("planmagnet.analytics.throughput.day", "Day").toLowerCase() : T("planmagnet.analytics.throughput.week", "Week").toLowerCase() })
83
- })] }), /* @__PURE__ */ p(_, { children: k && !O ? /* @__PURE__ */ p("div", {
83
+ })] }), /* @__PURE__ */ p(g, { children: k && !O ? /* @__PURE__ */ p("div", {
84
84
  className: "flex justify-center py-12",
85
85
  children: /* @__PURE__ */ p("div", { className: "animate-spin h-6 w-6 border-2 border-primary border-t-transparent rounded-full" })
86
86
  }) : A ? /* @__PURE__ */ p("p", {
@@ -10,8 +10,8 @@ import { LayoutGrid as c } from "lucide-react";
10
10
  import { gql as l } from "@apollo/client";
11
11
  import { useQuery as u } from "@apollo/client/react";
12
12
  import { jsx as d, jsxs as f } from "react/jsx-runtime";
13
- import { useI18n as p } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
14
- import { Card as m, CardContent as h, CardHeader as g, CardTitle as _ } from "@burdenoff/fe-libs/ui";
13
+ import { Card as p, CardContent as m, CardHeader as h, CardTitle as g } from "@burdenoff/fe-libs/ui";
14
+ import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
15
15
  //#region src/planmagnet/pages/analytics/WorkBreakdownCard.tsx
16
16
  var v = l`
17
17
  query GetAnalyticsWorkBreakdown($workspaceId: ID!, $projectIds: [ID!]) {
@@ -168,7 +168,7 @@ function T(e) {
168
168
  });
169
169
  }
170
170
  function E({ workspaceId: a, projectId: o }) {
171
- let { t: l } = p(), y = e(), [b, x] = s("items"), { data: S, loading: w, error: E } = u(v, {
171
+ let { t: l } = _(), y = e(), [b, x] = s("items"), { data: S, loading: w, error: E } = u(v, {
172
172
  variables: {
173
173
  workspaceId: a,
174
174
  projectIds: o ? [o] : void 0
@@ -178,11 +178,11 @@ function E({ workspaceId: a, projectId: o }) {
178
178
  function M(e) {
179
179
  y(`/tasks/task-detail-page?taskId=${encodeURIComponent(e)}`);
180
180
  }
181
- return /* @__PURE__ */ f(m, {
181
+ return /* @__PURE__ */ f(p, {
182
182
  "data-testid": "work-breakdown-card",
183
- children: [/* @__PURE__ */ f(g, { children: [/* @__PURE__ */ f("div", {
183
+ children: [/* @__PURE__ */ f(h, { children: [/* @__PURE__ */ f("div", {
184
184
  className: "flex flex-wrap items-center justify-between gap-2",
185
- children: [/* @__PURE__ */ f(_, {
185
+ children: [/* @__PURE__ */ f(g, {
186
186
  className: "flex items-center gap-2",
187
187
  children: [/* @__PURE__ */ d(c, { className: "h-4 w-4" }), l("planmagnet.analytics.workBreakdown.title", "Work breakdown")]
188
188
  }), /* @__PURE__ */ d("div", {
@@ -201,7 +201,7 @@ function E({ workspaceId: a, projectId: o }) {
201
201
  }), /* @__PURE__ */ d("p", {
202
202
  className: "text-xs text-muted-foreground",
203
203
  children: l("planmagnet.analytics.workBreakdown.subtitle", "Live open/done work, by project and epic — current state, not limited by the date range above.")
204
- })] }), /* @__PURE__ */ d(h, { children: w && !S ? /* @__PURE__ */ d("div", {
204
+ })] }), /* @__PURE__ */ d(m, { children: w && !S ? /* @__PURE__ */ d("div", {
205
205
  className: "flex justify-center py-12",
206
206
  children: /* @__PURE__ */ d("div", { className: "animate-spin h-6 w-6 border-2 border-primary border-t-transparent rounded-full" })
207
207
  }) : E ? /* @__PURE__ */ d("p", {
@@ -1,6 +1,20 @@
1
1
  import { ActorProfile } from '@burdenoff/fe-libs/shared';
2
2
  import { ReactNode } from 'react';
3
3
 
4
+ /**
5
+ * CWF-15's redaction sentinel: `FeatureRequest.submittedBy`/`createdBy`/`updatedBy` and `FeatureVote.voterId`
6
+ * read back this literal string, instead of the real actor id, for a non-moderator caller when the record (or,
7
+ * for a vote, that vote) is flagged `isAnonymous`. Never a real actor id — those are workspace-member uuids —
8
+ * so, like the `automation:` actor ids above, it must never be sent through `useActorProfiles`: that would only
9
+ * ever resolve to the generic "not a member" fallback, and would burn a wasted slot in every batch lookup.
10
+ */
11
+ export declare const ANONYMOUS_ACTOR_ID = "anonymous";
12
+ export declare function isAnonymousActorId(id: string | null | undefined): boolean;
13
+ /** The literal "Anonymous" badge CWF-15 asks for everywhere a redacted actor id would otherwise show — see
14
+ * `PersonName` below, which is the one place `submittedBy`/`createdBy`/`updatedBy`/`voterId` ever render. */
15
+ export declare function AnonymousBadge({ className }: {
16
+ className?: string;
17
+ }): import("react/jsx-runtime").JSX.Element;
4
18
  export declare function PeopleProvider({ workspaceId, children, }: {
5
19
  workspaceId?: string;
6
20
  children: ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"People.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/people/People.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,YAAY,EAElB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AA8Cf,wBAAgB,cAAc,CAAC,EAC7B,WAAW,EACX,QAAQ,GACT,EAAE;IACD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAkBA;AAED,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,YAAY,GAAG,IAAI,CAsBnF;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,eAAe,2CAQ5D;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,iBAAiB,2CAahE"}
1
+ {"version":3,"file":"People.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/people/People.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,YAAY,EAElB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AA4Cf;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,cAAc,CAAC;AAE9C,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEzE;AAED;8GAC8G;AAC9G,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,2CAMnE;AAID,wBAAgB,cAAc,CAAC,EAC7B,WAAW,EACX,QAAQ,GACT,EAAE;IACD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB,2CAkBA;AAED,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;GAMG;AACH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,YAAY,GAAG,IAAI,CA2BnF;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,eAAe,2CAW5D;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ/C;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,iBAAiB,2CAahE"}
@@ -1,48 +1,62 @@
1
1
  import { createContext as e, useCallback as t, useContext as n, useEffect as r, useMemo as i, useState as a } from "react";
2
2
  import { jsx as o } from "react/jsx-runtime";
3
3
  import { buildActorFallback as s, useActorProfiles as c } from "@burdenoff/fe-libs/shared";
4
+ import { Badge as l } from "@burdenoff/fe-libs/ui";
4
5
  //#region src/planmagnet/people/People.tsx
5
- var l = {
6
+ var u = {
6
7
  "automation:engine": "Automation",
7
8
  "automation:scheduler": "Automation"
8
- }, u = e(null);
9
- function d({ workspaceId: e, children: n }) {
9
+ }, d = "anonymous";
10
+ function f(e) {
11
+ return e === d;
12
+ }
13
+ function p({ className: e }) {
14
+ return /* @__PURE__ */ o(l, {
15
+ variant: "secondary",
16
+ className: e ?? "text-xs",
17
+ "data-testid": "anonymous-badge",
18
+ children: "Anonymous"
19
+ });
20
+ }
21
+ var m = e(null);
22
+ function h({ workspaceId: e, children: n }) {
10
23
  let [r, s] = a([]), l = t((e) => {
11
24
  s((t) => t.includes(e) ? t : [...t, e]);
12
- }, []), d = c(i(() => r.map((e) => ({
25
+ }, []), u = c(i(() => r.map((e) => ({
13
26
  actorId: e,
14
27
  actorType: "user"
15
- })), [r]), { workspaceId: e }), f = i(() => ({
28
+ })), [r]), { workspaceId: e }), d = i(() => ({
16
29
  request: l,
17
- profiles: d
18
- }), [l, d]);
19
- return /* @__PURE__ */ o(u.Provider, {
20
- value: f,
30
+ profiles: u
31
+ }), [l, u]);
32
+ return /* @__PURE__ */ o(m.Provider, {
33
+ value: d,
21
34
  children: n
22
35
  });
23
36
  }
24
- function f(e) {
25
- let t = n(u), i = t?.request, a = e ? l[e] : void 0;
37
+ function g(e) {
38
+ let t = n(m), i = t?.request, a = e ? u[e] : void 0, o = f(e);
26
39
  return r(() => {
27
- e && i && !a && i(e);
40
+ e && i && !a && !o && i(e);
28
41
  }, [
29
42
  e,
30
43
  i,
31
- a
44
+ a,
45
+ o
32
46
  ]), e ? a ? {
33
47
  actorId: e,
34
48
  actorType: "service",
35
49
  displayName: a,
36
50
  secondaryLabel: "Automation",
37
51
  resolved: !0
38
- } : t?.profiles[e] ?? s({
52
+ } : o ? null : t?.profiles[e] ?? s({
39
53
  actorId: e,
40
54
  actorType: "user"
41
55
  }) : null;
42
56
  }
43
- function p({ id: e, className: t }) {
44
- let n = f(e);
45
- return n ? /* @__PURE__ */ o("span", {
57
+ function _({ id: e, className: t }) {
58
+ let n = g(e);
59
+ return f(e) ? /* @__PURE__ */ o(p, { className: t }) : n ? /* @__PURE__ */ o("span", {
46
60
  className: t,
47
61
  title: n.email ?? void 0,
48
62
  children: n.displayName
@@ -51,19 +65,19 @@ function p({ id: e, className: t }) {
51
65
  children: "—"
52
66
  });
53
67
  }
54
- function m(e) {
68
+ function v(e) {
55
69
  return e.trim().split(/\s+/).filter(Boolean).slice(0, 2).map((e) => e[0].toUpperCase()).join("");
56
70
  }
57
- function h({ id: e, className: t }) {
58
- let n = f(e), r = n ? n.email ? `${n.displayName} (${n.email})` : n.displayName : void 0;
71
+ function y({ id: e, className: t }) {
72
+ let n = g(e), r = n ? n.email ? `${n.displayName} (${n.email})` : n.displayName : void 0;
59
73
  return /* @__PURE__ */ o("span", {
60
74
  className: t,
61
75
  title: r,
62
76
  "aria-label": r,
63
- children: (n?.resolved ? m(n.displayName) : "") || "?"
77
+ children: (n?.resolved ? v(n.displayName) : "") || "?"
64
78
  });
65
79
  }
66
80
  //#endregion
67
- export { d as PeopleProvider, h as PersonAvatar, p as PersonName, m as initialsOf, f as usePersonProfile };
81
+ export { h as PeopleProvider, y as PersonAvatar, _ as PersonName, v as initialsOf, g as usePersonProfile };
68
82
 
69
83
  //# sourceMappingURL=People.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"People.js","names":[],"sources":["../../../src/planmagnet/people/People.tsx"],"sourcesContent":["import {\n buildActorFallback,\n useActorProfiles,\n type ActorInput,\n type ActorProfile,\n type ActorProfileMap,\n} from '@burdenoff/fe-libs/shared';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\n\n/**\n * Show people by name, not by UUID.\n *\n * Until 2026-09-24, 21 places in this MFE rendered a raw user id where a\n * person belonged — project owners, roadmap owners, assignees, the team lead.\n * fe-libs already resolves ids to workspace-member identities\n * (`useActorProfiles`, with a 5-minute cache), but it batches per CALL and\n * does not dedupe across calls, so calling it from every row would fire a\n * burst of lookups on the first render of each list.\n *\n * So there is exactly one call, here. Every `<PersonName id>` on screen\n * registers its id with the provider; ids registered during the same render\n * land in one state update, and the provider resolves them together. A\n * growing list costs one request for the NEW ids only — already-resolved ids\n * come from the fe-libs cache.\n *\n * An id that cannot be resolved (not a member of this workspace, lookup\n * failed) renders fe-libs' short fallback, \"User 1a2b3c\", rather than the full\n * UUID: still identifiable, never a wall of hex.\n */\n\ninterface PeopleContextValue {\n request: (id: string) => void;\n profiles: ActorProfileMap;\n}\n\n/**\n * The automation engine's own actor identities (BOFF-8047 follow-up) — never a real workspace member's id, so\n * they are mapped explicitly rather than sent through `useActorProfiles` (which would only ever resolve them to\n * its generic \"not a member\" fallback). Sourced directly from wspace-planmagnet-svc, not guessed:\n * - `automation-engine.ts`'s `AUTOMATION_COMMENT_AUTHOR_ID` (`'automation:engine'`) — the fixed author of every\n * comment a POST_COMMENT action posts, regardless of which trigger or actor caused the run.\n * - `automation-scheduler.ts`'s `AUTOMATION_SCHEDULER_ACTOR_ID` (`'automation:scheduler'`) — the actor behind a\n * SCHEDULE-triggered run (threaded through as `updatedBy` on that run's other actions).\n * No real actor id can ever collide with the `automation:` prefix (workspace-member ids are uuids) — see that\n * constant's own doc comment in the engine.\n */\nconst AUTOMATION_ACTOR_NAMES: Record<string, string> = {\n 'automation:engine': 'Automation',\n 'automation:scheduler': 'Automation',\n};\n\nconst PeopleContext = createContext<PeopleContextValue | null>(null);\n\nexport function PeopleProvider({\n workspaceId,\n children,\n}: {\n workspaceId?: string;\n children: ReactNode;\n}) {\n const [ids, setIds] = useState<readonly string[]>([]);\n\n const request = useCallback((id: string) => {\n setIds((previous) => (previous.includes(id) ? previous : [...previous, id]));\n }, []);\n\n const actors = useMemo<ActorInput[]>(\n () => ids.map((actorId) => ({ actorId, actorType: 'user' })),\n [ids]\n );\n\n // No apiGatewayUrl on purpose: this MFE is handed the WORKSPACE gateway, and\n // the hook resolves the right gateways from the hostname itself.\n const profiles = useActorProfiles(actors, { workspaceId });\n\n const value = useMemo(() => ({ request, profiles }), [request, profiles]);\n return <PeopleContext.Provider value={value}>{children}</PeopleContext.Provider>;\n}\n\nexport interface PersonNameProps {\n /** A user id. Empty or missing renders an em dash. */\n id: string | null | undefined;\n className?: string;\n}\n\n/**\n * Inline text on purpose. fe-libs' `ActorIdentity` is a block (avatar plus two\n * stacked paragraphs); every place this replaces is an inline label —\n * \"Owner: …\", a table cell, a <span> inside a <p> — where a block would break\n * the layout and nest a <div> inside a <p>. The email, when known, is the\n * hover title, so two people with the same name stay distinguishable.\n */\n/**\n * Register an id with the provider and return its profile: the resolved identity, or fe-libs' short fallback\n * (\"User 1a2b3c\", `resolved: false`) until and unless it resolves. `null` for an empty id.\n */\nexport function usePersonProfile(id: string | null | undefined): ActorProfile | null {\n const context = useContext(PeopleContext);\n const request = context?.request;\n const automationName = id ? AUTOMATION_ACTOR_NAMES[id] : undefined;\n\n useEffect(() => {\n // An automation identity is never a real workspace member — registering it with the provider would only\n // ever come back as the generic \"not a member\" fallback, and would cost a wasted slot in every batch lookup.\n if (id && request && !automationName) request(id);\n }, [id, request, automationName]);\n\n if (!id) return null;\n if (automationName) {\n return {\n actorId: id,\n actorType: 'service',\n displayName: automationName,\n secondaryLabel: 'Automation',\n resolved: true,\n };\n }\n return context?.profiles[id] ?? buildActorFallback({ actorId: id, actorType: 'user' });\n}\n\nexport function PersonName({ id, className }: PersonNameProps) {\n const profile = usePersonProfile(id);\n if (!profile) return <span className={className ?? 'text-muted-foreground'}>—</span>;\n return (\n <span className={className} title={profile.email ?? undefined}>\n {profile.displayName}\n </span>\n );\n}\n\n/** Up to two initials from a display name (\"Ada Lovelace\" → \"AL\", \"ada\" → \"A\"). */\nexport function initialsOf(name: string): string {\n return name\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((word) => word[0]!.toUpperCase())\n .join('');\n}\n\nexport interface PersonAvatarProps {\n id: string | null | undefined;\n className?: string;\n}\n\n/**\n * An initials bubble for a user id. Initials come from the RESOLVED name; until the id resolves (or when it never\n * does) the bubble shows a neutral \"?\" rather than letters cut from the UUID, which matched nobody (BOFF-7977,\n * BOFF-8000). The tooltip is the name, plus the email when known.\n */\nexport function PersonAvatar({ id, className }: PersonAvatarProps) {\n const profile = usePersonProfile(id);\n const label = profile\n ? profile.email\n ? `${profile.displayName} (${profile.email})`\n : profile.displayName\n : undefined;\n const initials = profile?.resolved ? initialsOf(profile.displayName) : '';\n return (\n <span className={className} title={label} aria-label={label}>\n {initials || '?'}\n </span>\n );\n}\n"],"mappings":";;;;AAsDA,IAAM,IAAiD;CACrD,qBAAqB;CACrB,wBAAwB;CACzB,EAEK,IAAgB,EAAyC,KAAK;AAEpE,SAAgB,EAAe,EAC7B,gBACA,eAIC;CACD,IAAM,CAAC,GAAK,KAAU,EAA4B,EAAE,CAAC,EAE/C,IAAU,GAAa,MAAe;AAC1C,KAAQ,MAAc,EAAS,SAAS,EAAG,GAAG,IAAW,CAAC,GAAG,GAAU,EAAG,CAAE;IAC3E,EAAE,CAAC,EASA,IAAW,EAPF,QACP,EAAI,KAAK,OAAa;EAAE;EAAS,WAAW;EAAQ,EAAE,EAC5D,CAAC,EAAI,CACN,EAIyC,EAAE,gBAAa,CAAC,EAEpD,IAAQ,SAAe;EAAE;EAAS;EAAU,GAAG,CAAC,GAAS,EAAS,CAAC;AACzE,QAAO,kBAAC,EAAc,UAAf;EAA+B;EAAQ;EAAkC,CAAA;;AAoBlF,SAAgB,EAAiB,GAAoD;CACnF,IAAM,IAAU,EAAW,EAAc,EACnC,IAAU,GAAS,SACnB,IAAiB,IAAK,EAAuB,KAAM,KAAA;AAkBzD,QAhBA,QAAgB;AAGd,EAAI,KAAM,KAAW,CAAC,KAAgB,EAAQ,EAAG;IAChD;EAAC;EAAI;EAAS;EAAe,CAAC,EAE5B,IACD,IACK;EACL,SAAS;EACT,WAAW;EACX,aAAa;EACb,gBAAgB;EAChB,UAAU;EACX,GAEI,GAAS,SAAS,MAAO,EAAmB;EAAE,SAAS;EAAI,WAAW;EAAQ,CAAC,GAVtE;;AAalB,SAAgB,EAAW,EAAE,OAAI,gBAA8B;CAC7D,IAAM,IAAU,EAAiB,EAAG;AAEpC,QADK,IAEH,kBAAC,QAAD;EAAiB;EAAW,OAAO,EAAQ,SAAS,KAAA;YACjD,EAAQ;EACJ,CAAA,GAJY,kBAAC,QAAD;EAAM,WAAW,KAAa;YAAyB;EAAQ,CAAA;;AAStF,SAAgB,EAAW,GAAsB;AAC/C,QAAO,EACJ,MAAM,CACN,MAAM,MAAM,CACZ,OAAO,QAAQ,CACf,MAAM,GAAG,EAAE,CACX,KAAK,MAAS,EAAK,GAAI,aAAa,CAAC,CACrC,KAAK,GAAG;;AAab,SAAgB,EAAa,EAAE,OAAI,gBAAgC;CACjE,IAAM,IAAU,EAAiB,EAAG,EAC9B,IAAQ,IACV,EAAQ,QACN,GAAG,EAAQ,YAAY,IAAI,EAAQ,MAAM,KACzC,EAAQ,cACV,KAAA;AAEJ,QACE,kBAAC,QAAD;EAAiB;EAAW,OAAO;EAAO,cAAY;aAFvC,GAAS,WAAW,EAAW,EAAQ,YAAY,GAAG,OAGtD;EACR,CAAA"}
1
+ {"version":3,"file":"People.js","names":[],"sources":["../../../src/planmagnet/people/People.tsx"],"sourcesContent":["import {\n buildActorFallback,\n useActorProfiles,\n type ActorInput,\n type ActorProfile,\n type ActorProfileMap,\n} from '@burdenoff/fe-libs/shared';\nimport { Badge } from '@burdenoff/fe-libs/ui';\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react';\n\n/**\n * Show people by name, not by UUID.\n *\n * Until 2026-09-24, 21 places in this MFE rendered a raw user id where a\n * person belonged — project owners, roadmap owners, assignees, the team lead.\n * fe-libs already resolves ids to workspace-member identities\n * (`useActorProfiles`, with a 5-minute cache), but it batches per CALL and\n * does not dedupe across calls, so calling it from every row would fire a\n * burst of lookups on the first render of each list.\n *\n * So there is exactly one call, here. Every `<PersonName id>` on screen\n * registers its id with the provider; ids registered during the same render\n * land in one state update, and the provider resolves them together. A\n * growing list costs one request for the NEW ids only — already-resolved ids\n * come from the fe-libs cache.\n *\n * An id that cannot be resolved (not a member of this workspace, lookup\n * failed) renders fe-libs' short fallback, \"User 1a2b3c\", rather than the full\n * UUID: still identifiable, never a wall of hex.\n */\n\ninterface PeopleContextValue {\n request: (id: string) => void;\n profiles: ActorProfileMap;\n}\n\n/**\n * The automation engine's own actor identities (BOFF-8047 follow-up) — never a real workspace member's id, so\n * they are mapped explicitly rather than sent through `useActorProfiles` (which would only ever resolve them to\n * its generic \"not a member\" fallback). Sourced directly from wspace-planmagnet-svc, not guessed:\n * - `automation-engine.ts`'s `AUTOMATION_COMMENT_AUTHOR_ID` (`'automation:engine'`) — the fixed author of every\n * comment a POST_COMMENT action posts, regardless of which trigger or actor caused the run.\n * - `automation-scheduler.ts`'s `AUTOMATION_SCHEDULER_ACTOR_ID` (`'automation:scheduler'`) — the actor behind a\n * SCHEDULE-triggered run (threaded through as `updatedBy` on that run's other actions).\n * No real actor id can ever collide with the `automation:` prefix (workspace-member ids are uuids) — see that\n * constant's own doc comment in the engine.\n */\nconst AUTOMATION_ACTOR_NAMES: Record<string, string> = {\n 'automation:engine': 'Automation',\n 'automation:scheduler': 'Automation',\n};\n\n/**\n * CWF-15's redaction sentinel: `FeatureRequest.submittedBy`/`createdBy`/`updatedBy` and `FeatureVote.voterId`\n * read back this literal string, instead of the real actor id, for a non-moderator caller when the record (or,\n * for a vote, that vote) is flagged `isAnonymous`. Never a real actor id — those are workspace-member uuids —\n * so, like the `automation:` actor ids above, it must never be sent through `useActorProfiles`: that would only\n * ever resolve to the generic \"not a member\" fallback, and would burn a wasted slot in every batch lookup.\n */\nexport const ANONYMOUS_ACTOR_ID = 'anonymous';\n\nexport function isAnonymousActorId(id: string | null | undefined): boolean {\n return id === ANONYMOUS_ACTOR_ID;\n}\n\n/** The literal \"Anonymous\" badge CWF-15 asks for everywhere a redacted actor id would otherwise show — see\n * `PersonName` below, which is the one place `submittedBy`/`createdBy`/`updatedBy`/`voterId` ever render. */\nexport function AnonymousBadge({ className }: { className?: string }) {\n return (\n <Badge variant=\"secondary\" className={className ?? 'text-xs'} data-testid=\"anonymous-badge\">\n Anonymous\n </Badge>\n );\n}\n\nconst PeopleContext = createContext<PeopleContextValue | null>(null);\n\nexport function PeopleProvider({\n workspaceId,\n children,\n}: {\n workspaceId?: string;\n children: ReactNode;\n}) {\n const [ids, setIds] = useState<readonly string[]>([]);\n\n const request = useCallback((id: string) => {\n setIds((previous) => (previous.includes(id) ? previous : [...previous, id]));\n }, []);\n\n const actors = useMemo<ActorInput[]>(\n () => ids.map((actorId) => ({ actorId, actorType: 'user' })),\n [ids]\n );\n\n // No apiGatewayUrl on purpose: this MFE is handed the WORKSPACE gateway, and\n // the hook resolves the right gateways from the hostname itself.\n const profiles = useActorProfiles(actors, { workspaceId });\n\n const value = useMemo(() => ({ request, profiles }), [request, profiles]);\n return <PeopleContext.Provider value={value}>{children}</PeopleContext.Provider>;\n}\n\nexport interface PersonNameProps {\n /** A user id. Empty or missing renders an em dash. */\n id: string | null | undefined;\n className?: string;\n}\n\n/**\n * Inline text on purpose. fe-libs' `ActorIdentity` is a block (avatar plus two\n * stacked paragraphs); every place this replaces is an inline label —\n * \"Owner: …\", a table cell, a <span> inside a <p> — where a block would break\n * the layout and nest a <div> inside a <p>. The email, when known, is the\n * hover title, so two people with the same name stay distinguishable.\n */\n/**\n * Register an id with the provider and return its profile: the resolved identity, or fe-libs' short fallback\n * (\"User 1a2b3c\", `resolved: false`) until and unless it resolves. `null` for an empty id.\n */\nexport function usePersonProfile(id: string | null | undefined): ActorProfile | null {\n const context = useContext(PeopleContext);\n const request = context?.request;\n const automationName = id ? AUTOMATION_ACTOR_NAMES[id] : undefined;\n const anonymous = isAnonymousActorId(id);\n\n useEffect(() => {\n // An automation identity is never a real workspace member, and the CWF-15 \"anonymous\" sentinel is never an\n // actor id at all — registering either with the provider would only ever come back as the generic \"not a\n // member\" fallback, and would cost a wasted slot in every batch lookup.\n if (id && request && !automationName && !anonymous) request(id);\n }, [id, request, automationName, anonymous]);\n\n if (!id) return null;\n if (automationName) {\n return {\n actorId: id,\n actorType: 'service',\n displayName: automationName,\n secondaryLabel: 'Automation',\n resolved: true,\n };\n }\n // CWF-15: \"anonymous\" is a redaction sentinel, never a real actor id — PersonName/PersonAvatar below render it\n // specially rather than resolving it (which would only ever land on the generic \"not a member\" fallback).\n if (anonymous) return null;\n return context?.profiles[id] ?? buildActorFallback({ actorId: id, actorType: 'user' });\n}\n\nexport function PersonName({ id, className }: PersonNameProps) {\n const profile = usePersonProfile(id);\n // CWF-15: the literal \"anonymous\" sentinel renders as the Anonymous badge everywhere a person's name would\n // otherwise show — never resolved as, or displayed like, a real user id.\n if (isAnonymousActorId(id)) return <AnonymousBadge className={className} />;\n if (!profile) return <span className={className ?? 'text-muted-foreground'}>—</span>;\n return (\n <span className={className} title={profile.email ?? undefined}>\n {profile.displayName}\n </span>\n );\n}\n\n/** Up to two initials from a display name (\"Ada Lovelace\" → \"AL\", \"ada\" → \"A\"). */\nexport function initialsOf(name: string): string {\n return name\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n .slice(0, 2)\n .map((word) => word[0]!.toUpperCase())\n .join('');\n}\n\nexport interface PersonAvatarProps {\n id: string | null | undefined;\n className?: string;\n}\n\n/**\n * An initials bubble for a user id. Initials come from the RESOLVED name; until the id resolves (or when it never\n * does) the bubble shows a neutral \"?\" rather than letters cut from the UUID, which matched nobody (BOFF-7977,\n * BOFF-8000). The tooltip is the name, plus the email when known.\n */\nexport function PersonAvatar({ id, className }: PersonAvatarProps) {\n const profile = usePersonProfile(id);\n const label = profile\n ? profile.email\n ? `${profile.displayName} (${profile.email})`\n : profile.displayName\n : undefined;\n const initials = profile?.resolved ? initialsOf(profile.displayName) : '';\n return (\n <span className={className} title={label} aria-label={label}>\n {initials || '?'}\n </span>\n );\n}\n"],"mappings":";;;;;AAuDA,IAAM,IAAiD;CACrD,qBAAqB;CACrB,wBAAwB;CACzB,EASY,IAAqB;AAElC,SAAgB,EAAmB,GAAwC;AACzE,QAAO,MAAO;;AAKhB,SAAgB,EAAe,EAAE,gBAAqC;AACpE,QACE,kBAAC,GAAD;EAAO,SAAQ;EAAY,WAAW,KAAa;EAAW,eAAY;YAAkB;EAEpF,CAAA;;AAIZ,IAAM,IAAgB,EAAyC,KAAK;AAEpE,SAAgB,EAAe,EAC7B,gBACA,eAIC;CACD,IAAM,CAAC,GAAK,KAAU,EAA4B,EAAE,CAAC,EAE/C,IAAU,GAAa,MAAe;AAC1C,KAAQ,MAAc,EAAS,SAAS,EAAG,GAAG,IAAW,CAAC,GAAG,GAAU,EAAG,CAAE;IAC3E,EAAE,CAAC,EASA,IAAW,EAPF,QACP,EAAI,KAAK,OAAa;EAAE;EAAS,WAAW;EAAQ,EAAE,EAC5D,CAAC,EAAI,CACN,EAIyC,EAAE,gBAAa,CAAC,EAEpD,IAAQ,SAAe;EAAE;EAAS;EAAU,GAAG,CAAC,GAAS,EAAS,CAAC;AACzE,QAAO,kBAAC,EAAc,UAAf;EAA+B;EAAQ;EAAkC,CAAA;;AAoBlF,SAAgB,EAAiB,GAAoD;CACnF,IAAM,IAAU,EAAW,EAAc,EACnC,IAAU,GAAS,SACnB,IAAiB,IAAK,EAAuB,KAAM,KAAA,GACnD,IAAY,EAAmB,EAAG;AAsBxC,QApBA,QAAgB;AAId,EAAI,KAAM,KAAW,CAAC,KAAkB,CAAC,KAAW,EAAQ,EAAG;IAC9D;EAAC;EAAI;EAAS;EAAgB;EAAU,CAAC,EAEvC,IACD,IACK;EACL,SAAS;EACT,WAAW;EACX,aAAa;EACb,gBAAgB;EAChB,UAAU;EACX,GAIC,IAAkB,OACf,GAAS,SAAS,MAAO,EAAmB;EAAE,SAAS;EAAI,WAAW;EAAQ,CAAC,GAbtE;;AAgBlB,SAAgB,EAAW,EAAE,OAAI,gBAA8B;CAC7D,IAAM,IAAU,EAAiB,EAAG;AAKpC,QAFI,EAAmB,EAAG,GAAS,kBAAC,GAAD,EAA2B,cAAa,CAAA,GACtE,IAEH,kBAAC,QAAD;EAAiB;EAAW,OAAO,EAAQ,SAAS,KAAA;YACjD,EAAQ;EACJ,CAAA,GAJY,kBAAC,QAAD;EAAM,WAAW,KAAa;YAAyB;EAAQ,CAAA;;AAStF,SAAgB,EAAW,GAAsB;AAC/C,QAAO,EACJ,MAAM,CACN,MAAM,MAAM,CACZ,OAAO,QAAQ,CACf,MAAM,GAAG,EAAE,CACX,KAAK,MAAS,EAAK,GAAI,aAAa,CAAC,CACrC,KAAK,GAAG;;AAab,SAAgB,EAAa,EAAE,OAAI,gBAAgC;CACjE,IAAM,IAAU,EAAiB,EAAG,EAC9B,IAAQ,IACV,EAAQ,QACN,GAAG,EAAQ,YAAY,IAAI,EAAQ,MAAM,KACzC,EAAQ,cACV,KAAA;AAEJ,QACE,kBAAC,QAAD;EAAiB;EAAW,OAAO;EAAO,cAAY;aAFvC,GAAS,WAAW,EAAW,EAAQ,YAAY,GAAG,OAGtD;EACR,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"RoadmapNowNextLater.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/roadmaps/RoadmapNowNextLater.tsx"],"names":[],"mappings":"AAoFA,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oBAAoB,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAClE;AAqGD;;qHAEqH;AACrH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,IAAI,GACL,EAAE;IACD,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,kDA4BA;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,kDAW5E;AA0JD,wBAAgB,mBAAmB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,2CAmXvE"}
1
+ {"version":3,"file":"RoadmapNowNextLater.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/roadmaps/RoadmapNowNextLater.tsx"],"names":[],"mappings":"AA4FA,UAAU,OAAO;IACf,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oBAAoB,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAClE;AA4ID;;qHAEqH;AACrH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,IAAI,GACL,EAAE;IACD,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,kDA4BA;AAED,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,kDAW5E;AA0JD,wBAAgB,mBAAmB,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,2CAmYvE"}