@mhosaic/feedback 0.26.0 → 0.27.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/README.md +24 -0
- package/dist/{chunk-FYF5KICC.mjs → chunk-BXUX5UTI.mjs} +571 -93
- package/dist/chunk-BXUX5UTI.mjs.map +1 -0
- package/dist/embed.min.js +183 -6
- package/dist/embed.min.js.map +1 -1
- package/dist/error-tracking.d.ts +1 -1
- package/dist/{index-B8Q72Whs.d.ts → index-BYDyenfe.d.ts} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/loader/react.d.ts +1 -1
- package/dist/loader.d.ts +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/react.mjs +1 -1
- package/dist/replay.d.ts +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/{types-CRCxVLFH.d.ts → types-C4iSSmUD.d.ts} +4 -0
- package/dist/webvitals.d.ts +1 -1
- package/dist/widget.min.js +184 -7
- package/dist/widget.min.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-FYF5KICC.mjs.map +0 -1
|
@@ -555,6 +555,14 @@ function installCapture(options = {}) {
|
|
|
555
555
|
// src/widget/i18n.ts
|
|
556
556
|
var DEFAULT_STRINGS = {
|
|
557
557
|
"fab.label": "Send feedback",
|
|
558
|
+
"page.badge.aria": "Feedback \u2014 {n} open on this page",
|
|
559
|
+
"page.badge.aria.one": "Feedback \u2014 1 open on this page",
|
|
560
|
+
"page.strip.text": "{n} open reports on this page",
|
|
561
|
+
"page.strip.text.one": "1 open report on this page",
|
|
562
|
+
"page.strip.view": "View",
|
|
563
|
+
"page.peek.title": "On this page",
|
|
564
|
+
"page.peek.viewAll": "View all {n}",
|
|
565
|
+
"page.peek.viewAll.one": "View 1 open report",
|
|
558
566
|
"form.title": "Send feedback",
|
|
559
567
|
"form.description.label": "What happened?",
|
|
560
568
|
"form.description.placeholder": "Describe the issue or idea in one or two sentences.",
|
|
@@ -639,6 +647,11 @@ var DEFAULT_STRINGS = {
|
|
|
639
647
|
"board.scope.project": "Project reports",
|
|
640
648
|
"board.scope.mine": "Your reports",
|
|
641
649
|
"board.scope.thisPage": "This page",
|
|
650
|
+
"board.scope.allPages": "All pages",
|
|
651
|
+
"board.scope.onThisPage": "on this page",
|
|
652
|
+
"board.list.count.page": "{n} of {total} \xB7 this page",
|
|
653
|
+
"board.list.empty.page.title": "No feedback on this page yet.",
|
|
654
|
+
"board.list.empty.page.description": "Be the first to report something here \u2014 or browse the whole project.",
|
|
642
655
|
"board.back": "Back",
|
|
643
656
|
"changelog.empty.title": "Nothing resolved yet",
|
|
644
657
|
"changelog.empty.body": "Once a report you sent is fixed it will appear here, grouped by week.",
|
|
@@ -706,6 +719,14 @@ var DEFAULT_STRINGS = {
|
|
|
706
719
|
};
|
|
707
720
|
var FRENCH_STRINGS = {
|
|
708
721
|
"fab.label": "Envoyer un commentaire",
|
|
722
|
+
"page.badge.aria": "Retours \u2014 {n} ouverts sur cette page",
|
|
723
|
+
"page.badge.aria.one": "Retours \u2014 1 ouvert sur cette page",
|
|
724
|
+
"page.strip.text": "{n} retours ouverts sur cette page",
|
|
725
|
+
"page.strip.text.one": "1 retour ouvert sur cette page",
|
|
726
|
+
"page.strip.view": "Voir",
|
|
727
|
+
"page.peek.title": "Sur cette page",
|
|
728
|
+
"page.peek.viewAll": "Voir les {n}",
|
|
729
|
+
"page.peek.viewAll.one": "Voir 1 retour ouvert",
|
|
709
730
|
"form.title": "Envoyer un commentaire",
|
|
710
731
|
"form.description.label": "Qu\u2019est-il arriv\xE9 ?",
|
|
711
732
|
"form.description.placeholder": "D\xE9crivez le probl\xE8me ou l\u2019id\xE9e en une ou deux phrases.",
|
|
@@ -790,6 +811,11 @@ var FRENCH_STRINGS = {
|
|
|
790
811
|
"board.scope.project": "Rapports du projet",
|
|
791
812
|
"board.scope.mine": "Vos rapports",
|
|
792
813
|
"board.scope.thisPage": "Cette page",
|
|
814
|
+
"board.scope.allPages": "Toutes les pages",
|
|
815
|
+
"board.scope.onThisPage": "sur cette page",
|
|
816
|
+
"board.list.count.page": "{n} sur {total} \xB7 cette page",
|
|
817
|
+
"board.list.empty.page.title": "Aucun retour sur cette page pour l\u2019instant.",
|
|
818
|
+
"board.list.empty.page.description": "Soyez le premier \xE0 signaler quelque chose ici \u2014 ou parcourez tout le projet.",
|
|
793
819
|
"board.back": "Retour",
|
|
794
820
|
"changelog.empty.title": "Rien de r\xE9solu pour l\u2019instant",
|
|
795
821
|
"changelog.empty.body": "Quand un rapport que vous avez envoy\xE9 est corrig\xE9, il appara\xEEtra ici, regroup\xE9 par semaine.",
|
|
@@ -874,7 +900,7 @@ function resolveStrings(overrides, options = {}) {
|
|
|
874
900
|
|
|
875
901
|
// src/widget/mount.tsx
|
|
876
902
|
import { h, render } from "preact";
|
|
877
|
-
import { useCallback, useEffect as
|
|
903
|
+
import { useCallback as useCallback2, useEffect as useEffect10, useRef as useRef7, useState as useState9 } from "preact/hooks";
|
|
878
904
|
|
|
879
905
|
// src/widget/currentPage.ts
|
|
880
906
|
function currentPagePath(opts) {
|
|
@@ -928,6 +954,47 @@ function saveBoardView(externalId, view) {
|
|
|
928
954
|
}
|
|
929
955
|
}
|
|
930
956
|
|
|
957
|
+
// src/widget/poll.ts
|
|
958
|
+
var MAX_BACKOFF_MULTIPLIER = 10;
|
|
959
|
+
function startPoll(tick, intervalMs) {
|
|
960
|
+
let stopped = false;
|
|
961
|
+
let parked = false;
|
|
962
|
+
let failures = 0;
|
|
963
|
+
let timer = null;
|
|
964
|
+
const doc = typeof document !== "undefined" ? document : null;
|
|
965
|
+
const delayMs = () => Math.min(intervalMs * 2 ** failures, intervalMs * MAX_BACKOFF_MULTIPLIER);
|
|
966
|
+
const run = async () => {
|
|
967
|
+
if (stopped) return;
|
|
968
|
+
if (doc?.hidden) {
|
|
969
|
+
parked = true;
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
let ok = false;
|
|
973
|
+
try {
|
|
974
|
+
ok = await tick();
|
|
975
|
+
} catch {
|
|
976
|
+
ok = false;
|
|
977
|
+
}
|
|
978
|
+
if (stopped) return;
|
|
979
|
+
failures = ok ? 0 : failures + 1;
|
|
980
|
+
timer = setTimeout(() => void run(), delayMs());
|
|
981
|
+
};
|
|
982
|
+
const onVisibilityChange = () => {
|
|
983
|
+
if (stopped || !parked || doc?.hidden) return;
|
|
984
|
+
parked = false;
|
|
985
|
+
void run();
|
|
986
|
+
};
|
|
987
|
+
doc?.addEventListener("visibilitychange", onVisibilityChange);
|
|
988
|
+
void run();
|
|
989
|
+
return {
|
|
990
|
+
stop() {
|
|
991
|
+
stopped = true;
|
|
992
|
+
if (timer) clearTimeout(timer);
|
|
993
|
+
doc?.removeEventListener("visibilitychange", onVisibilityChange);
|
|
994
|
+
}
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
|
|
931
998
|
// src/widget/ReportDetailView.tsx
|
|
932
999
|
import { useEffect, useRef, useState } from "preact/hooks";
|
|
933
1000
|
|
|
@@ -1019,24 +1086,23 @@ function ReportDetailView({
|
|
|
1019
1086
|
const fetchDetail = async () => {
|
|
1020
1087
|
try {
|
|
1021
1088
|
const next = await api.getReport(reportId, externalId);
|
|
1022
|
-
if (!mountedRef.current) return;
|
|
1089
|
+
if (!mountedRef.current) return true;
|
|
1023
1090
|
setDetail(next);
|
|
1024
1091
|
setError(null);
|
|
1092
|
+
return true;
|
|
1025
1093
|
} catch (err) {
|
|
1026
1094
|
if (typeof console !== "undefined") console.warn("[mhosaic] getReport:", err);
|
|
1027
|
-
if (!mountedRef.current) return;
|
|
1095
|
+
if (!mountedRef.current) return false;
|
|
1028
1096
|
setError("load_failed");
|
|
1097
|
+
return false;
|
|
1029
1098
|
}
|
|
1030
1099
|
};
|
|
1031
1100
|
useEffect(() => {
|
|
1032
1101
|
mountedRef.current = true;
|
|
1033
|
-
|
|
1034
|
-
const timer = setInterval(() => {
|
|
1035
|
-
void fetchDetail();
|
|
1036
|
-
}, POLL_MS);
|
|
1102
|
+
const poll = startPoll(fetchDetail, POLL_MS);
|
|
1037
1103
|
return () => {
|
|
1038
1104
|
mountedRef.current = false;
|
|
1039
|
-
|
|
1105
|
+
poll.stop();
|
|
1040
1106
|
};
|
|
1041
1107
|
}, [reportId, externalId]);
|
|
1042
1108
|
const handleSend = async () => {
|
|
@@ -1378,7 +1444,13 @@ var STATUSES = [
|
|
|
1378
1444
|
];
|
|
1379
1445
|
var TYPES = ["bug", "feature", "question", "praise", "typo"];
|
|
1380
1446
|
var SEVERITIES = ["blocker", "high", "medium", "low"];
|
|
1381
|
-
function BoardView({
|
|
1447
|
+
function BoardView({
|
|
1448
|
+
api,
|
|
1449
|
+
externalId,
|
|
1450
|
+
strings,
|
|
1451
|
+
getCurrentPage,
|
|
1452
|
+
initialSelectedId
|
|
1453
|
+
}) {
|
|
1382
1454
|
const [filters, setFilters] = useState2(() => loadBoardView(externalId));
|
|
1383
1455
|
const [thisPage, setThisPage] = useState2(true);
|
|
1384
1456
|
useEffect2(() => {
|
|
@@ -1388,7 +1460,7 @@ function BoardView({ api, externalId, strings, getCurrentPage }) {
|
|
|
1388
1460
|
const [kpis, setKpis] = useState2(null);
|
|
1389
1461
|
const [loading, setLoading] = useState2(true);
|
|
1390
1462
|
const [error, setError] = useState2(null);
|
|
1391
|
-
const [selectedId, setSelectedId] = useState2(null);
|
|
1463
|
+
const [selectedId, setSelectedId] = useState2(initialSelectedId ?? null);
|
|
1392
1464
|
const [detailKey, setDetailKey] = useState2(0);
|
|
1393
1465
|
const [reloadTick, setReloadTick] = useState2(0);
|
|
1394
1466
|
const activeFilterCount = useMemo(() => {
|
|
@@ -1405,30 +1477,29 @@ function BoardView({ api, externalId, strings, getCurrentPage }) {
|
|
|
1405
1477
|
);
|
|
1406
1478
|
useEffect2(() => {
|
|
1407
1479
|
let cancelled = false;
|
|
1408
|
-
|
|
1409
|
-
const
|
|
1480
|
+
setLoading(true);
|
|
1481
|
+
const poll = startPoll(async () => {
|
|
1410
1482
|
try {
|
|
1411
1483
|
const [list, k] = await Promise.all([
|
|
1412
1484
|
api.listBoard(externalId, fetchFilters),
|
|
1413
1485
|
api.fetchBoardKpis(externalId, fetchFilters)
|
|
1414
1486
|
]);
|
|
1415
|
-
if (cancelled) return;
|
|
1487
|
+
if (cancelled) return true;
|
|
1416
1488
|
setPage(list);
|
|
1417
1489
|
setKpis(k);
|
|
1418
1490
|
setError(null);
|
|
1491
|
+
return true;
|
|
1419
1492
|
} catch (e) {
|
|
1420
|
-
if (cancelled) return;
|
|
1493
|
+
if (cancelled) return false;
|
|
1421
1494
|
setError(e instanceof Error ? e.message : String(e));
|
|
1495
|
+
return false;
|
|
1422
1496
|
} finally {
|
|
1423
1497
|
if (!cancelled) setLoading(false);
|
|
1424
|
-
if (!cancelled) timer = setTimeout(tick, POLL_MS2);
|
|
1425
1498
|
}
|
|
1426
|
-
};
|
|
1427
|
-
setLoading(true);
|
|
1428
|
-
void tick();
|
|
1499
|
+
}, POLL_MS2);
|
|
1429
1500
|
return () => {
|
|
1430
1501
|
cancelled = true;
|
|
1431
|
-
|
|
1502
|
+
poll.stop();
|
|
1432
1503
|
};
|
|
1433
1504
|
}, [api, externalId, JSON.stringify(fetchFilters)]);
|
|
1434
1505
|
const selectedRow = useMemo(() => {
|
|
@@ -1440,7 +1511,7 @@ function BoardView({ api, externalId, strings, getCurrentPage }) {
|
|
|
1440
1511
|
setDetailKey((k) => k + 1);
|
|
1441
1512
|
};
|
|
1442
1513
|
return /* @__PURE__ */ jsxs3("div", { class: "board-view", children: [
|
|
1443
|
-
/* @__PURE__ */ jsx3(BoardHeader, { strings, kpis }),
|
|
1514
|
+
/* @__PURE__ */ jsx3(BoardHeader, { strings, kpis, thisPage }),
|
|
1444
1515
|
/* @__PURE__ */ jsx3(
|
|
1445
1516
|
BoardFilters,
|
|
1446
1517
|
{
|
|
@@ -1471,7 +1542,14 @@ function BoardView({ api, externalId, strings, getCurrentPage }) {
|
|
|
1471
1542
|
)
|
|
1472
1543
|
] }),
|
|
1473
1544
|
!error && loading && !page && /* @__PURE__ */ jsx3(BoardListSkeleton, {}),
|
|
1474
|
-
!error && page && page.results.length === 0 && !loading && /* @__PURE__ */ jsx3(
|
|
1545
|
+
!error && page && page.results.length === 0 && !loading && /* @__PURE__ */ jsx3(
|
|
1546
|
+
BoardEmpty,
|
|
1547
|
+
{
|
|
1548
|
+
strings,
|
|
1549
|
+
thisPage,
|
|
1550
|
+
onAllPages: () => setThisPage(false)
|
|
1551
|
+
}
|
|
1552
|
+
),
|
|
1475
1553
|
!error && page && page.results.length > 0 && /* @__PURE__ */ jsx3(
|
|
1476
1554
|
BoardList,
|
|
1477
1555
|
{
|
|
@@ -1479,7 +1557,8 @@ function BoardView({ api, externalId, strings, getCurrentPage }) {
|
|
|
1479
1557
|
selectedId,
|
|
1480
1558
|
onPick: onPickRow,
|
|
1481
1559
|
strings,
|
|
1482
|
-
total: page.count
|
|
1560
|
+
total: page.count,
|
|
1561
|
+
thisPage
|
|
1483
1562
|
}
|
|
1484
1563
|
)
|
|
1485
1564
|
] }),
|
|
@@ -1504,9 +1583,10 @@ function BoardView({ api, externalId, strings, getCurrentPage }) {
|
|
|
1504
1583
|
}
|
|
1505
1584
|
function BoardHeader({
|
|
1506
1585
|
strings,
|
|
1507
|
-
kpis
|
|
1586
|
+
kpis,
|
|
1587
|
+
thisPage
|
|
1508
1588
|
}) {
|
|
1509
|
-
const scopeLabel = kpis?.scope === "project" ? strings["board.scope.project"] : strings["board.scope.mine"];
|
|
1589
|
+
const scopeLabel = thisPage ? strings["board.scope.onThisPage"] : kpis?.scope === "project" ? strings["board.scope.project"] : strings["board.scope.mine"];
|
|
1510
1590
|
return /* @__PURE__ */ jsxs3("header", { class: "board-header", children: [
|
|
1511
1591
|
/* @__PURE__ */ jsxs3("div", { class: "board-header-title", children: [
|
|
1512
1592
|
/* @__PURE__ */ jsx3("span", { class: "board-header-emoji", "aria-hidden": "true", children: "\u{1F4CB}" }),
|
|
@@ -1601,6 +1681,28 @@ function BoardFilters({
|
|
|
1601
1681
|
};
|
|
1602
1682
|
const clear = () => onChange({});
|
|
1603
1683
|
return /* @__PURE__ */ jsxs3("div", { class: "board-filters", children: [
|
|
1684
|
+
/* @__PURE__ */ jsxs3("div", { class: "board-scope", role: "group", "aria-label": strings["board.scope.thisPage"], children: [
|
|
1685
|
+
/* @__PURE__ */ jsx3(
|
|
1686
|
+
"button",
|
|
1687
|
+
{
|
|
1688
|
+
type: "button",
|
|
1689
|
+
class: `board-scope-btn ${thisPage ? "is-active" : ""}`,
|
|
1690
|
+
"aria-pressed": thisPage,
|
|
1691
|
+
onClick: () => !thisPage && onToggleThisPage(),
|
|
1692
|
+
children: strings["board.scope.thisPage"]
|
|
1693
|
+
}
|
|
1694
|
+
),
|
|
1695
|
+
/* @__PURE__ */ jsx3(
|
|
1696
|
+
"button",
|
|
1697
|
+
{
|
|
1698
|
+
type: "button",
|
|
1699
|
+
class: `board-scope-btn ${!thisPage ? "is-active" : ""}`,
|
|
1700
|
+
"aria-pressed": !thisPage,
|
|
1701
|
+
onClick: () => thisPage && onToggleThisPage(),
|
|
1702
|
+
children: strings["board.scope.allPages"]
|
|
1703
|
+
}
|
|
1704
|
+
)
|
|
1705
|
+
] }),
|
|
1604
1706
|
/* @__PURE__ */ jsx3(
|
|
1605
1707
|
"select",
|
|
1606
1708
|
{
|
|
@@ -1671,19 +1773,6 @@ function BoardFilters({
|
|
|
1671
1773
|
),
|
|
1672
1774
|
/* @__PURE__ */ jsx3("span", { children: strings["board.filter.mine"] })
|
|
1673
1775
|
] }),
|
|
1674
|
-
/* @__PURE__ */ jsxs3(
|
|
1675
|
-
"button",
|
|
1676
|
-
{
|
|
1677
|
-
type: "button",
|
|
1678
|
-
class: `board-chip ${thisPage ? "board-chip--on" : ""}`,
|
|
1679
|
-
onClick: onToggleThisPage,
|
|
1680
|
-
children: [
|
|
1681
|
-
"\u{1F4CD} ",
|
|
1682
|
-
strings["board.scope.thisPage"],
|
|
1683
|
-
thisPage ? " \u2715" : ""
|
|
1684
|
-
]
|
|
1685
|
-
}
|
|
1686
|
-
),
|
|
1687
1776
|
activeCount > 0 && /* @__PURE__ */ jsxs3("button", { type: "button", class: "board-filter-clear", onClick: clear, children: [
|
|
1688
1777
|
/* @__PURE__ */ jsx3(CloseIcon, {}),
|
|
1689
1778
|
strings["board.filter.clear"]
|
|
@@ -1695,10 +1784,11 @@ function BoardList({
|
|
|
1695
1784
|
selectedId,
|
|
1696
1785
|
onPick,
|
|
1697
1786
|
strings,
|
|
1698
|
-
total
|
|
1787
|
+
total,
|
|
1788
|
+
thisPage
|
|
1699
1789
|
}) {
|
|
1700
1790
|
return /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1701
|
-
/* @__PURE__ */ jsx3("div", { class: "board-list-count", children: strings["board.list.count"].replace("{n}", String(rows.length)).replace("{total}", String(total)) }),
|
|
1791
|
+
/* @__PURE__ */ jsx3("div", { class: "board-list-count", children: strings[thisPage ? "board.list.count.page" : "board.list.count"].replace("{n}", String(rows.length)).replace("{total}", String(total)) }),
|
|
1702
1792
|
/* @__PURE__ */ jsx3("ul", { class: "board-list", role: "list", children: rows.map((row) => /* @__PURE__ */ jsx3(
|
|
1703
1793
|
BoardRowCard,
|
|
1704
1794
|
{
|
|
@@ -1744,11 +1834,16 @@ function BoardRowCard({
|
|
|
1744
1834
|
}
|
|
1745
1835
|
) });
|
|
1746
1836
|
}
|
|
1747
|
-
function BoardEmpty({
|
|
1837
|
+
function BoardEmpty({
|
|
1838
|
+
strings,
|
|
1839
|
+
thisPage,
|
|
1840
|
+
onAllPages
|
|
1841
|
+
}) {
|
|
1748
1842
|
return /* @__PURE__ */ jsxs3("div", { class: "board-empty", children: [
|
|
1749
1843
|
/* @__PURE__ */ jsx3(EmptyIllustration, {}),
|
|
1750
|
-
/* @__PURE__ */ jsx3("h3", { children: strings["board.list.empty.title"] }),
|
|
1751
|
-
/* @__PURE__ */ jsx3("p", { children: strings["board.list.empty.description"] })
|
|
1844
|
+
/* @__PURE__ */ jsx3("h3", { children: strings[thisPage ? "board.list.empty.page.title" : "board.list.empty.title"] }),
|
|
1845
|
+
/* @__PURE__ */ jsx3("p", { children: strings[thisPage ? "board.list.empty.page.description" : "board.list.empty.description"] }),
|
|
1846
|
+
thisPage && /* @__PURE__ */ jsx3("button", { type: "button", class: "btn btn--ghost", onClick: onAllPages, children: strings["board.scope.allPages"] })
|
|
1752
1847
|
] });
|
|
1753
1848
|
}
|
|
1754
1849
|
function BoardListSkeleton() {
|
|
@@ -1901,26 +1996,25 @@ function ChangelogList({ api, externalId, strings, onSelect }) {
|
|
|
1901
1996
|
setError(null);
|
|
1902
1997
|
try {
|
|
1903
1998
|
const next = await api.listChangelog(externalId);
|
|
1904
|
-
if (!mountedRef.current) return;
|
|
1999
|
+
if (!mountedRef.current) return true;
|
|
1905
2000
|
setRows(next);
|
|
2001
|
+
return true;
|
|
1906
2002
|
} catch (err) {
|
|
1907
2003
|
if (typeof console !== "undefined")
|
|
1908
2004
|
console.warn("[mhosaic] listChangelog:", err);
|
|
1909
|
-
if (!mountedRef.current) return;
|
|
2005
|
+
if (!mountedRef.current) return false;
|
|
1910
2006
|
setError(strings["mine.error"]);
|
|
2007
|
+
return false;
|
|
1911
2008
|
} finally {
|
|
1912
2009
|
if (mountedRef.current) setRefreshing(false);
|
|
1913
2010
|
}
|
|
1914
2011
|
};
|
|
1915
2012
|
useEffect3(() => {
|
|
1916
2013
|
mountedRef.current = true;
|
|
1917
|
-
|
|
1918
|
-
const timer = setInterval(() => {
|
|
1919
|
-
void fetchRows();
|
|
1920
|
-
}, POLL_MS3);
|
|
2014
|
+
const poll = startPoll(fetchRows, POLL_MS3);
|
|
1921
2015
|
return () => {
|
|
1922
2016
|
mountedRef.current = false;
|
|
1923
|
-
|
|
2017
|
+
poll.stop();
|
|
1924
2018
|
};
|
|
1925
2019
|
}, [externalId]);
|
|
1926
2020
|
const groups = useMemo2(() => rows ? groupRowsByWeek(rows) : [], [rows]);
|
|
@@ -1992,8 +2086,11 @@ function BugIcon() {
|
|
|
1992
2086
|
}
|
|
1993
2087
|
);
|
|
1994
2088
|
}
|
|
1995
|
-
function Fab({ label, onClick }) {
|
|
1996
|
-
return /* @__PURE__ */
|
|
2089
|
+
function Fab({ label, onClick, count }) {
|
|
2090
|
+
return /* @__PURE__ */ jsxs6("button", { type: "button", class: "fab", "aria-label": label, title: label, onClick, children: [
|
|
2091
|
+
/* @__PURE__ */ jsx6(BugIcon, {}),
|
|
2092
|
+
count !== void 0 && count > 0 && /* @__PURE__ */ jsx6("span", { class: "fab-badge", "aria-hidden": "true", children: count > 9 ? "9+" : String(count) })
|
|
2093
|
+
] });
|
|
1997
2094
|
}
|
|
1998
2095
|
|
|
1999
2096
|
// src/widget/Form.tsx
|
|
@@ -2885,25 +2982,24 @@ function MineList({ api, externalId, strings, onSelect }) {
|
|
|
2885
2982
|
setError(null);
|
|
2886
2983
|
try {
|
|
2887
2984
|
const next = await api.listMine(externalId);
|
|
2888
|
-
if (!mountedRef.current) return;
|
|
2985
|
+
if (!mountedRef.current) return true;
|
|
2889
2986
|
setRows(next);
|
|
2987
|
+
return true;
|
|
2890
2988
|
} catch (err) {
|
|
2891
2989
|
if (typeof console !== "undefined") console.warn("[mhosaic] listMine:", err);
|
|
2892
|
-
if (!mountedRef.current) return;
|
|
2990
|
+
if (!mountedRef.current) return false;
|
|
2893
2991
|
setError(strings["mine.error"]);
|
|
2992
|
+
return false;
|
|
2894
2993
|
} finally {
|
|
2895
2994
|
if (mountedRef.current) setRefreshing(false);
|
|
2896
2995
|
}
|
|
2897
2996
|
};
|
|
2898
2997
|
useEffect6(() => {
|
|
2899
2998
|
mountedRef.current = true;
|
|
2900
|
-
|
|
2901
|
-
const timer = setInterval(() => {
|
|
2902
|
-
void fetchRows();
|
|
2903
|
-
}, POLL_MS4);
|
|
2999
|
+
const poll = startPoll(fetchRows, POLL_MS4);
|
|
2904
3000
|
return () => {
|
|
2905
3001
|
mountedRef.current = false;
|
|
2906
|
-
|
|
3002
|
+
poll.stop();
|
|
2907
3003
|
};
|
|
2908
3004
|
}, [externalId]);
|
|
2909
3005
|
const isEmpty = rows !== null && rows.length === 0;
|
|
@@ -3000,6 +3096,136 @@ function Modal({ onDismiss, children, closeLabel = "Close", expanded = false })
|
|
|
3000
3096
|
);
|
|
3001
3097
|
}
|
|
3002
3098
|
|
|
3099
|
+
// src/widget/PageActivityStrip.tsx
|
|
3100
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "preact/jsx-runtime";
|
|
3101
|
+
function PageActivityStrip({
|
|
3102
|
+
open,
|
|
3103
|
+
strings,
|
|
3104
|
+
onView
|
|
3105
|
+
}) {
|
|
3106
|
+
if (open === 0) return null;
|
|
3107
|
+
const text = open === 1 ? strings["page.strip.text.one"] : strings["page.strip.text"].replace("{n}", String(open));
|
|
3108
|
+
return /* @__PURE__ */ jsxs12("div", { class: "page-strip", children: [
|
|
3109
|
+
/* @__PURE__ */ jsx12("span", { children: text }),
|
|
3110
|
+
/* @__PURE__ */ jsx12("button", { type: "button", class: "page-strip-view", onClick: onView, children: strings["page.strip.view"] })
|
|
3111
|
+
] });
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
// src/widget/PagePeekPanel.tsx
|
|
3115
|
+
import { useEffect as useEffect8, useState as useState7 } from "preact/hooks";
|
|
3116
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "preact/jsx-runtime";
|
|
3117
|
+
function PagePeekPanel({
|
|
3118
|
+
api,
|
|
3119
|
+
externalId,
|
|
3120
|
+
strings,
|
|
3121
|
+
getCurrentPage,
|
|
3122
|
+
open,
|
|
3123
|
+
onViewAll,
|
|
3124
|
+
onPickRow,
|
|
3125
|
+
onSend
|
|
3126
|
+
}) {
|
|
3127
|
+
const [rows, setRows] = useState7(null);
|
|
3128
|
+
const [failed, setFailed] = useState7(false);
|
|
3129
|
+
useEffect8(() => {
|
|
3130
|
+
let cancelled = false;
|
|
3131
|
+
const pagePath = currentPagePath(getCurrentPage !== void 0 ? { getCurrentPage } : {});
|
|
3132
|
+
api.listBoard(externalId, {
|
|
3133
|
+
pagePath,
|
|
3134
|
+
status: ["new", "in_progress", "awaiting_validation"]
|
|
3135
|
+
}).then((page) => {
|
|
3136
|
+
if (!cancelled) setRows(page.results.slice(0, 5));
|
|
3137
|
+
}).catch(() => {
|
|
3138
|
+
if (!cancelled) setFailed(true);
|
|
3139
|
+
});
|
|
3140
|
+
return () => {
|
|
3141
|
+
cancelled = true;
|
|
3142
|
+
};
|
|
3143
|
+
}, [api, externalId]);
|
|
3144
|
+
return /* @__PURE__ */ jsxs13("div", { class: "page-peek", role: "region", "aria-label": strings["page.peek.title"], children: [
|
|
3145
|
+
/* @__PURE__ */ jsx13("div", { class: "page-peek-title", children: strings["page.peek.title"] }),
|
|
3146
|
+
rows === null && !failed && /* @__PURE__ */ jsxs13("div", { class: "page-peek-skeleton", "aria-hidden": "true", children: [
|
|
3147
|
+
/* @__PURE__ */ jsx13("div", {}),
|
|
3148
|
+
" ",
|
|
3149
|
+
/* @__PURE__ */ jsx13("div", {})
|
|
3150
|
+
] }),
|
|
3151
|
+
rows !== null && rows.map((row) => /* @__PURE__ */ jsxs13(
|
|
3152
|
+
"button",
|
|
3153
|
+
{
|
|
3154
|
+
type: "button",
|
|
3155
|
+
class: "page-peek-row",
|
|
3156
|
+
onClick: () => onPickRow?.(row.id),
|
|
3157
|
+
children: [
|
|
3158
|
+
/* @__PURE__ */ jsx13("span", { class: `page-peek-dot status-${row.status}`, "aria-hidden": "true" }),
|
|
3159
|
+
/* @__PURE__ */ jsx13("span", { class: "page-peek-desc", children: row.description })
|
|
3160
|
+
]
|
|
3161
|
+
},
|
|
3162
|
+
row.id
|
|
3163
|
+
)),
|
|
3164
|
+
/* @__PURE__ */ jsxs13("div", { class: "page-peek-footer", children: [
|
|
3165
|
+
/* @__PURE__ */ jsx13("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)) }),
|
|
3166
|
+
/* @__PURE__ */ jsx13("button", { type: "button", class: "page-peek-send", onClick: onSend, children: strings["fab.label"] })
|
|
3167
|
+
] })
|
|
3168
|
+
] });
|
|
3169
|
+
}
|
|
3170
|
+
|
|
3171
|
+
// src/widget/pageSignal.ts
|
|
3172
|
+
import { useCallback, useEffect as useEffect9, useState as useState8 } from "preact/hooks";
|
|
3173
|
+
var TTL_MS = 6e4;
|
|
3174
|
+
function computeOpenCount(kpis) {
|
|
3175
|
+
const s = kpis.by_status;
|
|
3176
|
+
return (s.new ?? 0) + (s.in_progress ?? 0) + (s.awaiting_validation ?? 0);
|
|
3177
|
+
}
|
|
3178
|
+
var cache = /* @__PURE__ */ new Map();
|
|
3179
|
+
var inflight = /* @__PURE__ */ new Map();
|
|
3180
|
+
function invalidatePageSignal() {
|
|
3181
|
+
cache.clear();
|
|
3182
|
+
}
|
|
3183
|
+
function fetchOpen(api, externalId, path) {
|
|
3184
|
+
const key = `${externalId}|${path}`;
|
|
3185
|
+
const hit = cache.get(key);
|
|
3186
|
+
if (hit && Date.now() - hit.fetchedAt < TTL_MS) return Promise.resolve(hit.open);
|
|
3187
|
+
const pending = inflight.get(key);
|
|
3188
|
+
if (pending) return pending;
|
|
3189
|
+
const p = api.fetchBoardKpis(externalId, { pagePath: path }).then((kpis) => {
|
|
3190
|
+
const open = computeOpenCount(kpis);
|
|
3191
|
+
cache.set(key, { open, fetchedAt: Date.now() });
|
|
3192
|
+
return open;
|
|
3193
|
+
}).finally(() => inflight.delete(key));
|
|
3194
|
+
inflight.set(key, p);
|
|
3195
|
+
return p;
|
|
3196
|
+
}
|
|
3197
|
+
function usePageOpenCount(opts) {
|
|
3198
|
+
const { api, externalId, getCurrentPage, enabled } = opts;
|
|
3199
|
+
const [open, setOpen] = useState8(0);
|
|
3200
|
+
const [tick, setTick] = useState8(0);
|
|
3201
|
+
const refresh = useCallback(() => {
|
|
3202
|
+
invalidatePageSignal();
|
|
3203
|
+
setTick((t) => t + 1);
|
|
3204
|
+
}, []);
|
|
3205
|
+
useEffect9(() => {
|
|
3206
|
+
if (!enabled || !api || !externalId) {
|
|
3207
|
+
setOpen(0);
|
|
3208
|
+
return;
|
|
3209
|
+
}
|
|
3210
|
+
let cancelled = false;
|
|
3211
|
+
const load = () => {
|
|
3212
|
+
const path = currentPagePath(getCurrentPage !== void 0 ? { getCurrentPage } : {});
|
|
3213
|
+
fetchOpen(api, externalId, path).then((n) => {
|
|
3214
|
+
if (!cancelled) setOpen(n);
|
|
3215
|
+
}).catch(() => {
|
|
3216
|
+
if (!cancelled) setOpen(0);
|
|
3217
|
+
});
|
|
3218
|
+
};
|
|
3219
|
+
load();
|
|
3220
|
+
const unsub = onLocationChange(load);
|
|
3221
|
+
return () => {
|
|
3222
|
+
cancelled = true;
|
|
3223
|
+
unsub();
|
|
3224
|
+
};
|
|
3225
|
+
}, [api, externalId, enabled, tick]);
|
|
3226
|
+
return { open, refresh };
|
|
3227
|
+
}
|
|
3228
|
+
|
|
3003
3229
|
// src/widget/styles.ts
|
|
3004
3230
|
var WIDGET_STYLES = `
|
|
3005
3231
|
:host {
|
|
@@ -3074,10 +3300,20 @@ var WIDGET_STYLES = `
|
|
|
3074
3300
|
soft-black background with a light steel-blue lucide-bug glyph;
|
|
3075
3301
|
custom SVG inlined (no emoji \u2014 emoji renders inconsistently across
|
|
3076
3302
|
OSes and can't inherit color). Two-layer elevation, scale-on-press. */
|
|
3077
|
-
.fab {
|
|
3303
|
+
.fab-area {
|
|
3078
3304
|
position: fixed;
|
|
3079
3305
|
bottom: 24px;
|
|
3080
3306
|
right: 24px;
|
|
3307
|
+
/* No z-index on purpose: the modal .backdrop/.modal are later siblings in
|
|
3308
|
+
the shadow root, so DOM order must keep them painting above the FAB \u2014
|
|
3309
|
+
an explicit z-index here would trap the FAB on top of the open modal. */
|
|
3310
|
+
}
|
|
3311
|
+
.fab-area .fab {
|
|
3312
|
+
position: relative;
|
|
3313
|
+
right: auto;
|
|
3314
|
+
bottom: auto;
|
|
3315
|
+
}
|
|
3316
|
+
.fab {
|
|
3081
3317
|
width: 48px;
|
|
3082
3318
|
height: 48px;
|
|
3083
3319
|
border-radius: 999px;
|
|
@@ -3121,9 +3357,43 @@ var WIDGET_STYLES = `
|
|
|
3121
3357
|
0 4px 12px rgba(0, 0, 0, 0.32),
|
|
3122
3358
|
0 2px 4px rgba(0, 0, 0, 0.40); }
|
|
3123
3359
|
}
|
|
3360
|
+
|
|
3361
|
+
/* Page-activity badge \u2014 absolute so it never shifts the FAB's layout. */
|
|
3362
|
+
.fab-badge {
|
|
3363
|
+
position: absolute;
|
|
3364
|
+
top: -2px;
|
|
3365
|
+
right: -2px;
|
|
3366
|
+
min-width: 16px;
|
|
3367
|
+
height: 16px;
|
|
3368
|
+
padding: 0 4px;
|
|
3369
|
+
box-sizing: border-box;
|
|
3370
|
+
border-radius: 999px;
|
|
3371
|
+
background: var(--mfb-accent);
|
|
3372
|
+
color: #fff;
|
|
3373
|
+
font-size: 10px;
|
|
3374
|
+
font-weight: 700;
|
|
3375
|
+
line-height: 16px;
|
|
3376
|
+
text-align: center;
|
|
3377
|
+
box-shadow: 0 0 0 2px var(--mfb-fab-bg);
|
|
3378
|
+
animation: mfb-badge-in 150ms ease-out;
|
|
3379
|
+
}
|
|
3380
|
+
@keyframes mfb-badge-in {
|
|
3381
|
+
from {
|
|
3382
|
+
opacity: 0;
|
|
3383
|
+
transform: scale(0.6);
|
|
3384
|
+
}
|
|
3385
|
+
to {
|
|
3386
|
+
opacity: 1;
|
|
3387
|
+
transform: scale(1);
|
|
3388
|
+
}
|
|
3389
|
+
}
|
|
3390
|
+
|
|
3124
3391
|
@media (prefers-reduced-motion: reduce) {
|
|
3125
3392
|
.fab { transition: none; }
|
|
3126
3393
|
.fab:hover, .fab:active { transform: none; }
|
|
3394
|
+
.fab-badge {
|
|
3395
|
+
animation: none;
|
|
3396
|
+
}
|
|
3127
3397
|
}
|
|
3128
3398
|
|
|
3129
3399
|
/* Backdrop \u2014 fade in with a slight blur for depth. The blur gives the
|
|
@@ -4470,6 +4740,59 @@ var WIDGET_STYLES = `
|
|
|
4470
4740
|
background: var(--mfb-surface);
|
|
4471
4741
|
}
|
|
4472
4742
|
|
|
4743
|
+
/* Scope segmented control \u2014 [This page | All pages], front of the filter row. */
|
|
4744
|
+
.board-scope {
|
|
4745
|
+
display: inline-flex;
|
|
4746
|
+
border: 1px solid var(--mfb-border);
|
|
4747
|
+
border-radius: var(--mfb-radius);
|
|
4748
|
+
overflow: hidden;
|
|
4749
|
+
flex: none;
|
|
4750
|
+
}
|
|
4751
|
+
.board-scope-btn {
|
|
4752
|
+
border: none;
|
|
4753
|
+
background: none;
|
|
4754
|
+
padding: 6px 10px;
|
|
4755
|
+
font: inherit;
|
|
4756
|
+
font-size: var(--mfb-text-sm);
|
|
4757
|
+
color: var(--mfb-text-muted);
|
|
4758
|
+
cursor: pointer;
|
|
4759
|
+
}
|
|
4760
|
+
.board-scope-btn.is-active {
|
|
4761
|
+
background: color-mix(in srgb, var(--mfb-accent) 14%, transparent);
|
|
4762
|
+
color: var(--mfb-accent);
|
|
4763
|
+
font-weight: 600;
|
|
4764
|
+
}
|
|
4765
|
+
.board-scope-btn:focus-visible {
|
|
4766
|
+
outline: 2px solid var(--mfb-accent);
|
|
4767
|
+
outline-offset: -2px;
|
|
4768
|
+
}
|
|
4769
|
+
|
|
4770
|
+
/* Send-tab page-activity strip \u2014 one line, muted, non-blocking. */
|
|
4771
|
+
.page-strip {
|
|
4772
|
+
display: flex;
|
|
4773
|
+
align-items: center;
|
|
4774
|
+
justify-content: space-between;
|
|
4775
|
+
gap: var(--mfb-space-3);
|
|
4776
|
+
margin: var(--mfb-space-3) 0 0;
|
|
4777
|
+
padding: var(--mfb-space-2) var(--mfb-space-3);
|
|
4778
|
+
border-radius: var(--mfb-radius);
|
|
4779
|
+
background: var(--mfb-surface-2);
|
|
4780
|
+
color: var(--mfb-text-muted);
|
|
4781
|
+
font-size: var(--mfb-text-sm);
|
|
4782
|
+
}
|
|
4783
|
+
.page-strip-view {
|
|
4784
|
+
border: none;
|
|
4785
|
+
background: none;
|
|
4786
|
+
padding: 0;
|
|
4787
|
+
color: var(--mfb-accent);
|
|
4788
|
+
font-size: var(--mfb-text-sm);
|
|
4789
|
+
font-weight: 600;
|
|
4790
|
+
cursor: pointer;
|
|
4791
|
+
}
|
|
4792
|
+
.page-strip-view:hover {
|
|
4793
|
+
text-decoration: underline;
|
|
4794
|
+
}
|
|
4795
|
+
|
|
4473
4796
|
/* Master/detail layout \u2014 two-column at >=900px, stacked below. */
|
|
4474
4797
|
.board-body {
|
|
4475
4798
|
display: grid;
|
|
@@ -4698,10 +5021,90 @@ var WIDGET_STYLES = `
|
|
|
4698
5021
|
@media (prefers-reduced-motion: reduce) {
|
|
4699
5022
|
.skeleton-line { animation: none; }
|
|
4700
5023
|
}
|
|
5024
|
+
|
|
5025
|
+
/* Hover peek panel \u2014 desktop-only ambient surface listing this page's
|
|
5026
|
+
open reports above the FAB (spec \xA73.2). Non-modal; never renders while
|
|
5027
|
+
the modal itself is open. */
|
|
5028
|
+
.page-peek {
|
|
5029
|
+
position: absolute;
|
|
5030
|
+
right: 0;
|
|
5031
|
+
bottom: 60px;
|
|
5032
|
+
width: 300px;
|
|
5033
|
+
padding: var(--mfb-space-3);
|
|
5034
|
+
border: 1px solid var(--mfb-border);
|
|
5035
|
+
border-radius: var(--mfb-radius-lg);
|
|
5036
|
+
background: var(--mfb-surface);
|
|
5037
|
+
color: var(--mfb-text);
|
|
5038
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
|
|
5039
|
+
font-size: var(--mfb-text-sm);
|
|
5040
|
+
}
|
|
5041
|
+
.page-peek-title {
|
|
5042
|
+
font-weight: 700;
|
|
5043
|
+
margin-bottom: var(--mfb-space-2);
|
|
5044
|
+
color: var(--mfb-text-muted);
|
|
5045
|
+
text-transform: uppercase;
|
|
5046
|
+
font-size: var(--mfb-text-xs);
|
|
5047
|
+
letter-spacing: 0.04em;
|
|
5048
|
+
}
|
|
5049
|
+
.page-peek-row {
|
|
5050
|
+
display: flex;
|
|
5051
|
+
align-items: center;
|
|
5052
|
+
gap: var(--mfb-space-2);
|
|
5053
|
+
width: 100%;
|
|
5054
|
+
padding: var(--mfb-space-2);
|
|
5055
|
+
border: none;
|
|
5056
|
+
border-radius: var(--mfb-radius);
|
|
5057
|
+
background: none;
|
|
5058
|
+
color: var(--mfb-text);
|
|
5059
|
+
text-align: left;
|
|
5060
|
+
cursor: pointer;
|
|
5061
|
+
}
|
|
5062
|
+
.page-peek-row:hover {
|
|
5063
|
+
background: var(--mfb-surface-2);
|
|
5064
|
+
}
|
|
5065
|
+
.page-peek-dot {
|
|
5066
|
+
width: 8px;
|
|
5067
|
+
height: 8px;
|
|
5068
|
+
border-radius: 50%;
|
|
5069
|
+
flex: none;
|
|
5070
|
+
}
|
|
5071
|
+
.page-peek-dot.status-new { background: #1e40af; }
|
|
5072
|
+
.page-peek-dot.status-in_progress { background: #92400e; }
|
|
5073
|
+
.page-peek-dot.status-awaiting_validation { background: #6b21a8; }
|
|
5074
|
+
.page-peek-dot.status-closed { background: #065f46; }
|
|
5075
|
+
.page-peek-dot.status-rejected { background: #991b1b; }
|
|
5076
|
+
.page-peek-desc {
|
|
5077
|
+
overflow: hidden;
|
|
5078
|
+
white-space: nowrap;
|
|
5079
|
+
text-overflow: ellipsis;
|
|
5080
|
+
}
|
|
5081
|
+
.page-peek-footer {
|
|
5082
|
+
display: flex;
|
|
5083
|
+
justify-content: space-between;
|
|
5084
|
+
margin-top: var(--mfb-space-2);
|
|
5085
|
+
padding-top: var(--mfb-space-2);
|
|
5086
|
+
border-top: 1px solid var(--mfb-border);
|
|
5087
|
+
}
|
|
5088
|
+
.page-peek-viewall,
|
|
5089
|
+
.page-peek-send {
|
|
5090
|
+
border: none;
|
|
5091
|
+
background: none;
|
|
5092
|
+
padding: 0;
|
|
5093
|
+
cursor: pointer;
|
|
5094
|
+
color: var(--mfb-accent);
|
|
5095
|
+
font-weight: 600;
|
|
5096
|
+
font-size: var(--mfb-text-sm);
|
|
5097
|
+
}
|
|
5098
|
+
.page-peek-skeleton div {
|
|
5099
|
+
height: 14px;
|
|
5100
|
+
border-radius: 4px;
|
|
5101
|
+
background: var(--mfb-surface-2);
|
|
5102
|
+
margin: var(--mfb-space-2) 0;
|
|
5103
|
+
}
|
|
4701
5104
|
`;
|
|
4702
5105
|
|
|
4703
5106
|
// src/widget/mount.tsx
|
|
4704
|
-
import { Fragment as Fragment3, jsx as
|
|
5107
|
+
import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs14 } from "preact/jsx-runtime";
|
|
4705
5108
|
function computeFabVisible(opts, externalId, visibilityAllowed) {
|
|
4706
5109
|
if (!opts.showFAB) return false;
|
|
4707
5110
|
if (opts.getExternalId !== void 0 && !externalId) return false;
|
|
@@ -4722,8 +5125,9 @@ function mountWidget(options) {
|
|
|
4722
5125
|
render(h(Root, { state }), mountPoint);
|
|
4723
5126
|
}
|
|
4724
5127
|
function clearSelected(s) {
|
|
4725
|
-
const { selectedReportId: _drop, ...rest } = s;
|
|
5128
|
+
const { selectedReportId: _drop, boardSelectId: _drop2, ...rest } = s;
|
|
4726
5129
|
void _drop;
|
|
5130
|
+
void _drop2;
|
|
4727
5131
|
return rest;
|
|
4728
5132
|
}
|
|
4729
5133
|
function openWidget(externalId) {
|
|
@@ -4738,10 +5142,11 @@ function mountWidget(options) {
|
|
|
4738
5142
|
}
|
|
4739
5143
|
}
|
|
4740
5144
|
function Root({ state }) {
|
|
4741
|
-
const handleSubmit =
|
|
5145
|
+
const handleSubmit = useCallback2(async (values) => {
|
|
4742
5146
|
rerender({ ...currentState, status: "submitting" });
|
|
4743
5147
|
try {
|
|
4744
5148
|
await options.onSubmit(values);
|
|
5149
|
+
pageSignal.refresh();
|
|
4745
5150
|
rerender({ ...currentState, status: "success" });
|
|
4746
5151
|
if (postSubmitTimer !== null) clearTimeout(postSubmitTimer);
|
|
4747
5152
|
postSubmitTimer = setTimeout(() => {
|
|
@@ -4767,10 +5172,18 @@ function mountWidget(options) {
|
|
|
4767
5172
|
}
|
|
4768
5173
|
}, []);
|
|
4769
5174
|
const externalId = options.getExternalId?.();
|
|
4770
|
-
const
|
|
5175
|
+
const pageActivityEnabled = options.showPageActivity !== false;
|
|
5176
|
+
const pageSignal = usePageOpenCount({
|
|
5177
|
+
...options.api !== void 0 && { api: options.api },
|
|
5178
|
+
...externalId !== void 0 && { externalId },
|
|
5179
|
+
...options.getCurrentPage !== void 0 && { getCurrentPage: options.getCurrentPage },
|
|
5180
|
+
enabled: pageActivityEnabled
|
|
5181
|
+
});
|
|
5182
|
+
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"];
|
|
5183
|
+
const [visibilityAllowed, setVisibilityAllowed] = useState9(
|
|
4771
5184
|
!options.requiresVisibilityCheck
|
|
4772
5185
|
);
|
|
4773
|
-
|
|
5186
|
+
useEffect10(() => {
|
|
4774
5187
|
if (!options.requiresVisibilityCheck) {
|
|
4775
5188
|
setVisibilityAllowed(true);
|
|
4776
5189
|
return;
|
|
@@ -4791,23 +5204,74 @@ function mountWidget(options) {
|
|
|
4791
5204
|
}, [externalId]);
|
|
4792
5205
|
const fabVisible = computeFabVisible(options, externalId, visibilityAllowed);
|
|
4793
5206
|
const showMineTab = Boolean(options.api && externalId);
|
|
4794
|
-
|
|
4795
|
-
|
|
4796
|
-
|
|
5207
|
+
const [peekOpen, setPeekOpen] = useState9(false);
|
|
5208
|
+
const peekTimers = useRef7({});
|
|
5209
|
+
const peekEnter = () => {
|
|
5210
|
+
if (peekTimers.current.close) clearTimeout(peekTimers.current.close);
|
|
5211
|
+
peekTimers.current.open = setTimeout(() => setPeekOpen(true), 250);
|
|
5212
|
+
};
|
|
5213
|
+
const peekLeave = () => {
|
|
5214
|
+
if (peekTimers.current.open) clearTimeout(peekTimers.current.open);
|
|
5215
|
+
peekTimers.current.close = setTimeout(() => setPeekOpen(false), 140);
|
|
5216
|
+
};
|
|
5217
|
+
return /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
5218
|
+
fabVisible && /* @__PURE__ */ jsxs14(
|
|
5219
|
+
"div",
|
|
4797
5220
|
{
|
|
4798
|
-
|
|
4799
|
-
|
|
5221
|
+
class: "fab-area",
|
|
5222
|
+
onMouseEnter: peekEnter,
|
|
5223
|
+
onMouseLeave: peekLeave,
|
|
5224
|
+
onFocusIn: (e) => {
|
|
5225
|
+
if (peekTimers.current.close) clearTimeout(peekTimers.current.close);
|
|
5226
|
+
if (e.target.matches?.(":focus-visible")) setPeekOpen(true);
|
|
5227
|
+
},
|
|
5228
|
+
onFocusOut: () => setPeekOpen(false),
|
|
5229
|
+
onKeyDown: (e) => e.key === "Escape" && setPeekOpen(false),
|
|
5230
|
+
children: [
|
|
5231
|
+
peekOpen && !state.open && pageActivityEnabled && pageSignal.open > 0 && options.api && externalId && /* @__PURE__ */ jsx14(
|
|
5232
|
+
PagePeekPanel,
|
|
5233
|
+
{
|
|
5234
|
+
api: options.api,
|
|
5235
|
+
externalId,
|
|
5236
|
+
strings: options.strings,
|
|
5237
|
+
...options.getCurrentPage !== void 0 && {
|
|
5238
|
+
getCurrentPage: options.getCurrentPage
|
|
5239
|
+
},
|
|
5240
|
+
open: pageSignal.open,
|
|
5241
|
+
onViewAll: () => {
|
|
5242
|
+
setPeekOpen(false);
|
|
5243
|
+
rerender({ ...currentState, open: true, tab: "board" });
|
|
5244
|
+
},
|
|
5245
|
+
onPickRow: (reportId) => {
|
|
5246
|
+
setPeekOpen(false);
|
|
5247
|
+
rerender({ ...currentState, open: true, tab: "board", boardSelectId: reportId });
|
|
5248
|
+
},
|
|
5249
|
+
onSend: () => {
|
|
5250
|
+
setPeekOpen(false);
|
|
5251
|
+
openWidget(externalId);
|
|
5252
|
+
}
|
|
5253
|
+
}
|
|
5254
|
+
),
|
|
5255
|
+
/* @__PURE__ */ jsx14(
|
|
5256
|
+
Fab,
|
|
5257
|
+
{
|
|
5258
|
+
label: fabLabel,
|
|
5259
|
+
onClick: () => openWidget(externalId),
|
|
5260
|
+
...pageSignal.open > 0 && { count: pageSignal.open }
|
|
5261
|
+
}
|
|
5262
|
+
)
|
|
5263
|
+
]
|
|
4800
5264
|
}
|
|
4801
5265
|
),
|
|
4802
|
-
state.open && /* @__PURE__ */
|
|
5266
|
+
state.open && /* @__PURE__ */ jsxs14(
|
|
4803
5267
|
Modal,
|
|
4804
5268
|
{
|
|
4805
5269
|
onDismiss: () => rerender(clearSelected({ ...currentState, open: false, status: "idle" })),
|
|
4806
5270
|
closeLabel: options.strings["form.close"],
|
|
4807
5271
|
expanded: state.tab === "board",
|
|
4808
5272
|
children: [
|
|
4809
|
-
showMineTab && /* @__PURE__ */
|
|
4810
|
-
/* @__PURE__ */
|
|
5273
|
+
showMineTab && /* @__PURE__ */ jsxs14("div", { class: "tab-strip", role: "tablist", children: [
|
|
5274
|
+
/* @__PURE__ */ jsx14(
|
|
4811
5275
|
"button",
|
|
4812
5276
|
{
|
|
4813
5277
|
type: "button",
|
|
@@ -4818,7 +5282,7 @@ function mountWidget(options) {
|
|
|
4818
5282
|
children: options.strings["tab.send"]
|
|
4819
5283
|
}
|
|
4820
5284
|
),
|
|
4821
|
-
/* @__PURE__ */
|
|
5285
|
+
/* @__PURE__ */ jsx14(
|
|
4822
5286
|
"button",
|
|
4823
5287
|
{
|
|
4824
5288
|
type: "button",
|
|
@@ -4829,7 +5293,7 @@ function mountWidget(options) {
|
|
|
4829
5293
|
children: options.strings["tab.mine"]
|
|
4830
5294
|
}
|
|
4831
5295
|
),
|
|
4832
|
-
/* @__PURE__ */
|
|
5296
|
+
/* @__PURE__ */ jsx14(
|
|
4833
5297
|
"button",
|
|
4834
5298
|
{
|
|
4835
5299
|
type: "button",
|
|
@@ -4840,7 +5304,7 @@ function mountWidget(options) {
|
|
|
4840
5304
|
children: options.strings["tab.changelog"]
|
|
4841
5305
|
}
|
|
4842
5306
|
),
|
|
4843
|
-
/* @__PURE__ */
|
|
5307
|
+
/* @__PURE__ */ jsx14(
|
|
4844
5308
|
"button",
|
|
4845
5309
|
{
|
|
4846
5310
|
type: "button",
|
|
@@ -4852,17 +5316,27 @@ function mountWidget(options) {
|
|
|
4852
5316
|
}
|
|
4853
5317
|
)
|
|
4854
5318
|
] }),
|
|
4855
|
-
state.tab === "send" && /* @__PURE__ */
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
|
|
4863
|
-
|
|
4864
|
-
|
|
4865
|
-
|
|
5319
|
+
state.tab === "send" && /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
5320
|
+
showMineTab && pageActivityEnabled && /* @__PURE__ */ jsx14(
|
|
5321
|
+
PageActivityStrip,
|
|
5322
|
+
{
|
|
5323
|
+
open: pageSignal.open,
|
|
5324
|
+
strings: options.strings,
|
|
5325
|
+
onView: () => rerender(clearSelected({ ...currentState, tab: "board" }))
|
|
5326
|
+
}
|
|
5327
|
+
),
|
|
5328
|
+
/* @__PURE__ */ jsx14(
|
|
5329
|
+
Form,
|
|
5330
|
+
{
|
|
5331
|
+
strings: options.strings,
|
|
5332
|
+
onSubmit: handleSubmit,
|
|
5333
|
+
onCancel: () => rerender({ ...currentState, open: false, status: "idle" }),
|
|
5334
|
+
status: state.status,
|
|
5335
|
+
...state.error !== void 0 && { errorMessage: state.error }
|
|
5336
|
+
}
|
|
5337
|
+
)
|
|
5338
|
+
] }),
|
|
5339
|
+
state.tab === "mine" && options.api && externalId && !state.selectedReportId && /* @__PURE__ */ jsx14(
|
|
4866
5340
|
MineList,
|
|
4867
5341
|
{
|
|
4868
5342
|
api: options.api,
|
|
@@ -4871,7 +5345,7 @@ function mountWidget(options) {
|
|
|
4871
5345
|
onSelect: (row) => rerender({ ...currentState, selectedReportId: row.id })
|
|
4872
5346
|
}
|
|
4873
5347
|
),
|
|
4874
|
-
(state.tab === "mine" || state.tab === "changelog") && options.api && externalId && state.selectedReportId && /* @__PURE__ */
|
|
5348
|
+
(state.tab === "mine" || state.tab === "changelog") && options.api && externalId && state.selectedReportId && /* @__PURE__ */ jsx14(
|
|
4875
5349
|
ReportDetailView,
|
|
4876
5350
|
{
|
|
4877
5351
|
api: options.api,
|
|
@@ -4881,7 +5355,7 @@ function mountWidget(options) {
|
|
|
4881
5355
|
onBack: () => rerender(clearSelected({ ...currentState }))
|
|
4882
5356
|
}
|
|
4883
5357
|
),
|
|
4884
|
-
state.tab === "changelog" && options.api && externalId && !state.selectedReportId && /* @__PURE__ */
|
|
5358
|
+
state.tab === "changelog" && options.api && externalId && !state.selectedReportId && /* @__PURE__ */ jsx14(
|
|
4885
5359
|
ChangelogList,
|
|
4886
5360
|
{
|
|
4887
5361
|
api: options.api,
|
|
@@ -4892,13 +5366,14 @@ function mountWidget(options) {
|
|
|
4892
5366
|
),
|
|
4893
5367
|
state.tab === "board" && options.api && externalId && // BoardView owns its own master/detail navigation — no
|
|
4894
5368
|
// selectedReportId routing through the modal-level state.
|
|
4895
|
-
/* @__PURE__ */
|
|
5369
|
+
/* @__PURE__ */ jsx14(
|
|
4896
5370
|
BoardView,
|
|
4897
5371
|
{
|
|
4898
5372
|
api: options.api,
|
|
4899
5373
|
externalId,
|
|
4900
5374
|
strings: options.strings,
|
|
4901
|
-
...options.getCurrentPage !== void 0 && { getCurrentPage: options.getCurrentPage }
|
|
5375
|
+
...options.getCurrentPage !== void 0 && { getCurrentPage: options.getCurrentPage },
|
|
5376
|
+
...state.boardSelectId !== void 0 && { initialSelectedId: state.boardSelectId }
|
|
4902
5377
|
}
|
|
4903
5378
|
)
|
|
4904
5379
|
]
|
|
@@ -4993,8 +5468,8 @@ function createFeedback(config) {
|
|
|
4993
5468
|
capture_method: captureMethod,
|
|
4994
5469
|
technical_context
|
|
4995
5470
|
};
|
|
4996
|
-
if ("0.
|
|
4997
|
-
payload.widget_version = "0.
|
|
5471
|
+
if ("0.27.0") {
|
|
5472
|
+
payload.widget_version = "0.27.0";
|
|
4998
5473
|
}
|
|
4999
5474
|
if (manualScreenshots?.length) {
|
|
5000
5475
|
payload.screenshots = manualScreenshots;
|
|
@@ -5050,6 +5525,9 @@ function createFeedback(config) {
|
|
|
5050
5525
|
// Opt-in: FAB opens to the page-scoped Board (default off → Send-first).
|
|
5051
5526
|
...config.openToCurrentPageFeedback !== void 0 && {
|
|
5052
5527
|
openToCurrentPageFeedback: config.openToCurrentPageFeedback
|
|
5528
|
+
},
|
|
5529
|
+
...config.showPageActivity !== void 0 && {
|
|
5530
|
+
showPageActivity: config.showPageActivity
|
|
5053
5531
|
}
|
|
5054
5532
|
});
|
|
5055
5533
|
let qaHandle;
|
|
@@ -5118,4 +5596,4 @@ function createFeedback(config) {
|
|
|
5118
5596
|
export {
|
|
5119
5597
|
createFeedback
|
|
5120
5598
|
};
|
|
5121
|
-
//# sourceMappingURL=chunk-
|
|
5599
|
+
//# sourceMappingURL=chunk-BXUX5UTI.mjs.map
|