@mhosaic/feedback 0.13.0 → 0.15.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-64HXWJCH.mjs → chunk-67JM6XVT.mjs} +78 -197
- package/dist/chunk-67JM6XVT.mjs.map +1 -0
- package/dist/{chunk-DKE6ELJ4.mjs → chunk-FGA63IEZ.mjs} +16 -4
- package/dist/chunk-FGA63IEZ.mjs.map +1 -0
- package/dist/embed.min.js +4 -38
- package/dist/embed.min.js.map +1 -1
- package/dist/error-tracking.d.ts +19 -0
- package/dist/error-tracking.mjs +35 -4
- package/dist/error-tracking.mjs.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/react.mjs +2 -2
- package/dist/webvitals.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-64HXWJCH.mjs.map +0 -1
- package/dist/chunk-DKE6ELJ4.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
scrubCredentials
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FGA63IEZ.mjs";
|
|
4
4
|
|
|
5
5
|
// src/api/client.ts
|
|
6
6
|
var SCALAR_FIELDS = [
|
|
@@ -12,6 +12,23 @@ var SCALAR_FIELDS = [
|
|
|
12
12
|
"user_agent",
|
|
13
13
|
"capture_method"
|
|
14
14
|
];
|
|
15
|
+
function assertSafeEndpoint(endpoint) {
|
|
16
|
+
let parsed;
|
|
17
|
+
try {
|
|
18
|
+
parsed = new URL(endpoint);
|
|
19
|
+
} catch {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`[mhosaic-feedback] \`endpoint\` is not a valid URL: ${endpoint}`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
if (parsed.protocol === "https:") return;
|
|
25
|
+
if (parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "[::1]")) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
throw new Error(
|
|
29
|
+
`[mhosaic-feedback] \`endpoint\` must use https:// (got ${parsed.protocol}//${parsed.hostname}). http:// is only allowed for localhost in dev.`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
15
32
|
function createApiClient(options) {
|
|
16
33
|
const endpoint = (options.endpoint ?? "").replace(/\/+$/, "");
|
|
17
34
|
if (!endpoint) {
|
|
@@ -19,6 +36,7 @@ function createApiClient(options) {
|
|
|
19
36
|
'[mhosaic-feedback] `endpoint` is required (e.g. "https://feedback.example.com").'
|
|
20
37
|
);
|
|
21
38
|
}
|
|
39
|
+
assertSafeEndpoint(endpoint);
|
|
22
40
|
const fetcher = options.fetch ?? globalThis.fetch;
|
|
23
41
|
async function submitReport(input) {
|
|
24
42
|
let payload = input;
|
|
@@ -551,10 +569,6 @@ var DEFAULT_STRINGS = {
|
|
|
551
569
|
"form.screenshot.annotate": "Annotate",
|
|
552
570
|
"form.screenshot.error_type": "Unsupported file type. Use PNG, JPEG or WebP.",
|
|
553
571
|
"form.screenshot.error_size": "File too large (max {max} MB).",
|
|
554
|
-
"form.screenshot.or": "or",
|
|
555
|
-
"form.screenshot.capture_page": "Capture this page",
|
|
556
|
-
"form.screenshot.capture_page_hint": "Pick a tab or window to share",
|
|
557
|
-
"form.screenshot.capture_error": "Couldn\u2019t capture the page. Try uploading a screenshot instead.",
|
|
558
572
|
"form.context.label": "Page",
|
|
559
573
|
"type.bug": "Bug",
|
|
560
574
|
"type.feature": "Feature request",
|
|
@@ -688,10 +702,6 @@ var FRENCH_STRINGS = {
|
|
|
688
702
|
"form.screenshot.annotate": "Annoter",
|
|
689
703
|
"form.screenshot.error_type": "Format non support\xE9. Utilisez PNG, JPEG ou WebP.",
|
|
690
704
|
"form.screenshot.error_size": "Fichier trop volumineux (max {max} Mo).",
|
|
691
|
-
"form.screenshot.or": "ou",
|
|
692
|
-
"form.screenshot.capture_page": "Capturer la page",
|
|
693
|
-
"form.screenshot.capture_page_hint": "Choisissez un onglet ou une fen\xEAtre \xE0 partager",
|
|
694
|
-
"form.screenshot.capture_error": "Impossible de capturer la page. T\xE9l\xE9versez une capture \xE0 la place.",
|
|
695
705
|
"form.context.label": "Page",
|
|
696
706
|
"type.bug": "Bogue",
|
|
697
707
|
"type.feature": "Suggestion",
|
|
@@ -880,64 +890,19 @@ function truncateUrl(url, maxLength = 80) {
|
|
|
880
890
|
const keepEnd = maxLength - 1 - keepStart;
|
|
881
891
|
return `${url.slice(0, keepStart)}\u2026${url.slice(url.length - keepEnd)}`;
|
|
882
892
|
}
|
|
883
|
-
|
|
884
|
-
if (
|
|
885
|
-
|
|
886
|
-
}
|
|
887
|
-
let stream = null;
|
|
893
|
+
function safeExternalHref(url) {
|
|
894
|
+
if (!url) return void 0;
|
|
895
|
+
let parsed;
|
|
888
896
|
try {
|
|
889
|
-
|
|
890
|
-
video: { displaySurface: "browser" },
|
|
891
|
-
audio: false
|
|
892
|
-
// Hint that audio isn't needed; not all browsers honor this but it
|
|
893
|
-
// avoids the audio-share toggle being defaulted on in some.
|
|
894
|
-
});
|
|
897
|
+
parsed = new URL(url);
|
|
895
898
|
} catch {
|
|
896
|
-
return
|
|
899
|
+
return void 0;
|
|
897
900
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
const ImageCaptureCtor = window.ImageCapture;
|
|
902
|
-
let bitmap = null;
|
|
903
|
-
if (ImageCaptureCtor) {
|
|
904
|
-
try {
|
|
905
|
-
const ic = new ImageCaptureCtor(track);
|
|
906
|
-
bitmap = await ic.grabFrame();
|
|
907
|
-
} catch {
|
|
908
|
-
bitmap = null;
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
if (!bitmap) {
|
|
912
|
-
bitmap = await grabFrameViaVideo(stream);
|
|
913
|
-
}
|
|
914
|
-
if (!bitmap) return null;
|
|
915
|
-
const canvas = document.createElement("canvas");
|
|
916
|
-
canvas.width = bitmap.width;
|
|
917
|
-
canvas.height = bitmap.height;
|
|
918
|
-
const ctx = canvas.getContext("2d");
|
|
919
|
-
if (!ctx) return null;
|
|
920
|
-
ctx.drawImage(bitmap, 0, 0);
|
|
921
|
-
return await new Promise(
|
|
922
|
-
(resolve) => canvas.toBlob(resolve, "image/png")
|
|
923
|
-
);
|
|
924
|
-
} finally {
|
|
925
|
-
stream.getTracks().forEach((t) => t.stop());
|
|
926
|
-
}
|
|
927
|
-
}
|
|
928
|
-
async function grabFrameViaVideo(stream) {
|
|
929
|
-
const video = document.createElement("video");
|
|
930
|
-
video.muted = true;
|
|
931
|
-
video.playsInline = true;
|
|
932
|
-
video.srcObject = stream;
|
|
933
|
-
try {
|
|
934
|
-
await video.play();
|
|
935
|
-
await new Promise((r) => requestAnimationFrame(() => r()));
|
|
936
|
-
if (!video.videoWidth || !video.videoHeight) return null;
|
|
937
|
-
return await createImageBitmap(video);
|
|
938
|
-
} catch {
|
|
939
|
-
return null;
|
|
901
|
+
if (parsed.protocol === "https:") return parsed.toString();
|
|
902
|
+
if (parsed.protocol === "http:" && (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "[::1]")) {
|
|
903
|
+
return parsed.toString();
|
|
940
904
|
}
|
|
905
|
+
return void 0;
|
|
941
906
|
}
|
|
942
907
|
|
|
943
908
|
// src/widget/ReportDetailView.tsx
|
|
@@ -1047,16 +1012,19 @@ function ReportDetailView({
|
|
|
1047
1012
|
/* @__PURE__ */ jsxs2("div", { class: "report-detail-body", children: [
|
|
1048
1013
|
/* @__PURE__ */ jsx2(ContextBlock, { detail, strings }),
|
|
1049
1014
|
/* @__PURE__ */ jsx2("p", { class: "report-detail-description", children: detail.description }),
|
|
1050
|
-
detail.screenshot_url &&
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1015
|
+
detail.screenshot_url && (() => {
|
|
1016
|
+
const safeHref = safeExternalHref(detail.screenshot_url);
|
|
1017
|
+
return safeHref ? /* @__PURE__ */ jsx2(
|
|
1018
|
+
"a",
|
|
1019
|
+
{
|
|
1020
|
+
class: "report-detail-screenshot",
|
|
1021
|
+
href: safeHref,
|
|
1022
|
+
target: "_blank",
|
|
1023
|
+
rel: "noopener noreferrer",
|
|
1024
|
+
children: /* @__PURE__ */ jsx2("img", { src: detail.screenshot_url, alt: "", loading: "lazy" })
|
|
1025
|
+
}
|
|
1026
|
+
) : /* @__PURE__ */ jsx2("div", { class: "report-detail-screenshot", children: /* @__PURE__ */ jsx2("img", { src: detail.screenshot_url, alt: "", loading: "lazy" }) });
|
|
1027
|
+
})(),
|
|
1060
1028
|
/* @__PURE__ */ jsx2("h3", { class: "report-detail-section", children: strings["detail.thread"] }),
|
|
1061
1029
|
detail.comments.length === 0 ? /* @__PURE__ */ jsx2("p", { class: "report-detail-empty", children: strings["detail.no_replies"] }) : /* @__PURE__ */ jsx2("ul", { class: "report-comments", children: detail.comments.map((c) => /* @__PURE__ */ jsx2("li", { children: /* @__PURE__ */ jsx2(CommentBubble, { comment: c, strings }) })) }),
|
|
1062
1030
|
detail.status_history && detail.status_history.length > 0 && /* @__PURE__ */ jsx2(StatusHistorySection, { rows: detail.status_history, strings }),
|
|
@@ -1115,19 +1083,22 @@ function ContextBlock({ detail, strings }) {
|
|
|
1115
1083
|
/* @__PURE__ */ jsx2("span", { class: "report-detail-context-label", children: strings["detail.context.submitted_at"] }),
|
|
1116
1084
|
/* @__PURE__ */ jsx2("span", { children: formatSubmittedAt(detail.created_at) })
|
|
1117
1085
|
] }),
|
|
1118
|
-
detail.page_url &&
|
|
1119
|
-
|
|
1120
|
-
/* @__PURE__ */
|
|
1121
|
-
"
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1086
|
+
detail.page_url && (() => {
|
|
1087
|
+
const safeHref = safeExternalHref(detail.page_url);
|
|
1088
|
+
return /* @__PURE__ */ jsxs2("div", { class: "report-detail-context-line", title: detail.page_url, children: [
|
|
1089
|
+
/* @__PURE__ */ jsx2("span", { class: "report-detail-context-label", children: strings["detail.context.page"] }),
|
|
1090
|
+
safeHref ? /* @__PURE__ */ jsx2(
|
|
1091
|
+
"a",
|
|
1092
|
+
{
|
|
1093
|
+
class: "report-detail-context-url",
|
|
1094
|
+
href: safeHref,
|
|
1095
|
+
target: "_blank",
|
|
1096
|
+
rel: "noopener noreferrer",
|
|
1097
|
+
children: truncateUrl(detail.page_url, 64)
|
|
1098
|
+
}
|
|
1099
|
+
) : /* @__PURE__ */ jsx2("span", { class: "report-detail-context-url", children: truncateUrl(detail.page_url, 64) })
|
|
1100
|
+
] });
|
|
1101
|
+
})()
|
|
1131
1102
|
] });
|
|
1132
1103
|
}
|
|
1133
1104
|
function formatSubmittedAt(iso) {
|
|
@@ -2347,10 +2318,8 @@ function Form({ strings, onSubmit, onCancel, status, errorMessage }) {
|
|
|
2347
2318
|
const [localError, setLocalError] = useState5("");
|
|
2348
2319
|
const [screenshotBlob, setScreenshotBlob] = useState5(null);
|
|
2349
2320
|
const [screenshotPreview, setScreenshotPreview] = useState5(null);
|
|
2350
|
-
const [screenshotMethod, setScreenshotMethod] = useState5("manual");
|
|
2351
2321
|
const [isDragOver, setIsDragOver] = useState5(false);
|
|
2352
2322
|
const [annotatorOpen, setAnnotatorOpen] = useState5(false);
|
|
2353
|
-
const [capturing, setCapturing] = useState5(false);
|
|
2354
2323
|
const fileInputRef = useRef4(null);
|
|
2355
2324
|
const dropZoneRef = useRef4(null);
|
|
2356
2325
|
const submitting = status === "submitting";
|
|
@@ -2361,7 +2330,7 @@ function Form({ strings, onSubmit, onCancel, status, errorMessage }) {
|
|
|
2361
2330
|
if (screenshotPreview) URL.revokeObjectURL(screenshotPreview);
|
|
2362
2331
|
};
|
|
2363
2332
|
}, [screenshotPreview]);
|
|
2364
|
-
const acceptFile = (file
|
|
2333
|
+
const acceptFile = (file) => {
|
|
2365
2334
|
setLocalError("");
|
|
2366
2335
|
if (file instanceof File) {
|
|
2367
2336
|
const err = validateScreenshotFile(file);
|
|
@@ -2375,41 +2344,14 @@ function Form({ strings, onSubmit, onCancel, status, errorMessage }) {
|
|
|
2375
2344
|
if (screenshotPreview) URL.revokeObjectURL(screenshotPreview);
|
|
2376
2345
|
setScreenshotBlob(file);
|
|
2377
2346
|
setScreenshotPreview(URL.createObjectURL(file));
|
|
2378
|
-
setScreenshotMethod(method);
|
|
2379
2347
|
};
|
|
2380
2348
|
const clearScreenshot = () => {
|
|
2381
2349
|
if (screenshotPreview) URL.revokeObjectURL(screenshotPreview);
|
|
2382
2350
|
setScreenshotPreview(null);
|
|
2383
2351
|
setScreenshotBlob(null);
|
|
2384
|
-
setScreenshotMethod("manual");
|
|
2385
2352
|
setLocalError("");
|
|
2386
2353
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
2387
2354
|
};
|
|
2388
|
-
const handleCapturePage = async () => {
|
|
2389
|
-
if (capturing) return;
|
|
2390
|
-
setLocalError("");
|
|
2391
|
-
setCapturing(true);
|
|
2392
|
-
try {
|
|
2393
|
-
const blob = await captureWithDisplayMedia();
|
|
2394
|
-
if (!blob) {
|
|
2395
|
-
if (typeof navigator === "undefined" || !navigator.mediaDevices?.getDisplayMedia) {
|
|
2396
|
-
setLocalError(strings["form.screenshot.capture_error"]);
|
|
2397
|
-
}
|
|
2398
|
-
return;
|
|
2399
|
-
}
|
|
2400
|
-
if (blob.size > 10 * 1024 * 1024) {
|
|
2401
|
-
setLocalError(
|
|
2402
|
-
strings["form.screenshot.error_size"].replace("{max}", "10")
|
|
2403
|
-
);
|
|
2404
|
-
return;
|
|
2405
|
-
}
|
|
2406
|
-
acceptFile(blob, "display_media");
|
|
2407
|
-
} catch {
|
|
2408
|
-
setLocalError(strings["form.screenshot.capture_error"]);
|
|
2409
|
-
} finally {
|
|
2410
|
-
setCapturing(false);
|
|
2411
|
-
}
|
|
2412
|
-
};
|
|
2413
2355
|
const handleFileInputChange = (e) => {
|
|
2414
2356
|
const file = e.target.files?.[0];
|
|
2415
2357
|
if (file) acceptFile(file);
|
|
@@ -2471,7 +2413,7 @@ function Form({ strings, onSubmit, onCancel, status, errorMessage }) {
|
|
|
2471
2413
|
};
|
|
2472
2414
|
if (screenshotBlob) {
|
|
2473
2415
|
values.screenshot = screenshotBlob;
|
|
2474
|
-
values.capture_method =
|
|
2416
|
+
values.capture_method = "manual";
|
|
2475
2417
|
}
|
|
2476
2418
|
onSubmit(values);
|
|
2477
2419
|
};
|
|
@@ -2584,43 +2526,7 @@ function Form({ strings, onSubmit, onCancel, status, errorMessage }) {
|
|
|
2584
2526
|
/* @__PURE__ */ jsx8("div", { class: "screenshot-formats", children: strings["form.screenshot.formats"] })
|
|
2585
2527
|
]
|
|
2586
2528
|
}
|
|
2587
|
-
)
|
|
2588
|
-
!screenshotPreview && /* @__PURE__ */ jsxs7("div", { class: "screenshot-alt", children: [
|
|
2589
|
-
/* @__PURE__ */ jsx8("span", { class: "screenshot-or", children: strings["form.screenshot.or"] }),
|
|
2590
|
-
/* @__PURE__ */ jsxs7(
|
|
2591
|
-
"button",
|
|
2592
|
-
{
|
|
2593
|
-
type: "button",
|
|
2594
|
-
class: "btn btn--ghost screenshot-capture-page",
|
|
2595
|
-
onClick: handleCapturePage,
|
|
2596
|
-
disabled: capturing || submitting,
|
|
2597
|
-
"aria-label": strings["form.screenshot.capture_page"],
|
|
2598
|
-
children: [
|
|
2599
|
-
/* @__PURE__ */ jsxs7(
|
|
2600
|
-
"svg",
|
|
2601
|
-
{
|
|
2602
|
-
width: "14",
|
|
2603
|
-
height: "14",
|
|
2604
|
-
viewBox: "0 0 24 24",
|
|
2605
|
-
fill: "none",
|
|
2606
|
-
stroke: "currentColor",
|
|
2607
|
-
"stroke-width": "2",
|
|
2608
|
-
"stroke-linecap": "round",
|
|
2609
|
-
"stroke-linejoin": "round",
|
|
2610
|
-
"aria-hidden": "true",
|
|
2611
|
-
children: [
|
|
2612
|
-
/* @__PURE__ */ jsx8("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2", ry: "2" }),
|
|
2613
|
-
/* @__PURE__ */ jsx8("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
|
|
2614
|
-
/* @__PURE__ */ jsx8("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
|
|
2615
|
-
]
|
|
2616
|
-
}
|
|
2617
|
-
),
|
|
2618
|
-
capturing ? strings["form.submitting"] : strings["form.screenshot.capture_page"]
|
|
2619
|
-
]
|
|
2620
|
-
}
|
|
2621
|
-
),
|
|
2622
|
-
/* @__PURE__ */ jsx8("span", { class: "screenshot-capture-hint", children: strings["form.screenshot.capture_page_hint"] })
|
|
2623
|
-
] })
|
|
2529
|
+
)
|
|
2624
2530
|
] }),
|
|
2625
2531
|
pageUrl && /* @__PURE__ */ jsxs7("div", { class: "page-context", title: pageUrl, children: [
|
|
2626
2532
|
/* @__PURE__ */ jsx8("span", { class: "page-context-label", children: strings["form.context.label"] }),
|
|
@@ -3261,40 +3167,6 @@ var WIDGET_STYLES = `
|
|
|
3261
3167
|
.screenshot-cta strong { color: var(--mfb-accent); font-weight: 600; }
|
|
3262
3168
|
.screenshot-formats { font-size: var(--mfb-text-xs); color: var(--mfb-text-muted); }
|
|
3263
3169
|
|
|
3264
|
-
/* "or \u2014 Capture this page" row sits below the dropzone. The thin "or"
|
|
3265
|
-
* separator borrows the pattern from auth forms so the second option
|
|
3266
|
-
* reads as an alternative, not a follow-up step. v0.12. */
|
|
3267
|
-
.screenshot-alt {
|
|
3268
|
-
display: flex;
|
|
3269
|
-
align-items: center;
|
|
3270
|
-
gap: 12px;
|
|
3271
|
-
margin-top: 8px;
|
|
3272
|
-
flex-wrap: wrap;
|
|
3273
|
-
}
|
|
3274
|
-
.screenshot-or {
|
|
3275
|
-
position: relative;
|
|
3276
|
-
font-size: var(--mfb-text-xs);
|
|
3277
|
-
color: var(--mfb-text-muted);
|
|
3278
|
-
text-transform: uppercase;
|
|
3279
|
-
letter-spacing: 0.08em;
|
|
3280
|
-
padding: 0 4px;
|
|
3281
|
-
}
|
|
3282
|
-
.screenshot-capture-page {
|
|
3283
|
-
display: inline-flex;
|
|
3284
|
-
align-items: center;
|
|
3285
|
-
gap: 6px;
|
|
3286
|
-
}
|
|
3287
|
-
.screenshot-capture-page:disabled {
|
|
3288
|
-
opacity: 0.55;
|
|
3289
|
-
cursor: progress;
|
|
3290
|
-
}
|
|
3291
|
-
.screenshot-capture-hint {
|
|
3292
|
-
font-size: var(--mfb-text-xs);
|
|
3293
|
-
color: var(--mfb-text-muted);
|
|
3294
|
-
flex: 1 1 100%;
|
|
3295
|
-
margin-top: 4px;
|
|
3296
|
-
}
|
|
3297
|
-
|
|
3298
3170
|
.screenshot-preview {
|
|
3299
3171
|
position: relative;
|
|
3300
3172
|
border: 1px solid var(--mfb-border);
|
|
@@ -4530,6 +4402,7 @@ function mountWidget(options) {
|
|
|
4530
4402
|
const mountPoint = document.createElement("div");
|
|
4531
4403
|
shadow.appendChild(mountPoint);
|
|
4532
4404
|
let currentState = { open: false, status: "idle", tab: "send" };
|
|
4405
|
+
let postSubmitTimer = null;
|
|
4533
4406
|
function rerender(state) {
|
|
4534
4407
|
currentState = state;
|
|
4535
4408
|
render(h(Root, { state }), mountPoint);
|
|
@@ -4545,8 +4418,10 @@ function mountWidget(options) {
|
|
|
4545
4418
|
try {
|
|
4546
4419
|
await options.onSubmit(values);
|
|
4547
4420
|
rerender({ ...currentState, status: "success" });
|
|
4548
|
-
|
|
4549
|
-
|
|
4421
|
+
if (postSubmitTimer !== null) clearTimeout(postSubmitTimer);
|
|
4422
|
+
postSubmitTimer = setTimeout(() => {
|
|
4423
|
+
postSubmitTimer = null;
|
|
4424
|
+
rerender({
|
|
4550
4425
|
...currentState,
|
|
4551
4426
|
open: false,
|
|
4552
4427
|
status: "idle",
|
|
@@ -4554,9 +4429,8 @@ function mountWidget(options) {
|
|
|
4554
4429
|
// they immediately see their just-filed report in the list
|
|
4555
4430
|
// (and the conversation that's about to start).
|
|
4556
4431
|
tab: options.api ? "mine" : "send"
|
|
4557
|
-
})
|
|
4558
|
-
|
|
4559
|
-
);
|
|
4432
|
+
});
|
|
4433
|
+
}, 1200);
|
|
4560
4434
|
} catch (err) {
|
|
4561
4435
|
rerender({
|
|
4562
4436
|
...currentState,
|
|
@@ -4691,6 +4565,10 @@ function mountWidget(options) {
|
|
|
4691
4565
|
rerender({ ...currentState, open: false, status: "idle" });
|
|
4692
4566
|
},
|
|
4693
4567
|
dispose() {
|
|
4568
|
+
if (postSubmitTimer !== null) {
|
|
4569
|
+
clearTimeout(postSubmitTimer);
|
|
4570
|
+
postSubmitTimer = null;
|
|
4571
|
+
}
|
|
4694
4572
|
render(null, mountPoint);
|
|
4695
4573
|
options.host.innerHTML = "";
|
|
4696
4574
|
},
|
|
@@ -4743,7 +4621,10 @@ function createFeedback(config) {
|
|
|
4743
4621
|
async function buildAndSubmit(values) {
|
|
4744
4622
|
const manualScreenshot = values.synthetic ? void 0 : values.screenshot;
|
|
4745
4623
|
const technical_context = capture.snapshot();
|
|
4746
|
-
if (user)
|
|
4624
|
+
if (user) {
|
|
4625
|
+
const { userHash: _hash, exp: _exp, ...safeUser } = user;
|
|
4626
|
+
technical_context.user = safeUser;
|
|
4627
|
+
}
|
|
4747
4628
|
if (metadata && Object.keys(metadata).length > 0) {
|
|
4748
4629
|
technical_context.metadata = { ...metadata };
|
|
4749
4630
|
}
|
|
@@ -4758,8 +4639,8 @@ function createFeedback(config) {
|
|
|
4758
4639
|
capture_method: captureMethod,
|
|
4759
4640
|
technical_context
|
|
4760
4641
|
};
|
|
4761
|
-
if ("0.
|
|
4762
|
-
payload.widget_version = "0.
|
|
4642
|
+
if ("0.15.0") {
|
|
4643
|
+
payload.widget_version = "0.15.0";
|
|
4763
4644
|
}
|
|
4764
4645
|
if (manualScreenshot) payload.screenshot = manualScreenshot;
|
|
4765
4646
|
if (values.synthetic) payload.synthetic = true;
|
|
@@ -4845,4 +4726,4 @@ function createFeedback(config) {
|
|
|
4845
4726
|
export {
|
|
4846
4727
|
createFeedback
|
|
4847
4728
|
};
|
|
4848
|
-
//# sourceMappingURL=chunk-
|
|
4729
|
+
//# sourceMappingURL=chunk-67JM6XVT.mjs.map
|