@burdenoff/microfe-planmagnet 2026.1008.3 → 2026.1009.1
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.
|
@@ -2,10 +2,10 @@ import { usePlanMagnet as e } from "../providers/PlanMagnetProvider.js";
|
|
|
2
2
|
import { useTr as t } from "../../shared/hooks/useTr.js";
|
|
3
3
|
import { isForbidden as n } from "../utils/graphqlErrors.js";
|
|
4
4
|
import { ErrorLine as r } from "../controls/ConfirmButton.js";
|
|
5
|
-
import { METRIC_TYPES as
|
|
6
|
-
import { SatisfactionFigureCards as
|
|
7
|
-
import { CUSTOMER_SATISFACTION_SUMMARY as
|
|
8
|
-
import { ProductSelect as
|
|
5
|
+
import { METRIC_TYPES as ee, pageStateFromSearch as i, windowInput as a } from "../satisfaction/satisfaction.js";
|
|
6
|
+
import { SatisfactionFigureCards as o } from "../satisfaction/SatisfactionFigures.js";
|
|
7
|
+
import { CUSTOMER_SATISFACTION_SUMMARY as s, SATISFACTION_QUERIES as c } from "../satisfaction/satisfactionOperations.js";
|
|
8
|
+
import { ProductSelect as l, ProjectSelect as te } from "../controls/Pickers.js";
|
|
9
9
|
import { writeUrlParam as u } from "../utils/urlParam.js";
|
|
10
10
|
import { SatisfactionReleaseSelect as d, useSatisfactionReleaseOptions as f } from "../satisfaction/SatisfactionReleaseSelect.js";
|
|
11
11
|
import { SatisfactionImportDialog as p } from "../satisfaction/SatisfactionImportDialog.js";
|
|
@@ -13,27 +13,40 @@ import { SatisfactionResponseDialog as m } from "../satisfaction/SatisfactionRes
|
|
|
13
13
|
import { SatisfactionResponsesTable as h } from "../satisfaction/SatisfactionResponsesTable.js";
|
|
14
14
|
import { SatisfactionWindowPicker as g } from "../satisfaction/SatisfactionWindowPicker.js";
|
|
15
15
|
import { useSatisfactionAccess as _ } from "../satisfaction/useSatisfactionAccess.js";
|
|
16
|
-
import { useEffect as v, useMemo as y,
|
|
17
|
-
import { Info as
|
|
18
|
-
import { useLocation as
|
|
19
|
-
import { useApolloClient as
|
|
20
|
-
import { Fragment as
|
|
21
|
-
import { Button as
|
|
22
|
-
import { clearGraphqlFetchResponseCache as
|
|
16
|
+
import { useEffect as v, useMemo as y, useRef as b, useState as x } from "react";
|
|
17
|
+
import { Info as S, Loader2 as C, MessageSquareHeart as ne, X as re } from "lucide-react";
|
|
18
|
+
import { useLocation as ie } from "react-router";
|
|
19
|
+
import { useApolloClient as ae, useQuery as oe } from "@apollo/client/react";
|
|
20
|
+
import { Fragment as se, jsx as w, jsxs as T } from "react/jsx-runtime";
|
|
21
|
+
import { Button as ce, Card as E, CardContent as D, CardHeader as O, CardTitle as k } from "@burdenoff/fe-libs/ui";
|
|
22
|
+
import { clearGraphqlFetchResponseCache as A } from "@burdenoff/fe-libs/shared/graphql";
|
|
23
23
|
//#region src/planmagnet/pages/ProductsCustomerSatisfactionPagePage.tsx
|
|
24
|
-
function
|
|
25
|
-
let
|
|
24
|
+
function j() {
|
|
25
|
+
let j = t(), { workspaceId: M } = e(), N = _(), P = ae(), { releases: F } = f(), I = ie(), { search: L } = I, R = b({
|
|
26
|
+
key: I.key,
|
|
27
|
+
search: L
|
|
28
|
+
}), [z, B] = x(() => i(L, /* @__PURE__ */ new Date())), [V, H] = x(() => a(z.window) ?? { preset: "LAST_90_DAYS" });
|
|
29
|
+
v(() => {
|
|
30
|
+
if (R.current.key === I.key && R.current.search === L) return;
|
|
31
|
+
R.current = {
|
|
32
|
+
key: I.key,
|
|
33
|
+
search: L
|
|
34
|
+
};
|
|
35
|
+
let e = i(L, /* @__PURE__ */ new Date());
|
|
36
|
+
B(e), H(a(e.window) ?? { preset: "LAST_90_DAYS" });
|
|
37
|
+
}, [I.key, L]);
|
|
38
|
+
let [U, W] = x(null), G = (e) => {
|
|
26
39
|
let t = {
|
|
27
40
|
...z,
|
|
28
41
|
...e
|
|
29
42
|
};
|
|
30
43
|
B(t);
|
|
31
|
-
let n =
|
|
44
|
+
let n = a(t.window);
|
|
32
45
|
n && H(n);
|
|
33
46
|
};
|
|
34
47
|
v(() => {
|
|
35
48
|
let e = V.preset;
|
|
36
|
-
u("window", e === "LAST_90_DAYS" ? null : e), u("from", e === "CUSTOM" ? V.from ?? null : null), u("to", e === "CUSTOM" ? V.to ?? null : null), u("product", z.productId || null), u("release", z.releaseId || null), u("
|
|
49
|
+
u("window", e === "LAST_90_DAYS" ? null : e), u("from", e === "CUSTOM" ? V.from ?? null : null), u("to", e === "CUSTOM" ? V.to ?? null : null), u("product", z.productId || null), u("release", z.releaseId || null), u("satisfactionProject", z.projectId || null), u("metric", z.metricType || null);
|
|
37
50
|
}, [
|
|
38
51
|
V,
|
|
39
52
|
z.productId,
|
|
@@ -61,115 +74,115 @@ function P() {
|
|
|
61
74
|
productId: z.productId,
|
|
62
75
|
releaseId: z.releaseId,
|
|
63
76
|
projectId: z.projectId
|
|
64
|
-
}, Y = !!(z.productId || z.releaseId || z.projectId), { data: X, previousData:
|
|
77
|
+
}, Y = !!(z.productId || z.releaseId || z.projectId), { data: X, previousData: le, loading: Z, error: Q } = oe(s, {
|
|
65
78
|
variables: {
|
|
66
|
-
workspaceId:
|
|
79
|
+
workspaceId: M ?? "",
|
|
67
80
|
filter: {
|
|
68
81
|
...K,
|
|
69
82
|
window: V
|
|
70
83
|
}
|
|
71
84
|
},
|
|
72
|
-
skip: !
|
|
73
|
-
}), $ = (X ??
|
|
74
|
-
|
|
85
|
+
skip: !M
|
|
86
|
+
}), $ = (X ?? le)?.planmagnetCustomerSatisfaction ?? null, ue = Z && !X && !!$, de = () => {
|
|
87
|
+
A(), P.refetchQueries({ include: c });
|
|
75
88
|
};
|
|
76
|
-
return
|
|
89
|
+
return M ? /* @__PURE__ */ T("div", {
|
|
77
90
|
className: "space-y-6 p-6",
|
|
78
91
|
"data-testid": "satisfaction-page",
|
|
79
92
|
children: [
|
|
80
|
-
/* @__PURE__ */
|
|
93
|
+
/* @__PURE__ */ T("div", {
|
|
81
94
|
className: "flex flex-wrap items-start justify-between gap-4",
|
|
82
|
-
children: [/* @__PURE__ */
|
|
95
|
+
children: [/* @__PURE__ */ T("div", {
|
|
83
96
|
className: "max-w-3xl",
|
|
84
|
-
children: [/* @__PURE__ */
|
|
97
|
+
children: [/* @__PURE__ */ T("h1", {
|
|
85
98
|
className: "flex items-center gap-2 text-2xl font-semibold",
|
|
86
|
-
children: [/* @__PURE__ */
|
|
99
|
+
children: [/* @__PURE__ */ w(ne, {
|
|
87
100
|
className: "h-6 w-6",
|
|
88
101
|
"aria-hidden": !0
|
|
89
|
-
}),
|
|
90
|
-
}), /* @__PURE__ */
|
|
102
|
+
}), j("planmagnet.satisfaction.title", "Customer satisfaction")]
|
|
103
|
+
}), /* @__PURE__ */ w("p", {
|
|
91
104
|
className: "mt-1 text-sm text-muted-foreground",
|
|
92
|
-
children:
|
|
105
|
+
children: j("planmagnet.satisfaction.subtitle", "CSAT and NPS from what customers said about your products, releases and projects. Responses are entered by your team or imported from a CSV file.")
|
|
93
106
|
})]
|
|
94
|
-
}),
|
|
107
|
+
}), N.canCreate && /* @__PURE__ */ T("div", {
|
|
95
108
|
className: "flex flex-wrap items-center gap-2",
|
|
96
|
-
children: [/* @__PURE__ */
|
|
109
|
+
children: [/* @__PURE__ */ w(p, {
|
|
97
110
|
links: J,
|
|
98
111
|
onImported: (e) => W({
|
|
99
112
|
tone: "status",
|
|
100
|
-
message:
|
|
113
|
+
message: j("planmagnet.satisfaction.notice.imported", "Import done — new responses: {{created}}; already imported and skipped: {{skipped}}.", {
|
|
101
114
|
created: e.createdCount,
|
|
102
115
|
skipped: e.skippedCount
|
|
103
116
|
})
|
|
104
117
|
})
|
|
105
|
-
}), /* @__PURE__ */
|
|
118
|
+
}), /* @__PURE__ */ w(m, {
|
|
106
119
|
links: J,
|
|
107
120
|
onSaved: () => W({
|
|
108
121
|
tone: "status",
|
|
109
|
-
message:
|
|
122
|
+
message: j("planmagnet.satisfaction.notice.created", "The response was added.")
|
|
110
123
|
})
|
|
111
124
|
})]
|
|
112
125
|
})]
|
|
113
126
|
}),
|
|
114
|
-
|
|
127
|
+
N.readOnly && /* @__PURE__ */ T("p", {
|
|
115
128
|
className: "flex items-center gap-1.5 text-xs text-muted-foreground",
|
|
116
129
|
"data-testid": "satisfaction-read-only",
|
|
117
|
-
children: [/* @__PURE__ */
|
|
130
|
+
children: [/* @__PURE__ */ w(S, {
|
|
118
131
|
className: "h-3.5 w-3.5 shrink-0",
|
|
119
132
|
"aria-hidden": !0
|
|
120
|
-
}),
|
|
133
|
+
}), j("planmagnet.satisfaction.readOnly", "You can read customer satisfaction. Adding, importing, editing and deleting responses is for product managers.")]
|
|
121
134
|
}),
|
|
122
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ T("div", {
|
|
123
136
|
className: "space-y-3 rounded-lg border p-3",
|
|
124
137
|
"data-testid": "satisfaction-filters",
|
|
125
|
-
children: [/* @__PURE__ */
|
|
138
|
+
children: [/* @__PURE__ */ w(g, {
|
|
126
139
|
value: z.window,
|
|
127
140
|
onChange: (e) => G({ window: e }),
|
|
128
141
|
current: $?.window ?? null
|
|
129
|
-
}), /* @__PURE__ */
|
|
142
|
+
}), /* @__PURE__ */ T("div", {
|
|
130
143
|
className: "flex flex-col gap-2 sm:flex-row sm:items-center",
|
|
131
|
-
children: [/* @__PURE__ */
|
|
144
|
+
children: [/* @__PURE__ */ T("div", {
|
|
132
145
|
className: "grid flex-1 gap-2 sm:grid-cols-3",
|
|
133
146
|
children: [
|
|
134
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("label", {
|
|
135
148
|
htmlFor: "satisfaction-filter-product",
|
|
136
149
|
className: "sr-only",
|
|
137
|
-
children:
|
|
138
|
-
}), /* @__PURE__ */
|
|
150
|
+
children: j("planmagnet.satisfaction.filters.product", "Product")
|
|
151
|
+
}), /* @__PURE__ */ w(l, {
|
|
139
152
|
id: "satisfaction-filter-product",
|
|
140
153
|
value: z.productId,
|
|
141
|
-
noneLabel:
|
|
154
|
+
noneLabel: j("planmagnet.satisfaction.filters.allProducts", "All products"),
|
|
142
155
|
onChange: (e) => {
|
|
143
|
-
let t =
|
|
156
|
+
let t = F.find((e) => e.id === z.releaseId);
|
|
144
157
|
G({
|
|
145
158
|
productId: e,
|
|
146
159
|
releaseId: !t || !t.productId || !e || t.productId === e ? z.releaseId : ""
|
|
147
160
|
});
|
|
148
161
|
}
|
|
149
162
|
})] }),
|
|
150
|
-
/* @__PURE__ */
|
|
163
|
+
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("label", {
|
|
151
164
|
htmlFor: "satisfaction-filter-release",
|
|
152
165
|
className: "sr-only",
|
|
153
|
-
children:
|
|
154
|
-
}), /* @__PURE__ */
|
|
166
|
+
children: j("planmagnet.satisfaction.filters.release", "Release")
|
|
167
|
+
}), /* @__PURE__ */ w(d, {
|
|
155
168
|
id: "satisfaction-filter-release",
|
|
156
169
|
value: z.releaseId,
|
|
157
170
|
productId: z.productId,
|
|
158
|
-
noneLabel:
|
|
171
|
+
noneLabel: j("planmagnet.satisfaction.filters.allReleases", "All releases"),
|
|
159
172
|
onChange: (e) => G({ releaseId: e })
|
|
160
173
|
})] }),
|
|
161
|
-
/* @__PURE__ */
|
|
174
|
+
/* @__PURE__ */ T("div", { children: [/* @__PURE__ */ w("label", {
|
|
162
175
|
htmlFor: "satisfaction-filter-project",
|
|
163
176
|
className: "sr-only",
|
|
164
|
-
children:
|
|
165
|
-
}), /* @__PURE__ */
|
|
177
|
+
children: j("planmagnet.satisfaction.filters.project", "Project")
|
|
178
|
+
}), /* @__PURE__ */ w(te, {
|
|
166
179
|
id: "satisfaction-filter-project",
|
|
167
180
|
value: z.projectId,
|
|
168
|
-
noneLabel:
|
|
181
|
+
noneLabel: j("planmagnet.satisfaction.filters.allProjects", "All projects"),
|
|
169
182
|
onChange: (e) => G({ projectId: e })
|
|
170
183
|
})] })
|
|
171
184
|
]
|
|
172
|
-
}), Y && /* @__PURE__ */
|
|
185
|
+
}), Y && /* @__PURE__ */ T(ce, {
|
|
173
186
|
size: "sm",
|
|
174
187
|
variant: "ghost",
|
|
175
188
|
onClick: () => G({
|
|
@@ -178,72 +191,72 @@ function P() {
|
|
|
178
191
|
projectId: ""
|
|
179
192
|
}),
|
|
180
193
|
"data-testid": "satisfaction-filters-clear",
|
|
181
|
-
children: [/* @__PURE__ */
|
|
194
|
+
children: [/* @__PURE__ */ w(re, { className: "mr-1 h-4 w-4" }), j("planmagnet.satisfaction.filters.clear", "Clear filters")]
|
|
182
195
|
})]
|
|
183
196
|
})]
|
|
184
197
|
}),
|
|
185
|
-
z.productId && /* @__PURE__ */
|
|
198
|
+
z.productId && /* @__PURE__ */ w("p", {
|
|
186
199
|
className: "-mt-3 text-xs text-muted-foreground",
|
|
187
|
-
children:
|
|
200
|
+
children: j("planmagnet.satisfaction.filters.productNote", "A product counts its own responses and those about its releases that name no product of their own.")
|
|
188
201
|
}),
|
|
189
|
-
U && /* @__PURE__ */
|
|
202
|
+
U && /* @__PURE__ */ T("div", {
|
|
190
203
|
role: U.tone,
|
|
191
204
|
className: `flex items-start justify-between gap-3 rounded-md p-3 text-sm ${U.tone === "alert" ? "bg-status-error-bg-subtle text-status-error-text" : "bg-muted"}`,
|
|
192
205
|
"data-testid": "satisfaction-notice",
|
|
193
|
-
children: [/* @__PURE__ */
|
|
206
|
+
children: [/* @__PURE__ */ w("span", { children: U.message }), /* @__PURE__ */ w("button", {
|
|
194
207
|
type: "button",
|
|
195
208
|
className: "shrink-0 text-xs text-muted-foreground hover:underline",
|
|
196
209
|
onClick: () => W(null),
|
|
197
|
-
children:
|
|
210
|
+
children: j("planmagnet.satisfaction.dismiss", "Dismiss")
|
|
198
211
|
})]
|
|
199
212
|
}),
|
|
200
|
-
Z && !$ ? /* @__PURE__ */
|
|
213
|
+
Z && !$ ? /* @__PURE__ */ T("div", {
|
|
201
214
|
className: "flex items-center gap-2 text-sm text-muted-foreground",
|
|
202
|
-
children: [/* @__PURE__ */
|
|
203
|
-
}) : Q && !$ ? /* @__PURE__ */
|
|
204
|
-
Q && /* @__PURE__ */
|
|
205
|
-
|
|
215
|
+
children: [/* @__PURE__ */ w(C, { className: "h-4 w-4 animate-spin" }), j("planmagnet.satisfaction.loading", "Loading…")]
|
|
216
|
+
}) : Q && !$ ? /* @__PURE__ */ w(r, { message: n(Q) ? j("planmagnet.satisfaction.errors.readForbidden", "Your role cannot see customer satisfaction in this workspace.") : j("planmagnet.satisfaction.errors.load", "Customer satisfaction could not be loaded: {{message}}", { message: Q.message }) }) : $ ? /* @__PURE__ */ T(se, { children: [
|
|
217
|
+
Q && /* @__PURE__ */ w(r, { message: j("planmagnet.satisfaction.errors.refresh", "The figures could not be refreshed: {{message}}", { message: Q.message }) }),
|
|
218
|
+
ue && /* @__PURE__ */ T("p", {
|
|
206
219
|
className: "flex items-center gap-2 text-xs text-muted-foreground",
|
|
207
220
|
role: "status",
|
|
208
|
-
children: [/* @__PURE__ */
|
|
221
|
+
children: [/* @__PURE__ */ w(C, {
|
|
209
222
|
className: "h-3.5 w-3.5 animate-spin",
|
|
210
223
|
"aria-hidden": !0
|
|
211
|
-
}),
|
|
224
|
+
}), j("planmagnet.satisfaction.updating", "Updating the figures…")]
|
|
212
225
|
}),
|
|
213
|
-
/* @__PURE__ */
|
|
226
|
+
/* @__PURE__ */ w(o, { summary: $ })
|
|
214
227
|
] }) : null,
|
|
215
|
-
/* @__PURE__ */
|
|
228
|
+
/* @__PURE__ */ T(E, { children: [/* @__PURE__ */ T(O, {
|
|
216
229
|
className: "flex flex-row flex-wrap items-center justify-between gap-2 space-y-0",
|
|
217
|
-
children: [/* @__PURE__ */
|
|
230
|
+
children: [/* @__PURE__ */ w(k, { children: j("planmagnet.satisfaction.list.title", "Responses") }), /* @__PURE__ */ w("div", {
|
|
218
231
|
className: "flex items-center gap-1 rounded-md border p-0.5",
|
|
219
232
|
role: "group",
|
|
220
|
-
"aria-label":
|
|
221
|
-
children: ["", ...
|
|
233
|
+
"aria-label": j("planmagnet.satisfaction.list.metricFilter", "Metric"),
|
|
234
|
+
children: ["", ...ee].map((e) => /* @__PURE__ */ w("button", {
|
|
222
235
|
type: "button",
|
|
223
236
|
"aria-pressed": z.metricType === e,
|
|
224
237
|
onClick: () => G({ metricType: e }),
|
|
225
238
|
"data-testid": `satisfaction-metric-${e || "ALL"}`,
|
|
226
239
|
className: `rounded px-2.5 py-1 text-xs ${z.metricType === e ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"}`,
|
|
227
|
-
children: e ||
|
|
240
|
+
children: e || j("planmagnet.satisfaction.list.allMetrics", "All")
|
|
228
241
|
}, e || "all"))
|
|
229
242
|
})]
|
|
230
|
-
}), /* @__PURE__ */
|
|
231
|
-
workspaceId:
|
|
243
|
+
}), /* @__PURE__ */ w(D, { children: /* @__PURE__ */ w(h, {
|
|
244
|
+
workspaceId: M,
|
|
232
245
|
filter: q,
|
|
233
|
-
access:
|
|
246
|
+
access: N,
|
|
234
247
|
links: J,
|
|
235
248
|
filtered: Y || !!z.metricType,
|
|
236
249
|
onNotice: (e, t) => W({
|
|
237
250
|
message: e,
|
|
238
251
|
tone: t
|
|
239
252
|
}),
|
|
240
|
-
onStale:
|
|
253
|
+
onStale: de
|
|
241
254
|
}, JSON.stringify(q)) })] })
|
|
242
255
|
]
|
|
243
|
-
}) : /* @__PURE__ */
|
|
256
|
+
}) : /* @__PURE__ */ w("div", {
|
|
244
257
|
className: "p-6 text-sm text-muted-foreground",
|
|
245
|
-
children:
|
|
258
|
+
children: j("planmagnet.satisfaction.noWorkspace", "Choose a workspace to see customer satisfaction.")
|
|
246
259
|
});
|
|
247
260
|
}
|
|
248
261
|
//#endregion
|
|
249
|
-
export {
|
|
262
|
+
export { j as ProductsCustomerSatisfactionPagePage };
|
|
@@ -36,7 +36,7 @@ function f({ workspaceId: f, projectId: p, startDate: m, endDate: h }) {
|
|
|
36
36
|
preset: "CUSTOM",
|
|
37
37
|
from: S,
|
|
38
38
|
to: C
|
|
39
|
-
} : void 0)),
|
|
39
|
+
} : void 0, p)),
|
|
40
40
|
"data-testid": "delivery-satisfaction-open",
|
|
41
41
|
children: [g("planmagnet.analytics.delivery.satisfactionOpen", "Responses"), /* @__PURE__ */ l(s, { className: "ml-1 h-3.5 w-3.5" })]
|
|
42
42
|
})]
|
|
@@ -121,10 +121,16 @@ export interface SatisfactionPageState {
|
|
|
121
121
|
/** '' = both metrics (the responses list only; the figures always show both). */
|
|
122
122
|
metricType: SatisfactionMetricType | '';
|
|
123
123
|
}
|
|
124
|
-
/** The Customer satisfaction page for a scope (and a window other than the default), as a navigate() path. */
|
|
125
|
-
export declare function satisfactionPageLink(scope: SatisfactionScope, window?: WindowChoice): string;
|
|
126
124
|
/**
|
|
127
|
-
* The page
|
|
125
|
+
* The Customer satisfaction page for a scope (and a window other than the default), as a navigate() path.
|
|
126
|
+
* `hostProjectId` keeps the host's active project (`?project=`) on a drill-down that starts inside a project-scoped view:
|
|
127
|
+
* navigate() hands the shell the whole path, so a link without it would reset that context. It is context only, never a
|
|
128
|
+
* satisfaction filter (see pageStateFromSearch).
|
|
129
|
+
*/
|
|
130
|
+
export declare function satisfactionPageLink(scope: SatisfactionScope, window?: WindowChoice, hostProjectId?: string): string;
|
|
131
|
+
/**
|
|
132
|
+
* The page state a URL query asks for (`?window=&from=&to=&product=&release=&satisfactionProject=&metric=`).
|
|
133
|
+
* `project` belongs to the host's active context; it must never silently filter this page. Anything unreadable
|
|
128
134
|
* falls back to the default — the trailing 90 days, every product, release and project, both metrics.
|
|
129
135
|
*/
|
|
130
136
|
export declare function pageStateFromSearch(search: string, now: Date): SatisfactionPageState;
|
|
@@ -105,11 +105,11 @@ function j(e, t) {
|
|
|
105
105
|
to: n
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
|
-
function M(e, t) {
|
|
109
|
-
let
|
|
110
|
-
t && t.preset !== "LAST_90_DAYS" && (
|
|
111
|
-
let
|
|
112
|
-
return `/${n}${
|
|
108
|
+
function M(e, t, r) {
|
|
109
|
+
let i = new URLSearchParams();
|
|
110
|
+
t && t.preset !== "LAST_90_DAYS" && (i.set("window", t.preset), t.preset === "CUSTOM" && (i.set("from", t.from), i.set("to", t.to))), e.productId && i.set("product", e.productId), e.releaseId && i.set("release", e.releaseId), r && i.set("project", r), e.projectId && i.set("satisfactionProject", e.projectId);
|
|
111
|
+
let a = i.toString();
|
|
112
|
+
return `/${n}${a ? `?${a}` : ""}`;
|
|
113
113
|
}
|
|
114
114
|
function N(e, t) {
|
|
115
115
|
let n = new URLSearchParams(e), r = n.get("window"), i = n.get("from") ?? "", o = n.get("to") ?? "", s;
|
|
@@ -134,7 +134,7 @@ function N(e, t) {
|
|
|
134
134
|
window: s,
|
|
135
135
|
productId: n.get("product") ?? "",
|
|
136
136
|
releaseId: n.get("release") ?? "",
|
|
137
|
-
projectId: n.get("
|
|
137
|
+
projectId: n.get("satisfactionProject") ?? "",
|
|
138
138
|
metricType: a(c) ? c : ""
|
|
139
139
|
};
|
|
140
140
|
}
|