@firstlook-uat/sdk 0.4.0 โ 0.4.2
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/firstlook.es.js +207 -118
- package/dist/firstlook.es.js.map +1 -1
- package/dist/firstlook.umd.js +50 -3
- package/dist/firstlook.umd.js.map +1 -1
- package/package.json +1 -1
package/dist/firstlook.es.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const
|
|
1
|
+
const I = [
|
|
2
2
|
'input[type="password"]',
|
|
3
3
|
"[data-sensitive]",
|
|
4
4
|
"[data-mask]",
|
|
5
5
|
".uat-mask"
|
|
6
6
|
];
|
|
7
|
-
function
|
|
7
|
+
function M(a) {
|
|
8
8
|
var t, e, s, i, n, o, l, c, h, d;
|
|
9
9
|
if (!a.endpoint)
|
|
10
10
|
throw new Error("[FirstLook] 'endpoint' is required. Set your Supabase ingest-session URL.");
|
|
@@ -23,7 +23,7 @@ function q(a) {
|
|
|
23
23
|
},
|
|
24
24
|
security: {
|
|
25
25
|
watermark: ((n = a.security) == null ? void 0 : n.watermark) ?? !0,
|
|
26
|
-
maskSelectors: ((o = a.security) == null ? void 0 : o.maskSelectors) ??
|
|
26
|
+
maskSelectors: ((o = a.security) == null ? void 0 : o.maskSelectors) ?? I
|
|
27
27
|
},
|
|
28
28
|
recording: {
|
|
29
29
|
domSnapshot: ((l = a.recording) == null ? void 0 : l.domSnapshot) ?? !0,
|
|
@@ -33,7 +33,7 @@ function q(a) {
|
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
function
|
|
36
|
+
function y() {
|
|
37
37
|
return {
|
|
38
38
|
userAgent: navigator.userAgent,
|
|
39
39
|
platform: navigator.platform,
|
|
@@ -44,7 +44,7 @@ function w() {
|
|
|
44
44
|
touchSupport: "ontouchstart" in window || navigator.maxTouchPoints > 0
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
|
-
class
|
|
47
|
+
class E {
|
|
48
48
|
constructor() {
|
|
49
49
|
this.listeners = /* @__PURE__ */ new Map();
|
|
50
50
|
}
|
|
@@ -75,7 +75,7 @@ class C {
|
|
|
75
75
|
this.listeners.clear();
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
class
|
|
78
|
+
class R {
|
|
79
79
|
constructor(t) {
|
|
80
80
|
this.events = t, this.quests = [], this.results = [], this.currentIndex = -1, this.sessionStartTime = 0, this.blocked = !1, this.pendingFeedbacks = [];
|
|
81
81
|
}
|
|
@@ -116,15 +116,16 @@ class I {
|
|
|
116
116
|
logs: t,
|
|
117
117
|
comment: e == null ? void 0 : e.comment,
|
|
118
118
|
concern: (e == null ? void 0 : e.concern) ?? !1,
|
|
119
|
-
feedbacks: this.drainFeedbacks()
|
|
119
|
+
feedbacks: this.drainFeedbacks(),
|
|
120
|
+
checklist: e == null ? void 0 : e.checklist
|
|
120
121
|
};
|
|
121
122
|
return this.results.push(i), this.events.emit({ type: "quest:completed", questId: s.id }), this.advance(), i;
|
|
122
123
|
}
|
|
123
|
-
failCurrentQuest(t, e, s) {
|
|
124
|
-
const
|
|
125
|
-
if (!
|
|
126
|
-
const
|
|
127
|
-
questId:
|
|
124
|
+
failCurrentQuest(t, e, s, i) {
|
|
125
|
+
const n = this.getCurrentQuest();
|
|
126
|
+
if (!n) return null;
|
|
127
|
+
const o = {
|
|
128
|
+
questId: n.id,
|
|
128
129
|
status: "FAILED",
|
|
129
130
|
timestamp: Date.now(),
|
|
130
131
|
relativeTime: Date.now() - this.sessionStartTime,
|
|
@@ -132,9 +133,10 @@ class I {
|
|
|
132
133
|
logs: t,
|
|
133
134
|
comment: e,
|
|
134
135
|
concern: !1,
|
|
135
|
-
feedbacks: this.drainFeedbacks()
|
|
136
|
+
feedbacks: this.drainFeedbacks(),
|
|
137
|
+
checklist: i
|
|
136
138
|
};
|
|
137
|
-
return this.results.push(
|
|
139
|
+
return this.results.push(o), this.events.emit({ type: "quest:failed", questId: n.id }), n.blocking ? (this.blocked = !0, this.events.emit({ type: "quest:blocked", questId: n.id })) : this.advance(), o;
|
|
138
140
|
}
|
|
139
141
|
addFeedback(t) {
|
|
140
142
|
this.pendingFeedbacks.push(t);
|
|
@@ -160,16 +162,34 @@ function r(a, t, e) {
|
|
|
160
162
|
typeof i == "string" ? s.appendChild(document.createTextNode(i)) : s.appendChild(i);
|
|
161
163
|
return s;
|
|
162
164
|
}
|
|
163
|
-
function
|
|
165
|
+
function L() {
|
|
164
166
|
return `fl_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
165
167
|
}
|
|
166
|
-
function
|
|
168
|
+
function A(a) {
|
|
167
169
|
const t = Math.floor(a / 60), e = a % 60;
|
|
168
170
|
return `${t.toString().padStart(2, "0")}:${e.toString().padStart(2, "0")}`;
|
|
169
171
|
}
|
|
170
|
-
|
|
172
|
+
function D(a) {
|
|
173
|
+
const t = a.split(`
|
|
174
|
+
`), e = [], s = [];
|
|
175
|
+
let i = !1;
|
|
176
|
+
for (const n of t) {
|
|
177
|
+
const o = n.trim(), l = o.match(/^(?:(\d+)[\.\)]\s+|[-*]\s+)(.+)$/);
|
|
178
|
+
l ? (i = !0, s.push({
|
|
179
|
+
index: s.length,
|
|
180
|
+
text: l[2],
|
|
181
|
+
checked: !1
|
|
182
|
+
})) : !i && o && e.push(o);
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
preamble: e.join(`
|
|
186
|
+
`),
|
|
187
|
+
items: s
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
class N {
|
|
171
191
|
constructor(t, e) {
|
|
172
|
-
this.shadowRoot = t, this.callbacks = e, this.minimized = !1, this.timerInterval = null, this.startTime = 0, this.root = document.createElement("div"), this.root.className = "fl-quest-overlay", this.root.style.pointerEvents = "auto";
|
|
192
|
+
this.shadowRoot = t, this.callbacks = e, this.minimized = !1, this.timerInterval = null, this.startTime = 0, this.checklist = [], this.root = document.createElement("div"), this.root.className = "fl-quest-overlay", this.root.style.pointerEvents = "auto";
|
|
173
193
|
for (const s of ["click", "mousedown", "mouseup", "pointerdown", "pointerup", "touchstart", "touchend"])
|
|
174
194
|
this.root.addEventListener(s, (i) => i.stopPropagation());
|
|
175
195
|
this.shadowRoot.appendChild(this.root);
|
|
@@ -186,37 +206,54 @@ class E {
|
|
|
186
206
|
this.root.appendChild(n);
|
|
187
207
|
const o = r("div", { className: "fl-quest-content" }), l = r("div", { className: "fl-quest-progress" });
|
|
188
208
|
for (const f of e) {
|
|
189
|
-
const
|
|
190
|
-
l.appendChild(r("div", { className: `fl-quest-progress-dot ${
|
|
209
|
+
const p = f === "COMPLETED" ? "fl-completed" : f === "FAILED" ? "fl-failed" : f === "ACTIVE" ? "fl-active" : "";
|
|
210
|
+
l.appendChild(r("div", { className: `fl-quest-progress-dot ${p}` }));
|
|
191
211
|
}
|
|
192
|
-
const c =
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
212
|
+
const c = D(t.description);
|
|
213
|
+
this.checklist = c.items;
|
|
214
|
+
const h = r("div", { className: "fl-quest-body" });
|
|
215
|
+
if (h.appendChild(l), c.items.length > 0) {
|
|
216
|
+
const f = r("div", { className: "fl-checklist-counter" }), p = () => {
|
|
217
|
+
const b = this.checklist.filter((k) => k.checked).length;
|
|
218
|
+
f.textContent = `โ ${b}/${this.checklist.length} ็ขบ่ชๆธใฟ`;
|
|
219
|
+
};
|
|
220
|
+
p(), h.appendChild(f), c.preamble && h.appendChild(r("p", { className: "fl-quest-description" }, [c.preamble]));
|
|
221
|
+
const g = r("ul", { className: "fl-checklist" });
|
|
222
|
+
for (const b of this.checklist) {
|
|
223
|
+
const k = r("li", { className: "fl-checklist-item" }), v = document.createElement("input");
|
|
224
|
+
v.type = "checkbox", v.className = "fl-checklist-checkbox", v.checked = b.checked;
|
|
225
|
+
const T = r("span", { className: "fl-checklist-text" }, [b.text]);
|
|
226
|
+
v.onchange = () => {
|
|
227
|
+
b.checked = v.checked, k.classList.toggle("fl-checked", b.checked), p();
|
|
228
|
+
}, k.onclick = (q) => {
|
|
229
|
+
q.target !== v && (v.checked = !v.checked, b.checked = v.checked, k.classList.toggle("fl-checked", b.checked), p());
|
|
230
|
+
}, k.appendChild(v), k.appendChild(T), g.appendChild(k);
|
|
231
|
+
}
|
|
232
|
+
h.appendChild(g);
|
|
233
|
+
} else
|
|
234
|
+
h.appendChild(r("p", { className: "fl-quest-description" }, [t.description]));
|
|
235
|
+
h.appendChild(r("div", { className: "fl-quest-memo-row" }, [
|
|
236
|
+
this.createButton("fl-btn fl-btn-memo", "๐ ใกใขใๆฎใ", () => this.renderFeedbackModal(t.title))
|
|
237
|
+
])), h.appendChild(r("div", { className: "fl-quest-actions" }, [
|
|
238
|
+
this.createButton("fl-btn fl-btn-ok", "โ OK", () => this.renderFeedbackModal(t.title, "ok")),
|
|
239
|
+
this.createButton("fl-btn fl-btn-concern", "โ ๆฐใซใชใ", () => this.renderFeedbackModal(t.title, "concern")),
|
|
240
|
+
this.createButton("fl-btn fl-btn-ng", "โ NG", this.callbacks.onNg)
|
|
241
|
+
])), o.appendChild(h), s && o.appendChild(
|
|
205
242
|
r("div", { className: "fl-voice-indicator" }, [
|
|
206
243
|
r("span", { className: "fl-voice-dot" }),
|
|
207
244
|
"Recording..."
|
|
208
245
|
])
|
|
209
246
|
);
|
|
210
|
-
const
|
|
211
|
-
s &&
|
|
247
|
+
const d = r("div", { className: "fl-status-bar" });
|
|
248
|
+
s && d.appendChild(
|
|
212
249
|
r("span", { className: "fl-status-recording" }, [
|
|
213
250
|
r("span", { className: "fl-voice-dot" }),
|
|
214
251
|
"REC"
|
|
215
252
|
])
|
|
216
253
|
);
|
|
217
|
-
const
|
|
218
|
-
|
|
219
|
-
this.minimized && (this.minimized = !1, this.root.className = "fl-quest-overlay", this.root.innerHTML = "", this.root.appendChild(n), this.root.appendChild(o), this.startTimer(
|
|
254
|
+
const m = r("span", { className: "fl-status-timer" }, ["00:00"]);
|
|
255
|
+
d.appendChild(m), o.appendChild(d), this.root.appendChild(o), this.startTimer(m), this.root.onclick = () => {
|
|
256
|
+
this.minimized && (this.minimized = !1, this.root.className = "fl-quest-overlay", this.root.innerHTML = "", this.root.appendChild(n), this.root.appendChild(o), this.startTimer(m));
|
|
220
257
|
};
|
|
221
258
|
}
|
|
222
259
|
renderFeedbackModal(t, e = "memo") {
|
|
@@ -249,25 +286,24 @@ class E {
|
|
|
249
286
|
memo: "ๆฐใฅใใใใจใใกใข...๐"
|
|
250
287
|
}, d = document.createElement("textarea");
|
|
251
288
|
d.className = "fl-feedback-textarea fl-feedback-textarea-modal", d.placeholder = h[e], d.rows = 3, c.appendChild(d);
|
|
252
|
-
const
|
|
253
|
-
this.createButton("fl-btn fl-btn-skip",
|
|
254
|
-
e === "ng" ? this.callbacks.onNgWithFeedback("") : e === "ok"
|
|
289
|
+
const m = "้ไฟก", f = e === "ok" ? "ในใญใใ" : "ใญใฃใณใปใซ", p = r("div", { className: "fl-quest-actions fl-feedback-modal-actions" }, [
|
|
290
|
+
this.createButton("fl-btn fl-btn-skip", f, () => {
|
|
291
|
+
e === "ng" ? this.callbacks.onNgWithFeedback("") : e === "ok" ? this.callbacks.onOkWithFeedback("") : e === "concern" && this.callbacks.onConcern(""), s.remove();
|
|
255
292
|
}),
|
|
256
|
-
this.createButton("fl-btn fl-btn-finish",
|
|
257
|
-
const
|
|
293
|
+
this.createButton("fl-btn fl-btn-finish", m, () => {
|
|
294
|
+
const g = d.value.trim();
|
|
258
295
|
if (e === "ng")
|
|
259
|
-
this.callbacks.onNgWithFeedback(
|
|
296
|
+
this.callbacks.onNgWithFeedback(g);
|
|
260
297
|
else if (e === "ok")
|
|
261
|
-
this.callbacks.onOkWithFeedback(
|
|
262
|
-
else if (e === "concern")
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (!m) {
|
|
298
|
+
this.callbacks.onOkWithFeedback(g);
|
|
299
|
+
else if (e === "concern")
|
|
300
|
+
this.callbacks.onConcern(g);
|
|
301
|
+
else {
|
|
302
|
+
if (!g) {
|
|
267
303
|
s.remove();
|
|
268
304
|
return;
|
|
269
305
|
}
|
|
270
|
-
this.callbacks.onMemo(
|
|
306
|
+
this.callbacks.onMemo(g);
|
|
271
307
|
}
|
|
272
308
|
s.remove();
|
|
273
309
|
})
|
|
@@ -304,6 +340,9 @@ class E {
|
|
|
304
340
|
]);
|
|
305
341
|
this.root.appendChild(e);
|
|
306
342
|
}
|
|
343
|
+
getChecklist() {
|
|
344
|
+
return this.checklist.length > 0 ? [...this.checklist] : void 0;
|
|
345
|
+
}
|
|
307
346
|
destroy() {
|
|
308
347
|
this.stopTimer(), this.root.remove();
|
|
309
348
|
}
|
|
@@ -330,15 +369,15 @@ class E {
|
|
|
330
369
|
startTimer(t) {
|
|
331
370
|
this.stopTimer(), this.startTime || (this.startTime = Date.now()), this.timerInterval = setInterval(() => {
|
|
332
371
|
const e = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
333
|
-
t.textContent =
|
|
372
|
+
t.textContent = A(e);
|
|
334
373
|
}, 1e3);
|
|
335
374
|
}
|
|
336
375
|
stopTimer() {
|
|
337
376
|
this.timerInterval && (clearInterval(this.timerInterval), this.timerInterval = null);
|
|
338
377
|
}
|
|
339
378
|
}
|
|
340
|
-
const
|
|
341
|
-
class
|
|
379
|
+
const F = 100, P = 2 * 1024 * 1024;
|
|
380
|
+
class z {
|
|
342
381
|
constructor(t, e, s) {
|
|
343
382
|
this.config = t, this.events = e, this.maskSelector = s, this.actionLogs = [], this.snapshots = [], this.snapshotTimer = null, this.startTime = 0, this.running = !1, this.handleClick = this.onClick.bind(this), this.handleScroll = this.throttle(this.onScroll.bind(this), 500), this.handleInput = this.onInput.bind(this);
|
|
344
383
|
}
|
|
@@ -405,8 +444,8 @@ class D {
|
|
|
405
444
|
const s = t.querySelector("#firstlook-sdk-root");
|
|
406
445
|
s == null || s.remove();
|
|
407
446
|
const i = t.outerHTML;
|
|
408
|
-
if (i.length >
|
|
409
|
-
this.snapshots.length >=
|
|
447
|
+
if (i.length > P) return;
|
|
448
|
+
this.snapshots.length >= F && this.snapshots.shift(), this.snapshots.push({
|
|
410
449
|
type: "dom-snapshot",
|
|
411
450
|
timestamp: Date.now() - this.startTime,
|
|
412
451
|
data: i
|
|
@@ -427,7 +466,7 @@ function x(a) {
|
|
|
427
466
|
const t = a.tagName.toLowerCase(), e = a.id ? `#${a.id}` : "", s = a.className && typeof a.className == "string" ? `.${a.className.trim().split(/\s+/).slice(0, 2).join(".")}` : "", i = ((n = a.textContent) == null ? void 0 : n.trim().slice(0, 30)) || "";
|
|
428
467
|
return `${t}${e}${s}${i ? ` "${i}"` : ""}`;
|
|
429
468
|
}
|
|
430
|
-
class
|
|
469
|
+
class O {
|
|
431
470
|
constructor(t) {
|
|
432
471
|
this.events = t, this.mediaRecorder = null, this.stream = null, this.chunks = [], this._recording = !1;
|
|
433
472
|
}
|
|
@@ -486,7 +525,7 @@ class N {
|
|
|
486
525
|
return "";
|
|
487
526
|
}
|
|
488
527
|
}
|
|
489
|
-
class
|
|
528
|
+
class Q {
|
|
490
529
|
constructor(t, e) {
|
|
491
530
|
this.shadowRoot = t, this.config = e, this.container = null, this.refreshInterval = null, this.cachedIp = null;
|
|
492
531
|
}
|
|
@@ -516,7 +555,7 @@ class F {
|
|
|
516
555
|
}
|
|
517
556
|
}
|
|
518
557
|
}
|
|
519
|
-
class
|
|
558
|
+
class B {
|
|
520
559
|
constructor(t) {
|
|
521
560
|
this.selectors = t, this.observer = null, this.maskedElements = /* @__PURE__ */ new Set();
|
|
522
561
|
}
|
|
@@ -554,20 +593,20 @@ class P {
|
|
|
554
593
|
}
|
|
555
594
|
}
|
|
556
595
|
}
|
|
557
|
-
const
|
|
596
|
+
const $ = "firstlook_uat", U = 1, u = {
|
|
558
597
|
sessions: "sessions",
|
|
559
598
|
recordings: "recordings",
|
|
560
599
|
annotations: "annotations",
|
|
561
600
|
uploadQueue: "upload_queue"
|
|
562
601
|
};
|
|
563
|
-
class
|
|
602
|
+
class j {
|
|
564
603
|
constructor() {
|
|
565
604
|
this.db = null;
|
|
566
605
|
}
|
|
567
606
|
async open() {
|
|
568
607
|
if (!this.db)
|
|
569
608
|
return new Promise((t, e) => {
|
|
570
|
-
const s = indexedDB.open(
|
|
609
|
+
const s = indexedDB.open($, U);
|
|
571
610
|
s.onupgradeneeded = () => {
|
|
572
611
|
const i = s.result;
|
|
573
612
|
i.objectStoreNames.contains(u.sessions) || i.createObjectStore(u.sessions, { keyPath: "sessionId" }), i.objectStoreNames.contains(u.recordings) || i.createObjectStore(u.recordings, { autoIncrement: !0 }).createIndex("sessionId", "sessionId", { unique: !1 }), i.objectStoreNames.contains(u.annotations) || i.createObjectStore(u.annotations, { autoIncrement: !0 }).createIndex("sessionId", "sessionId", { unique: !1 }), i.objectStoreNames.contains(u.uploadQueue) || i.createObjectStore(u.uploadQueue, { autoIncrement: !0 });
|
|
@@ -677,10 +716,10 @@ class Q {
|
|
|
677
716
|
});
|
|
678
717
|
}
|
|
679
718
|
}
|
|
680
|
-
const
|
|
681
|
-
class
|
|
719
|
+
const S = ["#e17055", "#6c5ce7", "#00b894", "#fdcb6e", "#ffffff"];
|
|
720
|
+
class K {
|
|
682
721
|
constructor(t) {
|
|
683
|
-
this.shadowRoot = t, this.overlay = null, this.canvas = null, this.ctx = null, this.drawing = !1, this.currentPath = [], this.paths = [], this.selectedColor =
|
|
722
|
+
this.shadowRoot = t, this.overlay = null, this.canvas = null, this.ctx = null, this.drawing = !1, this.currentPath = [], this.paths = [], this.selectedColor = S[0], this.screenshotDataUrl = "";
|
|
684
723
|
}
|
|
685
724
|
async open() {
|
|
686
725
|
return this.screenshotDataUrl = await this.captureScreenshot(), new Promise((t) => {
|
|
@@ -692,7 +731,7 @@ class B {
|
|
|
692
731
|
type: "text",
|
|
693
732
|
placeholder: "Add a comment..."
|
|
694
733
|
}), i = r("div", { className: "fl-color-picker" });
|
|
695
|
-
for (const c of
|
|
734
|
+
for (const c of S) {
|
|
696
735
|
const h = r("div", { className: `fl-color-swatch ${c === this.selectedColor ? "fl-selected" : ""}` });
|
|
697
736
|
h.style.background = c, h.onclick = () => {
|
|
698
737
|
this.selectedColor = c, i.querySelectorAll(".fl-color-swatch").forEach((d) => d.classList.remove("fl-selected")), h.classList.add("fl-selected");
|
|
@@ -742,16 +781,16 @@ class B {
|
|
|
742
781
|
<foreignObject width="100%" height="100%">
|
|
743
782
|
${l}
|
|
744
783
|
</foreignObject>
|
|
745
|
-
</svg>`, h = new Blob([c], { type: "image/svg+xml;charset=utf-8" }), d = URL.createObjectURL(h),
|
|
746
|
-
|
|
747
|
-
const
|
|
748
|
-
return
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
},
|
|
784
|
+
</svg>`, h = new Blob([c], { type: "image/svg+xml;charset=utf-8" }), d = URL.createObjectURL(h), m = document.createElement("canvas");
|
|
785
|
+
m.width = t * window.devicePixelRatio, m.height = e * window.devicePixelRatio;
|
|
786
|
+
const f = m.getContext("2d");
|
|
787
|
+
return f.scale(window.devicePixelRatio, window.devicePixelRatio), new Promise((p) => {
|
|
788
|
+
const g = new Image();
|
|
789
|
+
g.onload = () => {
|
|
790
|
+
f.drawImage(g, 0, 0, t, e), URL.revokeObjectURL(d), p(m.toDataURL("image/png"));
|
|
791
|
+
}, g.onerror = () => {
|
|
753
792
|
URL.revokeObjectURL(d), p(this.captureScreenshotFallback(t, e));
|
|
754
|
-
},
|
|
793
|
+
}, g.src = d;
|
|
755
794
|
});
|
|
756
795
|
} catch {
|
|
757
796
|
return this.captureScreenshotFallback(window.innerWidth, window.innerHeight);
|
|
@@ -796,11 +835,11 @@ class B {
|
|
|
796
835
|
return ((t = this.canvas) == null ? void 0 : t.toDataURL("image/png")) || this.screenshotDataUrl;
|
|
797
836
|
}
|
|
798
837
|
}
|
|
799
|
-
class
|
|
838
|
+
class H {
|
|
800
839
|
constructor(t, e) {
|
|
801
840
|
this.shadowRoot = t, this.events = e, this.annotations = [], this.active = !1, this.onKeydown = (s) => {
|
|
802
841
|
s.ctrlKey && s.shiftKey && s.key === "R" && (s.preventDefault(), this.trigger());
|
|
803
|
-
}, this.annotationCanvas = new
|
|
842
|
+
}, this.annotationCanvas = new K(t);
|
|
804
843
|
}
|
|
805
844
|
start() {
|
|
806
845
|
document.addEventListener("keydown", this.onKeydown);
|
|
@@ -823,7 +862,7 @@ class U {
|
|
|
823
862
|
}
|
|
824
863
|
}
|
|
825
864
|
}
|
|
826
|
-
class
|
|
865
|
+
class _ {
|
|
827
866
|
constructor(t, e) {
|
|
828
867
|
this.requiredTaps = t, this.onActivate = e, this.tapCount = 0, this.tapTimer = null, this.handler = null;
|
|
829
868
|
}
|
|
@@ -840,8 +879,8 @@ class j {
|
|
|
840
879
|
this.tapCount = 0, this.tapTimer && (clearTimeout(this.tapTimer), this.tapTimer = null);
|
|
841
880
|
}
|
|
842
881
|
}
|
|
843
|
-
const
|
|
844
|
-
class
|
|
882
|
+
const w = "firstlook:uat-active";
|
|
883
|
+
class C {
|
|
845
884
|
constructor(t) {
|
|
846
885
|
this.onActivate = t, this.handlers = [];
|
|
847
886
|
}
|
|
@@ -866,7 +905,7 @@ class S {
|
|
|
866
905
|
}
|
|
867
906
|
static clearPersisted() {
|
|
868
907
|
try {
|
|
869
|
-
sessionStorage.removeItem(
|
|
908
|
+
sessionStorage.removeItem(w);
|
|
870
909
|
} catch {
|
|
871
910
|
}
|
|
872
911
|
}
|
|
@@ -884,19 +923,19 @@ class S {
|
|
|
884
923
|
}
|
|
885
924
|
persist() {
|
|
886
925
|
try {
|
|
887
|
-
sessionStorage.setItem(
|
|
926
|
+
sessionStorage.setItem(w, "1");
|
|
888
927
|
} catch {
|
|
889
928
|
}
|
|
890
929
|
}
|
|
891
930
|
hasPersisted() {
|
|
892
931
|
try {
|
|
893
|
-
return sessionStorage.getItem(
|
|
932
|
+
return sessionStorage.getItem(w) === "1";
|
|
894
933
|
} catch {
|
|
895
934
|
return !1;
|
|
896
935
|
}
|
|
897
936
|
}
|
|
898
937
|
}
|
|
899
|
-
class
|
|
938
|
+
class W {
|
|
900
939
|
constructor(t) {
|
|
901
940
|
this.onActivate = t, this.handler = null;
|
|
902
941
|
}
|
|
@@ -909,7 +948,7 @@ class $ {
|
|
|
909
948
|
this.handler && (window.removeEventListener("keydown", this.handler), this.handler = null);
|
|
910
949
|
}
|
|
911
950
|
}
|
|
912
|
-
class
|
|
951
|
+
class V {
|
|
913
952
|
constructor(t, e) {
|
|
914
953
|
this.shadowRoot = t, this.callbacks = e, this.root = null, this.outsideClickHandler = null;
|
|
915
954
|
}
|
|
@@ -946,7 +985,7 @@ class K {
|
|
|
946
985
|
return this.root !== null;
|
|
947
986
|
}
|
|
948
987
|
}
|
|
949
|
-
const
|
|
988
|
+
const X = (
|
|
950
989
|
/* css */
|
|
951
990
|
`
|
|
952
991
|
:host {
|
|
@@ -1157,6 +1196,51 @@ const H = (
|
|
|
1157
1196
|
50% { opacity: 0.3; }
|
|
1158
1197
|
}
|
|
1159
1198
|
|
|
1199
|
+
/* === Checklist === */
|
|
1200
|
+
.fl-checklist-counter {
|
|
1201
|
+
font-size: 13px;
|
|
1202
|
+
font-weight: 600;
|
|
1203
|
+
color: #6c5ce7;
|
|
1204
|
+
margin-bottom: 8px;
|
|
1205
|
+
}
|
|
1206
|
+
.fl-checklist {
|
|
1207
|
+
list-style: none;
|
|
1208
|
+
padding: 0;
|
|
1209
|
+
margin: 0 0 12px;
|
|
1210
|
+
max-height: 240px;
|
|
1211
|
+
overflow-y: auto;
|
|
1212
|
+
-webkit-overflow-scrolling: touch;
|
|
1213
|
+
}
|
|
1214
|
+
.fl-checklist-item {
|
|
1215
|
+
display: flex;
|
|
1216
|
+
align-items: flex-start;
|
|
1217
|
+
gap: 8px;
|
|
1218
|
+
padding: 8px 4px;
|
|
1219
|
+
border-bottom: 1px solid rgba(0,0,0,.06);
|
|
1220
|
+
font-size: 13px;
|
|
1221
|
+
color: #4a4a5a;
|
|
1222
|
+
cursor: pointer;
|
|
1223
|
+
min-height: 40px;
|
|
1224
|
+
transition: background .2s;
|
|
1225
|
+
}
|
|
1226
|
+
.fl-checklist-item:last-child { border-bottom: none; }
|
|
1227
|
+
.fl-checklist-item:active { background: rgba(108,92,231,.05); }
|
|
1228
|
+
.fl-checklist-item.fl-checked { color: #aaa; }
|
|
1229
|
+
.fl-checklist-item.fl-checked .fl-checklist-text { text-decoration: line-through; }
|
|
1230
|
+
.fl-checklist-checkbox {
|
|
1231
|
+
margin-top: 2px;
|
|
1232
|
+
width: 18px;
|
|
1233
|
+
height: 18px;
|
|
1234
|
+
accent-color: #6c5ce7;
|
|
1235
|
+
flex-shrink: 0;
|
|
1236
|
+
cursor: pointer;
|
|
1237
|
+
}
|
|
1238
|
+
.fl-checklist-text {
|
|
1239
|
+
flex: 1;
|
|
1240
|
+
line-height: 1.4;
|
|
1241
|
+
word-break: break-word;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1160
1244
|
/* === Annotation overlay === */
|
|
1161
1245
|
.fl-annotation-overlay {
|
|
1162
1246
|
position: fixed;
|
|
@@ -1402,10 +1486,10 @@ const H = (
|
|
|
1402
1486
|
}
|
|
1403
1487
|
.fl-feedback-modal-actions { padding: 0 16px 16px; }
|
|
1404
1488
|
`
|
|
1405
|
-
),
|
|
1406
|
-
class
|
|
1489
|
+
), Y = 5;
|
|
1490
|
+
class G {
|
|
1407
1491
|
constructor() {
|
|
1408
|
-
this.config = null, this.events = new
|
|
1492
|
+
this.config = null, this.events = new E(), this.state = "idle", this.hostElement = null, this.shadowRoot = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.watermark = null, this.fieldMasker = null, this.storage = null, this.issueReporter = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.sessionId = null, this.sessionStartTime = 0, this.maxDurationTimer = null, this.backupTimer = null, this.isFlushing = !1;
|
|
1409
1493
|
}
|
|
1410
1494
|
// ----------------------------------------------------------------
|
|
1411
1495
|
// Public API
|
|
@@ -1419,7 +1503,7 @@ class W {
|
|
|
1419
1503
|
console.warn("[FirstLook] SDK already initialized.");
|
|
1420
1504
|
return;
|
|
1421
1505
|
}
|
|
1422
|
-
this.config =
|
|
1506
|
+
this.config = M(t), this.storage = new j(), await this.storage.open(), this.createShadowHost(), this.setupTriggers(), this.fieldMasker = new B(this.config.security.maskSelectors), this.state = "initialized", this.events.emit({ type: "sdk:initialized" }), this.flushUploadQueue(!0);
|
|
1423
1507
|
}
|
|
1424
1508
|
/**
|
|
1425
1509
|
* Manually activate the SDK UI (bypassing triggers).
|
|
@@ -1438,11 +1522,11 @@ class W {
|
|
|
1438
1522
|
var s;
|
|
1439
1523
|
if (this.state !== "active")
|
|
1440
1524
|
throw new Error("[FirstLook] Cannot start session: SDK not active. Call activate() first.");
|
|
1441
|
-
(s = this.debugMenu) == null || s.hide(), this.sessionId =
|
|
1525
|
+
(s = this.debugMenu) == null || s.hide(), this.sessionId = L(), this.sessionStartTime = Date.now(), this.questManager = new R(this.events), this.questManager.loadQuests(t), this.sessionRecorder = new z(
|
|
1442
1526
|
this.config,
|
|
1443
1527
|
this.events,
|
|
1444
1528
|
this.fieldMasker.getCombinedSelector()
|
|
1445
|
-
), this.voiceRecorder = new
|
|
1529
|
+
), this.voiceRecorder = new O(this.events), this.issueReporter = new H(this.shadowRoot, this.events), this.issueReporter.start(), this.sessionRecorder.start(), this.fieldMasker.start(), this.config.recording.voice && await this.voiceRecorder.start(), this.config.security.watermark && (this.watermark = new Q(this.shadowRoot, this.config), this.watermark.show()), this.questOverlay = new N(this.shadowRoot, {
|
|
1446
1530
|
onOkWithFeedback: (i) => this.handleQuestOk(i),
|
|
1447
1531
|
onConcern: (i) => this.handleConcern(i),
|
|
1448
1532
|
onNg: () => this.handleQuestNg(),
|
|
@@ -1475,7 +1559,7 @@ class W {
|
|
|
1475
1559
|
* End the current session, persist data, and trigger upload.
|
|
1476
1560
|
*/
|
|
1477
1561
|
async endSession() {
|
|
1478
|
-
var i, n, o, l, c, h, d,
|
|
1562
|
+
var i, n, o, l, c, h, d, m, f, p, g;
|
|
1479
1563
|
if (this.state !== "recording" || !this.sessionId) return null;
|
|
1480
1564
|
this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (i = this.sessionRecorder) == null || i.stop(), await ((n = this.voiceRecorder) == null ? void 0 : n.stopAsync()), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (c = this.watermark) == null || c.hide();
|
|
1481
1565
|
const t = this.questManager.getResults();
|
|
@@ -1489,13 +1573,13 @@ class W {
|
|
|
1489
1573
|
delete b.voiceMemoBlob;
|
|
1490
1574
|
}
|
|
1491
1575
|
await Promise.allSettled(
|
|
1492
|
-
b.feedbacks.map(async (
|
|
1493
|
-
if (
|
|
1576
|
+
b.feedbacks.map(async (k) => {
|
|
1577
|
+
if (k.voiceMemoBlob) {
|
|
1494
1578
|
try {
|
|
1495
|
-
|
|
1579
|
+
k.voiceMemoBase64 = await this.blobToBase64(k.voiceMemoBlob);
|
|
1496
1580
|
} catch {
|
|
1497
1581
|
}
|
|
1498
|
-
delete
|
|
1582
|
+
delete k.voiceMemoBlob;
|
|
1499
1583
|
}
|
|
1500
1584
|
})
|
|
1501
1585
|
);
|
|
@@ -1506,7 +1590,7 @@ class W {
|
|
|
1506
1590
|
projectId: this.config.projectId,
|
|
1507
1591
|
userId: this.config.userId,
|
|
1508
1592
|
role: this.config.role,
|
|
1509
|
-
deviceInfo:
|
|
1593
|
+
deviceInfo: y(),
|
|
1510
1594
|
startedAt: new Date(this.sessionStartTime).toISOString(),
|
|
1511
1595
|
endedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1512
1596
|
duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
|
|
@@ -1514,10 +1598,10 @@ class W {
|
|
|
1514
1598
|
recordings: ((h = this.sessionRecorder) == null ? void 0 : h.getSnapshots()) ?? []
|
|
1515
1599
|
};
|
|
1516
1600
|
await ((d = this.storage) == null ? void 0 : d.saveSession(e));
|
|
1517
|
-
const s = ((
|
|
1601
|
+
const s = ((m = this.issueReporter) == null ? void 0 : m.getAnnotations()) ?? [];
|
|
1518
1602
|
for (const b of s)
|
|
1519
|
-
await ((
|
|
1520
|
-
return await ((p = this.storage) == null ? void 0 : p.enqueueUpload({ session: e, annotations: s })), (
|
|
1603
|
+
await ((f = this.storage) == null ? void 0 : f.saveAnnotation(this.sessionId, b));
|
|
1604
|
+
return await ((p = this.storage) == null ? void 0 : p.enqueueUpload({ session: e, annotations: s })), (g = this.questOverlay) == null || g.destroy(), this.questOverlay = null, this.state = "finished", this.events.emit({ type: "session:ended", sessionId: this.sessionId }), this.flushUploadQueue(!1), e;
|
|
1521
1605
|
}
|
|
1522
1606
|
/**
|
|
1523
1607
|
* Subscribe to SDK events.
|
|
@@ -1535,9 +1619,9 @@ class W {
|
|
|
1535
1619
|
* Completely destroy the SDK instance and clean up all resources.
|
|
1536
1620
|
*/
|
|
1537
1621
|
destroy() {
|
|
1538
|
-
var t, e, s, i, n, o, l, c, h, d,
|
|
1539
|
-
this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(),
|
|
1540
|
-
}), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (c = this.watermark) == null || c.hide(), (h = this.questOverlay) == null || h.destroy(), (d = this.debugMenu) == null || d.hide(), (
|
|
1622
|
+
var t, e, s, i, n, o, l, c, h, d, m, f;
|
|
1623
|
+
this.maxDurationTimer && (clearTimeout(this.maxDurationTimer), this.maxDurationTimer = null), this.backupTimer && (clearInterval(this.backupTimer), this.backupTimer = null), (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(), C.clearPersisted(), (i = this.sessionRecorder) == null || i.stop(), (n = this.voiceRecorder) == null || n.stopAsync().catch(() => {
|
|
1624
|
+
}), (o = this.issueReporter) == null || o.stop(), (l = this.fieldMasker) == null || l.stop(), (c = this.watermark) == null || c.hide(), (h = this.questOverlay) == null || h.destroy(), (d = this.debugMenu) == null || d.hide(), (m = this.hostElement) == null || m.remove(), (f = this.storage) == null || f.close(), this.events.removeAll(), this.config = null, this.questManager = null, this.questOverlay = null, this.sessionRecorder = null, this.voiceRecorder = null, this.issueReporter = null, this.fieldMasker = null, this.debugMenu = null, this.tapTrigger = null, this.deepLinkTrigger = null, this.keyboardTrigger = null, this.storage = null, this.hostElement = null, this.shadowRoot = null, this.sessionId = null, this.state = "idle";
|
|
1541
1625
|
}
|
|
1542
1626
|
// ----------------------------------------------------------------
|
|
1543
1627
|
// Private methods
|
|
@@ -1546,15 +1630,15 @@ class W {
|
|
|
1546
1630
|
var e;
|
|
1547
1631
|
(e = document.getElementById("firstlook-sdk-root")) == null || e.remove(), this.hostElement = document.createElement("div"), this.hostElement.id = "firstlook-sdk-root", this.hostElement.style.cssText = "position:fixed;inset:0;z-index:2147483647;pointer-events:none;", document.body.appendChild(this.hostElement), this.shadowRoot = this.hostElement.attachShadow({ mode: "closed" });
|
|
1548
1632
|
const t = document.createElement("style");
|
|
1549
|
-
t.textContent =
|
|
1633
|
+
t.textContent = X, this.shadowRoot.appendChild(t);
|
|
1550
1634
|
}
|
|
1551
1635
|
setupTriggers() {
|
|
1552
1636
|
const t = this.config.triggers;
|
|
1553
|
-
this.tapTrigger = new
|
|
1637
|
+
this.tapTrigger = new _(t.tapCount, () => this.onActivate()), this.tapTrigger.start(), t.deepLink && (this.deepLinkTrigger = new C(() => this.onActivate()), this.deepLinkTrigger.start()), t.keyboard && (this.keyboardTrigger = new W(() => this.onActivate()), this.keyboardTrigger.start()), t.customCheck && t.customCheck() && this.onActivate();
|
|
1554
1638
|
}
|
|
1555
1639
|
onActivate() {
|
|
1556
1640
|
var t, e, s;
|
|
1557
|
-
this.state === "initialized" && (this.state = "active", (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(), this.events.emit({ type: "sdk:activated" }), this.debugMenu = new
|
|
1641
|
+
this.state === "initialized" && (this.state = "active", (t = this.tapTrigger) == null || t.stop(), (e = this.deepLinkTrigger) == null || e.stop(), (s = this.keyboardTrigger) == null || s.stop(), this.events.emit({ type: "sdk:activated" }), this.debugMenu = new V(this.shadowRoot, {
|
|
1558
1642
|
onStartSession: () => {
|
|
1559
1643
|
this.events.emit({ type: "sdk:activated" });
|
|
1560
1644
|
},
|
|
@@ -1568,18 +1652,22 @@ class W {
|
|
|
1568
1652
|
}), this.debugMenu.show());
|
|
1569
1653
|
}
|
|
1570
1654
|
handleQuestOk(t) {
|
|
1655
|
+
var i;
|
|
1571
1656
|
if (!this.questManager || !this.sessionRecorder) return;
|
|
1572
|
-
const e = this.sessionRecorder.getActionLogs();
|
|
1657
|
+
const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
|
|
1573
1658
|
this.questManager.completeCurrentQuest(e, {
|
|
1574
|
-
comment: t || void 0
|
|
1659
|
+
comment: t || void 0,
|
|
1660
|
+
checklist: s
|
|
1575
1661
|
}), this.renderCurrentQuest();
|
|
1576
1662
|
}
|
|
1577
1663
|
handleConcern(t) {
|
|
1664
|
+
var i;
|
|
1578
1665
|
if (!this.questManager || !this.sessionRecorder) return;
|
|
1579
|
-
const e = this.sessionRecorder.getActionLogs();
|
|
1666
|
+
const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
|
|
1580
1667
|
this.questManager.completeCurrentQuest(e, {
|
|
1581
1668
|
comment: t,
|
|
1582
|
-
concern: !0
|
|
1669
|
+
concern: !0,
|
|
1670
|
+
checklist: s
|
|
1583
1671
|
}), this.renderCurrentQuest();
|
|
1584
1672
|
}
|
|
1585
1673
|
handleQuestNg() {
|
|
@@ -1588,9 +1676,10 @@ class W {
|
|
|
1588
1676
|
t && this.questOverlay.renderFeedbackModal(t.title, "ng");
|
|
1589
1677
|
}
|
|
1590
1678
|
handleNgFeedbackSubmit(t) {
|
|
1679
|
+
var i;
|
|
1591
1680
|
if (!this.questManager || !this.sessionRecorder) return;
|
|
1592
|
-
const e = this.sessionRecorder.getActionLogs();
|
|
1593
|
-
this.questManager.failCurrentQuest(e, t || void 0), this.renderCurrentQuest();
|
|
1681
|
+
const e = this.sessionRecorder.getActionLogs(), s = (i = this.questOverlay) == null ? void 0 : i.getChecklist();
|
|
1682
|
+
this.questManager.failCurrentQuest(e, t || void 0, void 0, s), this.renderCurrentQuest();
|
|
1594
1683
|
}
|
|
1595
1684
|
handleMemo(t) {
|
|
1596
1685
|
if (!this.questManager || !t) return;
|
|
@@ -1606,8 +1695,8 @@ class W {
|
|
|
1606
1695
|
if (!this.questManager || !this.questOverlay) return;
|
|
1607
1696
|
const t = this.questManager.getStatus();
|
|
1608
1697
|
if (t.isBlocked) {
|
|
1609
|
-
const
|
|
1610
|
-
this.questOverlay.renderBlocked(
|
|
1698
|
+
const n = this.questManager.getResults().find((l) => l.status === "FAILED"), o = n ? n.questId : "Unknown";
|
|
1699
|
+
this.questOverlay.renderBlocked(o);
|
|
1611
1700
|
return;
|
|
1612
1701
|
}
|
|
1613
1702
|
if (t.isFinished) {
|
|
@@ -1632,7 +1721,7 @@ class W {
|
|
|
1632
1721
|
}
|
|
1633
1722
|
const e = await this.storage.getPendingUploads();
|
|
1634
1723
|
for (const s of e) {
|
|
1635
|
-
if (s.attempts >=
|
|
1724
|
+
if (s.attempts >= Y) {
|
|
1636
1725
|
await this.storage.removeFromQueue(s.key);
|
|
1637
1726
|
continue;
|
|
1638
1727
|
}
|
|
@@ -1668,7 +1757,7 @@ class W {
|
|
|
1668
1757
|
projectId: this.config.projectId,
|
|
1669
1758
|
userId: this.config.userId,
|
|
1670
1759
|
role: this.config.role,
|
|
1671
|
-
deviceInfo:
|
|
1760
|
+
deviceInfo: y(),
|
|
1672
1761
|
startedAt: new Date(this.sessionStartTime).toISOString(),
|
|
1673
1762
|
duration: Math.floor((Date.now() - this.sessionStartTime) / 1e3),
|
|
1674
1763
|
quests: ((t = this.questManager) == null ? void 0 : t.getResults()) ?? [],
|
|
@@ -1686,6 +1775,6 @@ class W {
|
|
|
1686
1775
|
}
|
|
1687
1776
|
}
|
|
1688
1777
|
export {
|
|
1689
|
-
|
|
1778
|
+
G as FirstLookSDK
|
|
1690
1779
|
};
|
|
1691
1780
|
//# sourceMappingURL=firstlook.es.js.map
|