@burdenoff/microfe-planmagnet 2026.1001.5 → 2026.1001.7

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 (126) 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/CompetitorControls.d.ts +71 -0
  9. package/dist/planmagnet/controls/CompetitorControls.d.ts.map +1 -1
  10. package/dist/planmagnet/controls/CompetitorControls.js +346 -12
  11. package/dist/planmagnet/controls/CompetitorControls.js.map +1 -1
  12. package/dist/planmagnet/controls/FeatureControls.d.ts +23 -1
  13. package/dist/planmagnet/controls/FeatureControls.d.ts.map +1 -1
  14. package/dist/planmagnet/controls/FeatureControls.js +431 -229
  15. package/dist/planmagnet/controls/FeatureControls.js.map +1 -1
  16. package/dist/planmagnet/controls/FeedbackControls.d.ts +70 -0
  17. package/dist/planmagnet/controls/FeedbackControls.d.ts.map +1 -0
  18. package/dist/planmagnet/controls/FeedbackControls.js +153 -0
  19. package/dist/planmagnet/controls/FeedbackControls.js.map +1 -0
  20. package/dist/planmagnet/controls/Pickers.d.ts +15 -0
  21. package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
  22. package/dist/planmagnet/controls/Pickers.js +61 -1
  23. package/dist/planmagnet/controls/Pickers.js.map +1 -1
  24. package/dist/planmagnet/controls/PrioritizationControls.d.ts +36 -0
  25. package/dist/planmagnet/controls/PrioritizationControls.d.ts.map +1 -1
  26. package/dist/planmagnet/controls/PrioritizationControls.js +118 -1
  27. package/dist/planmagnet/controls/PrioritizationControls.js.map +1 -1
  28. package/dist/planmagnet/controls/SyncControls.d.ts.map +1 -1
  29. package/dist/planmagnet/controls/SyncControls.js +1 -0
  30. package/dist/planmagnet/controls/SyncControls.js.map +1 -1
  31. package/dist/planmagnet/controls/WebhookSubscriptionControls.d.ts +47 -0
  32. package/dist/planmagnet/controls/WebhookSubscriptionControls.d.ts.map +1 -0
  33. package/dist/planmagnet/controls/WebhookSubscriptionControls.js +542 -0
  34. package/dist/planmagnet/controls/WebhookSubscriptionControls.js.map +1 -0
  35. package/dist/planmagnet/dashboards/DashboardUI.js +8 -8
  36. package/dist/planmagnet/dashboards/cards/RiskSeverityCard.js +4 -4
  37. package/dist/planmagnet/dashboards/cards/SprintCapacityCard.d.ts.map +1 -1
  38. package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js +67 -59
  39. package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js.map +1 -1
  40. package/dist/planmagnet/forecast/DeliveryForecastCard.js +8 -8
  41. package/dist/planmagnet/forecast/ProjectOutlookCard.js +10 -10
  42. package/dist/planmagnet/forecast/ProjectRiskSummaryCard.js +9 -9
  43. package/dist/planmagnet/forecast/ResourceForecastCard.js +6 -6
  44. package/dist/planmagnet/integrations/syncTypes.d.ts +2 -1
  45. package/dist/planmagnet/integrations/syncTypes.d.ts.map +1 -1
  46. package/dist/planmagnet/integrations/syncTypes.js +19 -9
  47. package/dist/planmagnet/integrations/syncTypes.js.map +1 -1
  48. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
  49. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +290 -283
  50. package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
  51. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.d.ts.map +1 -1
  52. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js +126 -63
  53. package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js.map +1 -1
  54. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.d.ts.map +1 -1
  55. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js +14 -0
  56. package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js.map +1 -1
  57. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.d.ts.map +1 -1
  58. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js +93 -57
  59. package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js.map +1 -1
  60. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.d.ts.map +1 -1
  61. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js +125 -83
  62. package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js.map +1 -1
  63. package/dist/planmagnet/pages/DashboardDashboardPagePage.js +23 -23
  64. package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
  65. package/dist/planmagnet/pages/DocsDocDetailPagePage.js +340 -248
  66. package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
  67. package/dist/planmagnet/pages/IntegrationsSyncDetailPagePage.d.ts.map +1 -1
  68. package/dist/planmagnet/pages/IntegrationsSyncDetailPagePage.js +172 -167
  69. package/dist/planmagnet/pages/IntegrationsSyncDetailPagePage.js.map +1 -1
  70. package/dist/planmagnet/pages/IntegrationsSyncsPagePage.d.ts.map +1 -1
  71. package/dist/planmagnet/pages/IntegrationsSyncsPagePage.js +92 -83
  72. package/dist/planmagnet/pages/IntegrationsSyncsPagePage.js.map +1 -1
  73. package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.d.ts +2 -0
  74. package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.d.ts.map +1 -0
  75. package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.js +175 -0
  76. package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.js.map +1 -0
  77. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.d.ts.map +1 -1
  78. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js +226 -126
  79. package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js.map +1 -1
  80. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
  81. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +151 -126
  82. package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
  83. package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
  84. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +169 -122
  85. package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
  86. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
  87. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +165 -109
  88. package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
  89. package/dist/planmagnet/pages/ProductsProductsPagePage.js +13 -13
  90. package/dist/planmagnet/pages/ProjectsAtRiskPagePage.js +9 -9
  91. package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +8 -8
  92. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
  93. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +15 -3
  94. package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
  95. package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +12 -12
  96. package/dist/planmagnet/pages/ReportsReportsPagePage.js +23 -23
  97. package/dist/planmagnet/pages/TasksMyDashboardPagePage.js +18 -18
  98. package/dist/planmagnet/pages/TasksMyWorkPagePage.js +10 -10
  99. package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js +5 -5
  100. package/dist/planmagnet/pages/TeamTeamPagePage.d.ts.map +1 -1
  101. package/dist/planmagnet/pages/TeamTeamPagePage.js +59 -53
  102. package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
  103. package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +8 -8
  104. package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js +6 -6
  105. package/dist/planmagnet/pages/analytics/MetricsCard.d.ts +8 -0
  106. package/dist/planmagnet/pages/analytics/MetricsCard.d.ts.map +1 -0
  107. package/dist/planmagnet/pages/analytics/MetricsCard.js +164 -0
  108. package/dist/planmagnet/pages/analytics/MetricsCard.js.map +1 -0
  109. package/dist/planmagnet/pages/analytics/QualityMetricsCard.js +6 -6
  110. package/dist/planmagnet/pages/analytics/SprintDeliveryCards.js +8 -8
  111. package/dist/planmagnet/pages/analytics/StatusFlowCard.js +7 -7
  112. package/dist/planmagnet/pages/analytics/ThroughputCard.js +7 -7
  113. package/dist/planmagnet/pages/analytics/WorkBreakdownCard.js +7 -7
  114. package/dist/planmagnet/people/People.d.ts +14 -0
  115. package/dist/planmagnet/people/People.d.ts.map +1 -1
  116. package/dist/planmagnet/people/People.js +36 -22
  117. package/dist/planmagnet/people/People.js.map +1 -1
  118. package/dist/planmagnet/team/UnmatchedCrewIdentities.d.ts +2 -0
  119. package/dist/planmagnet/team/UnmatchedCrewIdentities.d.ts.map +1 -0
  120. package/dist/planmagnet/team/UnmatchedCrewIdentities.js +155 -0
  121. package/dist/planmagnet/team/UnmatchedCrewIdentities.js.map +1 -0
  122. package/dist/planmagnet/webhooks/webhookTypes.d.ts +54 -0
  123. package/dist/planmagnet/webhooks/webhookTypes.d.ts.map +1 -0
  124. package/dist/planmagnet/webhooks/webhookTypes.js +17 -0
  125. package/dist/planmagnet/webhooks/webhookTypes.js.map +1 -0
  126. package/package.json +1 -1
