glitchgrab 1.58.2 → 1.58.3
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 +4 -0
- package/dist/index.js +1453 -690
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1453 -690
- package/dist/index.mjs.map +1 -1
- package/dist/server.d.mts +11 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.js +7 -2
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +7 -2
- package/dist/server.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -239,7 +239,7 @@ function argsToString(args) {
|
|
|
239
239
|
function previewJson(value, max) {
|
|
240
240
|
let out = "";
|
|
241
241
|
const path = /* @__PURE__ */ new WeakSet();
|
|
242
|
-
const
|
|
242
|
+
const write2 = (input, inArray) => {
|
|
243
243
|
if (out.length > max) return;
|
|
244
244
|
let v = input;
|
|
245
245
|
if (v !== null && typeof v === "object" && typeof v.toJSON === "function") {
|
|
@@ -276,7 +276,7 @@ function previewJson(value, max) {
|
|
|
276
276
|
out += "[";
|
|
277
277
|
for (let i = 0; i < obj.length && out.length <= max; i++) {
|
|
278
278
|
if (i > 0) out += ",";
|
|
279
|
-
|
|
279
|
+
write2(obj[i], true);
|
|
280
280
|
}
|
|
281
281
|
out += "]";
|
|
282
282
|
} else {
|
|
@@ -289,13 +289,13 @@ function previewJson(value, max) {
|
|
|
289
289
|
if (child === void 0 || typeof child === "function" || typeof child === "symbol") continue;
|
|
290
290
|
out += `${first ? "" : ","}${JSON.stringify(key)}:`;
|
|
291
291
|
first = false;
|
|
292
|
-
|
|
292
|
+
write2(child, false);
|
|
293
293
|
}
|
|
294
294
|
out += "}";
|
|
295
295
|
}
|
|
296
296
|
path.delete(obj);
|
|
297
297
|
};
|
|
298
|
-
|
|
298
|
+
write2(value, false);
|
|
299
299
|
return out;
|
|
300
300
|
}
|
|
301
301
|
async function readErrorBody(response, url) {
|
|
@@ -956,6 +956,292 @@ function clearDedupCache() {
|
|
|
956
956
|
seen.clear();
|
|
957
957
|
}
|
|
958
958
|
|
|
959
|
+
// src/hydration.ts
|
|
960
|
+
var HYDRATION_CODE_RE = /Minified React error #(418|419|422|423|425)\b/;
|
|
961
|
+
var HYDRATION_DEV_RE = /Hydration failed|hydration mismatch|Text content does not match|did not match\. Server|There was an error while hydrating|error occurred during hydration|server rendered HTML didn't match/i;
|
|
962
|
+
var BAILOUT_DIGEST = "BAILOUT_TO_CLIENT_SIDE_RENDERING";
|
|
963
|
+
var DOM_SNIPPET_MAX = 3e3;
|
|
964
|
+
var STACK_FRAMES_MAX = 40;
|
|
965
|
+
function messageOf(error) {
|
|
966
|
+
if (error && typeof error === "object" && typeof error.message === "string") {
|
|
967
|
+
return error.message;
|
|
968
|
+
}
|
|
969
|
+
return typeof error === "string" ? error : "";
|
|
970
|
+
}
|
|
971
|
+
function hydrationCode(message) {
|
|
972
|
+
if (!message) return null;
|
|
973
|
+
const m = HYDRATION_CODE_RE.exec(message);
|
|
974
|
+
if (m) return m[1];
|
|
975
|
+
return HYDRATION_DEV_RE.test(message) ? "dev" : null;
|
|
976
|
+
}
|
|
977
|
+
function isHydrationError(error) {
|
|
978
|
+
if (hydrationCode(messageOf(error))) return true;
|
|
979
|
+
const cause = error && typeof error === "object" ? error.cause : void 0;
|
|
980
|
+
return cause !== void 0 && cause !== error && hydrationCode(messageOf(cause)) !== null;
|
|
981
|
+
}
|
|
982
|
+
function isBailout(error) {
|
|
983
|
+
const e = error;
|
|
984
|
+
if (!e || typeof e !== "object") return false;
|
|
985
|
+
if (e.digest === BAILOUT_DIGEST) return true;
|
|
986
|
+
const c = e.cause;
|
|
987
|
+
return !!c && typeof c === "object" && c.digest === BAILOUT_DIGEST;
|
|
988
|
+
}
|
|
989
|
+
function componentStackNames(stack) {
|
|
990
|
+
if (!stack) return [];
|
|
991
|
+
const names = [];
|
|
992
|
+
for (const raw of stack.split("\n")) {
|
|
993
|
+
const line = raw.trim();
|
|
994
|
+
if (!line) continue;
|
|
995
|
+
let name = "";
|
|
996
|
+
if (line.startsWith("at ")) {
|
|
997
|
+
name = line.slice(3).split(" (")[0].trim();
|
|
998
|
+
} else if (line.includes("@")) {
|
|
999
|
+
name = line.slice(0, line.indexOf("@")).trim();
|
|
1000
|
+
} else {
|
|
1001
|
+
name = line;
|
|
1002
|
+
}
|
|
1003
|
+
if (name) names.push(name);
|
|
1004
|
+
if (names.length >= STACK_FRAMES_MAX) break;
|
|
1005
|
+
}
|
|
1006
|
+
return names;
|
|
1007
|
+
}
|
|
1008
|
+
function componentStackKey(stack) {
|
|
1009
|
+
return componentStackNames(stack).join(">");
|
|
1010
|
+
}
|
|
1011
|
+
var observer = null;
|
|
1012
|
+
var observerStarted = false;
|
|
1013
|
+
var observerStopAt = 0;
|
|
1014
|
+
var OBSERVE_MS = 3e4;
|
|
1015
|
+
function startObserver() {
|
|
1016
|
+
if (observerStarted || typeof MutationObserver === "undefined" || typeof document === "undefined") {
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
observerStarted = true;
|
|
1020
|
+
try {
|
|
1021
|
+
observer = new MutationObserver(() => {
|
|
1022
|
+
if (Date.now() > observerStopAt) stopObserver();
|
|
1023
|
+
});
|
|
1024
|
+
observer.observe(document, { childList: true, subtree: true });
|
|
1025
|
+
observerStopAt = Date.now() + OBSERVE_MS;
|
|
1026
|
+
setTimeout(stopObserver, OBSERVE_MS);
|
|
1027
|
+
} catch (e) {
|
|
1028
|
+
observer = null;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
function stopObserver() {
|
|
1032
|
+
try {
|
|
1033
|
+
observer == null ? void 0 : observer.disconnect();
|
|
1034
|
+
} catch (e) {
|
|
1035
|
+
}
|
|
1036
|
+
observer = null;
|
|
1037
|
+
}
|
|
1038
|
+
function describeNode(node) {
|
|
1039
|
+
if (!node) return "";
|
|
1040
|
+
if (node.nodeType === 9) return "#document";
|
|
1041
|
+
const el = node;
|
|
1042
|
+
if (!el.tagName) return node.nodeName;
|
|
1043
|
+
const id = el.id ? `#${el.id}` : "";
|
|
1044
|
+
const cls = typeof el.className === "string" && el.className.trim() ? "." + el.className.trim().split(/\s+/).slice(0, 3).join(".") : "";
|
|
1045
|
+
return `${el.tagName.toLowerCase()}${id}${cls}`;
|
|
1046
|
+
}
|
|
1047
|
+
function pathOf(node) {
|
|
1048
|
+
const parts = [];
|
|
1049
|
+
let cur = node;
|
|
1050
|
+
while (cur && parts.length < 6) {
|
|
1051
|
+
parts.unshift(describeNode(cur));
|
|
1052
|
+
if (cur.nodeType === 9) break;
|
|
1053
|
+
cur = cur.parentNode;
|
|
1054
|
+
}
|
|
1055
|
+
return parts.join(" > ");
|
|
1056
|
+
}
|
|
1057
|
+
var NON_CONTENT_TAGS = /* @__PURE__ */ new Set(["SCRIPT", "STYLE", "LINK", "META", "NOSCRIPT", "TEMPLATE", "TITLE", "HEAD"]);
|
|
1058
|
+
function isInHead(node) {
|
|
1059
|
+
for (let cur = node; cur; cur = cur.parentNode) {
|
|
1060
|
+
if (cur.nodeName === "HEAD") return true;
|
|
1061
|
+
if (cur.nodeName === "BODY") return false;
|
|
1062
|
+
}
|
|
1063
|
+
return false;
|
|
1064
|
+
}
|
|
1065
|
+
var GSTIN_RE = /\b\d{2}[A-Z]{5}\d{4}[A-Z][A-Z0-9]Z[A-Z0-9]\b/g;
|
|
1066
|
+
var PAN_RE = /\b[A-Z]{5}\d{4}[A-Z]\b/g;
|
|
1067
|
+
function scrubHtml(html) {
|
|
1068
|
+
return redactString(
|
|
1069
|
+
html.replace(/\svalue="[^"]*"/gi, ' value="[REDACTED]"').replace(GSTIN_RE, "[REDACTED_GSTIN]").replace(PAN_RE, "[REDACTED_PAN]").replace(/\d{6,}/g, (m) => "#".repeat(Math.min(m.length, 6)))
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
function takeRemovedServerHtml() {
|
|
1073
|
+
var _a, _b;
|
|
1074
|
+
if (!observer) return { html: "", where: "" };
|
|
1075
|
+
try {
|
|
1076
|
+
const records = observer.takeRecords();
|
|
1077
|
+
let html = "";
|
|
1078
|
+
let where = "";
|
|
1079
|
+
for (const rec of records) {
|
|
1080
|
+
if (rec.type !== "childList" || rec.removedNodes.length === 0) continue;
|
|
1081
|
+
if (isInHead(rec.target)) continue;
|
|
1082
|
+
if (!where) where = pathOf(rec.target);
|
|
1083
|
+
for (const node of Array.from(rec.removedNodes)) {
|
|
1084
|
+
if (node.nodeType === 1 && NON_CONTENT_TAGS.has(node.tagName)) continue;
|
|
1085
|
+
if (node.nodeType === 3 && !((_a = node.textContent) != null ? _a : "").trim()) continue;
|
|
1086
|
+
const piece = node.nodeType === 1 ? node.outerHTML : node.nodeType === 3 ? `#text "${(_b = node.textContent) != null ? _b : ""}"` : "";
|
|
1087
|
+
if (!piece) continue;
|
|
1088
|
+
html += (html ? "\n" : "") + piece;
|
|
1089
|
+
if (html.length >= DOM_SNIPPET_MAX) break;
|
|
1090
|
+
}
|
|
1091
|
+
if (html.length >= DOM_SNIPPET_MAX) break;
|
|
1092
|
+
}
|
|
1093
|
+
const scrubbed = scrubHtml(html);
|
|
1094
|
+
return {
|
|
1095
|
+
html: scrubbed.length > DOM_SNIPPET_MAX ? `${scrubbed.slice(0, DOM_SNIPPET_MAX)}\u2026[truncated]` : scrubbed,
|
|
1096
|
+
where
|
|
1097
|
+
};
|
|
1098
|
+
} catch (e) {
|
|
1099
|
+
return { html: "", where: "" };
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
function detectForeignNodes(doc = document) {
|
|
1103
|
+
var _a;
|
|
1104
|
+
const found = [];
|
|
1105
|
+
try {
|
|
1106
|
+
const html = doc.documentElement;
|
|
1107
|
+
if ((html == null ? void 0 : html.classList.contains("translated-ltr")) || (html == null ? void 0 : html.classList.contains("translated-rtl"))) {
|
|
1108
|
+
found.push("Google Translate is active (html.translated-*)");
|
|
1109
|
+
}
|
|
1110
|
+
const fonts = doc.getElementsByTagName("font").length;
|
|
1111
|
+
if (fonts > 0) found.push(`<font> \xD7 ${fonts} (Google Translate or a translation extension)`);
|
|
1112
|
+
const detectors = doc.querySelectorAll("a[x-apple-data-detectors]").length;
|
|
1113
|
+
if (detectors > 0) {
|
|
1114
|
+
found.push(`<a x-apple-data-detectors> \xD7 ${detectors} (iOS format detection turned text into links)`);
|
|
1115
|
+
}
|
|
1116
|
+
if (doc.querySelector("[data-gr-ext-installed],[data-new-gr-c-s-check-loaded],grammarly-desktop-integration")) {
|
|
1117
|
+
found.push("Grammarly extension attributes");
|
|
1118
|
+
}
|
|
1119
|
+
if (doc.querySelector("[data-lt-installed]")) found.push("LanguageTool extension attributes");
|
|
1120
|
+
if ((_a = doc.body) == null ? void 0 : _a.hasAttribute("cz-shortcut-listen")) found.push("ColorZilla extension attribute on <body>");
|
|
1121
|
+
const custom = /* @__PURE__ */ new Set();
|
|
1122
|
+
for (const parent of [html, doc.body]) {
|
|
1123
|
+
if (!parent) continue;
|
|
1124
|
+
for (const child of Array.from(parent.children)) {
|
|
1125
|
+
const tag = child.tagName.toLowerCase();
|
|
1126
|
+
if (tag.includes("-")) custom.add(tag);
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
if (custom.size > 0) {
|
|
1130
|
+
found.push(`custom elements at top level: ${Array.from(custom).slice(0, 5).join(", ")} (often an extension)`);
|
|
1131
|
+
}
|
|
1132
|
+
} catch (e) {
|
|
1133
|
+
}
|
|
1134
|
+
return found;
|
|
1135
|
+
}
|
|
1136
|
+
function hydrationTiming() {
|
|
1137
|
+
var _a, _b, _c, _d;
|
|
1138
|
+
try {
|
|
1139
|
+
if (typeof performance === "undefined") return "";
|
|
1140
|
+
const at2 = Math.round(performance.now());
|
|
1141
|
+
const parts = [`error at ${at2}ms after navigation start`];
|
|
1142
|
+
const nav = (_b = (_a = performance.getEntriesByType) == null ? void 0 : _a.call(performance, "navigation")) == null ? void 0 : _b[0];
|
|
1143
|
+
if (nav == null ? void 0 : nav.domContentLoadedEventEnd) {
|
|
1144
|
+
parts.push(`DOMContentLoaded ${Math.round(nav.domContentLoadedEventEnd)}ms`);
|
|
1145
|
+
}
|
|
1146
|
+
const fetches = ((_d = (_c = performance.getEntriesByType) == null ? void 0 : _c.call(performance, "resource")) != null ? _d : []).filter((e) => {
|
|
1147
|
+
const t = e.initiatorType;
|
|
1148
|
+
return t === "fetch" || t === "xmlhttprequest";
|
|
1149
|
+
}).sort((a, b) => a.responseEnd - b.responseEnd).slice(0, 8).map((e) => {
|
|
1150
|
+
let path = e.name;
|
|
1151
|
+
try {
|
|
1152
|
+
const u = new URL(e.name);
|
|
1153
|
+
path = u.origin === window.location.origin ? u.pathname : `${u.host}${u.pathname}`;
|
|
1154
|
+
} catch (e2) {
|
|
1155
|
+
}
|
|
1156
|
+
return `${path} ${Math.round(e.responseEnd)}ms`;
|
|
1157
|
+
});
|
|
1158
|
+
if (fetches.length > 0) parts.push(`fetches finished before it: ${fetches.join(", ")}`);
|
|
1159
|
+
else parts.push("no fetch had finished yet");
|
|
1160
|
+
return parts.join("; ");
|
|
1161
|
+
} catch (e) {
|
|
1162
|
+
return "";
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
function hydrationMetadata(error, extra) {
|
|
1166
|
+
var _a, _b, _c;
|
|
1167
|
+
const code = (_a = hydrationCode(messageOf(error))) != null ? _a : hydrationCode(messageOf(error == null ? void 0 : error.cause));
|
|
1168
|
+
const meta = { errorKind: "hydration" };
|
|
1169
|
+
if (code) meta.hydrationCode = code;
|
|
1170
|
+
const cause = error == null ? void 0 : error.cause;
|
|
1171
|
+
if (cause && cause !== error && messageOf(cause)) {
|
|
1172
|
+
meta.hydrationCause = messageOf(cause).slice(0, 500);
|
|
1173
|
+
}
|
|
1174
|
+
if ((_b = extra == null ? void 0 : extra.removed) == null ? void 0 : _b.html) meta.hydrationServerHtml = extra.removed.html;
|
|
1175
|
+
if ((_c = extra == null ? void 0 : extra.removed) == null ? void 0 : _c.where) meta.hydrationReplacedIn = extra.removed.where;
|
|
1176
|
+
const foreign = detectForeignNodes();
|
|
1177
|
+
if (foreign.length > 0) meta.hydrationForeignNodes = foreign.join("\n");
|
|
1178
|
+
const timing = hydrationTiming();
|
|
1179
|
+
if (timing) meta.hydrationTiming = timing;
|
|
1180
|
+
return meta;
|
|
1181
|
+
}
|
|
1182
|
+
var handled = /* @__PURE__ */ new WeakSet();
|
|
1183
|
+
function isHandledHydrationError(error) {
|
|
1184
|
+
return !!error && typeof error === "object" && handled.has(error);
|
|
1185
|
+
}
|
|
1186
|
+
function markHandled(error) {
|
|
1187
|
+
if (error && typeof error === "object") {
|
|
1188
|
+
handled.add(error);
|
|
1189
|
+
const cause = error.cause;
|
|
1190
|
+
if (cause && typeof cause === "object") handled.add(cause);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
var reporter = null;
|
|
1194
|
+
var PATCHED = "__glitchgrabHydrationPatched";
|
|
1195
|
+
function findFiberRoot(container) {
|
|
1196
|
+
if (!container || typeof container !== "object") return null;
|
|
1197
|
+
try {
|
|
1198
|
+
const key = Object.keys(container).find((k) => k.startsWith("__reactContainer$"));
|
|
1199
|
+
if (!key) return null;
|
|
1200
|
+
const hostRoot = container[key];
|
|
1201
|
+
const root = hostRoot == null ? void 0 : hostRoot.stateNode;
|
|
1202
|
+
return root && typeof root === "object" ? root : null;
|
|
1203
|
+
} catch (e) {
|
|
1204
|
+
return null;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
function patchRoot(root) {
|
|
1208
|
+
if (root[PATCHED]) return true;
|
|
1209
|
+
const original = root.onRecoverableError;
|
|
1210
|
+
if (typeof original !== "function") return false;
|
|
1211
|
+
root.onRecoverableError = function glitchgrabOnRecoverableError(error, info) {
|
|
1212
|
+
var _a;
|
|
1213
|
+
try {
|
|
1214
|
+
if (reporter && isHydrationError(error) && !isBailout(error)) {
|
|
1215
|
+
const removed = takeRemovedServerHtml();
|
|
1216
|
+
markHandled(error);
|
|
1217
|
+
reporter(error, (_a = info == null ? void 0 : info.componentStack) != null ? _a : "", hydrationMetadata(error, { removed }));
|
|
1218
|
+
}
|
|
1219
|
+
} catch (e) {
|
|
1220
|
+
}
|
|
1221
|
+
return original.call(this, error, info);
|
|
1222
|
+
};
|
|
1223
|
+
root[PATCHED] = true;
|
|
1224
|
+
return true;
|
|
1225
|
+
}
|
|
1226
|
+
function patchKnownRoots() {
|
|
1227
|
+
if (typeof document === "undefined") return false;
|
|
1228
|
+
let patched = false;
|
|
1229
|
+
for (const container of [document, document.getElementById("__next"), document.getElementById("root")]) {
|
|
1230
|
+
const root = findFiberRoot(container);
|
|
1231
|
+
if (root && patchRoot(root)) patched = true;
|
|
1232
|
+
}
|
|
1233
|
+
return patched;
|
|
1234
|
+
}
|
|
1235
|
+
function installHydrationCapture(report) {
|
|
1236
|
+
try {
|
|
1237
|
+
if (typeof window === "undefined") return;
|
|
1238
|
+
reporter = report;
|
|
1239
|
+
startObserver();
|
|
1240
|
+
patchKnownRoots();
|
|
1241
|
+
} catch (e) {
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
959
1245
|
// src/capture.ts
|
|
960
1246
|
var config = null;
|
|
961
1247
|
function registerCaptureConfig(next) {
|
|
@@ -975,7 +1261,7 @@ function sessionMetadata(session) {
|
|
|
975
1261
|
...(session == null ? void 0 : session.phone) ? { sessionUserPhone: String(session.phone) } : {}
|
|
976
1262
|
};
|
|
977
1263
|
}
|
|
978
|
-
function buildCapturedErrorPayload(error, options, cfg, capturedBy = "captureError") {
|
|
1264
|
+
function buildCapturedErrorPayload(error, options, cfg, capturedBy = "captureError", dedupKey) {
|
|
979
1265
|
var _a, _b, _c;
|
|
980
1266
|
const err = error instanceof Error ? error : void 0;
|
|
981
1267
|
const errorMessage = err ? err.message : String(error);
|
|
@@ -987,7 +1273,7 @@ function buildCapturedErrorPayload(error, options, cfg, capturedBy = "captureErr
|
|
|
987
1273
|
const sig = computeSignature({
|
|
988
1274
|
errorMessage,
|
|
989
1275
|
pageUrl: context.url,
|
|
990
|
-
errorStack: err == null ? void 0 : err.stack,
|
|
1276
|
+
errorStack: dedupKey ? `at ${dedupKey}` : err == null ? void 0 : err.stack,
|
|
991
1277
|
digest
|
|
992
1278
|
});
|
|
993
1279
|
if (shouldSkipDuplicate(sig)) return null;
|
|
@@ -1027,6 +1313,25 @@ function captureError(error, options) {
|
|
|
1027
1313
|
} catch (e) {
|
|
1028
1314
|
}
|
|
1029
1315
|
}
|
|
1316
|
+
function reportHydrationError(error, componentStack, metadata) {
|
|
1317
|
+
try {
|
|
1318
|
+
const cfg = config;
|
|
1319
|
+
if (!(cfg == null ? void 0 : cfg.token)) return;
|
|
1320
|
+
const payload = buildCapturedErrorPayload(
|
|
1321
|
+
error,
|
|
1322
|
+
{ componentStack: componentStack || void 0, metadata },
|
|
1323
|
+
cfg,
|
|
1324
|
+
"onRecoverableError",
|
|
1325
|
+
componentStackKey(componentStack) || void 0
|
|
1326
|
+
);
|
|
1327
|
+
if (!payload) return;
|
|
1328
|
+
void sendReport(payload, cfg.baseUrl).then((result) => {
|
|
1329
|
+
if (result && cfg.onReportSent) cfg.onReportSent(result);
|
|
1330
|
+
});
|
|
1331
|
+
if (cfg.onError && error instanceof Error) cfg.onError(error);
|
|
1332
|
+
} catch (e) {
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1030
1335
|
|
|
1031
1336
|
// src/error-boundary.tsx
|
|
1032
1337
|
var GlitchgrabErrorBoundary = class extends React.Component {
|
|
@@ -1948,6 +2253,79 @@ function renderBlocks(lines, theme, key) {
|
|
|
1948
2253
|
function ChatMarkdown({ text, theme }) {
|
|
1949
2254
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: STACK, children: renderBlocks(text.replace(/\r\n?/g, "\n").split("\n"), theme, "md") });
|
|
1950
2255
|
}
|
|
2256
|
+
var MAX_SAVED_CHATS = 20;
|
|
2257
|
+
var SAVED_CHAT_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
2258
|
+
var TITLE_CHARS = 80;
|
|
2259
|
+
var PREFIX = "glitchgrab:ai-chats:";
|
|
2260
|
+
function chatHistoryKey(...parts) {
|
|
2261
|
+
const input = parts.map((p) => p != null ? p : "").join("\0");
|
|
2262
|
+
let hash = 2166136261;
|
|
2263
|
+
for (let i = 0; i < input.length; i++) {
|
|
2264
|
+
hash ^= input.charCodeAt(i);
|
|
2265
|
+
hash = Math.imul(hash, 16777619);
|
|
2266
|
+
}
|
|
2267
|
+
return (hash >>> 0).toString(36);
|
|
2268
|
+
}
|
|
2269
|
+
function chatTitle(messages) {
|
|
2270
|
+
var _a, _b;
|
|
2271
|
+
const first = (_b = (_a = messages.find((m) => m.role === "user")) == null ? void 0 : _a.content.trim()) != null ? _b : "";
|
|
2272
|
+
const line = first.replace(/\s+/g, " ");
|
|
2273
|
+
return line.length > TITLE_CHARS ? `${line.slice(0, TITLE_CHARS - 1)}\u2026` : line;
|
|
2274
|
+
}
|
|
2275
|
+
function storage() {
|
|
2276
|
+
try {
|
|
2277
|
+
return typeof window !== "undefined" && window.localStorage ? window.localStorage : null;
|
|
2278
|
+
} catch (e) {
|
|
2279
|
+
return null;
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
function isSavedChat(value) {
|
|
2283
|
+
if (!value || typeof value !== "object") return false;
|
|
2284
|
+
const c = value;
|
|
2285
|
+
return typeof c.id === "string" && typeof c.title === "string" && typeof c.updatedAt === "number" && (c.status === "open" || c.status === "filed") && Array.isArray(c.messages);
|
|
2286
|
+
}
|
|
2287
|
+
function loadChats(key, now = Date.now()) {
|
|
2288
|
+
const store = storage();
|
|
2289
|
+
if (!store) return [];
|
|
2290
|
+
try {
|
|
2291
|
+
const raw = store.getItem(PREFIX + key);
|
|
2292
|
+
if (!raw) return [];
|
|
2293
|
+
const parsed = JSON.parse(raw);
|
|
2294
|
+
if (!Array.isArray(parsed)) return [];
|
|
2295
|
+
return parsed.filter(isSavedChat).filter((c) => now - c.updatedAt < SAVED_CHAT_MAX_AGE_MS).sort((a, b) => b.updatedAt - a.updatedAt).slice(0, MAX_SAVED_CHATS);
|
|
2296
|
+
} catch (e) {
|
|
2297
|
+
return [];
|
|
2298
|
+
}
|
|
2299
|
+
}
|
|
2300
|
+
function write(key, chats) {
|
|
2301
|
+
const store = storage();
|
|
2302
|
+
if (!store) return;
|
|
2303
|
+
try {
|
|
2304
|
+
if (chats.length === 0) store.removeItem(PREFIX + key);
|
|
2305
|
+
else store.setItem(PREFIX + key, JSON.stringify(chats));
|
|
2306
|
+
} catch (e) {
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
function saveChat(key, chat, now = Date.now()) {
|
|
2310
|
+
const rest = loadChats(key, now).filter((c) => c.id !== chat.id);
|
|
2311
|
+
const next = [chat, ...rest].slice(0, MAX_SAVED_CHATS);
|
|
2312
|
+
write(key, next);
|
|
2313
|
+
return next;
|
|
2314
|
+
}
|
|
2315
|
+
function markChatFiled(key, conversationId, label, now = Date.now()) {
|
|
2316
|
+
const chats = loadChats(key, now);
|
|
2317
|
+
const hit = chats.find((c) => c.conversationId === conversationId);
|
|
2318
|
+
if (!hit || hit.status === "filed") return;
|
|
2319
|
+
write(
|
|
2320
|
+
key,
|
|
2321
|
+
chats.map((c) => c === hit ? { ...c, status: "filed", filedLabel: label, updatedAt: now } : c)
|
|
2322
|
+
);
|
|
2323
|
+
}
|
|
2324
|
+
function removeChat(key, id, now = Date.now()) {
|
|
2325
|
+
const next = loadChats(key, now).filter((c) => c.id !== id);
|
|
2326
|
+
write(key, next);
|
|
2327
|
+
return next;
|
|
2328
|
+
}
|
|
1951
2329
|
function pickAssistImages(all) {
|
|
1952
2330
|
const picked = [];
|
|
1953
2331
|
let total = 0;
|
|
@@ -1974,6 +2352,18 @@ function pickAssistFiles(files) {
|
|
|
1974
2352
|
}
|
|
1975
2353
|
return picked;
|
|
1976
2354
|
}
|
|
2355
|
+
function newChatId() {
|
|
2356
|
+
return `local-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;
|
|
2357
|
+
}
|
|
2358
|
+
function chatAge(at2, now = Date.now()) {
|
|
2359
|
+
const min = Math.round((now - at2) / 6e4);
|
|
2360
|
+
if (min < 1) return "just now";
|
|
2361
|
+
if (min < 60) return `${min} min ago`;
|
|
2362
|
+
const hours = Math.round(min / 60);
|
|
2363
|
+
if (hours < 24) return `${hours} h ago`;
|
|
2364
|
+
if (hours < 48) return "yesterday";
|
|
2365
|
+
return new Date(at2).toLocaleDateString(void 0, { day: "numeric", month: "short" });
|
|
2366
|
+
}
|
|
1977
2367
|
var STARTERS = [
|
|
1978
2368
|
"Something on this page is broken",
|
|
1979
2369
|
"It did the wrong thing",
|
|
@@ -2056,6 +2446,33 @@ function Avatar({
|
|
|
2056
2446
|
}
|
|
2057
2447
|
);
|
|
2058
2448
|
}
|
|
2449
|
+
var THINKING_SLOW_SECONDS = 20;
|
|
2450
|
+
function ThinkingClock({ color }) {
|
|
2451
|
+
const [seconds, setSeconds] = (0, import_react3.useState)(0);
|
|
2452
|
+
(0, import_react3.useEffect)(() => {
|
|
2453
|
+
const started = Date.now();
|
|
2454
|
+
const id = setInterval(() => setSeconds(Math.floor((Date.now() - started) / 1e3)), 1e3);
|
|
2455
|
+
return () => clearInterval(id);
|
|
2456
|
+
}, []);
|
|
2457
|
+
return (
|
|
2458
|
+
// Hidden from screen readers: the bubble already says "Thinking", and a
|
|
2459
|
+
// number changing every second would be read out every second.
|
|
2460
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2461
|
+
"span",
|
|
2462
|
+
{
|
|
2463
|
+
"data-gg-thinking-clock": "",
|
|
2464
|
+
"aria-hidden": "true",
|
|
2465
|
+
style: { marginLeft: "6px", fontSize: "12px", color, fontVariantNumeric: "tabular-nums" },
|
|
2466
|
+
children: [
|
|
2467
|
+
"Thinking\u2026 ",
|
|
2468
|
+
seconds,
|
|
2469
|
+
"s",
|
|
2470
|
+
seconds >= THINKING_SLOW_SECONDS ? " \xB7 taking longer than usual, still working" : ""
|
|
2471
|
+
]
|
|
2472
|
+
}
|
|
2473
|
+
)
|
|
2474
|
+
);
|
|
2475
|
+
}
|
|
2059
2476
|
function AssistSheet({
|
|
2060
2477
|
assist,
|
|
2061
2478
|
theme: t,
|
|
@@ -2096,14 +2513,22 @@ function AssistSheet({
|
|
|
2096
2513
|
onDegrade,
|
|
2097
2514
|
onClose,
|
|
2098
2515
|
onFinish,
|
|
2099
|
-
onReportGlitchgrabProblem
|
|
2516
|
+
onReportGlitchgrabProblem,
|
|
2517
|
+
historyKey = null
|
|
2100
2518
|
}) {
|
|
2519
|
+
var _a;
|
|
2101
2520
|
const narrow = useIsNarrow();
|
|
2102
2521
|
const severityAsked = showSeverity && currentTile === "BUG";
|
|
2103
2522
|
const [messages, setMessages] = (0, import_react3.useState)([]);
|
|
2104
2523
|
const [input, setInput] = (0, import_react3.useState)("");
|
|
2105
2524
|
const [busy, setBusy] = (0, import_react3.useState)(false);
|
|
2106
2525
|
const [conversationId, setConversationId] = (0, import_react3.useState)(null);
|
|
2526
|
+
const chatIdRef = (0, import_react3.useRef)(newChatId());
|
|
2527
|
+
const [savedChats, setSavedChats] = (0, import_react3.useState)(
|
|
2528
|
+
() => historyKey ? loadChats(historyKey) : []
|
|
2529
|
+
);
|
|
2530
|
+
const [showChats, setShowChats] = (0, import_react3.useState)(false);
|
|
2531
|
+
const [viewingChat, setViewingChat] = (0, import_react3.useState)(null);
|
|
2107
2532
|
const [hoveredStar, setHoveredStar] = (0, import_react3.useState)(0);
|
|
2108
2533
|
const [options, setOptions] = (0, import_react3.useState)([]);
|
|
2109
2534
|
const [duplicate, setDuplicate] = (0, import_react3.useState)(null);
|
|
@@ -2155,8 +2580,8 @@ function AssistSheet({
|
|
|
2155
2580
|
if (el) el.scrollTop = el.scrollHeight;
|
|
2156
2581
|
}, [messages, busy, phase]);
|
|
2157
2582
|
(0, import_react3.useEffect)(() => {
|
|
2158
|
-
var
|
|
2159
|
-
if (phase === "draft") (
|
|
2583
|
+
var _a2;
|
|
2584
|
+
if (phase === "draft") (_a2 = draftRef.current) == null ? void 0 : _a2.focus();
|
|
2160
2585
|
}, [phase]);
|
|
2161
2586
|
(0, import_react3.useEffect)(() => {
|
|
2162
2587
|
const el = composerRef.current;
|
|
@@ -2188,7 +2613,8 @@ function AssistSheet({
|
|
|
2188
2613
|
onDegrade(message, retryable);
|
|
2189
2614
|
}
|
|
2190
2615
|
async function runTurn(history2, autoFile = false) {
|
|
2191
|
-
var
|
|
2616
|
+
var _a2, _b, _c;
|
|
2617
|
+
const turnChat = chatIdRef.current;
|
|
2192
2618
|
setBusy(true);
|
|
2193
2619
|
setAutoFileLeft(null);
|
|
2194
2620
|
let result;
|
|
@@ -2225,6 +2651,7 @@ function AssistSheet({
|
|
|
2225
2651
|
} finally {
|
|
2226
2652
|
setBusy(false);
|
|
2227
2653
|
}
|
|
2654
|
+
if (chatIdRef.current !== turnChat) return;
|
|
2228
2655
|
if (result.degraded) {
|
|
2229
2656
|
degradeKeepingEvents(events, result.degraded, result.retryable === true);
|
|
2230
2657
|
return;
|
|
@@ -2235,7 +2662,7 @@ function AssistSheet({
|
|
|
2235
2662
|
}
|
|
2236
2663
|
const attach = result.duplicate ? { ...result.duplicate, kind: "duplicate" } : result.related ? { ...result.related, kind: "related" } : null;
|
|
2237
2664
|
setDuplicate(attach);
|
|
2238
|
-
onDuplicateChange == null ? void 0 : onDuplicateChange((
|
|
2665
|
+
onDuplicateChange == null ? void 0 : onDuplicateChange((_a2 = attach == null ? void 0 : attach.number) != null ? _a2 : null, attach == null ? void 0 : attach.kind);
|
|
2239
2666
|
setGlitchgrabOffer(!!result.aboutGlitchgrab && !!onReportGlitchgrabProblem && !!result.question);
|
|
2240
2667
|
if (result.solved) {
|
|
2241
2668
|
setSolved(result.solved);
|
|
@@ -2289,9 +2716,9 @@ function AssistSheet({
|
|
|
2289
2716
|
}
|
|
2290
2717
|
}
|
|
2291
2718
|
function sendTyped(text) {
|
|
2292
|
-
var
|
|
2719
|
+
var _a2;
|
|
2293
2720
|
const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
|
|
2294
|
-
const checkingBack = options.includes(CONFIRM_OPTION) || (lastAssistant == null ? void 0 : lastAssistant.kind) !== "report" && isCheckBackQuestion((
|
|
2721
|
+
const checkingBack = options.includes(CONFIRM_OPTION) || (lastAssistant == null ? void 0 : lastAssistant.kind) !== "report" && isCheckBackQuestion((_a2 = lastAssistant == null ? void 0 : lastAssistant.content) != null ? _a2 : "");
|
|
2295
2722
|
send(text, checkingBack && isAffirmativeReply(text));
|
|
2296
2723
|
}
|
|
2297
2724
|
function send(text, autoFile = false) {
|
|
@@ -2333,7 +2760,215 @@ function AssistSheet({
|
|
|
2333
2760
|
flushEvents();
|
|
2334
2761
|
onSend();
|
|
2335
2762
|
}
|
|
2763
|
+
(0, import_react3.useEffect)(() => {
|
|
2764
|
+
if (!historyKey || !messages.some((m) => m.role === "user")) return;
|
|
2765
|
+
const done = submitted || phase === "solved";
|
|
2766
|
+
const kept = submitted || phase === "draft" ? withCurrentDraft(messages) : messages;
|
|
2767
|
+
setSavedChats(
|
|
2768
|
+
saveChat(historyKey, {
|
|
2769
|
+
id: chatIdRef.current,
|
|
2770
|
+
conversationId,
|
|
2771
|
+
title: chatTitle(kept),
|
|
2772
|
+
tile: currentTile,
|
|
2773
|
+
messages: kept,
|
|
2774
|
+
...issueTitle ? { issueTitle } : {},
|
|
2775
|
+
status: done ? "filed" : "open",
|
|
2776
|
+
...done ? {
|
|
2777
|
+
filedLabel: submitted ? submittedText != null ? submittedText : `${reportTypeLabel} sent` : "Answered \u2014 nothing was filed"
|
|
2778
|
+
} : {},
|
|
2779
|
+
updatedAt: Date.now()
|
|
2780
|
+
})
|
|
2781
|
+
);
|
|
2782
|
+
}, [
|
|
2783
|
+
historyKey,
|
|
2784
|
+
messages,
|
|
2785
|
+
conversationId,
|
|
2786
|
+
submitted,
|
|
2787
|
+
phase === "solved",
|
|
2788
|
+
issueTitle,
|
|
2789
|
+
phase === "draft" ? description : null
|
|
2790
|
+
]);
|
|
2791
|
+
function resumeChat(chat) {
|
|
2792
|
+
var _a2;
|
|
2793
|
+
flushEvents();
|
|
2794
|
+
chatIdRef.current = chat.id;
|
|
2795
|
+
setMessages(chat.messages);
|
|
2796
|
+
setConversationId(chat.conversationId);
|
|
2797
|
+
onConversationChange == null ? void 0 : onConversationChange(chat.conversationId);
|
|
2798
|
+
setOptions([]);
|
|
2799
|
+
setDuplicate(null);
|
|
2800
|
+
onDuplicateChange == null ? void 0 : onDuplicateChange(null);
|
|
2801
|
+
setGlitchgrabOffer(false);
|
|
2802
|
+
setAutoFileLeft(null);
|
|
2803
|
+
setInput("");
|
|
2804
|
+
if (chat.tile !== currentTile && tiles.includes(chat.tile)) {
|
|
2805
|
+
onPickType(chat.tile);
|
|
2806
|
+
}
|
|
2807
|
+
const last = chat.messages[chat.messages.length - 1];
|
|
2808
|
+
if ((last == null ? void 0 : last.kind) === "report") {
|
|
2809
|
+
onDescriptionChange(last.content);
|
|
2810
|
+
onIssueTitleChange((_a2 = chat.issueTitle) != null ? _a2 : "");
|
|
2811
|
+
aiDraftRef.current = last.content;
|
|
2812
|
+
setPhase("draft");
|
|
2813
|
+
} else {
|
|
2814
|
+
setPhase("chat");
|
|
2815
|
+
}
|
|
2816
|
+
setShowChats(false);
|
|
2817
|
+
setViewingChat(null);
|
|
2818
|
+
}
|
|
2819
|
+
function startNewChat() {
|
|
2820
|
+
flushEvents();
|
|
2821
|
+
chatIdRef.current = newChatId();
|
|
2822
|
+
setMessages([]);
|
|
2823
|
+
setConversationId(null);
|
|
2824
|
+
onConversationChange == null ? void 0 : onConversationChange(null);
|
|
2825
|
+
setOptions([]);
|
|
2826
|
+
setDuplicate(null);
|
|
2827
|
+
onDuplicateChange == null ? void 0 : onDuplicateChange(null);
|
|
2828
|
+
setGlitchgrabOffer(false);
|
|
2829
|
+
setAutoFileLeft(null);
|
|
2830
|
+
setInput("");
|
|
2831
|
+
onDescriptionChange("");
|
|
2832
|
+
onIssueTitleChange("");
|
|
2833
|
+
aiDraftRef.current = null;
|
|
2834
|
+
setPhase("chat");
|
|
2835
|
+
setShowChats(false);
|
|
2836
|
+
setViewingChat(null);
|
|
2837
|
+
}
|
|
2838
|
+
function forgetChat(id) {
|
|
2839
|
+
if (!historyKey) return;
|
|
2840
|
+
setSavedChats(removeChat(historyKey, id));
|
|
2841
|
+
if (viewingChat === id) setViewingChat(null);
|
|
2842
|
+
}
|
|
2843
|
+
const otherChats = savedChats.filter((c) => c.id !== chatIdRef.current);
|
|
2844
|
+
const resumable = (_a = otherChats.find((c) => c.status === "open" && c.messages.length > 0)) != null ? _a : null;
|
|
2336
2845
|
const empty = phase === "chat" && messages.length === 0 && !busy;
|
|
2846
|
+
function renderChatList() {
|
|
2847
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { "data-gg-chat-list": "", style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
|
|
2848
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between" }, children: [
|
|
2849
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontSize: "13px", fontWeight: 600 }, children: "Your chats" }),
|
|
2850
|
+
messages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2851
|
+
"button",
|
|
2852
|
+
{
|
|
2853
|
+
type: "button",
|
|
2854
|
+
"data-gg-new-chat": "",
|
|
2855
|
+
onClick: startNewChat,
|
|
2856
|
+
style: {
|
|
2857
|
+
border: `1px solid ${t.inputBorder}`,
|
|
2858
|
+
borderRadius: "999px",
|
|
2859
|
+
background: "transparent",
|
|
2860
|
+
color: t.text,
|
|
2861
|
+
padding: "7px 12px",
|
|
2862
|
+
fontSize: "12px",
|
|
2863
|
+
fontFamily: "inherit",
|
|
2864
|
+
cursor: "pointer"
|
|
2865
|
+
},
|
|
2866
|
+
children: "+ New chat"
|
|
2867
|
+
}
|
|
2868
|
+
)
|
|
2869
|
+
] }),
|
|
2870
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontSize: "11.5px", color: t.textMuted, lineHeight: 1.5 }, children: "Kept in this browser only, for 30 days." }),
|
|
2871
|
+
otherChats.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontSize: "12.5px", color: t.textMuted, padding: "12px 0" }, children: "No other chats yet." }),
|
|
2872
|
+
otherChats.map((chat) => {
|
|
2873
|
+
var _a2;
|
|
2874
|
+
const filed = chat.status === "filed";
|
|
2875
|
+
const open = viewingChat === chat.id;
|
|
2876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2877
|
+
"div",
|
|
2878
|
+
{
|
|
2879
|
+
"data-gg-saved-chat": chat.status,
|
|
2880
|
+
style: {
|
|
2881
|
+
border: `1px solid ${t.border}`,
|
|
2882
|
+
borderRadius: "10px",
|
|
2883
|
+
padding: "10px 12px",
|
|
2884
|
+
display: "flex",
|
|
2885
|
+
flexDirection: "column",
|
|
2886
|
+
gap: "6px",
|
|
2887
|
+
minWidth: 0
|
|
2888
|
+
},
|
|
2889
|
+
children: [
|
|
2890
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px", alignItems: "flex-start", minWidth: 0 }, children: [
|
|
2891
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2892
|
+
"button",
|
|
2893
|
+
{
|
|
2894
|
+
type: "button",
|
|
2895
|
+
onClick: () => filed ? setViewingChat(open ? null : chat.id) : resumeChat(chat),
|
|
2896
|
+
style: {
|
|
2897
|
+
flex: 1,
|
|
2898
|
+
minWidth: 0,
|
|
2899
|
+
textAlign: "left",
|
|
2900
|
+
border: "none",
|
|
2901
|
+
background: "transparent",
|
|
2902
|
+
color: t.text,
|
|
2903
|
+
padding: 0,
|
|
2904
|
+
fontFamily: "inherit",
|
|
2905
|
+
cursor: "pointer",
|
|
2906
|
+
display: "flex",
|
|
2907
|
+
flexDirection: "column",
|
|
2908
|
+
gap: "4px"
|
|
2909
|
+
},
|
|
2910
|
+
children: [
|
|
2911
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontSize: "13px", lineHeight: 1.45, overflowWrap: "anywhere" }, children: chat.title || "Untitled chat" }),
|
|
2912
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: { fontSize: "11.5px", color: t.textMuted }, children: [
|
|
2913
|
+
filed ? (_a2 = chat.filedLabel) != null ? _a2 : "Sent" : "Not sent yet \u2014 tap to continue",
|
|
2914
|
+
" \xB7",
|
|
2915
|
+
" ",
|
|
2916
|
+
chatAge(chat.updatedAt)
|
|
2917
|
+
] })
|
|
2918
|
+
]
|
|
2919
|
+
}
|
|
2920
|
+
),
|
|
2921
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2922
|
+
"button",
|
|
2923
|
+
{
|
|
2924
|
+
type: "button",
|
|
2925
|
+
"aria-label": `Delete chat: ${chat.title}`,
|
|
2926
|
+
onClick: () => forgetChat(chat.id),
|
|
2927
|
+
style: {
|
|
2928
|
+
flexShrink: 0,
|
|
2929
|
+
border: "none",
|
|
2930
|
+
background: "transparent",
|
|
2931
|
+
color: t.textMuted,
|
|
2932
|
+
fontSize: "16px",
|
|
2933
|
+
lineHeight: 1,
|
|
2934
|
+
padding: "4px 6px",
|
|
2935
|
+
cursor: "pointer",
|
|
2936
|
+
fontFamily: "inherit"
|
|
2937
|
+
},
|
|
2938
|
+
children: "\xD7"
|
|
2939
|
+
}
|
|
2940
|
+
)
|
|
2941
|
+
] }),
|
|
2942
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2943
|
+
"div",
|
|
2944
|
+
{
|
|
2945
|
+
"data-gg-saved-transcript": "",
|
|
2946
|
+
style: {
|
|
2947
|
+
display: "flex",
|
|
2948
|
+
flexDirection: "column",
|
|
2949
|
+
gap: "6px",
|
|
2950
|
+
borderTop: `1px solid ${t.border}`,
|
|
2951
|
+
paddingTop: "8px",
|
|
2952
|
+
fontSize: "12.5px",
|
|
2953
|
+
lineHeight: 1.5
|
|
2954
|
+
},
|
|
2955
|
+
children: chat.messages.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { minWidth: 0, overflowWrap: "anywhere" }, children: [
|
|
2956
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: { color: t.textMuted, fontWeight: 600 }, children: [
|
|
2957
|
+
m.role === "user" ? "You" : m.kind === "report" ? "Report" : "Assistant",
|
|
2958
|
+
":",
|
|
2959
|
+
" "
|
|
2960
|
+
] }),
|
|
2961
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { whiteSpace: "pre-wrap" }, children: m.content })
|
|
2962
|
+
] }, i))
|
|
2963
|
+
}
|
|
2964
|
+
)
|
|
2965
|
+
]
|
|
2966
|
+
},
|
|
2967
|
+
chat.id
|
|
2968
|
+
);
|
|
2969
|
+
})
|
|
2970
|
+
] });
|
|
2971
|
+
}
|
|
2337
2972
|
function renderKnownIssue({ title, footer }) {
|
|
2338
2973
|
if (!duplicate) return null;
|
|
2339
2974
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
@@ -2367,8 +3002,8 @@ function AssistSheet({
|
|
|
2367
3002
|
);
|
|
2368
3003
|
}
|
|
2369
3004
|
const initials2 = (reporterName != null ? reporterName : "").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => {
|
|
2370
|
-
var
|
|
2371
|
-
return (_b = (
|
|
3005
|
+
var _a2, _b;
|
|
3006
|
+
return (_b = (_a2 = w[0]) == null ? void 0 : _a2.toUpperCase()) != null ? _b : "";
|
|
2372
3007
|
}).join("");
|
|
2373
3008
|
const panelStyle = narrow ? {
|
|
2374
3009
|
width: "100%",
|
|
@@ -2459,7 +3094,9 @@ function AssistSheet({
|
|
|
2459
3094
|
alignItems: "center",
|
|
2460
3095
|
gap: "7px",
|
|
2461
3096
|
fontSize: "14px",
|
|
2462
|
-
fontWeight: 600
|
|
3097
|
+
fontWeight: 600,
|
|
3098
|
+
// One line even with the Chats pill beside it (#567).
|
|
3099
|
+
whiteSpace: "nowrap"
|
|
2463
3100
|
},
|
|
2464
3101
|
children: [
|
|
2465
3102
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Sparkle, { color: t.accent }),
|
|
@@ -2489,34 +3126,64 @@ function AssistSheet({
|
|
|
2489
3126
|
projectSlot ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { marginLeft: "6px" }, children: projectSlot }) : null
|
|
2490
3127
|
] })
|
|
2491
3128
|
] }),
|
|
2492
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
3129
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "6px", flexShrink: 0 }, children: [
|
|
3130
|
+
historyKey && (showChats || otherChats.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3131
|
+
"button",
|
|
3132
|
+
{
|
|
3133
|
+
type: "button",
|
|
3134
|
+
"data-gg-chats-toggle": "",
|
|
3135
|
+
disabled: busy,
|
|
3136
|
+
"aria-pressed": showChats,
|
|
3137
|
+
onClick: () => {
|
|
3138
|
+
setShowChats((v) => !v);
|
|
3139
|
+
setViewingChat(null);
|
|
3140
|
+
},
|
|
3141
|
+
style: {
|
|
3142
|
+
flexShrink: 0,
|
|
3143
|
+
border: `1px solid ${showChats ? t.accent : t.inputBorder}`,
|
|
3144
|
+
borderRadius: "999px",
|
|
3145
|
+
background: "transparent",
|
|
3146
|
+
color: showChats ? t.accent : t.textMuted,
|
|
3147
|
+
cursor: busy ? "default" : "pointer",
|
|
3148
|
+
opacity: busy ? 0.5 : 1,
|
|
3149
|
+
fontSize: "11.5px",
|
|
3150
|
+
lineHeight: 1,
|
|
3151
|
+
fontFamily: "inherit",
|
|
3152
|
+
whiteSpace: "nowrap",
|
|
3153
|
+
padding: "9px 11px"
|
|
3154
|
+
},
|
|
3155
|
+
children: showChats ? "\u2190 Chat" : `Chats \xB7 ${otherChats.length}`
|
|
3156
|
+
}
|
|
3157
|
+
),
|
|
3158
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3159
|
+
"button",
|
|
3160
|
+
{
|
|
3161
|
+
type: "button",
|
|
3162
|
+
"data-gg-write-myself": "",
|
|
3163
|
+
onClick: () => leave("write_myself", `header, ${phase}`),
|
|
3164
|
+
"aria-label": "Write it myself instead",
|
|
3165
|
+
style: {
|
|
3166
|
+
flexShrink: 0,
|
|
3167
|
+
border: `1px solid ${t.inputBorder}`,
|
|
3168
|
+
borderRadius: "999px",
|
|
3169
|
+
background: "transparent",
|
|
3170
|
+
color: t.textMuted,
|
|
3171
|
+
cursor: "pointer",
|
|
3172
|
+
fontSize: "11.5px",
|
|
3173
|
+
lineHeight: 1,
|
|
3174
|
+
fontFamily: "inherit",
|
|
3175
|
+
whiteSpace: "nowrap",
|
|
3176
|
+
// ~32px tall either way — this is the escape hatch, not a hint.
|
|
3177
|
+
padding: "9px 11px"
|
|
3178
|
+
},
|
|
3179
|
+
children: "Write it myself"
|
|
3180
|
+
}
|
|
3181
|
+
)
|
|
3182
|
+
] })
|
|
2516
3183
|
]
|
|
2517
3184
|
}
|
|
2518
3185
|
),
|
|
2519
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
3186
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2520
3187
|
"div",
|
|
2521
3188
|
{
|
|
2522
3189
|
ref: scrollRef,
|
|
@@ -2528,762 +3195,845 @@ function AssistSheet({
|
|
|
2528
3195
|
display: "flex",
|
|
2529
3196
|
flexDirection: "column"
|
|
2530
3197
|
},
|
|
2531
|
-
children:
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3198
|
+
children: [
|
|
3199
|
+
showChats && renderChatList(),
|
|
3200
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3201
|
+
"div",
|
|
3202
|
+
{
|
|
3203
|
+
style: {
|
|
3204
|
+
marginTop: "auto",
|
|
3205
|
+
display: "flex",
|
|
3206
|
+
flexDirection: "column",
|
|
3207
|
+
gap: "12px",
|
|
3208
|
+
minWidth: 0
|
|
3209
|
+
},
|
|
3210
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: showChats ? "none" : "contents" }, children: [
|
|
3211
|
+
phase === "type" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
3212
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
3213
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
3214
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3215
|
+
"div",
|
|
3216
|
+
{
|
|
3217
|
+
style: {
|
|
3218
|
+
padding: "9px 12px",
|
|
3219
|
+
borderRadius: "12px 12px 12px 4px",
|
|
3220
|
+
backgroundColor: t.bgSecondary,
|
|
3221
|
+
fontSize: "13px",
|
|
3222
|
+
lineHeight: 1.55,
|
|
3223
|
+
maxWidth: "88%"
|
|
3224
|
+
},
|
|
3225
|
+
children: [
|
|
3226
|
+
reporterName ? `Hi ${reporterName.split(" ")[0]} \u2014 w` : "W",
|
|
3227
|
+
"hat do you want to do? Pick one and I'll take it from there."
|
|
3228
|
+
]
|
|
3229
|
+
}
|
|
3230
|
+
)
|
|
3231
|
+
] }),
|
|
3232
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2546
3233
|
"div",
|
|
2547
3234
|
{
|
|
2548
3235
|
style: {
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
lineHeight: 1.55,
|
|
2554
|
-
maxWidth: "88%"
|
|
3236
|
+
display: "flex",
|
|
3237
|
+
flexWrap: "wrap",
|
|
3238
|
+
gap: "6px",
|
|
3239
|
+
paddingLeft: "32px"
|
|
2555
3240
|
},
|
|
2556
|
-
children:
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
3241
|
+
children: tiles.map((tile) => {
|
|
3242
|
+
const rate = tile === "RATING";
|
|
3243
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3244
|
+
"button",
|
|
3245
|
+
{
|
|
3246
|
+
type: "button",
|
|
3247
|
+
"data-gg-chip": "",
|
|
3248
|
+
"data-gg-tile": tile,
|
|
3249
|
+
onClick: () => pickType(tile),
|
|
3250
|
+
style: {
|
|
3251
|
+
display: "inline-flex",
|
|
3252
|
+
alignItems: "center",
|
|
3253
|
+
gap: "5px",
|
|
3254
|
+
// The rating is the only tile that isn't a report, so
|
|
3255
|
+
// it wears the star colour the dialog's hero row uses
|
|
3256
|
+
// rather than hiding among the report types.
|
|
3257
|
+
border: `1px solid ${rate ? "rgba(245,158,11,0.5)" : t.inputBorder}`,
|
|
3258
|
+
background: rate ? "rgba(245,158,11,0.08)" : "transparent",
|
|
3259
|
+
color: rate ? "#f59e0b" : t.textMuted,
|
|
3260
|
+
borderRadius: "999px",
|
|
3261
|
+
// 8px vertical keeps the tap target at ~32px.
|
|
3262
|
+
padding: "8px 12px",
|
|
3263
|
+
fontSize: "12px",
|
|
3264
|
+
fontWeight: rate ? 600 : 400,
|
|
3265
|
+
fontFamily: "inherit",
|
|
3266
|
+
cursor: "pointer"
|
|
3267
|
+
},
|
|
3268
|
+
children: rate ? "\u2605 Rate us" : getTypeLabel(tile)
|
|
3269
|
+
},
|
|
3270
|
+
tile
|
|
3271
|
+
);
|
|
3272
|
+
})
|
|
2560
3273
|
}
|
|
2561
3274
|
)
|
|
2562
3275
|
] }),
|
|
2563
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
2564
|
-
"div",
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
3276
|
+
phase === "severity" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
3277
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
3278
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
3279
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3280
|
+
"div",
|
|
3281
|
+
{
|
|
3282
|
+
style: {
|
|
3283
|
+
padding: "9px 12px",
|
|
3284
|
+
borderRadius: "12px 12px 12px 4px",
|
|
3285
|
+
backgroundColor: t.bgSecondary,
|
|
3286
|
+
fontSize: "13px",
|
|
3287
|
+
lineHeight: 1.55,
|
|
3288
|
+
maxWidth: "88%"
|
|
3289
|
+
},
|
|
3290
|
+
children: "How bad is it?"
|
|
3291
|
+
}
|
|
3292
|
+
)
|
|
3293
|
+
] }),
|
|
3294
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3295
|
+
"div",
|
|
3296
|
+
{
|
|
3297
|
+
role: "radiogroup",
|
|
3298
|
+
"aria-label": "Severity",
|
|
3299
|
+
style: {
|
|
3300
|
+
display: "flex",
|
|
3301
|
+
flexWrap: "wrap",
|
|
3302
|
+
gap: "6px",
|
|
3303
|
+
paddingLeft: "32px"
|
|
3304
|
+
},
|
|
3305
|
+
children: SEVERITY_LEVELS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2575
3306
|
"button",
|
|
2576
3307
|
{
|
|
2577
3308
|
type: "button",
|
|
3309
|
+
role: "radio",
|
|
3310
|
+
"aria-checked": severity === s,
|
|
2578
3311
|
"data-gg-chip": "",
|
|
2579
|
-
"data-gg-
|
|
2580
|
-
onClick: () =>
|
|
3312
|
+
"data-gg-severity": s,
|
|
3313
|
+
onClick: () => answerSeverity(s),
|
|
2581
3314
|
style: {
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
// The rating is the only tile that isn't a report, so
|
|
2586
|
-
// it wears the star colour the dialog's hero row uses
|
|
2587
|
-
// rather than hiding among the report types.
|
|
2588
|
-
border: `1px solid ${rate ? "rgba(245,158,11,0.5)" : t.inputBorder}`,
|
|
2589
|
-
background: rate ? "rgba(245,158,11,0.08)" : "transparent",
|
|
2590
|
-
color: rate ? "#f59e0b" : t.textMuted,
|
|
3315
|
+
border: `1px solid ${t.inputBorder}`,
|
|
3316
|
+
background: "transparent",
|
|
3317
|
+
color: t.textMuted,
|
|
2591
3318
|
borderRadius: "999px",
|
|
2592
|
-
//
|
|
3319
|
+
// Same as the picker and option chips — one chip size.
|
|
2593
3320
|
padding: "8px 12px",
|
|
2594
3321
|
fontSize: "12px",
|
|
2595
|
-
fontWeight: rate ? 600 : 400,
|
|
2596
3322
|
fontFamily: "inherit",
|
|
2597
3323
|
cursor: "pointer"
|
|
2598
3324
|
},
|
|
2599
|
-
children:
|
|
3325
|
+
children: SEVERITY_LABELS[s]
|
|
2600
3326
|
},
|
|
2601
|
-
|
|
2602
|
-
)
|
|
2603
|
-
})
|
|
2604
|
-
}
|
|
2605
|
-
)
|
|
2606
|
-
] }),
|
|
2607
|
-
phase === "severity" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
2608
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
2609
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
2610
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2611
|
-
"div",
|
|
2612
|
-
{
|
|
2613
|
-
style: {
|
|
2614
|
-
padding: "9px 12px",
|
|
2615
|
-
borderRadius: "12px 12px 12px 4px",
|
|
2616
|
-
backgroundColor: t.bgSecondary,
|
|
2617
|
-
fontSize: "13px",
|
|
2618
|
-
lineHeight: 1.55,
|
|
2619
|
-
maxWidth: "88%"
|
|
2620
|
-
},
|
|
2621
|
-
children: "How bad is it?"
|
|
3327
|
+
s
|
|
3328
|
+
))
|
|
2622
3329
|
}
|
|
2623
3330
|
)
|
|
2624
3331
|
] }),
|
|
2625
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
2626
|
-
"div",
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
style: {
|
|
2631
|
-
display: "flex",
|
|
2632
|
-
flexWrap: "wrap",
|
|
2633
|
-
gap: "6px",
|
|
2634
|
-
paddingLeft: "32px"
|
|
2635
|
-
},
|
|
2636
|
-
children: SEVERITY_LEVELS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2637
|
-
"button",
|
|
3332
|
+
phase === "rating" && !submitted && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
3333
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
3334
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
3335
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3336
|
+
"div",
|
|
2638
3337
|
{
|
|
2639
|
-
type: "button",
|
|
2640
|
-
role: "radio",
|
|
2641
|
-
"aria-checked": severity === s,
|
|
2642
|
-
"data-gg-chip": "",
|
|
2643
|
-
"data-gg-severity": s,
|
|
2644
|
-
onClick: () => answerSeverity(s),
|
|
2645
3338
|
style: {
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
fontSize: "12px",
|
|
2653
|
-
fontFamily: "inherit",
|
|
2654
|
-
cursor: "pointer"
|
|
3339
|
+
padding: "9px 12px",
|
|
3340
|
+
borderRadius: "12px 12px 12px 4px",
|
|
3341
|
+
backgroundColor: t.bgSecondary,
|
|
3342
|
+
fontSize: "13px",
|
|
3343
|
+
lineHeight: 1.55,
|
|
3344
|
+
maxWidth: "88%"
|
|
2655
3345
|
},
|
|
2656
|
-
children:
|
|
2657
|
-
}
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
)
|
|
2662
|
-
] }),
|
|
2663
|
-
phase === "rating" && !submitted && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
2664
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
2665
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
2666
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3346
|
+
children: "How are we doing? Tap a star \u2014 the words are optional."
|
|
3347
|
+
}
|
|
3348
|
+
)
|
|
3349
|
+
] }),
|
|
3350
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2667
3351
|
"div",
|
|
2668
3352
|
{
|
|
2669
3353
|
style: {
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
3354
|
+
display: "flex",
|
|
3355
|
+
flexDirection: "column",
|
|
3356
|
+
gap: "10px",
|
|
3357
|
+
marginLeft: "32px",
|
|
3358
|
+
padding: "12px",
|
|
3359
|
+
borderRadius: "12px",
|
|
3360
|
+
border: "1px solid rgba(245,158,11,0.4)",
|
|
3361
|
+
backgroundColor: "rgba(245,158,11,0.06)"
|
|
2676
3362
|
},
|
|
2677
|
-
children:
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
3363
|
+
children: [
|
|
3364
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { display: "flex", gap: "4px" }, role: "group", "aria-label": "Rating", children: [1, 2, 3, 4, 5].map((star) => {
|
|
3365
|
+
const filled = star <= (hoveredStar || rating);
|
|
3366
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3367
|
+
"button",
|
|
3368
|
+
{
|
|
3369
|
+
type: "button",
|
|
3370
|
+
"aria-label": `${star} star${star > 1 ? "s" : ""}`,
|
|
3371
|
+
"aria-pressed": star <= rating,
|
|
3372
|
+
onClick: () => onRatingChange(star),
|
|
3373
|
+
onMouseEnter: () => setHoveredStar(star),
|
|
3374
|
+
onMouseLeave: () => setHoveredStar(0),
|
|
3375
|
+
style: {
|
|
3376
|
+
border: "none",
|
|
3377
|
+
background: "transparent",
|
|
3378
|
+
padding: 0,
|
|
3379
|
+
cursor: "pointer",
|
|
3380
|
+
lineHeight: 0
|
|
3381
|
+
},
|
|
3382
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("svg", { width: "30", height: "30", viewBox: "0 0 24 24", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3383
|
+
"path",
|
|
3384
|
+
{
|
|
3385
|
+
d: "M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z",
|
|
3386
|
+
fill: filled ? "#f59e0b" : "transparent",
|
|
3387
|
+
stroke: filled ? "#f59e0b" : t.inputBorder,
|
|
3388
|
+
strokeWidth: "1.5",
|
|
3389
|
+
strokeLinejoin: "round"
|
|
3390
|
+
}
|
|
3391
|
+
) })
|
|
3392
|
+
},
|
|
3393
|
+
star
|
|
3394
|
+
);
|
|
3395
|
+
}) }),
|
|
3396
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3397
|
+
"textarea",
|
|
3398
|
+
{
|
|
3399
|
+
value: description,
|
|
3400
|
+
onChange: (e) => onDescriptionChange(e.target.value),
|
|
3401
|
+
rows: 3,
|
|
3402
|
+
placeholder: "What made it good \u2014 or what let you down? (optional)",
|
|
3403
|
+
style: {
|
|
3404
|
+
width: "100%",
|
|
3405
|
+
padding: "10px",
|
|
3406
|
+
borderRadius: "8px",
|
|
3407
|
+
border: `1px solid ${t.inputBorder}`,
|
|
3408
|
+
backgroundColor: t.inputBg,
|
|
3409
|
+
color: t.text,
|
|
3410
|
+
fontSize: "13px",
|
|
3411
|
+
lineHeight: 1.5,
|
|
3412
|
+
fontFamily: "inherit",
|
|
3413
|
+
resize: "vertical",
|
|
3414
|
+
outline: "none",
|
|
3415
|
+
boxSizing: "border-box"
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
),
|
|
3419
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2698
3420
|
"button",
|
|
2699
3421
|
{
|
|
2700
3422
|
type: "button",
|
|
2701
|
-
|
|
2702
|
-
"aria-pressed": star <= rating,
|
|
2703
|
-
onClick: () => onRatingChange(star),
|
|
2704
|
-
onMouseEnter: () => setHoveredStar(star),
|
|
2705
|
-
onMouseLeave: () => setHoveredStar(0),
|
|
3423
|
+
onClick: () => setPhase("type"),
|
|
2706
3424
|
style: {
|
|
3425
|
+
alignSelf: "flex-start",
|
|
2707
3426
|
border: "none",
|
|
2708
3427
|
background: "transparent",
|
|
2709
|
-
|
|
3428
|
+
color: t.textMuted,
|
|
3429
|
+
fontSize: "12px",
|
|
3430
|
+
fontFamily: "inherit",
|
|
3431
|
+
// A bare text link is ~14px tall — half a thumb.
|
|
3432
|
+
padding: "9px 0",
|
|
2710
3433
|
cursor: "pointer",
|
|
2711
|
-
|
|
3434
|
+
textDecoration: "underline"
|
|
2712
3435
|
},
|
|
2713
|
-
children:
|
|
2714
|
-
"path",
|
|
2715
|
-
{
|
|
2716
|
-
d: "M12 3l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.4 6.8 19.1l1-5.8L3.5 9.2l5.9-.9L12 3z",
|
|
2717
|
-
fill: filled ? "#f59e0b" : "transparent",
|
|
2718
|
-
stroke: filled ? "#f59e0b" : t.inputBorder,
|
|
2719
|
-
strokeWidth: "1.5",
|
|
2720
|
-
strokeLinejoin: "round"
|
|
2721
|
-
}
|
|
2722
|
-
) })
|
|
2723
|
-
},
|
|
2724
|
-
star
|
|
2725
|
-
);
|
|
2726
|
-
}) }),
|
|
2727
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2728
|
-
"textarea",
|
|
2729
|
-
{
|
|
2730
|
-
value: description,
|
|
2731
|
-
onChange: (e) => onDescriptionChange(e.target.value),
|
|
2732
|
-
rows: 3,
|
|
2733
|
-
placeholder: "What made it good \u2014 or what let you down? (optional)",
|
|
2734
|
-
style: {
|
|
2735
|
-
width: "100%",
|
|
2736
|
-
padding: "10px",
|
|
2737
|
-
borderRadius: "8px",
|
|
2738
|
-
border: `1px solid ${t.inputBorder}`,
|
|
2739
|
-
backgroundColor: t.inputBg,
|
|
2740
|
-
color: t.text,
|
|
2741
|
-
fontSize: "13px",
|
|
2742
|
-
lineHeight: 1.5,
|
|
2743
|
-
fontFamily: "inherit",
|
|
2744
|
-
resize: "vertical",
|
|
2745
|
-
outline: "none",
|
|
2746
|
-
boxSizing: "border-box"
|
|
3436
|
+
children: "Report something instead"
|
|
2747
3437
|
}
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
3438
|
+
)
|
|
3439
|
+
]
|
|
3440
|
+
}
|
|
3441
|
+
)
|
|
3442
|
+
] }),
|
|
3443
|
+
empty && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
3444
|
+
resumable && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3445
|
+
"div",
|
|
3446
|
+
{
|
|
3447
|
+
"data-gg-resume-chat": "",
|
|
3448
|
+
style: {
|
|
3449
|
+
display: "flex",
|
|
3450
|
+
flexDirection: "column",
|
|
3451
|
+
gap: "8px",
|
|
3452
|
+
padding: "10px 12px",
|
|
3453
|
+
borderRadius: "10px",
|
|
3454
|
+
border: `1px solid ${t.accent}55`,
|
|
3455
|
+
backgroundColor: t.bgSecondary,
|
|
3456
|
+
minWidth: 0
|
|
3457
|
+
},
|
|
3458
|
+
children: [
|
|
3459
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: { fontSize: "11.5px", color: t.textMuted }, children: [
|
|
3460
|
+
"Pick up where you left off \xB7 ",
|
|
3461
|
+
chatAge(resumable.updatedAt)
|
|
3462
|
+
] }),
|
|
3463
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3464
|
+
"span",
|
|
3465
|
+
{
|
|
3466
|
+
style: {
|
|
3467
|
+
fontSize: "13px",
|
|
3468
|
+
lineHeight: 1.45,
|
|
3469
|
+
overflowWrap: "anywhere"
|
|
3470
|
+
},
|
|
3471
|
+
children: resumable.title
|
|
3472
|
+
}
|
|
3473
|
+
),
|
|
3474
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px", flexWrap: "wrap" }, children: [
|
|
3475
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3476
|
+
"button",
|
|
3477
|
+
{
|
|
3478
|
+
type: "button",
|
|
3479
|
+
"data-gg-resume-continue": "",
|
|
3480
|
+
onClick: () => resumeChat(resumable),
|
|
3481
|
+
style: {
|
|
3482
|
+
border: "none",
|
|
3483
|
+
borderRadius: "999px",
|
|
3484
|
+
backgroundColor: t.accent,
|
|
3485
|
+
color: t.accentText,
|
|
3486
|
+
padding: "7px 13px",
|
|
3487
|
+
fontSize: "12px",
|
|
3488
|
+
fontWeight: 600,
|
|
3489
|
+
fontFamily: "inherit",
|
|
3490
|
+
cursor: "pointer"
|
|
3491
|
+
},
|
|
3492
|
+
children: "Continue this chat"
|
|
3493
|
+
}
|
|
3494
|
+
),
|
|
3495
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3496
|
+
"button",
|
|
3497
|
+
{
|
|
3498
|
+
type: "button",
|
|
3499
|
+
onClick: () => setShowChats(true),
|
|
3500
|
+
style: {
|
|
3501
|
+
border: `1px solid ${t.inputBorder}`,
|
|
3502
|
+
borderRadius: "999px",
|
|
3503
|
+
background: "transparent",
|
|
3504
|
+
color: t.textMuted,
|
|
3505
|
+
padding: "7px 13px",
|
|
3506
|
+
fontSize: "12px",
|
|
3507
|
+
fontFamily: "inherit",
|
|
3508
|
+
cursor: "pointer"
|
|
3509
|
+
},
|
|
3510
|
+
children: "All chats"
|
|
3511
|
+
}
|
|
3512
|
+
)
|
|
3513
|
+
] })
|
|
3514
|
+
]
|
|
3515
|
+
}
|
|
3516
|
+
),
|
|
3517
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
3518
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
3519
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3520
|
+
"div",
|
|
3521
|
+
{
|
|
3522
|
+
style: {
|
|
3523
|
+
padding: "9px 12px",
|
|
3524
|
+
borderRadius: "12px 12px 12px 4px",
|
|
3525
|
+
backgroundColor: t.bgSecondary,
|
|
3526
|
+
fontSize: "13px",
|
|
3527
|
+
lineHeight: 1.55,
|
|
3528
|
+
maxWidth: "88%"
|
|
3529
|
+
},
|
|
3530
|
+
children: [
|
|
3531
|
+
reporterName ? `Hi ${reporterName.split(" ")[0]} \u2014 t` : "T",
|
|
3532
|
+
"ell me what went wrong in your own words. I can already see your screenshot and what you clicked, so skip the boring parts."
|
|
3533
|
+
]
|
|
3534
|
+
}
|
|
3535
|
+
)
|
|
3536
|
+
] }),
|
|
3537
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3538
|
+
"div",
|
|
3539
|
+
{
|
|
3540
|
+
style: {
|
|
3541
|
+
display: "flex",
|
|
3542
|
+
flexWrap: "wrap",
|
|
3543
|
+
gap: "6px",
|
|
3544
|
+
paddingLeft: "32px"
|
|
3545
|
+
},
|
|
3546
|
+
children: STARTERS.map((s) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2751
3547
|
"button",
|
|
2752
3548
|
{
|
|
2753
3549
|
type: "button",
|
|
2754
|
-
|
|
3550
|
+
"data-gg-chip": "",
|
|
3551
|
+
onClick: () => {
|
|
3552
|
+
logEvent("starter_tap", s);
|
|
3553
|
+
send(s);
|
|
3554
|
+
},
|
|
2755
3555
|
style: {
|
|
2756
|
-
|
|
2757
|
-
border: "none",
|
|
3556
|
+
border: `1px solid ${t.inputBorder}`,
|
|
2758
3557
|
background: "transparent",
|
|
2759
3558
|
color: t.textMuted,
|
|
3559
|
+
borderRadius: "999px",
|
|
3560
|
+
padding: "6px 11px",
|
|
2760
3561
|
fontSize: "12px",
|
|
2761
3562
|
fontFamily: "inherit",
|
|
2762
|
-
|
|
2763
|
-
padding: "9px 0",
|
|
2764
|
-
cursor: "pointer",
|
|
2765
|
-
textDecoration: "underline"
|
|
3563
|
+
cursor: "pointer"
|
|
2766
3564
|
},
|
|
2767
|
-
children:
|
|
3565
|
+
children: s
|
|
3566
|
+
},
|
|
3567
|
+
s
|
|
3568
|
+
))
|
|
3569
|
+
}
|
|
3570
|
+
)
|
|
3571
|
+
] }),
|
|
3572
|
+
messages.map((m, i) => {
|
|
3573
|
+
const mine = m.role === "user";
|
|
3574
|
+
if (m.kind === "report") {
|
|
3575
|
+
const live = phase === "draft" && i === messages.length - 1;
|
|
3576
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px", minWidth: 0 }, children: [
|
|
3577
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
3578
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3579
|
+
"div",
|
|
3580
|
+
{
|
|
3581
|
+
"data-gg-draft-bubble": "",
|
|
3582
|
+
style: {
|
|
3583
|
+
maxWidth: "82%",
|
|
3584
|
+
minWidth: 0,
|
|
3585
|
+
padding: "9px 12px",
|
|
3586
|
+
borderRadius: "12px 12px 12px 4px",
|
|
3587
|
+
fontSize: "13px",
|
|
3588
|
+
lineHeight: 1.55,
|
|
3589
|
+
backgroundColor: t.bgSecondary,
|
|
3590
|
+
color: t.text,
|
|
3591
|
+
border: live ? "none" : `1px solid ${t.accent}66`
|
|
3592
|
+
},
|
|
3593
|
+
children: live ? (
|
|
3594
|
+
// #402: "have a read" beside a countdown reads as a
|
|
3595
|
+
// contradiction. Say what is about to happen instead.
|
|
3596
|
+
autoFileLeft !== null ? "Here's your report \u2014 I'll file it unless you want to change something." : "Here's your report \u2014 have a read."
|
|
3597
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
3598
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3599
|
+
"span",
|
|
3600
|
+
{
|
|
3601
|
+
style: {
|
|
3602
|
+
display: "block",
|
|
3603
|
+
fontSize: "10px",
|
|
3604
|
+
fontWeight: 700,
|
|
3605
|
+
letterSpacing: ".06em",
|
|
3606
|
+
textTransform: "uppercase",
|
|
3607
|
+
color: t.accent,
|
|
3608
|
+
marginBottom: "4px"
|
|
3609
|
+
},
|
|
3610
|
+
children: "Draft so far"
|
|
3611
|
+
}
|
|
3612
|
+
),
|
|
3613
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3614
|
+
"span",
|
|
3615
|
+
{
|
|
3616
|
+
style: {
|
|
3617
|
+
display: "block",
|
|
3618
|
+
whiteSpace: "pre-wrap",
|
|
3619
|
+
wordBreak: "break-word",
|
|
3620
|
+
maxHeight: "160px",
|
|
3621
|
+
overflowY: "auto",
|
|
3622
|
+
color: t.textMuted
|
|
3623
|
+
},
|
|
3624
|
+
children: m.content
|
|
3625
|
+
}
|
|
3626
|
+
)
|
|
3627
|
+
] })
|
|
2768
3628
|
}
|
|
2769
3629
|
)
|
|
2770
|
-
]
|
|
3630
|
+
] }, i);
|
|
2771
3631
|
}
|
|
2772
|
-
|
|
2773
|
-
] }),
|
|
2774
|
-
empty && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
2775
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
2776
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
2777
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2778
3633
|
"div",
|
|
2779
3634
|
{
|
|
2780
3635
|
style: {
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
lineHeight: 1.55,
|
|
2786
|
-
maxWidth: "88%"
|
|
3636
|
+
display: "flex",
|
|
3637
|
+
gap: "8px",
|
|
3638
|
+
minWidth: 0,
|
|
3639
|
+
flexDirection: mine ? "row-reverse" : "row"
|
|
2787
3640
|
},
|
|
2788
3641
|
children: [
|
|
2789
|
-
|
|
2790
|
-
|
|
3642
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: m.role, theme: t, initials: initials2 }),
|
|
3643
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3644
|
+
"div",
|
|
3645
|
+
{
|
|
3646
|
+
style: {
|
|
3647
|
+
maxWidth: "82%",
|
|
3648
|
+
minWidth: 0,
|
|
3649
|
+
padding: "9px 12px",
|
|
3650
|
+
borderRadius: mine ? "12px 12px 4px 12px" : "12px 12px 12px 4px",
|
|
3651
|
+
fontSize: "13px",
|
|
3652
|
+
lineHeight: 1.55,
|
|
3653
|
+
// Markdown owns the assistant's line breaks and lists.
|
|
3654
|
+
whiteSpace: mine ? "pre-wrap" : "normal",
|
|
3655
|
+
wordBreak: "break-word",
|
|
3656
|
+
backgroundColor: mine ? t.accent : t.bgSecondary,
|
|
3657
|
+
color: mine ? t.accentText : t.text
|
|
3658
|
+
},
|
|
3659
|
+
children: mine ? m.content : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChatMarkdown, { text: m.content, theme: t })
|
|
3660
|
+
}
|
|
3661
|
+
)
|
|
2791
3662
|
]
|
|
2792
|
-
}
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
3663
|
+
},
|
|
3664
|
+
i
|
|
3665
|
+
);
|
|
3666
|
+
}),
|
|
3667
|
+
duplicate && !busy && phase === "chat" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { paddingLeft: "32px", minWidth: 0 }, children: renderKnownIssue({ title: false }) }),
|
|
3668
|
+
glitchgrabOffer && onReportGlitchgrabProblem && !busy && phase === "chat" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { paddingLeft: "32px", minWidth: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2796
3669
|
"div",
|
|
2797
3670
|
{
|
|
3671
|
+
"data-gg-glitchgrab-offer": "",
|
|
2798
3672
|
style: {
|
|
2799
3673
|
display: "flex",
|
|
3674
|
+
flexDirection: "column",
|
|
3675
|
+
gap: "8px",
|
|
3676
|
+
padding: "10px",
|
|
3677
|
+
borderRadius: "8px",
|
|
3678
|
+
border: `1px solid ${t.accent}55`,
|
|
3679
|
+
backgroundColor: `${t.accent}14`,
|
|
3680
|
+
fontSize: "12px",
|
|
3681
|
+
lineHeight: 1.5
|
|
3682
|
+
},
|
|
3683
|
+
children: [
|
|
3684
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: t.text, fontWeight: 600 }, children: "This is about Glitchgrab, not this app" }),
|
|
3685
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: t.textMuted }, children: "It goes to the team that builds this reporter, with your chat attached." }),
|
|
3686
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: [
|
|
3687
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3688
|
+
"button",
|
|
3689
|
+
{
|
|
3690
|
+
type: "button",
|
|
3691
|
+
"data-gg-glitchgrab-offer-send": "",
|
|
3692
|
+
onClick: () => {
|
|
3693
|
+
logEvent("glitchgrab_offer_tap");
|
|
3694
|
+
setGlitchgrabOffer(false);
|
|
3695
|
+
onReportGlitchgrabProblem(
|
|
3696
|
+
messages.filter((m) => m.role === "user").map((m) => m.content.trim()).filter(Boolean).join("\n\n")
|
|
3697
|
+
);
|
|
3698
|
+
},
|
|
3699
|
+
style: {
|
|
3700
|
+
padding: "8px 12px",
|
|
3701
|
+
borderRadius: "999px",
|
|
3702
|
+
border: "none",
|
|
3703
|
+
backgroundColor: t.accent,
|
|
3704
|
+
color: t.accentText,
|
|
3705
|
+
fontSize: "12px",
|
|
3706
|
+
fontWeight: 700,
|
|
3707
|
+
fontFamily: "inherit",
|
|
3708
|
+
cursor: "pointer",
|
|
3709
|
+
// Both stretch, so on a phone each wrapped line reads as
|
|
3710
|
+
// a choice rather than one button left stranded.
|
|
3711
|
+
flex: "1 1 auto"
|
|
3712
|
+
},
|
|
3713
|
+
children: "Send to the Glitchgrab team"
|
|
3714
|
+
}
|
|
3715
|
+
),
|
|
3716
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3717
|
+
"button",
|
|
3718
|
+
{
|
|
3719
|
+
type: "button",
|
|
3720
|
+
"data-gg-glitchgrab-offer-no": "",
|
|
3721
|
+
onClick: () => {
|
|
3722
|
+
logEvent("glitchgrab_offer_declined");
|
|
3723
|
+
send("No \u2014 it's about this app, not the reporting tool");
|
|
3724
|
+
},
|
|
3725
|
+
style: {
|
|
3726
|
+
padding: "8px 12px",
|
|
3727
|
+
borderRadius: "999px",
|
|
3728
|
+
border: `1px solid ${t.inputBorder}`,
|
|
3729
|
+
background: "transparent",
|
|
3730
|
+
color: t.textMuted,
|
|
3731
|
+
fontSize: "12px",
|
|
3732
|
+
fontFamily: "inherit",
|
|
3733
|
+
cursor: "pointer",
|
|
3734
|
+
flex: "1 1 auto"
|
|
3735
|
+
},
|
|
3736
|
+
children: "No, it's about this app"
|
|
3737
|
+
}
|
|
3738
|
+
)
|
|
3739
|
+
] })
|
|
3740
|
+
]
|
|
3741
|
+
}
|
|
3742
|
+
) }),
|
|
3743
|
+
options.length > 0 && !busy && phase === "chat" && !glitchgrabOffer && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3744
|
+
"div",
|
|
3745
|
+
{
|
|
3746
|
+
style: {
|
|
3747
|
+
display: "flex",
|
|
3748
|
+
// Long labels wrapped into a ragged row that always stranded
|
|
3749
|
+
// the last chip on a line of its own. Past ~24 characters
|
|
3750
|
+
// these stop being chips and become a choice list, so they
|
|
3751
|
+
// stack full width and read like one.
|
|
3752
|
+
flexDirection: options.some((o) => o.length > 24) ? "column" : "row",
|
|
3753
|
+
alignItems: options.some((o) => o.length > 24) ? "stretch" : "flex-start",
|
|
2800
3754
|
flexWrap: "wrap",
|
|
2801
3755
|
gap: "6px",
|
|
2802
3756
|
paddingLeft: "32px"
|
|
2803
3757
|
},
|
|
2804
|
-
children:
|
|
3758
|
+
children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2805
3759
|
"button",
|
|
2806
3760
|
{
|
|
2807
3761
|
type: "button",
|
|
2808
3762
|
"data-gg-chip": "",
|
|
3763
|
+
"data-gg-option": "",
|
|
2809
3764
|
onClick: () => {
|
|
2810
|
-
logEvent("
|
|
2811
|
-
send(
|
|
3765
|
+
logEvent("option_tap", option);
|
|
3766
|
+
send(option, option === CONFIRM_OPTION);
|
|
2812
3767
|
},
|
|
2813
3768
|
style: {
|
|
2814
3769
|
border: `1px solid ${t.inputBorder}`,
|
|
2815
3770
|
background: "transparent",
|
|
2816
3771
|
color: t.textMuted,
|
|
2817
3772
|
borderRadius: "999px",
|
|
2818
|
-
|
|
3773
|
+
// Same 8px as the picker chips — one tap target size in
|
|
3774
|
+
// this sheet, not two.
|
|
3775
|
+
padding: "8px 12px",
|
|
2819
3776
|
fontSize: "12px",
|
|
2820
3777
|
fontFamily: "inherit",
|
|
2821
|
-
cursor: "pointer"
|
|
3778
|
+
cursor: "pointer",
|
|
3779
|
+
textAlign: "left"
|
|
2822
3780
|
},
|
|
2823
|
-
children:
|
|
3781
|
+
children: option
|
|
2824
3782
|
},
|
|
2825
|
-
|
|
3783
|
+
option
|
|
2826
3784
|
))
|
|
2827
3785
|
}
|
|
2828
|
-
)
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
marginBottom: "4px"
|
|
2867
|
-
},
|
|
2868
|
-
children: "Draft so far"
|
|
2869
|
-
}
|
|
2870
|
-
),
|
|
2871
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2872
|
-
"span",
|
|
2873
|
-
{
|
|
2874
|
-
style: {
|
|
2875
|
-
display: "block",
|
|
2876
|
-
whiteSpace: "pre-wrap",
|
|
2877
|
-
wordBreak: "break-word",
|
|
2878
|
-
maxHeight: "160px",
|
|
2879
|
-
overflowY: "auto",
|
|
2880
|
-
color: t.textMuted
|
|
2881
|
-
},
|
|
2882
|
-
children: m.content
|
|
2883
|
-
}
|
|
2884
|
-
)
|
|
2885
|
-
] })
|
|
2886
|
-
}
|
|
2887
|
-
)
|
|
2888
|
-
] }, i);
|
|
2889
|
-
}
|
|
2890
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3786
|
+
),
|
|
3787
|
+
busy && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px", minWidth: 0 }, role: "status", "aria-label": "Thinking", children: [
|
|
3788
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
3789
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3790
|
+
"span",
|
|
3791
|
+
{
|
|
3792
|
+
style: {
|
|
3793
|
+
display: "inline-flex",
|
|
3794
|
+
alignItems: "center",
|
|
3795
|
+
// The "still working" line must wrap on a phone, not push
|
|
3796
|
+
// the bubble past the sheet's edge.
|
|
3797
|
+
flexWrap: "wrap",
|
|
3798
|
+
minWidth: 0,
|
|
3799
|
+
gap: "4px",
|
|
3800
|
+
padding: "12px",
|
|
3801
|
+
borderRadius: "12px 12px 12px 4px",
|
|
3802
|
+
backgroundColor: t.bgSecondary
|
|
3803
|
+
},
|
|
3804
|
+
children: [
|
|
3805
|
+
[0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3806
|
+
"span",
|
|
3807
|
+
{
|
|
3808
|
+
style: {
|
|
3809
|
+
width: "5px",
|
|
3810
|
+
height: "5px",
|
|
3811
|
+
borderRadius: "50%",
|
|
3812
|
+
backgroundColor: t.textMuted,
|
|
3813
|
+
animation: `gg-dot 1.1s ease-in-out ${i * 0.15}s infinite`
|
|
3814
|
+
}
|
|
3815
|
+
},
|
|
3816
|
+
i
|
|
3817
|
+
)),
|
|
3818
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ThinkingClock, { color: t.textMuted })
|
|
3819
|
+
]
|
|
3820
|
+
}
|
|
3821
|
+
)
|
|
3822
|
+
] }),
|
|
3823
|
+
phase === "draft" && !submitted && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2891
3824
|
"div",
|
|
2892
3825
|
{
|
|
2893
3826
|
style: {
|
|
3827
|
+
border: `1px solid ${t.accent}`,
|
|
3828
|
+
borderRadius: "12px",
|
|
3829
|
+
backgroundColor: t.bgSecondary,
|
|
3830
|
+
padding: "12px",
|
|
2894
3831
|
display: "flex",
|
|
2895
|
-
|
|
3832
|
+
flexDirection: "column",
|
|
3833
|
+
gap: "10px",
|
|
2896
3834
|
minWidth: 0,
|
|
2897
|
-
|
|
3835
|
+
boxSizing: "border-box"
|
|
2898
3836
|
},
|
|
2899
3837
|
children: [
|
|
2900
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: m.role, theme: t, initials: initials2 }),
|
|
2901
3838
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2902
|
-
"
|
|
3839
|
+
"span",
|
|
2903
3840
|
{
|
|
2904
3841
|
style: {
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
lineHeight: 1.55,
|
|
2911
|
-
// Markdown owns the assistant's line breaks and lists.
|
|
2912
|
-
whiteSpace: mine ? "pre-wrap" : "normal",
|
|
2913
|
-
wordBreak: "break-word",
|
|
2914
|
-
backgroundColor: mine ? t.accent : t.bgSecondary,
|
|
2915
|
-
color: mine ? t.accentText : t.text
|
|
3842
|
+
fontSize: "10px",
|
|
3843
|
+
fontWeight: 700,
|
|
3844
|
+
letterSpacing: ".06em",
|
|
3845
|
+
textTransform: "uppercase",
|
|
3846
|
+
color: t.accent
|
|
2916
3847
|
},
|
|
2917
|
-
children:
|
|
3848
|
+
children: duplicate ? `What we'll add to #${duplicate.number}${duplicate.kind === "related" ? " as a related request" : ""} \xB7 edit anything` : "Your report \xB7 edit anything"
|
|
2918
3849
|
}
|
|
2919
|
-
)
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
"div",
|
|
2928
|
-
{
|
|
2929
|
-
"data-gg-glitchgrab-offer": "",
|
|
2930
|
-
style: {
|
|
2931
|
-
display: "flex",
|
|
2932
|
-
flexDirection: "column",
|
|
2933
|
-
gap: "8px",
|
|
2934
|
-
padding: "10px",
|
|
2935
|
-
borderRadius: "8px",
|
|
2936
|
-
border: `1px solid ${t.accent}55`,
|
|
2937
|
-
backgroundColor: `${t.accent}14`,
|
|
2938
|
-
fontSize: "12px",
|
|
2939
|
-
lineHeight: 1.5
|
|
2940
|
-
},
|
|
2941
|
-
children: [
|
|
2942
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: t.text, fontWeight: 600 }, children: "This is about Glitchgrab, not this app" }),
|
|
2943
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: t.textMuted }, children: "It goes to the team that builds this reporter, with your chat attached." }),
|
|
2944
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: "6px" }, children: [
|
|
3850
|
+
),
|
|
3851
|
+
renderKnownIssue({
|
|
3852
|
+
title: true,
|
|
3853
|
+
footer: "Your details will be added to it instead of opening a new issue."
|
|
3854
|
+
}),
|
|
3855
|
+
!duplicate && issueTitle && // Wraps rather than scrolls sideways: a title cut off at the
|
|
3856
|
+
// box edge is the very thing #543 is about. One line of text,
|
|
3857
|
+
// so Enter is swallowed.
|
|
2945
3858
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2946
|
-
"
|
|
3859
|
+
"textarea",
|
|
2947
3860
|
{
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
3861
|
+
"aria-label": "Title",
|
|
3862
|
+
value: issueTitle,
|
|
3863
|
+
maxLength: 120,
|
|
3864
|
+
rows: 2,
|
|
3865
|
+
onKeyDown: (e) => {
|
|
3866
|
+
if (e.key === "Enter") e.preventDefault();
|
|
3867
|
+
},
|
|
3868
|
+
onChange: (e) => {
|
|
3869
|
+
stopAutoFile("edited the title");
|
|
3870
|
+
onIssueTitleChange(e.target.value.replace(/[\r\n]+/g, " "));
|
|
2956
3871
|
},
|
|
2957
3872
|
style: {
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
3873
|
+
width: "100%",
|
|
3874
|
+
padding: "8px 10px",
|
|
3875
|
+
lineHeight: 1.45,
|
|
3876
|
+
resize: "none",
|
|
3877
|
+
borderRadius: "8px",
|
|
3878
|
+
border: `1px solid ${t.inputBorder}`,
|
|
3879
|
+
backgroundColor: t.inputBg,
|
|
3880
|
+
color: t.text,
|
|
3881
|
+
fontSize: "13px",
|
|
3882
|
+
fontWeight: 600,
|
|
2965
3883
|
fontFamily: "inherit",
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
flex: "1 1 auto"
|
|
2970
|
-
},
|
|
2971
|
-
children: "Send to the Glitchgrab team"
|
|
3884
|
+
outline: "none",
|
|
3885
|
+
boxSizing: "border-box"
|
|
3886
|
+
}
|
|
2972
3887
|
}
|
|
2973
3888
|
),
|
|
2974
3889
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2975
|
-
"
|
|
3890
|
+
"textarea",
|
|
2976
3891
|
{
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
3892
|
+
ref: draftRef,
|
|
3893
|
+
value: description,
|
|
3894
|
+
onChange: (e) => {
|
|
3895
|
+
stopAutoFile("edited the draft");
|
|
3896
|
+
onDescriptionChange(e.target.value);
|
|
2982
3897
|
},
|
|
3898
|
+
rows: 6,
|
|
2983
3899
|
style: {
|
|
2984
|
-
|
|
2985
|
-
|
|
3900
|
+
width: "100%",
|
|
3901
|
+
minHeight: "120px",
|
|
3902
|
+
padding: "10px",
|
|
3903
|
+
borderRadius: "8px",
|
|
2986
3904
|
border: `1px solid ${t.inputBorder}`,
|
|
2987
|
-
|
|
2988
|
-
color: t.
|
|
2989
|
-
fontSize: "
|
|
3905
|
+
backgroundColor: t.inputBg,
|
|
3906
|
+
color: t.text,
|
|
3907
|
+
fontSize: "13px",
|
|
3908
|
+
lineHeight: 1.55,
|
|
2990
3909
|
fontFamily: "inherit",
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
}
|
|
2996
|
-
)
|
|
2997
|
-
] })
|
|
2998
|
-
]
|
|
2999
|
-
}
|
|
3000
|
-
) }),
|
|
3001
|
-
options.length > 0 && !busy && phase === "chat" && !glitchgrabOffer && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3002
|
-
"div",
|
|
3003
|
-
{
|
|
3004
|
-
style: {
|
|
3005
|
-
display: "flex",
|
|
3006
|
-
// Long labels wrapped into a ragged row that always stranded
|
|
3007
|
-
// the last chip on a line of its own. Past ~24 characters
|
|
3008
|
-
// these stop being chips and become a choice list, so they
|
|
3009
|
-
// stack full width and read like one.
|
|
3010
|
-
flexDirection: options.some((o) => o.length > 24) ? "column" : "row",
|
|
3011
|
-
alignItems: options.some((o) => o.length > 24) ? "stretch" : "flex-start",
|
|
3012
|
-
flexWrap: "wrap",
|
|
3013
|
-
gap: "6px",
|
|
3014
|
-
paddingLeft: "32px"
|
|
3015
|
-
},
|
|
3016
|
-
children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3017
|
-
"button",
|
|
3018
|
-
{
|
|
3019
|
-
type: "button",
|
|
3020
|
-
"data-gg-chip": "",
|
|
3021
|
-
"data-gg-option": "",
|
|
3022
|
-
onClick: () => {
|
|
3023
|
-
logEvent("option_tap", option);
|
|
3024
|
-
send(option, option === CONFIRM_OPTION);
|
|
3025
|
-
},
|
|
3026
|
-
style: {
|
|
3027
|
-
border: `1px solid ${t.inputBorder}`,
|
|
3028
|
-
background: "transparent",
|
|
3029
|
-
color: t.textMuted,
|
|
3030
|
-
borderRadius: "999px",
|
|
3031
|
-
// Same 8px as the picker chips — one tap target size in
|
|
3032
|
-
// this sheet, not two.
|
|
3033
|
-
padding: "8px 12px",
|
|
3034
|
-
fontSize: "12px",
|
|
3035
|
-
fontFamily: "inherit",
|
|
3036
|
-
cursor: "pointer",
|
|
3037
|
-
textAlign: "left"
|
|
3038
|
-
},
|
|
3039
|
-
children: option
|
|
3040
|
-
},
|
|
3041
|
-
option
|
|
3042
|
-
))
|
|
3043
|
-
}
|
|
3044
|
-
),
|
|
3045
|
-
busy && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, role: "status", "aria-label": "Thinking", children: [
|
|
3046
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
3047
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3048
|
-
"span",
|
|
3049
|
-
{
|
|
3050
|
-
style: {
|
|
3051
|
-
display: "inline-flex",
|
|
3052
|
-
alignItems: "center",
|
|
3053
|
-
gap: "4px",
|
|
3054
|
-
padding: "12px",
|
|
3055
|
-
borderRadius: "12px 12px 12px 4px",
|
|
3056
|
-
backgroundColor: t.bgSecondary
|
|
3057
|
-
},
|
|
3058
|
-
children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3059
|
-
"span",
|
|
3060
|
-
{
|
|
3061
|
-
style: {
|
|
3062
|
-
width: "5px",
|
|
3063
|
-
height: "5px",
|
|
3064
|
-
borderRadius: "50%",
|
|
3065
|
-
backgroundColor: t.textMuted,
|
|
3066
|
-
animation: `gg-dot 1.1s ease-in-out ${i * 0.15}s infinite`
|
|
3910
|
+
resize: "vertical",
|
|
3911
|
+
outline: "none",
|
|
3912
|
+
boxSizing: "border-box"
|
|
3913
|
+
}
|
|
3067
3914
|
}
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3915
|
+
),
|
|
3916
|
+
severityAsked && autoFileLeft === null && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
|
|
3917
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3918
|
+
"span",
|
|
3919
|
+
{
|
|
3920
|
+
style: {
|
|
3921
|
+
fontSize: "11.5px",
|
|
3922
|
+
color: t.textMuted,
|
|
3923
|
+
display: "block",
|
|
3924
|
+
marginBottom: "6px"
|
|
3925
|
+
},
|
|
3926
|
+
children: [
|
|
3927
|
+
"How bad is it?",
|
|
3928
|
+
!severity && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3929
|
+
"span",
|
|
3930
|
+
{
|
|
3931
|
+
style: {
|
|
3932
|
+
marginLeft: "6px",
|
|
3933
|
+
fontSize: "11px",
|
|
3934
|
+
color: severityRefused ? "#ef4444" : t.textMuted
|
|
3935
|
+
},
|
|
3936
|
+
children: "\xB7 required"
|
|
3937
|
+
}
|
|
3938
|
+
)
|
|
3939
|
+
]
|
|
3940
|
+
}
|
|
3941
|
+
),
|
|
3942
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3943
|
+
"div",
|
|
3944
|
+
{
|
|
3945
|
+
role: "radiogroup",
|
|
3946
|
+
"aria-label": "Severity",
|
|
3947
|
+
style: { display: "flex", gap: "6px" },
|
|
3948
|
+
children: SEVERITY_LEVELS.map((s) => {
|
|
3949
|
+
const on = severity === s;
|
|
3950
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3951
|
+
"button",
|
|
3952
|
+
{
|
|
3953
|
+
type: "button",
|
|
3954
|
+
onClick: () => onSeverityChange(s),
|
|
3955
|
+
role: "radio",
|
|
3956
|
+
"aria-checked": on,
|
|
3957
|
+
style: {
|
|
3958
|
+
flex: 1,
|
|
3959
|
+
minWidth: 0,
|
|
3960
|
+
padding: "8px 2px",
|
|
3961
|
+
borderRadius: "8px",
|
|
3962
|
+
border: `1px solid ${on ? t.accent : severityRefused ? "#ef4444" : t.inputBorder}`,
|
|
3963
|
+
backgroundColor: on ? t.accent : "transparent",
|
|
3964
|
+
color: on ? t.accentText : t.textMuted,
|
|
3965
|
+
fontSize: "12px",
|
|
3966
|
+
fontWeight: 600,
|
|
3967
|
+
fontFamily: "inherit",
|
|
3968
|
+
whiteSpace: "nowrap",
|
|
3969
|
+
overflow: "hidden",
|
|
3970
|
+
textOverflow: "ellipsis",
|
|
3971
|
+
cursor: "pointer"
|
|
3972
|
+
},
|
|
3973
|
+
children: SEVERITY_LABELS[s]
|
|
3974
|
+
},
|
|
3975
|
+
s
|
|
3976
|
+
);
|
|
3977
|
+
})
|
|
3978
|
+
}
|
|
3979
|
+
)
|
|
3980
|
+
] }),
|
|
3981
|
+
attachmentCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: { fontSize: "11.5px", color: t.textMuted }, children: [
|
|
3982
|
+
attachmentCount,
|
|
3983
|
+
" ",
|
|
3984
|
+
attachmentCount === 1 ? "attachment" : "attachments",
|
|
3985
|
+
" will be sent with this."
|
|
3986
|
+
] })
|
|
3987
|
+
]
|
|
3071
3988
|
}
|
|
3072
|
-
)
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
{
|
|
3077
|
-
style: {
|
|
3078
|
-
border: `1px solid ${t.accent}`,
|
|
3079
|
-
borderRadius: "12px",
|
|
3080
|
-
backgroundColor: t.bgSecondary,
|
|
3081
|
-
padding: "12px",
|
|
3082
|
-
display: "flex",
|
|
3083
|
-
flexDirection: "column",
|
|
3084
|
-
gap: "10px",
|
|
3085
|
-
minWidth: 0,
|
|
3086
|
-
boxSizing: "border-box"
|
|
3087
|
-
},
|
|
3088
|
-
children: [
|
|
3089
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3090
|
-
"span",
|
|
3091
|
-
{
|
|
3092
|
-
style: {
|
|
3093
|
-
fontSize: "10px",
|
|
3094
|
-
fontWeight: 700,
|
|
3095
|
-
letterSpacing: ".06em",
|
|
3096
|
-
textTransform: "uppercase",
|
|
3097
|
-
color: t.accent
|
|
3098
|
-
},
|
|
3099
|
-
children: duplicate ? `What we'll add to #${duplicate.number}${duplicate.kind === "related" ? " as a related request" : ""} \xB7 edit anything` : "Your report \xB7 edit anything"
|
|
3100
|
-
}
|
|
3101
|
-
),
|
|
3102
|
-
renderKnownIssue({
|
|
3103
|
-
title: true,
|
|
3104
|
-
footer: "Your details will be added to it instead of opening a new issue."
|
|
3105
|
-
}),
|
|
3106
|
-
!duplicate && issueTitle && // Wraps rather than scrolls sideways: a title cut off at the
|
|
3107
|
-
// box edge is the very thing #543 is about. One line of text,
|
|
3108
|
-
// so Enter is swallowed.
|
|
3109
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3110
|
-
"textarea",
|
|
3111
|
-
{
|
|
3112
|
-
"aria-label": "Title",
|
|
3113
|
-
value: issueTitle,
|
|
3114
|
-
maxLength: 120,
|
|
3115
|
-
rows: 2,
|
|
3116
|
-
onKeyDown: (e) => {
|
|
3117
|
-
if (e.key === "Enter") e.preventDefault();
|
|
3118
|
-
},
|
|
3119
|
-
onChange: (e) => {
|
|
3120
|
-
stopAutoFile("edited the title");
|
|
3121
|
-
onIssueTitleChange(e.target.value.replace(/[\r\n]+/g, " "));
|
|
3122
|
-
},
|
|
3123
|
-
style: {
|
|
3124
|
-
width: "100%",
|
|
3125
|
-
padding: "8px 10px",
|
|
3126
|
-
lineHeight: 1.45,
|
|
3127
|
-
resize: "none",
|
|
3128
|
-
borderRadius: "8px",
|
|
3129
|
-
border: `1px solid ${t.inputBorder}`,
|
|
3130
|
-
backgroundColor: t.inputBg,
|
|
3131
|
-
color: t.text,
|
|
3132
|
-
fontSize: "13px",
|
|
3133
|
-
fontWeight: 600,
|
|
3134
|
-
fontFamily: "inherit",
|
|
3135
|
-
outline: "none",
|
|
3136
|
-
boxSizing: "border-box"
|
|
3137
|
-
}
|
|
3138
|
-
}
|
|
3139
|
-
),
|
|
3989
|
+
),
|
|
3990
|
+
phase === "solved" && solved && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
3991
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
3992
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
3140
3993
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3141
|
-
"
|
|
3994
|
+
"div",
|
|
3142
3995
|
{
|
|
3143
|
-
ref: draftRef,
|
|
3144
|
-
value: description,
|
|
3145
|
-
onChange: (e) => {
|
|
3146
|
-
stopAutoFile("edited the draft");
|
|
3147
|
-
onDescriptionChange(e.target.value);
|
|
3148
|
-
},
|
|
3149
|
-
rows: 6,
|
|
3150
3996
|
style: {
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
borderRadius: "8px",
|
|
3155
|
-
border: `1px solid ${t.inputBorder}`,
|
|
3156
|
-
backgroundColor: t.inputBg,
|
|
3157
|
-
color: t.text,
|
|
3997
|
+
padding: "9px 12px",
|
|
3998
|
+
borderRadius: "12px 12px 12px 4px",
|
|
3999
|
+
backgroundColor: t.bgSecondary,
|
|
3158
4000
|
fontSize: "13px",
|
|
3159
4001
|
lineHeight: 1.55,
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
}
|
|
4002
|
+
maxWidth: "88%",
|
|
4003
|
+
whiteSpace: "pre-wrap"
|
|
4004
|
+
},
|
|
4005
|
+
children: solved
|
|
3165
4006
|
}
|
|
3166
|
-
)
|
|
3167
|
-
|
|
3168
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3169
|
-
"span",
|
|
3170
|
-
{
|
|
3171
|
-
style: {
|
|
3172
|
-
fontSize: "11.5px",
|
|
3173
|
-
color: t.textMuted,
|
|
3174
|
-
display: "block",
|
|
3175
|
-
marginBottom: "6px"
|
|
3176
|
-
},
|
|
3177
|
-
children: [
|
|
3178
|
-
"How bad is it?",
|
|
3179
|
-
!severity && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3180
|
-
"span",
|
|
3181
|
-
{
|
|
3182
|
-
style: {
|
|
3183
|
-
marginLeft: "6px",
|
|
3184
|
-
fontSize: "11px",
|
|
3185
|
-
color: severityRefused ? "#ef4444" : t.textMuted
|
|
3186
|
-
},
|
|
3187
|
-
children: "\xB7 required"
|
|
3188
|
-
}
|
|
3189
|
-
)
|
|
3190
|
-
]
|
|
3191
|
-
}
|
|
3192
|
-
),
|
|
3193
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3194
|
-
"div",
|
|
3195
|
-
{
|
|
3196
|
-
role: "radiogroup",
|
|
3197
|
-
"aria-label": "Severity",
|
|
3198
|
-
style: { display: "flex", gap: "6px" },
|
|
3199
|
-
children: SEVERITY_LEVELS.map((s) => {
|
|
3200
|
-
const on = severity === s;
|
|
3201
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3202
|
-
"button",
|
|
3203
|
-
{
|
|
3204
|
-
type: "button",
|
|
3205
|
-
onClick: () => onSeverityChange(s),
|
|
3206
|
-
role: "radio",
|
|
3207
|
-
"aria-checked": on,
|
|
3208
|
-
style: {
|
|
3209
|
-
flex: 1,
|
|
3210
|
-
minWidth: 0,
|
|
3211
|
-
padding: "8px 2px",
|
|
3212
|
-
borderRadius: "8px",
|
|
3213
|
-
border: `1px solid ${on ? t.accent : severityRefused ? "#ef4444" : t.inputBorder}`,
|
|
3214
|
-
backgroundColor: on ? t.accent : "transparent",
|
|
3215
|
-
color: on ? t.accentText : t.textMuted,
|
|
3216
|
-
fontSize: "12px",
|
|
3217
|
-
fontWeight: 600,
|
|
3218
|
-
fontFamily: "inherit",
|
|
3219
|
-
whiteSpace: "nowrap",
|
|
3220
|
-
overflow: "hidden",
|
|
3221
|
-
textOverflow: "ellipsis",
|
|
3222
|
-
cursor: "pointer"
|
|
3223
|
-
},
|
|
3224
|
-
children: SEVERITY_LABELS[s]
|
|
3225
|
-
},
|
|
3226
|
-
s
|
|
3227
|
-
);
|
|
3228
|
-
})
|
|
3229
|
-
}
|
|
3230
|
-
)
|
|
3231
|
-
] }),
|
|
3232
|
-
attachmentCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: { fontSize: "11.5px", color: t.textMuted }, children: [
|
|
3233
|
-
attachmentCount,
|
|
3234
|
-
" ",
|
|
3235
|
-
attachmentCount === 1 ? "attachment" : "attachments",
|
|
3236
|
-
" will be sent with this."
|
|
3237
|
-
] })
|
|
3238
|
-
]
|
|
3239
|
-
}
|
|
3240
|
-
),
|
|
3241
|
-
phase === "solved" && solved && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "12px" }, children: [
|
|
3242
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", gap: "8px" }, children: [
|
|
3243
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Avatar, { who: "assistant", theme: t }),
|
|
4007
|
+
)
|
|
4008
|
+
] }),
|
|
3244
4009
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3245
|
-
"
|
|
4010
|
+
"span",
|
|
3246
4011
|
{
|
|
3247
|
-
style: {
|
|
3248
|
-
|
|
3249
|
-
borderRadius: "12px 12px 12px 4px",
|
|
3250
|
-
backgroundColor: t.bgSecondary,
|
|
3251
|
-
fontSize: "13px",
|
|
3252
|
-
lineHeight: 1.55,
|
|
3253
|
-
maxWidth: "88%",
|
|
3254
|
-
whiteSpace: "pre-wrap"
|
|
3255
|
-
},
|
|
3256
|
-
children: solved
|
|
4012
|
+
style: { fontSize: "11.5px", color: t.textMuted, paddingLeft: "32px" },
|
|
4013
|
+
children: "Nothing was filed \u2014 you are all set."
|
|
3257
4014
|
}
|
|
3258
4015
|
)
|
|
3259
4016
|
] }),
|
|
3260
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
3261
|
-
"
|
|
4017
|
+
submitted && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
4018
|
+
"div",
|
|
3262
4019
|
{
|
|
3263
|
-
style: {
|
|
3264
|
-
|
|
4020
|
+
style: {
|
|
4021
|
+
textAlign: "center",
|
|
4022
|
+
padding: "24px 0",
|
|
4023
|
+
color: t.accent,
|
|
4024
|
+
fontSize: "14px",
|
|
4025
|
+
fontWeight: 600
|
|
4026
|
+
},
|
|
4027
|
+
children: submittedText != null ? submittedText : `${reportTypeLabel} sent. Thank you!`
|
|
3265
4028
|
}
|
|
3266
4029
|
)
|
|
3267
|
-
] })
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
style: {
|
|
3272
|
-
textAlign: "center",
|
|
3273
|
-
padding: "24px 0",
|
|
3274
|
-
color: t.accent,
|
|
3275
|
-
fontSize: "14px",
|
|
3276
|
-
fontWeight: 600
|
|
3277
|
-
},
|
|
3278
|
-
children: submittedText != null ? submittedText : `${reportTypeLabel} sent. Thank you!`
|
|
3279
|
-
}
|
|
3280
|
-
)
|
|
3281
|
-
]
|
|
3282
|
-
}
|
|
3283
|
-
)
|
|
4030
|
+
] })
|
|
4031
|
+
}
|
|
4032
|
+
)
|
|
4033
|
+
]
|
|
3284
4034
|
}
|
|
3285
4035
|
),
|
|
3286
|
-
!submitted && phase !== "type" && phase !== "severity" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
4036
|
+
!submitted && !showChats && phase !== "type" && phase !== "severity" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
3287
4037
|
"div",
|
|
3288
4038
|
{
|
|
3289
4039
|
style: {
|
|
@@ -3600,8 +4350,8 @@ function AssistSheet({
|
|
|
3600
4350
|
accept: canReadPdf ? ASSIST_ATTACHMENT_ACCEPT_WITH_PDF : ASSIST_ATTACHMENT_ACCEPT,
|
|
3601
4351
|
multiple: true,
|
|
3602
4352
|
onChange: (e) => {
|
|
3603
|
-
var
|
|
3604
|
-
const picked = Array.from((
|
|
4353
|
+
var _a2;
|
|
4354
|
+
const picked = Array.from((_a2 = e.target.files) != null ? _a2 : []);
|
|
3605
4355
|
if (picked.length) {
|
|
3606
4356
|
stopAutoFile("changed attachments");
|
|
3607
4357
|
const images = picked.filter((f) => f.type.startsWith("image/")).length;
|
|
@@ -4579,20 +5329,20 @@ function initialsOf(name) {
|
|
|
4579
5329
|
}).join("");
|
|
4580
5330
|
}
|
|
4581
5331
|
function ReporterChip({
|
|
4582
|
-
reporter,
|
|
5332
|
+
reporter: reporter2,
|
|
4583
5333
|
t
|
|
4584
5334
|
}) {
|
|
4585
5335
|
var _a;
|
|
4586
5336
|
const [avatarFailed, setAvatarFailed] = (0, import_react.useState)(false);
|
|
4587
|
-
const avatarUrl = (
|
|
5337
|
+
const avatarUrl = (reporter2 == null ? void 0 : reporter2.avatarUrl) || "";
|
|
4588
5338
|
(0, import_react.useEffect)(() => {
|
|
4589
5339
|
setAvatarFailed(false);
|
|
4590
5340
|
}, [avatarUrl]);
|
|
4591
|
-
const name = ((_a =
|
|
5341
|
+
const name = ((_a = reporter2 == null ? void 0 : reporter2.name) == null ? void 0 : _a.trim()) || "";
|
|
4592
5342
|
const isAnonymous = !name;
|
|
4593
5343
|
const initials2 = isAnonymous ? "" : initialsOf(name);
|
|
4594
5344
|
const label = isAnonymous ? "Anonymous" : name;
|
|
4595
|
-
const title = isAnonymous ? "No reporter identity was passed to Glitchgrab \u2014 this report won't be attributed to anyone" : [name,
|
|
5345
|
+
const title = isAnonymous ? "No reporter identity was passed to Glitchgrab \u2014 this report won't be attributed to anyone" : [name, reporter2 == null ? void 0 : reporter2.email, reporter2 == null ? void 0 : reporter2.role].filter(Boolean).join(" \xB7 ");
|
|
4596
5346
|
const showAvatarImage = !!avatarUrl && !avatarFailed;
|
|
4597
5347
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
4598
5348
|
"span",
|
|
@@ -4656,7 +5406,7 @@ function ReporterChip({
|
|
|
4656
5406
|
},
|
|
4657
5407
|
children: [
|
|
4658
5408
|
label,
|
|
4659
|
-
(
|
|
5409
|
+
(reporter2 == null ? void 0 : reporter2.role) ? ` \xB7 ${reporter2.role}` : ""
|
|
4660
5410
|
]
|
|
4661
5411
|
}
|
|
4662
5412
|
)
|
|
@@ -4773,11 +5523,12 @@ function ReportDialog({
|
|
|
4773
5523
|
types,
|
|
4774
5524
|
showSeverity = true,
|
|
4775
5525
|
captureScreenshot = captureDefaultScreenshot,
|
|
4776
|
-
reporter,
|
|
5526
|
+
reporter: reporter2,
|
|
4777
5527
|
onClose,
|
|
4778
5528
|
headerSlot,
|
|
4779
5529
|
reportGlitchgrabProblem,
|
|
4780
|
-
layout = "modal"
|
|
5530
|
+
layout = "modal",
|
|
5531
|
+
chatHistoryKey: chatHistoryKey2 = null
|
|
4781
5532
|
}) {
|
|
4782
5533
|
var _a;
|
|
4783
5534
|
const sheet = layout === "sheet";
|
|
@@ -4882,15 +5633,15 @@ function ReportDialog({
|
|
|
4882
5633
|
});
|
|
4883
5634
|
};
|
|
4884
5635
|
applyInert();
|
|
4885
|
-
const
|
|
5636
|
+
const observer2 = new MutationObserver((mutations) => {
|
|
4886
5637
|
const structural = mutations.some(
|
|
4887
5638
|
(m) => m.addedNodes.length > 0 || m.removedNodes.length > 0
|
|
4888
5639
|
);
|
|
4889
5640
|
if (structural) applyInert();
|
|
4890
5641
|
});
|
|
4891
|
-
|
|
5642
|
+
observer2.observe(document.body, { childList: true, subtree: true });
|
|
4892
5643
|
return () => {
|
|
4893
|
-
|
|
5644
|
+
observer2.disconnect();
|
|
4894
5645
|
inerted.forEach((el) => el.removeAttribute("inert"));
|
|
4895
5646
|
};
|
|
4896
5647
|
}, [isOpen]);
|
|
@@ -5542,6 +6293,9 @@ function ReportDialog({
|
|
|
5542
6293
|
setAddedAsRelated(!!duplicateOf && result.issueNumber === duplicateOf && attachKind === "related");
|
|
5543
6294
|
const queued = result.status === "QUEUED" && !!result.message;
|
|
5544
6295
|
setQueuedMessage(queued ? (_c = result.message) != null ? _c : null : null);
|
|
6296
|
+
if (chatHistoryKey2 && aiConversationId) {
|
|
6297
|
+
markChatFiled(chatHistoryKey2, aiConversationId, `${getTypeLabel(reportType)} sent`);
|
|
6298
|
+
}
|
|
5545
6299
|
setSubmitted(true);
|
|
5546
6300
|
setDescription("");
|
|
5547
6301
|
setScreenshots([]);
|
|
@@ -7361,7 +8115,7 @@ function ReportDialog({
|
|
|
7361
8115
|
gap: "12px"
|
|
7362
8116
|
},
|
|
7363
8117
|
children: [
|
|
7364
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ReporterChip, { reporter, t }),
|
|
8118
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ReporterChip, { reporter: reporter2, t }),
|
|
7365
8119
|
reportGlitchgrabProblem ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
7366
8120
|
"button",
|
|
7367
8121
|
{
|
|
@@ -7641,6 +8395,7 @@ function ReportDialog({
|
|
|
7641
8395
|
setDuplicateKind(issueNumber && kind === "related" ? "related" : "duplicate");
|
|
7642
8396
|
},
|
|
7643
8397
|
onConversationChange: setAiConversationId,
|
|
8398
|
+
historyKey: chatHistoryKey2,
|
|
7644
8399
|
onFinish: handleClose,
|
|
7645
8400
|
rating,
|
|
7646
8401
|
onRatingChange: (value) => {
|
|
@@ -7648,7 +8403,7 @@ function ReportDialog({
|
|
|
7648
8403
|
if (validationError) setValidationError(null);
|
|
7649
8404
|
},
|
|
7650
8405
|
projectSlot: headerSlot,
|
|
7651
|
-
reporterName: (_a =
|
|
8406
|
+
reporterName: (_a = reporter2 == null ? void 0 : reporter2.name) != null ? _a : null,
|
|
7652
8407
|
description,
|
|
7653
8408
|
onDescriptionChange: (value) => {
|
|
7654
8409
|
setDescription(value);
|
|
@@ -9235,6 +9990,9 @@ function GlitchgrabProviderInner({
|
|
|
9235
9990
|
onError,
|
|
9236
9991
|
onReportSent
|
|
9237
9992
|
});
|
|
9993
|
+
if (process.env.NODE_ENV !== "development") {
|
|
9994
|
+
installHydrationCapture(reportHydrationError);
|
|
9995
|
+
}
|
|
9238
9996
|
(0, import_react6.useEffect)(() => {
|
|
9239
9997
|
if (enableBreadcrumbs) {
|
|
9240
9998
|
initBreadcrumbs(maxBreadcrumbs2, { responseBodyOrigins: responseBodyOrigins2 });
|
|
@@ -9290,7 +10048,7 @@ function GlitchgrabProviderInner({
|
|
|
9290
10048
|
return matchesIgnorePatterns(message, ignoreErrors);
|
|
9291
10049
|
};
|
|
9292
10050
|
const handleError = (event) => {
|
|
9293
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
10051
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
9294
10052
|
try {
|
|
9295
10053
|
const isOpaqueCrossOrigin = event.message === "Script error." || event.message === "Script error" || !event.error && !event.filename;
|
|
9296
10054
|
if (isOpaqueCrossOrigin) {
|
|
@@ -9305,6 +10063,7 @@ function GlitchgrabProviderInner({
|
|
|
9305
10063
|
if (event.filename && EXTENSION_ORIGIN_RE.test(event.filename) || ((_a = event.error) == null ? void 0 : _a.stack) && EXTENSION_ORIGIN_RE.test(event.error.stack)) {
|
|
9306
10064
|
return;
|
|
9307
10065
|
}
|
|
10066
|
+
if (isHandledHydrationError(event.error)) return;
|
|
9308
10067
|
incrementErrorCount();
|
|
9309
10068
|
const context = captureContext(visitedPagesRef.current);
|
|
9310
10069
|
const sig = computeSignature({
|
|
@@ -9330,6 +10089,9 @@ function GlitchgrabProviderInner({
|
|
|
9330
10089
|
filename: (_e = event.filename) != null ? _e : "",
|
|
9331
10090
|
lineno: String((_f = event.lineno) != null ? _f : ""),
|
|
9332
10091
|
colno: String((_g = event.colno) != null ? _g : ""),
|
|
10092
|
+
// The root patch could not attach (React internals moved, or a
|
|
10093
|
+
// root it does not know): still label it and send the DOM context.
|
|
10094
|
+
...isHydrationError((_h = event.error) != null ? _h : event.message) ? hydrationMetadata((_i = event.error) != null ? _i : event.message) : {},
|
|
9333
10095
|
...(session == null ? void 0 : session.userId) ? { sessionUserId: session.userId } : {},
|
|
9334
10096
|
...(session == null ? void 0 : session.name) ? { sessionUserName: String(session.name) } : {},
|
|
9335
10097
|
...(session == null ? void 0 : session.email) ? { sessionUserEmail: String(session.email) } : {},
|
|
@@ -9671,7 +10433,7 @@ function GlitchgrabProviderInner({
|
|
|
9671
10433
|
} catch (e) {
|
|
9672
10434
|
}
|
|
9673
10435
|
}, [openReportDialog]);
|
|
9674
|
-
const
|
|
10436
|
+
const reporter2 = (0, import_react6.useMemo)(() => {
|
|
9675
10437
|
var _a;
|
|
9676
10438
|
if (!session) return null;
|
|
9677
10439
|
const avatar = (_a = session.avatarUrl) != null ? _a : session.image;
|
|
@@ -9742,7 +10504,8 @@ function GlitchgrabProviderInner({
|
|
|
9742
10504
|
transcribeAudio: aiBlockedUnsigned ? void 0 : transcribe,
|
|
9743
10505
|
types,
|
|
9744
10506
|
showSeverity,
|
|
9745
|
-
reporter,
|
|
10507
|
+
reporter: reporter2,
|
|
10508
|
+
chatHistoryKey: chatHistoryKey("sdk", token, session == null ? void 0 : session.userId),
|
|
9746
10509
|
headerSlot: projectName ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { fontSize: 11, color: "#9aa0a6" }, children: [
|
|
9747
10510
|
"Reporting to ",
|
|
9748
10511
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { style: { color: "#e5e5e5" }, children: projectName })
|