@burdenoff/microfe-planmagnet 2026.1001.5 → 2026.1001.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/CompetitorControls.d.ts +71 -0
- package/dist/planmagnet/controls/CompetitorControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/CompetitorControls.js +346 -12
- package/dist/planmagnet/controls/CompetitorControls.js.map +1 -1
- package/dist/planmagnet/controls/FeatureControls.d.ts +23 -1
- package/dist/planmagnet/controls/FeatureControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/FeatureControls.js +431 -229
- 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/Pickers.d.ts +15 -0
- package/dist/planmagnet/controls/Pickers.d.ts.map +1 -1
- package/dist/planmagnet/controls/Pickers.js +61 -1
- package/dist/planmagnet/controls/Pickers.js.map +1 -1
- package/dist/planmagnet/controls/PrioritizationControls.d.ts +36 -0
- package/dist/planmagnet/controls/PrioritizationControls.d.ts.map +1 -1
- package/dist/planmagnet/controls/PrioritizationControls.js +118 -1
- package/dist/planmagnet/controls/PrioritizationControls.js.map +1 -1
- 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 +8 -8
- package/dist/planmagnet/dashboards/cards/RiskSeverityCard.js +4 -4
- package/dist/planmagnet/dashboards/cards/SprintCapacityCard.d.ts.map +1 -1
- package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js +67 -59
- package/dist/planmagnet/dashboards/cards/SprintCapacityCard.js.map +1 -1
- 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.d.ts.map +1 -1
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js +290 -283
- package/dist/planmagnet/pages/AnalyticsAnalyticsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js +126 -63
- package/dist/planmagnet/pages/CompetitorsCompetitorDetailPagePage.js.map +1 -1
- package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js +14 -0
- package/dist/planmagnet/pages/CompetitorsCompetitorsPagePage.js.map +1 -1
- package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js +93 -57
- package/dist/planmagnet/pages/CompetitorsCreateCompetitorPagePage.js.map +1 -1
- package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js +125 -83
- package/dist/planmagnet/pages/CompetitorsEditCompetitorPagePage.js.map +1 -1
- 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/PortfoliosPortfolioDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js +226 -126
- package/dist/planmagnet/pages/PortfoliosPortfolioDetailPagePage.js.map +1 -1
- 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 +169 -122
- 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 +165 -109
- 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/ProjectsPlanningDetailPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js +15 -3
- package/dist/planmagnet/pages/ProjectsPlanningDetailPagePage.js.map +1 -1
- 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/TeamTeamPagePage.d.ts.map +1 -1
- package/dist/planmagnet/pages/TeamTeamPagePage.js +59 -53
- package/dist/planmagnet/pages/TeamTeamPagePage.js.map +1 -1
- package/dist/planmagnet/pages/analytics/DeliveryHealthCards.js +8 -8
- package/dist/planmagnet/pages/analytics/DeliveryKpisCard.js +6 -6
- package/dist/planmagnet/pages/analytics/MetricsCard.d.ts +8 -0
- package/dist/planmagnet/pages/analytics/MetricsCard.d.ts.map +1 -0
- package/dist/planmagnet/pages/analytics/MetricsCard.js +164 -0
- package/dist/planmagnet/pages/analytics/MetricsCard.js.map +1 -0
- 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/team/UnmatchedCrewIdentities.d.ts +2 -0
- package/dist/planmagnet/team/UnmatchedCrewIdentities.d.ts.map +1 -0
- package/dist/planmagnet/team/UnmatchedCrewIdentities.js +155 -0
- package/dist/planmagnet/team/UnmatchedCrewIdentities.js.map +1 -0
- 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
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { usePlanMagnetNavigate as e } from "../providers/PlanMagnetProvider.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
2
|
+
import { mutationErrorMessage as t } from "../utils/graphqlErrors.js";
|
|
3
|
+
import { throwOnError as n } from "../utils/mutationResult.js";
|
|
4
|
+
import { detailPath as r } from "../utils/rowNavigation.js";
|
|
5
|
+
import { JsonKeyValueEditor as i, StringListEditor as a, cleanStringList as o, competitorListValid as s, jsonRowsToObject as c, jsonRowsValid as l, jsonToRows as u } from "../controls/CompetitorControls.js";
|
|
6
|
+
import { useMemo as d, useState as f } from "react";
|
|
7
|
+
import { ArrowLeft as ee, Loader2 as p, Save as m } from "lucide-react";
|
|
8
|
+
import { useParams as te } from "react-router";
|
|
9
|
+
import { gql as h } from "@apollo/client";
|
|
10
|
+
import { useMutation as g, useQuery as _ } from "@apollo/client/react";
|
|
11
|
+
import { jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
12
|
+
import { Button as b, Card as x, CardContent as S, CardHeader as C, CardTitle as w, Input as T } from "@burdenoff/fe-libs/ui";
|
|
11
13
|
//#region src/planmagnet/pages/CompetitorsEditCompetitorPagePage.tsx
|
|
12
|
-
var
|
|
14
|
+
var ne = h`
|
|
13
15
|
query GetCompetitorForEdit($id: ID!) {
|
|
14
16
|
planmagnetCompetitor(id: $id) {
|
|
15
17
|
id
|
|
@@ -17,9 +19,13 @@ var b = l`
|
|
|
17
19
|
website
|
|
18
20
|
description
|
|
19
21
|
tags
|
|
22
|
+
strengths
|
|
23
|
+
weaknesses
|
|
24
|
+
pricing
|
|
25
|
+
features
|
|
20
26
|
}
|
|
21
27
|
}
|
|
22
|
-
`,
|
|
28
|
+
`, re = h`
|
|
23
29
|
mutation UpdateCompetitor($id: ID!, $input: PlanmagnetUpdateCompetitorInput!) {
|
|
24
30
|
planmagnetUpdateCompetitor(id: $id, input: $input) {
|
|
25
31
|
id
|
|
@@ -27,15 +33,19 @@ var b = l`
|
|
|
27
33
|
website
|
|
28
34
|
description
|
|
29
35
|
tags
|
|
36
|
+
strengths
|
|
37
|
+
weaknesses
|
|
38
|
+
pricing
|
|
39
|
+
features
|
|
30
40
|
updatedAt
|
|
31
41
|
}
|
|
32
42
|
}
|
|
33
43
|
`;
|
|
34
|
-
function
|
|
35
|
-
let
|
|
36
|
-
variables: { id:
|
|
37
|
-
skip: !
|
|
38
|
-
}), [
|
|
44
|
+
function E() {
|
|
45
|
+
let h = e(), E = te().id ?? "", { data: D, loading: O, error: k } = _(ne, {
|
|
46
|
+
variables: { id: E },
|
|
47
|
+
skip: !E
|
|
48
|
+
}), [A, { loading: j }] = g(re, {
|
|
39
49
|
refetchQueries: [
|
|
40
50
|
"ListCompetitors",
|
|
41
51
|
"GetCompetitorForEdit",
|
|
@@ -43,139 +53,171 @@ function S() {
|
|
|
43
53
|
"PickerCompetitors"
|
|
44
54
|
],
|
|
45
55
|
awaitRefetchQueries: !0
|
|
46
|
-
}), [
|
|
47
|
-
name:
|
|
48
|
-
website:
|
|
49
|
-
description:
|
|
50
|
-
tags:
|
|
51
|
-
}), [
|
|
52
|
-
...
|
|
53
|
-
...
|
|
54
|
-
},
|
|
55
|
-
return
|
|
56
|
+
}), [M, N] = f(null), [ie, P] = f(!1), F = D?.planmagnetCompetitor, I = d(() => ({
|
|
57
|
+
name: F?.name ?? "",
|
|
58
|
+
website: F?.website ?? "",
|
|
59
|
+
description: F?.description ?? "",
|
|
60
|
+
tags: F?.tags?.join(", ") ?? ""
|
|
61
|
+
}), [F]), [ae, oe] = f({}), L = {
|
|
62
|
+
...I,
|
|
63
|
+
...ae
|
|
64
|
+
}, R = (e) => oe(e), z = d(() => F?.strengths ?? [], [F]), B = d(() => F?.weaknesses ?? [], [F]), V = d(() => u(F?.pricing), [F]), H = d(() => u(F?.features), [F]), [U, W] = f(null), [G, K] = f(null), [q, se] = f(null), [J, ce] = f(null), Y = U ?? z, X = G ?? B, Z = q ?? V, Q = J ?? H, $ = s(Y) && s(X) && l(Z) && l(Q);
|
|
65
|
+
return O && !D ? /* @__PURE__ */ v("div", {
|
|
56
66
|
className: "flex items-center justify-center p-12",
|
|
57
|
-
children: /* @__PURE__ */
|
|
58
|
-
}) :
|
|
67
|
+
children: /* @__PURE__ */ v(p, { className: "h-8 w-8 animate-spin text-muted-foreground" })
|
|
68
|
+
}) : k ? /* @__PURE__ */ y("div", {
|
|
59
69
|
className: "p-6 text-destructive",
|
|
60
|
-
children: ["Failed to load competitor: ",
|
|
61
|
-
}) :
|
|
70
|
+
children: ["Failed to load competitor: ", k.message]
|
|
71
|
+
}) : F ? /* @__PURE__ */ y("div", {
|
|
62
72
|
className: "space-y-6 p-6 max-w-4xl",
|
|
63
73
|
children: [
|
|
64
|
-
/* @__PURE__ */
|
|
74
|
+
/* @__PURE__ */ y("div", {
|
|
65
75
|
className: "flex items-center justify-between",
|
|
66
|
-
children: [/* @__PURE__ */
|
|
76
|
+
children: [/* @__PURE__ */ y("div", {
|
|
67
77
|
className: "flex items-center gap-3",
|
|
68
|
-
children: [/* @__PURE__ */
|
|
78
|
+
children: [/* @__PURE__ */ v(b, {
|
|
69
79
|
variant: "ghost",
|
|
70
80
|
size: "sm",
|
|
71
81
|
"aria-label": "Back to the competitor",
|
|
72
|
-
onClick: () =>
|
|
73
|
-
children: /* @__PURE__ */
|
|
74
|
-
}), /* @__PURE__ */
|
|
82
|
+
onClick: () => h(r("/products/competitor-detail-page", E)),
|
|
83
|
+
children: /* @__PURE__ */ v(ee, { className: "h-4 w-4" })
|
|
84
|
+
}), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("h1", {
|
|
75
85
|
className: "text-2xl font-semibold",
|
|
76
86
|
children: "Edit Competitor"
|
|
77
|
-
}), /* @__PURE__ */
|
|
87
|
+
}), /* @__PURE__ */ v("p", {
|
|
78
88
|
className: "text-sm text-muted-foreground",
|
|
79
|
-
children:
|
|
89
|
+
children: F.name
|
|
80
90
|
})] })]
|
|
81
|
-
}), /* @__PURE__ */
|
|
91
|
+
}), /* @__PURE__ */ y(b, {
|
|
82
92
|
size: "sm",
|
|
83
93
|
onClick: async () => {
|
|
84
|
-
if (!
|
|
85
|
-
let e = (e) => e.split(",").map((e) => e.trim()).filter(Boolean),
|
|
86
|
-
name:
|
|
94
|
+
if (!F || !L.name.trim() || !$) return;
|
|
95
|
+
let e = (e) => e.split(",").map((e) => e.trim()).filter(Boolean), r = {
|
|
96
|
+
name: L.name.trim(),
|
|
97
|
+
website: L.website.trim() || null,
|
|
98
|
+
description: L.description.trim() || null,
|
|
99
|
+
tags: e(L.tags)
|
|
100
|
+
}, i = {
|
|
101
|
+
name: I.name,
|
|
87
102
|
website: I.website.trim() || null,
|
|
88
103
|
description: I.description.trim() || null,
|
|
89
104
|
tags: e(I.tags)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}, i = Object.fromEntries(Object.entries(n).filter(([e, t]) => JSON.stringify(t) !== JSON.stringify(r[e])));
|
|
96
|
-
if (k(null), j(!1), Object.keys(i).length === 0) {
|
|
97
|
-
j(!0);
|
|
105
|
+
};
|
|
106
|
+
U !== null && (r.strengths = o(Y), i.strengths = o(z)), G !== null && (r.weaknesses = o(X), i.weaknesses = o(B)), q !== null && (r.pricing = c(Z), i.pricing = F.pricing ?? null), J !== null && (r.features = c(Q), i.features = F.features ?? null);
|
|
107
|
+
let a = Object.fromEntries(Object.entries(r).filter(([e, t]) => JSON.stringify(t) !== JSON.stringify(i[e])));
|
|
108
|
+
if (N(null), P(!1), Object.keys(a).length === 0) {
|
|
109
|
+
P(!0);
|
|
98
110
|
return;
|
|
99
111
|
}
|
|
100
112
|
try {
|
|
101
|
-
await
|
|
102
|
-
id:
|
|
103
|
-
input:
|
|
104
|
-
} })),
|
|
113
|
+
await n(A({ variables: {
|
|
114
|
+
id: E,
|
|
115
|
+
input: a
|
|
116
|
+
} })), P(!0);
|
|
105
117
|
} catch (e) {
|
|
106
|
-
|
|
118
|
+
N(t(e, "The competitor could not be saved."));
|
|
107
119
|
}
|
|
108
120
|
},
|
|
109
|
-
disabled:
|
|
110
|
-
children: [
|
|
121
|
+
disabled: j || !L.name.trim() || !$,
|
|
122
|
+
children: [j ? /* @__PURE__ */ v(p, { className: "mr-1 h-4 w-4 animate-spin" }) : /* @__PURE__ */ v(m, { className: "mr-1 h-4 w-4" }), "Save Changes"]
|
|
111
123
|
})]
|
|
112
124
|
}),
|
|
113
|
-
|
|
125
|
+
ie && /* @__PURE__ */ v("div", {
|
|
114
126
|
role: "status",
|
|
115
127
|
className: "p-3 bg-muted text-status-success-text rounded-md text-sm",
|
|
116
128
|
children: "Changes saved."
|
|
117
129
|
}),
|
|
118
|
-
|
|
130
|
+
M && /* @__PURE__ */ v("div", {
|
|
119
131
|
role: "alert",
|
|
120
132
|
className: "p-3 rounded-md bg-destructive/10 text-destructive text-sm",
|
|
121
|
-
children:
|
|
133
|
+
children: M
|
|
122
134
|
}),
|
|
123
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ y(x, { children: [/* @__PURE__ */ v(C, { children: /* @__PURE__ */ v(w, { children: "Competitor Details" }) }), /* @__PURE__ */ y(S, {
|
|
124
136
|
className: "space-y-4",
|
|
125
137
|
children: [
|
|
126
|
-
/* @__PURE__ */
|
|
138
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
127
139
|
className: "text-sm font-medium",
|
|
128
140
|
children: "Name"
|
|
129
|
-
}), /* @__PURE__ */
|
|
130
|
-
value:
|
|
131
|
-
onChange: (e) =>
|
|
132
|
-
...
|
|
141
|
+
}), /* @__PURE__ */ v(T, {
|
|
142
|
+
value: L.name,
|
|
143
|
+
onChange: (e) => R({
|
|
144
|
+
...L,
|
|
133
145
|
name: e.target.value
|
|
134
146
|
}),
|
|
135
147
|
className: "mt-1"
|
|
136
148
|
})] }),
|
|
137
|
-
/* @__PURE__ */
|
|
149
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
138
150
|
className: "text-sm font-medium",
|
|
139
151
|
children: "Website"
|
|
140
|
-
}), /* @__PURE__ */
|
|
141
|
-
value:
|
|
142
|
-
onChange: (e) =>
|
|
143
|
-
...
|
|
152
|
+
}), /* @__PURE__ */ v(T, {
|
|
153
|
+
value: L.website,
|
|
154
|
+
onChange: (e) => R({
|
|
155
|
+
...L,
|
|
144
156
|
website: e.target.value
|
|
145
157
|
}),
|
|
146
158
|
className: "mt-1"
|
|
147
159
|
})] }),
|
|
148
|
-
/* @__PURE__ */
|
|
160
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
149
161
|
className: "text-sm font-medium",
|
|
150
162
|
children: "Description / Notes"
|
|
151
|
-
}), /* @__PURE__ */
|
|
163
|
+
}), /* @__PURE__ */ v("textarea", {
|
|
152
164
|
className: "mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]",
|
|
153
|
-
value:
|
|
154
|
-
onChange: (e) =>
|
|
155
|
-
...
|
|
165
|
+
value: L.description,
|
|
166
|
+
onChange: (e) => R({
|
|
167
|
+
...L,
|
|
156
168
|
description: e.target.value
|
|
157
169
|
})
|
|
158
170
|
})] }),
|
|
159
|
-
/* @__PURE__ */
|
|
171
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
160
172
|
className: "text-sm font-medium",
|
|
161
173
|
children: "Tags (comma-separated)"
|
|
162
|
-
}), /* @__PURE__ */
|
|
163
|
-
value:
|
|
164
|
-
onChange: (e) =>
|
|
165
|
-
...
|
|
174
|
+
}), /* @__PURE__ */ v(T, {
|
|
175
|
+
value: L.tags,
|
|
176
|
+
onChange: (e) => R({
|
|
177
|
+
...L,
|
|
166
178
|
tags: e.target.value
|
|
167
179
|
}),
|
|
168
180
|
className: "mt-1"
|
|
169
181
|
})] })
|
|
170
182
|
]
|
|
183
|
+
})] }),
|
|
184
|
+
/* @__PURE__ */ y(x, { children: [/* @__PURE__ */ v(C, { children: /* @__PURE__ */ v(w, { children: "Strengths & Weaknesses" }) }), /* @__PURE__ */ y(S, {
|
|
185
|
+
className: "space-y-4",
|
|
186
|
+
children: [/* @__PURE__ */ v(a, {
|
|
187
|
+
label: "Strengths",
|
|
188
|
+
values: Y,
|
|
189
|
+
onChange: W,
|
|
190
|
+
placeholder: "e.g. Strong enterprise SSO",
|
|
191
|
+
testId: "competitor-strengths"
|
|
192
|
+
}), /* @__PURE__ */ v(a, {
|
|
193
|
+
label: "Weaknesses",
|
|
194
|
+
values: X,
|
|
195
|
+
onChange: K,
|
|
196
|
+
placeholder: "e.g. No mobile app",
|
|
197
|
+
testId: "competitor-weaknesses"
|
|
198
|
+
})]
|
|
199
|
+
})] }),
|
|
200
|
+
/* @__PURE__ */ y(x, { children: [/* @__PURE__ */ v(C, { children: /* @__PURE__ */ v(w, { children: "Pricing & Feature Comparison" }) }), /* @__PURE__ */ y(S, {
|
|
201
|
+
className: "space-y-4",
|
|
202
|
+
children: [/* @__PURE__ */ v(i, {
|
|
203
|
+
label: "Pricing",
|
|
204
|
+
rows: Z,
|
|
205
|
+
onChange: se,
|
|
206
|
+
testId: "competitor-pricing"
|
|
207
|
+
}), /* @__PURE__ */ v(i, {
|
|
208
|
+
label: "Features",
|
|
209
|
+
rows: Q,
|
|
210
|
+
onChange: ce,
|
|
211
|
+
testId: "competitor-features"
|
|
212
|
+
})]
|
|
171
213
|
})] })
|
|
172
214
|
]
|
|
173
|
-
}) : /* @__PURE__ */
|
|
215
|
+
}) : /* @__PURE__ */ v("div", {
|
|
174
216
|
className: "p-6 text-muted-foreground",
|
|
175
217
|
children: "Competitor not found."
|
|
176
218
|
});
|
|
177
219
|
}
|
|
178
220
|
//#endregion
|
|
179
|
-
export {
|
|
221
|
+
export { E as CompetitorsEditCompetitorPagePage };
|
|
180
222
|
|
|
181
223
|
//# sourceMappingURL=CompetitorsEditCompetitorPagePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompetitorsEditCompetitorPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/CompetitorsEditCompetitorPagePage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery, useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, ArrowLeft, Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError } from '../utils/mutationResult';\n\nconst GET_COMPETITOR = gql`\n query GetCompetitorForEdit($id: ID!) {\n planmagnetCompetitor(id: $id) {\n id\n name\n website\n description\n tags\n }\n }\n`;\n\nconst UPDATE_COMPETITOR = gql`\n mutation UpdateCompetitor($id: ID!, $input: PlanmagnetUpdateCompetitorInput!) {\n planmagnetUpdateCompetitor(id: $id, input: $input) {\n id\n name\n website\n description\n tags\n updatedAt\n }\n }\n`;\n\nexport function CompetitorsEditCompetitorPagePage() {\n const navigate = usePlanMagnetNavigate();\n const params = useParams<{ id: string }>();\n const competitorId = params.id ?? '';\n\n const { data, loading, error } = useQuery<{\n planmagnetCompetitor: {\n id: string;\n name: string;\n website: string | null;\n description: string | null;\n tags: string[];\n } | null;\n }>(GET_COMPETITOR, { variables: { id: competitorId }, skip: !competitorId });\n\n const [updateCompetitor, { loading: saving }] = useMutation(UPDATE_COMPETITOR, {\n refetchQueries: [\n 'ListCompetitors',\n 'GetCompetitorForEdit',\n 'GetCompetitor',\n 'PickerCompetitors',\n ],\n awaitRefetchQueries: true,\n });\n const [saveError, setSaveError] = useState<string | null>(null);\n const [saved, setSaved] = useState(false);\n\n const competitor = data?.planmagnetCompetitor;\n\n const defaultForm = useMemo(\n () => ({\n name: competitor?.name ?? '',\n website: competitor?.website ?? '',\n description: competitor?.description ?? '',\n tags: competitor?.tags?.join(', ') ?? '',\n }),\n [competitor]\n );\n\n const [formOverrides, setFormOverrides] = useState<Record<string, string>>({});\n const form = { ...defaultForm, ...formOverrides };\n const setForm = (val: Record<string, string>) => setFormOverrides(val);\n\n const handleSave = async () => {\n if (!competitor || !form.name.trim()) return;\n const tagList = (v: string) =>\n v\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n const next: Record<string, unknown> = {\n name: form.name.trim(),\n website: form.website.trim() || null,\n description: form.description.trim() || null,\n tags: tagList(form.tags),\n };\n const before: Record<string, unknown> = {\n name: defaultForm.name,\n website: defaultForm.website.trim() || null,\n description: defaultForm.description.trim() || null,\n tags: tagList(defaultForm.tags),\n };\n const input = Object.fromEntries(\n Object.entries(next).filter(([k, v]) => JSON.stringify(v) !== JSON.stringify(before[k]))\n );\n setSaveError(null);\n setSaved(false);\n if (Object.keys(input).length === 0) {\n setSaved(true);\n return;\n }\n try {\n await throwOnError(updateCompetitor({ variables: { id: competitorId, input } }));\n setSaved(true);\n } catch (e) {\n setSaveError(e instanceof Error ? e.message : 'The competitor could not be saved.');\n }\n };\n\n // Only before the first load: a refetch must not blank the page (it unmounts every component on it and\n // loses their state).\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load competitor: {error.message}</div>;\n }\n\n if (!competitor) return <div className=\"p-6 text-muted-foreground\">Competitor not found.</div>;\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Back to the competitor\"\n onClick={() => navigate(detailPath('/products/competitor-detail-page', competitorId))}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Edit Competitor</h1>\n <p className=\"text-sm text-muted-foreground\">{competitor.name}</p>\n </div>\n </div>\n <Button size=\"sm\" onClick={handleSave} disabled={saving || !form.name.trim()}>\n {saving ? (\n <Loader2 className=\"mr-1 h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"mr-1 h-4 w-4\" />\n )}\n Save Changes\n </Button>\n </div>\n\n {saved && (\n <div role=\"status\" className=\"p-3 bg-muted text-status-success-text rounded-md text-sm\">\n Changes saved.\n </div>\n )}\n {saveError && (\n <div role=\"alert\" className=\"p-3 rounded-md bg-destructive/10 text-destructive text-sm\">\n {saveError}\n </div>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Competitor Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Name</label>\n <Input\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Website</label>\n <Input\n value={form.website}\n onChange={(e) => setForm({ ...form, website: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description / Notes</label>\n <textarea\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Tags (comma-separated)</label>\n <Input\n value={form.tags}\n onChange={(e) => setForm({ ...form, tags: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CompetitorsEditCompetitorPagePage.js","names":[],"sources":["../../../src/planmagnet/pages/CompetitorsEditCompetitorPagePage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery, useMutation } from '@apollo/client/react';\nimport { Card, CardContent, CardHeader, CardTitle, Button, Input } from '@burdenoff/fe-libs/ui';\nimport { Save, ArrowLeft, Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router';\nimport { usePlanMagnetNavigate } from '../providers/PlanMagnetProvider';\nimport { detailPath } from '../utils/rowNavigation';\nimport { throwOnError } from '../utils/mutationResult';\nimport { mutationErrorMessage } from '../utils/graphqlErrors';\nimport {\n JsonKeyValueEditor,\n StringListEditor,\n cleanStringList,\n competitorListValid,\n jsonRowsToObject,\n jsonRowsValid,\n jsonToRows,\n type JsonKeyValueRow,\n} from '../controls/CompetitorControls';\n\nconst GET_COMPETITOR = gql`\n query GetCompetitorForEdit($id: ID!) {\n planmagnetCompetitor(id: $id) {\n id\n name\n website\n description\n tags\n strengths\n weaknesses\n pricing\n features\n }\n }\n`;\n\nconst UPDATE_COMPETITOR = gql`\n mutation UpdateCompetitor($id: ID!, $input: PlanmagnetUpdateCompetitorInput!) {\n planmagnetUpdateCompetitor(id: $id, input: $input) {\n id\n name\n website\n description\n tags\n strengths\n weaknesses\n pricing\n features\n updatedAt\n }\n }\n`;\n\nexport function CompetitorsEditCompetitorPagePage() {\n const navigate = usePlanMagnetNavigate();\n const params = useParams<{ id: string }>();\n const competitorId = params.id ?? '';\n\n const { data, loading, error } = useQuery<{\n planmagnetCompetitor: {\n id: string;\n name: string;\n website: string | null;\n description: string | null;\n tags: string[];\n strengths: string[];\n weaknesses: string[];\n pricing: unknown;\n features: unknown;\n } | null;\n }>(GET_COMPETITOR, { variables: { id: competitorId }, skip: !competitorId });\n\n const [updateCompetitor, { loading: saving }] = useMutation(UPDATE_COMPETITOR, {\n refetchQueries: [\n 'ListCompetitors',\n 'GetCompetitorForEdit',\n 'GetCompetitor',\n 'PickerCompetitors',\n ],\n awaitRefetchQueries: true,\n });\n const [saveError, setSaveError] = useState<string | null>(null);\n const [saved, setSaved] = useState(false);\n\n const competitor = data?.planmagnetCompetitor;\n\n const defaultForm = useMemo(\n () => ({\n name: competitor?.name ?? '',\n website: competitor?.website ?? '',\n description: competitor?.description ?? '',\n tags: competitor?.tags?.join(', ') ?? '',\n }),\n [competitor]\n );\n\n const [formOverrides, setFormOverrides] = useState<Record<string, string>>({});\n const form = { ...defaultForm, ...formOverrides };\n const setForm = (val: Record<string, string>) => setFormOverrides(val);\n\n // PRM-31 — array/object fields can't live in the plain string `form` above; same \"null override = still\n // following the loaded record\" shape, just per-field instead of merged into one object.\n const defaultStrengths = useMemo(() => competitor?.strengths ?? [], [competitor]);\n const defaultWeaknesses = useMemo(() => competitor?.weaknesses ?? [], [competitor]);\n const defaultPricingRows = useMemo(() => jsonToRows(competitor?.pricing), [competitor]);\n const defaultFeaturesRows = useMemo(() => jsonToRows(competitor?.features), [competitor]);\n const [strengthsOverride, setStrengthsOverride] = useState<string[] | null>(null);\n const [weaknessesOverride, setWeaknessesOverride] = useState<string[] | null>(null);\n const [pricingOverride, setPricingOverride] = useState<JsonKeyValueRow[] | null>(null);\n const [featuresOverride, setFeaturesOverride] = useState<JsonKeyValueRow[] | null>(null);\n const strengths = strengthsOverride ?? defaultStrengths;\n const weaknesses = weaknessesOverride ?? defaultWeaknesses;\n const pricingRows = pricingOverride ?? defaultPricingRows;\n const featuresRows = featuresOverride ?? defaultFeaturesRows;\n\n const fieldsValid =\n competitorListValid(strengths) &&\n competitorListValid(weaknesses) &&\n jsonRowsValid(pricingRows) &&\n jsonRowsValid(featuresRows);\n\n const handleSave = async () => {\n if (!competitor || !form.name.trim() || !fieldsValid) return;\n const tagList = (v: string) =>\n v\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n const next: Record<string, unknown> = {\n name: form.name.trim(),\n website: form.website.trim() || null,\n description: form.description.trim() || null,\n tags: tagList(form.tags),\n };\n const before: Record<string, unknown> = {\n name: defaultForm.name,\n website: defaultForm.website.trim() || null,\n description: defaultForm.description.trim() || null,\n tags: tagList(defaultForm.tags),\n };\n // PRM-31 — only even considered once the user actually opened that editor and changed something: a\n // pricing/features value this editor cannot fully represent (a nested object/array — see jsonToRows) round-\n // trips through its rows as a flattened string, which must never go out as an unrequested side effect of\n // saving some other, unrelated field.\n if (strengthsOverride !== null) {\n next.strengths = cleanStringList(strengths);\n before.strengths = cleanStringList(defaultStrengths);\n }\n if (weaknessesOverride !== null) {\n next.weaknesses = cleanStringList(weaknesses);\n before.weaknesses = cleanStringList(defaultWeaknesses);\n }\n if (pricingOverride !== null) {\n next.pricing = jsonRowsToObject(pricingRows);\n before.pricing = competitor.pricing ?? null;\n }\n if (featuresOverride !== null) {\n next.features = jsonRowsToObject(featuresRows);\n before.features = competitor.features ?? null;\n }\n const input = Object.fromEntries(\n Object.entries(next).filter(([k, v]) => JSON.stringify(v) !== JSON.stringify(before[k]))\n );\n setSaveError(null);\n setSaved(false);\n if (Object.keys(input).length === 0) {\n setSaved(true);\n return;\n }\n try {\n await throwOnError(updateCompetitor({ variables: { id: competitorId, input } }));\n setSaved(true);\n } catch (e) {\n setSaveError(mutationErrorMessage(e, 'The competitor could not be saved.'));\n }\n };\n\n // Only before the first load: a refetch must not blank the page (it unmounts every component on it and\n // loses their state).\n if (loading && !data) {\n return (\n <div className=\"flex items-center justify-center p-12\">\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n </div>\n );\n }\n\n if (error) {\n return <div className=\"p-6 text-destructive\">Failed to load competitor: {error.message}</div>;\n }\n\n if (!competitor) return <div className=\"p-6 text-muted-foreground\">Competitor not found.</div>;\n\n return (\n <div className=\"space-y-6 p-6 max-w-4xl\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <Button\n variant=\"ghost\"\n size=\"sm\"\n aria-label=\"Back to the competitor\"\n onClick={() => navigate(detailPath('/products/competitor-detail-page', competitorId))}\n >\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <h1 className=\"text-2xl font-semibold\">Edit Competitor</h1>\n <p className=\"text-sm text-muted-foreground\">{competitor.name}</p>\n </div>\n </div>\n <Button\n size=\"sm\"\n onClick={handleSave}\n disabled={saving || !form.name.trim() || !fieldsValid}\n >\n {saving ? (\n <Loader2 className=\"mr-1 h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"mr-1 h-4 w-4\" />\n )}\n Save Changes\n </Button>\n </div>\n\n {saved && (\n <div role=\"status\" className=\"p-3 bg-muted text-status-success-text rounded-md text-sm\">\n Changes saved.\n </div>\n )}\n {saveError && (\n <div role=\"alert\" className=\"p-3 rounded-md bg-destructive/10 text-destructive text-sm\">\n {saveError}\n </div>\n )}\n\n <Card>\n <CardHeader>\n <CardTitle>Competitor Details</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <label className=\"text-sm font-medium\">Name</label>\n <Input\n value={form.name}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Website</label>\n <Input\n value={form.website}\n onChange={(e) => setForm({ ...form, website: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Description / Notes</label>\n <textarea\n className=\"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm min-h-[80px]\"\n value={form.description}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n />\n </div>\n <div>\n <label className=\"text-sm font-medium\">Tags (comma-separated)</label>\n <Input\n value={form.tags}\n onChange={(e) => setForm({ ...form, tags: e.target.value })}\n className=\"mt-1\"\n />\n </div>\n </CardContent>\n </Card>\n\n {/* PRM-31 */}\n <Card>\n <CardHeader>\n <CardTitle>Strengths & Weaknesses</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <StringListEditor\n label=\"Strengths\"\n values={strengths}\n onChange={setStrengthsOverride}\n placeholder=\"e.g. Strong enterprise SSO\"\n testId=\"competitor-strengths\"\n />\n <StringListEditor\n label=\"Weaknesses\"\n values={weaknesses}\n onChange={setWeaknessesOverride}\n placeholder=\"e.g. No mobile app\"\n testId=\"competitor-weaknesses\"\n />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader>\n <CardTitle>Pricing & Feature Comparison</CardTitle>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <JsonKeyValueEditor\n label=\"Pricing\"\n rows={pricingRows}\n onChange={setPricingOverride}\n testId=\"competitor-pricing\"\n />\n <JsonKeyValueEditor\n label=\"Features\"\n rows={featuresRows}\n onChange={setFeaturesOverride}\n testId=\"competitor-features\"\n />\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -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"}
|