@@ -1,16 +1,17 @@
1
1
  import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
2
2
  import { PersonName as t } from "../people/People.js";
3
- import { enumLabel as n } from "../controls/WorkItemControls.js";
4
- import { detailPath as r } from "../utils/rowNavigation.js";
5
- import { PortfolioHeaderActions as i } from "../controls/PortfolioControls.js";
6
- import { AlertTriangle as a, Briefcase as o, Clock as s, Loader2 as c, Target as l } from "lucide-react";
7
- import { useParams as u } from "react-router";
8
- import { gql as d } from "@apollo/client";
9
- import { useQuery as f } from "@apollo/client/react";
10
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
11
- import { Badge as h, Button as g, Card as _, CardContent as v, CardHeader as y, CardTitle as b } from "@burdenoff/fe-libs/ui";
3
+ import { StatTile as n } from "./analytics/DeliveryHealthCards.js";
4
+ import { enumLabel as r } from "../controls/WorkItemControls.js";
5
+ import { detailPath as i } from "../utils/rowNavigation.js";
6
+ import { PortfolioHeaderActions as a } from "../controls/PortfolioControls.js";
7
+ import { AlertTriangle as o, BarChart3 as s, Briefcase as c, Clock as l, Loader2 as u, Target as d } from "lucide-react";
8
+ import { useParams as f } from "react-router";
9
+ import { gql as p } from "@apollo/client";
10
+ import { useQuery as m } from "@apollo/client/react";
11
+ import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
12
+ import { Badge as v, Button as y, Card as b, CardContent as x, CardHeader as S, CardTitle as C } from "@burdenoff/fe-libs/ui";
12
13
  //#region src/planmagnet/pages/PortfoliosPortfolioDetailPagePage.tsx
