@sailfish-ai/recorder 1.10.13 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +309 -7
- package/dist/babel-plugin-sailfish-source.cjs.br +0 -0
- package/dist/babel-plugin-sailfish-source.cjs.gz +0 -0
- package/dist/babel-plugin-sailfish-source.js.br +0 -0
- package/dist/babel-plugin-sailfish-source.js.gz +0 -0
- package/dist/chunkSerializer.js.br +0 -0
- package/dist/chunkSerializer.js.gz +0 -0
- package/dist/chunks/{chunkSerializer-Dk1eF3S8.js → chunkSerializer-BiemuRlf.js} +1 -1
- package/dist/chunks/chunkSerializer-BiemuRlf.js.br +0 -0
- package/dist/chunks/chunkSerializer-BiemuRlf.js.gz +0 -0
- package/dist/chunks/{chunkSerializer-CodMnuS3.js → chunkSerializer-CJQCxiLD.js} +1 -1
- package/dist/chunks/chunkSerializer-CJQCxiLD.js.br +0 -0
- package/dist/chunks/chunkSerializer-CJQCxiLD.js.gz +0 -0
- package/dist/chunks/{index-DW416eVj.js → index-Cfj4Epfd.js} +126 -96
- package/dist/chunks/index-Cfj4Epfd.js.br +0 -0
- package/dist/chunks/index-Cfj4Epfd.js.gz +0 -0
- package/dist/chunks/{index-DvLh2k6O.js → index-CuXHImrI.js} +126 -94
- package/dist/chunks/index-CuXHImrI.js.br +0 -0
- package/dist/chunks/index-CuXHImrI.js.gz +0 -0
- package/dist/constants.js.br +0 -0
- package/dist/constants.js.gz +0 -0
- package/dist/deviceInfo.js.br +0 -0
- package/dist/deviceInfo.js.gz +0 -0
- package/dist/env.js.br +0 -0
- package/dist/env.js.gz +0 -0
- package/dist/errorInterceptor.js.br +0 -0
- package/dist/errorInterceptor.js.gz +0 -0
- package/dist/eventStore.js.br +0 -0
- package/dist/eventStore.js.gz +0 -0
- package/dist/exponentialBackoff.js.br +0 -0
- package/dist/exponentialBackoff.js.gz +0 -0
- package/dist/fiberHook.js.br +0 -0
- package/dist/fiberHook.js.gz +0 -0
- package/dist/frameworkDetection.js.br +0 -0
- package/dist/frameworkDetection.js.gz +0 -0
- package/dist/graphql.js.br +0 -0
- package/dist/graphql.js.gz +0 -0
- package/dist/headlessDetection.js.br +0 -0
- package/dist/headlessDetection.js.gz +0 -0
- package/dist/inAppReportIssueModal/index.js +15 -14
- package/dist/inAppReportIssueModal/index.js.br +0 -0
- package/dist/inAppReportIssueModal/index.js.gz +0 -0
- package/dist/inAppReportIssueModal/integrations.js +56 -4
- package/dist/inAppReportIssueModal/integrations.js.br +0 -0
- package/dist/inAppReportIssueModal/integrations.js.gz +0 -0
- package/dist/inAppReportIssueModal/state.js.br +0 -0
- package/dist/inAppReportIssueModal/state.js.gz +0 -0
- package/dist/inAppReportIssueModal/ui.js.br +0 -0
- package/dist/inAppReportIssueModal/ui.js.gz +0 -0
- package/dist/index.js +98 -73
- package/dist/index.js.br +0 -0
- package/dist/index.js.gz +0 -0
- package/dist/notifyEventStore.js.br +0 -0
- package/dist/notifyEventStore.js.gz +0 -0
- package/dist/recorder.cjs +2 -2
- package/dist/recorder.cjs.br +0 -0
- package/dist/recorder.cjs.gz +0 -0
- package/dist/recorder.js +26 -25
- package/dist/recorder.js.br +0 -0
- package/dist/recorder.js.gz +0 -0
- package/dist/recorder.umd.cjs +8909 -0
- package/dist/recorder.umd.cjs.br +0 -0
- package/dist/recorder.umd.cjs.gz +0 -0
- package/dist/recording.js +2 -2
- package/dist/recording.js.br +0 -0
- package/dist/recording.js.gz +0 -0
- package/dist/segmentHelpers.js.br +0 -0
- package/dist/segmentHelpers.js.gz +0 -0
- package/dist/sendSailfishMessages.js +4 -0
- package/dist/sendSailfishMessages.js.br +0 -0
- package/dist/sendSailfishMessages.js.gz +0 -0
- package/dist/session.js.br +0 -0
- package/dist/session.js.gz +0 -0
- package/dist/snippet-auto-init.js +173 -0
- package/dist/snippet-auto-init.js.br +0 -0
- package/dist/snippet-auto-init.js.gz +0 -0
- package/dist/sourceLocation.js.br +0 -0
- package/dist/sourceLocation.js.gz +0 -0
- package/dist/types/inAppReportIssueModal/integrations.d.ts +7 -0
- package/dist/types/index.d.ts +5 -1
- package/dist/types/sendSailfishMessages.d.ts +4 -0
- package/dist/types/snippet-auto-init.d.ts +31 -0
- package/dist/types/types.d.ts +1 -0
- package/dist/types/umd-entry.d.ts +9 -0
- package/dist/umd-entry.js +11 -0
- package/dist/utils.js.br +0 -0
- package/dist/utils.js.gz +0 -0
- package/dist/uuid.js.br +0 -0
- package/dist/uuid.js.gz +0 -0
- package/dist/websocket.js.br +0 -0
- package/dist/websocket.js.gz +0 -0
- package/package.json +9 -5
- package/dist/chunks/chunkSerializer-CodMnuS3.js.br +0 -0
- package/dist/chunks/chunkSerializer-CodMnuS3.js.gz +0 -0
- package/dist/chunks/chunkSerializer-Dk1eF3S8.js.br +0 -0
- package/dist/chunks/chunkSerializer-Dk1eF3S8.js.gz +0 -0
- package/dist/chunks/index-DW416eVj.js.br +0 -0
- package/dist/chunks/index-DW416eVj.js.gz +0 -0
- package/dist/chunks/index-DvLh2k6O.js.br +0 -0
- package/dist/chunks/index-DvLh2k6O.js.gz +0 -0
|
@@ -370,7 +370,7 @@ function initializeWebSocket(t2, n2, i2, o2, s2 = false) {
|
|
|
370
370
|
const t3 = new URL(e2);
|
|
371
371
|
return `${t3.hostname}${t3.port ? `:${t3.port}` : ""}`;
|
|
372
372
|
})(t2);
|
|
373
|
-
let r2 = `${"https:" === new URL(t2).protocol ? "wss" : "ws"}://${a2}/ws/notify/?apiKey=${n2}&sessionId=${i2}&sender=JS%2FTS&version=1.
|
|
373
|
+
let r2 = `${"https:" === new URL(t2).protocol ? "wss" : "ws"}://${a2}/ws/notify/?apiKey=${n2}&sessionId=${i2}&sender=JS%2FTS&version=1.11.1`;
|
|
374
374
|
if (o2 && (r2 += `&envValue=${encodeURIComponent(o2)}`), k = s2 ? (function tryCreateWsWorker() {
|
|
375
375
|
if ("undefined" == typeof Worker) return null;
|
|
376
376
|
try {
|
|
@@ -426,37 +426,40 @@ function getFuncSpanHeader() {
|
|
|
426
426
|
return { name: "X-Sf3-FunctionSpanCaptureOverride", value: "1-1-10-10-1-1.0-1-0-0" };
|
|
427
427
|
}
|
|
428
428
|
const O = Object.freeze(Object.defineProperty({ __proto__: null, clearStaleFuncSpanState, disableFunctionSpanTracking, enableFunctionSpanTracking, ensureHrefCache, flushBufferedEvents, getCachedHref, getCachedHrefNoQuery, getFuncSpanHeader, initializeFunctionSpanTrackingFromApi, initializeWebSocket, isFunctionSpanTrackingEnabled, onNavigationChange, restoreFuncSpanState, sendEvent, sendMessage }, Symbol.toStringTag, { value: "Module" }));
|
|
429
|
-
let
|
|
429
|
+
let U = null, z = null;
|
|
430
|
+
function getIdentifiedUser() {
|
|
431
|
+
return U;
|
|
432
|
+
}
|
|
430
433
|
function identify(e2, t2 = {}, n2 = false) {
|
|
431
434
|
const i2 = { type: "identify", userId: e2, traits: t2 };
|
|
432
|
-
|
|
435
|
+
U && U.userId === e2 && JSON.stringify(U.traits) === JSON.stringify(t2) || (U = { userId: e2, traits: t2, overwrite: n2 }, sendMessage(i2));
|
|
433
436
|
}
|
|
434
437
|
function addOrUpdateMetadata(e2) {
|
|
435
438
|
const t2 = { type: "addOrUpdateMetadata", metadata: e2 };
|
|
436
|
-
|
|
439
|
+
z && JSON.stringify(z) === JSON.stringify(e2) || (z = e2, sendMessage(t2));
|
|
437
440
|
}
|
|
438
441
|
function trackingEvent(e2) {
|
|
439
442
|
sendMessage({ type: "trackingEvent", trackingData: e2, timestamp: w() });
|
|
440
443
|
}
|
|
441
|
-
let
|
|
442
|
-
const
|
|
444
|
+
let N = null;
|
|
445
|
+
const H = ["https://api.ipify.org?format=json", "https://api.ip.sb/jsonip", "https://api4.my-ip.io/ip.json"];
|
|
443
446
|
function fetchAndSendIp(e2) {
|
|
444
|
-
|
|
445
|
-
for (const e3 of
|
|
447
|
+
N !== e2 && (N = e2, (async () => {
|
|
448
|
+
for (const e3 of H) try {
|
|
446
449
|
const t2 = new AbortController(), n2 = setTimeout(() => t2.abort(), 5e3), i2 = await fetch(e3, { signal: t2.signal });
|
|
447
450
|
if (clearTimeout(n2), !i2.ok) continue;
|
|
448
451
|
const o2 = await i2.json(), s2 = o2.ip || o2.origin || null;
|
|
449
452
|
if (s2 && "string" == typeof s2 && s2.length <= 45) return void sendMessage({ type: "visitorIp", ip: s2, timestamp: w() });
|
|
450
453
|
} catch {
|
|
451
454
|
}
|
|
452
|
-
|
|
455
|
+
N = null;
|
|
453
456
|
})().catch(() => {
|
|
454
|
-
|
|
457
|
+
N = null;
|
|
455
458
|
}));
|
|
456
459
|
}
|
|
457
|
-
let
|
|
460
|
+
let q = null;
|
|
458
461
|
async function getSourceMapModule() {
|
|
459
|
-
return
|
|
462
|
+
return q || (q = await import("source-map-js")), q;
|
|
460
463
|
}
|
|
461
464
|
const W = /* @__PURE__ */ new Map(), K = /(?:\(|\s|^)(https?:\/\/[^)\s]+|\/[^)\s]+|[^)\s]+)?\/?([^/]+\.js)(?:\?[^:)]*)?:(\d+):(\d+)/;
|
|
462
465
|
async function getConsumerFor(e2, t2) {
|
|
@@ -701,12 +704,12 @@ async function initializeRecording(e2, n2, i2, o2, s2, a2 = true, r2 = false, l2
|
|
|
701
704
|
}
|
|
702
705
|
const { record: n4 } = await import("@sailfish-rrweb/rrweb-record-only");
|
|
703
706
|
if (J = n4, await yieldToMain(), l2) {
|
|
704
|
-
const { chunkedSnapshot: i3 } = await import("./chunkSerializer-
|
|
707
|
+
const { chunkedSnapshot: i3 } = await import("./chunkSerializer-BiemuRlf.js"), o3 = n4.mirror;
|
|
705
708
|
let s3 = true;
|
|
706
709
|
const a3 = [];
|
|
707
710
|
n4({ emit(e3) {
|
|
708
711
|
s3 ? a3.push(e3) : emitWithContext(e3);
|
|
709
|
-
}, maskInputOptions: { text: true }, maskInputFn, maskTextClass: X,
|
|
712
|
+
}, maskInputOptions: { text: true }, maskInputFn, ...e2, maskTextClass: e2.maskTextClass ?? X, recordDOM: false });
|
|
710
713
|
const r3 = Date.now(), l3 = await i3(document, o3, { chunkSize: 500, maxChunkMs: 16, blockClass: e2.blockClass, blockSelector: e2.blockSelector, maskTextClass: e2.maskTextClass ?? X, maskTextSelector: e2.maskTextSelector });
|
|
711
714
|
if (l3) {
|
|
712
715
|
emitWithContext({ type: t.Meta, data: { href: window.location.href, width: document.documentElement.clientWidth || document.body.clientWidth, height: document.documentElement.clientHeight || document.body.clientHeight }, timestamp: r3 }), emitWithContext({ type: t.FullSnapshot, data: { node: l3, initialOffset: { left: void 0 !== window.pageXOffset ? window.pageXOffset : document.documentElement.scrollLeft, top: void 0 !== window.pageYOffset ? window.pageYOffset : document.documentElement.scrollTop } }, timestamp: r3 });
|
|
@@ -715,7 +718,7 @@ async function initializeRecording(e2, n2, i2, o2, s2, a2 = true, r2 = false, l2
|
|
|
715
718
|
} else console.warn("[Sailfish] chunkSnapshot serialization failed; session continues without initial DOM snapshot"), s3 = false;
|
|
716
719
|
} else n4({ emit(e3) {
|
|
717
720
|
emitWithContext(e3);
|
|
718
|
-
}, maskInputOptions: { text: true }, maskInputFn, maskTextClass: X
|
|
721
|
+
}, maskInputOptions: { text: true }, maskInputFn, ...e2, maskTextClass: e2.maskTextClass ?? X });
|
|
719
722
|
};
|
|
720
723
|
if (a2) {
|
|
721
724
|
let e3 = false;
|
|
@@ -930,12 +933,26 @@ function updateIssueTypeOptions(e2, t2) {
|
|
|
930
933
|
}
|
|
931
934
|
function getFieldsForProject(e2, t2) {
|
|
932
935
|
if (!(re == null ? void 0 : re.fieldConfigurations) || !e2) return [];
|
|
933
|
-
const n2 = Array.isArray(re.fieldConfigurations) ? re.fieldConfigurations.find((n3) => n3.project_key
|
|
936
|
+
const n2 = Array.isArray(re.fieldConfigurations) ? re.fieldConfigurations.find((n3) => !(n3.project_key !== e2 && String(n3.project_id) !== String(e2) || t2 && String(n3.issue_type_id) !== String(t2))) : re.fieldConfigurations[e2];
|
|
934
937
|
return n2 && n2.fields ? n2.fields : [];
|
|
935
938
|
}
|
|
936
939
|
function getUsers() {
|
|
937
940
|
return (re == null ? void 0 : re.users) ? re.users : [];
|
|
938
941
|
}
|
|
942
|
+
function getDefaultReporterAccountId() {
|
|
943
|
+
const e2 = getUsers(), t2 = getIdentifiedUser();
|
|
944
|
+
if (!e2.length || !t2) return null;
|
|
945
|
+
const n2 = t2.traits || {}, i2 = (n2.email || t2.userId || "").toLowerCase().trim(), o2 = (n2.name || n2.displayName || n2.fullName || n2.full_name || (n2.firstName || n2.first_name ? `${n2.firstName || n2.first_name} ${n2.lastName || n2.last_name || ""}`.trim() : "") || "").toLowerCase().trim(), findUnique = (t3) => {
|
|
946
|
+
const n3 = e2.filter(t3);
|
|
947
|
+
return 1 === n3.length ? n3[0] : null;
|
|
948
|
+
};
|
|
949
|
+
let s2 = i2 ? findUnique((e3) => (e3.email || e3.emailAddress || "").toLowerCase().trim() === i2) : null;
|
|
950
|
+
if (!s2 && o2 && (s2 = findUnique((e3) => (e3.name || e3.displayName || "").toLowerCase().trim() === o2)), !s2 && i2) {
|
|
951
|
+
const e3 = i2.split("@")[0];
|
|
952
|
+
e3.length >= 3 && (s2 = findUnique((t3) => (t3.name || t3.displayName || "").toLowerCase().trim().includes(e3)));
|
|
953
|
+
}
|
|
954
|
+
return s2 && (s2.id || s2.accountId) || null;
|
|
955
|
+
}
|
|
939
956
|
function getProjectsForTeam(e2) {
|
|
940
957
|
if (!re) return [];
|
|
941
958
|
const t2 = re.teams && Array.isArray(re.teams) && re.teams.length > 0;
|
|
@@ -968,7 +985,7 @@ const ce = Object.freeze(Object.defineProperty({ __proto__: null, fetchIntegrati
|
|
|
968
985
|
} catch (e3) {
|
|
969
986
|
console.error("Error fetching integration data:", e3), re = null;
|
|
970
987
|
}
|
|
971
|
-
}, getFieldsForProject, getIntegrationData, getProjectsForTeam, getSprintFieldId, getUsers, hasValidIntegration, populatePriorityOptions, populateSelectOptions, populateSprintOptions, refreshIntegrationData, updateFormWithIntegrationData, updateIssueTypeOptions }, Symbol.toStringTag, { value: "Module" })), de = "sf-create-issue-preference", ue = "sf-create-eng-ticket-preference";
|
|
988
|
+
}, getDefaultReporterAccountId, getFieldsForProject, getIntegrationData, getProjectsForTeam, getSprintFieldId, getUsers, hasValidIntegration, populatePriorityOptions, populateSelectOptions, populateSprintOptions, refreshIntegrationData, updateFormWithIntegrationData, updateIssueTypeOptions }, Symbol.toStringTag, { value: "Module" })), de = "sf-create-issue-preference", ue = "sf-create-eng-ticket-preference";
|
|
972
989
|
function getInitialState() {
|
|
973
990
|
const e2 = (function loadUserPreferences() {
|
|
974
991
|
return { createIssue: f && "true" === localStorage.getItem(de), createEngTicket: f && "true" === localStorage.getItem(ue) };
|
|
@@ -1558,8 +1575,11 @@ function injectModalHTML(e2 = "lookback") {
|
|
|
1558
1575
|
if (!hasValidIntegration()) return l2.checked = false, pe.createEngTicket = false, localStorage.setItem(ue, "false"), c2 && (c2.style.display = "none"), void alert("No engineering ticket integration found. Please install and configure an integration (Jira, Linear, or Zendesk) first.");
|
|
1559
1576
|
const e5 = getIntegrationData();
|
|
1560
1577
|
if (e5) {
|
|
1561
|
-
if (!pe.engTicketTeam && e5.defaultTeam && (pe.engTicketTeam = e5.defaultTeam), !pe.engTicketProject && e5.defaultProject && (pe.engTicketProject = e5.defaultProject), !pe.engTicketPriority && e5.defaultPriority && (pe.engTicketPriority = e5.defaultPriority), updateFormWithIntegrationData(pe), "jira" === ((_a = e5.provider) == null ? void 0 : _a.toLowerCase()) &&
|
|
1562
|
-
getFieldsForProject(pe.engTicketProject, pe.engTicketIssueType).find((e6) => "reporter" === e6.fieldId)
|
|
1578
|
+
if (!pe.engTicketTeam && e5.defaultTeam && (pe.engTicketTeam = e5.defaultTeam), !pe.engTicketProject && e5.defaultProject && (pe.engTicketProject = e5.defaultProject), !pe.engTicketPriority && e5.defaultPriority && (pe.engTicketPriority = e5.defaultPriority), updateFormWithIntegrationData(pe), "jira" === ((_a = e5.provider) == null ? void 0 : _a.toLowerCase()) && pe.engTicketProject && !pe.engTicketCustomFields.reporter) {
|
|
1579
|
+
if (getFieldsForProject(pe.engTicketProject, pe.engTicketIssueType).find((e6) => "reporter" === e6.fieldId)) {
|
|
1580
|
+
const t5 = getDefaultReporterAccountId();
|
|
1581
|
+
pe.engTicketCustomFields.reporter = t5 || e5.jiraReporterAccountId || "";
|
|
1582
|
+
}
|
|
1563
1583
|
}
|
|
1564
1584
|
const t4 = document.getElementById("sf-eng-ticket-project"), n3 = document.getElementById("sf-eng-ticket-type");
|
|
1565
1585
|
t4 && t4.value && renderDynamicFields(t4.value, n3 == null ? void 0 : n3.value);
|
|
@@ -1693,8 +1713,11 @@ function initializeEngTicketForm() {
|
|
|
1693
1713
|
var _a;
|
|
1694
1714
|
const e2 = be.integrationData;
|
|
1695
1715
|
if (e2) {
|
|
1696
|
-
if (!pe.engTicketTeam && e2.defaultTeam && (pe.engTicketTeam = e2.defaultTeam), !pe.engTicketProject && e2.defaultProject && (pe.engTicketProject = e2.defaultProject), !pe.engTicketPriority && e2.defaultPriority && (pe.engTicketPriority = e2.defaultPriority), updateFormWithIntegrationData(pe), "jira" === ((_a = e2.provider) == null ? void 0 : _a.toLowerCase()) &&
|
|
1697
|
-
getFieldsForProject(pe.engTicketProject, pe.engTicketIssueType).find((e3) => "reporter" === e3.fieldId)
|
|
1716
|
+
if (!pe.engTicketTeam && e2.defaultTeam && (pe.engTicketTeam = e2.defaultTeam), !pe.engTicketProject && e2.defaultProject && (pe.engTicketProject = e2.defaultProject), !pe.engTicketPriority && e2.defaultPriority && (pe.engTicketPriority = e2.defaultPriority), updateFormWithIntegrationData(pe), "jira" === ((_a = e2.provider) == null ? void 0 : _a.toLowerCase()) && pe.engTicketProject && !pe.engTicketCustomFields.reporter) {
|
|
1717
|
+
if (getFieldsForProject(pe.engTicketProject, pe.engTicketIssueType).find((e3) => "reporter" === e3.fieldId)) {
|
|
1718
|
+
const t2 = getDefaultReporterAccountId();
|
|
1719
|
+
pe.engTicketCustomFields.reporter = t2 || e2.jiraReporterAccountId || "";
|
|
1720
|
+
}
|
|
1698
1721
|
}
|
|
1699
1722
|
pe.engTicketProject && renderDynamicFields(pe.engTicketProject, pe.engTicketIssueType);
|
|
1700
1723
|
}
|
|
@@ -1732,8 +1755,11 @@ function bindEngTicketListeners() {
|
|
|
1732
1755
|
var _a;
|
|
1733
1756
|
pe.engTicketProject = t2.value, t2.style.color = t2.value ? "" : "#9ca3af", pe.engTicketCustomFields = {};
|
|
1734
1757
|
const e3 = getIntegrationData();
|
|
1735
|
-
if (e3 && o2 && (updateIssueTypeOptions(o2, t2.value), pe.engTicketIssueType = o2.value), e3 && "jira" === ((_a = e3.provider) == null ? void 0 : _a.toLowerCase()) &&
|
|
1736
|
-
getFieldsForProject(t2.value, pe.engTicketIssueType).find((e4) => "reporter" === e4.fieldId)
|
|
1758
|
+
if (e3 && o2 && (updateIssueTypeOptions(o2, t2.value), pe.engTicketIssueType = o2.value), e3 && "jira" === ((_a = e3.provider) == null ? void 0 : _a.toLowerCase()) && t2.value) {
|
|
1759
|
+
if (getFieldsForProject(t2.value, pe.engTicketIssueType).find((e4) => "reporter" === e4.fieldId)) {
|
|
1760
|
+
const t3 = getDefaultReporterAccountId();
|
|
1761
|
+
pe.engTicketCustomFields.reporter = t3 || e3.jiraReporterAccountId || "";
|
|
1762
|
+
}
|
|
1737
1763
|
}
|
|
1738
1764
|
renderDynamicFields(t2.value, pe.engTicketIssueType);
|
|
1739
1765
|
}), s2 && s2.addEventListener("change", () => {
|
|
@@ -1985,39 +2011,40 @@ function _ensureModuleSideEffects() {
|
|
|
1985
2011
|
clearPageVisitDataFromSessionStorage();
|
|
1986
2012
|
}));
|
|
1987
2013
|
}
|
|
1988
|
-
function
|
|
1989
|
-
|
|
1990
|
-
if ("string" == typeof e2 ? n2 = e2 : "undefined" != typeof URL && e2 instanceof URL ? n2 = e2.href : "undefined" != typeof Request && e2 instanceof Request ? n2 = e2.url : null != e2 && "function" == typeof e2.toString && (n2 = e2.toString()), !n2) return false;
|
|
1991
|
-
try {
|
|
1992
|
-
const e3 = "undefined" != typeof window ? window.location.href : "http://localhost/";
|
|
1993
|
-
i2 = new URL(n2, e3);
|
|
1994
|
-
} catch {
|
|
1995
|
-
return false;
|
|
1996
|
-
}
|
|
1997
|
-
const { hostname: o2, pathname: s2, port: a2, protocol: r2 } = i2;
|
|
1998
|
-
if (!/^https?:$/.test(r2)) return false;
|
|
1999
|
-
const l2 = o2.startsWith("www.") ? o2.slice(4).toLowerCase() : o2.toLowerCase();
|
|
2014
|
+
function matchParsedUrlAgainstPatterns(e2, t2) {
|
|
2015
|
+
const { hostname: n2, pathname: i2, port: o2 } = e2, s2 = n2.startsWith("www.") ? n2.slice(4).toLowerCase() : n2.toLowerCase();
|
|
2000
2016
|
return t2.some((e3) => {
|
|
2001
2017
|
const t3 = String(e3 || "").replace(/^[a-zA-Z]+:\/\//, "");
|
|
2002
|
-
let [n3,
|
|
2003
|
-
n3.includes(":") && ([n3,
|
|
2004
|
-
const
|
|
2005
|
-
if (
|
|
2018
|
+
let [n3, a2] = t3.split("/", 2), r2 = "";
|
|
2019
|
+
n3.includes(":") && ([n3, r2] = n3.split(":"));
|
|
2020
|
+
const l2 = getCachedRegex(`^${n3.replace(/\./g, "\\.").replace(/\*/g, ".*")}$`, "i"), c2 = s2.startsWith("www.") ? s2.slice(4) : s2;
|
|
2021
|
+
if (r2 && "*" !== r2 && o2 !== r2) return false;
|
|
2006
2022
|
if (n3.startsWith("*.")) {
|
|
2007
2023
|
const e4 = n3.slice(2).toLowerCase();
|
|
2008
|
-
if (!(
|
|
2009
|
-
if (
|
|
2010
|
-
return getCachedRegex(`^/${
|
|
2024
|
+
if (!(s2 === e4 || c2 === e4 || s2.endsWith("." + e4))) return false;
|
|
2025
|
+
if (a2) {
|
|
2026
|
+
return getCachedRegex(`^/${a2.replace(/\*/g, ".*").replace(/\/$/, "")}`, "i").test(i2);
|
|
2011
2027
|
}
|
|
2012
2028
|
return true;
|
|
2013
2029
|
}
|
|
2014
|
-
if (!
|
|
2015
|
-
if (
|
|
2016
|
-
return getCachedRegex(`^/${
|
|
2030
|
+
if (!l2.test(c2) && !l2.test(s2)) return false;
|
|
2031
|
+
if (a2) {
|
|
2032
|
+
return getCachedRegex(`^/${a2.replace(/\*/g, ".*").replace(/\/$/, "")}`, "i").test(i2);
|
|
2017
2033
|
}
|
|
2018
2034
|
return true;
|
|
2019
2035
|
});
|
|
2020
2036
|
}
|
|
2037
|
+
function matchUrlWithWildcard(e2, t2) {
|
|
2038
|
+
let n2, i2;
|
|
2039
|
+
if ("string" == typeof e2 ? n2 = e2 : "undefined" != typeof URL && e2 instanceof URL ? n2 = e2.href : "undefined" != typeof Request && e2 instanceof Request ? n2 = e2.url : null != e2 && "function" == typeof e2.toString && (n2 = e2.toString()), !n2) return false;
|
|
2040
|
+
try {
|
|
2041
|
+
const e3 = "undefined" != typeof window ? window.location.href : "http://localhost/";
|
|
2042
|
+
i2 = new URL(n2, e3);
|
|
2043
|
+
} catch {
|
|
2044
|
+
return false;
|
|
2045
|
+
}
|
|
2046
|
+
return matchParsedUrlAgainstPatterns(i2, t2);
|
|
2047
|
+
}
|
|
2021
2048
|
function createSkipHeadersPropagationChecker(e2 = [], t2 = []) {
|
|
2022
2049
|
const n2 = [...Te, ...e2], i2 = t2.length > 0;
|
|
2023
2050
|
return function shouldSkipHeadersPropagation(e3) {
|
|
@@ -2028,7 +2055,7 @@ function createSkipHeadersPropagationChecker(e2 = [], t2 = []) {
|
|
|
2028
2055
|
return true;
|
|
2029
2056
|
}
|
|
2030
2057
|
const s2 = o2.pathname.toLowerCase(), a2 = s2.lastIndexOf(".");
|
|
2031
|
-
return !(-1 === a2 || !Ie.has(s2.slice(a2))) || (!(!i2 ||
|
|
2058
|
+
return !(-1 === a2 || !Ie.has(s2.slice(a2))) || (!(!i2 || matchParsedUrlAgainstPatterns(o2, t2)) || !!matchParsedUrlAgainstPatterns(o2, n2));
|
|
2032
2059
|
};
|
|
2033
2060
|
}
|
|
2034
2061
|
function setupFetchInterceptor(e2 = [], t2 = { captureStreamingResponseBody: true, captureResponseBodyMaxMb: 10, captureStreamPrefixKb: 64, captureStreamTimeoutMs: 1e4 }, i2 = []) {
|
|
@@ -2201,7 +2228,7 @@ function setupFetchInterceptor(e2 = [], t2 = { captureStreamingResponseBody: tru
|
|
|
2201
2228
|
})(e3, i3, o3, d2, u2, s2, c2);
|
|
2202
2229
|
} });
|
|
2203
2230
|
}
|
|
2204
|
-
async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-service.sailfishqa.com", domainsToPropagateHeaderTo: i2 = [], domainsToNotPropagateHeaderTo: o2 = [], serviceVersion: s2, serviceIdentifier: a2, gitSha: r2, serviceAdditionalMetadata: l2, enableIpTracking: c2, captureStreamingResponseBody: d2 = true, captureResponseBodyMaxMb: u2 = 10, captureStreamPrefixKb: p2 = 64, captureStreamTimeoutMs: f2 = 1e4, enableFiberTracking: m2 = false, deferRecording: h2, deferRecordingStart: y2, chunkSnapshot: b2, useWsWorker: w2 = true }) {
|
|
2231
|
+
async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-service.sailfishqa.com", domainsToPropagateHeaderTo: i2 = ["*"], domainsToNotPropagateHeaderTo: o2 = [], serviceVersion: s2, serviceIdentifier: a2, gitSha: r2, serviceAdditionalMetadata: l2, enableIpTracking: c2, captureStreamingResponseBody: d2 = true, captureResponseBodyMaxMb: u2 = 10, captureStreamPrefixKb: p2 = 64, captureStreamTimeoutMs: f2 = 1e4, enableFiberTracking: m2 = false, deferRecording: h2, deferRecordingStart: y2, chunkSnapshot: b2, useWsWorker: w2 = true, maskTextClass: v2, library: S2 }) {
|
|
2205
2232
|
var _a, _b;
|
|
2206
2233
|
if ((function isHeadlessOrLighthouse() {
|
|
2207
2234
|
try {
|
|
@@ -2214,10 +2241,10 @@ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-servic
|
|
|
2214
2241
|
return false;
|
|
2215
2242
|
}
|
|
2216
2243
|
})()) return;
|
|
2217
|
-
const
|
|
2218
|
-
if (
|
|
2219
|
-
const
|
|
2220
|
-
sessionStorage.getItem("pageVisitUUID") || (sessionStorage.setItem("pageVisitUUID", uuidv4()), invalidateUrlCache()),
|
|
2244
|
+
const k2 = h2 ?? y2 ?? true, x2 = getOrSetSessionId(), I2 = window.__sailfish_recorder || (window.__sailfish_recorder = {});
|
|
2245
|
+
if (I2.sessionId = x2, I2.apiKey = e2, I2.backendApi = t2, I2.serviceAdditionalMetadata = l2, I2.initialized && I2.sessionId === x2 && I2.ws && 1 === I2.ws.readyState) return void trackDomainChangesOnce();
|
|
2246
|
+
const T2 = { captureStreamingResponseBody: d2, captureResponseBodyMaxMb: u2, captureStreamPrefixKb: p2, captureStreamTimeoutMs: f2 };
|
|
2247
|
+
sessionStorage.getItem("pageVisitUUID") || (sessionStorage.setItem("pageVisitUUID", uuidv4()), invalidateUrlCache()), I2.xhrPatched || (!(function setupXMLHttpRequestInterceptor(e3 = [], t3 = { captureStreamingResponseBody: true, captureResponseBodyMaxMb: 10, captureStreamPrefixKb: 64, captureStreamTimeoutMs: 1e4 }, i3 = []) {
|
|
2221
2248
|
const o3 = XMLHttpRequest.prototype.open, s3 = XMLHttpRequest.prototype.send, a3 = XMLHttpRequest.prototype.setRequestHeader, r3 = getOrSetSessionId(), l3 = createSkipHeadersPropagationChecker(e3, i3);
|
|
2222
2249
|
XMLHttpRequest.prototype.setRequestHeader = function(e4, t4) {
|
|
2223
2250
|
return this._capturedRequestHeaders || (this._capturedRequestHeaders = {}), this._capturedRequestHeaders[e4] = t4, a3.call(this, e4, t4);
|
|
@@ -2282,22 +2309,22 @@ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-servic
|
|
|
2282
2309
|
emitFinished(false, e5, t4);
|
|
2283
2310
|
}, { once: true }), s3.apply(this, e4);
|
|
2284
2311
|
};
|
|
2285
|
-
})(o2,
|
|
2312
|
+
})(o2, T2, i2), I2.xhrPatched = true), I2.fetchPatched || (setupFetchInterceptor(o2, T2, i2), I2.fetchPatched = true), await yieldToMain(), I2.domEventsInit || (initializeDomContentEvents(x2), I2.domEventsInit = true), await yieldToMain(), I2.consoleInit || (initializeConsolePlugin(Ae, x2), I2.consoleInit = true), await yieldToMain(), I2.errorInit || (!(function initializeErrorInterceptor() {
|
|
2286
2313
|
window.addEventListener("error", (e3) => {
|
|
2287
2314
|
captureError(e3.error || e3.message);
|
|
2288
2315
|
}), window.addEventListener("unhandledrejection", (e3) => {
|
|
2289
2316
|
captureError(e3.reason, true);
|
|
2290
2317
|
});
|
|
2291
|
-
})(),
|
|
2318
|
+
})(), I2.errorInit = true), await yieldToMain(), _ensureModuleSideEffects(), (function storeCredentialsAndConnection({ apiKey: e3, backendApi: t3 }) {
|
|
2292
2319
|
g && (sessionStorage.setItem("sailfishApiKey", e3), sessionStorage.setItem("sailfishBackendApi", t3));
|
|
2293
|
-
})({ apiKey: e2, backendApi: t2 }), !isFunctionSpanTrackingEnabled() ||
|
|
2320
|
+
})({ apiKey: e2, backendApi: t2 }), !isFunctionSpanTrackingEnabled() || I2.ws && 1 === I2.ws.readyState || fetchFunctionSpanTrackingEnabled(e2, t2).then((e3) => {
|
|
2294
2321
|
var _a2;
|
|
2295
2322
|
((_a2 = e3.data) == null ? void 0 : _a2.isFunctionSpanTrackingEnabledFromApiKey) ?? false ? ke && console.log("[Sailfish] Function span tracking state validated with backend: ACTIVE") : (clearStaleFuncSpanState(), ke && console.log("[Sailfish] Cleared stale function span tracking state - backend validation shows tracking is not active"));
|
|
2296
2323
|
}).catch((e3) => {
|
|
2297
2324
|
ke && console.warn("[Sailfish] Failed to validate function span tracking status with backend:", e3);
|
|
2298
|
-
}),
|
|
2325
|
+
}), I2.sentDoNotPropagateOnce || (sendDomainsToNotPropagateHeaderTo(e2, [...o2, ...Te], t2).catch((e3) => console.error("Failed to send domains to not propagate header to:", e3)), I2.sentDoNotPropagateOnce = true), (async function gatherAndCacheDeviceInfo() {
|
|
2299
2326
|
sendMessage({ type: "deviceInfo", data: { deviceInfo: { language: navigator.language, userAgent: navigator.userAgent } } });
|
|
2300
|
-
})(), c2 && fetchAndSendIp(
|
|
2327
|
+
})(), c2 && fetchAndSendIp(x2);
|
|
2301
2328
|
try {
|
|
2302
2329
|
const n2 = r2 ?? (function readGitSha() {
|
|
2303
2330
|
var _a2;
|
|
@@ -2316,7 +2343,7 @@ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-servic
|
|
|
2316
2343
|
if ("string" == typeof e3 && e3) return e3;
|
|
2317
2344
|
} catch {
|
|
2318
2345
|
}
|
|
2319
|
-
})(), i3 = a2 ?? "", o3 = s2 ?? "", c3 = "JS/TS", d3 = (function getMapUuidFromWindow() {
|
|
2346
|
+
})(), i3 = a2 ?? "", o3 = s2 ?? "", c3 = S2 ?? "JS/TS", d3 = (function getMapUuidFromWindow() {
|
|
2320
2347
|
try {
|
|
2321
2348
|
const e3 = window;
|
|
2322
2349
|
if (e3 && "string" == typeof e3.sfMapUuid && e3.sfMapUuid) return e3.sfMapUuid;
|
|
@@ -2336,15 +2363,15 @@ async function startRecording({ apiKey: e2, backendApi: t2 = "https://api-servic
|
|
|
2336
2363
|
return { framework: i4[0] ?? null, additionalFrameworks: i4.slice(1), serviceRole: "frontend" };
|
|
2337
2364
|
})(), f3 = { ...u3, serviceRole: p3.serviceRole, ...null !== p3.framework && { framework: p3.framework }, ...p3.additionalFrameworks.length > 0 && { additionalFrameworks: p3.additionalFrameworks } };
|
|
2338
2365
|
await yieldToMain();
|
|
2339
|
-
const [g2, h3] = await Promise.all([fetchCaptureSettings(e2, t2), startRecordingSession(e2,
|
|
2340
|
-
if (
|
|
2366
|
+
const [g2, h3] = await Promise.all([fetchCaptureSettings(e2, t2), startRecordingSession(e2, x2, t2, i3, o3, d3, n2, c3, f3)]), y3 = { ...Me, ...(_a = g2.data) == null ? void 0 : _a.captureSettingsFromApiKey, enableFiberTracking: m2, ...void 0 !== v2 ? { maskTextClass: v2 } : {} };
|
|
2367
|
+
if (I2.ws && 1 === I2.ws.readyState) return;
|
|
2341
2368
|
if ((_b = h3.data) == null ? void 0 : _b.startRecordingSession) {
|
|
2342
2369
|
const n3 = (l2 == null ? void 0 : l2.env) || (l2 == null ? void 0 : l2.environment);
|
|
2343
2370
|
await yieldToMain();
|
|
2344
|
-
const i4 = await initializeRecording(y3, t2, e2,
|
|
2345
|
-
|
|
2371
|
+
const i4 = await initializeRecording(y3, t2, e2, x2, n3, k2, w2, b2 ?? false);
|
|
2372
|
+
I2.ws = i4, I2.initialized = true, trackDomainChangesOnce(), I2.sentMapUuidOnce || (!(function sendMapUuidIfAvailable(e3 = "", t3 = "") {
|
|
2346
2373
|
window.sfMapUuid && sendMessage({ type: "mapUuid", data: { mapUuid: window.sfMapUuid, serviceIdentifier: e3, serviceVersion: t3 } });
|
|
2347
|
-
})(a2, s2),
|
|
2374
|
+
})(a2, s2), I2.sentMapUuidOnce = true);
|
|
2348
2375
|
} else console.error("Failed to start recording session:", h3.errors || h3);
|
|
2349
2376
|
} catch (e3) {
|
|
2350
2377
|
console.error("Error starting recording:", e3);
|
|
@@ -2354,41 +2381,46 @@ const initRecorder = async (e2) => {
|
|
|
2354
2381
|
if ("undefined" == typeof window) return;
|
|
2355
2382
|
const t2 = window.__sailfish_recorder || (window.__sailfish_recorder = {}), n2 = getOrSetSessionId();
|
|
2356
2383
|
return clearPageVisitDataFromSessionStorage(), t2.initialized && t2.sessionId === n2 && t2.ws && 1 === t2.ws.readyState ? void 0 : (t2.initPromise || (t2.initPromise = (async () => {
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2384
|
+
try {
|
|
2385
|
+
if (t2.hasLoggedInitOnce || (console.log("Initializing Sailfish Recorder (first run) …"), t2.hasLoggedInitOnce = true), await startRecording(e2), !t2.issueReportingInit) {
|
|
2386
|
+
const n3 = e2.backendApi ?? "https://api-service.sailfishqa.com", [{ setupIssueReporting: i2 }, { fetchIntegrationData: o2, getIntegrationData: s2 }] = await Promise.all([Promise.resolve().then(() => Se), Promise.resolve().then(() => ce)]);
|
|
2387
|
+
let a2 = null;
|
|
2388
|
+
try {
|
|
2389
|
+
await o2(e2.apiKey, n3), a2 = s2();
|
|
2390
|
+
} catch (e3) {
|
|
2391
|
+
console.warn("[Sailfish] Failed to fetch integration data for issue reporting:", e3);
|
|
2392
|
+
}
|
|
2393
|
+
i2({ apiKey: e2.apiKey, backendApi: n3, getSessionId: () => getOrSetSessionId(), shortcuts: e2.reportIssueShortcuts, customBaseUrl: e2.customBaseUrl, integrationData: a2, showEngTicketFieldsInReportIssueModalDefault: e2.showEngTicketFieldsInReportIssueModalDefault }), t2.issueReportingInit = true;
|
|
2364
2394
|
}
|
|
2365
|
-
|
|
2395
|
+
} catch (e3) {
|
|
2396
|
+
console.warn("[Sailfish] Recorder initialization failed:", e3);
|
|
2366
2397
|
}
|
|
2367
2398
|
})().finally(() => {
|
|
2368
2399
|
delete t2.initPromise;
|
|
2369
2400
|
})), t2.initPromise);
|
|
2370
2401
|
};
|
|
2371
2402
|
export {
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2403
|
+
initializeDomContentEvents as A,
|
|
2404
|
+
initializeFunctionSpanTrackingFromApi as B,
|
|
2405
|
+
initializeRecording as C,
|
|
2375
2406
|
Me as D,
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2407
|
+
initializeWebSocket as E,
|
|
2408
|
+
invalidateUrlCache as F,
|
|
2409
|
+
isFunctionSpanTrackingEnabled as G,
|
|
2410
|
+
matchUrlWithWildcard as H,
|
|
2411
|
+
w as I,
|
|
2412
|
+
onNavigationChange as J,
|
|
2413
|
+
openReportIssueModal as K,
|
|
2414
|
+
restoreFuncSpanState as L,
|
|
2415
|
+
sendDomainsToNotPropagateHeaderTo as M,
|
|
2416
|
+
sendEvent as N,
|
|
2417
|
+
sendGraphQLRequest as O,
|
|
2418
|
+
sendMessage as P,
|
|
2419
|
+
startRecording as Q,
|
|
2420
|
+
startRecordingSession as R,
|
|
2390
2421
|
$e as S,
|
|
2391
|
-
|
|
2422
|
+
trackingEvent as T,
|
|
2423
|
+
withAppUrlMetadata as U,
|
|
2392
2424
|
Ae as a,
|
|
2393
2425
|
addOrUpdateMetadata as b,
|
|
2394
2426
|
buildBatches as c,
|
|
@@ -2408,11 +2440,11 @@ export {
|
|
|
2408
2440
|
getCachedHref as q,
|
|
2409
2441
|
getCachedHrefNoQuery as r,
|
|
2410
2442
|
getFuncSpanHeader as s,
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2443
|
+
getIdentifiedUser as t,
|
|
2444
|
+
getOrSetSessionId as u,
|
|
2445
|
+
getUrlAndStoredUuids as v,
|
|
2446
|
+
identify as w,
|
|
2447
|
+
initRecorder as x,
|
|
2416
2448
|
yieldToMain as y,
|
|
2417
|
-
|
|
2449
|
+
initializeConsolePlugin as z
|
|
2418
2450
|
};
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/env.js.br
ADDED
|
Binary file
|
package/dist/env.js.gz
ADDED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createTriageAndIssueFromRecorder, createTriageFromRecorder, } from "../graphql";
|
|
2
|
-
import { getFieldsForProject, getIntegrationData, getProjectsForTeam, getSprintFieldId, getUsers, hasValidIntegration, refreshIntegrationData, updateFormWithIntegrationData, updateIssueTypeOptions, } from "./integrations";
|
|
2
|
+
import { getDefaultReporterAccountId, getFieldsForProject, getIntegrationData, getProjectsForTeam, getSprintFieldId, getUsers, hasValidIntegration, refreshIntegrationData, updateFormWithIntegrationData, updateIssueTypeOptions, } from "./integrations";
|
|
3
3
|
import { currentState, isRecording, recordingEndTime, recordingStartTime, resetState, setIsRecording, setRecordingEndTime, setRecordingStartTime, setTimerInterval, timerInterval, } from "./state";
|
|
4
4
|
import { STORAGE_KEYS } from "./types";
|
|
5
5
|
import { getChevronSVG, renderCustomMultiSelect, renderDynamicField, } from "./ui";
|
|
@@ -837,15 +837,16 @@ function initializeEngTicketForm() {
|
|
|
837
837
|
}
|
|
838
838
|
// Update form with integration data
|
|
839
839
|
updateFormWithIntegrationData(currentState);
|
|
840
|
-
// Handle reporter field for Jira
|
|
840
|
+
// Handle reporter field for Jira — match identified user by name/email
|
|
841
841
|
if (integrationData.provider?.toLowerCase() === "jira" &&
|
|
842
|
-
|
|
843
|
-
currentState.
|
|
842
|
+
currentState.engTicketProject &&
|
|
843
|
+
!currentState.engTicketCustomFields["reporter"]) {
|
|
844
844
|
const fields = getFieldsForProject(currentState.engTicketProject, currentState.engTicketIssueType);
|
|
845
845
|
const reporterField = fields.find((f) => f.fieldId === "reporter");
|
|
846
|
-
if (reporterField
|
|
846
|
+
if (reporterField) {
|
|
847
|
+
const matchedReporter = getDefaultReporterAccountId();
|
|
847
848
|
currentState.engTicketCustomFields["reporter"] =
|
|
848
|
-
integrationData.jiraReporterAccountId;
|
|
849
|
+
matchedReporter || integrationData.jiraReporterAccountId || "";
|
|
849
850
|
}
|
|
850
851
|
}
|
|
851
852
|
// If a project is already selected, render dynamic fields
|
|
@@ -961,13 +962,13 @@ function bindEngTicketListeners() {
|
|
|
961
962
|
}
|
|
962
963
|
if (integrationData &&
|
|
963
964
|
integrationData.provider?.toLowerCase() === "jira" &&
|
|
964
|
-
integrationData.jiraReporterAccountId &&
|
|
965
965
|
engProjectSelect.value) {
|
|
966
966
|
const fields = getFieldsForProject(engProjectSelect.value, currentState.engTicketIssueType);
|
|
967
967
|
const reporterField = fields.find((f) => f.fieldId === "reporter");
|
|
968
968
|
if (reporterField) {
|
|
969
|
+
const matchedReporter = getDefaultReporterAccountId();
|
|
969
970
|
currentState.engTicketCustomFields["reporter"] =
|
|
970
|
-
integrationData.jiraReporterAccountId;
|
|
971
|
+
matchedReporter || integrationData.jiraReporterAccountId || "";
|
|
971
972
|
}
|
|
972
973
|
}
|
|
973
974
|
renderDynamicFields(engProjectSelect.value, currentState.engTicketIssueType);
|
|
@@ -1160,16 +1161,16 @@ function bindListeners() {
|
|
|
1160
1161
|
currentState.engTicketPriority = integrationData.defaultPriority;
|
|
1161
1162
|
}
|
|
1162
1163
|
updateFormWithIntegrationData(currentState);
|
|
1163
|
-
// Handle reporter field for Jira
|
|
1164
|
+
// Handle reporter field for Jira — match identified user
|
|
1164
1165
|
if (integrationData.provider?.toLowerCase() === "jira" &&
|
|
1165
|
-
|
|
1166
|
-
currentState.
|
|
1166
|
+
currentState.engTicketProject &&
|
|
1167
|
+
!currentState.engTicketCustomFields["reporter"]) {
|
|
1167
1168
|
const fields = getFieldsForProject(currentState.engTicketProject, currentState.engTicketIssueType);
|
|
1168
1169
|
const reporterField = fields.find((f) => f.fieldId === "reporter");
|
|
1169
|
-
if (reporterField
|
|
1170
|
-
|
|
1170
|
+
if (reporterField) {
|
|
1171
|
+
const matchedReporter = getDefaultReporterAccountId();
|
|
1171
1172
|
currentState.engTicketCustomFields["reporter"] =
|
|
1172
|
-
integrationData.jiraReporterAccountId;
|
|
1173
|
+
matchedReporter || integrationData.jiraReporterAccountId || "";
|
|
1173
1174
|
}
|
|
1174
1175
|
}
|
|
1175
1176
|
// Render dynamic fields if a project is already selected
|
|
Binary file
|
|
Binary file
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { fetchEngineeringTicketPlatformIntegrations } from "../graphql";
|
|
2
|
+
import { getIdentifiedUser } from "../sendSailfishMessages";
|
|
2
3
|
const SUPPORT_TICKET_INTEGRATIONS = ["jira", "linear", "zendesk"];
|
|
3
4
|
let integrationData = null;
|
|
4
5
|
// Cache per cloud so switching between clouds is instant
|
|
@@ -220,11 +221,14 @@ export function getFieldsForProject(projectId, issueTypeId) {
|
|
|
220
221
|
if (!integrationData?.fieldConfigurations || !projectId) {
|
|
221
222
|
return [];
|
|
222
223
|
}
|
|
223
|
-
// fieldConfigurations is organized by project+issue_type combination
|
|
224
|
-
// Match
|
|
224
|
+
// fieldConfigurations is organized by project+issue_type combination.
|
|
225
|
+
// Match project by key OR numeric id, and issue type with string coercion
|
|
226
|
+
// to avoid type mismatches (number vs string from different code paths).
|
|
225
227
|
const projectConfig = Array.isArray(integrationData.fieldConfigurations)
|
|
226
|
-
? integrationData.fieldConfigurations.find((config) => config.project_key === projectId
|
|
227
|
-
(
|
|
228
|
+
? integrationData.fieldConfigurations.find((config) => (config.project_key === projectId ||
|
|
229
|
+
String(config.project_id) === String(projectId)) &&
|
|
230
|
+
(!issueTypeId ||
|
|
231
|
+
String(config.issue_type_id) === String(issueTypeId)))
|
|
228
232
|
: integrationData.fieldConfigurations[projectId];
|
|
229
233
|
if (!projectConfig || !projectConfig.fields) {
|
|
230
234
|
return [];
|
|
@@ -237,6 +241,54 @@ export function getUsers() {
|
|
|
237
241
|
}
|
|
238
242
|
return integrationData.users;
|
|
239
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* Match the current identified user against the Jira users list and
|
|
246
|
+
* return their accountId. Uses email, name, and email-prefix matching
|
|
247
|
+
* (same logic as the dashboard). Only returns a match when exactly one
|
|
248
|
+
* user matches to avoid ambiguity.
|
|
249
|
+
*/
|
|
250
|
+
export function getDefaultReporterAccountId() {
|
|
251
|
+
const users = getUsers();
|
|
252
|
+
const identified = getIdentifiedUser();
|
|
253
|
+
if (!users.length || !identified)
|
|
254
|
+
return null;
|
|
255
|
+
const traits = identified.traits || {};
|
|
256
|
+
const email = (traits.email || identified.userId || "").toLowerCase().trim();
|
|
257
|
+
const name = (traits.name ||
|
|
258
|
+
traits.displayName ||
|
|
259
|
+
traits.fullName ||
|
|
260
|
+
traits.full_name ||
|
|
261
|
+
(traits.firstName || traits.first_name
|
|
262
|
+
? `${traits.firstName || traits.first_name} ${traits.lastName || traits.last_name || ""}`.trim()
|
|
263
|
+
: "") ||
|
|
264
|
+
"").toLowerCase().trim();
|
|
265
|
+
const findUnique = (pred) => {
|
|
266
|
+
const matches = users.filter(pred);
|
|
267
|
+
return matches.length === 1 ? matches[0] : null;
|
|
268
|
+
};
|
|
269
|
+
// 1. Exact email match
|
|
270
|
+
let matched = email
|
|
271
|
+
? findUnique((u) => (u.email || u.emailAddress || "").toLowerCase().trim() === email)
|
|
272
|
+
: null;
|
|
273
|
+
// 2. Exact name match
|
|
274
|
+
if (!matched && name) {
|
|
275
|
+
matched = findUnique((u) => {
|
|
276
|
+
const userName = (u.name || u.displayName || "").toLowerCase().trim();
|
|
277
|
+
return userName === name;
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
// 3. Email prefix match against name
|
|
281
|
+
if (!matched && email) {
|
|
282
|
+
const prefix = email.split("@")[0];
|
|
283
|
+
if (prefix.length >= 3) {
|
|
284
|
+
matched = findUnique((u) => {
|
|
285
|
+
const userName = (u.name || u.displayName || "").toLowerCase().trim();
|
|
286
|
+
return userName.includes(prefix);
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return matched ? (matched.id || matched.accountId || null) : null;
|
|
291
|
+
}
|
|
240
292
|
// Get projects based on team selection (for Linear) or directly from integration (for Jira)
|
|
241
293
|
export function getProjectsForTeam(teamId) {
|
|
242
294
|
if (!integrationData)
|