@burdenoff/microfe-planmagnet 2026.1001.6 → 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.
- package/dist/planmagnet/PlanMagnetRoutes.d.ts.map +1 -1
- package/dist/planmagnet/PlanMagnetRoutes.js +10 -6
- package/dist/planmagnet/PlanMagnetRoutes.js.map +1 -1
- package/dist/planmagnet/automation/automationRuleTypes.d.ts +31 -19
- package/dist/planmagnet/automation/automationRuleTypes.d.ts.map +1 -1
- package/dist/planmagnet/automation/automationRuleTypes.js +4 -8
- package/dist/planmagnet/automation/automationRuleTypes.js.map +1 -1
- package/dist/planmagnet/controls/FeatureControls.d.ts +18 -1
- package/dist/planmagnet/controls/FeatureControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/FeatureControls.js +259 -202
- package/dist/planmagnet/controls/FeatureControls.js.map +1 -1
- package/dist/planmagnet/controls/FeedbackControls.d.ts +70 -0
- package/dist/planmagnet/controls/FeedbackControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/FeedbackControls.js +153 -0
- package/dist/planmagnet/controls/FeedbackControls.js.map +1 -0
- package/dist/planmagnet/controls/SyncControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/SyncControls.js +1 -0
- package/dist/planmagnet/controls/SyncControls.js.map +1 -1
- package/dist/planmagnet/controls/WebhookSubscriptionControls.d.ts +47 -0
- package/dist/planmagnet/controls/WebhookSubscriptionControls.d.ts.map +1 -0
- package/dist/planmagnet/controls/WebhookSubscriptionControls.js +542 -0
- package/dist/planmagnet/controls/WebhookSubscriptionControls.js.map +1 -0
- package/dist/planmagnet/dashboards/DashboardUI.js +7 -7
- package/dist/planmagnet/dashboards/cards/RiskSeverityCard.js +4 -4
- package/dist/planmagnet/forecast/DeliveryForecastCard.js +8 -8
- package/dist/planmagnet/forecast/ProjectOutlookCard.js +10 -10
- package/dist/planmagnet/forecast/ProjectRiskSummaryCard.js +9 -9
- package/dist/planmagnet/forecast/ResourceForecastCard.js +6 -6
- package/dist/planmagnet/integrations/syncTypes.d.ts +2 -1
- package/dist/planmagnet/integrations/syncTypes.d.ts.map +1 -1
- package/dist/planmagnet/integrations/syncTypes.js +19 -9
- package/dist/planmagnet/integrations/syncTypes.js.map +1 -1
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +8 -8
- package/dist/planmagnet/pages/DashboardDashboardPagePage.js +23 -23
- package/dist/planmagnet/pages/DocsDocDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js +340 -248
- package/dist/planmagnet/pages/DocsDocDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/IntegrationsSyncDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/IntegrationsSyncDetailPagePage.js +172 -167
- package/dist/planmagnet/pages/IntegrationsSyncDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/IntegrationsSyncsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/IntegrationsSyncsPagePage.js +92 -83
- package/dist/planmagnet/pages/IntegrationsSyncsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.d.ts +2 -0
- package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.d.ts.map +1 -0
- package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.js +175 -0
- package/dist/planmagnet/pages/IntegrationsWebhooksPagePage.js.map +1 -0
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js +151 -126
- package/dist/planmagnet/pages/ProductsFeatureDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js +136 -129
- package/dist/planmagnet/pages/ProductsFeaturesPagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js +149 -119
- package/dist/planmagnet/pages/ProductsNewFeaturePagePage.js.map +1 -1
- package/dist/planmagnet/pages/ProductsProductsPagePage.js +13 -13
- package/dist/planmagnet/pages/ProjectsAtRiskPagePage.js +9 -9
- package/dist/planmagnet/pages/ProjectsBudgetsPagePage.js +8 -8
- package/dist/planmagnet/pages/ProjectsProjectsPagePage.js +12 -12
- package/dist/planmagnet/pages/ReportsReportsPagePage.js +23 -23
- package/dist/planmagnet/pages/TasksMyDashboardPagePage.js +18 -18
- package/dist/planmagnet/pages/TasksMyWorkPagePage.js +10 -10
- package/dist/planmagnet/pages/TasksTimeEntriesPagePage.js +5 -5
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +8 -8
- package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js +6 -6
- package/dist/planmagnet/pages/analytics/MetricsCard.js +6 -6
- package/dist/planmagnet/pages/analytics/QualityMetricsCard.js +6 -6
- package/dist/planmagnet/pages/analytics/SprintDeliveryCards.js +8 -8
- package/dist/planmagnet/pages/analytics/StatusFlowCard.js +7 -7
- package/dist/planmagnet/pages/analytics/ThroughputCard.js +7 -7
- package/dist/planmagnet/pages/analytics/WorkBreakdownCard.js +7 -7
- package/dist/planmagnet/people/People.d.ts +14 -0
- package/dist/planmagnet/people/People.d.ts.map +1 -1
- package/dist/planmagnet/people/People.js +36 -22
- package/dist/planmagnet/people/People.js.map +1 -1
- package/dist/planmagnet/webhooks/webhookTypes.d.ts +54 -0
- package/dist/planmagnet/webhooks/webhookTypes.d.ts.map +1 -0
- package/dist/planmagnet/webhooks/webhookTypes.js +17 -0
- package/dist/planmagnet/webhooks/webhookTypes.js.map +1 -0
- package/package.json +1 -1
|
@@ -3,8 +3,8 @@ import { ShieldAlert as t } from "lucide-react";
|
|
|
3
3
|
import { gql as n } from "@apollo/client";
|
|
4
4
|
import { useQuery as r } from "@apollo/client/react";
|
|
5
5
|
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { Badge as o } from "@burdenoff/fe-libs/ui";
|
|
7
|
+
import { useI18n as s } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
8
8
|
//#region src/planmagnet/dashboards/cards/RiskSeverityCard.tsx
|
|
9
9
|
var c = n`
|
|
10
10
|
query DashboardProjectRisks($workspaceId: ID!, $projectId: String!) {
|
|
@@ -39,7 +39,7 @@ var c = n`
|
|
|
39
39
|
NEGLIGIBLE: "secondary"
|
|
40
40
|
};
|
|
41
41
|
function f({ workspaceId: n, projectId: f, onDrillDown: p }) {
|
|
42
|
-
let { t: m } =
|
|
42
|
+
let { t: m } = s(), { data: h, loading: g, error: _ } = r(c, {
|
|
43
43
|
variables: {
|
|
44
44
|
workspaceId: n,
|
|
45
45
|
projectId: f
|
|
@@ -72,7 +72,7 @@ function f({ workspaceId: n, projectId: f, onDrillDown: p }) {
|
|
|
72
72
|
children: m("planmagnet.dashboards.pm.risks.noneOpen", "No open risks for this project.")
|
|
73
73
|
}) : /* @__PURE__ */ i("div", {
|
|
74
74
|
className: "flex flex-wrap gap-2",
|
|
75
|
-
children: u.filter((e) => x.has(e)).map((e) => /* @__PURE__ */ a(
|
|
75
|
+
children: u.filter((e) => x.has(e)).map((e) => /* @__PURE__ */ a(o, {
|
|
76
76
|
variant: d[e],
|
|
77
77
|
children: [
|
|
78
78
|
e.toLowerCase(),
|
|
@@ -4,8 +4,8 @@ import { CalendarRange as n } from "lucide-react";
|
|
|
4
4
|
import { gql as r } from "@apollo/client";
|
|
5
5
|
import { useQuery as i } from "@apollo/client/react";
|
|
6
6
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { Card as s, CardContent as c, CardHeader as l, CardTitle as u, Checkbox as d } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
import { useI18n as f } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
9
9
|
//#region src/planmagnet/forecast/DeliveryForecastCard.tsx
|
|
10
10
|
var p = r`
|
|
11
11
|
query PlanmagnetDeliveryForecast(
|
|
@@ -49,7 +49,7 @@ function m(e) {
|
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
function h({ workspaceId: r, projectId: h, sprintId: g, sprintName: _ }) {
|
|
52
|
-
let { t: v } =
|
|
52
|
+
let { t: v } = f(), [y, b] = t(!1), x = y && !!g, { data: S, loading: C, error: w } = i(p, {
|
|
53
53
|
variables: {
|
|
54
54
|
workspaceId: r,
|
|
55
55
|
projectId: h,
|
|
@@ -57,10 +57,10 @@ function h({ workspaceId: r, projectId: h, sprintId: g, sprintName: _ }) {
|
|
|
57
57
|
},
|
|
58
58
|
skip: !r || !h
|
|
59
59
|
}), T = S?.planmagnetForecastDelivery;
|
|
60
|
-
return /* @__PURE__ */ o(
|
|
60
|
+
return /* @__PURE__ */ o(s, {
|
|
61
61
|
"data-testid": "forecast-card",
|
|
62
|
-
children: [/* @__PURE__ */ o(
|
|
63
|
-
/* @__PURE__ */ o(
|
|
62
|
+
children: [/* @__PURE__ */ o(l, { children: [
|
|
63
|
+
/* @__PURE__ */ o(u, {
|
|
64
64
|
className: "flex items-center gap-2",
|
|
65
65
|
children: [/* @__PURE__ */ a(n, { className: "h-4 w-4" }), v("planmagnet.forecast.delivery.title", "Delivery forecast")]
|
|
66
66
|
}),
|
|
@@ -71,13 +71,13 @@ function h({ workspaceId: r, projectId: h, sprintId: g, sprintName: _ }) {
|
|
|
71
71
|
g && /* @__PURE__ */ o("label", {
|
|
72
72
|
htmlFor: `forecast-scope-sprint-${h}`,
|
|
73
73
|
className: "flex items-center gap-2 pt-1 text-xs font-normal text-muted-foreground",
|
|
74
|
-
children: [/* @__PURE__ */ a(
|
|
74
|
+
children: [/* @__PURE__ */ a(d, {
|
|
75
75
|
id: `forecast-scope-sprint-${h}`,
|
|
76
76
|
checked: y,
|
|
77
77
|
onCheckedChange: (e) => b(e === !0)
|
|
78
78
|
}), v("planmagnet.forecast.delivery.scopeToggle", "Only this sprint's items ({{sprint}})", { sprint: _ ?? v("planmagnet.forecast.delivery.thisSprint", "this sprint") })]
|
|
79
79
|
})
|
|
80
|
-
] }), /* @__PURE__ */ a(
|
|
80
|
+
] }), /* @__PURE__ */ a(c, { children: h ? C && !S ? /* @__PURE__ */ a("div", {
|
|
81
81
|
className: "flex justify-center py-8",
|
|
82
82
|
children: /* @__PURE__ */ a("div", { className: "animate-spin h-6 w-6 border-2 border-primary border-t-transparent rounded-full" })
|
|
83
83
|
}) : w ? /* @__PURE__ */ a("p", {
|
|
@@ -5,8 +5,8 @@ import { Compass as r } from "lucide-react";
|
|
|
5
5
|
import { gql as i } from "@apollo/client";
|
|
6
6
|
import { useQuery as a } from "@apollo/client/react";
|
|
7
7
|
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { Badge as c, Card as l, CardContent as u, CardHeader as d, CardTitle as f } from "@burdenoff/fe-libs/ui";
|
|
9
|
+
import { useI18n as p } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
10
10
|
//#region src/planmagnet/forecast/ProjectOutlookCard.tsx
|
|
11
11
|
var m = i`
|
|
12
12
|
query PlanmagnetProjectOutlook($workspaceId: ID!, $projectId: ID!) {
|
|
@@ -57,28 +57,28 @@ function _(e) {
|
|
|
57
57
|
return e === null ? "—" : `${Math.round(e * 100)}%`;
|
|
58
58
|
}
|
|
59
59
|
function v({ workspaceId: i, projectId: v }) {
|
|
60
|
-
let { t: y } =
|
|
60
|
+
let { t: y } = p(), b = e(), { data: x, loading: S, error: C } = a(m, {
|
|
61
61
|
variables: {
|
|
62
62
|
workspaceId: i,
|
|
63
63
|
projectId: v
|
|
64
64
|
},
|
|
65
65
|
skip: !i || !v
|
|
66
66
|
}), w = x?.planmagnetProjectOutlook;
|
|
67
|
-
return /* @__PURE__ */ s(
|
|
67
|
+
return /* @__PURE__ */ s(l, {
|
|
68
68
|
"data-testid": "outlook-card",
|
|
69
|
-
children: [/* @__PURE__ */ s(
|
|
69
|
+
children: [/* @__PURE__ */ s(d, {
|
|
70
70
|
className: "flex flex-row items-start justify-between space-y-0",
|
|
71
|
-
children: [/* @__PURE__ */ s("div", { children: [/* @__PURE__ */ s(
|
|
71
|
+
children: [/* @__PURE__ */ s("div", { children: [/* @__PURE__ */ s(f, {
|
|
72
72
|
className: "flex items-center gap-2",
|
|
73
73
|
children: [/* @__PURE__ */ o(r, { className: "h-4 w-4" }), y("planmagnet.forecast.outlook.title", "Project outlook")]
|
|
74
74
|
}), /* @__PURE__ */ o("p", {
|
|
75
75
|
className: "text-xs text-muted-foreground",
|
|
76
76
|
children: y("planmagnet.forecast.outlook.subtitle", "Explicit rule-based heuristics over real data — never AI.")
|
|
77
|
-
})] }), /* @__PURE__ */ o(
|
|
77
|
+
})] }), /* @__PURE__ */ o(c, {
|
|
78
78
|
variant: "outline",
|
|
79
79
|
children: y("planmagnet.forecast.outlook.method", "HEURISTIC")
|
|
80
80
|
})]
|
|
81
|
-
}), /* @__PURE__ */ o(
|
|
81
|
+
}), /* @__PURE__ */ o(u, { children: S && !x ? /* @__PURE__ */ o("div", {
|
|
82
82
|
className: "flex justify-center py-8",
|
|
83
83
|
children: /* @__PURE__ */ o("div", { className: "animate-spin h-6 w-6 border-2 border-primary border-t-transparent rounded-full" })
|
|
84
84
|
}) : C ? /* @__PURE__ */ o("p", {
|
|
@@ -89,7 +89,7 @@ function v({ workspaceId: i, projectId: v }) {
|
|
|
89
89
|
children: [
|
|
90
90
|
/* @__PURE__ */ s("div", {
|
|
91
91
|
className: "flex flex-wrap items-center gap-2",
|
|
92
|
-
children: [/* @__PURE__ */ o(
|
|
92
|
+
children: [/* @__PURE__ */ o(c, {
|
|
93
93
|
variant: h[w.successLikelihood],
|
|
94
94
|
children: y("planmagnet.forecast.outlook.successLikelihood", "Success likelihood: {{level}}", { level: w.successLikelihood })
|
|
95
95
|
}), /* @__PURE__ */ o("span", {
|
|
@@ -107,7 +107,7 @@ function v({ workspaceId: i, projectId: v }) {
|
|
|
107
107
|
className: "rounded-md border p-3",
|
|
108
108
|
children: [/* @__PURE__ */ s("h3", {
|
|
109
109
|
className: "mb-1 flex items-center gap-2 text-sm font-medium",
|
|
110
|
-
children: [y("planmagnet.forecast.outlook.quality", "Quality trend"), /* @__PURE__ */ o(
|
|
110
|
+
children: [y("planmagnet.forecast.outlook.quality", "Quality trend"), /* @__PURE__ */ o(c, {
|
|
111
111
|
variant: g[w.qualityTrend.trend],
|
|
112
112
|
children: w.qualityTrend.trend
|
|
113
113
|
})]
|
|
@@ -6,8 +6,8 @@ import { ShieldAlert as s } from "lucide-react";
|
|
|
6
6
|
import { gql as c } from "@apollo/client";
|
|
7
7
|
import { useQuery as l } from "@apollo/client/react";
|
|
8
8
|
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { Badge as f, Card as p, CardContent as m, CardHeader as h, CardTitle as g } from "@burdenoff/fe-libs/ui";
|
|
10
|
+
import { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
11
|
//#region src/planmagnet/forecast/ProjectRiskSummaryCard.tsx
|
|
12
12
|
var v = c`
|
|
13
13
|
query PlanmagnetProjectRiskSummary($workspaceId: ID!, $projectId: ID!) {
|
|
@@ -26,28 +26,28 @@ var v = c`
|
|
|
26
26
|
}
|
|
27
27
|
`;
|
|
28
28
|
function y({ workspaceId: c, projectId: y }) {
|
|
29
|
-
let { t: b } =
|
|
29
|
+
let { t: b } = _(), x = e(), { data: S, loading: C, error: w } = l(v, {
|
|
30
30
|
variables: {
|
|
31
31
|
workspaceId: c,
|
|
32
32
|
projectId: y
|
|
33
33
|
},
|
|
34
34
|
skip: !c || !y
|
|
35
35
|
}), T = S?.planmagnetProjectRiskSummary, E = new Map(T?.byKind.map((e) => [e.kind, e.count]) ?? []), D = new Map(T?.bySeverity.map((e) => [e.severity, e.count]) ?? []);
|
|
36
|
-
return /* @__PURE__ */ d(
|
|
36
|
+
return /* @__PURE__ */ d(p, {
|
|
37
37
|
"data-testid": "risk-summary",
|
|
38
|
-
children: [/* @__PURE__ */ d(
|
|
38
|
+
children: [/* @__PURE__ */ d(h, {
|
|
39
39
|
className: "flex flex-row items-start justify-between space-y-0",
|
|
40
|
-
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d(
|
|
40
|
+
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d(g, {
|
|
41
41
|
className: "flex items-center gap-2",
|
|
42
42
|
children: [/* @__PURE__ */ u(s, { className: "h-4 w-4" }), b("planmagnet.forecast.riskSummary.title", "At-risk work")]
|
|
43
43
|
}), /* @__PURE__ */ u("p", {
|
|
44
44
|
className: "text-xs text-muted-foreground",
|
|
45
45
|
children: b("planmagnet.forecast.riskSummary.subtitle", "Explicit threshold rules — never AI.")
|
|
46
|
-
})] }), /* @__PURE__ */ u(
|
|
46
|
+
})] }), /* @__PURE__ */ u(f, {
|
|
47
47
|
variant: "outline",
|
|
48
48
|
children: b("planmagnet.forecast.riskSummary.method", "Rule-based")
|
|
49
49
|
})]
|
|
50
|
-
}), /* @__PURE__ */ u(
|
|
50
|
+
}), /* @__PURE__ */ u(m, { children: C && !S ? /* @__PURE__ */ u("p", {
|
|
51
51
|
className: "text-sm text-muted-foreground",
|
|
52
52
|
children: b("planmagnet.forecast.loading", "Loading…")
|
|
53
53
|
}) : w ? /* @__PURE__ */ u("p", {
|
|
@@ -61,7 +61,7 @@ function y({ workspaceId: c, projectId: y }) {
|
|
|
61
61
|
children: [
|
|
62
62
|
/* @__PURE__ */ u("div", {
|
|
63
63
|
className: "flex flex-wrap items-center gap-2",
|
|
64
|
-
children: i.filter((e) => (D.get(e) ?? 0) > 0).map((e) => /* @__PURE__ */ d(
|
|
64
|
+
children: i.filter((e) => (D.get(e) ?? 0) > 0).map((e) => /* @__PURE__ */ d(f, {
|
|
65
65
|
variant: o(e),
|
|
66
66
|
children: [
|
|
67
67
|
n(e),
|
|
@@ -4,8 +4,8 @@ import { Gauge as n } from "lucide-react";
|
|
|
4
4
|
import { gql as r } from "@apollo/client";
|
|
5
5
|
import { useQuery as i } from "@apollo/client/react";
|
|
6
6
|
import { jsx as a, jsxs as o } from "react/jsx-runtime";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { Card as s, CardContent as c, CardHeader as l, CardTitle as u } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
import { useI18n as d } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
9
9
|
//#region src/planmagnet/forecast/ResourceForecastCard.tsx
|
|
10
10
|
var f = r`
|
|
11
11
|
query PlanmagnetResourceForecast(
|
|
@@ -39,7 +39,7 @@ var f = r`
|
|
|
39
39
|
}
|
|
40
40
|
`;
|
|
41
41
|
function p({ workspaceId: r, teamId: p, projectId: m, horizonSprints: h = 3 }) {
|
|
42
|
-
let { t: g } =
|
|
42
|
+
let { t: g } = d(), { data: _, loading: v, error: y } = i(f, {
|
|
43
43
|
variables: {
|
|
44
44
|
workspaceId: r,
|
|
45
45
|
teamId: p,
|
|
@@ -48,15 +48,15 @@ function p({ workspaceId: r, teamId: p, projectId: m, horizonSprints: h = 3 }) {
|
|
|
48
48
|
},
|
|
49
49
|
skip: !r || !p && !m
|
|
50
50
|
}), b = _?.planmagnetResourceForecast, x = Math.max(1, ...b?.capacityGaps.map((e) => Math.abs(e.gapPoints)) ?? [1]);
|
|
51
|
-
return /* @__PURE__ */ o(
|
|
51
|
+
return /* @__PURE__ */ o(s, {
|
|
52
52
|
"data-testid": "resource-forecast",
|
|
53
|
-
children: [/* @__PURE__ */ o(
|
|
53
|
+
children: [/* @__PURE__ */ o(l, { children: [/* @__PURE__ */ o(u, {
|
|
54
54
|
className: "flex items-center gap-2",
|
|
55
55
|
children: [/* @__PURE__ */ a(n, { className: "h-4 w-4" }), g("planmagnet.forecast.resource.title", "Resource forecast")]
|
|
56
56
|
}), /* @__PURE__ */ a("p", {
|
|
57
57
|
className: "text-xs text-muted-foreground",
|
|
58
58
|
children: g("planmagnet.forecast.resource.subtitle", "Open backlog vs. historical velocity, over the next {{count}} sprint(s).", { count: h })
|
|
59
|
-
})] }), /* @__PURE__ */ a(
|
|
59
|
+
})] }), /* @__PURE__ */ a(c, { children: !p && !m ? null : v && !_ ? /* @__PURE__ */ a("div", {
|
|
60
60
|
className: "flex justify-center py-8",
|
|
61
61
|
children: /* @__PURE__ */ a("div", { className: "animate-spin h-6 w-6 border-2 border-primary border-t-transparent rounded-full" })
|
|
62
62
|
}) : y ? /* @__PURE__ */ a("p", {
|
|
@@ -28,7 +28,7 @@ export declare const SYNC_DIRECTIONS: readonly ["INBOUND", "OUTBOUND", "BIDIRECT
|
|
|
28
28
|
export type SyncDirection = (typeof SYNC_DIRECTIONS)[number];
|
|
29
29
|
export declare const SYNC_STATUSES: readonly ["IDLE", "SYNCING", "SUCCESS", "FAILED", "PAUSED", "DISABLED"];
|
|
30
30
|
export type SyncStatus = (typeof SYNC_STATUSES)[number];
|
|
31
|
-
export declare const CONFLICT_RESOLUTIONS: readonly ["SOURCE_WINS", "TARGET_WINS", "MANUAL"];
|
|
31
|
+
export declare const CONFLICT_RESOLUTIONS: readonly ["SOURCE_WINS", "TARGET_WINS", "MERGE", "MANUAL"];
|
|
32
32
|
export type ConflictResolution = (typeof CONFLICT_RESOLUTIONS)[number];
|
|
33
33
|
export declare const CONFLICT_STATUSES: readonly ["OPEN", "RESOLVED"];
|
|
34
34
|
export type ConflictStatus = (typeof CONFLICT_STATUSES)[number];
|
|
@@ -133,6 +133,7 @@ export interface SyncConnectionTestResult {
|
|
|
133
133
|
}
|
|
134
134
|
export declare function providerLabel(provider: string): string;
|
|
135
135
|
export declare function directionLabel(direction: string): string;
|
|
136
|
+
export declare function conflictStrategyLabel(value: string): string;
|
|
136
137
|
/** Whether a capability supports a given direction at all — the single gate the wizard and the edit form both use. */
|
|
137
138
|
export declare function directionSupported(capability: Pick<SyncProviderCapability, 'supportsImport' | 'supportsExport' | 'supportsBidirectional'>, direction: SyncDirection): boolean;
|
|
138
139
|
/** True once a provider can run at least one live direction — the gate for selecting it in the wizard at all. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncTypes.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/integrations/syncTypes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,eAAO,MAAM,cAAc,qHAWjB,CAAC;AACX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,eAAO,MAAM,eAAe,mDAAoD,CAAC;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,eAAO,MAAM,aAAa,yEAOhB,CAAC;AACX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"syncTypes.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/integrations/syncTypes.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,7 @@ var e = [
|
|
|
13
13
|
], n = [
|
|
14
14
|
"SOURCE_WINS",
|
|
15
15
|
"TARGET_WINS",
|
|
16
|
+
"MERGE",
|
|
16
17
|
"MANUAL"
|
|
17
18
|
], r = ["priority", "dueDate"], i = {
|
|
18
19
|
priority: "priority:",
|
|
@@ -40,20 +41,29 @@ var s = {
|
|
|
40
41
|
function c(e) {
|
|
41
42
|
return s[e] ?? e;
|
|
42
43
|
}
|
|
43
|
-
|
|
44
|
+
var l = {
|
|
45
|
+
SOURCE_WINS: "PlanMagnet wins",
|
|
46
|
+
TARGET_WINS: "Provider wins",
|
|
47
|
+
MERGE: "Merge",
|
|
48
|
+
MANUAL: "Manual"
|
|
49
|
+
};
|
|
50
|
+
function u(e) {
|
|
51
|
+
return l[e] ?? e;
|
|
52
|
+
}
|
|
53
|
+
function d(e, t) {
|
|
44
54
|
return t === "INBOUND" ? e.supportsImport : t === "OUTBOUND" ? e.supportsExport : e.supportsBidirectional;
|
|
45
55
|
}
|
|
46
|
-
function
|
|
56
|
+
function f(e) {
|
|
47
57
|
return e.supportsImport || e.supportsExport || e.supportsBidirectional;
|
|
48
58
|
}
|
|
49
|
-
var
|
|
50
|
-
function
|
|
51
|
-
return
|
|
59
|
+
var p = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/, m = /^[A-Za-z0-9._-]{1,100}$/;
|
|
60
|
+
function h(e) {
|
|
61
|
+
return p.test(e.trim());
|
|
52
62
|
}
|
|
53
|
-
function
|
|
54
|
-
return
|
|
63
|
+
function g(e) {
|
|
64
|
+
return m.test(e.trim());
|
|
55
65
|
}
|
|
56
|
-
function
|
|
66
|
+
function _(e) {
|
|
57
67
|
let t = {
|
|
58
68
|
priority: "",
|
|
59
69
|
dueDate: ""
|
|
@@ -66,6 +76,6 @@ function h(e) {
|
|
|
66
76
|
return t;
|
|
67
77
|
}
|
|
68
78
|
//#endregion
|
|
69
|
-
export { n as CONFLICT_RESOLUTIONS, i as GITHUB_FIELD_MAPPING_DEFAULTS, e as SYNC_DIRECTIONS, t as SYNC_STATUSES, c as directionLabel,
|
|
79
|
+
export { n as CONFLICT_RESOLUTIONS, i as GITHUB_FIELD_MAPPING_DEFAULTS, e as SYNC_DIRECTIONS, t as SYNC_STATUSES, u as conflictStrategyLabel, c as directionLabel, d as directionSupported, h as isValidGithubOwner, g as isValidGithubRepo, _ as parseGithubFieldMapping, f as providerIsLive, o as providerLabel };
|
|
70
80
|
|
|
71
81
|
//# sourceMappingURL=syncTypes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncTypes.js","names":[],"sources":["../../../src/planmagnet/integrations/syncTypes.ts"],"sourcesContent":["/**\n * Shared shapes and constants for External Sync (AUT-06/08/09/10/20/22/23/24/40) — GraphQL Hive doc comments and\n * `wspace-planmagnet-svc#63` are the source of truth for all of this, not guesswork:\n *\n * - GITHUB is the one provider with a real, live connector today (`github-connector.ts`); every other\n * `PlanmagnetSyncProvider` is accepted by `planmagnetCreateExternalSync` (a customer can configure it ahead of\n * time) but has no live connector, which `planmagnetSupportedSyncProviders` reports honestly (every capability\n * flag false except `supportsFileImport`, which is the unrelated `planmagnetImportExternalIssues` CSV/JSON\n * upload path, not an `ExternalSync` live run). The wizard reads that capability list rather than hard-coding\n * \"GitHub only\" — if a second connector ships, this UI lights up for it automatically.\n * - `ExternalSync.connectionConfig` for GITHUB is `{ token, owner, repo }` and is REDACTED server-side on every\n * read (`token` -> `[REDACTED]`; `owner`/`repo` are not secret and pass through). It must never be displayed as\n * if it still held the token, and never round-tripped back to the server as if `[REDACTED]` were a real value.\n * - `ExternalSync.fieldMapping` for GITHUB is exactly two optional label-prefix strings —\n * `{ priority?: string; dueDate?: string }` (default `\"priority:\"` / `\"due:\"`) — because GitHub Issues have no\n * native priority or due-date column; the connector encodes/decodes them as a label of the form\n * `{prefix}{value}` (e.g. `priority:HIGH`, `due:2026-10-01`). This is the only field-mapping shape the live\n * connector reads; it is NOT the (unrelated) CSV/JSON import's column-name mapping.\n * - `PlanmagnetUpdateExternalSyncInput.connectionConfig` REPLACES the whole stored config — it does not merge —\n * so an edit that changes only the token must resend `owner`/`repo` too (read back from the redacted\n * `connectionConfig`, which is safe since only `token` is masked), and an edit that changes owner/repo without a\n * new token cannot be sent at all (the real token can never be read back to resend it). See\n * `controls/SyncControls.tsx`'s `EditSyncConnectionDialog`.\n */\n\nexport const SYNC_PROVIDERS = [\n 'JIRA',\n 'GITHUB',\n 'GITLAB',\n 'AZURE_DEVOPS',\n 'ASANA',\n 'TRELLO',\n 'LINEAR',\n 'SHORTCUT',\n 'CLICKUP',\n 'CUSTOM',\n] as const;\nexport type SyncProvider = (typeof SYNC_PROVIDERS)[number];\n\nexport const SYNC_DIRECTIONS = ['INBOUND', 'OUTBOUND', 'BIDIRECTIONAL'] as const;\nexport type SyncDirection = (typeof SYNC_DIRECTIONS)[number];\n\nexport const SYNC_STATUSES = [\n 'IDLE',\n 'SYNCING',\n 'SUCCESS',\n 'FAILED',\n 'PAUSED',\n 'DISABLED',\n] as const;\nexport type SyncStatus = (typeof SYNC_STATUSES)[number];\n\nexport const CONFLICT_RESOLUTIONS = ['SOURCE_WINS', 'TARGET_WINS', 'MANUAL'] as const;\nexport type ConflictResolution = (typeof CONFLICT_RESOLUTIONS)[number];\n\nexport const CONFLICT_STATUSES = ['OPEN', 'RESOLVED'] as const;\nexport type ConflictStatus = (typeof CONFLICT_STATUSES)[number];\n\nexport const SYNC_RUN_STATUSES = ['SUCCEEDED', 'FAILED', 'PARTIAL'] as const;\nexport type SyncRunStatus = (typeof SYNC_RUN_STATUSES)[number];\n\n/** The two GitHub label-prefix keys `ExternalSync.fieldMapping` actually understands (github-connector.ts). */\nexport const GITHUB_FIELD_MAPPING_KEYS = ['priority', 'dueDate'] as const;\nexport type GithubFieldMappingKey = (typeof GITHUB_FIELD_MAPPING_KEYS)[number];\n/** The connector's own built-in defaults, used only as placeholder copy — never assumed server-side. */\nexport const GITHUB_FIELD_MAPPING_DEFAULTS: Record<GithubFieldMappingKey, string> = {\n priority: 'priority:',\n dueDate: 'due:',\n};\n\nexport interface ProjectRef {\n id: string;\n name: string;\n}\n\nexport interface RunHealth {\n lastRunAt: string | null;\n lastStatus: SyncRunStatus | null;\n consecutiveFailures: number;\n runsLast7Days: number;\n}\n\nexport interface ExternalSyncRow {\n id: string;\n provider: SyncProvider;\n direction: SyncDirection;\n status: SyncStatus;\n projectId: string;\n project: ProjectRef | null;\n externalProjectId: string;\n externalProjectUrl: string | null;\n conflictStrategy: ConflictResolution;\n fieldMapping: unknown;\n /** Stored but not yet read by any run (sync.service.ts) — surfaced honestly in the edit form, not hidden. */\n syncFilters: unknown;\n lastSyncedAt: string | null;\n lastSyncError: string | null;\n totalItemsSynced: number;\n createdAt: string;\n updatedAt: string;\n runHealth: RunHealth;\n}\n\nexport interface SyncProviderCapability {\n provider: SyncProvider;\n supportsImport: boolean;\n supportsExport: boolean;\n supportsBidirectional: boolean;\n supportsFileImport: boolean;\n supportsConnectionTest: boolean;\n}\n\nexport interface SyncRunRow {\n id: string;\n direction: SyncDirection;\n status: SyncRunStatus;\n startedAt: string;\n finishedAt: string;\n itemsCreated: number;\n itemsUpdated: number;\n itemsSkipped: number;\n errorCount: number;\n conflictCount: number;\n errorMessage: string | null;\n triggeredBy: string;\n}\n\nexport interface ExternalMappingRef {\n id: string;\n internalId: string;\n internalType: string;\n externalId: string;\n externalType: string;\n externalUrl: string | null;\n}\n\nexport interface SyncConflictRow {\n id: string;\n createdAt: string;\n fields: string[];\n localUpdatedAt: string;\n remoteUpdatedAt: string;\n resolution: ConflictResolution | null;\n resolvedAt: string | null;\n resolvedBy: string | null;\n status: ConflictStatus;\n mapping: ExternalMappingRef | null;\n mappingId: string;\n}\n\n/** `PlanmagnetSyncResult` — what `planmagnetStartSync` returns. */\nexport interface SyncRunResult {\n syncId: string;\n success: boolean;\n itemsCreated: number;\n itemsUpdated: number;\n itemsSkipped: number;\n errorCount: number;\n errors: string[] | null;\n conflictCount: number;\n durationMs: number | null;\n syncedAt: string;\n}\n\n/** `PlanmagnetSyncConnectionTestResult` — what `planmagnetTestExternalSync` returns. */\nexport interface SyncConnectionTestResult {\n ok: boolean;\n message: string;\n rateLimitRemaining: number | null;\n}\n\nconst PROVIDER_LABELS: Record<SyncProvider, string> = {\n JIRA: 'Jira',\n GITHUB: 'GitHub',\n GITLAB: 'GitLab',\n AZURE_DEVOPS: 'Azure DevOps',\n ASANA: 'Asana',\n TRELLO: 'Trello',\n LINEAR: 'Linear',\n SHORTCUT: 'Shortcut',\n CLICKUP: 'ClickUp',\n CUSTOM: 'Custom',\n};\n\nexport function providerLabel(provider: string): string {\n return PROVIDER_LABELS[provider as SyncProvider] ?? provider;\n}\n\nconst DIRECTION_LABELS: Record<SyncDirection, string> = {\n INBOUND: 'Inbound (provider → PlanMagnet)',\n OUTBOUND: 'Outbound (PlanMagnet → provider)',\n BIDIRECTIONAL: 'Bidirectional (both ways)',\n};\n\nexport function directionLabel(direction: string): string {\n return DIRECTION_LABELS[direction as SyncDirection] ?? direction;\n}\n\n/** Whether a capability supports a given direction at all — the single gate the wizard and the edit form both use. */\nexport function directionSupported(\n capability: Pick<\n SyncProviderCapability,\n 'supportsImport' | 'supportsExport' | 'supportsBidirectional'\n >,\n direction: SyncDirection\n): boolean {\n if (direction === 'INBOUND') return capability.supportsImport;\n if (direction === 'OUTBOUND') return capability.supportsExport;\n return capability.supportsBidirectional;\n}\n\n/** True once a provider can run at least one live direction — the gate for selecting it in the wizard at all. */\nexport function providerIsLive(\n capability: Pick<\n SyncProviderCapability,\n 'supportsImport' | 'supportsExport' | 'supportsBidirectional'\n >\n): boolean {\n return capability.supportsImport || capability.supportsExport || capability.supportsBidirectional;\n}\n\n/**\n * `ExternalSync.fieldMapping` -> the two GitHub label prefixes, as blank strings when unset (meaning \"the\n * connector's built-in default applies\"), never pre-filled with that default text — so an untouched form saves\n * nothing and a save always reflects a real, deliberate choice.\n */\n/** GitHub org/user name rules: 1-39 chars, alphanumeric or single hyphens, no leading/trailing hyphen. */\nconst GITHUB_OWNER_RE = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;\n/** GitHub repo name rules: 1-100 chars of letters, digits, `.`, `-`, `_`. */\nconst GITHUB_REPO_RE = /^[A-Za-z0-9._-]{1,100}$/;\n\nexport function isValidGithubOwner(value: string): boolean {\n return GITHUB_OWNER_RE.test(value.trim());\n}\nexport function isValidGithubRepo(value: string): boolean {\n return GITHUB_REPO_RE.test(value.trim());\n}\n\nexport function parseGithubFieldMapping(value: unknown): Record<GithubFieldMappingKey, string> {\n const out: Record<GithubFieldMappingKey, string> = { priority: '', dueDate: '' };\n if (!value || typeof value !== 'object' || Array.isArray(value)) return out;\n for (const key of GITHUB_FIELD_MAPPING_KEYS) {\n const raw = (value as Record<string, unknown>)[key];\n if (typeof raw === 'string' && raw.trim()) out[key] = raw.trim();\n }\n return out;\n}\n"],"mappings":";AAuCA,IAAa,IAAkB;CAAC;CAAW;CAAY;CAAgB,EAG1D,IAAgB;CAC3B;CACA;CACA;CACA;CACA;CACA;CACD,EAGY,IAAuB;CAAC;CAAe;CAAe;CAAS,EAU/D,IAA4B,CAAC,YAAY,UAAU,EAGnD,IAAuE;CAClF,UAAU;CACV,SAAS;CACV,EAuGK,IAAgD;CACpD,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,cAAc;CACd,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,SAAS;CACT,QAAQ;CACT;AAED,SAAgB,EAAc,GAA0B;AACtD,QAAO,EAAgB,MAA6B;;AAGtD,IAAM,IAAkD;CACtD,SAAS;CACT,UAAU;CACV,eAAe;CAChB;AAED,SAAgB,EAAe,GAA2B;AACxD,QAAO,EAAiB,MAA+B;;AAIzD,SAAgB,EACd,GAIA,GACS;AAGT,QAFI,MAAc,YAAkB,EAAW,iBAC3C,MAAc,aAAmB,EAAW,iBACzC,EAAW;;AAIpB,SAAgB,EACd,GAIS;AACT,QAAO,EAAW,kBAAkB,EAAW,kBAAkB,EAAW;;AAS9E,IAAM,IAAkB,mDAElB,IAAiB;AAEvB,SAAgB,EAAmB,GAAwB;AACzD,QAAO,EAAgB,KAAK,EAAM,MAAM,CAAC;;AAE3C,SAAgB,EAAkB,GAAwB;AACxD,QAAO,EAAe,KAAK,EAAM,MAAM,CAAC;;AAG1C,SAAgB,EAAwB,GAAuD;CAC7F,IAAM,IAA6C;EAAE,UAAU;EAAI,SAAS;EAAI;AAChF,KAAI,CAAC,KAAS,OAAO,KAAU,YAAY,MAAM,QAAQ,EAAM,CAAE,QAAO;AACxE,MAAK,IAAM,KAAO,GAA2B;EAC3C,IAAM,IAAO,EAAkC;AAC/C,EAAI,OAAO,KAAQ,YAAY,EAAI,MAAM,KAAE,EAAI,KAAO,EAAI,MAAM;;AAElE,QAAO"}
|
|
1
|
+
{"version":3,"file":"syncTypes.js","names":[],"sources":["../../../src/planmagnet/integrations/syncTypes.ts"],"sourcesContent":["/**\n * Shared shapes and constants for External Sync (AUT-06/08/09/10/20/22/23/24/40) — GraphQL Hive doc comments and\n * `wspace-planmagnet-svc#63` are the source of truth for all of this, not guesswork:\n *\n * - GITHUB is the one provider with a real, live connector today (`github-connector.ts`); every other\n * `PlanmagnetSyncProvider` is accepted by `planmagnetCreateExternalSync` (a customer can configure it ahead of\n * time) but has no live connector, which `planmagnetSupportedSyncProviders` reports honestly (every capability\n * flag false except `supportsFileImport`, which is the unrelated `planmagnetImportExternalIssues` CSV/JSON\n * upload path, not an `ExternalSync` live run). The wizard reads that capability list rather than hard-coding\n * \"GitHub only\" — if a second connector ships, this UI lights up for it automatically.\n * - `ExternalSync.connectionConfig` for GITHUB is `{ token, owner, repo }` and is REDACTED server-side on every\n * read (`token` -> `[REDACTED]`; `owner`/`repo` are not secret and pass through). It must never be displayed as\n * if it still held the token, and never round-tripped back to the server as if `[REDACTED]` were a real value.\n * - `ExternalSync.fieldMapping` for GITHUB is exactly two optional label-prefix strings —\n * `{ priority?: string; dueDate?: string }` (default `\"priority:\"` / `\"due:\"`) — because GitHub Issues have no\n * native priority or due-date column; the connector encodes/decodes them as a label of the form\n * `{prefix}{value}` (e.g. `priority:HIGH`, `due:2026-10-01`). This is the only field-mapping shape the live\n * connector reads; it is NOT the (unrelated) CSV/JSON import's column-name mapping.\n * - `PlanmagnetUpdateExternalSyncInput.connectionConfig` REPLACES the whole stored config — it does not merge —\n * so an edit that changes only the token must resend `owner`/`repo` too (read back from the redacted\n * `connectionConfig`, which is safe since only `token` is masked), and an edit that changes owner/repo without a\n * new token cannot be sent at all (the real token can never be read back to resend it). See\n * `controls/SyncControls.tsx`'s `EditSyncConnectionDialog`.\n */\n\nexport const SYNC_PROVIDERS = [\n 'JIRA',\n 'GITHUB',\n 'GITLAB',\n 'AZURE_DEVOPS',\n 'ASANA',\n 'TRELLO',\n 'LINEAR',\n 'SHORTCUT',\n 'CLICKUP',\n 'CUSTOM',\n] as const;\nexport type SyncProvider = (typeof SYNC_PROVIDERS)[number];\n\nexport const SYNC_DIRECTIONS = ['INBOUND', 'OUTBOUND', 'BIDIRECTIONAL'] as const;\nexport type SyncDirection = (typeof SYNC_DIRECTIONS)[number];\n\nexport const SYNC_STATUSES = [\n 'IDLE',\n 'SYNCING',\n 'SUCCESS',\n 'FAILED',\n 'PAUSED',\n 'DISABLED',\n] as const;\nexport type SyncStatus = (typeof SYNC_STATUSES)[number];\n\n// AUT-24: MERGE added alongside the two whole-side picks and the manual flag — PlanmagnetSyncConflictResolution's\n// own doc comment (graphql/wspace.graphql) has the exact field-level policy: each sync leg keeps whichever\n// side's title/description it is NOT overwriting, while status/priority/dueDate/labels still follow that leg's\n// normal direction.\nexport const CONFLICT_RESOLUTIONS = ['SOURCE_WINS', 'TARGET_WINS', 'MERGE', 'MANUAL'] as const;\nexport type ConflictResolution = (typeof CONFLICT_RESOLUTIONS)[number];\n\nexport const CONFLICT_STATUSES = ['OPEN', 'RESOLVED'] as const;\nexport type ConflictStatus = (typeof CONFLICT_STATUSES)[number];\n\nexport const SYNC_RUN_STATUSES = ['SUCCEEDED', 'FAILED', 'PARTIAL'] as const;\nexport type SyncRunStatus = (typeof SYNC_RUN_STATUSES)[number];\n\n/** The two GitHub label-prefix keys `ExternalSync.fieldMapping` actually understands (github-connector.ts). */\nexport const GITHUB_FIELD_MAPPING_KEYS = ['priority', 'dueDate'] as const;\nexport type GithubFieldMappingKey = (typeof GITHUB_FIELD_MAPPING_KEYS)[number];\n/** The connector's own built-in defaults, used only as placeholder copy — never assumed server-side. */\nexport const GITHUB_FIELD_MAPPING_DEFAULTS: Record<GithubFieldMappingKey, string> = {\n priority: 'priority:',\n dueDate: 'due:',\n};\n\nexport interface ProjectRef {\n id: string;\n name: string;\n}\n\nexport interface RunHealth {\n lastRunAt: string | null;\n lastStatus: SyncRunStatus | null;\n consecutiveFailures: number;\n runsLast7Days: number;\n}\n\nexport interface ExternalSyncRow {\n id: string;\n provider: SyncProvider;\n direction: SyncDirection;\n status: SyncStatus;\n projectId: string;\n project: ProjectRef | null;\n externalProjectId: string;\n externalProjectUrl: string | null;\n conflictStrategy: ConflictResolution;\n fieldMapping: unknown;\n /** Stored but not yet read by any run (sync.service.ts) — surfaced honestly in the edit form, not hidden. */\n syncFilters: unknown;\n lastSyncedAt: string | null;\n lastSyncError: string | null;\n totalItemsSynced: number;\n createdAt: string;\n updatedAt: string;\n runHealth: RunHealth;\n}\n\nexport interface SyncProviderCapability {\n provider: SyncProvider;\n supportsImport: boolean;\n supportsExport: boolean;\n supportsBidirectional: boolean;\n supportsFileImport: boolean;\n supportsConnectionTest: boolean;\n}\n\nexport interface SyncRunRow {\n id: string;\n direction: SyncDirection;\n status: SyncRunStatus;\n startedAt: string;\n finishedAt: string;\n itemsCreated: number;\n itemsUpdated: number;\n itemsSkipped: number;\n errorCount: number;\n conflictCount: number;\n errorMessage: string | null;\n triggeredBy: string;\n}\n\nexport interface ExternalMappingRef {\n id: string;\n internalId: string;\n internalType: string;\n externalId: string;\n externalType: string;\n externalUrl: string | null;\n}\n\nexport interface SyncConflictRow {\n id: string;\n createdAt: string;\n fields: string[];\n localUpdatedAt: string;\n remoteUpdatedAt: string;\n resolution: ConflictResolution | null;\n resolvedAt: string | null;\n resolvedBy: string | null;\n status: ConflictStatus;\n mapping: ExternalMappingRef | null;\n mappingId: string;\n}\n\n/** `PlanmagnetSyncResult` — what `planmagnetStartSync` returns. */\nexport interface SyncRunResult {\n syncId: string;\n success: boolean;\n itemsCreated: number;\n itemsUpdated: number;\n itemsSkipped: number;\n errorCount: number;\n errors: string[] | null;\n conflictCount: number;\n durationMs: number | null;\n syncedAt: string;\n}\n\n/** `PlanmagnetSyncConnectionTestResult` — what `planmagnetTestExternalSync` returns. */\nexport interface SyncConnectionTestResult {\n ok: boolean;\n message: string;\n rateLimitRemaining: number | null;\n}\n\nconst PROVIDER_LABELS: Record<SyncProvider, string> = {\n JIRA: 'Jira',\n GITHUB: 'GitHub',\n GITLAB: 'GitLab',\n AZURE_DEVOPS: 'Azure DevOps',\n ASANA: 'Asana',\n TRELLO: 'Trello',\n LINEAR: 'Linear',\n SHORTCUT: 'Shortcut',\n CLICKUP: 'ClickUp',\n CUSTOM: 'Custom',\n};\n\nexport function providerLabel(provider: string): string {\n return PROVIDER_LABELS[provider as SyncProvider] ?? provider;\n}\n\nconst DIRECTION_LABELS: Record<SyncDirection, string> = {\n INBOUND: 'Inbound (provider → PlanMagnet)',\n OUTBOUND: 'Outbound (PlanMagnet → provider)',\n BIDIRECTIONAL: 'Bidirectional (both ways)',\n};\n\nexport function directionLabel(direction: string): string {\n return DIRECTION_LABELS[direction as SyncDirection] ?? direction;\n}\n\n/** Short labels for `ExternalSync.conflictStrategy` / `SyncConflict.resolution` — friendlier than `enumLabel`'s\n * literal \"Source wins\"/\"Target wins\" (this is the one place PlanMagnet calls itself \"PlanMagnet\", not \"source\",\n * to the person choosing the strategy). Covers all four `PlanmagnetSyncConflictResolution` values, including\n * `MERGE` (AUT-24) — a prior version of this UI fell through to \"Manual\" for it in two places that read the raw\n * enum with a 3-way ternary instead of this map. */\nconst CONFLICT_STRATEGY_LABELS: Record<ConflictResolution, string> = {\n SOURCE_WINS: 'PlanMagnet wins',\n TARGET_WINS: 'Provider wins',\n MERGE: 'Merge',\n MANUAL: 'Manual',\n};\n\nexport function conflictStrategyLabel(value: string): string {\n return CONFLICT_STRATEGY_LABELS[value as ConflictResolution] ?? value;\n}\n\n/** Whether a capability supports a given direction at all — the single gate the wizard and the edit form both use. */\nexport function directionSupported(\n capability: Pick<\n SyncProviderCapability,\n 'supportsImport' | 'supportsExport' | 'supportsBidirectional'\n >,\n direction: SyncDirection\n): boolean {\n if (direction === 'INBOUND') return capability.supportsImport;\n if (direction === 'OUTBOUND') return capability.supportsExport;\n return capability.supportsBidirectional;\n}\n\n/** True once a provider can run at least one live direction — the gate for selecting it in the wizard at all. */\nexport function providerIsLive(\n capability: Pick<\n SyncProviderCapability,\n 'supportsImport' | 'supportsExport' | 'supportsBidirectional'\n >\n): boolean {\n return capability.supportsImport || capability.supportsExport || capability.supportsBidirectional;\n}\n\n/**\n * `ExternalSync.fieldMapping` -> the two GitHub label prefixes, as blank strings when unset (meaning \"the\n * connector's built-in default applies\"), never pre-filled with that default text — so an untouched form saves\n * nothing and a save always reflects a real, deliberate choice.\n */\n/** GitHub org/user name rules: 1-39 chars, alphanumeric or single hyphens, no leading/trailing hyphen. */\nconst GITHUB_OWNER_RE = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;\n/** GitHub repo name rules: 1-100 chars of letters, digits, `.`, `-`, `_`. */\nconst GITHUB_REPO_RE = /^[A-Za-z0-9._-]{1,100}$/;\n\nexport function isValidGithubOwner(value: string): boolean {\n return GITHUB_OWNER_RE.test(value.trim());\n}\nexport function isValidGithubRepo(value: string): boolean {\n return GITHUB_REPO_RE.test(value.trim());\n}\n\nexport function parseGithubFieldMapping(value: unknown): Record<GithubFieldMappingKey, string> {\n const out: Record<GithubFieldMappingKey, string> = { priority: '', dueDate: '' };\n if (!value || typeof value !== 'object' || Array.isArray(value)) return out;\n for (const key of GITHUB_FIELD_MAPPING_KEYS) {\n const raw = (value as Record<string, unknown>)[key];\n if (typeof raw === 'string' && raw.trim()) out[key] = raw.trim();\n }\n return out;\n}\n"],"mappings":";AAuCA,IAAa,IAAkB;CAAC;CAAW;CAAY;CAAgB,EAG1D,IAAgB;CAC3B;CACA;CACA;CACA;CACA;CACA;CACD,EAOY,IAAuB;CAAC;CAAe;CAAe;CAAS;CAAS,EAUxE,IAA4B,CAAC,YAAY,UAAU,EAGnD,IAAuE;CAClF,UAAU;CACV,SAAS;CACV,EAuGK,IAAgD;CACpD,MAAM;CACN,QAAQ;CACR,QAAQ;CACR,cAAc;CACd,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,SAAS;CACT,QAAQ;CACT;AAED,SAAgB,EAAc,GAA0B;AACtD,QAAO,EAAgB,MAA6B;;AAGtD,IAAM,IAAkD;CACtD,SAAS;CACT,UAAU;CACV,eAAe;CAChB;AAED,SAAgB,EAAe,GAA2B;AACxD,QAAO,EAAiB,MAA+B;;AAQzD,IAAM,IAA+D;CACnE,aAAa;CACb,aAAa;CACb,OAAO;CACP,QAAQ;CACT;AAED,SAAgB,EAAsB,GAAuB;AAC3D,QAAO,EAAyB,MAAgC;;AAIlE,SAAgB,EACd,GAIA,GACS;AAGT,QAFI,MAAc,YAAkB,EAAW,iBAC3C,MAAc,aAAmB,EAAW,iBACzC,EAAW;;AAIpB,SAAgB,EACd,GAIS;AACT,QAAO,EAAW,kBAAkB,EAAW,kBAAkB,EAAW;;AAS9E,IAAM,IAAkB,mDAElB,IAAiB;AAEvB,SAAgB,EAAmB,GAAwB;AACzD,QAAO,EAAgB,KAAK,EAAM,MAAM,CAAC;;AAE3C,SAAgB,EAAkB,GAAwB;AACxD,QAAO,EAAe,KAAK,EAAM,MAAM,CAAC;;AAG1C,SAAgB,EAAwB,GAAuD;CAC7F,IAAM,IAA6C;EAAE,UAAU;EAAI,SAAS;EAAI;AAChF,KAAI,CAAC,KAAS,OAAO,KAAU,YAAY,MAAM,QAAQ,EAAM,CAAE,QAAO;AACxE,MAAK,IAAM,KAAO,GAA2B;EAC3C,IAAM,IAAO,EAAkC;AAC/C,EAAI,OAAO,KAAQ,YAAY,EAAI,MAAM,KAAE,EAAI,KAAO,EAAI,MAAM;;AAElE,QAAO"}
|
|
@@ -29,8 +29,8 @@ import { useSearchParams as Ee } from "react-router";
|
|
|
29
29
|
import { gql as f } from "@apollo/client";
|
|
30
30
|
import { useQuery as p } from "@apollo/client/react";
|
|
31
31
|
import { Fragment as De, jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
32
|
-
import {
|
|
33
|
-
import {
|
|
32
|
+
import { Badge as Oe, Card as g, CardContent as _, CardHeader as v, CardTitle as y, Input as b, Select as x, SelectContent as S, SelectItem as C, SelectTrigger as ke, SelectValue as Ae } from "@burdenoff/fe-libs/ui";
|
|
33
|
+
import { useI18n as je } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
34
34
|
//#region src/planmagnet/pages/AnalyticsAnalyticsPagePage.tsx
|
|
35
35
|
var Me = f`
|
|
36
36
|
query AnalyticsProjectSprints($workspaceId: ID!, $projectId: String) {
|
|
@@ -179,7 +179,7 @@ function T(e) {
|
|
|
179
179
|
return `${t.getUTCMonth() + 1}/${t.getUTCDate()}`;
|
|
180
180
|
}
|
|
181
181
|
function E() {
|
|
182
|
-
let { workspaceId: f } = e(), { t: E } =
|
|
182
|
+
let { workspaceId: f } = e(), { t: E } = je(), [ze, D] = u(""), [O, Be] = Ee(), k = O.get("from"), A = O.get("to"), [j, M] = u(() => k && A && l(k, A) ? {
|
|
183
183
|
from: k,
|
|
184
184
|
to: A
|
|
185
185
|
} : ye("30")), [Ve, He] = u(j), [N, Ue] = u(O.get("project") || "all"), P = be(N), F = ve(j), I = l(j.from, j.to), We = I ? null : E("planmagnet.analytics.range.invalid", "\"From\" must be on or before \"To\".");
|
|
@@ -381,10 +381,10 @@ function E() {
|
|
|
381
381
|
}), /* @__PURE__ */ h(x, {
|
|
382
382
|
value: N,
|
|
383
383
|
onValueChange: Je,
|
|
384
|
-
children: [/* @__PURE__ */ m(
|
|
384
|
+
children: [/* @__PURE__ */ m(ke, {
|
|
385
385
|
className: "h-8 w-56",
|
|
386
386
|
"data-testid": "analytics-project",
|
|
387
|
-
children: /* @__PURE__ */ m(
|
|
387
|
+
children: /* @__PURE__ */ m(Ae, { placeholder: E("planmagnet.analytics.range.allProjects", "All projects") })
|
|
388
388
|
}), /* @__PURE__ */ h(S, { children: [/* @__PURE__ */ m(C, {
|
|
389
389
|
value: "all",
|
|
390
390
|
children: E("planmagnet.analytics.range.allProjects", "All projects")
|
|
@@ -487,9 +487,9 @@ function E() {
|
|
|
487
487
|
children: /* @__PURE__ */ h(x, {
|
|
488
488
|
value: G,
|
|
489
489
|
onValueChange: D,
|
|
490
|
-
children: [/* @__PURE__ */ m(
|
|
490
|
+
children: [/* @__PURE__ */ m(ke, {
|
|
491
491
|
className: "h-8 w-48",
|
|
492
|
-
children: /* @__PURE__ */ m(
|
|
492
|
+
children: /* @__PURE__ */ m(Ae, { placeholder: E("planmagnet.analytics.delivery.sprintPlaceholder", "Select sprint") })
|
|
493
493
|
}), /* @__PURE__ */ m(S, { children: W.map((e) => /* @__PURE__ */ m(C, {
|
|
494
494
|
value: e.id,
|
|
495
495
|
children: e.name
|
|
@@ -763,7 +763,7 @@ function E() {
|
|
|
763
763
|
className: "text-sm w-12 text-right",
|
|
764
764
|
children: [t, "%"]
|
|
765
765
|
}),
|
|
766
|
-
/* @__PURE__ */ m(
|
|
766
|
+
/* @__PURE__ */ m(Oe, {
|
|
767
767
|
variant: "outline",
|
|
768
768
|
className: "capitalize text-xs w-20 justify-center",
|
|
769
769
|
children: n.replace("_", " ")
|
|
@@ -9,8 +9,8 @@ import { AlertTriangle as m, ArrowUpRight as h, Calendar as g, CheckSquare as _,
|
|
|
9
9
|
import { gql as C } from "@apollo/client";
|
|
10
10
|
import { useQuery as w } from "@apollo/client/react";
|
|
11
11
|
import { Fragment as T, jsx as E, jsxs as D } from "react/jsx-runtime";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
12
|
+
import { Badge as O, Card as k, CardContent as A, CardHeader as j, CardTitle as M } from "@burdenoff/fe-libs/ui";
|
|
13
|
+
import { useI18n as N } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
14
14
|
//#region src/planmagnet/pages/DashboardDashboardPagePage.tsx
|
|
15
15
|
var P = [
|
|
16
16
|
"GetDashboardData",
|
|
@@ -121,7 +121,7 @@ var P = [
|
|
|
121
121
|
}
|
|
122
122
|
`;
|
|
123
123
|
function I() {
|
|
124
|
-
let { workspaceId: C } = e(), { t: I } =
|
|
124
|
+
let { workspaceId: C } = e(), { t: I } = N(), { data: L, loading: R, error: z } = w(F, { variables: {
|
|
125
125
|
workspaceId: C ?? "default",
|
|
126
126
|
today: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10)
|
|
127
127
|
} }), B = i(), V = a(), H = t(), U = f({
|
|
@@ -181,16 +181,16 @@ function I() {
|
|
|
181
181
|
}),
|
|
182
182
|
/* @__PURE__ */ E("div", {
|
|
183
183
|
className: "grid gap-4 md:grid-cols-2 lg:grid-cols-4",
|
|
184
|
-
children: Y.map((e) => /* @__PURE__ */ D(
|
|
184
|
+
children: Y.map((e) => /* @__PURE__ */ D(k, {
|
|
185
185
|
"data-testid": "dashboard-tile-link",
|
|
186
186
|
...l(() => H(`/analytics/analytics-page${u(d("30"))}`), `${e.label}: ${e.value}. ${I("planmagnet.dashboard.metrics.openAnalytics", "Open in Analytics")}`),
|
|
187
|
-
children: [/* @__PURE__ */ D(
|
|
187
|
+
children: [/* @__PURE__ */ D(j, {
|
|
188
188
|
className: "flex flex-row items-center justify-between space-y-0 pb-2",
|
|
189
|
-
children: [/* @__PURE__ */ E(
|
|
189
|
+
children: [/* @__PURE__ */ E(M, {
|
|
190
190
|
className: "text-sm font-medium",
|
|
191
191
|
children: e.label
|
|
192
192
|
}), /* @__PURE__ */ E(b, { className: "h-4 w-4 text-muted-foreground" })]
|
|
193
|
-
}), /* @__PURE__ */ D(
|
|
193
|
+
}), /* @__PURE__ */ D(A, { children: [/* @__PURE__ */ E("div", {
|
|
194
194
|
className: "text-2xl font-bold",
|
|
195
195
|
children: e.value
|
|
196
196
|
}), /* @__PURE__ */ E("p", {
|
|
@@ -201,12 +201,12 @@ function I() {
|
|
|
201
201
|
}),
|
|
202
202
|
/* @__PURE__ */ D("div", {
|
|
203
203
|
className: "grid gap-6 lg:grid-cols-12",
|
|
204
|
-
children: [/* @__PURE__ */ D(
|
|
204
|
+
children: [/* @__PURE__ */ D(k, {
|
|
205
205
|
className: "lg:col-span-8",
|
|
206
|
-
children: [/* @__PURE__ */ E(
|
|
206
|
+
children: [/* @__PURE__ */ E(j, { children: /* @__PURE__ */ D(M, {
|
|
207
207
|
className: "flex items-center gap-2 text-base",
|
|
208
208
|
children: [/* @__PURE__ */ E(S, { className: "h-5 w-5 text-blue-500" }), I("planmagnet.dashboard.activeSprints.title", "Active Sprints")]
|
|
209
|
-
}) }), /* @__PURE__ */ D(
|
|
209
|
+
}) }), /* @__PURE__ */ D(A, {
|
|
210
210
|
className: "space-y-4",
|
|
211
211
|
children: [K.map((e) => {
|
|
212
212
|
let t = e.workItems.reduce((e, t) => e + (t.storyPoints ?? 0), 0), n = e.workItems.filter((e) => e.status === "DONE").reduce((e, t) => e + (t.storyPoints ?? 0), 0), r = e.workItems.length, i = e.workItems.filter((e) => e.status === "DONE").length, a = o(e.workItems) ?? 0;
|
|
@@ -231,7 +231,7 @@ function I() {
|
|
|
231
231
|
" ",
|
|
232
232
|
e.project?.name ?? I("planmagnet.dashboard.shared.projectUnavailable", "not available")
|
|
233
233
|
] })
|
|
234
|
-
})] }), /* @__PURE__ */ D(
|
|
234
|
+
})] }), /* @__PURE__ */ D(O, {
|
|
235
235
|
variant: "secondary",
|
|
236
236
|
children: [
|
|
237
237
|
n,
|
|
@@ -273,25 +273,25 @@ function I() {
|
|
|
273
273
|
})]
|
|
274
274
|
}), /* @__PURE__ */ D("div", {
|
|
275
275
|
className: "lg:col-span-4 space-y-6",
|
|
276
|
-
children: [G.length > 0 && /* @__PURE__ */ D(
|
|
276
|
+
children: [G.length > 0 && /* @__PURE__ */ D(k, { children: [/* @__PURE__ */ E(j, { children: /* @__PURE__ */ D(M, {
|
|
277
277
|
className: "flex items-center gap-2 text-base",
|
|
278
278
|
children: [/* @__PURE__ */ E(m, { className: "h-5 w-5 text-orange-500" }), I("planmagnet.dashboard.onHoldProjects.title", "On-Hold Projects")]
|
|
279
|
-
}) }), /* @__PURE__ */ E(
|
|
279
|
+
}) }), /* @__PURE__ */ E(A, {
|
|
280
280
|
className: "space-y-3",
|
|
281
281
|
children: G.map((e) => /* @__PURE__ */ D("div", {
|
|
282
282
|
className: "flex items-center justify-between rounded border p-2",
|
|
283
283
|
children: [/* @__PURE__ */ E("div", { children: /* @__PURE__ */ E("p", {
|
|
284
284
|
className: "text-sm font-medium",
|
|
285
285
|
children: e.name
|
|
286
|
-
}) }), /* @__PURE__ */ E(
|
|
286
|
+
}) }), /* @__PURE__ */ E(O, {
|
|
287
287
|
variant: "destructive",
|
|
288
288
|
children: e.status.toLowerCase().replace("_", " ")
|
|
289
289
|
})]
|
|
290
290
|
}, e.id))
|
|
291
|
-
})] }), /* @__PURE__ */ D(
|
|
291
|
+
})] }), /* @__PURE__ */ D(k, { children: [/* @__PURE__ */ E(j, { children: /* @__PURE__ */ D(M, {
|
|
292
292
|
className: "flex items-center gap-2 text-base",
|
|
293
293
|
children: [/* @__PURE__ */ E(g, { className: "h-5 w-5 text-green-500" }), I("planmagnet.dashboard.upcomingMilestones.title", "Upcoming Milestones")]
|
|
294
|
-
}) }), /* @__PURE__ */ D(
|
|
294
|
+
}) }), /* @__PURE__ */ D(A, {
|
|
295
295
|
className: "space-y-3",
|
|
296
296
|
children: [q.map((e) => /* @__PURE__ */ D("div", {
|
|
297
297
|
...l(() => H(c("/projects/milestone-detail-page", e.id)), e.name),
|
|
@@ -321,7 +321,7 @@ function I() {
|
|
|
321
321
|
]
|
|
322
322
|
})
|
|
323
323
|
]
|
|
324
|
-
}), /* @__PURE__ */ E(
|
|
324
|
+
}), /* @__PURE__ */ E(O, {
|
|
325
325
|
variant: "secondary",
|
|
326
326
|
className: "text-xs flex-shrink-0 capitalize",
|
|
327
327
|
children: e.status.toLowerCase().replace("_", " ")
|
|
@@ -335,10 +335,10 @@ function I() {
|
|
|
335
335
|
}),
|
|
336
336
|
/* @__PURE__ */ D("div", {
|
|
337
337
|
className: "grid gap-6 lg:grid-cols-2",
|
|
338
|
-
children: [/* @__PURE__ */ D(
|
|
338
|
+
children: [/* @__PURE__ */ D(k, { children: [/* @__PURE__ */ E(j, { children: /* @__PURE__ */ D(M, {
|
|
339
339
|
className: "flex items-center gap-2 text-base",
|
|
340
340
|
children: [/* @__PURE__ */ E(_, { className: "h-5 w-5 text-purple-500" }), I("planmagnet.dashboard.recentWorkItems.title", "Recent Work Items")]
|
|
341
|
-
}) }), /* @__PURE__ */ D(
|
|
341
|
+
}) }), /* @__PURE__ */ D(A, {
|
|
342
342
|
className: "space-y-3",
|
|
343
343
|
children: [J.map((e) => /* @__PURE__ */ D("div", {
|
|
344
344
|
...l(() => H(`/tasks/task-detail-page?taskId=${encodeURIComponent(e.id)}`), `${e.key} ${e.title}`),
|
|
@@ -361,7 +361,7 @@ function I() {
|
|
|
361
361
|
})]
|
|
362
362
|
}), /* @__PURE__ */ D("div", {
|
|
363
363
|
className: "flex items-center gap-2 flex-shrink-0",
|
|
364
|
-
children: [/* @__PURE__ */ D(
|
|
364
|
+
children: [/* @__PURE__ */ D(O, {
|
|
365
365
|
variant: "outline",
|
|
366
366
|
className: "text-xs",
|
|
367
367
|
children: [
|
|
@@ -369,7 +369,7 @@ function I() {
|
|
|
369
369
|
" ",
|
|
370
370
|
I("planmagnet.dashboard.shared.pointsShort", "pts")
|
|
371
371
|
]
|
|
372
|
-
}), /* @__PURE__ */ E(
|
|
372
|
+
}), /* @__PURE__ */ E(O, {
|
|
373
373
|
variant: "secondary",
|
|
374
374
|
className: "text-xs capitalize",
|
|
375
375
|
children: e.status.toLowerCase().replace("_", " ")
|
|
@@ -379,10 +379,10 @@ function I() {
|
|
|
379
379
|
className: "text-sm text-muted-foreground text-center py-4",
|
|
380
380
|
children: I("planmagnet.dashboard.recentWorkItems.empty", "No work items yet.")
|
|
381
381
|
})]
|
|
382
|
-
})] }), /* @__PURE__ */ D(
|
|
382
|
+
})] }), /* @__PURE__ */ D(k, { children: [/* @__PURE__ */ E(j, { children: /* @__PURE__ */ D(M, {
|
|
383
383
|
className: "flex items-center gap-2 text-base",
|
|
384
384
|
children: [/* @__PURE__ */ E(v, { className: "h-5 w-5 text-cyan-500" }), I("planmagnet.dashboard.projectStatus.title", "Project Status")]
|
|
385
|
-
}) }), /* @__PURE__ */ D(
|
|
385
|
+
}) }), /* @__PURE__ */ D(A, {
|
|
386
386
|
className: "space-y-3",
|
|
387
387
|
children: [W.map((e) => /* @__PURE__ */ D("div", {
|
|
388
388
|
...l(() => H(c("/projects/project-detail-page", e.id)), e.name),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocsDocDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/DocsDocDetailPagePage.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DocsDocDetailPagePage.d.ts","sourceRoot":"","sources":["../../../src/planmagnet/pages/DocsDocDetailPagePage.tsx"],"names":[],"mappings":"AAwTA,wBAAgB,qBAAqB,4CA+wBpC"}
|