@mhosaic/feedback 0.32.0 → 0.34.0
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/{chunk-YNDBZR37.mjs → chunk-J45ACCSP.mjs} +522 -362
- package/dist/chunk-J45ACCSP.mjs.map +1 -0
- package/dist/{chunk-IP4Y5EZE.mjs → chunk-WROPP3IB.mjs} +17 -1
- package/dist/chunk-WROPP3IB.mjs.map +1 -0
- package/dist/embed.min.js +21 -5
- package/dist/embed.min.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/loader/react.mjs +1 -1
- package/dist/loader.min.js +1 -1
- package/dist/loader.min.js.map +1 -1
- package/dist/loader.mjs +1 -1
- package/dist/react.mjs +1 -1
- package/dist/vue.d.ts +29 -0
- package/dist/vue.mjs +44 -0
- package/dist/vue.mjs.map +1 -0
- package/dist/widget.min.js +22 -6
- package/dist/widget.min.js.map +1 -1
- package/package.json +16 -7
- package/dist/chunk-IP4Y5EZE.mjs.map +0 -1
- package/dist/chunk-YNDBZR37.mjs.map +0 -1
|
@@ -145,6 +145,32 @@ function createApiClient(options) {
|
|
|
145
145
|
if (response.status === 404) return [];
|
|
146
146
|
return readJsonArray(response, "listMine");
|
|
147
147
|
}
|
|
148
|
+
async function diagnose(opts) {
|
|
149
|
+
const onLine = opts?.onLine ?? (typeof navigator !== "undefined" ? navigator.onLine : true);
|
|
150
|
+
if (onLine === false) return "offline";
|
|
151
|
+
const probeUrl = `${endpoint}/api/feedback/v1/widget-manifest/?pk=${encodeURIComponent(options.apiKey)}`;
|
|
152
|
+
let simple;
|
|
153
|
+
try {
|
|
154
|
+
simple = await fetcher(probeUrl, { method: "GET", redirect: "manual" });
|
|
155
|
+
} catch {
|
|
156
|
+
return "blocked";
|
|
157
|
+
}
|
|
158
|
+
if (simple.type === "opaqueredirect" || simple.status >= 300 && simple.status < 400) {
|
|
159
|
+
return "intercepted";
|
|
160
|
+
}
|
|
161
|
+
let authed;
|
|
162
|
+
try {
|
|
163
|
+
authed = await fetcher(probeUrl, {
|
|
164
|
+
method: "GET",
|
|
165
|
+
headers: { Authorization: `Bearer ${options.apiKey}` }
|
|
166
|
+
});
|
|
167
|
+
} catch {
|
|
168
|
+
return "preflight";
|
|
169
|
+
}
|
|
170
|
+
if (authed.status === 401 || authed.status === 403) return "key";
|
|
171
|
+
if (authed.status === 429) return "throttle";
|
|
172
|
+
return "healthy";
|
|
173
|
+
}
|
|
148
174
|
async function listChangelog(externalId) {
|
|
149
175
|
const response = await fetcher(
|
|
150
176
|
`${endpoint}/api/feedback/v1/reports/widget/changelog/`,
|
|
@@ -330,6 +356,14 @@ function createApiClient(options) {
|
|
|
330
356
|
checkVisibility,
|
|
331
357
|
listMine,
|
|
332
358
|
listChangelog,
|
|
359
|
+
diagnose,
|
|
360
|
+
endpointHost: (() => {
|
|
361
|
+
try {
|
|
362
|
+
return new URL(endpoint).host;
|
|
363
|
+
} catch {
|
|
364
|
+
return endpoint;
|
|
365
|
+
}
|
|
366
|
+
})(),
|
|
333
367
|
getReport,
|
|
334
368
|
getReportBySeq,
|
|
335
369
|
addComment,
|
|
@@ -739,6 +773,19 @@ var DEFAULT_STRINGS = {
|
|
|
739
773
|
"mine.empty.title": "No reports yet",
|
|
740
774
|
"mine.empty.body": "Once you send feedback you can follow the thread here.",
|
|
741
775
|
"mine.refresh": "Refresh",
|
|
776
|
+
"mine.validate.banner": "{count} fix(es) awaiting your confirmation",
|
|
777
|
+
"mine.validate.confirm": "Fix works",
|
|
778
|
+
"mine.validate.reopen": "Still broken",
|
|
779
|
+
"mine.validate.view": "Review",
|
|
780
|
+
"diag.run": "Diagnose",
|
|
781
|
+
"diag.running": "Checking the connection\u2026",
|
|
782
|
+
"diag.offline": "You appear to be offline. Reconnect and retry.",
|
|
783
|
+
"diag.blocked": "The feedback service is unreachable from this network. A firewall or proxy is blocking it \u2014 ask IT to allow {host}.",
|
|
784
|
+
"diag.intercepted": "Your corporate network (SSL-inspection proxy) is intercepting widget traffic. Ask IT to add {host} to the inspection bypass list.",
|
|
785
|
+
"diag.preflight": "A network proxy is blocking the widget\u2019s secure requests (CORS preflight). Ask IT to allow {host}.",
|
|
786
|
+
"diag.key": "The widget\u2019s access key was rejected. Contact the site team.",
|
|
787
|
+
"diag.throttle": "Too many requests right now \u2014 wait a moment and retry.",
|
|
788
|
+
"diag.healthy": "The service is reachable \u2014 this looks like a temporary hiccup. Retry.",
|
|
742
789
|
"mine.loading": "Loading\u2026",
|
|
743
790
|
"mine.error": "Could not load your reports.",
|
|
744
791
|
"mine.jump.placeholder": "#",
|
|
@@ -926,6 +973,19 @@ var FRENCH_STRINGS = {
|
|
|
926
973
|
"mine.empty.title": "Aucun rapport",
|
|
927
974
|
"mine.empty.body": "Apr\xE8s votre premier envoi vous pourrez suivre la conversation ici.",
|
|
928
975
|
"mine.refresh": "Actualiser",
|
|
976
|
+
"mine.validate.banner": "{count} correctif(s) \xE0 confirmer",
|
|
977
|
+
"mine.validate.confirm": "Corrig\xE9 \u2713",
|
|
978
|
+
"mine.validate.reopen": "Toujours cass\xE9",
|
|
979
|
+
"mine.validate.view": "Voir",
|
|
980
|
+
"diag.run": "Diagnostiquer",
|
|
981
|
+
"diag.running": "V\xE9rification de la connexion\u2026",
|
|
982
|
+
"diag.offline": "Vous semblez hors ligne. Reconnectez-vous puis r\xE9essayez.",
|
|
983
|
+
"diag.blocked": "Le service de feedback est injoignable depuis ce r\xE9seau. Un pare-feu ou proxy le bloque \u2014 demandez \xE0 votre TI d\u2019autoriser {host}.",
|
|
984
|
+
"diag.intercepted": "Votre r\xE9seau d\u2019entreprise (inspection SSL) intercepte le trafic du widget. Demandez \xE0 votre TI d\u2019ajouter {host} \xE0 la liste d\u2019exclusion.",
|
|
985
|
+
"diag.preflight": "Un proxy r\xE9seau bloque les requ\xEAtes s\xE9curis\xE9es du widget (pr\xE9flight CORS). Demandez \xE0 votre TI d\u2019autoriser {host}.",
|
|
986
|
+
"diag.key": "La cl\xE9 d\u2019acc\xE8s du widget a \xE9t\xE9 refus\xE9e. Contactez l\u2019\xE9quipe du site.",
|
|
987
|
+
"diag.throttle": "Trop de requ\xEAtes pour le moment \u2014 patientez puis r\xE9essayez.",
|
|
988
|
+
"diag.healthy": "Le service est joignable \u2014 le probl\xE8me semble passager. R\xE9essayez.",
|
|
929
989
|
"mine.loading": "Chargement\u2026",
|
|
930
990
|
"mine.error": "Impossible de charger vos rapports.",
|
|
931
991
|
"mine.jump.placeholder": "#",
|
|
@@ -1017,7 +1077,7 @@ function resolveStrings(overrides, options = {}) {
|
|
|
1017
1077
|
|
|
1018
1078
|
// src/widget/mount.tsx
|
|
1019
1079
|
import { h, render } from "preact";
|
|
1020
|
-
import { useCallback as useCallback2, useEffect as useEffect10, useRef as useRef7, useState as
|
|
1080
|
+
import { useCallback as useCallback2, useEffect as useEffect10, useRef as useRef7, useState as useState10 } from "preact/hooks";
|
|
1021
1081
|
|
|
1022
1082
|
// src/widget/currentPage.ts
|
|
1023
1083
|
function currentPagePath(opts) {
|
|
@@ -1050,7 +1110,30 @@ function onLocationChange(cb) {
|
|
|
1050
1110
|
}
|
|
1051
1111
|
|
|
1052
1112
|
// src/widget/BoardView.tsx
|
|
1053
|
-
import { useEffect as useEffect2, useMemo, useState as
|
|
1113
|
+
import { useEffect as useEffect2, useMemo, useState as useState3 } from "preact/hooks";
|
|
1114
|
+
|
|
1115
|
+
// src/widget/DiagnosticHint.tsx
|
|
1116
|
+
import { useState } from "preact/hooks";
|
|
1117
|
+
import { jsx } from "preact/jsx-runtime";
|
|
1118
|
+
function DiagnosticHint({ api, strings, host }) {
|
|
1119
|
+
const [state, setState] = useState("idle");
|
|
1120
|
+
const run = async () => {
|
|
1121
|
+
setState("running");
|
|
1122
|
+
try {
|
|
1123
|
+
setState(await api.diagnose());
|
|
1124
|
+
} catch {
|
|
1125
|
+
setState("blocked");
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
if (state === "idle") {
|
|
1129
|
+
return /* @__PURE__ */ jsx("button", { type: "button", class: "btn diag-btn", onClick: () => void run(), children: strings["diag.run"] });
|
|
1130
|
+
}
|
|
1131
|
+
if (state === "running") {
|
|
1132
|
+
return /* @__PURE__ */ jsx("div", { class: "diag-result", children: strings["diag.running"] });
|
|
1133
|
+
}
|
|
1134
|
+
const key = `diag.${state}`;
|
|
1135
|
+
return /* @__PURE__ */ jsx("div", { class: "diag-result", children: (strings[key] ?? state).replace("{host}", host) });
|
|
1136
|
+
}
|
|
1054
1137
|
|
|
1055
1138
|
// src/widget/boardCache.ts
|
|
1056
1139
|
var TTL_MS = 6e4;
|
|
@@ -1142,7 +1225,7 @@ function rateLimitMessage(err, strings) {
|
|
|
1142
1225
|
}
|
|
1143
1226
|
|
|
1144
1227
|
// src/widget/ReportDetailView.tsx
|
|
1145
|
-
import { useEffect, useRef, useState } from "preact/hooks";
|
|
1228
|
+
import { useEffect, useRef, useState as useState2 } from "preact/hooks";
|
|
1146
1229
|
|
|
1147
1230
|
// src/widget/linkifySeq.tsx
|
|
1148
1231
|
import { jsxs } from "preact/jsx-runtime";
|
|
@@ -1179,7 +1262,7 @@ function linkifySeq(text, onOpenSeq) {
|
|
|
1179
1262
|
}
|
|
1180
1263
|
|
|
1181
1264
|
// src/widget/CommentBubble.tsx
|
|
1182
|
-
import { jsx, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
1265
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "preact/jsx-runtime";
|
|
1183
1266
|
function CommentBubble({ comment, strings, onOpenSeq, stableUrl }) {
|
|
1184
1267
|
const isMine = comment.is_mine;
|
|
1185
1268
|
const isAgent = !isMine && comment.author_source === "mcp";
|
|
@@ -1189,23 +1272,23 @@ function CommentBubble({ comment, strings, onOpenSeq, stableUrl }) {
|
|
|
1189
1272
|
const label = comment.author_label || strings[labelKey];
|
|
1190
1273
|
const images = (comment.attachments ?? []).filter((a) => a.url);
|
|
1191
1274
|
return /* @__PURE__ */ jsxs2("div", { class: `comment-bubble ${isMine ? "is-mine" : "is-other"}`, children: [
|
|
1192
|
-
!isMine && label && /* @__PURE__ */
|
|
1193
|
-
comment.body && /* @__PURE__ */
|
|
1194
|
-
images.length > 0 && /* @__PURE__ */
|
|
1275
|
+
!isMine && label && /* @__PURE__ */ jsx2("div", { class: `comment-author comment-author--${variant}`, children: label }),
|
|
1276
|
+
comment.body && /* @__PURE__ */ jsx2("div", { class: "comment-body", children: linkifySeq(comment.body, onOpenSeq) }),
|
|
1277
|
+
images.length > 0 && /* @__PURE__ */ jsx2("div", { class: "comment-attachments", children: images.map((a) => {
|
|
1195
1278
|
const src = stableUrl ? stableUrl(`att:${a.id}`, a.url) : a.url;
|
|
1196
|
-
return /* @__PURE__ */
|
|
1279
|
+
return /* @__PURE__ */ jsx2(
|
|
1197
1280
|
"a",
|
|
1198
1281
|
{
|
|
1199
1282
|
class: "comment-attachment",
|
|
1200
1283
|
href: src,
|
|
1201
1284
|
target: "_blank",
|
|
1202
1285
|
rel: "noopener noreferrer",
|
|
1203
|
-
children: /* @__PURE__ */
|
|
1286
|
+
children: /* @__PURE__ */ jsx2("img", { src, alt: strings["detail.attachment_alt"], loading: "lazy" })
|
|
1204
1287
|
},
|
|
1205
1288
|
a.id
|
|
1206
1289
|
);
|
|
1207
1290
|
}) }),
|
|
1208
|
-
/* @__PURE__ */
|
|
1291
|
+
/* @__PURE__ */ jsx2("div", { class: "comment-time", children: formatTime(comment.created_at) })
|
|
1209
1292
|
] });
|
|
1210
1293
|
}
|
|
1211
1294
|
function formatTime(iso) {
|
|
@@ -1260,7 +1343,7 @@ function safeExternalHref(url) {
|
|
|
1260
1343
|
}
|
|
1261
1344
|
|
|
1262
1345
|
// src/widget/ReportDetailView.tsx
|
|
1263
|
-
import { Fragment, jsx as
|
|
1346
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "preact/jsx-runtime";
|
|
1264
1347
|
var POLL_MS = 3e4;
|
|
1265
1348
|
function ReportDetailView({
|
|
1266
1349
|
api,
|
|
@@ -1274,23 +1357,23 @@ function ReportDetailView({
|
|
|
1274
1357
|
buildPermalink,
|
|
1275
1358
|
seed
|
|
1276
1359
|
}) {
|
|
1277
|
-
const [detail, setDetail] =
|
|
1278
|
-
const [error, setError] =
|
|
1279
|
-
const [copied, setCopied] =
|
|
1280
|
-
const [editing, setEditing] =
|
|
1281
|
-
const [editBody, setEditBody] =
|
|
1282
|
-
const [savingEdit, setSavingEdit] =
|
|
1283
|
-
const [editError, setEditError] =
|
|
1284
|
-
const [composeBody, setComposeBody] =
|
|
1285
|
-
const [sending, setSending] =
|
|
1286
|
-
const [closing, setClosing] =
|
|
1287
|
-
const [reopening, setReopening] =
|
|
1288
|
-
const [composeShots, setComposeShots] =
|
|
1289
|
-
const [attachError, setAttachError] =
|
|
1360
|
+
const [detail, setDetail] = useState2(null);
|
|
1361
|
+
const [error, setError] = useState2(null);
|
|
1362
|
+
const [copied, setCopied] = useState2(false);
|
|
1363
|
+
const [editing, setEditing] = useState2(false);
|
|
1364
|
+
const [editBody, setEditBody] = useState2("");
|
|
1365
|
+
const [savingEdit, setSavingEdit] = useState2(false);
|
|
1366
|
+
const [editError, setEditError] = useState2(false);
|
|
1367
|
+
const [composeBody, setComposeBody] = useState2("");
|
|
1368
|
+
const [sending, setSending] = useState2(false);
|
|
1369
|
+
const [closing, setClosing] = useState2(false);
|
|
1370
|
+
const [reopening, setReopening] = useState2(false);
|
|
1371
|
+
const [composeShots, setComposeShots] = useState2([]);
|
|
1372
|
+
const [attachError, setAttachError] = useState2("");
|
|
1290
1373
|
const fileInputRef = useRef(null);
|
|
1291
1374
|
const mountedRef = useRef(true);
|
|
1292
1375
|
const urlPins = useRef(/* @__PURE__ */ new Map());
|
|
1293
|
-
const [, bumpPinTick] =
|
|
1376
|
+
const [, bumpPinTick] = useState2(0);
|
|
1294
1377
|
const PIN_MAX_AGE_MS = 45 * 6e4;
|
|
1295
1378
|
const pinUrl = (key, url) => {
|
|
1296
1379
|
if (!url) return url;
|
|
@@ -1474,7 +1557,7 @@ function ReportDetailView({
|
|
|
1474
1557
|
};
|
|
1475
1558
|
if (!detail && !error) {
|
|
1476
1559
|
if (seed) {
|
|
1477
|
-
const seedPill = /* @__PURE__ */
|
|
1560
|
+
const seedPill = /* @__PURE__ */ jsx3("span", { class: `pill pill-status pill-status--${seed.status}`, children: strings[`status.${seed.status}`] ?? seed.status });
|
|
1478
1561
|
return /* @__PURE__ */ jsxs3("div", { class: `report-detail variant-${variant} is-seeded`, children: [
|
|
1479
1562
|
variant === "modal" && /* @__PURE__ */ jsxs3("div", { class: "report-detail-header", children: [
|
|
1480
1563
|
/* @__PURE__ */ jsxs3("button", { type: "button", class: "btn", onClick: onBack, children: [
|
|
@@ -1500,19 +1583,19 @@ function ReportDetailView({
|
|
|
1500
1583
|
seedPill
|
|
1501
1584
|
] }),
|
|
1502
1585
|
/* @__PURE__ */ jsxs3("div", { class: "report-detail-body", children: [
|
|
1503
|
-
/* @__PURE__ */
|
|
1504
|
-
/* @__PURE__ */
|
|
1505
|
-
/* @__PURE__ */
|
|
1586
|
+
/* @__PURE__ */ jsx3("div", { class: "report-detail-description-row", children: /* @__PURE__ */ jsx3("p", { class: "report-detail-description", children: linkifySeq(seed.description, onOpenSeq) }) }),
|
|
1587
|
+
/* @__PURE__ */ jsx3("h3", { class: "report-detail-section", children: strings["detail.thread"] }),
|
|
1588
|
+
/* @__PURE__ */ jsx3("div", { class: "mine-loading", children: strings["mine.loading"] })
|
|
1506
1589
|
] })
|
|
1507
1590
|
] });
|
|
1508
1591
|
}
|
|
1509
|
-
return /* @__PURE__ */
|
|
1592
|
+
return /* @__PURE__ */ jsx3("div", { class: "mine-loading", children: strings["mine.loading"] });
|
|
1510
1593
|
}
|
|
1511
1594
|
if (!detail) {
|
|
1512
1595
|
if (error && error !== "load_failed") {
|
|
1513
1596
|
return /* @__PURE__ */ jsxs3("div", { class: "report-detail-empty-state", role: "alert", children: [
|
|
1514
|
-
/* @__PURE__ */
|
|
1515
|
-
/* @__PURE__ */
|
|
1597
|
+
/* @__PURE__ */ jsx3("p", { class: "report-detail-empty-state-body", children: error }),
|
|
1598
|
+
/* @__PURE__ */ jsx3("button", { type: "button", class: "btn", onClick: () => void fetchDetail(), children: strings["board.retry"] }),
|
|
1516
1599
|
/* @__PURE__ */ jsxs3("button", { type: "button", class: "btn", onClick: onBack, children: [
|
|
1517
1600
|
"\u2190 ",
|
|
1518
1601
|
strings["detail.load_failed.cta"]
|
|
@@ -1520,8 +1603,8 @@ function ReportDetailView({
|
|
|
1520
1603
|
] });
|
|
1521
1604
|
}
|
|
1522
1605
|
return /* @__PURE__ */ jsxs3("div", { class: "report-detail-empty-state", role: "alert", children: [
|
|
1523
|
-
/* @__PURE__ */
|
|
1524
|
-
/* @__PURE__ */
|
|
1606
|
+
/* @__PURE__ */ jsx3("p", { class: "report-detail-empty-state-title", children: strings["detail.load_failed.title"] }),
|
|
1607
|
+
/* @__PURE__ */ jsx3("p", { class: "report-detail-empty-state-body", children: strings["detail.load_failed.body"] }),
|
|
1525
1608
|
/* @__PURE__ */ jsxs3("button", { type: "button", class: "btn", onClick: onBack, children: [
|
|
1526
1609
|
"\u2190 ",
|
|
1527
1610
|
strings["detail.load_failed.cta"]
|
|
@@ -1538,7 +1621,7 @@ function ReportDetailView({
|
|
|
1538
1621
|
"\u2190 ",
|
|
1539
1622
|
strings["detail.back"]
|
|
1540
1623
|
] }),
|
|
1541
|
-
/* @__PURE__ */
|
|
1624
|
+
/* @__PURE__ */ jsx3("span", { class: `pill pill-status pill-status--${detail.status}`, children: strings[`status.${detail.status}`] ?? detail.status })
|
|
1542
1625
|
] }),
|
|
1543
1626
|
variant === "board" && /* @__PURE__ */ jsxs3("div", { class: "report-detail-header report-detail-header--board", children: [
|
|
1544
1627
|
/* @__PURE__ */ jsxs3(
|
|
@@ -1554,12 +1637,12 @@ function ReportDetailView({
|
|
|
1554
1637
|
]
|
|
1555
1638
|
}
|
|
1556
1639
|
),
|
|
1557
|
-
/* @__PURE__ */
|
|
1640
|
+
/* @__PURE__ */ jsx3("span", { class: `pill pill-status pill-status--${detail.status}`, children: strings[`status.${detail.status}`] ?? detail.status })
|
|
1558
1641
|
] }),
|
|
1559
1642
|
/* @__PURE__ */ jsxs3("div", { class: "report-detail-body", children: [
|
|
1560
|
-
/* @__PURE__ */
|
|
1643
|
+
/* @__PURE__ */ jsx3(ContextBlock, { detail, strings }),
|
|
1561
1644
|
editing ? /* @__PURE__ */ jsxs3("div", { class: "report-detail-edit", children: [
|
|
1562
|
-
/* @__PURE__ */
|
|
1645
|
+
/* @__PURE__ */ jsx3(
|
|
1563
1646
|
"textarea",
|
|
1564
1647
|
{
|
|
1565
1648
|
class: "report-detail-edit-input",
|
|
@@ -1571,9 +1654,9 @@ function ReportDetailView({
|
|
|
1571
1654
|
disabled: savingEdit
|
|
1572
1655
|
}
|
|
1573
1656
|
),
|
|
1574
|
-
editError && /* @__PURE__ */
|
|
1657
|
+
editError && /* @__PURE__ */ jsx3("p", { class: "error", role: "alert", children: strings["detail.edit_failed"] }),
|
|
1575
1658
|
/* @__PURE__ */ jsxs3("div", { class: "report-detail-edit-actions", children: [
|
|
1576
|
-
/* @__PURE__ */
|
|
1659
|
+
/* @__PURE__ */ jsx3(
|
|
1577
1660
|
"button",
|
|
1578
1661
|
{
|
|
1579
1662
|
type: "button",
|
|
@@ -1583,7 +1666,7 @@ function ReportDetailView({
|
|
|
1583
1666
|
children: strings["detail.edit_cancel"]
|
|
1584
1667
|
}
|
|
1585
1668
|
),
|
|
1586
|
-
/* @__PURE__ */
|
|
1669
|
+
/* @__PURE__ */ jsx3(
|
|
1587
1670
|
"button",
|
|
1588
1671
|
{
|
|
1589
1672
|
type: "button",
|
|
@@ -1595,8 +1678,8 @@ function ReportDetailView({
|
|
|
1595
1678
|
)
|
|
1596
1679
|
] })
|
|
1597
1680
|
] }) : /* @__PURE__ */ jsxs3("div", { class: "report-detail-description-row", children: [
|
|
1598
|
-
/* @__PURE__ */
|
|
1599
|
-
isMine && /* @__PURE__ */
|
|
1681
|
+
/* @__PURE__ */ jsx3("p", { class: "report-detail-description", children: linkifySeq(detail.description, onOpenSeq) }),
|
|
1682
|
+
isMine && /* @__PURE__ */ jsx3(
|
|
1600
1683
|
"button",
|
|
1601
1684
|
{
|
|
1602
1685
|
type: "button",
|
|
@@ -1606,7 +1689,7 @@ function ReportDetailView({
|
|
|
1606
1689
|
}
|
|
1607
1690
|
)
|
|
1608
1691
|
] }),
|
|
1609
|
-
buildPermalink && /* @__PURE__ */
|
|
1692
|
+
buildPermalink && /* @__PURE__ */ jsx3("div", { class: "report-detail-permalink", children: /* @__PURE__ */ jsx3(
|
|
1610
1693
|
"button",
|
|
1611
1694
|
{
|
|
1612
1695
|
type: "button",
|
|
@@ -1617,19 +1700,19 @@ function ReportDetailView({
|
|
|
1617
1700
|
) }),
|
|
1618
1701
|
(detail.screenshots?.length ? detail.screenshots.map((s) => s.url) : [detail.screenshot_url]).map((url, i) => ({ url: pinUrl(`shot:${i}`, url ?? null), pinKey: `shot:${i}` })).filter((s) => Boolean(s.url)).map(({ url, pinKey }) => {
|
|
1619
1702
|
const safeHref = safeExternalHref(url);
|
|
1620
|
-
return safeHref ? /* @__PURE__ */
|
|
1703
|
+
return safeHref ? /* @__PURE__ */ jsx3(
|
|
1621
1704
|
"a",
|
|
1622
1705
|
{
|
|
1623
1706
|
class: "report-detail-screenshot",
|
|
1624
1707
|
href: safeHref,
|
|
1625
1708
|
target: "_blank",
|
|
1626
1709
|
rel: "noopener noreferrer",
|
|
1627
|
-
children: /* @__PURE__ */
|
|
1710
|
+
children: /* @__PURE__ */ jsx3("img", { src: url, alt: "", loading: "lazy", onError: () => unpinUrl(pinKey) })
|
|
1628
1711
|
}
|
|
1629
|
-
) : /* @__PURE__ */
|
|
1712
|
+
) : /* @__PURE__ */ jsx3("div", { class: "report-detail-screenshot", children: /* @__PURE__ */ jsx3("img", { src: url, alt: "", loading: "lazy", onError: () => unpinUrl(pinKey) }) });
|
|
1630
1713
|
}),
|
|
1631
|
-
/* @__PURE__ */
|
|
1632
|
-
detail.comments.length === 0 ? /* @__PURE__ */
|
|
1714
|
+
/* @__PURE__ */ jsx3("h3", { class: "report-detail-section", children: strings["detail.thread"] }),
|
|
1715
|
+
detail.comments.length === 0 ? /* @__PURE__ */ jsx3("p", { class: "report-detail-empty", children: strings["detail.no_replies"] }) : /* @__PURE__ */ jsx3("ul", { class: "report-comments", children: detail.comments.map((c) => /* @__PURE__ */ jsx3("li", { children: /* @__PURE__ */ jsx3(
|
|
1633
1716
|
CommentBubble,
|
|
1634
1717
|
{
|
|
1635
1718
|
comment: c,
|
|
@@ -1638,10 +1721,10 @@ function ReportDetailView({
|
|
|
1638
1721
|
stableUrl: (key, url) => pinUrl(key, url) ?? url
|
|
1639
1722
|
}
|
|
1640
1723
|
) })) }),
|
|
1641
|
-
detail.status_history && detail.status_history.length > 0 && /* @__PURE__ */
|
|
1642
|
-
detail.technical_context && /* @__PURE__ */
|
|
1724
|
+
detail.status_history && detail.status_history.length > 0 && /* @__PURE__ */ jsx3(StatusHistorySection, { rows: detail.status_history, strings }),
|
|
1725
|
+
detail.technical_context && /* @__PURE__ */ jsx3(TechnicalContextDrawer, { ctx: detail.technical_context, strings }),
|
|
1643
1726
|
showComposeBox ? /* @__PURE__ */ jsxs3("div", { class: "report-compose", children: [
|
|
1644
|
-
/* @__PURE__ */
|
|
1727
|
+
/* @__PURE__ */ jsx3(
|
|
1645
1728
|
"textarea",
|
|
1646
1729
|
{
|
|
1647
1730
|
value: composeBody,
|
|
@@ -1650,9 +1733,9 @@ function ReportDetailView({
|
|
|
1650
1733
|
disabled: sending
|
|
1651
1734
|
}
|
|
1652
1735
|
),
|
|
1653
|
-
composeShots.length > 0 && /* @__PURE__ */
|
|
1654
|
-
/* @__PURE__ */
|
|
1655
|
-
/* @__PURE__ */
|
|
1736
|
+
composeShots.length > 0 && /* @__PURE__ */ jsx3("div", { class: "compose-attachments", children: composeShots.map((s, i) => /* @__PURE__ */ jsxs3("div", { class: "compose-attachment", children: [
|
|
1737
|
+
/* @__PURE__ */ jsx3("img", { src: s.preview, alt: strings["detail.attachment_alt"] }),
|
|
1738
|
+
/* @__PURE__ */ jsx3(
|
|
1656
1739
|
"button",
|
|
1657
1740
|
{
|
|
1658
1741
|
type: "button",
|
|
@@ -1664,8 +1747,8 @@ function ReportDetailView({
|
|
|
1664
1747
|
}
|
|
1665
1748
|
)
|
|
1666
1749
|
] }, s.preview)) }),
|
|
1667
|
-
attachError && /* @__PURE__ */
|
|
1668
|
-
/* @__PURE__ */
|
|
1750
|
+
attachError && /* @__PURE__ */ jsx3("p", { class: "compose-attach-error", role: "alert", children: attachError }),
|
|
1751
|
+
/* @__PURE__ */ jsx3(
|
|
1669
1752
|
"input",
|
|
1670
1753
|
{
|
|
1671
1754
|
ref: fileInputRef,
|
|
@@ -1678,7 +1761,7 @@ function ReportDetailView({
|
|
|
1678
1761
|
}
|
|
1679
1762
|
),
|
|
1680
1763
|
/* @__PURE__ */ jsxs3("div", { class: "report-compose-actions", children: [
|
|
1681
|
-
/* @__PURE__ */
|
|
1764
|
+
/* @__PURE__ */ jsx3(
|
|
1682
1765
|
"button",
|
|
1683
1766
|
{
|
|
1684
1767
|
type: "button",
|
|
@@ -1688,7 +1771,7 @@ function ReportDetailView({
|
|
|
1688
1771
|
children: strings["detail.attach_add"]
|
|
1689
1772
|
}
|
|
1690
1773
|
),
|
|
1691
|
-
showCloseCta && /* @__PURE__ */
|
|
1774
|
+
showCloseCta && /* @__PURE__ */ jsx3(
|
|
1692
1775
|
"button",
|
|
1693
1776
|
{
|
|
1694
1777
|
type: "button",
|
|
@@ -1698,7 +1781,7 @@ function ReportDetailView({
|
|
|
1698
1781
|
children: closing ? strings["detail.close_busy"] : strings["detail.close_cta"]
|
|
1699
1782
|
}
|
|
1700
1783
|
),
|
|
1701
|
-
showCloseCta && /* @__PURE__ */
|
|
1784
|
+
showCloseCta && /* @__PURE__ */ jsx3(
|
|
1702
1785
|
"button",
|
|
1703
1786
|
{
|
|
1704
1787
|
type: "button",
|
|
@@ -1708,7 +1791,7 @@ function ReportDetailView({
|
|
|
1708
1791
|
children: reopening ? strings["detail.reopen_busy"] : strings["detail.reopen_cta"]
|
|
1709
1792
|
}
|
|
1710
1793
|
),
|
|
1711
|
-
/* @__PURE__ */
|
|
1794
|
+
/* @__PURE__ */ jsx3(
|
|
1712
1795
|
"button",
|
|
1713
1796
|
{
|
|
1714
1797
|
type: "button",
|
|
@@ -1724,9 +1807,9 @@ function ReportDetailView({
|
|
|
1724
1807
|
// to the submitter, so we hide the compose box entirely (action
|
|
1725
1808
|
// is genuinely unavailable) and surface a short notice so the
|
|
1726
1809
|
// viewer understands why.
|
|
1727
|
-
/* @__PURE__ */
|
|
1810
|
+
/* @__PURE__ */ jsx3("p", { class: "report-detail-teammate-notice", role: "note", children: strings["detail.teammate_notice"] })
|
|
1728
1811
|
),
|
|
1729
|
-
error && /* @__PURE__ */
|
|
1812
|
+
error && /* @__PURE__ */ jsx3("div", { class: "error", children: error })
|
|
1730
1813
|
] })
|
|
1731
1814
|
] });
|
|
1732
1815
|
}
|
|
@@ -1739,19 +1822,19 @@ function ContextBlock({ detail, strings }) {
|
|
|
1739
1822
|
const captureLabel = strings[captureKey] ?? detail.capture_method;
|
|
1740
1823
|
return /* @__PURE__ */ jsxs3("div", { class: "report-detail-context", children: [
|
|
1741
1824
|
/* @__PURE__ */ jsxs3("div", { class: "report-detail-context-pills", children: [
|
|
1742
|
-
/* @__PURE__ */
|
|
1743
|
-
/* @__PURE__ */
|
|
1744
|
-
/* @__PURE__ */
|
|
1825
|
+
/* @__PURE__ */ jsx3("span", { class: "pill pill-type", children: strings[`type.${detail.feedback_type}`] }),
|
|
1826
|
+
/* @__PURE__ */ jsx3("span", { class: `pill pill-severity pill-severity--${detail.severity}`, children: strings[`severity.${detail.severity}`] }),
|
|
1827
|
+
/* @__PURE__ */ jsx3("span", { class: "pill pill-capture", children: captureLabel })
|
|
1745
1828
|
] }),
|
|
1746
1829
|
/* @__PURE__ */ jsxs3("div", { class: "report-detail-context-line", children: [
|
|
1747
|
-
/* @__PURE__ */
|
|
1748
|
-
/* @__PURE__ */
|
|
1830
|
+
/* @__PURE__ */ jsx3("span", { class: "report-detail-context-label", children: strings["detail.context.submitted_at"] }),
|
|
1831
|
+
/* @__PURE__ */ jsx3("span", { children: formatSubmittedAt(detail.created_at) })
|
|
1749
1832
|
] }),
|
|
1750
1833
|
detail.page_url && (() => {
|
|
1751
1834
|
const safeHref = safeExternalHref(detail.page_url);
|
|
1752
1835
|
return /* @__PURE__ */ jsxs3("div", { class: "report-detail-context-line", title: detail.page_url, children: [
|
|
1753
|
-
/* @__PURE__ */
|
|
1754
|
-
safeHref ? /* @__PURE__ */
|
|
1836
|
+
/* @__PURE__ */ jsx3("span", { class: "report-detail-context-label", children: strings["detail.context.page"] }),
|
|
1837
|
+
safeHref ? /* @__PURE__ */ jsx3(
|
|
1755
1838
|
"a",
|
|
1756
1839
|
{
|
|
1757
1840
|
class: "report-detail-context-url",
|
|
@@ -1760,7 +1843,7 @@ function ContextBlock({ detail, strings }) {
|
|
|
1760
1843
|
rel: "noopener noreferrer",
|
|
1761
1844
|
children: truncateUrl(detail.page_url, 64)
|
|
1762
1845
|
}
|
|
1763
|
-
) : /* @__PURE__ */
|
|
1846
|
+
) : /* @__PURE__ */ jsx3("span", { class: "report-detail-context-url", children: truncateUrl(detail.page_url, 64) })
|
|
1764
1847
|
] });
|
|
1765
1848
|
})()
|
|
1766
1849
|
] });
|
|
@@ -1787,12 +1870,12 @@ function TechnicalContextDrawer({ ctx, strings }) {
|
|
|
1787
1870
|
const errorCount = errors.length;
|
|
1788
1871
|
const summary = errorCount > 0 ? `${strings["detail.tech.title"]} \xB7 ${errorCount} ${errorCount === 1 ? strings["detail.tech.errors_one"] : strings["detail.tech.errors_many"]}` : strings["detail.tech.title"];
|
|
1789
1872
|
return /* @__PURE__ */ jsxs3("details", { class: "report-detail-tech", children: [
|
|
1790
|
-
/* @__PURE__ */
|
|
1873
|
+
/* @__PURE__ */ jsx3("summary", { children: summary }),
|
|
1791
1874
|
/* @__PURE__ */ jsxs3("div", { class: "tech-body", children: [
|
|
1792
|
-
device && /* @__PURE__ */
|
|
1793
|
-
errors.length > 0 && /* @__PURE__ */
|
|
1794
|
-
consoleLogs.length > 0 && /* @__PURE__ */
|
|
1795
|
-
network.length > 0 && /* @__PURE__ */
|
|
1875
|
+
device && /* @__PURE__ */ jsx3(DeviceSection, { device, strings }),
|
|
1876
|
+
errors.length > 0 && /* @__PURE__ */ jsx3(ErrorsSection, { errors, strings }),
|
|
1877
|
+
consoleLogs.length > 0 && /* @__PURE__ */ jsx3(ConsoleSection, { logs: consoleLogs, strings }),
|
|
1878
|
+
network.length > 0 && /* @__PURE__ */ jsx3(NetworkSection, { rows: network, strings })
|
|
1796
1879
|
] })
|
|
1797
1880
|
] });
|
|
1798
1881
|
}
|
|
@@ -1814,10 +1897,10 @@ function DeviceSection({
|
|
|
1814
1897
|
if (device?.connection) parts.push({ label: strings["detail.tech.device.connection"], value: device.connection });
|
|
1815
1898
|
if (parts.length === 0) return null;
|
|
1816
1899
|
return /* @__PURE__ */ jsxs3("div", { class: "tech-section", children: [
|
|
1817
|
-
/* @__PURE__ */
|
|
1818
|
-
/* @__PURE__ */
|
|
1819
|
-
/* @__PURE__ */
|
|
1820
|
-
/* @__PURE__ */
|
|
1900
|
+
/* @__PURE__ */ jsx3("h4", { children: strings["detail.tech.device"] }),
|
|
1901
|
+
/* @__PURE__ */ jsx3("dl", { class: "tech-device", children: parts.map((p) => /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
1902
|
+
/* @__PURE__ */ jsx3("dt", { children: p.label }),
|
|
1903
|
+
/* @__PURE__ */ jsx3("dd", { children: p.value })
|
|
1821
1904
|
] })) })
|
|
1822
1905
|
] });
|
|
1823
1906
|
}
|
|
@@ -1826,10 +1909,10 @@ function ErrorsSection({
|
|
|
1826
1909
|
strings
|
|
1827
1910
|
}) {
|
|
1828
1911
|
return /* @__PURE__ */ jsxs3("div", { class: "tech-section", children: [
|
|
1829
|
-
/* @__PURE__ */
|
|
1830
|
-
/* @__PURE__ */
|
|
1831
|
-
/* @__PURE__ */
|
|
1832
|
-
e.stack && /* @__PURE__ */
|
|
1912
|
+
/* @__PURE__ */ jsx3("h4", { children: strings["detail.tech.errors"] }),
|
|
1913
|
+
/* @__PURE__ */ jsx3("ul", { class: "tech-errors", children: errors.map((e) => /* @__PURE__ */ jsxs3("li", { children: [
|
|
1914
|
+
/* @__PURE__ */ jsx3("div", { class: "tech-errors-msg", children: e.message }),
|
|
1915
|
+
e.stack && /* @__PURE__ */ jsx3("pre", { class: "tech-errors-stack", children: truncateStack(e.stack) })
|
|
1833
1916
|
] })) })
|
|
1834
1917
|
] });
|
|
1835
1918
|
}
|
|
@@ -1838,10 +1921,10 @@ function ConsoleSection({
|
|
|
1838
1921
|
strings
|
|
1839
1922
|
}) {
|
|
1840
1923
|
return /* @__PURE__ */ jsxs3("div", { class: "tech-section", children: [
|
|
1841
|
-
/* @__PURE__ */
|
|
1842
|
-
/* @__PURE__ */
|
|
1843
|
-
/* @__PURE__ */
|
|
1844
|
-
/* @__PURE__ */
|
|
1924
|
+
/* @__PURE__ */ jsx3("h4", { children: strings["detail.tech.console"] }),
|
|
1925
|
+
/* @__PURE__ */ jsx3("ul", { class: "tech-console", children: logs.map((l) => /* @__PURE__ */ jsxs3("li", { class: `tech-console-row tech-console-row--${l.level}`, children: [
|
|
1926
|
+
/* @__PURE__ */ jsx3("span", { class: "tech-console-level", children: l.level }),
|
|
1927
|
+
/* @__PURE__ */ jsx3("span", { class: "tech-console-msg", children: l.message })
|
|
1845
1928
|
] })) })
|
|
1846
1929
|
] });
|
|
1847
1930
|
}
|
|
@@ -1850,13 +1933,13 @@ function NetworkSection({
|
|
|
1850
1933
|
strings
|
|
1851
1934
|
}) {
|
|
1852
1935
|
return /* @__PURE__ */ jsxs3("div", { class: "tech-section", children: [
|
|
1853
|
-
/* @__PURE__ */
|
|
1854
|
-
/* @__PURE__ */
|
|
1936
|
+
/* @__PURE__ */ jsx3("h4", { children: strings["detail.tech.network"] }),
|
|
1937
|
+
/* @__PURE__ */ jsx3("ul", { class: "tech-network", children: rows.map((n) => {
|
|
1855
1938
|
const failed = n.status >= 400 || n.status === 0;
|
|
1856
1939
|
return /* @__PURE__ */ jsxs3("li", { class: `tech-network-row${failed ? " tech-network-row--fail" : ""}`, children: [
|
|
1857
|
-
/* @__PURE__ */
|
|
1858
|
-
/* @__PURE__ */
|
|
1859
|
-
/* @__PURE__ */
|
|
1940
|
+
/* @__PURE__ */ jsx3("span", { class: "tech-network-status", children: n.status || "\u2014" }),
|
|
1941
|
+
/* @__PURE__ */ jsx3("span", { class: "tech-network-method", children: n.method }),
|
|
1942
|
+
/* @__PURE__ */ jsx3("span", { class: "tech-network-url", title: n.url, children: truncateUrl(n.url, 56) }),
|
|
1860
1943
|
/* @__PURE__ */ jsxs3("span", { class: "tech-network-time", children: [
|
|
1861
1944
|
Math.round(n.durationMs),
|
|
1862
1945
|
"ms"
|
|
@@ -1872,26 +1955,26 @@ function truncateStack(stack) {
|
|
|
1872
1955
|
}
|
|
1873
1956
|
function StatusHistorySection({ rows, strings }) {
|
|
1874
1957
|
return /* @__PURE__ */ jsxs3("div", { class: "report-detail-history", children: [
|
|
1875
|
-
/* @__PURE__ */
|
|
1876
|
-
/* @__PURE__ */
|
|
1958
|
+
/* @__PURE__ */ jsx3("h3", { class: "report-detail-section", children: strings["detail.history"] }),
|
|
1959
|
+
/* @__PURE__ */ jsx3("ol", { class: "status-history", children: rows.map((r) => {
|
|
1877
1960
|
const from = strings[`status.${r.from_status}`] ?? r.from_status;
|
|
1878
1961
|
const to = strings[`status.${r.to_status}`] ?? r.to_status;
|
|
1879
1962
|
const sourceKey = r.changed_by_source === "mcp" ? "detail.author.mcp" : r.changed_by_source === "system" ? "detail.author.system" : "detail.author.staff";
|
|
1880
1963
|
return /* @__PURE__ */ jsxs3("li", { class: "status-history-row", children: [
|
|
1881
|
-
/* @__PURE__ */
|
|
1964
|
+
/* @__PURE__ */ jsx3("span", { class: "status-history-time", children: formatSubmittedAt(r.created_at) }),
|
|
1882
1965
|
/* @__PURE__ */ jsxs3("span", { class: "status-history-transition", children: [
|
|
1883
|
-
/* @__PURE__ */
|
|
1884
|
-
/* @__PURE__ */
|
|
1885
|
-
/* @__PURE__ */
|
|
1966
|
+
/* @__PURE__ */ jsx3("span", { class: `pill pill-status pill-status--${r.from_status}`, children: from }),
|
|
1967
|
+
/* @__PURE__ */ jsx3("span", { class: "status-history-arrow", "aria-hidden": "true", children: "\u2192" }),
|
|
1968
|
+
/* @__PURE__ */ jsx3("span", { class: `pill pill-status pill-status--${r.to_status}`, children: to })
|
|
1886
1969
|
] }),
|
|
1887
|
-
/* @__PURE__ */
|
|
1970
|
+
/* @__PURE__ */ jsx3("span", { class: `status-history-source status-history-source--${r.changed_by_source}`, children: strings[sourceKey] })
|
|
1888
1971
|
] });
|
|
1889
1972
|
}) })
|
|
1890
1973
|
] });
|
|
1891
1974
|
}
|
|
1892
1975
|
|
|
1893
1976
|
// src/widget/BoardView.tsx
|
|
1894
|
-
import { Fragment as Fragment2, jsx as
|
|
1977
|
+
import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "preact/jsx-runtime";
|
|
1895
1978
|
var POLL_MS2 = 3e4;
|
|
1896
1979
|
var SEARCH_DEBOUNCE_MS = 300;
|
|
1897
1980
|
var SORT_OPTIONS = ["recent", "oldest", "updated", "severity", "status"];
|
|
@@ -1911,22 +1994,22 @@ function BoardView({
|
|
|
1911
1994
|
getCurrentPage,
|
|
1912
1995
|
initialSelectedId
|
|
1913
1996
|
}) {
|
|
1914
|
-
const [filters, setFilters] =
|
|
1915
|
-
const [thisPage, setThisPage] =
|
|
1997
|
+
const [filters, setFilters] = useState3(() => loadBoardView(externalId));
|
|
1998
|
+
const [thisPage, setThisPage] = useState3(true);
|
|
1916
1999
|
useEffect2(() => {
|
|
1917
2000
|
saveBoardView(externalId, filters);
|
|
1918
2001
|
}, [externalId, filtersHash(filters)]);
|
|
1919
|
-
const [page, setPage] =
|
|
1920
|
-
const [kpis, setKpis] =
|
|
1921
|
-
const [loading, setLoading] =
|
|
1922
|
-
const [stale, setStale] =
|
|
1923
|
-
const [error, setError] =
|
|
1924
|
-
const [selectedId, setSelectedId] =
|
|
1925
|
-
const [detailKey, setDetailKey] =
|
|
1926
|
-
const [reloadTick, setReloadTick] =
|
|
1927
|
-
const [extra, setExtra] =
|
|
1928
|
-
const [loadingMore, setLoadingMore] =
|
|
1929
|
-
const [qDraft, setQDraft] =
|
|
2002
|
+
const [page, setPage] = useState3(null);
|
|
2003
|
+
const [kpis, setKpis] = useState3(null);
|
|
2004
|
+
const [loading, setLoading] = useState3(true);
|
|
2005
|
+
const [stale, setStale] = useState3(false);
|
|
2006
|
+
const [error, setError] = useState3(null);
|
|
2007
|
+
const [selectedId, setSelectedId] = useState3(initialSelectedId ?? null);
|
|
2008
|
+
const [detailKey, setDetailKey] = useState3(0);
|
|
2009
|
+
const [reloadTick, setReloadTick] = useState3(0);
|
|
2010
|
+
const [extra, setExtra] = useState3(null);
|
|
2011
|
+
const [loadingMore, setLoadingMore] = useState3(false);
|
|
2012
|
+
const [qDraft, setQDraft] = useState3(filters.q ?? "");
|
|
1930
2013
|
const debouncedQ = useDebouncedValue(qDraft, SEARCH_DEBOUNCE_MS);
|
|
1931
2014
|
useEffect2(() => {
|
|
1932
2015
|
setFilters((f) => {
|
|
@@ -2033,8 +2116,8 @@ function BoardView({
|
|
|
2033
2116
|
setDetailKey((k) => k + 1);
|
|
2034
2117
|
};
|
|
2035
2118
|
return /* @__PURE__ */ jsxs4("div", { class: `board-view ${stale ? "is-stale" : ""}`, children: [
|
|
2036
|
-
/* @__PURE__ */
|
|
2037
|
-
/* @__PURE__ */
|
|
2119
|
+
/* @__PURE__ */ jsx4(BoardHeader, { strings, kpis, thisPage }),
|
|
2120
|
+
/* @__PURE__ */ jsx4(
|
|
2038
2121
|
BoardFilters,
|
|
2039
2122
|
{
|
|
2040
2123
|
filters,
|
|
@@ -2050,8 +2133,8 @@ function BoardView({
|
|
|
2050
2133
|
/* @__PURE__ */ jsxs4("div", { class: "board-body", children: [
|
|
2051
2134
|
/* @__PURE__ */ jsxs4("div", { class: "board-list-wrap", "aria-busy": loading, children: [
|
|
2052
2135
|
error && /* @__PURE__ */ jsxs4("div", { class: "board-error", role: "alert", children: [
|
|
2053
|
-
/* @__PURE__ */
|
|
2054
|
-
/* @__PURE__ */
|
|
2136
|
+
/* @__PURE__ */ jsx4("span", { children: error }),
|
|
2137
|
+
/* @__PURE__ */ jsx4(
|
|
2055
2138
|
"button",
|
|
2056
2139
|
{
|
|
2057
2140
|
type: "button",
|
|
@@ -2063,10 +2146,11 @@ function BoardView({
|
|
|
2063
2146
|
},
|
|
2064
2147
|
children: strings["board.retry"]
|
|
2065
2148
|
}
|
|
2066
|
-
)
|
|
2149
|
+
),
|
|
2150
|
+
/* @__PURE__ */ jsx4(DiagnosticHint, { api, strings, host: api.endpointHost })
|
|
2067
2151
|
] }),
|
|
2068
|
-
!error && loading && !page && /* @__PURE__ */
|
|
2069
|
-
!error && page && visibleRows.length === 0 && (!loading || stale) && /* @__PURE__ */
|
|
2152
|
+
!error && loading && !page && /* @__PURE__ */ jsx4(BoardListSkeleton, {}),
|
|
2153
|
+
!error && page && visibleRows.length === 0 && (!loading || stale) && /* @__PURE__ */ jsx4(
|
|
2070
2154
|
BoardEmpty,
|
|
2071
2155
|
{
|
|
2072
2156
|
strings,
|
|
@@ -2075,7 +2159,7 @@ function BoardView({
|
|
|
2075
2159
|
}
|
|
2076
2160
|
),
|
|
2077
2161
|
!error && page && visibleRows.length > 0 && /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
2078
|
-
/* @__PURE__ */
|
|
2162
|
+
/* @__PURE__ */ jsx4(
|
|
2079
2163
|
BoardList,
|
|
2080
2164
|
{
|
|
2081
2165
|
rows: visibleRows,
|
|
@@ -2086,7 +2170,7 @@ function BoardView({
|
|
|
2086
2170
|
thisPage
|
|
2087
2171
|
}
|
|
2088
2172
|
),
|
|
2089
|
-
hasMore && !stale && /* @__PURE__ */
|
|
2173
|
+
hasMore && !stale && /* @__PURE__ */ jsx4(
|
|
2090
2174
|
"button",
|
|
2091
2175
|
{
|
|
2092
2176
|
type: "button",
|
|
@@ -2098,7 +2182,7 @@ function BoardView({
|
|
|
2098
2182
|
)
|
|
2099
2183
|
] })
|
|
2100
2184
|
] }),
|
|
2101
|
-
/* @__PURE__ */
|
|
2185
|
+
/* @__PURE__ */ jsx4("div", { class: `board-detail-wrap ${selectedId ? "has-selection" : ""}`, children: selectedId ? /* @__PURE__ */ jsx4(
|
|
2102
2186
|
ReportDetailView,
|
|
2103
2187
|
{
|
|
2104
2188
|
api,
|
|
@@ -2119,8 +2203,8 @@ function BoardView({
|
|
|
2119
2203
|
},
|
|
2120
2204
|
detailKey
|
|
2121
2205
|
) : /* @__PURE__ */ jsxs4("div", { class: "board-detail-empty", children: [
|
|
2122
|
-
/* @__PURE__ */
|
|
2123
|
-
/* @__PURE__ */
|
|
2206
|
+
/* @__PURE__ */ jsx4(DetailEmptyIllustration, {}),
|
|
2207
|
+
/* @__PURE__ */ jsx4("p", { children: strings["board.detail.empty"] })
|
|
2124
2208
|
] }) })
|
|
2125
2209
|
] })
|
|
2126
2210
|
] });
|
|
@@ -2133,13 +2217,13 @@ function BoardHeader({
|
|
|
2133
2217
|
const scopeLabel = thisPage ? strings["board.scope.onThisPage"] : kpis?.scope === "project" ? strings["board.scope.project"] : strings["board.scope.mine"];
|
|
2134
2218
|
return /* @__PURE__ */ jsxs4("header", { class: "board-header", children: [
|
|
2135
2219
|
/* @__PURE__ */ jsxs4("div", { class: "board-header-title", children: [
|
|
2136
|
-
/* @__PURE__ */
|
|
2220
|
+
/* @__PURE__ */ jsx4("span", { class: "board-header-emoji", "aria-hidden": "true", children: "\u{1F4CB}" }),
|
|
2137
2221
|
/* @__PURE__ */ jsxs4("div", { children: [
|
|
2138
|
-
/* @__PURE__ */
|
|
2139
|
-
/* @__PURE__ */
|
|
2222
|
+
/* @__PURE__ */ jsx4("h2", { class: "board-header-h", children: strings["tab.board"] }),
|
|
2223
|
+
/* @__PURE__ */ jsx4("p", { class: "board-header-sub", children: kpis ? `${kpis.total} \xB7 ${scopeLabel}` : scopeLabel })
|
|
2140
2224
|
] })
|
|
2141
2225
|
] }),
|
|
2142
|
-
/* @__PURE__ */
|
|
2226
|
+
/* @__PURE__ */ jsx4(BoardKpiStrip, { kpis, strings })
|
|
2143
2227
|
] });
|
|
2144
2228
|
}
|
|
2145
2229
|
function BoardKpiStrip({
|
|
@@ -2172,9 +2256,9 @@ function BoardKpiStrip({
|
|
|
2172
2256
|
tone: "tone-rate"
|
|
2173
2257
|
}
|
|
2174
2258
|
];
|
|
2175
|
-
return /* @__PURE__ */
|
|
2176
|
-
/* @__PURE__ */
|
|
2177
|
-
/* @__PURE__ */
|
|
2259
|
+
return /* @__PURE__ */ jsx4("div", { class: `board-kpi-strip ${kpis ? "is-ready" : "is-loading"}`, "aria-live": "polite", children: cells.map((c) => /* @__PURE__ */ jsxs4("div", { class: `board-kpi-card ${c.tone}`, children: [
|
|
2260
|
+
/* @__PURE__ */ jsx4("div", { class: "board-kpi-value", children: c.value }),
|
|
2261
|
+
/* @__PURE__ */ jsx4("div", { class: "board-kpi-label", children: c.label })
|
|
2178
2262
|
] }, c.key)) });
|
|
2179
2263
|
}
|
|
2180
2264
|
function BoardFilters({
|
|
@@ -2227,7 +2311,7 @@ function BoardFilters({
|
|
|
2227
2311
|
const clear = () => onChange({});
|
|
2228
2312
|
return /* @__PURE__ */ jsxs4("div", { class: "board-filters", children: [
|
|
2229
2313
|
/* @__PURE__ */ jsxs4("div", { class: "board-scope", role: "group", "aria-label": strings["board.scope.thisPage"], children: [
|
|
2230
|
-
/* @__PURE__ */
|
|
2314
|
+
/* @__PURE__ */ jsx4(
|
|
2231
2315
|
"button",
|
|
2232
2316
|
{
|
|
2233
2317
|
type: "button",
|
|
@@ -2237,7 +2321,7 @@ function BoardFilters({
|
|
|
2237
2321
|
children: strings["board.scope.thisPage"]
|
|
2238
2322
|
}
|
|
2239
2323
|
),
|
|
2240
|
-
/* @__PURE__ */
|
|
2324
|
+
/* @__PURE__ */ jsx4(
|
|
2241
2325
|
"button",
|
|
2242
2326
|
{
|
|
2243
2327
|
type: "button",
|
|
@@ -2248,14 +2332,14 @@ function BoardFilters({
|
|
|
2248
2332
|
}
|
|
2249
2333
|
)
|
|
2250
2334
|
] }),
|
|
2251
|
-
/* @__PURE__ */
|
|
2335
|
+
/* @__PURE__ */ jsx4(
|
|
2252
2336
|
"select",
|
|
2253
2337
|
{
|
|
2254
2338
|
class: "board-filter-select",
|
|
2255
2339
|
"aria-label": strings["board.sort"],
|
|
2256
2340
|
value: filters.ordering ?? "recent",
|
|
2257
2341
|
onChange: (e) => setOrdering(e.target.value),
|
|
2258
|
-
children: SORT_OPTIONS.map((o) => /* @__PURE__ */
|
|
2342
|
+
children: SORT_OPTIONS.map((o) => /* @__PURE__ */ jsx4("option", { value: o, children: strings[`board.sort.${o}`] }, o))
|
|
2259
2343
|
}
|
|
2260
2344
|
),
|
|
2261
2345
|
/* @__PURE__ */ jsxs4(
|
|
@@ -2266,8 +2350,8 @@ function BoardFilters({
|
|
|
2266
2350
|
value: filters.status?.[0] ?? "",
|
|
2267
2351
|
onChange: (e) => setStatus(e.target.value),
|
|
2268
2352
|
children: [
|
|
2269
|
-
/* @__PURE__ */
|
|
2270
|
-
STATUSES.map((s) => /* @__PURE__ */
|
|
2353
|
+
/* @__PURE__ */ jsx4("option", { value: "", children: strings["board.filter.status"] }),
|
|
2354
|
+
STATUSES.map((s) => /* @__PURE__ */ jsx4("option", { value: s, children: strings[`board.kpi.${s}`] ?? s }, s))
|
|
2271
2355
|
]
|
|
2272
2356
|
}
|
|
2273
2357
|
),
|
|
@@ -2279,8 +2363,8 @@ function BoardFilters({
|
|
|
2279
2363
|
value: filters.type?.[0] ?? "",
|
|
2280
2364
|
onChange: (e) => setType(e.target.value),
|
|
2281
2365
|
children: [
|
|
2282
|
-
/* @__PURE__ */
|
|
2283
|
-
TYPES.map((t) => /* @__PURE__ */
|
|
2366
|
+
/* @__PURE__ */ jsx4("option", { value: "", children: strings["board.filter.type"] }),
|
|
2367
|
+
TYPES.map((t) => /* @__PURE__ */ jsx4("option", { value: t, children: strings[`type.${t}`] ?? t }, t))
|
|
2284
2368
|
]
|
|
2285
2369
|
}
|
|
2286
2370
|
),
|
|
@@ -2292,12 +2376,12 @@ function BoardFilters({
|
|
|
2292
2376
|
value: filters.severity?.[0] ?? "",
|
|
2293
2377
|
onChange: (e) => setSeverity(e.target.value),
|
|
2294
2378
|
children: [
|
|
2295
|
-
/* @__PURE__ */
|
|
2296
|
-
SEVERITIES.map((s) => /* @__PURE__ */
|
|
2379
|
+
/* @__PURE__ */ jsx4("option", { value: "", children: strings["board.filter.severity"] }),
|
|
2380
|
+
SEVERITIES.map((s) => /* @__PURE__ */ jsx4("option", { value: s, children: strings[`severity.${s}`] ?? s }, s))
|
|
2297
2381
|
]
|
|
2298
2382
|
}
|
|
2299
2383
|
),
|
|
2300
|
-
/* @__PURE__ */
|
|
2384
|
+
/* @__PURE__ */ jsx4(
|
|
2301
2385
|
"input",
|
|
2302
2386
|
{
|
|
2303
2387
|
type: "search",
|
|
@@ -2308,7 +2392,7 @@ function BoardFilters({
|
|
|
2308
2392
|
}
|
|
2309
2393
|
),
|
|
2310
2394
|
/* @__PURE__ */ jsxs4("label", { class: "board-filter-toggle", children: [
|
|
2311
|
-
/* @__PURE__ */
|
|
2395
|
+
/* @__PURE__ */ jsx4(
|
|
2312
2396
|
"input",
|
|
2313
2397
|
{
|
|
2314
2398
|
type: "checkbox",
|
|
@@ -2316,10 +2400,10 @@ function BoardFilters({
|
|
|
2316
2400
|
onChange: toggleMine
|
|
2317
2401
|
}
|
|
2318
2402
|
),
|
|
2319
|
-
/* @__PURE__ */
|
|
2403
|
+
/* @__PURE__ */ jsx4("span", { children: strings["board.filter.mine"] })
|
|
2320
2404
|
] }),
|
|
2321
2405
|
activeCount > 0 && /* @__PURE__ */ jsxs4("button", { type: "button", class: "board-filter-clear", onClick: clear, children: [
|
|
2322
|
-
/* @__PURE__ */
|
|
2406
|
+
/* @__PURE__ */ jsx4(CloseIcon, {}),
|
|
2323
2407
|
strings["board.filter.clear"]
|
|
2324
2408
|
] })
|
|
2325
2409
|
] });
|
|
@@ -2333,8 +2417,8 @@ function BoardList({
|
|
|
2333
2417
|
thisPage
|
|
2334
2418
|
}) {
|
|
2335
2419
|
return /* @__PURE__ */ jsxs4(Fragment2, { children: [
|
|
2336
|
-
/* @__PURE__ */
|
|
2337
|
-
/* @__PURE__ */
|
|
2420
|
+
/* @__PURE__ */ jsx4("div", { class: "board-list-count", children: strings[thisPage ? "board.list.count.page" : "board.list.count"].replace("{n}", String(rows.length)).replace("{total}", String(total)) }),
|
|
2421
|
+
/* @__PURE__ */ jsx4("ul", { class: "board-list", role: "list", children: rows.map((row) => /* @__PURE__ */ jsx4(
|
|
2338
2422
|
BoardRowCard,
|
|
2339
2423
|
{
|
|
2340
2424
|
row,
|
|
@@ -2353,7 +2437,7 @@ function BoardRowCard({
|
|
|
2353
2437
|
strings
|
|
2354
2438
|
}) {
|
|
2355
2439
|
const author = row.is_mine ? strings["board.list.you"] : row.author_label || "\u2014";
|
|
2356
|
-
return /* @__PURE__ */
|
|
2440
|
+
return /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsxs4(
|
|
2357
2441
|
"button",
|
|
2358
2442
|
{
|
|
2359
2443
|
type: "button",
|
|
@@ -2362,18 +2446,18 @@ function BoardRowCard({
|
|
|
2362
2446
|
"aria-pressed": selected,
|
|
2363
2447
|
children: [
|
|
2364
2448
|
/* @__PURE__ */ jsxs4("div", { class: "board-row-badges", children: [
|
|
2365
|
-
/* @__PURE__ */
|
|
2366
|
-
/* @__PURE__ */
|
|
2449
|
+
/* @__PURE__ */ jsx4("span", { class: `badge status-${row.status}`, children: strings[`status.${row.status}`] ?? row.status }),
|
|
2450
|
+
/* @__PURE__ */ jsx4("span", { class: `badge severity-${row.severity}`, children: strings[`severity.${row.severity}`] ?? row.severity })
|
|
2367
2451
|
] }),
|
|
2368
|
-
/* @__PURE__ */
|
|
2452
|
+
/* @__PURE__ */ jsx4("div", { class: "board-row-description", children: row.description }),
|
|
2369
2453
|
/* @__PURE__ */ jsxs4("div", { class: "board-row-meta", children: [
|
|
2370
|
-
/* @__PURE__ */
|
|
2454
|
+
/* @__PURE__ */ jsx4("span", { class: "board-row-author", children: author }),
|
|
2371
2455
|
row.comment_count > 0 && /* @__PURE__ */ jsxs4("span", { class: "board-row-comments", children: [
|
|
2372
|
-
/* @__PURE__ */
|
|
2456
|
+
/* @__PURE__ */ jsx4(CommentIcon, {}),
|
|
2373
2457
|
" ",
|
|
2374
2458
|
row.comment_count
|
|
2375
2459
|
] }),
|
|
2376
|
-
/* @__PURE__ */
|
|
2460
|
+
/* @__PURE__ */ jsx4("span", { class: "board-row-time", children: formatRelative(row.created_at) })
|
|
2377
2461
|
] })
|
|
2378
2462
|
]
|
|
2379
2463
|
}
|
|
@@ -2385,44 +2469,44 @@ function BoardEmpty({
|
|
|
2385
2469
|
onAllPages
|
|
2386
2470
|
}) {
|
|
2387
2471
|
return /* @__PURE__ */ jsxs4("div", { class: "board-empty", children: [
|
|
2388
|
-
/* @__PURE__ */
|
|
2389
|
-
/* @__PURE__ */
|
|
2390
|
-
/* @__PURE__ */
|
|
2391
|
-
thisPage && /* @__PURE__ */
|
|
2472
|
+
/* @__PURE__ */ jsx4(EmptyIllustration, {}),
|
|
2473
|
+
/* @__PURE__ */ jsx4("h3", { children: strings[thisPage ? "board.list.empty.page.title" : "board.list.empty.title"] }),
|
|
2474
|
+
/* @__PURE__ */ jsx4("p", { children: strings[thisPage ? "board.list.empty.page.description" : "board.list.empty.description"] }),
|
|
2475
|
+
thisPage && /* @__PURE__ */ jsx4("button", { type: "button", class: "btn btn--ghost", onClick: onAllPages, children: strings["board.scope.allPages"] })
|
|
2392
2476
|
] });
|
|
2393
2477
|
}
|
|
2394
2478
|
function BoardListSkeleton() {
|
|
2395
|
-
return /* @__PURE__ */
|
|
2396
|
-
/* @__PURE__ */
|
|
2397
|
-
/* @__PURE__ */
|
|
2398
|
-
/* @__PURE__ */
|
|
2479
|
+
return /* @__PURE__ */ jsx4("ul", { class: "board-list board-list-skeleton", "aria-hidden": "true", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsx4("li", { children: /* @__PURE__ */ jsxs4("div", { class: "board-row skeleton-row", children: [
|
|
2480
|
+
/* @__PURE__ */ jsx4("div", { class: "skeleton-line skeleton-badges" }),
|
|
2481
|
+
/* @__PURE__ */ jsx4("div", { class: "skeleton-line skeleton-text" }),
|
|
2482
|
+
/* @__PURE__ */ jsx4("div", { class: "skeleton-line skeleton-text short" })
|
|
2399
2483
|
] }) }, i)) });
|
|
2400
2484
|
}
|
|
2401
2485
|
function CommentIcon() {
|
|
2402
|
-
return /* @__PURE__ */
|
|
2486
|
+
return /* @__PURE__ */ jsx4("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx4("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) });
|
|
2403
2487
|
}
|
|
2404
2488
|
function CloseIcon() {
|
|
2405
2489
|
return /* @__PURE__ */ jsxs4("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: [
|
|
2406
|
-
/* @__PURE__ */
|
|
2407
|
-
/* @__PURE__ */
|
|
2490
|
+
/* @__PURE__ */ jsx4("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
2491
|
+
/* @__PURE__ */ jsx4("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
2408
2492
|
] });
|
|
2409
2493
|
}
|
|
2410
2494
|
function EmptyIllustration() {
|
|
2411
2495
|
return /* @__PURE__ */ jsxs4("svg", { width: "64", height: "64", viewBox: "0 0 64 64", fill: "none", "aria-hidden": "true", children: [
|
|
2412
|
-
/* @__PURE__ */
|
|
2413
|
-
/* @__PURE__ */
|
|
2496
|
+
/* @__PURE__ */ jsx4("circle", { cx: "32", cy: "32", r: "28", stroke: "currentColor", "stroke-opacity": "0.18", "stroke-width": "2" }),
|
|
2497
|
+
/* @__PURE__ */ jsx4("path", { d: "M22 32h20M32 22v20", stroke: "currentColor", "stroke-opacity": "0.35", "stroke-width": "2", "stroke-linecap": "round" })
|
|
2414
2498
|
] });
|
|
2415
2499
|
}
|
|
2416
2500
|
function DetailEmptyIllustration() {
|
|
2417
2501
|
return /* @__PURE__ */ jsxs4("svg", { width: "80", height: "80", viewBox: "0 0 64 64", fill: "none", "aria-hidden": "true", children: [
|
|
2418
|
-
/* @__PURE__ */
|
|
2419
|
-
/* @__PURE__ */
|
|
2420
|
-
/* @__PURE__ */
|
|
2421
|
-
/* @__PURE__ */
|
|
2502
|
+
/* @__PURE__ */ jsx4("rect", { x: "10", y: "12", width: "44", height: "36", rx: "4", stroke: "currentColor", "stroke-opacity": "0.22", "stroke-width": "2" }),
|
|
2503
|
+
/* @__PURE__ */ jsx4("line", { x1: "18", y1: "22", x2: "46", y2: "22", stroke: "currentColor", "stroke-opacity": "0.22", "stroke-width": "2", "stroke-linecap": "round" }),
|
|
2504
|
+
/* @__PURE__ */ jsx4("line", { x1: "18", y1: "30", x2: "38", y2: "30", stroke: "currentColor", "stroke-opacity": "0.18", "stroke-width": "2", "stroke-linecap": "round" }),
|
|
2505
|
+
/* @__PURE__ */ jsx4("line", { x1: "18", y1: "38", x2: "32", y2: "38", stroke: "currentColor", "stroke-opacity": "0.14", "stroke-width": "2", "stroke-linecap": "round" })
|
|
2422
2506
|
] });
|
|
2423
2507
|
}
|
|
2424
2508
|
function useDebouncedValue(value, ms) {
|
|
2425
|
-
const [debounced, setDebounced] =
|
|
2509
|
+
const [debounced, setDebounced] = useState3(value);
|
|
2426
2510
|
useEffect2(() => {
|
|
2427
2511
|
const t = setTimeout(() => setDebounced(value), ms);
|
|
2428
2512
|
return () => clearTimeout(t);
|
|
@@ -2482,10 +2566,10 @@ function formatRelative(iso) {
|
|
|
2482
2566
|
}
|
|
2483
2567
|
|
|
2484
2568
|
// src/widget/ChangelogList.tsx
|
|
2485
|
-
import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as
|
|
2569
|
+
import { useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState4 } from "preact/hooks";
|
|
2486
2570
|
|
|
2487
2571
|
// src/widget/ReportRow.tsx
|
|
2488
|
-
import { jsx as
|
|
2572
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "preact/jsx-runtime";
|
|
2489
2573
|
function statusClassName(status) {
|
|
2490
2574
|
return `pill pill-status pill-status--${status}`;
|
|
2491
2575
|
}
|
|
@@ -2515,13 +2599,13 @@ function ReportRow({ row, strings, onClick, extraMeta }) {
|
|
|
2515
2599
|
const preview = row.description.length > 120 ? row.description.slice(0, 117) + "\u2026" : row.description;
|
|
2516
2600
|
return /* @__PURE__ */ jsxs5("button", { type: "button", class: "mine-row", onClick, children: [
|
|
2517
2601
|
/* @__PURE__ */ jsxs5("div", { class: "mine-row-pills", children: [
|
|
2518
|
-
/* @__PURE__ */
|
|
2519
|
-
/* @__PURE__ */
|
|
2520
|
-
/* @__PURE__ */
|
|
2602
|
+
/* @__PURE__ */ jsx5("span", { class: statusClassName(row.status), children: strings[`status.${row.status}`] ?? row.status }),
|
|
2603
|
+
/* @__PURE__ */ jsx5("span", { class: typeClassName(), children: strings[`type.${row.feedback_type}`] }),
|
|
2604
|
+
/* @__PURE__ */ jsx5("span", { class: severityClassName(row.severity), children: strings[`severity.${row.severity}`] })
|
|
2521
2605
|
] }),
|
|
2522
|
-
/* @__PURE__ */
|
|
2606
|
+
/* @__PURE__ */ jsx5("div", { class: "mine-row-preview", children: preview }),
|
|
2523
2607
|
/* @__PURE__ */ jsxs5("div", { class: "mine-row-meta", children: [
|
|
2524
|
-
/* @__PURE__ */
|
|
2608
|
+
/* @__PURE__ */ jsx5("span", { children: formatRelative2(row.updated_at || row.created_at) }),
|
|
2525
2609
|
row.comment_count > 0 && /* @__PURE__ */ jsxs5("span", { children: [
|
|
2526
2610
|
"\xB7 ",
|
|
2527
2611
|
repliesLabel(row.comment_count, strings)
|
|
@@ -2535,7 +2619,7 @@ function ReportRow({ row, strings, onClick, extraMeta }) {
|
|
|
2535
2619
|
}
|
|
2536
2620
|
|
|
2537
2621
|
// src/widget/ChangelogList.tsx
|
|
2538
|
-
import { jsx as
|
|
2622
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "preact/jsx-runtime";
|
|
2539
2623
|
var POLL_MS3 = 3e4;
|
|
2540
2624
|
function isoWeekKey(iso) {
|
|
2541
2625
|
const d = new Date(iso);
|
|
@@ -2571,9 +2655,9 @@ function formatWeekLabel(weekKey) {
|
|
|
2571
2655
|
}
|
|
2572
2656
|
}
|
|
2573
2657
|
function ChangelogList({ api, externalId, strings, onSelect }) {
|
|
2574
|
-
const [rows, setRows] =
|
|
2575
|
-
const [error, setError] =
|
|
2576
|
-
const [refreshing, setRefreshing] =
|
|
2658
|
+
const [rows, setRows] = useState4(null);
|
|
2659
|
+
const [error, setError] = useState4(null);
|
|
2660
|
+
const [refreshing, setRefreshing] = useState4(false);
|
|
2577
2661
|
const mountedRef = useRef2(true);
|
|
2578
2662
|
const fetchRows = async () => {
|
|
2579
2663
|
setRefreshing(true);
|
|
@@ -2606,8 +2690,8 @@ function ChangelogList({ api, externalId, strings, onSelect }) {
|
|
|
2606
2690
|
const isEmpty = rows !== null && rows.length === 0;
|
|
2607
2691
|
return /* @__PURE__ */ jsxs6("div", { class: "mine-list", children: [
|
|
2608
2692
|
/* @__PURE__ */ jsxs6("div", { class: "mine-list-header", children: [
|
|
2609
|
-
/* @__PURE__ */
|
|
2610
|
-
/* @__PURE__ */
|
|
2693
|
+
/* @__PURE__ */ jsx6("h2", { children: strings["tab.changelog"] }),
|
|
2694
|
+
/* @__PURE__ */ jsx6(
|
|
2611
2695
|
"button",
|
|
2612
2696
|
{
|
|
2613
2697
|
type: "button",
|
|
@@ -2620,20 +2704,20 @@ function ChangelogList({ api, externalId, strings, onSelect }) {
|
|
|
2620
2704
|
}
|
|
2621
2705
|
)
|
|
2622
2706
|
] }),
|
|
2623
|
-
isLoading && /* @__PURE__ */
|
|
2624
|
-
error && /* @__PURE__ */
|
|
2707
|
+
isLoading && /* @__PURE__ */ jsx6("div", { class: "mine-loading", children: strings["mine.loading"] }),
|
|
2708
|
+
error && /* @__PURE__ */ jsx6("div", { class: "error", children: error }),
|
|
2625
2709
|
isEmpty && /* @__PURE__ */ jsxs6("div", { class: "mine-empty", children: [
|
|
2626
|
-
/* @__PURE__ */
|
|
2627
|
-
/* @__PURE__ */
|
|
2710
|
+
/* @__PURE__ */ jsx6("strong", { children: strings["changelog.empty.title"] }),
|
|
2711
|
+
/* @__PURE__ */ jsx6("p", { children: strings["changelog.empty.body"] })
|
|
2628
2712
|
] }),
|
|
2629
|
-
groups.length > 0 && /* @__PURE__ */
|
|
2713
|
+
groups.length > 0 && /* @__PURE__ */ jsx6("div", { class: "changelog-groups", children: groups.map((g) => /* @__PURE__ */ jsxs6("section", { class: "changelog-group", children: [
|
|
2630
2714
|
/* @__PURE__ */ jsxs6("header", { class: "changelog-group-header", children: [
|
|
2631
|
-
/* @__PURE__ */
|
|
2632
|
-
/* @__PURE__ */
|
|
2633
|
-
/* @__PURE__ */
|
|
2634
|
-
/* @__PURE__ */
|
|
2715
|
+
/* @__PURE__ */ jsx6("span", { class: "changelog-group-marker", "aria-hidden": "true", children: "\u25CF" }),
|
|
2716
|
+
/* @__PURE__ */ jsx6("span", { class: "changelog-group-label", children: strings["changelog.week_of"].replace("{date}", g.label) }),
|
|
2717
|
+
/* @__PURE__ */ jsx6("span", { class: "changelog-group-rule", "aria-hidden": "true" }),
|
|
2718
|
+
/* @__PURE__ */ jsx6("span", { class: "changelog-group-count", children: strings[g.rows.length === 1 ? "changelog.resolved_one" : "changelog.resolved_many"].replace("{count}", String(g.rows.length)) })
|
|
2635
2719
|
] }),
|
|
2636
|
-
/* @__PURE__ */
|
|
2720
|
+
/* @__PURE__ */ jsx6("ul", { class: "mine-rows", children: g.rows.map((row) => /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsx6(
|
|
2637
2721
|
ReportRow,
|
|
2638
2722
|
{
|
|
2639
2723
|
row,
|
|
@@ -2647,7 +2731,7 @@ function ChangelogList({ api, externalId, strings, onSelect }) {
|
|
|
2647
2731
|
}
|
|
2648
2732
|
|
|
2649
2733
|
// src/widget/Fab.tsx
|
|
2650
|
-
import { jsx as
|
|
2734
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "preact/jsx-runtime";
|
|
2651
2735
|
function BugIcon() {
|
|
2652
2736
|
return /* @__PURE__ */ jsxs7(
|
|
2653
2737
|
"svg",
|
|
@@ -2663,34 +2747,34 @@ function BugIcon() {
|
|
|
2663
2747
|
"aria-hidden": "true",
|
|
2664
2748
|
focusable: "false",
|
|
2665
2749
|
children: [
|
|
2666
|
-
/* @__PURE__ */
|
|
2667
|
-
/* @__PURE__ */
|
|
2668
|
-
/* @__PURE__ */
|
|
2669
|
-
/* @__PURE__ */
|
|
2670
|
-
/* @__PURE__ */
|
|
2671
|
-
/* @__PURE__ */
|
|
2672
|
-
/* @__PURE__ */
|
|
2673
|
-
/* @__PURE__ */
|
|
2674
|
-
/* @__PURE__ */
|
|
2675
|
-
/* @__PURE__ */
|
|
2676
|
-
/* @__PURE__ */
|
|
2750
|
+
/* @__PURE__ */ jsx7("path", { d: "m8 2 1.88 1.88" }),
|
|
2751
|
+
/* @__PURE__ */ jsx7("path", { d: "M14.12 3.88 16 2" }),
|
|
2752
|
+
/* @__PURE__ */ jsx7("path", { d: "M9 7.13v-1a3.003 3.003 0 1 1 6 0v1" }),
|
|
2753
|
+
/* @__PURE__ */ jsx7("path", { d: "M12 20c-3.3 0-6-2.7-6-6v-3a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v3c0 3.3-2.7 6-6 6" }),
|
|
2754
|
+
/* @__PURE__ */ jsx7("path", { d: "M12 20v-9" }),
|
|
2755
|
+
/* @__PURE__ */ jsx7("path", { d: "M6.53 9C4.6 8.8 3 7.1 3 5" }),
|
|
2756
|
+
/* @__PURE__ */ jsx7("path", { d: "M6 13H2" }),
|
|
2757
|
+
/* @__PURE__ */ jsx7("path", { d: "M3 21c0-2.1 1.7-3.9 3.8-4" }),
|
|
2758
|
+
/* @__PURE__ */ jsx7("path", { d: "M20.97 5c0 2.1-1.6 3.8-3.5 4" }),
|
|
2759
|
+
/* @__PURE__ */ jsx7("path", { d: "M22 13h-4" }),
|
|
2760
|
+
/* @__PURE__ */ jsx7("path", { d: "M17.2 17c2.1.1 3.8 1.9 3.8 4" })
|
|
2677
2761
|
]
|
|
2678
2762
|
}
|
|
2679
2763
|
);
|
|
2680
2764
|
}
|
|
2681
2765
|
function Fab({ label, onClick, count }) {
|
|
2682
2766
|
return /* @__PURE__ */ jsxs7("button", { type: "button", class: "fab", "aria-label": label, title: label, onClick, children: [
|
|
2683
|
-
/* @__PURE__ */
|
|
2684
|
-
count !== void 0 && count > 0 && /* @__PURE__ */
|
|
2767
|
+
/* @__PURE__ */ jsx7(BugIcon, {}),
|
|
2768
|
+
count !== void 0 && count > 0 && /* @__PURE__ */ jsx7("span", { class: "fab-badge", "aria-hidden": "true", children: count > 9 ? "9+" : String(count) })
|
|
2685
2769
|
] });
|
|
2686
2770
|
}
|
|
2687
2771
|
|
|
2688
2772
|
// src/widget/Form.tsx
|
|
2689
|
-
import { useEffect as useEffect5, useRef as useRef4, useState as
|
|
2773
|
+
import { useEffect as useEffect5, useRef as useRef4, useState as useState6 } from "preact/hooks";
|
|
2690
2774
|
|
|
2691
2775
|
// src/widget/Annotator.tsx
|
|
2692
|
-
import { useEffect as useEffect4, useLayoutEffect, useRef as useRef3, useState as
|
|
2693
|
-
import { jsx as
|
|
2776
|
+
import { useEffect as useEffect4, useLayoutEffect, useRef as useRef3, useState as useState5 } from "preact/hooks";
|
|
2777
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "preact/jsx-runtime";
|
|
2694
2778
|
var COLORS = ["#ef4444", "#f59e0b", "#10b981", "#3b82f6", "#ffffff"];
|
|
2695
2779
|
var HIGHLIGHT_ALPHA = 0.35;
|
|
2696
2780
|
function drawShape(ctx, shape, sourceImage) {
|
|
@@ -2812,43 +2896,43 @@ function drawBlur(ctx, shape, sourceImage) {
|
|
|
2812
2896
|
ctx.imageSmoothingEnabled = true;
|
|
2813
2897
|
}
|
|
2814
2898
|
var Icon = {
|
|
2815
|
-
rect: /* @__PURE__ */
|
|
2816
|
-
arrow: /* @__PURE__ */
|
|
2817
|
-
pencil: /* @__PURE__ */
|
|
2818
|
-
text: /* @__PURE__ */
|
|
2899
|
+
rect: /* @__PURE__ */ jsx8("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("rect", { x: "2", y: "3", width: "12", height: "10", fill: "none", stroke: "currentColor", "stroke-width": "1.5" }) }),
|
|
2900
|
+
arrow: /* @__PURE__ */ jsx8("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M2 8h11M9 4l4 4-4 4", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }) }),
|
|
2901
|
+
pencil: /* @__PURE__ */ jsx8("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M11.5 2.5l2 2L5 13H3v-2l8.5-8.5z", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linejoin": "round" }) }),
|
|
2902
|
+
text: /* @__PURE__ */ jsx8("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M3 3h10M8 3v10M5 13h6", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round" }) }),
|
|
2819
2903
|
highlight: /* @__PURE__ */ jsxs8("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", children: [
|
|
2820
|
-
/* @__PURE__ */
|
|
2821
|
-
/* @__PURE__ */
|
|
2904
|
+
/* @__PURE__ */ jsx8("path", { d: "M3 13l3-3L11 5l-2-2-5 5-3 3v2h2zM10 4l2 2", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }),
|
|
2905
|
+
/* @__PURE__ */ jsx8("path", { d: "M2 14h12", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round" })
|
|
2822
2906
|
] }),
|
|
2823
2907
|
blur: /* @__PURE__ */ jsxs8("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", children: [
|
|
2824
|
-
/* @__PURE__ */
|
|
2825
|
-
/* @__PURE__ */
|
|
2826
|
-
/* @__PURE__ */
|
|
2827
|
-
/* @__PURE__ */
|
|
2828
|
-
/* @__PURE__ */
|
|
2829
|
-
/* @__PURE__ */
|
|
2830
|
-
/* @__PURE__ */
|
|
2831
|
-
/* @__PURE__ */
|
|
2832
|
-
/* @__PURE__ */
|
|
2908
|
+
/* @__PURE__ */ jsx8("rect", { x: "2", y: "2", width: "4", height: "4", fill: "currentColor", opacity: "0.85" }),
|
|
2909
|
+
/* @__PURE__ */ jsx8("rect", { x: "7", y: "2", width: "3", height: "3", fill: "currentColor", opacity: "0.55" }),
|
|
2910
|
+
/* @__PURE__ */ jsx8("rect", { x: "11", y: "2", width: "3", height: "4", fill: "currentColor", opacity: "0.4" }),
|
|
2911
|
+
/* @__PURE__ */ jsx8("rect", { x: "2", y: "7", width: "3", height: "3", fill: "currentColor", opacity: "0.6" }),
|
|
2912
|
+
/* @__PURE__ */ jsx8("rect", { x: "6", y: "7", width: "3", height: "3", fill: "currentColor", opacity: "0.85" }),
|
|
2913
|
+
/* @__PURE__ */ jsx8("rect", { x: "10", y: "7", width: "4", height: "3", fill: "currentColor", opacity: "0.5" }),
|
|
2914
|
+
/* @__PURE__ */ jsx8("rect", { x: "2", y: "11", width: "4", height: "3", fill: "currentColor", opacity: "0.4" }),
|
|
2915
|
+
/* @__PURE__ */ jsx8("rect", { x: "7", y: "11", width: "3", height: "3", fill: "currentColor", opacity: "0.65" }),
|
|
2916
|
+
/* @__PURE__ */ jsx8("rect", { x: "11", y: "11", width: "3", height: "3", fill: "currentColor", opacity: "0.85" })
|
|
2833
2917
|
] }),
|
|
2834
|
-
undo: /* @__PURE__ */
|
|
2835
|
-
redo: /* @__PURE__ */
|
|
2836
|
-
trash: /* @__PURE__ */
|
|
2837
|
-
close: /* @__PURE__ */
|
|
2918
|
+
undo: /* @__PURE__ */ jsx8("svg", { width: "14", height: "14", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M4 7l3-3M4 7l3 3M4 7h6a3 3 0 0 1 0 6H7", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }) }),
|
|
2919
|
+
redo: /* @__PURE__ */ jsx8("svg", { width: "14", height: "14", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M12 7l-3-3M12 7l-3 3M12 7H6a3 3 0 0 0 0 6h2", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }) }),
|
|
2920
|
+
trash: /* @__PURE__ */ jsx8("svg", { width: "14", height: "14", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M3 4h10M6 4V2.5h4V4M5 4l.5 9h5L11 4", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }) }),
|
|
2921
|
+
close: /* @__PURE__ */ jsx8("svg", { width: "16", height: "16", viewBox: "0 0 16 16", "aria-hidden": "true", children: /* @__PURE__ */ jsx8("path", { d: "M4 4l8 8M12 4l-8 8", fill: "none", stroke: "currentColor", "stroke-width": "1.5", "stroke-linecap": "round" }) })
|
|
2838
2922
|
};
|
|
2839
2923
|
function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
2840
2924
|
const canvasRef = useRef3(null);
|
|
2841
2925
|
const containerRef = useRef3(null);
|
|
2842
2926
|
const imageRef = useRef3(null);
|
|
2843
|
-
const [tool, setTool] =
|
|
2844
|
-
const [color, setColor] =
|
|
2845
|
-
const [shapes, setShapes] =
|
|
2846
|
-
const [past, setPast] =
|
|
2847
|
-
const [future, setFuture] =
|
|
2927
|
+
const [tool, setTool] = useState5("rectangle");
|
|
2928
|
+
const [color, setColor] = useState5(COLORS[0]);
|
|
2929
|
+
const [shapes, setShapes] = useState5([]);
|
|
2930
|
+
const [past, setPast] = useState5([]);
|
|
2931
|
+
const [future, setFuture] = useState5([]);
|
|
2848
2932
|
const isDrawingRef = useRef3(false);
|
|
2849
|
-
const [draftShape, setDraftShape] =
|
|
2850
|
-
const [imageLoaded, setImageLoaded] =
|
|
2851
|
-
const [saving, setSaving] =
|
|
2933
|
+
const [draftShape, setDraftShape] = useState5(null);
|
|
2934
|
+
const [imageLoaded, setImageLoaded] = useState5(false);
|
|
2935
|
+
const [saving, setSaving] = useState5(false);
|
|
2852
2936
|
const scaleRef = useRef3(1);
|
|
2853
2937
|
function addShape(shape) {
|
|
2854
2938
|
setShapes((s) => {
|
|
@@ -3068,7 +3152,7 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3068
3152
|
{ id: "highlight", icon: Icon.highlight, label: strings["annotator.tool.highlight"] },
|
|
3069
3153
|
{ id: "blur", icon: Icon.blur, label: strings["annotator.tool.blur"] }
|
|
3070
3154
|
];
|
|
3071
|
-
return /* @__PURE__ */
|
|
3155
|
+
return /* @__PURE__ */ jsx8(
|
|
3072
3156
|
"div",
|
|
3073
3157
|
{
|
|
3074
3158
|
class: "annotator-backdrop",
|
|
@@ -3078,8 +3162,8 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3078
3162
|
},
|
|
3079
3163
|
children: /* @__PURE__ */ jsxs8("div", { class: "annotator", role: "dialog", "aria-modal": "true", "aria-label": strings["annotator.title"], children: [
|
|
3080
3164
|
/* @__PURE__ */ jsxs8("div", { class: "annotator-header", children: [
|
|
3081
|
-
/* @__PURE__ */
|
|
3082
|
-
/* @__PURE__ */
|
|
3165
|
+
/* @__PURE__ */ jsx8("span", { children: strings["annotator.title"] }),
|
|
3166
|
+
/* @__PURE__ */ jsx8(
|
|
3083
3167
|
"button",
|
|
3084
3168
|
{
|
|
3085
3169
|
type: "button",
|
|
@@ -3091,7 +3175,7 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3091
3175
|
)
|
|
3092
3176
|
] }),
|
|
3093
3177
|
/* @__PURE__ */ jsxs8("div", { class: "annotator-toolbar", children: [
|
|
3094
|
-
/* @__PURE__ */
|
|
3178
|
+
/* @__PURE__ */ jsx8("div", { class: "annotator-tools", children: tools.map((t) => /* @__PURE__ */ jsx8(
|
|
3095
3179
|
"button",
|
|
3096
3180
|
{
|
|
3097
3181
|
type: "button",
|
|
@@ -3104,9 +3188,9 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3104
3188
|
},
|
|
3105
3189
|
t.id
|
|
3106
3190
|
)) }),
|
|
3107
|
-
/* @__PURE__ */
|
|
3191
|
+
/* @__PURE__ */ jsx8("span", { class: "annotator-sep" }),
|
|
3108
3192
|
/* @__PURE__ */ jsxs8("div", { class: "annotator-colors", children: [
|
|
3109
|
-
COLORS.map((c) => /* @__PURE__ */
|
|
3193
|
+
COLORS.map((c) => /* @__PURE__ */ jsx8(
|
|
3110
3194
|
"button",
|
|
3111
3195
|
{
|
|
3112
3196
|
type: "button",
|
|
@@ -3118,7 +3202,7 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3118
3202
|
},
|
|
3119
3203
|
c
|
|
3120
3204
|
)),
|
|
3121
|
-
/* @__PURE__ */
|
|
3205
|
+
/* @__PURE__ */ jsx8("label", { class: "annotator-color annotator-color-picker", title: strings["annotator.color_picker"], children: /* @__PURE__ */ jsx8(
|
|
3122
3206
|
"input",
|
|
3123
3207
|
{
|
|
3124
3208
|
type: "color",
|
|
@@ -3128,7 +3212,7 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3128
3212
|
}
|
|
3129
3213
|
) })
|
|
3130
3214
|
] }),
|
|
3131
|
-
/* @__PURE__ */
|
|
3215
|
+
/* @__PURE__ */ jsx8("span", { class: "annotator-sep" }),
|
|
3132
3216
|
/* @__PURE__ */ jsxs8(
|
|
3133
3217
|
"button",
|
|
3134
3218
|
{
|
|
@@ -3139,7 +3223,7 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3139
3223
|
title: strings["annotator.undo"],
|
|
3140
3224
|
children: [
|
|
3141
3225
|
Icon.undo,
|
|
3142
|
-
/* @__PURE__ */
|
|
3226
|
+
/* @__PURE__ */ jsx8("span", { children: strings["annotator.undo"] })
|
|
3143
3227
|
]
|
|
3144
3228
|
}
|
|
3145
3229
|
),
|
|
@@ -3153,7 +3237,7 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3153
3237
|
title: strings["annotator.redo"],
|
|
3154
3238
|
children: [
|
|
3155
3239
|
Icon.redo,
|
|
3156
|
-
/* @__PURE__ */
|
|
3240
|
+
/* @__PURE__ */ jsx8("span", { children: strings["annotator.redo"] })
|
|
3157
3241
|
]
|
|
3158
3242
|
}
|
|
3159
3243
|
),
|
|
@@ -3166,18 +3250,18 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3166
3250
|
disabled: shapes.length === 0,
|
|
3167
3251
|
children: [
|
|
3168
3252
|
Icon.trash,
|
|
3169
|
-
/* @__PURE__ */
|
|
3253
|
+
/* @__PURE__ */ jsx8("span", { children: strings["annotator.clear"] })
|
|
3170
3254
|
]
|
|
3171
3255
|
}
|
|
3172
3256
|
),
|
|
3173
|
-
/* @__PURE__ */
|
|
3257
|
+
/* @__PURE__ */ jsx8("span", { class: "annotator-spacer" }),
|
|
3174
3258
|
/* @__PURE__ */ jsxs8("span", { class: "annotator-count", children: [
|
|
3175
3259
|
shapes.length,
|
|
3176
3260
|
" ",
|
|
3177
3261
|
strings["annotator.count_suffix"]
|
|
3178
3262
|
] })
|
|
3179
3263
|
] }),
|
|
3180
|
-
/* @__PURE__ */
|
|
3264
|
+
/* @__PURE__ */ jsx8("div", { ref: containerRef, class: "annotator-canvas-wrap", children: !imageLoaded ? /* @__PURE__ */ jsx8("span", { class: "annotator-loading", children: strings["annotator.loading"] }) : /* @__PURE__ */ jsx8(
|
|
3181
3265
|
"canvas",
|
|
3182
3266
|
{
|
|
3183
3267
|
ref: canvasRef,
|
|
@@ -3189,8 +3273,8 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3189
3273
|
}
|
|
3190
3274
|
) }),
|
|
3191
3275
|
/* @__PURE__ */ jsxs8("div", { class: "annotator-footer", children: [
|
|
3192
|
-
/* @__PURE__ */
|
|
3193
|
-
/* @__PURE__ */
|
|
3276
|
+
/* @__PURE__ */ jsx8("button", { type: "button", class: "btn", onClick: onCancel, children: strings["form.cancel"] }),
|
|
3277
|
+
/* @__PURE__ */ jsx8(
|
|
3194
3278
|
"button",
|
|
3195
3279
|
{
|
|
3196
3280
|
type: "button",
|
|
@@ -3207,7 +3291,7 @@ function Annotator({ imageBlob, strings, onSave, onCancel }) {
|
|
|
3207
3291
|
}
|
|
3208
3292
|
|
|
3209
3293
|
// src/widget/Form.tsx
|
|
3210
|
-
import { jsx as
|
|
3294
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "preact/jsx-runtime";
|
|
3211
3295
|
var TYPES2 = ["bug", "feature", "question", "praise", "typo"];
|
|
3212
3296
|
var SEVERITIES2 = ["blocker", "high", "medium", "low"];
|
|
3213
3297
|
function Form({
|
|
@@ -3219,13 +3303,13 @@ function Form({
|
|
|
3219
3303
|
submittedSeq,
|
|
3220
3304
|
onDirtyChange
|
|
3221
3305
|
}) {
|
|
3222
|
-
const [description, setDescription] =
|
|
3223
|
-
const [feedbackType, setFeedbackType] =
|
|
3224
|
-
const [severity, setSeverity] =
|
|
3225
|
-
const [localError, setLocalError] =
|
|
3226
|
-
const [shots, setShots] =
|
|
3227
|
-
const [isDragOver, setIsDragOver] =
|
|
3228
|
-
const [annotatingIndex, setAnnotatingIndex] =
|
|
3306
|
+
const [description, setDescription] = useState6("");
|
|
3307
|
+
const [feedbackType, setFeedbackType] = useState6("bug");
|
|
3308
|
+
const [severity, setSeverity] = useState6("medium");
|
|
3309
|
+
const [localError, setLocalError] = useState6("");
|
|
3310
|
+
const [shots, setShots] = useState6([]);
|
|
3311
|
+
const [isDragOver, setIsDragOver] = useState6(false);
|
|
3312
|
+
const [annotatingIndex, setAnnotatingIndex] = useState6(null);
|
|
3229
3313
|
const fileInputRef = useRef4(null);
|
|
3230
3314
|
const dropZoneRef = useRef4(null);
|
|
3231
3315
|
const submitting = status === "submitting";
|
|
@@ -3347,10 +3431,10 @@ function Form({
|
|
|
3347
3431
|
onSubmit(values);
|
|
3348
3432
|
};
|
|
3349
3433
|
return /* @__PURE__ */ jsxs9("form", { onSubmit: handleSubmit, children: [
|
|
3350
|
-
/* @__PURE__ */
|
|
3434
|
+
/* @__PURE__ */ jsx9("h2", { children: strings["form.title"] }),
|
|
3351
3435
|
/* @__PURE__ */ jsxs9("div", { class: "field", children: [
|
|
3352
|
-
/* @__PURE__ */
|
|
3353
|
-
/* @__PURE__ */
|
|
3436
|
+
/* @__PURE__ */ jsx9("label", { for: "mfb-desc", children: strings["form.description.label"] }),
|
|
3437
|
+
/* @__PURE__ */ jsx9(
|
|
3354
3438
|
"textarea",
|
|
3355
3439
|
{
|
|
3356
3440
|
id: "mfb-desc",
|
|
@@ -3362,33 +3446,33 @@ function Form({
|
|
|
3362
3446
|
] }),
|
|
3363
3447
|
/* @__PURE__ */ jsxs9("div", { class: "row", children: [
|
|
3364
3448
|
/* @__PURE__ */ jsxs9("div", { class: "field", children: [
|
|
3365
|
-
/* @__PURE__ */
|
|
3366
|
-
/* @__PURE__ */
|
|
3449
|
+
/* @__PURE__ */ jsx9("label", { for: "mfb-type", children: strings["form.type.label"] }),
|
|
3450
|
+
/* @__PURE__ */ jsx9(
|
|
3367
3451
|
"select",
|
|
3368
3452
|
{
|
|
3369
3453
|
id: "mfb-type",
|
|
3370
3454
|
value: feedbackType,
|
|
3371
3455
|
onChange: (e) => setFeedbackType(e.target.value),
|
|
3372
|
-
children: TYPES2.map((t) => /* @__PURE__ */
|
|
3456
|
+
children: TYPES2.map((t) => /* @__PURE__ */ jsx9("option", { value: t, children: strings[`type.${t}`] }))
|
|
3373
3457
|
}
|
|
3374
3458
|
)
|
|
3375
3459
|
] }),
|
|
3376
3460
|
/* @__PURE__ */ jsxs9("div", { class: "field", children: [
|
|
3377
|
-
/* @__PURE__ */
|
|
3378
|
-
/* @__PURE__ */
|
|
3461
|
+
/* @__PURE__ */ jsx9("label", { for: "mfb-sev", children: strings["form.severity.label"] }),
|
|
3462
|
+
/* @__PURE__ */ jsx9(
|
|
3379
3463
|
"select",
|
|
3380
3464
|
{
|
|
3381
3465
|
id: "mfb-sev",
|
|
3382
3466
|
value: severity,
|
|
3383
3467
|
onChange: (e) => setSeverity(e.target.value),
|
|
3384
|
-
children: SEVERITIES2.map((s) => /* @__PURE__ */
|
|
3468
|
+
children: SEVERITIES2.map((s) => /* @__PURE__ */ jsx9("option", { value: s, children: strings[`severity.${s}`] }))
|
|
3385
3469
|
}
|
|
3386
3470
|
)
|
|
3387
3471
|
] })
|
|
3388
3472
|
] }),
|
|
3389
3473
|
/* @__PURE__ */ jsxs9("div", { class: "field", children: [
|
|
3390
|
-
/* @__PURE__ */
|
|
3391
|
-
/* @__PURE__ */
|
|
3474
|
+
/* @__PURE__ */ jsx9("label", { children: strings["form.screenshot.label"] }),
|
|
3475
|
+
/* @__PURE__ */ jsx9(
|
|
3392
3476
|
"input",
|
|
3393
3477
|
{
|
|
3394
3478
|
ref: fileInputRef,
|
|
@@ -3401,8 +3485,8 @@ function Form({
|
|
|
3401
3485
|
tabIndex: -1
|
|
3402
3486
|
}
|
|
3403
3487
|
),
|
|
3404
|
-
shots.length > 0 && /* @__PURE__ */
|
|
3405
|
-
/* @__PURE__ */
|
|
3488
|
+
shots.length > 0 && /* @__PURE__ */ jsx9("div", { class: "screenshot-strip", children: shots.map((shot, index) => /* @__PURE__ */ jsxs9("div", { class: "screenshot-preview", children: [
|
|
3489
|
+
/* @__PURE__ */ jsx9("img", { src: shot.preview, alt: "" }),
|
|
3406
3490
|
/* @__PURE__ */ jsxs9("div", { class: "screenshot-preview-actions", children: [
|
|
3407
3491
|
/* @__PURE__ */ jsxs9(
|
|
3408
3492
|
"button",
|
|
@@ -3412,15 +3496,15 @@ function Form({
|
|
|
3412
3496
|
onClick: () => setAnnotatingIndex(index),
|
|
3413
3497
|
children: [
|
|
3414
3498
|
/* @__PURE__ */ jsxs9("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: [
|
|
3415
|
-
/* @__PURE__ */
|
|
3416
|
-
/* @__PURE__ */
|
|
3499
|
+
/* @__PURE__ */ jsx9("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
|
|
3500
|
+
/* @__PURE__ */ jsx9("path", { d: "M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
|
|
3417
3501
|
] }),
|
|
3418
3502
|
strings["form.screenshot.annotate"]
|
|
3419
3503
|
]
|
|
3420
3504
|
}
|
|
3421
3505
|
),
|
|
3422
3506
|
/* @__PURE__ */ jsxs9("button", { type: "button", class: "btn", onClick: () => removeShot(index), children: [
|
|
3423
|
-
/* @__PURE__ */
|
|
3507
|
+
/* @__PURE__ */ jsx9("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx9("path", { d: "M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6h14z" }) }),
|
|
3424
3508
|
strings["form.screenshot.remove"]
|
|
3425
3509
|
] })
|
|
3426
3510
|
] })
|
|
@@ -3445,33 +3529,33 @@ function Form({
|
|
|
3445
3529
|
onDrop: handleDrop,
|
|
3446
3530
|
children: [
|
|
3447
3531
|
/* @__PURE__ */ jsxs9("svg", { class: "screenshot-icon", width: "28", height: "28", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "1.6", "stroke-linecap": "round", "stroke-linejoin": "round", "aria-hidden": "true", children: [
|
|
3448
|
-
/* @__PURE__ */
|
|
3449
|
-
/* @__PURE__ */
|
|
3450
|
-
/* @__PURE__ */
|
|
3532
|
+
/* @__PURE__ */ jsx9("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
|
|
3533
|
+
/* @__PURE__ */ jsx9("polyline", { points: "17 8 12 3 7 8" }),
|
|
3534
|
+
/* @__PURE__ */ jsx9("line", { x1: "12", y1: "3", x2: "12", y2: "15" })
|
|
3451
3535
|
] }),
|
|
3452
3536
|
/* @__PURE__ */ jsxs9("div", { class: "screenshot-cta", children: [
|
|
3453
|
-
/* @__PURE__ */
|
|
3537
|
+
/* @__PURE__ */ jsx9("strong", { children: strings["form.screenshot.cta_click"] }),
|
|
3454
3538
|
", ",
|
|
3455
3539
|
strings["form.screenshot.cta_rest"]
|
|
3456
3540
|
] }),
|
|
3457
|
-
/* @__PURE__ */
|
|
3541
|
+
/* @__PURE__ */ jsx9("div", { class: "screenshot-formats", children: strings["form.screenshot.formats"] })
|
|
3458
3542
|
]
|
|
3459
3543
|
}
|
|
3460
3544
|
)
|
|
3461
3545
|
] }),
|
|
3462
3546
|
pageUrl && /* @__PURE__ */ jsxs9("div", { class: "page-context", title: pageUrl, children: [
|
|
3463
|
-
/* @__PURE__ */
|
|
3464
|
-
/* @__PURE__ */
|
|
3547
|
+
/* @__PURE__ */ jsx9("span", { class: "page-context-label", children: strings["form.context.label"] }),
|
|
3548
|
+
/* @__PURE__ */ jsx9("span", { class: "page-context-url", children: truncateUrl(pageUrl, 90) })
|
|
3465
3549
|
] }),
|
|
3466
|
-
/* @__PURE__ */
|
|
3467
|
-
localError && /* @__PURE__ */
|
|
3468
|
-
status === "error" && errorMessage && /* @__PURE__ */
|
|
3469
|
-
status === "success" && /* @__PURE__ */
|
|
3550
|
+
/* @__PURE__ */ jsx9("div", { class: "capture-notice", children: strings["form.capture.notice"] }),
|
|
3551
|
+
localError && /* @__PURE__ */ jsx9("div", { class: "error", children: localError }),
|
|
3552
|
+
status === "error" && errorMessage && /* @__PURE__ */ jsx9("div", { class: "error", children: errorMessage }),
|
|
3553
|
+
status === "success" && /* @__PURE__ */ jsx9("div", { class: "success", children: submittedSeq !== void 0 ? strings["form.success.seq"].replace("{seq}", String(submittedSeq)) : strings["form.success"] }),
|
|
3470
3554
|
/* @__PURE__ */ jsxs9("div", { class: "actions", children: [
|
|
3471
|
-
/* @__PURE__ */
|
|
3472
|
-
/* @__PURE__ */
|
|
3555
|
+
/* @__PURE__ */ jsx9("button", { type: "button", class: "btn", onClick: onCancel, disabled: submitting, children: strings["form.cancel"] }),
|
|
3556
|
+
/* @__PURE__ */ jsx9("button", { type: "submit", class: "btn btn--primary", disabled: submitting, children: submitLabel })
|
|
3473
3557
|
] }),
|
|
3474
|
-
annotatingIndex !== null && shots[annotatingIndex] && /* @__PURE__ */
|
|
3558
|
+
annotatingIndex !== null && shots[annotatingIndex] && /* @__PURE__ */ jsx9(
|
|
3475
3559
|
Annotator,
|
|
3476
3560
|
{
|
|
3477
3561
|
imageBlob: shots[annotatingIndex].blob,
|
|
@@ -3484,10 +3568,10 @@ function Form({
|
|
|
3484
3568
|
}
|
|
3485
3569
|
|
|
3486
3570
|
// src/widget/MineList.tsx
|
|
3487
|
-
import { useEffect as useEffect6, useRef as useRef5, useState as
|
|
3571
|
+
import { useEffect as useEffect6, useRef as useRef5, useState as useState7 } from "preact/hooks";
|
|
3488
3572
|
|
|
3489
3573
|
// src/widget/KpiStrip.tsx
|
|
3490
|
-
import { jsx as
|
|
3574
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "preact/jsx-runtime";
|
|
3491
3575
|
function computeKpiCounts(rows) {
|
|
3492
3576
|
const counts = {
|
|
3493
3577
|
new: 0,
|
|
@@ -3554,7 +3638,7 @@ function KpiStrip({ rows, filter, onFilter, strings }) {
|
|
|
3554
3638
|
value: resolutionRate === null ? "\u2014" : `${resolutionRate}%`
|
|
3555
3639
|
}
|
|
3556
3640
|
];
|
|
3557
|
-
return /* @__PURE__ */
|
|
3641
|
+
return /* @__PURE__ */ jsx10("div", { class: "kpi-strip", role: "toolbar", children: cells.map((c) => {
|
|
3558
3642
|
const active = filter === c.key;
|
|
3559
3643
|
const toggleTo = active ? "all" : c.key;
|
|
3560
3644
|
return /* @__PURE__ */ jsxs10(
|
|
@@ -3565,8 +3649,8 @@ function KpiStrip({ rows, filter, onFilter, strings }) {
|
|
|
3565
3649
|
onClick: () => onFilter(toggleTo),
|
|
3566
3650
|
"aria-pressed": active,
|
|
3567
3651
|
children: [
|
|
3568
|
-
/* @__PURE__ */
|
|
3569
|
-
/* @__PURE__ */
|
|
3652
|
+
/* @__PURE__ */ jsx10("span", { class: "kpi-value", children: c.value }),
|
|
3653
|
+
/* @__PURE__ */ jsx10("span", { class: "kpi-label", children: c.label })
|
|
3570
3654
|
]
|
|
3571
3655
|
}
|
|
3572
3656
|
);
|
|
@@ -3574,16 +3658,30 @@ function KpiStrip({ rows, filter, onFilter, strings }) {
|
|
|
3574
3658
|
}
|
|
3575
3659
|
|
|
3576
3660
|
// src/widget/MineList.tsx
|
|
3577
|
-
import { jsx as
|
|
3661
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "preact/jsx-runtime";
|
|
3578
3662
|
var POLL_MS4 = 3e4;
|
|
3579
3663
|
function MineList({ api, externalId, strings, onSelect, onOpenSeq }) {
|
|
3580
|
-
const [rows, setRows] =
|
|
3581
|
-
const [error, setError] =
|
|
3582
|
-
const [refreshing, setRefreshing] =
|
|
3583
|
-
const [filter, setFilter] =
|
|
3584
|
-
const [
|
|
3585
|
-
const
|
|
3586
|
-
|
|
3664
|
+
const [rows, setRows] = useState7(null);
|
|
3665
|
+
const [error, setError] = useState7(null);
|
|
3666
|
+
const [refreshing, setRefreshing] = useState7(false);
|
|
3667
|
+
const [filter, setFilter] = useState7("all");
|
|
3668
|
+
const [validating, setValidating] = useState7(null);
|
|
3669
|
+
const validate = async (reportId, kind) => {
|
|
3670
|
+
setValidating(reportId);
|
|
3671
|
+
try {
|
|
3672
|
+
if (kind === "confirm") await api.closeAsResolved(reportId, externalId);
|
|
3673
|
+
else await api.reopenUnresolved(reportId, externalId);
|
|
3674
|
+
await fetchRows();
|
|
3675
|
+
} catch (err) {
|
|
3676
|
+
if (typeof console !== "undefined") console.warn("[mhosaic] validate:", err);
|
|
3677
|
+
if (mountedRef.current) setError(strings["mine.error"]);
|
|
3678
|
+
} finally {
|
|
3679
|
+
if (mountedRef.current) setValidating(null);
|
|
3680
|
+
}
|
|
3681
|
+
};
|
|
3682
|
+
const [jumpValue, setJumpValue] = useState7("");
|
|
3683
|
+
const [jumpError, setJumpError] = useState7(false);
|
|
3684
|
+
const [jumping, setJumping] = useState7(false);
|
|
3587
3685
|
const mountedRef = useRef5(true);
|
|
3588
3686
|
const handleJump = async (e) => {
|
|
3589
3687
|
e.preventDefault();
|
|
@@ -3635,10 +3733,10 @@ function MineList({ api, externalId, strings, onSelect, onOpenSeq }) {
|
|
|
3635
3733
|
const visibleEmpty = !!rows && rows.length > 0 && (visibleRows?.length ?? 0) === 0;
|
|
3636
3734
|
return /* @__PURE__ */ jsxs11("div", { class: "mine-list", children: [
|
|
3637
3735
|
/* @__PURE__ */ jsxs11("div", { class: "mine-list-header", children: [
|
|
3638
|
-
/* @__PURE__ */
|
|
3736
|
+
/* @__PURE__ */ jsx11("h2", { children: strings["tab.mine"] }),
|
|
3639
3737
|
/* @__PURE__ */ jsxs11("div", { class: "mine-list-header-actions", children: [
|
|
3640
3738
|
onOpenSeq && /* @__PURE__ */ jsxs11("form", { class: "mine-jump", onSubmit: handleJump, children: [
|
|
3641
|
-
/* @__PURE__ */
|
|
3739
|
+
/* @__PURE__ */ jsx11(
|
|
3642
3740
|
"input",
|
|
3643
3741
|
{
|
|
3644
3742
|
type: "text",
|
|
@@ -3653,9 +3751,9 @@ function MineList({ api, externalId, strings, onSelect, onOpenSeq }) {
|
|
|
3653
3751
|
disabled: jumping
|
|
3654
3752
|
}
|
|
3655
3753
|
),
|
|
3656
|
-
/* @__PURE__ */
|
|
3754
|
+
/* @__PURE__ */ jsx11("button", { type: "submit", class: "btn", disabled: jumping || !jumpValue.trim(), children: strings["mine.jump.go"] })
|
|
3657
3755
|
] }),
|
|
3658
|
-
/* @__PURE__ */
|
|
3756
|
+
/* @__PURE__ */ jsx11(
|
|
3659
3757
|
"button",
|
|
3660
3758
|
{
|
|
3661
3759
|
type: "button",
|
|
@@ -3669,22 +3767,68 @@ function MineList({ api, externalId, strings, onSelect, onOpenSeq }) {
|
|
|
3669
3767
|
)
|
|
3670
3768
|
] })
|
|
3671
3769
|
] }),
|
|
3672
|
-
jumpError && /* @__PURE__ */
|
|
3673
|
-
rows && rows.
|
|
3674
|
-
|
|
3675
|
-
|
|
3770
|
+
jumpError && /* @__PURE__ */ jsx11("div", { class: "mine-jump-error error", role: "alert", children: strings["mine.jump.not_found"] }),
|
|
3771
|
+
rows && rows.some((r) => r.status === "awaiting_validation") && /* @__PURE__ */ jsxs11("div", { class: "validate-banner", role: "status", children: [
|
|
3772
|
+
/* @__PURE__ */ jsx11("span", { children: strings["mine.validate.banner"].replace(
|
|
3773
|
+
"{count}",
|
|
3774
|
+
String(rows.filter((r) => r.status === "awaiting_validation").length)
|
|
3775
|
+
) }),
|
|
3776
|
+
/* @__PURE__ */ jsx11(
|
|
3777
|
+
"button",
|
|
3778
|
+
{
|
|
3779
|
+
type: "button",
|
|
3780
|
+
class: "btn",
|
|
3781
|
+
onClick: () => setFilter("awaiting_validation"),
|
|
3782
|
+
children: strings["mine.validate.view"]
|
|
3783
|
+
}
|
|
3784
|
+
)
|
|
3785
|
+
] }),
|
|
3786
|
+
rows && rows.length > 0 && /* @__PURE__ */ jsx11(KpiStrip, { rows, filter, onFilter: setFilter, strings }),
|
|
3787
|
+
isLoading && /* @__PURE__ */ jsx11("div", { class: "mine-loading", children: strings["mine.loading"] }),
|
|
3788
|
+
error && /* @__PURE__ */ jsxs11("div", { class: "error", children: [
|
|
3789
|
+
error,
|
|
3790
|
+
/* @__PURE__ */ jsx11(DiagnosticHint, { api, strings, host: api.endpointHost })
|
|
3791
|
+
] }),
|
|
3676
3792
|
isEmpty && /* @__PURE__ */ jsxs11("div", { class: "mine-empty", children: [
|
|
3677
|
-
/* @__PURE__ */
|
|
3678
|
-
/* @__PURE__ */
|
|
3793
|
+
/* @__PURE__ */ jsx11("strong", { children: strings["mine.empty.title"] }),
|
|
3794
|
+
/* @__PURE__ */ jsx11("p", { children: strings["mine.empty.body"] })
|
|
3679
3795
|
] }),
|
|
3680
|
-
visibleEmpty && /* @__PURE__ */
|
|
3681
|
-
visibleRows && visibleRows.length > 0 && /* @__PURE__ */
|
|
3796
|
+
visibleEmpty && /* @__PURE__ */ jsx11("div", { class: "mine-empty", children: /* @__PURE__ */ jsx11("p", { children: strings["mine.filter.empty"] }) }),
|
|
3797
|
+
visibleRows && visibleRows.length > 0 && /* @__PURE__ */ jsx11("ul", { class: "mine-rows", children: visibleRows.map((row) => /* @__PURE__ */ jsxs11("li", { children: [
|
|
3798
|
+
/* @__PURE__ */ jsx11(ReportRow, { row, strings, onClick: () => onSelect(row) }),
|
|
3799
|
+
row.status === "awaiting_validation" && /* @__PURE__ */ jsxs11("div", { class: "validate-actions", children: [
|
|
3800
|
+
/* @__PURE__ */ jsx11(
|
|
3801
|
+
"button",
|
|
3802
|
+
{
|
|
3803
|
+
type: "button",
|
|
3804
|
+
class: "btn",
|
|
3805
|
+
disabled: validating === row.id,
|
|
3806
|
+
onClick: () => {
|
|
3807
|
+
void validate(row.id, "confirm");
|
|
3808
|
+
},
|
|
3809
|
+
children: strings["mine.validate.confirm"]
|
|
3810
|
+
}
|
|
3811
|
+
),
|
|
3812
|
+
/* @__PURE__ */ jsx11(
|
|
3813
|
+
"button",
|
|
3814
|
+
{
|
|
3815
|
+
type: "button",
|
|
3816
|
+
class: "btn btn--ghost",
|
|
3817
|
+
disabled: validating === row.id,
|
|
3818
|
+
onClick: () => {
|
|
3819
|
+
void validate(row.id, "reopen");
|
|
3820
|
+
},
|
|
3821
|
+
children: strings["mine.validate.reopen"]
|
|
3822
|
+
}
|
|
3823
|
+
)
|
|
3824
|
+
] })
|
|
3825
|
+
] })) })
|
|
3682
3826
|
] });
|
|
3683
3827
|
}
|
|
3684
3828
|
|
|
3685
3829
|
// src/widget/Modal.tsx
|
|
3686
3830
|
import { useEffect as useEffect7, useRef as useRef6 } from "preact/hooks";
|
|
3687
|
-
import { jsx as
|
|
3831
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
|
|
3688
3832
|
function Modal({ onDismiss, children, closeLabel = "Close", expanded = false }) {
|
|
3689
3833
|
const modalRef = useRef6(null);
|
|
3690
3834
|
const previouslyFocused = useRef6(null);
|
|
@@ -3710,7 +3854,7 @@ function Modal({ onDismiss, children, closeLabel = "Close", expanded = false })
|
|
|
3710
3854
|
if (prev && typeof prev.focus === "function") prev.focus();
|
|
3711
3855
|
};
|
|
3712
3856
|
}, [onDismiss]);
|
|
3713
|
-
return /* @__PURE__ */
|
|
3857
|
+
return /* @__PURE__ */ jsx12(
|
|
3714
3858
|
"div",
|
|
3715
3859
|
{
|
|
3716
3860
|
class: `backdrop ${expanded ? "is-expanded" : ""}`,
|
|
@@ -3726,7 +3870,7 @@ function Modal({ onDismiss, children, closeLabel = "Close", expanded = false })
|
|
|
3726
3870
|
role: "dialog",
|
|
3727
3871
|
"aria-modal": "true",
|
|
3728
3872
|
children: [
|
|
3729
|
-
/* @__PURE__ */
|
|
3873
|
+
/* @__PURE__ */ jsx12(
|
|
3730
3874
|
"button",
|
|
3731
3875
|
{
|
|
3732
3876
|
type: "button",
|
|
@@ -3745,7 +3889,7 @@ function Modal({ onDismiss, children, closeLabel = "Close", expanded = false })
|
|
|
3745
3889
|
}
|
|
3746
3890
|
|
|
3747
3891
|
// src/widget/PageActivityStrip.tsx
|
|
3748
|
-
import { jsx as
|
|
3892
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
|
|
3749
3893
|
function PageActivityStrip({
|
|
3750
3894
|
open,
|
|
3751
3895
|
strings,
|
|
@@ -3754,14 +3898,14 @@ function PageActivityStrip({
|
|
|
3754
3898
|
if (open === 0) return null;
|
|
3755
3899
|
const text = open === 1 ? strings["page.strip.text.one"] : strings["page.strip.text"].replace("{n}", String(open));
|
|
3756
3900
|
return /* @__PURE__ */ jsxs13("div", { class: "page-strip", children: [
|
|
3757
|
-
/* @__PURE__ */
|
|
3758
|
-
/* @__PURE__ */
|
|
3901
|
+
/* @__PURE__ */ jsx13("span", { children: text }),
|
|
3902
|
+
/* @__PURE__ */ jsx13("button", { type: "button", class: "page-strip-view", onClick: onView, children: strings["page.strip.view"] })
|
|
3759
3903
|
] });
|
|
3760
3904
|
}
|
|
3761
3905
|
|
|
3762
3906
|
// src/widget/PagePeekPanel.tsx
|
|
3763
|
-
import { useEffect as useEffect8, useState as
|
|
3764
|
-
import { jsx as
|
|
3907
|
+
import { useEffect as useEffect8, useState as useState8 } from "preact/hooks";
|
|
3908
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
|
|
3765
3909
|
function PagePeekPanel({
|
|
3766
3910
|
api,
|
|
3767
3911
|
externalId,
|
|
@@ -3772,8 +3916,8 @@ function PagePeekPanel({
|
|
|
3772
3916
|
onPickRow,
|
|
3773
3917
|
onSend
|
|
3774
3918
|
}) {
|
|
3775
|
-
const [rows, setRows] =
|
|
3776
|
-
const [failed, setFailed] =
|
|
3919
|
+
const [rows, setRows] = useState8(null);
|
|
3920
|
+
const [failed, setFailed] = useState8(false);
|
|
3777
3921
|
useEffect8(() => {
|
|
3778
3922
|
let cancelled = false;
|
|
3779
3923
|
const pagePath = currentPagePath(getCurrentPage !== void 0 ? { getCurrentPage } : {});
|
|
@@ -3790,11 +3934,11 @@ function PagePeekPanel({
|
|
|
3790
3934
|
};
|
|
3791
3935
|
}, [api, externalId]);
|
|
3792
3936
|
return /* @__PURE__ */ jsxs14("div", { class: "page-peek", role: "region", "aria-label": strings["page.peek.title"], children: [
|
|
3793
|
-
/* @__PURE__ */
|
|
3937
|
+
/* @__PURE__ */ jsx14("div", { class: "page-peek-title", children: strings["page.peek.title"] }),
|
|
3794
3938
|
rows === null && !failed && /* @__PURE__ */ jsxs14("div", { class: "page-peek-skeleton", "aria-hidden": "true", children: [
|
|
3795
|
-
/* @__PURE__ */
|
|
3939
|
+
/* @__PURE__ */ jsx14("div", {}),
|
|
3796
3940
|
" ",
|
|
3797
|
-
/* @__PURE__ */
|
|
3941
|
+
/* @__PURE__ */ jsx14("div", {})
|
|
3798
3942
|
] }),
|
|
3799
3943
|
rows !== null && rows.map((row) => /* @__PURE__ */ jsxs14(
|
|
3800
3944
|
"button",
|
|
@@ -3803,21 +3947,21 @@ function PagePeekPanel({
|
|
|
3803
3947
|
class: "page-peek-row",
|
|
3804
3948
|
onClick: () => onPickRow?.(row.id),
|
|
3805
3949
|
children: [
|
|
3806
|
-
/* @__PURE__ */
|
|
3807
|
-
/* @__PURE__ */
|
|
3950
|
+
/* @__PURE__ */ jsx14("span", { class: `page-peek-dot status-${row.status}`, "aria-hidden": "true" }),
|
|
3951
|
+
/* @__PURE__ */ jsx14("span", { class: "page-peek-desc", children: row.description })
|
|
3808
3952
|
]
|
|
3809
3953
|
},
|
|
3810
3954
|
row.id
|
|
3811
3955
|
)),
|
|
3812
3956
|
/* @__PURE__ */ jsxs14("div", { class: "page-peek-footer", children: [
|
|
3813
|
-
/* @__PURE__ */
|
|
3814
|
-
/* @__PURE__ */
|
|
3957
|
+
/* @__PURE__ */ jsx14("button", { type: "button", class: "page-peek-viewall", onClick: onViewAll, children: open === 1 ? strings["page.peek.viewAll.one"] : strings["page.peek.viewAll"].replace("{n}", String(open)) }),
|
|
3958
|
+
/* @__PURE__ */ jsx14("button", { type: "button", class: "page-peek-send", onClick: onSend, children: strings["fab.label"] })
|
|
3815
3959
|
] })
|
|
3816
3960
|
] });
|
|
3817
3961
|
}
|
|
3818
3962
|
|
|
3819
3963
|
// src/widget/pageSignal.ts
|
|
3820
|
-
import { useCallback, useEffect as useEffect9, useState as
|
|
3964
|
+
import { useCallback, useEffect as useEffect9, useState as useState9 } from "preact/hooks";
|
|
3821
3965
|
var TTL_MS2 = 6e4;
|
|
3822
3966
|
function computeOpenCount(kpis) {
|
|
3823
3967
|
const s = kpis.by_status;
|
|
@@ -3846,8 +3990,8 @@ function fetchOpen(api, externalId, path) {
|
|
|
3846
3990
|
}
|
|
3847
3991
|
function usePageOpenCount(opts) {
|
|
3848
3992
|
const { api, externalId, getCurrentPage, enabled } = opts;
|
|
3849
|
-
const [open, setOpen] =
|
|
3850
|
-
const [tick, setTick] =
|
|
3993
|
+
const [open, setOpen] = useState9(0);
|
|
3994
|
+
const [tick, setTick] = useState9(0);
|
|
3851
3995
|
const refresh = useCallback(() => {
|
|
3852
3996
|
invalidatePageSignal();
|
|
3853
3997
|
setTick((t) => t + 1);
|
|
@@ -4696,6 +4840,22 @@ var WIDGET_STYLES = `
|
|
|
4696
4840
|
}
|
|
4697
4841
|
.mine-empty strong { display: block; color: var(--mfb-text); margin-bottom: 4px; }
|
|
4698
4842
|
|
|
4843
|
+
.validate-banner {
|
|
4844
|
+
display: flex;
|
|
4845
|
+
align-items: center;
|
|
4846
|
+
justify-content: space-between;
|
|
4847
|
+
gap: 8px;
|
|
4848
|
+
padding: 8px 12px;
|
|
4849
|
+
margin-bottom: 8px;
|
|
4850
|
+
border: 1px solid var(--mfb-accent, #2563eb);
|
|
4851
|
+
border-radius: 8px;
|
|
4852
|
+
font-size: 13px;
|
|
4853
|
+
}
|
|
4854
|
+
.validate-actions {
|
|
4855
|
+
display: flex;
|
|
4856
|
+
gap: 8px;
|
|
4857
|
+
margin: 4px 0 8px;
|
|
4858
|
+
}
|
|
4699
4859
|
.mine-rows {
|
|
4700
4860
|
list-style: none;
|
|
4701
4861
|
margin: 0;
|
|
@@ -5942,7 +6102,7 @@ button.report-detail-edit {
|
|
|
5942
6102
|
`;
|
|
5943
6103
|
|
|
5944
6104
|
// src/widget/mount.tsx
|
|
5945
|
-
import { Fragment as Fragment3, jsx as
|
|
6105
|
+
import { Fragment as Fragment3, jsx as jsx15, jsxs as jsxs15 } from "preact/jsx-runtime";
|
|
5946
6106
|
function computeFabVisible(opts, externalId, visibilityAllowed) {
|
|
5947
6107
|
if (!opts.showFAB) return false;
|
|
5948
6108
|
if (opts.getExternalId !== void 0 && !externalId) return false;
|
|
@@ -6040,7 +6200,7 @@ function mountWidget(options) {
|
|
|
6040
6200
|
enabled: pageActivityEnabled
|
|
6041
6201
|
});
|
|
6042
6202
|
const fabLabel = pageSignal.open === 1 ? options.strings["page.badge.aria.one"] : pageSignal.open > 0 ? options.strings["page.badge.aria"].replace("{n}", String(pageSignal.open)) : options.strings["fab.label"];
|
|
6043
|
-
const [visibilityAllowed, setVisibilityAllowed] =
|
|
6203
|
+
const [visibilityAllowed, setVisibilityAllowed] = useState10(
|
|
6044
6204
|
!options.requiresVisibilityCheck
|
|
6045
6205
|
);
|
|
6046
6206
|
useEffect10(() => {
|
|
@@ -6064,7 +6224,7 @@ function mountWidget(options) {
|
|
|
6064
6224
|
}, [externalId]);
|
|
6065
6225
|
const fabVisible = computeFabVisible(options, externalId, visibilityAllowed);
|
|
6066
6226
|
const showMineTab = Boolean(options.api && externalId);
|
|
6067
|
-
const [peekOpen, setPeekOpen] =
|
|
6227
|
+
const [peekOpen, setPeekOpen] = useState10(false);
|
|
6068
6228
|
const peekTimers = useRef7({});
|
|
6069
6229
|
const peekEnter = () => {
|
|
6070
6230
|
if (peekTimers.current.close) clearTimeout(peekTimers.current.close);
|
|
@@ -6088,7 +6248,7 @@ function mountWidget(options) {
|
|
|
6088
6248
|
onFocusOut: () => setPeekOpen(false),
|
|
6089
6249
|
onKeyDown: (e) => e.key === "Escape" && setPeekOpen(false),
|
|
6090
6250
|
children: [
|
|
6091
|
-
peekOpen && !state.open && pageActivityEnabled && pageSignal.open > 0 && options.api && externalId && /* @__PURE__ */
|
|
6251
|
+
peekOpen && !state.open && pageActivityEnabled && pageSignal.open > 0 && options.api && externalId && /* @__PURE__ */ jsx15(
|
|
6092
6252
|
PagePeekPanel,
|
|
6093
6253
|
{
|
|
6094
6254
|
api: options.api,
|
|
@@ -6112,7 +6272,7 @@ function mountWidget(options) {
|
|
|
6112
6272
|
}
|
|
6113
6273
|
}
|
|
6114
6274
|
),
|
|
6115
|
-
/* @__PURE__ */
|
|
6275
|
+
/* @__PURE__ */ jsx15(
|
|
6116
6276
|
Fab,
|
|
6117
6277
|
{
|
|
6118
6278
|
label: fabLabel,
|
|
@@ -6144,11 +6304,11 @@ function mountWidget(options) {
|
|
|
6144
6304
|
closeLabel: options.strings["form.close"],
|
|
6145
6305
|
expanded: state.tab === "board",
|
|
6146
6306
|
children: [
|
|
6147
|
-
state.confirmingDiscard && /* @__PURE__ */
|
|
6148
|
-
/* @__PURE__ */
|
|
6149
|
-
/* @__PURE__ */
|
|
6307
|
+
state.confirmingDiscard && /* @__PURE__ */ jsx15("div", { class: "discard-confirm", role: "alertdialog", "aria-modal": "true", children: /* @__PURE__ */ jsxs15("div", { class: "discard-confirm-card", children: [
|
|
6308
|
+
/* @__PURE__ */ jsx15("p", { class: "discard-confirm-title", children: options.strings["form.discard.title"] }),
|
|
6309
|
+
/* @__PURE__ */ jsx15("p", { class: "discard-confirm-body", children: options.strings["form.discard.body"] }),
|
|
6150
6310
|
/* @__PURE__ */ jsxs15("div", { class: "discard-confirm-actions", children: [
|
|
6151
|
-
/* @__PURE__ */
|
|
6311
|
+
/* @__PURE__ */ jsx15(
|
|
6152
6312
|
"button",
|
|
6153
6313
|
{
|
|
6154
6314
|
type: "button",
|
|
@@ -6157,7 +6317,7 @@ function mountWidget(options) {
|
|
|
6157
6317
|
children: options.strings["form.discard.keep"]
|
|
6158
6318
|
}
|
|
6159
6319
|
),
|
|
6160
|
-
/* @__PURE__ */
|
|
6320
|
+
/* @__PURE__ */ jsx15(
|
|
6161
6321
|
"button",
|
|
6162
6322
|
{
|
|
6163
6323
|
type: "button",
|
|
@@ -6179,7 +6339,7 @@ function mountWidget(options) {
|
|
|
6179
6339
|
] })
|
|
6180
6340
|
] }) }),
|
|
6181
6341
|
showMineTab && /* @__PURE__ */ jsxs15("div", { class: "tab-strip", role: "tablist", children: [
|
|
6182
|
-
/* @__PURE__ */
|
|
6342
|
+
/* @__PURE__ */ jsx15(
|
|
6183
6343
|
"button",
|
|
6184
6344
|
{
|
|
6185
6345
|
type: "button",
|
|
@@ -6190,7 +6350,7 @@ function mountWidget(options) {
|
|
|
6190
6350
|
children: options.strings["tab.send"]
|
|
6191
6351
|
}
|
|
6192
6352
|
),
|
|
6193
|
-
/* @__PURE__ */
|
|
6353
|
+
/* @__PURE__ */ jsx15(
|
|
6194
6354
|
"button",
|
|
6195
6355
|
{
|
|
6196
6356
|
type: "button",
|
|
@@ -6201,7 +6361,7 @@ function mountWidget(options) {
|
|
|
6201
6361
|
children: options.strings["tab.mine"]
|
|
6202
6362
|
}
|
|
6203
6363
|
),
|
|
6204
|
-
/* @__PURE__ */
|
|
6364
|
+
/* @__PURE__ */ jsx15(
|
|
6205
6365
|
"button",
|
|
6206
6366
|
{
|
|
6207
6367
|
type: "button",
|
|
@@ -6212,7 +6372,7 @@ function mountWidget(options) {
|
|
|
6212
6372
|
children: options.strings["tab.changelog"]
|
|
6213
6373
|
}
|
|
6214
6374
|
),
|
|
6215
|
-
/* @__PURE__ */
|
|
6375
|
+
/* @__PURE__ */ jsx15(
|
|
6216
6376
|
"button",
|
|
6217
6377
|
{
|
|
6218
6378
|
type: "button",
|
|
@@ -6225,7 +6385,7 @@ function mountWidget(options) {
|
|
|
6225
6385
|
)
|
|
6226
6386
|
] }),
|
|
6227
6387
|
state.tab === "send" && /* @__PURE__ */ jsxs15(Fragment3, { children: [
|
|
6228
|
-
showMineTab && pageActivityEnabled && /* @__PURE__ */
|
|
6388
|
+
showMineTab && pageActivityEnabled && /* @__PURE__ */ jsx15(
|
|
6229
6389
|
PageActivityStrip,
|
|
6230
6390
|
{
|
|
6231
6391
|
open: pageSignal.open,
|
|
@@ -6233,7 +6393,7 @@ function mountWidget(options) {
|
|
|
6233
6393
|
onView: () => rerender(clearSelected({ ...currentState, tab: "board" }))
|
|
6234
6394
|
}
|
|
6235
6395
|
),
|
|
6236
|
-
/* @__PURE__ */
|
|
6396
|
+
/* @__PURE__ */ jsx15(
|
|
6237
6397
|
Form,
|
|
6238
6398
|
{
|
|
6239
6399
|
strings: options.strings,
|
|
@@ -6250,7 +6410,7 @@ function mountWidget(options) {
|
|
|
6250
6410
|
}
|
|
6251
6411
|
)
|
|
6252
6412
|
] }),
|
|
6253
|
-
state.tab === "mine" && options.api && externalId && !state.selectedReportId && /* @__PURE__ */
|
|
6413
|
+
state.tab === "mine" && options.api && externalId && !state.selectedReportId && /* @__PURE__ */ jsx15(
|
|
6254
6414
|
MineList,
|
|
6255
6415
|
{
|
|
6256
6416
|
api: options.api,
|
|
@@ -6260,7 +6420,7 @@ function mountWidget(options) {
|
|
|
6260
6420
|
onOpenSeq: openSeq
|
|
6261
6421
|
}
|
|
6262
6422
|
),
|
|
6263
|
-
(state.tab === "mine" || state.tab === "changelog") && options.api && externalId && state.selectedReportId && /* @__PURE__ */
|
|
6423
|
+
(state.tab === "mine" || state.tab === "changelog") && options.api && externalId && state.selectedReportId && /* @__PURE__ */ jsx15(
|
|
6264
6424
|
ReportDetailView,
|
|
6265
6425
|
{
|
|
6266
6426
|
api: options.api,
|
|
@@ -6272,7 +6432,7 @@ function mountWidget(options) {
|
|
|
6272
6432
|
...buildPermalink && { buildPermalink }
|
|
6273
6433
|
}
|
|
6274
6434
|
),
|
|
6275
|
-
state.tab === "changelog" && options.api && externalId && !state.selectedReportId && /* @__PURE__ */
|
|
6435
|
+
state.tab === "changelog" && options.api && externalId && !state.selectedReportId && /* @__PURE__ */ jsx15(
|
|
6276
6436
|
ChangelogList,
|
|
6277
6437
|
{
|
|
6278
6438
|
api: options.api,
|
|
@@ -6283,7 +6443,7 @@ function mountWidget(options) {
|
|
|
6283
6443
|
),
|
|
6284
6444
|
state.tab === "board" && options.api && externalId && // BoardView owns its own master/detail navigation — no
|
|
6285
6445
|
// selectedReportId routing through the modal-level state.
|
|
6286
|
-
/* @__PURE__ */
|
|
6446
|
+
/* @__PURE__ */ jsx15(
|
|
6287
6447
|
BoardView,
|
|
6288
6448
|
{
|
|
6289
6449
|
api: options.api,
|
|
@@ -6404,8 +6564,8 @@ function createFeedback(config) {
|
|
|
6404
6564
|
capture_method: captureMethod,
|
|
6405
6565
|
technical_context
|
|
6406
6566
|
};
|
|
6407
|
-
if ("0.
|
|
6408
|
-
payload.widget_version = "0.
|
|
6567
|
+
if ("0.34.0") {
|
|
6568
|
+
payload.widget_version = "0.34.0";
|
|
6409
6569
|
}
|
|
6410
6570
|
if (manualScreenshots?.length) {
|
|
6411
6571
|
payload.screenshots = manualScreenshots;
|
|
@@ -6531,4 +6691,4 @@ function createFeedback(config) {
|
|
|
6531
6691
|
export {
|
|
6532
6692
|
createFeedback
|
|
6533
6693
|
};
|
|
6534
|
-
//# sourceMappingURL=chunk-
|
|
6694
|
+
//# sourceMappingURL=chunk-J45ACCSP.mjs.map
|