13
- var x = d`
14
+ var w = p`
14
15
  query GetPortfolio($id: ID!) {
15
16
  planmagnetPortfolio(id: $id) {
16
17
  id
@@ -39,7 +40,7 @@ var x = d`
39
40
  }
40
41
  }
41
42
  }
42
- `, S = d`
43
+ `, T = p`
43
44
  query GetPortfolioOverview($portfolioId: ID!) {
44
45
  planmagnetPortfolioOverview(portfolioId: $portfolioId) {
45
46
  portfolioId
@@ -54,111 +55,136 @@ var x = d`
54
55
  overdueMilestones
55
56
  }
56
57
  }
58
+ `, E = p`
59
+ query GetPortfolioRollup($portfolioId: ID!) {
60
+ planmagnetPortfolioRollup(portfolioId: $portfolioId) {
61
+ portfolioId
62
+ totalProjects
63
+ projectsByStatus
64
+ totalBudget
65
+ totalSpent
66
+ budgetUtilization
67
+ averageSprintOnTimeRate
68
+ averageReleaseOnTimeRate
69
+ averageMilestoneOnTimeRate
70
+ calculatedAt
71
+ }
72
+ }
57
73
  `;
58
- function C() {
59
- let d = e(), C = u().id ?? "", { data: w, loading: T, error: E } = f(x, {
60
- variables: { id: C },
61
- skip: !C
62
- }), { data: D } = f(S, {
63
- variables: { portfolioId: C },
64
- skip: !C
74
+ function D({ label: e, rate: t, emptyReason: r }) {
75
+ return /* @__PURE__ */ g(n, {
76
+ label: e,
77
+ value: t == null ? "—" : `${Math.round(t * 100)}%`,
78
+ hint: t == null ? r : void 0
65
79
  });
66
- if (T && !w) return /* @__PURE__ */ p("div", {
80
+ }
81
+ function O() {
82
+ let p = e(), O = f().id ?? "", { data: k, loading: A, error: j } = m(w, {
83
+ variables: { id: O },
84
+ skip: !O
85
+ }), { data: M } = m(T, {
86
+ variables: { portfolioId: O },
87
+ skip: !O
88
+ }), { data: N, loading: P, error: F } = m(E, {
89
+ variables: { portfolioId: O },
90
+ skip: !O
91
+ });
92
+ if (A && !k) return /* @__PURE__ */ g("div", {
67
93
  className: "flex items-center justify-center p-12",
68
- children: /* @__PURE__ */ p(c, { className: "h-8 w-8 animate-spin text-muted-foreground" })
94
+ children: /* @__PURE__ */ g(u, { className: "h-8 w-8 animate-spin text-muted-foreground" })
69
95
  });
70
- if (E) return /* @__PURE__ */ m("div", {
96
+ if (j) return /* @__PURE__ */ _("div", {
71
97
  className: "p-6 text-destructive",
72
- children: ["Failed to load portfolio: ", E.message]
98
+ children: ["Failed to load portfolio: ", j.message]
73
99
  });
74
- let O = w?.planmagnetPortfolio;
75
- if (!O) return /* @__PURE__ */ p("div", {
100
+ let I = k?.planmagnetPortfolio;
101
+ if (!I) return /* @__PURE__ */ g("div", {
76
102
  className: "p-6 text-muted-foreground",
77
103
  children: "Portfolio not found."
78
104
  });
79
- let k = D?.planmagnetPortfolioOverview ?? null;
80
- return /* @__PURE__ */ m("div", {
105
+ let L = M?.planmagnetPortfolioOverview ?? null, R = N?.planmagnetPortfolioRollup ?? null;
106
+ return /* @__PURE__ */ _("div", {
81
107
  className: "space-y-6 p-6",
82
108
  children: [
83
- /* @__PURE__ */ m("div", {
109
+ /* @__PURE__ */ _("div", {
84
110
  className: "flex items-center justify-between",
85
- children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("div", {
111
+ children: [/* @__PURE__ */ _("div", { children: [/* @__PURE__ */ _("div", {
86
112
  className: "flex items-center gap-2",
87
113
  children: [
88
- /* @__PURE__ */ p(o, { className: "h-5 w-5 text-primary" }),
89
- /* @__PURE__ */ p("h1", {
114
+ /* @__PURE__ */ g(c, { className: "h-5 w-5 text-primary" }),
115
+ /* @__PURE__ */ g("h1", {
90
116
  className: "text-2xl font-semibold",
91
- children: O.name
117
+ children: I.name
92
118
  }),
93
- /* @__PURE__ */ p(h, {
119
+ /* @__PURE__ */ g(v, {
94
120
  variant: "outline",
95
121
  className: "text-xs",
96
- children: n(O.status)
122
+ children: r(I.status)
97
123
  })
98
124
  ]
99
- }), O.alignment && /* @__PURE__ */ p("p", {
125
+ }), I.alignment && /* @__PURE__ */ g("p", {
100
126
  className: "text-sm text-muted-foreground mt-1",
101
- children: O.alignment === "CUSTOM" ? O.alignmentLabel ?? "Custom alignment" : n(O.alignment)
102
- })] }), /* @__PURE__ */ p(i, {
103
- portfolioId: O.id,
104
- name: O.name,
105
- status: O.status
127
+ children: I.alignment === "CUSTOM" ? I.alignmentLabel ?? "Custom alignment" : r(I.alignment)
128
+ })] }), /* @__PURE__ */ g(a, {
129
+ portfolioId: I.id,
130
+ name: I.name,
131
+ status: I.status
106
132
  })]
107
133
  }),
108
- /* @__PURE__ */ m("div", {
134
+ /* @__PURE__ */ _("div", {
109
135
  className: "grid grid-cols-2 md:grid-cols-4 gap-4",
110
136
  children: [
111
- /* @__PURE__ */ p(_, { children: /* @__PURE__ */ m(v, {
137
+ /* @__PURE__ */ g(b, { children: /* @__PURE__ */ _(x, {
112
138
  className: "pt-4 text-center",
113
139
  children: [
114
- /* @__PURE__ */ p(o, { className: "h-5 w-5 mx-auto text-primary" }),
115
- /* @__PURE__ */ p("p", {
140
+ /* @__PURE__ */ g(c, { className: "h-5 w-5 mx-auto text-primary" }),
141
+ /* @__PURE__ */ g("p", {
116
142
  className: "text-2xl font-bold mt-1",
117
- children: k?.totalPrograms ?? O.programs.length
143
+ children: L?.totalPrograms ?? I.programs.length
118
144
  }),
119
- /* @__PURE__ */ p("p", {
145
+ /* @__PURE__ */ g("p", {
120
146
  className: "text-xs text-muted-foreground",
121
147
  children: "Programs"
122
148
  })
123
149
  ]
124
150
  }) }),
125
- /* @__PURE__ */ p(_, { children: /* @__PURE__ */ m(v, {
151
+ /* @__PURE__ */ g(b, { children: /* @__PURE__ */ _(x, {
126
152
  className: "pt-4 text-center",
127
153
  children: [
128
- /* @__PURE__ */ p(l, { className: "h-5 w-5 mx-auto text-primary" }),
129
- /* @__PURE__ */ p("p", {
154
+ /* @__PURE__ */ g(d, { className: "h-5 w-5 mx-auto text-primary" }),
155
+ /* @__PURE__ */ g("p", {
130
156
  className: "text-2xl font-bold mt-1",
131
- children: k?.totalProjects ?? O.projects.length
157
+ children: L?.totalProjects ?? I.projects.length
132
158
  }),
133
- /* @__PURE__ */ p("p", {
159
+ /* @__PURE__ */ g("p", {
134
160
  className: "text-xs text-muted-foreground",
135
161
  children: "Projects"
136
162
  })
137
163
  ]
138
164
  }) }),
139
- /* @__PURE__ */ p(_, { children: /* @__PURE__ */ m(v, {
165
+ /* @__PURE__ */ g(b, { children: /* @__PURE__ */ _(x, {
140
166
  className: "pt-4 text-center",
141
167
  children: [
142
- /* @__PURE__ */ p(a, { className: "h-5 w-5 mx-auto text-destructive" }),
143
- /* @__PURE__ */ p("p", {
168
+ /* @__PURE__ */ g(o, { className: "h-5 w-5 mx-auto text-destructive" }),
169
+ /* @__PURE__ */ g("p", {
144
170
  className: "text-2xl font-bold mt-1",
145
- children: k?.atRiskCount ?? 0
171
+ children: L?.atRiskCount ?? 0
146
172
  }),
147
- /* @__PURE__ */ p("p", {
173
+ /* @__PURE__ */ g("p", {
148
174
  className: "text-xs text-muted-foreground",
149
175
  children: "At Risk"
150
176
  })
151
177
  ]
152
178
  }) }),
153
- /* @__PURE__ */ p(_, { children: /* @__PURE__ */ m(v, {
179
+ /* @__PURE__ */ g(b, { children: /* @__PURE__ */ _(x, {
154
180
  className: "pt-4 text-center",
155
181
  children: [
156
- /* @__PURE__ */ p(s, { className: "h-5 w-5 mx-auto text-status-warning-text" }),
157
- /* @__PURE__ */ p("p", {
182
+ /* @__PURE__ */ g(l, { className: "h-5 w-5 mx-auto text-status-warning-text" }),
183
+ /* @__PURE__ */ g("p", {
158
184
  className: "text-2xl font-bold mt-1",
159
- children: k?.overdueMilestones ?? 0
185
+ children: L?.overdueMilestones ?? 0
160
186
  }),
161
- /* @__PURE__ */ p("p", {
187
+ /* @__PURE__ */ g("p", {
162
188
  className: "text-xs text-muted-foreground",
163
189
  children: "Overdue Milestones"
164
190
  })
@@ -166,174 +192,248 @@ function C() {
166
192
  }) })
167
193
  ]
168
194
  }),
169
- /* @__PURE__ */ m("div", {
195
+ /* @__PURE__ */ _(b, {
196
+ "data-testid": "portfolio-rollup-card",
197
+ children: [/* @__PURE__ */ _(S, { children: [/* @__PURE__ */ _(C, {
198
+ className: "flex items-center gap-2",
199
+ children: [/* @__PURE__ */ g(s, { className: "h-4 w-4" }), "Portfolio Rollup"]
200
+ }), /* @__PURE__ */ g("p", {
201
+ className: "text-xs text-muted-foreground",
202
+ children: "Recomputed on every load across every live project in this portfolio."
203
+ })] }), /* @__PURE__ */ g(x, {
204
+ className: "space-y-4",
205
+ children: P && !R ? /* @__PURE__ */ g("p", {
206
+ className: "text-sm text-muted-foreground",
207
+ children: "Loading…"
208
+ }) : F ? /* @__PURE__ */ _("p", {
209
+ className: "text-sm text-status-error-text",
210
+ children: ["Rollup could not be loaded: ", F.message]
211
+ }) : R ? /* @__PURE__ */ _(h, { children: [
212
+ /* @__PURE__ */ _("div", {
213
+ className: "grid grid-cols-1 sm:grid-cols-2 gap-3",
214
+ children: [/* @__PURE__ */ g(n, {
215
+ label: "Total projects",
216
+ value: String(R.totalProjects)
217
+ }), /* @__PURE__ */ g(n, {
218
+ label: "Status breakdown",
219
+ value: Object.keys(R.projectsByStatus).length === 0 ? "—" : Object.entries(R.projectsByStatus).map(([e, t]) => `${r(e)}: ${t}`).join(", "),
220
+ hint: R.totalProjects === 0 ? "No live projects in this portfolio" : void 0
221
+ })]
222
+ }),
223
+ /* @__PURE__ */ _("div", {
224
+ className: "grid grid-cols-1 sm:grid-cols-3 gap-3",
225
+ children: [
226
+ /* @__PURE__ */ g(n, {
227
+ label: "Planned",
228
+ value: R.totalBudget == null ? "—" : R.totalBudget.toLocaleString(),
229
+ hint: R.totalBudget == null ? "No budgets set on these projects" : void 0
230
+ }),
231
+ /* @__PURE__ */ g(n, {
232
+ label: "Spent",
233
+ value: R.totalSpent == null ? "—" : R.totalSpent.toLocaleString(),
234
+ hint: R.totalSpent == null ? "No budgets set on these projects" : void 0
235
+ }),
236
+ /* @__PURE__ */ g(n, {
237
+ label: "Utilisation",
238
+ value: R.budgetUtilization == null ? "—" : `${R.budgetUtilization.toFixed(0)}%`,
239
+ hint: R.budgetUtilization == null ? "No budget to compare spend against" : void 0
240
+ })
241
+ ]
242
+ }),
243
+ /* @__PURE__ */ _("div", { children: [/* @__PURE__ */ g("h3", {
244
+ className: "text-sm font-medium mb-1",
245
+ children: "Average on-time rate (trailing 30 days)"
246
+ }), /* @__PURE__ */ _("div", {
247
+ className: "grid grid-cols-1 sm:grid-cols-3 gap-3",
248
+ children: [
249
+ /* @__PURE__ */ g(D, {
250
+ label: "Sprints",
251
+ rate: R.averageSprintOnTimeRate,
252
+ emptyReason: "No completed sprint in this window across these projects"
253
+ }),
254
+ /* @__PURE__ */ g(D, {
255
+ label: "Releases",
256
+ rate: R.averageReleaseOnTimeRate,
257
+ emptyReason: "No completed release in this window across these projects"
258
+ }),
259
+ /* @__PURE__ */ g(D, {
260
+ label: "Milestones",
261
+ rate: R.averageMilestoneOnTimeRate,
262
+ emptyReason: "No completed milestone in this window across these projects"
263
+ })
264
+ ]
265
+ })] })
266
+ ] }) : null
267
+ })]
268
+ }),
269
+ /* @__PURE__ */ _("div", {
170
270
  className: "grid grid-cols-1 lg:grid-cols-3 gap-6",
171
- children: [/* @__PURE__ */ m("div", {
271
+ children: [/* @__PURE__ */ _("div", {
172
272
  className: "lg:col-span-2 space-y-6",
173
273
  children: [
174
- /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ p(b, { children: "Overview" }) }), /* @__PURE__ */ m(v, {
274
+ /* @__PURE__ */ _(b, { children: [/* @__PURE__ */ g(S, { children: /* @__PURE__ */ g(C, { children: "Overview" }) }), /* @__PURE__ */ _(x, {
175
275
  className: "space-y-4",
176
- children: [/* @__PURE__ */ p("p", {
276
+ children: [/* @__PURE__ */ g("p", {
177
277
  className: "text-sm",
178
- children: O.description ?? "No description provided."
179
- }), k ? /* @__PURE__ */ m("div", {
278
+ children: I.description ?? "No description provided."
279
+ }), L ? /* @__PURE__ */ _("div", {
180
280
  className: "grid grid-cols-2 gap-4",
181
281
  children: [
182
- /* @__PURE__ */ m("div", {
282
+ /* @__PURE__ */ _("div", {
183
283
  className: "p-3 bg-muted rounded-md",
184
- children: [/* @__PURE__ */ p("p", {
284
+ children: [/* @__PURE__ */ g("p", {
185
285
  className: "text-xs text-muted-foreground",
186
286
  children: "Budget Utilization"
187
- }), /* @__PURE__ */ p("p", {
287
+ }), /* @__PURE__ */ g("p", {
188
288
  className: "text-lg font-semibold mt-1",
189
- children: k.budgetUtilization == null ? "No budget data" : `${k.budgetUtilization.toFixed(0)}%`
289
+ children: L.budgetUtilization == null ? "No budget data" : `${L.budgetUtilization.toFixed(0)}%`
190
290
  })]
191
291
  }),
192
- /* @__PURE__ */ m("div", {
292
+ /* @__PURE__ */ _("div", {
193
293
  className: "p-3 bg-muted rounded-md",
194
- children: [/* @__PURE__ */ p("p", {
294
+ children: [/* @__PURE__ */ g("p", {
195
295
  className: "text-xs text-muted-foreground",
196
296
  children: "Health Score"
197
- }), /* @__PURE__ */ p("p", {
297
+ }), /* @__PURE__ */ g("p", {
198
298
  className: "text-lg font-semibold mt-1",
199
- children: k.healthScore == null ? "No projects yet" : k.healthScore.toFixed(0)
299
+ children: L.healthScore == null ? "No projects yet" : L.healthScore.toFixed(0)
200
300
  })]
201
301
  }),
202
- /* @__PURE__ */ m("div", {
302
+ /* @__PURE__ */ _("div", {
203
303
  className: "p-3 bg-muted rounded-md",
204
- children: [/* @__PURE__ */ p("p", {
304
+ children: [/* @__PURE__ */ g("p", {
205
305
  className: "text-xs text-muted-foreground",
206
306
  children: "Total Spent"
207
- }), /* @__PURE__ */ p("p", {
307
+ }), /* @__PURE__ */ g("p", {
208
308
  className: "text-lg font-semibold mt-1",
209
- children: k.totalSpent == null ? "N/A" : k.totalSpent.toLocaleString()
309
+ children: L.totalSpent == null ? "N/A" : L.totalSpent.toLocaleString()
210
310
  })]
211
311
  }),
212
- /* @__PURE__ */ m("div", {
312
+ /* @__PURE__ */ _("div", {
213
313
  className: "p-3 bg-muted rounded-md",
214
- children: [/* @__PURE__ */ p("p", {
314
+ children: [/* @__PURE__ */ g("p", {
215
315
  className: "text-xs text-muted-foreground",
216
316
  children: "Projects by Status"
217
- }), /* @__PURE__ */ p("p", {
317
+ }), /* @__PURE__ */ g("p", {
218
318
  className: "text-sm mt-1",
219
- children: Object.keys(k.projectsByStatus).length > 0 ? Object.entries(k.projectsByStatus).map(([e, t]) => `${n(e)}: ${t}`).join(", ") : "No projects yet"
319
+ children: Object.keys(L.projectsByStatus).length > 0 ? Object.entries(L.projectsByStatus).map(([e, t]) => `${r(e)}: ${t}`).join(", ") : "No projects yet"
220
320
  })]
221
321
  })
222
322
  ]
223
- }) : /* @__PURE__ */ p("p", {
323
+ }) : /* @__PURE__ */ g("p", {
224
324
  className: "text-sm text-muted-foreground",
225
325
  children: "Loading overview…"
226
326
  })]
227
327
  })] }),
228
- /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ m(b, { children: [
328
+ /* @__PURE__ */ _(b, { children: [/* @__PURE__ */ g(S, { children: /* @__PURE__ */ _(C, { children: [
229
329
  "Programs (",
230
- O.programs.length,
330
+ I.programs.length,
231
331
  ")"
232
- ] }) }), /* @__PURE__ */ m(v, {
332
+ ] }) }), /* @__PURE__ */ _(x, {
233
333
  className: "space-y-2",
234
- children: [O.programs.length === 0 && /* @__PURE__ */ p("p", {
334
+ children: [I.programs.length === 0 && /* @__PURE__ */ g("p", {
235
335
  className: "text-sm text-muted-foreground",
236
336
  children: "No programs are linked to this portfolio yet."
237
- }), O.programs.map((e) => /* @__PURE__ */ m("button", {
337
+ }), I.programs.map((e) => /* @__PURE__ */ _("button", {
238
338
  type: "button",
239
339
  className: "flex w-full items-center justify-between rounded-md border p-3 text-left hover:bg-muted",
240
- onClick: () => d(r("/products/program-detail-page", e.id)),
241
- children: [/* @__PURE__ */ p("span", {
340
+ onClick: () => p(i("/products/program-detail-page", e.id)),
341
+ children: [/* @__PURE__ */ g("span", {
242
342
  className: "text-sm font-medium",
243
343
  children: e.name
244
- }), /* @__PURE__ */ p(h, {
344
+ }), /* @__PURE__ */ g(v, {
245
345
  variant: "outline",
246
346
  className: "text-xs",
247
- children: n(e.status)
347
+ children: r(e.status)
248
348
  })]
249
349
  }, e.id))]
250
350
  })] }),
251
- /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ m(b, { children: [
351
+ /* @__PURE__ */ _(b, { children: [/* @__PURE__ */ g(S, { children: /* @__PURE__ */ _(C, { children: [
252
352
  "Projects (",
253
- O.projects.length,
353
+ I.projects.length,
254
354
  ")"
255
- ] }) }), /* @__PURE__ */ m(v, {
355
+ ] }) }), /* @__PURE__ */ _(x, {
256
356
  className: "space-y-2",
257
- children: [O.projects.length === 0 && /* @__PURE__ */ m("div", {
357
+ children: [I.projects.length === 0 && /* @__PURE__ */ _("div", {
258
358
  className: "space-y-1",
259
- children: [/* @__PURE__ */ p("p", {
359
+ children: [/* @__PURE__ */ g("p", {
260
360
  className: "text-sm text-muted-foreground",
261
361
  children: "No projects are linked to this portfolio yet."
262
- }), /* @__PURE__ */ m("p", {
362
+ }), /* @__PURE__ */ _("p", {
263
363
  className: "text-sm text-muted-foreground",
264
364
  children: [
265
365
  "Open a project and set its Portfolio field to add it here.",
266
366
  " ",
267
- /* @__PURE__ */ p(g, {
367
+ /* @__PURE__ */ g(y, {
268
368
  variant: "link",
269
369
  className: "h-auto p-0 text-sm",
270
- onClick: () => d("/projects/projects-page"),
370
+ onClick: () => p("/projects/projects-page"),
271
371
  children: "Go to Projects"
272
372
  })
273
373
  ]
274
374
  })]
275
- }), O.projects.map((e) => /* @__PURE__ */ m("button", {
375
+ }), I.projects.map((e) => /* @__PURE__ */ _("button", {
276
376
  type: "button",
277
377
  className: "flex w-full items-center justify-between rounded-md border p-3 text-left hover:bg-muted",
278
- onClick: () => d(r("/projects/project-detail-page", e.id)),
279
- children: [/* @__PURE__ */ p("span", {
378
+ onClick: () => p(i("/projects/project-detail-page", e.id)),
379
+ children: [/* @__PURE__ */ g("span", {
280
380
  className: "text-sm font-medium",
281
381
  children: e.name
282
- }), /* @__PURE__ */ p(h, {
382
+ }), /* @__PURE__ */ g(v, {
283
383
  variant: "outline",
284
384
  className: "text-xs",
285
- children: n(e.status)
385
+ children: r(e.status)
286
386
  })]
287
387
  }, e.id))]
288
388
  })] })
289
389
  ]
290
- }), /* @__PURE__ */ m("div", {
390
+ }), /* @__PURE__ */ _("div", {
291
391
  className: "space-y-6",
292
- children: [/* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ p(b, { children: "Details" }) }), /* @__PURE__ */ m(v, {
392
+ children: [/* @__PURE__ */ _(b, { children: [/* @__PURE__ */ g(S, { children: /* @__PURE__ */ g(C, { children: "Details" }) }), /* @__PURE__ */ _(x, {
293
393
  className: "space-y-2 text-sm",
294
394
  children: [
295
- /* @__PURE__ */ m("div", {
395
+ /* @__PURE__ */ _("div", {
296
396
  className: "flex justify-between",
297
- children: [/* @__PURE__ */ p("span", {
397
+ children: [/* @__PURE__ */ g("span", {
298
398
  className: "text-muted-foreground",
299
399
  children: "Owner"
300
- }), /* @__PURE__ */ p(t, { id: O.ownerId })]
400
+ }), /* @__PURE__ */ g(t, { id: I.ownerId })]
301
401
  }),
302
- /* @__PURE__ */ m("div", {
402
+ /* @__PURE__ */ _("div", {
303
403
  className: "flex justify-between",
304
- children: [/* @__PURE__ */ p("span", {
404
+ children: [/* @__PURE__ */ g("span", {
305
405
  className: "text-muted-foreground",
306
406
  children: "Budget"
307
- }), /* @__PURE__ */ p("span", {
407
+ }), /* @__PURE__ */ g("span", {
308
408
  className: "font-medium",
309
- children: O.budgetTotal == null ? "Not set" : `${O.currency ?? ""} ${O.budgetTotal.toLocaleString()}`.trim()
409
+ children: I.budgetTotal == null ? "Not set" : `${I.currency ?? ""} ${I.budgetTotal.toLocaleString()}`.trim()
310
410
  })]
311
411
  }),
312
- /* @__PURE__ */ m("div", {
412
+ /* @__PURE__ */ _("div", {
313
413
  className: "flex justify-between",
314
- children: [/* @__PURE__ */ p("span", {
414
+ children: [/* @__PURE__ */ g("span", {
315
415
  className: "text-muted-foreground",
316
416
  children: "Fiscal Period"
317
- }), /* @__PURE__ */ p("span", { children: O.fiscalPeriod ?? "Not set" })]
417
+ }), /* @__PURE__ */ g("span", { children: I.fiscalPeriod ?? "Not set" })]
318
418
  }),
319
- /* @__PURE__ */ m("div", {
419
+ /* @__PURE__ */ _("div", {
320
420
  className: "flex justify-between",
321
- children: [/* @__PURE__ */ p("span", {
421
+ children: [/* @__PURE__ */ g("span", {
322
422
  className: "text-muted-foreground",
323
423
  children: "Created"
324
- }), /* @__PURE__ */ p("span", { children: new Date(O.createdAt).toLocaleDateString() })]
424
+ }), /* @__PURE__ */ g("span", { children: new Date(I.createdAt).toLocaleDateString() })]
325
425
  }),
326
- /* @__PURE__ */ m("div", {
426
+ /* @__PURE__ */ _("div", {
327
427
  className: "flex justify-between",
328
- children: [/* @__PURE__ */ p("span", {
428
+ children: [/* @__PURE__ */ g("span", {
329
429
  className: "text-muted-foreground",
330
430
  children: "Updated"
331
- }), /* @__PURE__ */ p("span", { children: new Date(O.updatedAt).toLocaleDateString() })]
431
+ }), /* @__PURE__ */ g("span", { children: new Date(I.updatedAt).toLocaleDateString() })]
332
432
  })
333
433
  ]
334
- })] }), O.tags.length > 0 && /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ p(b, { children: "Tags" }) }), /* @__PURE__ */ p(v, {
434
+ })] }), I.tags.length > 0 && /* @__PURE__ */ _(b, { children: [/* @__PURE__ */ g(S, { children: /* @__PURE__ */ g(C, { children: "Tags" }) }), /* @__PURE__ */ g(x, {
335
435
  className: "flex flex-wrap gap-1",
336
- children: O.tags.map((e) => /* @__PURE__ */ p(h, {
436
+ children: I.tags.map((e) => /* @__PURE__ */ g(v, {
337
437
  variant: "outline",
338
438
  className: "text-xs",
339
439
  children: e
@@ -345,6 +445,6 @@ function C() {
345
445
  });
346
446
  }
347
447
  //#endregion
348
- export { C as PortfoliosPortfolioDetailPagePage };
448
+ export { O as PortfoliosPortfolioDetailPagePage };
349
449
 
350
450
  //# sourceMappingURL=PortfoliosPortfolioDetailPagePage.js.map