@burdenoff/microfe-planmagnet 2026.930.21 → 2026.930.23
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.
- package/dist/node_modules/lodash/_arrayEach.js +14 -0
- package/dist/node_modules/lodash/_arrayEach.js.map +1 -0
- package/dist/node_modules/lodash/_assignValue.js +17 -0
- package/dist/node_modules/lodash/_assignValue.js.map +1 -0
- package/dist/node_modules/lodash/_baseAssign.js +16 -0
- package/dist/node_modules/lodash/_baseAssign.js.map +1 -0
- package/dist/node_modules/lodash/_baseAssignIn.js +16 -0
- package/dist/node_modules/lodash/_baseAssignIn.js.map +1 -0
- package/dist/node_modules/lodash/_baseClone.js +64 -0
- package/dist/node_modules/lodash/_baseClone.js.map +1 -0
- package/dist/node_modules/lodash/_baseCreate.js +21 -0
- package/dist/node_modules/lodash/_baseCreate.js.map +1 -0
- package/dist/node_modules/lodash/_baseIsMap.js +16 -0
- package/dist/node_modules/lodash/_baseIsMap.js.map +1 -0
- package/dist/node_modules/lodash/_baseIsSet.js +16 -0
- package/dist/node_modules/lodash/_baseIsSet.js.map +1 -0
- package/dist/node_modules/lodash/_baseKeysIn.js +20 -0
- package/dist/node_modules/lodash/_baseKeysIn.js.map +1 -0
- package/dist/node_modules/lodash/_baseSum.js +17 -0
- package/dist/node_modules/lodash/_baseSum.js.map +1 -0
- package/dist/node_modules/lodash/_baseUnset.js +26 -0
- package/dist/node_modules/lodash/_baseUnset.js.map +1 -0
- package/dist/node_modules/lodash/_cloneArrayBuffer.js +16 -0
- package/dist/node_modules/lodash/_cloneArrayBuffer.js.map +1 -0
- package/dist/node_modules/lodash/_cloneBuffer.js +17 -0
- package/dist/node_modules/lodash/_cloneBuffer.js.map +1 -0
- package/dist/node_modules/lodash/_cloneDataView.js +16 -0
- package/dist/node_modules/lodash/_cloneDataView.js.map +1 -0
- package/dist/node_modules/lodash/_cloneRegExp.js +15 -0
- package/dist/node_modules/lodash/_cloneRegExp.js.map +1 -0
- package/dist/node_modules/lodash/_cloneSymbol.js +15 -0
- package/dist/node_modules/lodash/_cloneSymbol.js.map +1 -0
- package/dist/node_modules/lodash/_cloneTypedArray.js +16 -0
- package/dist/node_modules/lodash/_cloneTypedArray.js.map +1 -0
- package/dist/node_modules/lodash/_copyArray.js +15 -0
- package/dist/node_modules/lodash/_copyArray.js.map +1 -0
- package/dist/node_modules/lodash/_copyObject.js +22 -0
- package/dist/node_modules/lodash/_copyObject.js.map +1 -0
- package/dist/node_modules/lodash/_copySymbols.js +16 -0
- package/dist/node_modules/lodash/_copySymbols.js.map +1 -0
- package/dist/node_modules/lodash/_copySymbolsIn.js +16 -0
- package/dist/node_modules/lodash/_copySymbolsIn.js.map +1 -0
- package/dist/node_modules/lodash/_customOmitClone.js +15 -0
- package/dist/node_modules/lodash/_customOmitClone.js.map +1 -0
- package/dist/node_modules/lodash/_flatRest.js +17 -0
- package/dist/node_modules/lodash/_flatRest.js.map +1 -0
- package/dist/node_modules/lodash/_getAllKeysIn.js +17 -0
- package/dist/node_modules/lodash/_getAllKeysIn.js.map +1 -0
- package/dist/node_modules/lodash/_getSymbolsIn.js +18 -0
- package/dist/node_modules/lodash/_getSymbolsIn.js.map +1 -0
- package/dist/node_modules/lodash/_initCloneArray.js +15 -0
- package/dist/node_modules/lodash/_initCloneArray.js.map +1 -0
- package/dist/node_modules/lodash/_initCloneByTag.js +40 -0
- package/dist/node_modules/lodash/_initCloneByTag.js.map +1 -0
- package/dist/node_modules/lodash/_initCloneObject.js +17 -0
- package/dist/node_modules/lodash/_initCloneObject.js.map +1 -0
- package/dist/node_modules/lodash/_nativeKeysIn.js +15 -0
- package/dist/node_modules/lodash/_nativeKeysIn.js.map +1 -0
- package/dist/node_modules/lodash/_parent.js +16 -0
- package/dist/node_modules/lodash/_parent.js.map +1 -0
- package/dist/node_modules/lodash/flatten.js +15 -0
- package/dist/node_modules/lodash/flatten.js.map +1 -0
- package/dist/node_modules/lodash/isMap.js +14 -0
- package/dist/node_modules/lodash/isMap.js.map +1 -0
- package/dist/node_modules/lodash/isSet.js +14 -0
- package/dist/node_modules/lodash/isSet.js.map +1 -0
- package/dist/node_modules/lodash/keysIn.js +17 -0
- package/dist/node_modules/lodash/keysIn.js.map +1 -0
- package/dist/node_modules/lodash/maxBy.js +17 -0
- package/dist/node_modules/lodash/maxBy.js.map +1 -0
- package/dist/node_modules/lodash/omit.js +28 -0
- package/dist/node_modules/lodash/omit.js.map +1 -0
- package/dist/node_modules/lodash/sumBy.js +16 -0
- package/dist/node_modules/lodash/sumBy.js.map +1 -0
- package/dist/node_modules/recharts/es6/chart/Sankey.js +556 -0
- package/dist/node_modules/recharts/es6/chart/Sankey.js.map +1 -0
- package/dist/node_modules/recharts/es6/chart/Treemap.js +545 -0
- package/dist/node_modules/recharts/es6/chart/Treemap.js.map +1 -0
- package/dist/node_modules/recharts/es6/shape/Polygon.js +112 -0
- package/dist/node_modules/recharts/es6/shape/Polygon.js.map +1 -0
- package/dist/node_modules/recharts/es6/util/Constants.js +31 -0
- package/dist/node_modules/recharts/es6/util/Constants.js.map +1 -0
- package/dist/node_modules/recharts/es6/util/ReactUtils.js +15 -10
- package/dist/node_modules/recharts/es6/util/ReactUtils.js.map +1 -1
- package/dist/planmagnet/controls/AutomationRuleControls.js +10 -10
- package/dist/planmagnet/controls/CompetitorControls.js +7 -7
- package/dist/planmagnet/controls/FeatureControls.js +38 -38
- package/dist/planmagnet/controls/ProgramControls.js +8 -8
- package/dist/planmagnet/dependency/DependencyGraph.d.ts.map +1 -1
- package/dist/planmagnet/dependency/DependencyGraph.js +13 -10
- package/dist/planmagnet/dependency/DependencyGraph.js.map +1 -1
- package/dist/planmagnet/dependency/DependencyPanel.js +13 -13
- package/dist/planmagnet/dependency/GanttChart.d.ts.map +1 -1
- package/dist/planmagnet/dependency/GanttChart.js +11 -5
- package/dist/planmagnet/dependency/GanttChart.js.map +1 -1
- package/dist/planmagnet/pages/ActivityActivityPagePage.js +16 -16
- package/dist/planmagnet/pages/ActivityActivityPagePage.js.map +1 -1
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +91 -73
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/AutomationAutomationRulesPagePage.js +6 -6
- package/dist/planmagnet/pages/AutomationCreateAutomationRulePagePage.js +4 -4
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js +11 -11
- package/dist/planmagnet/pages/DashboardsProjectManagerPagePage.js +5 -5
- package/dist/planmagnet/pages/DashboardsTeamUtilizationPagePage.js +5 -5
- package/dist/planmagnet/pages/IntegrationsNewSyncPagePage.js +6 -6
- package/dist/planmagnet/pages/IntegrationsNewSyncPagePage.js.map +1 -1
- package/dist/planmagnet/pages/IntegrationsSyncsPagePage.js +8 -8
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +10 -10
- package/dist/planmagnet/pages/ProjectsCriticalPathPagePage.js +6 -6
- package/dist/planmagnet/pages/ProjectsEditProjectPagePage.js +5 -5
- package/dist/planmagnet/pages/ProjectsPlanningPagePage.js +8 -8
- package/dist/planmagnet/pages/SprintsStartSprintPagePage.js +4 -4
- package/dist/planmagnet/pages/analytics/StatusFlowCard.d.ts +8 -0
- package/dist/planmagnet/pages/analytics/StatusFlowCard.d.ts.map +1 -0
- package/dist/planmagnet/pages/analytics/StatusFlowCard.js +234 -0
- package/dist/planmagnet/pages/analytics/StatusFlowCard.js.map +1 -0
- package/dist/planmagnet/pages/analytics/WorkBreakdownCard.d.ts +6 -0
- package/dist/planmagnet/pages/analytics/WorkBreakdownCard.d.ts.map +1 -0
- package/dist/planmagnet/pages/analytics/WorkBreakdownCard.js +367 -0
- package/dist/planmagnet/pages/analytics/WorkBreakdownCard.js.map +1 -0
- package/dist/planmagnet/roadmaps/RoadmapControls.js +17 -17
- package/dist/planmagnet/utils/statusColor.d.ts +8 -9
- package/dist/planmagnet/utils/statusColor.d.ts.map +1 -1
- package/dist/planmagnet/utils/statusColor.js +8 -40
- package/dist/planmagnet/utils/statusColor.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,8 +2,8 @@ import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
|
2
2
|
import { LEAVES_PAGE_CONTEXT as t, throwOnError as n } from "../utils/mutationResult.js";
|
|
3
3
|
import { ConfirmButton as r, ErrorLine as i } from "./ConfirmButton.js";
|
|
4
4
|
import { enumLabel as a } from "./WorkItemControls.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { detailPath as o } from "../utils/rowNavigation.js";
|
|
6
|
+
import { ProjectSelect as s, WorkItemSearchSelect as c } from "./Pickers.js";
|
|
7
7
|
import { parseIntField as l } from "../utils/formValidation.js";
|
|
8
8
|
import { useState as u } from "react";
|
|
9
9
|
import { BarChart3 as d, Pencil as f, ThumbsUp as p, Trash2 as m } from "lucide-react";
|
|
@@ -81,15 +81,15 @@ function F({ featureId: e, voted: t }) {
|
|
|
81
81
|
}), c && /* @__PURE__ */ _(i, { message: c })]
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
|
-
function I({ feature:
|
|
85
|
-
let
|
|
84
|
+
function I({ feature: s }) {
|
|
85
|
+
let c = e(), [l, f] = g(M, P), [p, h] = g(N, {
|
|
86
86
|
refetchQueries: k.filter((e) => e !== "GetFeatureRequest"),
|
|
87
87
|
context: t
|
|
88
|
-
}), [b, x] = u(null), S = f.loading || h.loading, C = O.includes(
|
|
88
|
+
}), [b, x] = u(null), S = f.loading || h.loading, C = O.includes(s.status) ? O : [s.status, ...O], w = async (e) => {
|
|
89
89
|
x(null);
|
|
90
90
|
try {
|
|
91
91
|
await n(l({ variables: {
|
|
92
|
-
id:
|
|
92
|
+
id: s.id,
|
|
93
93
|
input: { status: e }
|
|
94
94
|
} }));
|
|
95
95
|
} catch (e) {
|
|
@@ -98,7 +98,7 @@ function I({ feature: o }) {
|
|
|
98
98
|
}, T = async () => {
|
|
99
99
|
x(null);
|
|
100
100
|
try {
|
|
101
|
-
await n(p({ variables: { id:
|
|
101
|
+
await n(p({ variables: { id: s.id } })), c("/products/features-page");
|
|
102
102
|
} catch (e) {
|
|
103
103
|
x(e instanceof Error ? e.message : "The request could not be deleted.");
|
|
104
104
|
}
|
|
@@ -112,29 +112,29 @@ function I({ feature: o }) {
|
|
|
112
112
|
"aria-label": "Status",
|
|
113
113
|
"data-testid": "feature-status",
|
|
114
114
|
className: "rounded-md border border-input bg-background px-2 py-1 text-sm disabled:opacity-60",
|
|
115
|
-
value:
|
|
115
|
+
value: s.status,
|
|
116
116
|
disabled: S,
|
|
117
117
|
onChange: (e) => {
|
|
118
|
-
e.target.value !==
|
|
118
|
+
e.target.value !== s.status && w(e.target.value);
|
|
119
119
|
},
|
|
120
120
|
children: C.map((e) => /* @__PURE__ */ _("option", {
|
|
121
121
|
value: e,
|
|
122
122
|
children: a(e)
|
|
123
123
|
}, e))
|
|
124
124
|
}),
|
|
125
|
-
/* @__PURE__ */ _(L, { feature:
|
|
125
|
+
/* @__PURE__ */ _(L, { feature: s }),
|
|
126
126
|
/* @__PURE__ */ v(y, {
|
|
127
127
|
size: "sm",
|
|
128
128
|
variant: "outline",
|
|
129
129
|
"data-testid": "feature-analytics",
|
|
130
|
-
onClick: () =>
|
|
130
|
+
onClick: () => c(o("/products/feature-analytics-page", s.id)),
|
|
131
131
|
children: [/* @__PURE__ */ _(d, { className: "mr-1 h-4 w-4" }), "Analytics"]
|
|
132
132
|
}),
|
|
133
133
|
/* @__PURE__ */ _(r, {
|
|
134
134
|
label: "Delete",
|
|
135
135
|
variant: "outline",
|
|
136
136
|
icon: /* @__PURE__ */ _(m, { className: "mr-1 h-4 w-4" }),
|
|
137
|
-
title: `Delete "${
|
|
137
|
+
title: `Delete "${s.title}"?`,
|
|
138
138
|
description: "The request and its votes are deleted. This cannot be undone here.",
|
|
139
139
|
confirmLabel: "Delete request",
|
|
140
140
|
destructive: !0,
|
|
@@ -153,34 +153,34 @@ function L({ feature: e }) {
|
|
|
153
153
|
effortEstimate: e.effortEstimate ?? "",
|
|
154
154
|
projectId: e.projectId ?? "",
|
|
155
155
|
workItemId: e.workItemId ?? ""
|
|
156
|
-
}, [r, a] = u(!1), [
|
|
156
|
+
}, [r, a] = u(!1), [o, d] = u(t), [p, m] = u(null), [h, O] = g(M, P), k = l(o.businessValue, {
|
|
157
157
|
min: 0,
|
|
158
158
|
max: 100
|
|
159
|
-
}), A =
|
|
159
|
+
}), A = o.title.trim() !== "" && !k.invalid && !O.loading, j = async () => {
|
|
160
160
|
m(null);
|
|
161
161
|
let r = (e) => e.trim() ? e.trim() : null, i = {
|
|
162
|
-
title:
|
|
163
|
-
description: r(
|
|
162
|
+
title: o.title.trim(),
|
|
163
|
+
description: r(o.description),
|
|
164
164
|
businessValue: k.value ?? null,
|
|
165
|
-
effortEstimate: r(
|
|
166
|
-
projectId:
|
|
167
|
-
workItemId:
|
|
168
|
-
},
|
|
165
|
+
effortEstimate: r(o.effortEstimate),
|
|
166
|
+
projectId: o.projectId || null,
|
|
167
|
+
workItemId: o.workItemId || null
|
|
168
|
+
}, s = {
|
|
169
169
|
title: t.title,
|
|
170
170
|
description: r(t.description),
|
|
171
171
|
businessValue: t.businessValue === "" ? null : Number(t.businessValue),
|
|
172
172
|
effortEstimate: r(t.effortEstimate),
|
|
173
173
|
projectId: t.projectId || null,
|
|
174
174
|
workItemId: t.workItemId || null
|
|
175
|
-
},
|
|
176
|
-
if (Object.keys(
|
|
175
|
+
}, c = Object.fromEntries(Object.entries(i).filter(([e, t]) => t !== s[e]));
|
|
176
|
+
if (Object.keys(c).length === 0) {
|
|
177
177
|
a(!1);
|
|
178
178
|
return;
|
|
179
179
|
}
|
|
180
180
|
try {
|
|
181
181
|
await n(h({ variables: {
|
|
182
182
|
id: e.id,
|
|
183
|
-
input:
|
|
183
|
+
input: c
|
|
184
184
|
} })), a(!1);
|
|
185
185
|
} catch (e) {
|
|
186
186
|
m(e instanceof Error ? e.message : "The request could not be saved.");
|
|
@@ -213,9 +213,9 @@ function L({ feature: e }) {
|
|
|
213
213
|
}), /* @__PURE__ */ _(b, {
|
|
214
214
|
id: "feature-edit-title",
|
|
215
215
|
className: "mt-1",
|
|
216
|
-
value:
|
|
216
|
+
value: o.title,
|
|
217
217
|
onChange: (e) => d({
|
|
218
|
-
...
|
|
218
|
+
...o,
|
|
219
219
|
title: e.target.value
|
|
220
220
|
})
|
|
221
221
|
})] }),
|
|
@@ -226,9 +226,9 @@ function L({ feature: e }) {
|
|
|
226
226
|
}), /* @__PURE__ */ _("textarea", {
|
|
227
227
|
id: "feature-edit-description",
|
|
228
228
|
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[72px]",
|
|
229
|
-
value:
|
|
229
|
+
value: o.description,
|
|
230
230
|
onChange: (e) => d({
|
|
231
|
-
...
|
|
231
|
+
...o,
|
|
232
232
|
description: e.target.value
|
|
233
233
|
})
|
|
234
234
|
})] }),
|
|
@@ -244,10 +244,10 @@ function L({ feature: e }) {
|
|
|
244
244
|
min: 0,
|
|
245
245
|
max: 100,
|
|
246
246
|
className: "mt-1",
|
|
247
|
-
value:
|
|
247
|
+
value: o.businessValue,
|
|
248
248
|
"aria-invalid": k.invalid,
|
|
249
249
|
onChange: (e) => d({
|
|
250
|
-
...
|
|
250
|
+
...o,
|
|
251
251
|
businessValue: e.target.value
|
|
252
252
|
})
|
|
253
253
|
})] }), /* @__PURE__ */ v("div", { children: [/* @__PURE__ */ _("label", {
|
|
@@ -258,9 +258,9 @@ function L({ feature: e }) {
|
|
|
258
258
|
id: "feature-edit-effort",
|
|
259
259
|
className: "mt-1",
|
|
260
260
|
placeholder: "e.g. M",
|
|
261
|
-
value:
|
|
261
|
+
value: o.effortEstimate,
|
|
262
262
|
onChange: (e) => d({
|
|
263
|
-
...
|
|
263
|
+
...o,
|
|
264
264
|
effortEstimate: e.target.value
|
|
265
265
|
})
|
|
266
266
|
})] })]
|
|
@@ -272,12 +272,12 @@ function L({ feature: e }) {
|
|
|
272
272
|
children: "Project"
|
|
273
273
|
}), /* @__PURE__ */ _("div", {
|
|
274
274
|
className: "mt-1",
|
|
275
|
-
children: /* @__PURE__ */ _(
|
|
275
|
+
children: /* @__PURE__ */ _(s, {
|
|
276
276
|
id: "feature-edit-project",
|
|
277
|
-
value:
|
|
277
|
+
value: o.projectId,
|
|
278
278
|
noneLabel: "No project",
|
|
279
279
|
onChange: (e) => d({
|
|
280
|
-
...
|
|
280
|
+
...o,
|
|
281
281
|
projectId: e,
|
|
282
282
|
workItemId: ""
|
|
283
283
|
})
|
|
@@ -289,12 +289,12 @@ function L({ feature: e }) {
|
|
|
289
289
|
children: "Delivered by work item"
|
|
290
290
|
}), /* @__PURE__ */ _("div", {
|
|
291
291
|
className: "mt-1",
|
|
292
|
-
children: /* @__PURE__ */ _(
|
|
292
|
+
children: /* @__PURE__ */ _(c, {
|
|
293
293
|
id: "feature-edit-workitem",
|
|
294
|
-
projectId:
|
|
295
|
-
value:
|
|
294
|
+
projectId: o.projectId || void 0,
|
|
295
|
+
value: o.workItemId,
|
|
296
296
|
onChange: (e) => d({
|
|
297
|
-
...
|
|
297
|
+
...o,
|
|
298
298
|
workItemId: e
|
|
299
299
|
})
|
|
300
300
|
})
|
|
@@ -2,8 +2,8 @@ import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
|
2
2
|
import { LEAVES_PAGE_CONTEXT as t, throwOnError as n } from "../utils/mutationResult.js";
|
|
3
3
|
import { ConfirmButton as r, ErrorLine as i } from "./ConfirmButton.js";
|
|
4
4
|
import { enumLabel as a } from "./WorkItemControls.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { detailPath as o } from "../utils/rowNavigation.js";
|
|
6
|
+
import { ProjectSelect as s } from "./Pickers.js";
|
|
7
7
|
import { PROJECT_STATUSES as c } from "./ProjectControls.js";
|
|
8
8
|
import { useState as l } from "react";
|
|
9
9
|
import { Pencil as u, Trash2 as d, X as f } from "lucide-react";
|
|
@@ -28,7 +28,7 @@ var v = c, y = [
|
|
|
28
28
|
planmagnetDeleteProgram(id: $id)
|
|
29
29
|
}
|
|
30
30
|
`;
|
|
31
|
-
function S({ programId:
|
|
31
|
+
function S({ programId: s, name: c, status: f }) {
|
|
32
32
|
let p = e(), [S, C] = m(b, {
|
|
33
33
|
refetchQueries: y,
|
|
34
34
|
awaitRefetchQueries: !0
|
|
@@ -39,7 +39,7 @@ function S({ programId: o, name: c, status: f }) {
|
|
|
39
39
|
D(null);
|
|
40
40
|
try {
|
|
41
41
|
await n(S({ variables: {
|
|
42
|
-
id:
|
|
42
|
+
id: s,
|
|
43
43
|
input: { status: e }
|
|
44
44
|
} }));
|
|
45
45
|
} catch (e) {
|
|
@@ -48,7 +48,7 @@ function S({ programId: o, name: c, status: f }) {
|
|
|
48
48
|
}, j = async () => {
|
|
49
49
|
D(null);
|
|
50
50
|
try {
|
|
51
|
-
await n(w({ variables: { id:
|
|
51
|
+
await n(w({ variables: { id: s } })), p("/products/programs-page");
|
|
52
52
|
} catch (e) {
|
|
53
53
|
D(e instanceof Error ? e.message : "The program could not be deleted.");
|
|
54
54
|
}
|
|
@@ -76,7 +76,7 @@ function S({ programId: o, name: c, status: f }) {
|
|
|
76
76
|
size: "sm",
|
|
77
77
|
variant: "outline",
|
|
78
78
|
"data-testid": "program-edit",
|
|
79
|
-
onClick: () => p(
|
|
79
|
+
onClick: () => p(o("/products/edit-program-page", s)),
|
|
80
80
|
children: [/* @__PURE__ */ h(u, { className: "mr-1 h-4 w-4" }), "Edit"]
|
|
81
81
|
}),
|
|
82
82
|
/* @__PURE__ */ h(r, {
|
|
@@ -142,7 +142,7 @@ function w({ programId: t, projects: r }) {
|
|
|
142
142
|
/* @__PURE__ */ h("button", {
|
|
143
143
|
type: "button",
|
|
144
144
|
className: "flex-1 text-left text-sm font-medium hover:underline underline-offset-2",
|
|
145
|
-
onClick: () => c(
|
|
145
|
+
onClick: () => c(o("/projects/project-detail-page", e.id)),
|
|
146
146
|
children: e.name
|
|
147
147
|
}),
|
|
148
148
|
/* @__PURE__ */ h("span", {
|
|
@@ -163,7 +163,7 @@ function w({ programId: t, projects: r }) {
|
|
|
163
163
|
className: "flex items-center gap-2 pt-2 border-t",
|
|
164
164
|
children: [/* @__PURE__ */ h("div", {
|
|
165
165
|
className: "flex-1",
|
|
166
|
-
children: /* @__PURE__ */ h(
|
|
166
|
+
children: /* @__PURE__ */ h(s, {
|
|
167
167
|
id: "program-add-project",
|
|
168
168
|
value: u,
|
|
169
169
|
onChange: d,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DependencyGraph.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/dependency/DependencyGraph.tsx"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AAEH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,6FAA6F;IAC7F,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,2FAA2F;IAC3F,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,SAAS,EAAE,MAAM,CAAC;CACnB;AAWD,uGAAuG;AACvG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAMjE;AA0CD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,KAAK,EACL,eAAe,EACf,eAAe,EACf,cAAc,EACd,YAAY,EACZ,SAAS,GACV,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"DependencyGraph.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/dependency/DependencyGraph.tsx"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AAEH,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAC7B,6FAA6F;IAC7F,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,2FAA2F;IAC3F,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,SAAS,EAAE,MAAM,CAAC;CACnB;AAWD,uGAAuG;AACvG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAG/D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAMjE;AA0CD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,KAAK,EACL,eAAe,EACf,eAAe,EACf,cAAc,EACd,YAAY,EACZ,SAAS,GACV,EAAE,oBAAoB,2CA6MtB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { enumLabel as e } from "../controls/WorkItemControls.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { STATUS_LEGEND_ORDER as t, statusVisual as n } from "../utils/statusColor.js";
|
|
3
|
+
import { rowLinkProps as r } from "../utils/rowNavigation.js";
|
|
4
4
|
import { useMemo as i } from "react";
|
|
5
5
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
6
6
|
//#region src/planmagnet/dependency/DependencyGraph.tsx
|
|
@@ -66,7 +66,7 @@ function y({ nodes: y, edges: b, criticalNodeIds: x, criticalEdgeIds: S, onActiv
|
|
|
66
66
|
width: d * 2 + a * s + Math.max(0, a - 1) * l,
|
|
67
67
|
height: d * 2 + o * c + Math.max(0, o - 1) * u
|
|
68
68
|
};
|
|
69
|
-
}, [y, b]), D = i(() =>
|
|
69
|
+
}, [y, b]), D = i(() => t.filter((e) => y.some((t) => t.status === e)), [y]);
|
|
70
70
|
if (y.length === 0) return /* @__PURE__ */ a("div", {
|
|
71
71
|
"data-testid": "dependency-graph",
|
|
72
72
|
className: "p-6 text-center text-sm text-muted-foreground",
|
|
@@ -164,14 +164,14 @@ function y({ nodes: y, edges: b, criticalNodeIds: x, criticalEdgeIds: S, onActiv
|
|
|
164
164
|
]
|
|
165
165
|
}, e.id);
|
|
166
166
|
}),
|
|
167
|
-
y.map((
|
|
168
|
-
let i = E.position.get(
|
|
167
|
+
y.map((t) => {
|
|
168
|
+
let i = E.position.get(t.id);
|
|
169
169
|
if (!i) return null;
|
|
170
|
-
let l = x?.has(
|
|
170
|
+
let l = x?.has(t.id) ?? !1, u = n(t.status), d = t.title ?? "Untitled work item", g = t.key ?? "", _ = `${g ? `${g} — ` : ""}${d} (${e(t.status)})${l ? ", on critical path" : ""}`;
|
|
171
171
|
return /* @__PURE__ */ o("g", {
|
|
172
172
|
"data-testid": "dependency-graph-node",
|
|
173
173
|
transform: `translate(${i.x}, ${i.y})`,
|
|
174
|
-
...
|
|
174
|
+
...r(() => C(t.id), _),
|
|
175
175
|
className: "cursor-pointer focus:outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2",
|
|
176
176
|
children: [
|
|
177
177
|
/* @__PURE__ */ a("title", { children: _ }),
|
|
@@ -186,7 +186,7 @@ function y({ nodes: y, edges: b, criticalNodeIds: x, criticalEdgeIds: S, onActiv
|
|
|
186
186
|
cx: 16,
|
|
187
187
|
cy: c / 2,
|
|
188
188
|
r: f,
|
|
189
|
-
|
|
189
|
+
style: { fill: u.color }
|
|
190
190
|
}),
|
|
191
191
|
/* @__PURE__ */ a("text", {
|
|
192
192
|
x: 28,
|
|
@@ -201,7 +201,7 @@ function y({ nodes: y, edges: b, criticalNodeIds: x, criticalEdgeIds: S, onActiv
|
|
|
201
201
|
children: h(d, p)
|
|
202
202
|
})
|
|
203
203
|
]
|
|
204
|
-
},
|
|
204
|
+
}, t.id);
|
|
205
205
|
})
|
|
206
206
|
]
|
|
207
207
|
})
|
|
@@ -210,7 +210,10 @@ function y({ nodes: y, edges: b, criticalNodeIds: x, criticalEdgeIds: S, onActiv
|
|
|
210
210
|
className: "flex flex-wrap items-center gap-x-4 gap-y-1 border-t border-input px-3 py-2 text-[11px] text-muted-foreground",
|
|
211
211
|
children: [D.map((t) => /* @__PURE__ */ o("span", {
|
|
212
212
|
className: "inline-flex items-center gap-1.5",
|
|
213
|
-
children: [/* @__PURE__ */ a("span", {
|
|
213
|
+
children: [/* @__PURE__ */ a("span", {
|
|
214
|
+
className: "h-2.5 w-2.5 rounded-full",
|
|
215
|
+
style: { backgroundColor: n(t).color }
|
|
216
|
+
}), e(t)]
|
|
214
217
|
}, t)), x && x.size > 0 && /* @__PURE__ */ o("span", {
|
|
215
218
|
className: "inline-flex items-center gap-1.5",
|
|
216
219
|
children: [/* @__PURE__ */ a("span", { className: "h-2.5 w-2.5 rounded-full border-2 border-primary bg-background" }), "Critical path"]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DependencyGraph.js","names":[],"sources":["../../../src/planmagnet/dependency/DependencyGraph.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport { rowLinkProps } from '../utils/rowNavigation';\nimport { statusVisual, STATUS_LEGEND_ORDER } from '../utils/statusColor';\n\n/**\n * Reusable SVG dependency graph (PDM-27). Nodes are work items, edges are `WorkItemDependency` rows, laid out in\n * layers left-to-right by longest-path topological order. Two mount points share this component:\n * - the critical-path page's \"Graph\" view (the whole project — see useProjectWorkItemsGraph.ts)\n * - the task dependency panel's one-hop neighbourhood graph (this item, its predecessors, its successors)\n *\n * The existing text list stays the accessible/no-JS-heavy fallback at every call site — this component is an\n * additional view, never a replacement for it.\n */\n\nexport interface DependencyGraphNode {\n id: string;\n key: string | null;\n title: string | null;\n status: string;\n}\n\nexport interface DependencyGraphEdge {\n /** The WorkItemDependency's own id — stable per edge, used as the React key. */\n id: string;\n predecessorId: string;\n successorId: string;\n /** A DependencyType value. */\n type: string;\n lagMinutes: number | null;\n}\n\nexport interface DependencyGraphProps {\n nodes: DependencyGraphNode[];\n edges: DependencyGraphEdge[];\n /** Node ids on the critical path (CPM chain) — emphasised with a thicker primary outline. */\n criticalNodeIds?: ReadonlySet<string>;\n /** Edge ids that connect two consecutive critical-path nodes — emphasised the same way. */\n criticalEdgeIds?: ReadonlySet<string>;\n onActivateNode: (nodeId: string) => void;\n /** Shown instead of the graph when `nodes` is empty. */\n emptyMessage: string;\n /** Accessible name for the graph region — should say what project/item it scopes to. */\n ariaLabel: string;\n}\n\nconst NODE_WIDTH = 180;\nconst NODE_HEIGHT = 56;\nconst LAYER_GAP_X = 72;\nconst NODE_GAP_Y = 16;\nconst PADDING = 20;\nconst CHIP_R = 4;\nconst TITLE_MAX_CHARS = 24;\nconst KEY_MAX_CHARS = 16;\n\n/** Shared with GanttChart.tsx, which draws the same dependency edges between bars instead of nodes. */\nexport function truncate(text: string, maxChars: number): string {\n if (text.length <= maxChars) return text;\n return `${text.slice(0, Math.max(1, maxChars - 1))}…`;\n}\n\nexport function dependencyTypeLabel(type: string): string {\n switch (type) {\n case 'FINISH_TO_START':\n return 'Finish to start';\n case 'START_TO_START':\n return 'Start to start';\n case 'FINISH_TO_FINISH':\n return 'Finish to finish';\n case 'START_TO_FINISH':\n return 'Start to finish';\n default:\n return enumLabel(type);\n }\n}\n\nexport function lagLabel(lagMinutes: number | null): string | null {\n if (!lagMinutes) return null;\n const days = lagMinutes / (60 * 24);\n const verb = lagMinutes > 0 ? 'lag' : 'lead';\n if (Number.isInteger(days)) return `${Math.abs(days)}d ${verb}`;\n return `${Math.abs(Math.round((lagMinutes / 60) * 10) / 10)}h ${verb}`;\n}\n\n/**\n * Longest-path layering with a cycle guard. Every node ends up on the layer one past the FURTHEST-along of its\n * (in-graph) predecessors — never merely the first predecessor visited — so an edge never points backward across\n * layers except when a cycle forces it (the server refuses cycles; this is defensive, not the expected path).\n *\n * `resolving` tracks ids currently on the call stack: a predecessor already being resolved (a back-edge closing a\n * cycle) is treated as layer -1 (contributing 0) rather than recursed into again, so this always terminates —\n * every id is visited at most once per still-active ancestor chain, bounded by `nodeIds.length`.\n */\nfunction computeLayers(\n nodeIds: string[],\n edges: { predecessorId: string; successorId: string }[]\n): Map<string, number> {\n const predecessorsOf = new Map<string, string[]>(nodeIds.map((id) => [id, []]));\n for (const e of edges) {\n const preds = predecessorsOf.get(e.successorId);\n if (preds && predecessorsOf.has(e.predecessorId)) preds.push(e.predecessorId);\n }\n\n const layer = new Map<string, number>();\n const resolving = new Set<string>();\n\n function resolve(id: string, depth: number): number {\n const cached = layer.get(id);\n if (cached !== undefined) return cached;\n if (resolving.has(id) || depth > nodeIds.length) return -1;\n resolving.add(id);\n const preds = predecessorsOf.get(id) ?? [];\n let max = -1;\n for (const p of preds) max = Math.max(max, resolve(p, depth + 1));\n resolving.delete(id);\n const result = max + 1;\n layer.set(id, result);\n return result;\n }\n\n for (const id of nodeIds) resolve(id, 0);\n return layer;\n}\n\nexport function DependencyGraph({\n nodes,\n edges,\n criticalNodeIds,\n criticalEdgeIds,\n onActivateNode,\n emptyMessage,\n ariaLabel,\n}: DependencyGraphProps) {\n const layout = useMemo(() => {\n const nodeIds = nodes.map((n) => n.id);\n const nodeSet = new Set(nodeIds);\n // Cross-scope edges (e.g. a dependency on a work item outside this project, or outside this item's one-hop\n // neighbourhood) have no node to draw — drop them rather than crash on a missing endpoint.\n const inScopeEdges = edges.filter(\n (e) => nodeSet.has(e.predecessorId) && nodeSet.has(e.successorId)\n );\n const layerOf = computeLayers(nodeIds, inScopeEdges);\n\n const byLayer = new Map<number, string[]>();\n for (const id of nodeIds) {\n const l = layerOf.get(id) ?? 0;\n const list = byLayer.get(l);\n if (list) list.push(id);\n else byLayer.set(l, [id]);\n }\n const layerCount = byLayer.size === 0 ? 1 : Math.max(...byLayer.keys()) + 1;\n const maxPerLayer = Math.max(1, ...Array.from(byLayer.values(), (l) => l.length));\n\n const position = new Map<string, { x: number; y: number }>();\n for (const [l, ids] of byLayer) {\n const x = PADDING + l * (NODE_WIDTH + LAYER_GAP_X);\n // Centered vertically within the tallest layer, so a short layer doesn't hug the top.\n const layerHeight = ids.length * NODE_HEIGHT + (ids.length - 1) * NODE_GAP_Y;\n const fullHeight = maxPerLayer * NODE_HEIGHT + (maxPerLayer - 1) * NODE_GAP_Y;\n const yOffset = PADDING + Math.max(0, (fullHeight - layerHeight) / 2);\n ids.forEach((id, i) => {\n position.set(id, { x, y: yOffset + i * (NODE_HEIGHT + NODE_GAP_Y) });\n });\n }\n\n const width = PADDING * 2 + layerCount * NODE_WIDTH + Math.max(0, layerCount - 1) * LAYER_GAP_X;\n const height =\n PADDING * 2 + maxPerLayer * NODE_HEIGHT + Math.max(0, maxPerLayer - 1) * NODE_GAP_Y;\n\n return { position, inScopeEdges, width, height };\n }, [nodes, edges]);\n\n const presentStatuses = useMemo(\n () => STATUS_LEGEND_ORDER.filter((s) => nodes.some((n) => n.status === s)),\n [nodes]\n );\n\n if (nodes.length === 0) {\n return (\n <div data-testid=\"dependency-graph\" className=\"p-6 text-center text-sm text-muted-foreground\">\n {emptyMessage}\n </div>\n );\n }\n\n const nodesById = new Map(nodes.map((n) => [n.id, n]));\n\n return (\n <div data-testid=\"dependency-graph\" className=\"rounded-md border border-input bg-background\">\n <p className=\"sr-only\">\n Dependency graph with {nodes.length} work item{nodes.length === 1 ? '' : 's'} and{' '}\n {layout.inScopeEdges.length} dependenc{layout.inScopeEdges.length === 1 ? 'y' : 'ies'}.\n {criticalNodeIds && criticalNodeIds.size > 0\n ? ` ${criticalNodeIds.size} item${criticalNodeIds.size === 1 ? ' is' : 's are'} on the critical path.`\n : ''}{' '}\n The list above/below gives the same information as text.\n </p>\n <div className=\"overflow-x-auto p-3\">\n {/* No role=\"img\" here: each node below is its own focusable role=\"button\" descendant, and \"img\"\n semantics would tell assistive tech to treat the whole subtree as a single flattened image. */}\n <svg\n aria-label={ariaLabel}\n width={layout.width}\n height={layout.height}\n viewBox={`0 0 ${layout.width} ${layout.height}`}\n className=\"block\"\n >\n <defs>\n <marker\n id=\"dependency-graph-arrow\"\n viewBox=\"0 0 10 10\"\n refX=\"9\"\n refY=\"5\"\n markerWidth=\"6\"\n markerHeight=\"6\"\n orient=\"auto-start-reverse\"\n className=\"text-border-strong\"\n >\n <path d=\"M0,0 L10,5 L0,10 z\" fill=\"currentColor\" />\n </marker>\n <marker\n id=\"dependency-graph-arrow-critical\"\n viewBox=\"0 0 10 10\"\n refX=\"9\"\n refY=\"5\"\n markerWidth=\"6\"\n markerHeight=\"6\"\n orient=\"auto-start-reverse\"\n className=\"text-primary\"\n >\n <path d=\"M0,0 L10,5 L0,10 z\" fill=\"currentColor\" />\n </marker>\n </defs>\n\n {layout.inScopeEdges.map((edge) => {\n const from = layout.position.get(edge.predecessorId);\n const to = layout.position.get(edge.successorId);\n if (!from || !to) return null;\n const x1 = from.x + NODE_WIDTH;\n const y1 = from.y + NODE_HEIGHT / 2;\n const x2 = to.x;\n const y2 = to.y + NODE_HEIGHT / 2;\n const midX = (x1 + x2) / 2;\n const critical = criticalEdgeIds?.has(edge.id) ?? false;\n const typeLabel =\n edge.type === 'FINISH_TO_START' ? null : dependencyTypeLabel(edge.type);\n const lag = lagLabel(edge.lagMinutes);\n const label = [typeLabel, lag].filter((v): v is string => !!v).join(' · ');\n const predecessor = nodesById.get(edge.predecessorId);\n const successor = nodesById.get(edge.successorId);\n return (\n <g key={edge.id} data-testid=\"dependency-graph-edge\">\n <title>\n {predecessor?.key ?? edge.predecessorId} {dependencyTypeLabel(edge.type)}{' '}\n {successor?.key ?? edge.successorId}\n {lag ? ` (${lag})` : ''}\n </title>\n <path\n d={`M ${x1},${y1} C ${midX},${y1} ${midX},${y2} ${x2},${y2}`}\n fill=\"none\"\n strokeWidth={critical ? 2.5 : 1.5}\n className={critical ? 'text-primary' : 'text-border-strong'}\n stroke=\"currentColor\"\n markerEnd={`url(#${critical ? 'dependency-graph-arrow-critical' : 'dependency-graph-arrow'})`}\n />\n {label && (\n <text\n x={midX}\n y={(y1 + y2) / 2 - 4}\n textAnchor=\"middle\"\n className=\"fill-muted-foreground text-[9px]\"\n >\n {label}\n </text>\n )}\n </g>\n );\n })}\n\n {nodes.map((node) => {\n const pos = layout.position.get(node.id);\n if (!pos) return null;\n const critical = criticalNodeIds?.has(node.id) ?? false;\n const visual = statusVisual(node.status);\n const title = node.title ?? 'Untitled work item';\n const keyLabel = node.key ?? '';\n const accessibleLabel = `${keyLabel ? `${keyLabel} — ` : ''}${title} (${enumLabel(node.status)})${critical ? ', on critical path' : ''}`;\n // ROW_LINK_CLASS (in the rowLinkProps spread below) rings via box-shadow, which SVG elements\n // outside a <foreignObject> don't paint — the explicit className after the spread overrides it\n // with an outline-based focus style, which they do.\n return (\n <g\n key={node.id}\n data-testid=\"dependency-graph-node\"\n transform={`translate(${pos.x}, ${pos.y})`}\n {...rowLinkProps<SVGGElement>(() => onActivateNode(node.id), accessibleLabel)}\n className=\"cursor-pointer focus:outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2\"\n >\n <title>{accessibleLabel}</title>\n <rect\n width={NODE_WIDTH}\n height={NODE_HEIGHT}\n rx={8}\n className={`fill-background ${critical ? 'stroke-primary' : 'stroke-input'}`}\n strokeWidth={critical ? 2 : 1}\n />\n <circle cx={16} cy={NODE_HEIGHT / 2} r={CHIP_R} className={visual.fill} />\n <text x={28} y={22} className=\"fill-muted-foreground text-[10px] font-medium\">\n {truncate(keyLabel, KEY_MAX_CHARS)}\n </text>\n <text x={28} y={38} className=\"fill-foreground text-[11px] font-medium\">\n {truncate(title, TITLE_MAX_CHARS)}\n </text>\n </g>\n );\n })}\n </svg>\n </div>\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 border-t border-input px-3 py-2 text-[11px] text-muted-foreground\">\n {presentStatuses.map((status) => (\n <span key={status} className=\"inline-flex items-center gap-1.5\">\n <span className={`h-2.5 w-2.5 rounded-full ${statusVisual(status).swatch}`} />\n {enumLabel(status)}\n </span>\n ))}\n {criticalNodeIds && criticalNodeIds.size > 0 && (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-full border-2 border-primary bg-background\" />\n Critical path\n </span>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DependencyGraph.js","names":[],"sources":["../../../src/planmagnet/dependency/DependencyGraph.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport { enumLabel } from '../controls/WorkItemControls';\nimport { rowLinkProps } from '../utils/rowNavigation';\nimport { statusVisual, STATUS_LEGEND_ORDER } from '../utils/statusColor';\n\n/**\n * Reusable SVG dependency graph (PDM-27). Nodes are work items, edges are `WorkItemDependency` rows, laid out in\n * layers left-to-right by longest-path topological order. Two mount points share this component:\n * - the critical-path page's \"Graph\" view (the whole project — see useProjectWorkItemsGraph.ts)\n * - the task dependency panel's one-hop neighbourhood graph (this item, its predecessors, its successors)\n *\n * The existing text list stays the accessible/no-JS-heavy fallback at every call site — this component is an\n * additional view, never a replacement for it.\n */\n\nexport interface DependencyGraphNode {\n id: string;\n key: string | null;\n title: string | null;\n status: string;\n}\n\nexport interface DependencyGraphEdge {\n /** The WorkItemDependency's own id — stable per edge, used as the React key. */\n id: string;\n predecessorId: string;\n successorId: string;\n /** A DependencyType value. */\n type: string;\n lagMinutes: number | null;\n}\n\nexport interface DependencyGraphProps {\n nodes: DependencyGraphNode[];\n edges: DependencyGraphEdge[];\n /** Node ids on the critical path (CPM chain) — emphasised with a thicker primary outline. */\n criticalNodeIds?: ReadonlySet<string>;\n /** Edge ids that connect two consecutive critical-path nodes — emphasised the same way. */\n criticalEdgeIds?: ReadonlySet<string>;\n onActivateNode: (nodeId: string) => void;\n /** Shown instead of the graph when `nodes` is empty. */\n emptyMessage: string;\n /** Accessible name for the graph region — should say what project/item it scopes to. */\n ariaLabel: string;\n}\n\nconst NODE_WIDTH = 180;\nconst NODE_HEIGHT = 56;\nconst LAYER_GAP_X = 72;\nconst NODE_GAP_Y = 16;\nconst PADDING = 20;\nconst CHIP_R = 4;\nconst TITLE_MAX_CHARS = 24;\nconst KEY_MAX_CHARS = 16;\n\n/** Shared with GanttChart.tsx, which draws the same dependency edges between bars instead of nodes. */\nexport function truncate(text: string, maxChars: number): string {\n if (text.length <= maxChars) return text;\n return `${text.slice(0, Math.max(1, maxChars - 1))}…`;\n}\n\nexport function dependencyTypeLabel(type: string): string {\n switch (type) {\n case 'FINISH_TO_START':\n return 'Finish to start';\n case 'START_TO_START':\n return 'Start to start';\n case 'FINISH_TO_FINISH':\n return 'Finish to finish';\n case 'START_TO_FINISH':\n return 'Start to finish';\n default:\n return enumLabel(type);\n }\n}\n\nexport function lagLabel(lagMinutes: number | null): string | null {\n if (!lagMinutes) return null;\n const days = lagMinutes / (60 * 24);\n const verb = lagMinutes > 0 ? 'lag' : 'lead';\n if (Number.isInteger(days)) return `${Math.abs(days)}d ${verb}`;\n return `${Math.abs(Math.round((lagMinutes / 60) * 10) / 10)}h ${verb}`;\n}\n\n/**\n * Longest-path layering with a cycle guard. Every node ends up on the layer one past the FURTHEST-along of its\n * (in-graph) predecessors — never merely the first predecessor visited — so an edge never points backward across\n * layers except when a cycle forces it (the server refuses cycles; this is defensive, not the expected path).\n *\n * `resolving` tracks ids currently on the call stack: a predecessor already being resolved (a back-edge closing a\n * cycle) is treated as layer -1 (contributing 0) rather than recursed into again, so this always terminates —\n * every id is visited at most once per still-active ancestor chain, bounded by `nodeIds.length`.\n */\nfunction computeLayers(\n nodeIds: string[],\n edges: { predecessorId: string; successorId: string }[]\n): Map<string, number> {\n const predecessorsOf = new Map<string, string[]>(nodeIds.map((id) => [id, []]));\n for (const e of edges) {\n const preds = predecessorsOf.get(e.successorId);\n if (preds && predecessorsOf.has(e.predecessorId)) preds.push(e.predecessorId);\n }\n\n const layer = new Map<string, number>();\n const resolving = new Set<string>();\n\n function resolve(id: string, depth: number): number {\n const cached = layer.get(id);\n if (cached !== undefined) return cached;\n if (resolving.has(id) || depth > nodeIds.length) return -1;\n resolving.add(id);\n const preds = predecessorsOf.get(id) ?? [];\n let max = -1;\n for (const p of preds) max = Math.max(max, resolve(p, depth + 1));\n resolving.delete(id);\n const result = max + 1;\n layer.set(id, result);\n return result;\n }\n\n for (const id of nodeIds) resolve(id, 0);\n return layer;\n}\n\nexport function DependencyGraph({\n nodes,\n edges,\n criticalNodeIds,\n criticalEdgeIds,\n onActivateNode,\n emptyMessage,\n ariaLabel,\n}: DependencyGraphProps) {\n const layout = useMemo(() => {\n const nodeIds = nodes.map((n) => n.id);\n const nodeSet = new Set(nodeIds);\n // Cross-scope edges (e.g. a dependency on a work item outside this project, or outside this item's one-hop\n // neighbourhood) have no node to draw — drop them rather than crash on a missing endpoint.\n const inScopeEdges = edges.filter(\n (e) => nodeSet.has(e.predecessorId) && nodeSet.has(e.successorId)\n );\n const layerOf = computeLayers(nodeIds, inScopeEdges);\n\n const byLayer = new Map<number, string[]>();\n for (const id of nodeIds) {\n const l = layerOf.get(id) ?? 0;\n const list = byLayer.get(l);\n if (list) list.push(id);\n else byLayer.set(l, [id]);\n }\n const layerCount = byLayer.size === 0 ? 1 : Math.max(...byLayer.keys()) + 1;\n const maxPerLayer = Math.max(1, ...Array.from(byLayer.values(), (l) => l.length));\n\n const position = new Map<string, { x: number; y: number }>();\n for (const [l, ids] of byLayer) {\n const x = PADDING + l * (NODE_WIDTH + LAYER_GAP_X);\n // Centered vertically within the tallest layer, so a short layer doesn't hug the top.\n const layerHeight = ids.length * NODE_HEIGHT + (ids.length - 1) * NODE_GAP_Y;\n const fullHeight = maxPerLayer * NODE_HEIGHT + (maxPerLayer - 1) * NODE_GAP_Y;\n const yOffset = PADDING + Math.max(0, (fullHeight - layerHeight) / 2);\n ids.forEach((id, i) => {\n position.set(id, { x, y: yOffset + i * (NODE_HEIGHT + NODE_GAP_Y) });\n });\n }\n\n const width = PADDING * 2 + layerCount * NODE_WIDTH + Math.max(0, layerCount - 1) * LAYER_GAP_X;\n const height =\n PADDING * 2 + maxPerLayer * NODE_HEIGHT + Math.max(0, maxPerLayer - 1) * NODE_GAP_Y;\n\n return { position, inScopeEdges, width, height };\n }, [nodes, edges]);\n\n const presentStatuses = useMemo(\n () => STATUS_LEGEND_ORDER.filter((s) => nodes.some((n) => n.status === s)),\n [nodes]\n );\n\n if (nodes.length === 0) {\n return (\n <div data-testid=\"dependency-graph\" className=\"p-6 text-center text-sm text-muted-foreground\">\n {emptyMessage}\n </div>\n );\n }\n\n const nodesById = new Map(nodes.map((n) => [n.id, n]));\n\n return (\n <div data-testid=\"dependency-graph\" className=\"rounded-md border border-input bg-background\">\n <p className=\"sr-only\">\n Dependency graph with {nodes.length} work item{nodes.length === 1 ? '' : 's'} and{' '}\n {layout.inScopeEdges.length} dependenc{layout.inScopeEdges.length === 1 ? 'y' : 'ies'}.\n {criticalNodeIds && criticalNodeIds.size > 0\n ? ` ${criticalNodeIds.size} item${criticalNodeIds.size === 1 ? ' is' : 's are'} on the critical path.`\n : ''}{' '}\n The list above/below gives the same information as text.\n </p>\n <div className=\"overflow-x-auto p-3\">\n {/* No role=\"img\" here: each node below is its own focusable role=\"button\" descendant, and \"img\"\n semantics would tell assistive tech to treat the whole subtree as a single flattened image. */}\n <svg\n aria-label={ariaLabel}\n width={layout.width}\n height={layout.height}\n viewBox={`0 0 ${layout.width} ${layout.height}`}\n className=\"block\"\n >\n <defs>\n <marker\n id=\"dependency-graph-arrow\"\n viewBox=\"0 0 10 10\"\n refX=\"9\"\n refY=\"5\"\n markerWidth=\"6\"\n markerHeight=\"6\"\n orient=\"auto-start-reverse\"\n className=\"text-border-strong\"\n >\n <path d=\"M0,0 L10,5 L0,10 z\" fill=\"currentColor\" />\n </marker>\n <marker\n id=\"dependency-graph-arrow-critical\"\n viewBox=\"0 0 10 10\"\n refX=\"9\"\n refY=\"5\"\n markerWidth=\"6\"\n markerHeight=\"6\"\n orient=\"auto-start-reverse\"\n className=\"text-primary\"\n >\n <path d=\"M0,0 L10,5 L0,10 z\" fill=\"currentColor\" />\n </marker>\n </defs>\n\n {layout.inScopeEdges.map((edge) => {\n const from = layout.position.get(edge.predecessorId);\n const to = layout.position.get(edge.successorId);\n if (!from || !to) return null;\n const x1 = from.x + NODE_WIDTH;\n const y1 = from.y + NODE_HEIGHT / 2;\n const x2 = to.x;\n const y2 = to.y + NODE_HEIGHT / 2;\n const midX = (x1 + x2) / 2;\n const critical = criticalEdgeIds?.has(edge.id) ?? false;\n const typeLabel =\n edge.type === 'FINISH_TO_START' ? null : dependencyTypeLabel(edge.type);\n const lag = lagLabel(edge.lagMinutes);\n const label = [typeLabel, lag].filter((v): v is string => !!v).join(' · ');\n const predecessor = nodesById.get(edge.predecessorId);\n const successor = nodesById.get(edge.successorId);\n return (\n <g key={edge.id} data-testid=\"dependency-graph-edge\">\n <title>\n {predecessor?.key ?? edge.predecessorId} {dependencyTypeLabel(edge.type)}{' '}\n {successor?.key ?? edge.successorId}\n {lag ? ` (${lag})` : ''}\n </title>\n <path\n d={`M ${x1},${y1} C ${midX},${y1} ${midX},${y2} ${x2},${y2}`}\n fill=\"none\"\n strokeWidth={critical ? 2.5 : 1.5}\n className={critical ? 'text-primary' : 'text-border-strong'}\n stroke=\"currentColor\"\n markerEnd={`url(#${critical ? 'dependency-graph-arrow-critical' : 'dependency-graph-arrow'})`}\n />\n {label && (\n <text\n x={midX}\n y={(y1 + y2) / 2 - 4}\n textAnchor=\"middle\"\n className=\"fill-muted-foreground text-[9px]\"\n >\n {label}\n </text>\n )}\n </g>\n );\n })}\n\n {nodes.map((node) => {\n const pos = layout.position.get(node.id);\n if (!pos) return null;\n const critical = criticalNodeIds?.has(node.id) ?? false;\n const visual = statusVisual(node.status);\n const title = node.title ?? 'Untitled work item';\n const keyLabel = node.key ?? '';\n const accessibleLabel = `${keyLabel ? `${keyLabel} — ` : ''}${title} (${enumLabel(node.status)})${critical ? ', on critical path' : ''}`;\n // ROW_LINK_CLASS (in the rowLinkProps spread below) rings via box-shadow, which SVG elements\n // outside a <foreignObject> don't paint — the explicit className after the spread overrides it\n // with an outline-based focus style, which they do.\n return (\n <g\n key={node.id}\n data-testid=\"dependency-graph-node\"\n transform={`translate(${pos.x}, ${pos.y})`}\n {...rowLinkProps<SVGGElement>(() => onActivateNode(node.id), accessibleLabel)}\n className=\"cursor-pointer focus:outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-primary focus-visible:outline-offset-2\"\n >\n <title>{accessibleLabel}</title>\n <rect\n width={NODE_WIDTH}\n height={NODE_HEIGHT}\n rx={8}\n className={`fill-background ${critical ? 'stroke-primary' : 'stroke-input'}`}\n strokeWidth={critical ? 2 : 1}\n />\n <circle cx={16} cy={NODE_HEIGHT / 2} r={CHIP_R} style={{ fill: visual.color }} />\n <text x={28} y={22} className=\"fill-muted-foreground text-[10px] font-medium\">\n {truncate(keyLabel, KEY_MAX_CHARS)}\n </text>\n <text x={28} y={38} className=\"fill-foreground text-[11px] font-medium\">\n {truncate(title, TITLE_MAX_CHARS)}\n </text>\n </g>\n );\n })}\n </svg>\n </div>\n <div className=\"flex flex-wrap items-center gap-x-4 gap-y-1 border-t border-input px-3 py-2 text-[11px] text-muted-foreground\">\n {presentStatuses.map((status) => (\n <span key={status} className=\"inline-flex items-center gap-1.5\">\n <span\n className=\"h-2.5 w-2.5 rounded-full\"\n style={{ backgroundColor: statusVisual(status).color }}\n />\n {enumLabel(status)}\n </span>\n ))}\n {criticalNodeIds && criticalNodeIds.size > 0 && (\n <span className=\"inline-flex items-center gap-1.5\">\n <span className=\"h-2.5 w-2.5 rounded-full border-2 border-primary bg-background\" />\n Critical path\n </span>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
|
2
2
|
import { throwOnError as t } from "../utils/mutationResult.js";
|
|
3
3
|
import { ErrorLine as n } from "../controls/ConfirmButton.js";
|
|
4
4
|
import { enumLabel as r } from "../controls/WorkItemControls.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { DependencyGraph as i } from "./DependencyGraph.js";
|
|
6
|
+
import { WorkItemSearchSelect as a } from "../controls/Pickers.js";
|
|
7
7
|
import { useState as o } from "react";
|
|
8
8
|
import { ArrowLeft as s, ArrowRight as c, Plus as l, X as u } from "lucide-react";
|
|
9
9
|
import { gql as d } from "@apollo/client";
|
|
@@ -118,7 +118,7 @@ function D({ keyLabel: e, title: t, type: n, lagMinutes: i, onOpen: a, onRemove:
|
|
|
118
118
|
})]
|
|
119
119
|
});
|
|
120
120
|
}
|
|
121
|
-
function O({ workItemId: e, projectId:
|
|
121
|
+
function O({ workItemId: e, projectId: i, excludeIds: s, onDone: c }) {
|
|
122
122
|
let [l, u] = o("blocks"), [d, p] = o(""), [_, v] = o("FINISH_TO_START"), [y, b] = o(""), [S, C] = o(null), [T, { loading: E }] = f(w, {
|
|
123
123
|
refetchQueries: ["GetWorkItemDependencies", "GetProjectCriticalPath"],
|
|
124
124
|
awaitRefetchQueries: !0
|
|
@@ -166,9 +166,9 @@ function O({ workItemId: e, projectId: a, excludeIds: s, onDone: c }) {
|
|
|
166
166
|
children: "Blocked by…"
|
|
167
167
|
})]
|
|
168
168
|
}),
|
|
169
|
-
/* @__PURE__ */ m(
|
|
169
|
+
/* @__PURE__ */ m(a, {
|
|
170
170
|
id: "dependency-other-work-item",
|
|
171
|
-
projectId:
|
|
171
|
+
projectId: i,
|
|
172
172
|
value: d,
|
|
173
173
|
onChange: p,
|
|
174
174
|
exclude: s
|
|
@@ -220,18 +220,18 @@ function O({ workItemId: e, projectId: a, excludeIds: s, onDone: c }) {
|
|
|
220
220
|
]
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
|
-
function k({ workspaceId: r, workItemId:
|
|
223
|
+
function k({ workspaceId: r, workItemId: a, projectId: u }) {
|
|
224
224
|
let d = e(), [x, w] = o(!1), [E, k] = o(null), { data: A, loading: j, error: M, refetch: N } = p(S, {
|
|
225
225
|
variables: {
|
|
226
226
|
workspaceId: r,
|
|
227
|
-
workItemId:
|
|
227
|
+
workItemId: a
|
|
228
228
|
},
|
|
229
|
-
skip: !r || !
|
|
229
|
+
skip: !r || !a
|
|
230
230
|
}), { data: P, error: F } = p(C, {
|
|
231
|
-
variables: { id:
|
|
232
|
-
skip: !
|
|
231
|
+
variables: { id: a },
|
|
232
|
+
skip: !a
|
|
233
233
|
}), [I, { loading: L }] = f(T, { refetchQueries: ["GetWorkItemDependencies", "GetProjectCriticalPath"] }), R = A?.blocks.items ?? [], z = A?.blockedBy.items ?? [], B = [
|
|
234
|
-
|
|
234
|
+
a,
|
|
235
235
|
...R.map((e) => e.successorId),
|
|
236
236
|
...z.map((e) => e.predecessorId)
|
|
237
237
|
], V = P?.planmagnetWorkItem ?? null, H = /* @__PURE__ */ new Map();
|
|
@@ -270,7 +270,7 @@ function k({ workspaceId: r, workItemId: i, projectId: u }) {
|
|
|
270
270
|
className: "space-y-4",
|
|
271
271
|
children: [
|
|
272
272
|
x && /* @__PURE__ */ m(O, {
|
|
273
|
-
workItemId:
|
|
273
|
+
workItemId: a,
|
|
274
274
|
projectId: u,
|
|
275
275
|
excludeIds: B,
|
|
276
276
|
onDone: () => {
|
|
@@ -340,7 +340,7 @@ function k({ workspaceId: r, workItemId: i, projectId: u }) {
|
|
|
340
340
|
V && (R.length > 0 || z.length > 0) && /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
341
341
|
className: "mb-2 text-xs font-medium text-muted-foreground uppercase",
|
|
342
342
|
children: "Neighbourhood graph"
|
|
343
|
-
}), /* @__PURE__ */ m(
|
|
343
|
+
}), /* @__PURE__ */ m(i, {
|
|
344
344
|
nodes: Array.from(H.values()),
|
|
345
345
|
edges: U,
|
|
346
346
|
onActivateNode: (e) => d(`/tasks/task-detail-page?taskId=${encodeURIComponent(e)}`),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GanttChart.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/dependency/GanttChart.tsx"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,eAAe,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,2GAA2G;IAC3G,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,4EAA4E;IAC5E,KAAK,CAAC,EAAE,IAAI,CAAC;CACd;AAsED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,WAAW,EACX,eAAe,EACf,IAAI,EACJ,aAAa,EACb,KAAK,GACN,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"GanttChart.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/dependency/GanttChart.tsx"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,eAAe,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,2GAA2G;IAC3G,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,4EAA4E;IAC5E,KAAK,CAAC,EAAE,IAAI,CAAC;CACd;AAsED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,WAAW,EACX,eAAe,EACf,IAAI,EACJ,aAAa,EACb,KAAK,GACN,EAAE,eAAe,2CAmTjB"}
|
|
@@ -200,13 +200,14 @@ function T({ items: b, criticalIds: T, criticalEdgeIds: E, zoom: D, onActivateRo
|
|
|
200
200
|
x2: A.x(e.day),
|
|
201
201
|
y1: 0,
|
|
202
202
|
y2: A.plotHeight,
|
|
203
|
-
|
|
203
|
+
style: { color: "var(--color-chart-grid)" },
|
|
204
204
|
stroke: "currentColor",
|
|
205
205
|
strokeWidth: 1
|
|
206
206
|
}), /* @__PURE__ */ s("text", {
|
|
207
207
|
x: A.x(e.day) + 3,
|
|
208
208
|
y: p - 10,
|
|
209
|
-
className: "
|
|
209
|
+
className: "text-[10px]",
|
|
210
|
+
style: { fill: "var(--color-chart-axis)" },
|
|
210
211
|
children: e.label
|
|
211
212
|
})] }, e.day)),
|
|
212
213
|
/* @__PURE__ */ s("line", {
|
|
@@ -250,7 +251,8 @@ function T({ items: b, criticalIds: T, criticalEdgeIds: E, zoom: D, onActivateRo
|
|
|
250
251
|
width: h,
|
|
251
252
|
height: h,
|
|
252
253
|
transform: `rotate(45 ${e} ${i})`,
|
|
253
|
-
className:
|
|
254
|
+
className: a ? "stroke-primary" : "stroke-input",
|
|
255
|
+
style: { fill: o.color },
|
|
254
256
|
strokeWidth: a ? 2 : 1
|
|
255
257
|
})]
|
|
256
258
|
}, t.item.id);
|
|
@@ -264,7 +266,8 @@ function T({ items: b, criticalIds: T, criticalEdgeIds: E, zoom: D, onActivateRo
|
|
|
264
266
|
width: _,
|
|
265
267
|
height: m,
|
|
266
268
|
rx: 4,
|
|
267
|
-
className:
|
|
269
|
+
className: a ? "stroke-primary" : "stroke-input",
|
|
270
|
+
style: { fill: o.color },
|
|
268
271
|
strokeWidth: a ? 2 : 1
|
|
269
272
|
})]
|
|
270
273
|
}, t.item.id);
|
|
@@ -278,7 +281,10 @@ function T({ items: b, criticalIds: T, criticalEdgeIds: E, zoom: D, onActivateRo
|
|
|
278
281
|
children: [
|
|
279
282
|
j.map((t) => /* @__PURE__ */ c("span", {
|
|
280
283
|
className: "inline-flex items-center gap-1.5",
|
|
281
|
-
children: [/* @__PURE__ */ s("span", {
|
|
284
|
+
children: [/* @__PURE__ */ s("span", {
|
|
285
|
+
className: "h-2.5 w-2.5 rounded-full",
|
|
286
|
+
style: { backgroundColor: n(t).color }
|
|
287
|
+
}), e(t)]
|
|
282
288
|
}, t)),
|
|
283
289
|
/* @__PURE__ */ c("span", {
|
|
284
290
|
className: "inline-flex items-center gap-1.5",
|