qapture2 0.7.7 → 0.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-FVQKCQC3.js → chunk-2JX7YU2P.js} +227 -273
- package/dist/{chunk-WU7QMHPK.cjs → chunk-4LMLW73U.cjs} +227 -273
- package/dist/index.cjs +5 -5
- package/dist/index.js +1 -1
- package/dist/next.cjs +4 -4
- package/dist/next.js +1 -1
- package/dist/standalone.cjs +2 -2
- package/dist/standalone.js +1 -1
- package/package.json +1 -1
|
@@ -1862,6 +1862,13 @@ var STR = {
|
|
|
1862
1862
|
retest_not_found: "Can't find that spot on this page \u2014 open the right page first",
|
|
1863
1863
|
before_label: "Before",
|
|
1864
1864
|
after_label: "After",
|
|
1865
|
+
followup_label: "What happened this time",
|
|
1866
|
+
followup_add: "Say what happened",
|
|
1867
|
+
followup_placeholder: "What did it do this time, and how is that different from what you asked for?",
|
|
1868
|
+
followup_hint: "The first note stays as it is. This is added under it as round two.",
|
|
1869
|
+
keep_only_retest: "Keep only these {n}",
|
|
1870
|
+
keep_only_retest_q: "Delete the other {n}?",
|
|
1871
|
+
keep_only_retest_hint: "Delete every note that is not waiting to be re-tested",
|
|
1865
1872
|
welcome_title: "Testing {brand}",
|
|
1866
1873
|
welcome_capture: 'Click "Capture from page", then click whatever looks wrong.',
|
|
1867
1874
|
welcome_say: "Say what you expected in your own words. A screenshot is taken for you.",
|
|
@@ -2060,6 +2067,13 @@ var STR = {
|
|
|
2060
2067
|
retest_not_found: "\u062A\u0639\u0630\u0651\u0631 \u0625\u064A\u062C\u0627\u062F \u0630\u0644\u0643 \u0627\u0644\u0645\u0648\u0636\u0639 \u0641\u064A \u0647\u0630\u0647 \u0627\u0644\u0635\u0641\u062D\u0629 \u2014 \u0627\u0641\u062A\u062D \u0627\u0644\u0635\u0641\u062D\u0629 \u0627\u0644\u0635\u062D\u064A\u062D\u0629 \u0623\u0648\u0644\u064B\u0627",
|
|
2061
2068
|
before_label: "\u0642\u0628\u0644",
|
|
2062
2069
|
after_label: "\u0628\u0639\u062F",
|
|
2070
|
+
followup_label: "\u0645\u0627\u0630\u0627 \u062D\u062F\u062B \u0647\u0630\u0647 \u0627\u0644\u0645\u0631\u0629",
|
|
2071
|
+
followup_add: "\u0627\u0643\u062A\u0628 \u0645\u0627\u0630\u0627 \u062D\u062F\u062B",
|
|
2072
|
+
followup_placeholder: "\u0645\u0627\u0630\u0627 \u0641\u0639\u0644 \u0647\u0630\u0647 \u0627\u0644\u0645\u0631\u0629\u060C \u0648\u0643\u064A\u0641 \u064A\u062E\u062A\u0644\u0641 \u0630\u0644\u0643 \u0639\u0645\u0651\u0627 \u0637\u0644\u0628\u062A\u0647\u061F",
|
|
2073
|
+
followup_hint: "\u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0629 \u0627\u0644\u0623\u0648\u0644\u0649 \u062A\u0628\u0642\u0649 \u0643\u0645\u0627 \u0647\u064A. \u0647\u0630\u0647 \u062A\u064F\u0636\u0627\u0641 \u062A\u062D\u062A\u0647\u0627 \u0643\u062C\u0648\u0644\u0629 \u062B\u0627\u0646\u064A\u0629.",
|
|
2074
|
+
keep_only_retest: "\u0623\u0628\u0642\u0650 \u0647\u0630\u0647 \u0627\u0644\u0640 {n} \u0641\u0642\u0637",
|
|
2075
|
+
keep_only_retest_q: "\u062D\u0630\u0641 \u0627\u0644\u0640 {n} \u0627\u0644\u0623\u062E\u0631\u0649\u061F",
|
|
2076
|
+
keep_only_retest_hint: "\u062D\u0630\u0641 \u0643\u0644 \u0645\u0644\u0627\u062D\u0638\u0629 \u0644\u064A\u0633\u062A \u0628\u0627\u0646\u062A\u0638\u0627\u0631 \u0625\u0639\u0627\u062F\u0629 \u0627\u0644\u0627\u062E\u062A\u0628\u0627\u0631",
|
|
2063
2077
|
welcome_title: "\u0627\u062E\u062A\u0628\u0627\u0631 {brand}",
|
|
2064
2078
|
welcome_capture: "\u0627\u0636\u063A\u0637 \xAB\u0627\u0644\u062A\u0642\u0627\u0637 \u0645\u0646 \u0627\u0644\u0635\u0641\u062D\u0629\xBB \u062B\u0645 \u0627\u0636\u063A\u0637 \u0639\u0644\u0649 \u0645\u0627 \u064A\u0628\u062F\u0648 \u062E\u0627\u0637\u0626\u064B\u0627.",
|
|
2065
2079
|
welcome_say: "\u0627\u0643\u062A\u0628 \u0645\u0627 \u0643\u0646\u062A \u062A\u062A\u0648\u0642\u0639\u0647 \u0628\u0643\u0644\u0645\u0627\u062A\u0643. \u062A\u064F\u0644\u062A\u0642\u0637 \u0627\u0644\u0635\u0648\u0631\u0629 \u062A\u0644\u0642\u0627\u0626\u064A\u064B\u0627.",
|
|
@@ -2104,18 +2118,6 @@ function pick(value, lang) {
|
|
|
2104
2118
|
if (typeof value === "string") return value;
|
|
2105
2119
|
return value[lang] ?? value.en ?? "";
|
|
2106
2120
|
}
|
|
2107
|
-
|
|
2108
|
-
// src/lib/coverage.ts
|
|
2109
|
-
var RISK_COLORS = {
|
|
2110
|
-
red: "#FF6B6B",
|
|
2111
|
-
// --qa-danger
|
|
2112
|
-
amber: "#FBBF24",
|
|
2113
|
-
// --qa-warn
|
|
2114
|
-
green: "#34D399",
|
|
2115
|
-
// --qa-success
|
|
2116
|
-
none: "#5B616B"
|
|
2117
|
-
// --qa-neutral
|
|
2118
|
-
};
|
|
2119
2121
|
function computeCoverage(journey, guideChecked, skipped) {
|
|
2120
2122
|
const red = { total: 0, covered: 0 };
|
|
2121
2123
|
const amber = { total: 0, covered: 0 };
|
|
@@ -2969,16 +2971,19 @@ function clipToPaintedArea(el, rect) {
|
|
|
2969
2971
|
let top = rect.top;
|
|
2970
2972
|
let right = rect.left + rect.width;
|
|
2971
2973
|
let bottom = rect.top + rect.height;
|
|
2974
|
+
const doc = el.ownerDocument;
|
|
2975
|
+
const root2 = doc ? doc.documentElement : null;
|
|
2976
|
+
const body = doc ? doc.body : null;
|
|
2977
|
+
const rootStyle = root2 ? safeComputedStyle(root2) : null;
|
|
2978
|
+
const bodyStyle = body ? safeComputedStyle(body) : null;
|
|
2972
2979
|
let node = el.parentElement;
|
|
2973
|
-
while (node) {
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
const clipsX = style.overflowX !== "visible";
|
|
2981
|
-
const clipsY = style.overflowY !== "visible";
|
|
2980
|
+
while (node && node !== root2) {
|
|
2981
|
+
const style = safeComputedStyle(node);
|
|
2982
|
+
if (!style) break;
|
|
2983
|
+
const propagatedX = node === body && rootStyle?.overflowX === "visible";
|
|
2984
|
+
const propagatedY = node === body && rootStyle?.overflowY === "visible";
|
|
2985
|
+
const clipsX = !propagatedX && style.overflowX !== "visible";
|
|
2986
|
+
const clipsY = !propagatedY && style.overflowY !== "visible";
|
|
2982
2987
|
if (clipsX || clipsY) {
|
|
2983
2988
|
const b = node.getBoundingClientRect();
|
|
2984
2989
|
const padLeft = b.left + node.clientLeft;
|
|
@@ -2994,9 +2999,33 @@ function clipToPaintedArea(el, rect) {
|
|
|
2994
2999
|
}
|
|
2995
3000
|
node = node.parentElement;
|
|
2996
3001
|
}
|
|
3002
|
+
const vpX = usedViewportOverflow(rootStyle?.overflowX, bodyStyle?.overflowX);
|
|
3003
|
+
const vpY = usedViewportOverflow(rootStyle?.overflowY, bodyStyle?.overflowY);
|
|
3004
|
+
if (vpX === "hidden" || vpX === "clip" || vpY === "hidden" || vpY === "clip") {
|
|
3005
|
+
const { vw, vh } = viewportSize();
|
|
3006
|
+
if (vpX === "hidden" || vpX === "clip") {
|
|
3007
|
+
left = Math.max(left, 0);
|
|
3008
|
+
right = Math.min(right, vw);
|
|
3009
|
+
}
|
|
3010
|
+
if (vpY === "hidden" || vpY === "clip") {
|
|
3011
|
+
top = Math.max(top, 0);
|
|
3012
|
+
bottom = Math.min(bottom, vh);
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
2997
3015
|
if (right - left < 2 || bottom - top < 2) return rect;
|
|
2998
3016
|
return { left, top, width: right - left, height: bottom - top };
|
|
2999
3017
|
}
|
|
3018
|
+
function safeComputedStyle(node) {
|
|
3019
|
+
try {
|
|
3020
|
+
return getComputedStyle(node);
|
|
3021
|
+
} catch {
|
|
3022
|
+
return null;
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
function usedViewportOverflow(rootValue, bodyValue) {
|
|
3026
|
+
if (rootValue && rootValue !== "visible") return rootValue;
|
|
3027
|
+
return bodyValue || "visible";
|
|
3028
|
+
}
|
|
3000
3029
|
function intersectViewport(rect) {
|
|
3001
3030
|
const { vw, vh } = viewportSize();
|
|
3002
3031
|
const left = Math.max(0, rect.left);
|
|
@@ -3191,6 +3220,16 @@ function noteToMarkdown(note, opts) {
|
|
|
3191
3220
|
}
|
|
3192
3221
|
lines.push("");
|
|
3193
3222
|
lines.push(oneLine(note.description) ? note.description.trim() : "_(no description)_");
|
|
3223
|
+
if (note.followUp && oneLine(note.followUp)) {
|
|
3224
|
+
lines.push("");
|
|
3225
|
+
lines.push(
|
|
3226
|
+
"> **This one came back \u2014 round 2.** The point above was already worked on once and it is still not right. What follows is the tester re-testing it, so treat it as the current ask and the point above as the history of what was originally wanted."
|
|
3227
|
+
);
|
|
3228
|
+
lines.push("");
|
|
3229
|
+
lines.push(`**What happened this time**${note.followUpAt ? ` (${oneLine(note.followUpAt)})` : ""}`);
|
|
3230
|
+
lines.push("");
|
|
3231
|
+
lines.push(note.followUp.trim());
|
|
3232
|
+
}
|
|
3194
3233
|
const recordedSteps = note.context?.steps ?? [];
|
|
3195
3234
|
if (recordedSteps.length) {
|
|
3196
3235
|
const t0 = Date.parse(note.timestamp) || recordedSteps[recordedSteps.length - 1].t;
|
|
@@ -3277,7 +3316,7 @@ function fmtPct(n, d) {
|
|
|
3277
3316
|
}
|
|
3278
3317
|
function summariseSession(notes, stamp) {
|
|
3279
3318
|
if (!notes.length) return "No points captured.";
|
|
3280
|
-
let bugs = 0, enhancements = 0, designs = 0, verified = 0, awaiting = 0;
|
|
3319
|
+
let bugs = 0, enhancements = 0, designs = 0, verified = 0, awaiting = 0, secondRound = 0;
|
|
3281
3320
|
const pages = /* @__PURE__ */ new Set();
|
|
3282
3321
|
let earliest = Number.POSITIVE_INFINITY;
|
|
3283
3322
|
let latest = 0;
|
|
@@ -3289,6 +3328,7 @@ function summariseSession(notes, stamp) {
|
|
|
3289
3328
|
const status = n.status ?? "open";
|
|
3290
3329
|
if (status === "verified") verified++;
|
|
3291
3330
|
else if (status === "fixed") awaiting++;
|
|
3331
|
+
if (n.followUp && n.followUp.trim()) secondRound++;
|
|
3292
3332
|
pages.add((n.route || "/").split("?")[0]);
|
|
3293
3333
|
const t = Date.parse(n.timestamp);
|
|
3294
3334
|
if (Number.isFinite(t)) {
|
|
@@ -3304,6 +3344,7 @@ function summariseSession(notes, stamp) {
|
|
|
3304
3344
|
if (designs) parts.push(`${designs} design`);
|
|
3305
3345
|
if (verified) parts.push(`${verified} verified`);
|
|
3306
3346
|
if (awaiting) parts.push(`${awaiting} awaiting re-test`);
|
|
3347
|
+
if (secondRound) parts.push(`${secondRound} back for a second round`);
|
|
3307
3348
|
parts.push(`${pages.size} page${pages.size === 1 ? "" : "s"}`);
|
|
3308
3349
|
if (Number.isFinite(earliest) && latest > earliest) {
|
|
3309
3350
|
const minutes = Math.max(1, Math.round((latest - earliest) / 6e4));
|
|
@@ -3358,6 +3399,14 @@ The tester wants something added or changed: a new section, a new feature, a dif
|
|
|
3358
3399
|
|
|
3359
3400
|
Push back only when you have a real reason: it would break something, or it conflicts with an invariant below. Then say so plainly and propose the alternative you would build instead.
|
|
3360
3401
|
|
|
3402
|
+
### A point with a "round 2" on it
|
|
3403
|
+
|
|
3404
|
+
Some points carry a **round 2** block: the same finding, already worked on once, re-tested, and still not right. Two things follow from that.
|
|
3405
|
+
|
|
3406
|
+
First, **the round-2 text is the current ask** and the paragraph above it is history \u2014 read the history to understand what was wanted, act on the round 2.
|
|
3407
|
+
|
|
3408
|
+
Second, **the previous attempt is evidence.** Something about the first reading was wrong, so do not simply do it again more carefully. Work out what was misunderstood the first time and say so in one sentence, then fix that. If a "Before"/"After" screenshot pair is attached, the After is what the tester was looking at when they wrote the round 2.
|
|
3409
|
+
|
|
3361
3410
|
### When the tag and the words disagree
|
|
3362
3411
|
|
|
3363
3412
|
The tag sets your starting posture; **the words win.** A point tagged Design that says "this crashes" is a bug \u2014 treat it as one, and mention that you changed lane. People pick the wrong chip all the time; that is not a reason to do the wrong work.
|
|
@@ -4602,6 +4651,11 @@ function QaProvider({
|
|
|
4602
4651
|
}
|
|
4603
4652
|
if (patch.severity !== void 0) updated.severity = patch.severity;
|
|
4604
4653
|
if (patch.status !== void 0) updated.status = patch.status;
|
|
4654
|
+
if (patch.followUp !== void 0) {
|
|
4655
|
+
const text = patch.followUp.trim();
|
|
4656
|
+
updated.followUp = text || void 0;
|
|
4657
|
+
updated.followUpAt = text ? nowIso() : void 0;
|
|
4658
|
+
}
|
|
4605
4659
|
applyNotes((prev) => prev.map((n) => n.id === id ? updated : n));
|
|
4606
4660
|
const persisted = await idb.put(updated);
|
|
4607
4661
|
if (!persisted) {
|
|
@@ -6597,6 +6651,8 @@ function NoteItem({
|
|
|
6597
6651
|
const thumbUrl = useObjectUrl(editing ? img ?? void 0 : note.screenshot);
|
|
6598
6652
|
const afterUrl = useObjectUrl(note.afterScreenshot);
|
|
6599
6653
|
const [retesting, setRetesting] = useState(false);
|
|
6654
|
+
const [editingFollowUp, setEditingFollowUp] = useState(false);
|
|
6655
|
+
const [followUpDraft, setFollowUpDraft] = useState(note.followUp ?? "");
|
|
6600
6656
|
const [open, setOpen] = useState(false);
|
|
6601
6657
|
const severity = note.severity ?? "bug";
|
|
6602
6658
|
const status = note.status ?? "open";
|
|
@@ -6930,7 +6986,96 @@ function NoteItem({
|
|
|
6930
6986
|
style: { borderColor: "var(--qa-success)" }
|
|
6931
6987
|
}
|
|
6932
6988
|
)
|
|
6933
|
-
] })
|
|
6989
|
+
] }),
|
|
6990
|
+
(status === "fixed" || note.followUp) && /* @__PURE__ */ jsx(
|
|
6991
|
+
"div",
|
|
6992
|
+
{
|
|
6993
|
+
className: "qa-mt-2 qa-rounded-lg qa-border qa-border-subtle qa-bg-2 qa-p-2",
|
|
6994
|
+
"data-qa-followup": "true",
|
|
6995
|
+
children: editingFollowUp ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6996
|
+
/* @__PURE__ */ jsx("label", { className: "qa-text-10 qa-text-lo", htmlFor: `qa-fu-${note.id}`, children: t("followup_label") }),
|
|
6997
|
+
/* @__PURE__ */ jsx(
|
|
6998
|
+
"textarea",
|
|
6999
|
+
{
|
|
7000
|
+
id: `qa-fu-${note.id}`,
|
|
7001
|
+
value: followUpDraft,
|
|
7002
|
+
onChange: (e) => setFollowUpDraft(e.target.value),
|
|
7003
|
+
placeholder: t("followup_placeholder"),
|
|
7004
|
+
rows: 3,
|
|
7005
|
+
className: "qa-mt-1 qa-w-full qa-rounded-lg qa-border qa-border-subtle qa-bg-1 qa-p-2 qa-text-xs qa-text-hi",
|
|
7006
|
+
style: { outline: "none", resize: "vertical" }
|
|
7007
|
+
}
|
|
7008
|
+
),
|
|
7009
|
+
/* @__PURE__ */ jsx("p", { className: "qa-mt-1 qa-text-10 qa-text-lo", children: t("followup_hint") }),
|
|
7010
|
+
/* @__PURE__ */ jsxs("div", { className: "qa-mt-1.5 qa-flex qa-gap-2", children: [
|
|
7011
|
+
/* @__PURE__ */ jsxs(
|
|
7012
|
+
"button",
|
|
7013
|
+
{
|
|
7014
|
+
type: "button",
|
|
7015
|
+
onClick: () => {
|
|
7016
|
+
void updateNote(note.id, { followUp: followUpDraft });
|
|
7017
|
+
setEditingFollowUp(false);
|
|
7018
|
+
},
|
|
7019
|
+
className: "qa-tap qa-inline-flex qa-items-center qa-gap-1 qa-rounded-lg qa-bg-accent qa-px-2 qa-py-1 qa-text-11 qa-font-semibold",
|
|
7020
|
+
style: { border: "none", cursor: "pointer" },
|
|
7021
|
+
children: [
|
|
7022
|
+
/* @__PURE__ */ jsx(Icon, { name: "Check", size: 12 }),
|
|
7023
|
+
t("save")
|
|
7024
|
+
]
|
|
7025
|
+
}
|
|
7026
|
+
),
|
|
7027
|
+
/* @__PURE__ */ jsx(
|
|
7028
|
+
"button",
|
|
7029
|
+
{
|
|
7030
|
+
type: "button",
|
|
7031
|
+
onClick: () => {
|
|
7032
|
+
setFollowUpDraft(note.followUp ?? "");
|
|
7033
|
+
setEditingFollowUp(false);
|
|
7034
|
+
},
|
|
7035
|
+
className: "qa-tap qa-rounded-lg qa-border qa-border-subtle qa-px-2 qa-py-1 qa-text-11 qa-text-mid",
|
|
7036
|
+
style: { background: "transparent", cursor: "pointer" },
|
|
7037
|
+
children: t("cancel")
|
|
7038
|
+
}
|
|
7039
|
+
)
|
|
7040
|
+
] })
|
|
7041
|
+
] }) : note.followUp ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7042
|
+
/* @__PURE__ */ jsxs("div", { className: "qa-flex qa-items-center qa-gap-1", children: [
|
|
7043
|
+
/* @__PURE__ */ jsx(Icon, { name: "RotateCcw", size: 11, className: "qa-shrink-0 qa-text-warn" }),
|
|
7044
|
+
/* @__PURE__ */ jsx("span", { className: "qa-text-10 qa-text-warn", children: t("followup_label") }),
|
|
7045
|
+
/* @__PURE__ */ jsx(
|
|
7046
|
+
"button",
|
|
7047
|
+
{
|
|
7048
|
+
type: "button",
|
|
7049
|
+
onClick: () => {
|
|
7050
|
+
setFollowUpDraft(note.followUp ?? "");
|
|
7051
|
+
setEditingFollowUp(true);
|
|
7052
|
+
},
|
|
7053
|
+
"aria-label": t("edit"),
|
|
7054
|
+
className: "qa-tap-icon qa-ms-auto qa-text-lo",
|
|
7055
|
+
style: { background: "transparent", border: "none", cursor: "pointer" },
|
|
7056
|
+
children: /* @__PURE__ */ jsx(Icon, { name: "Pencil", size: 11 })
|
|
7057
|
+
}
|
|
7058
|
+
)
|
|
7059
|
+
] }),
|
|
7060
|
+
/* @__PURE__ */ jsx("p", { className: "qa-mt-1 qa-whitespace-pre-wrap qa-break-words qa-text-xs qa-text-hi", children: note.followUp })
|
|
7061
|
+
] }) : /* @__PURE__ */ jsxs(
|
|
7062
|
+
"button",
|
|
7063
|
+
{
|
|
7064
|
+
type: "button",
|
|
7065
|
+
onClick: () => {
|
|
7066
|
+
setFollowUpDraft("");
|
|
7067
|
+
setEditingFollowUp(true);
|
|
7068
|
+
},
|
|
7069
|
+
className: "qa-tap qa-inline-flex qa-items-center qa-gap-1 qa-text-11 qa-font-medium qa-text-accent",
|
|
7070
|
+
style: { background: "transparent", border: "none", cursor: "pointer" },
|
|
7071
|
+
children: [
|
|
7072
|
+
/* @__PURE__ */ jsx(Icon, { name: "Plus", size: 12 }),
|
|
7073
|
+
t("followup_add")
|
|
7074
|
+
]
|
|
7075
|
+
}
|
|
7076
|
+
)
|
|
7077
|
+
}
|
|
7078
|
+
)
|
|
6934
7079
|
] })
|
|
6935
7080
|
]
|
|
6936
7081
|
}
|
|
@@ -7163,8 +7308,11 @@ function FilterChip({ chip }) {
|
|
|
7163
7308
|
);
|
|
7164
7309
|
}
|
|
7165
7310
|
function NoteFilterBar() {
|
|
7166
|
-
const { filter, setFilter, noteCounts, notes, t } = useQa();
|
|
7311
|
+
const { filter, setFilter, noteCounts, notes, deleteNotes, t } = useQa();
|
|
7312
|
+
const [confirmPrune, setConfirmPrune] = useState(false);
|
|
7167
7313
|
if (notes.length < 3) return null;
|
|
7314
|
+
const others = notes.filter((n) => (n.status ?? "open") !== "fixed");
|
|
7315
|
+
const showPrune = filter.status === "fixed" && noteCounts.fixed > 0 && others.length > 0;
|
|
7168
7316
|
const sev = (key) => () => setFilter({ severity: filter.severity === key ? "all" : key });
|
|
7169
7317
|
const stat = (key) => () => setFilter({ status: filter.status === key ? "all" : key });
|
|
7170
7318
|
const chips = [
|
|
@@ -7269,7 +7417,48 @@ function NoteFilterBar() {
|
|
|
7269
7417
|
]
|
|
7270
7418
|
}
|
|
7271
7419
|
),
|
|
7272
|
-
/* @__PURE__ */ jsx("div", { className: "qa-flex qa-flex-wrap qa-gap-1", children: chips.map((chip) => /* @__PURE__ */ jsx(FilterChip, { chip }, chip.key)) })
|
|
7420
|
+
/* @__PURE__ */ jsx("div", { className: "qa-flex qa-flex-wrap qa-gap-1", children: chips.map((chip) => /* @__PURE__ */ jsx(FilterChip, { chip }, chip.key)) }),
|
|
7421
|
+
showPrune && /* @__PURE__ */ jsx("div", { className: "qa-text-11", "data-qa-prune": "true", children: confirmPrune ? /* @__PURE__ */ jsxs("span", { className: "qa-text-mid", children: [
|
|
7422
|
+
t("keep_only_retest_q", { n: others.length }),
|
|
7423
|
+
" ",
|
|
7424
|
+
/* @__PURE__ */ jsx(
|
|
7425
|
+
"button",
|
|
7426
|
+
{
|
|
7427
|
+
type: "button",
|
|
7428
|
+
onClick: () => {
|
|
7429
|
+
void deleteNotes(others.map((n) => n.id));
|
|
7430
|
+
setConfirmPrune(false);
|
|
7431
|
+
},
|
|
7432
|
+
className: "qa-font-semibold qa-text-danger qa-tap",
|
|
7433
|
+
style: { background: "transparent", border: "none", cursor: "pointer" },
|
|
7434
|
+
children: t("yes")
|
|
7435
|
+
}
|
|
7436
|
+
),
|
|
7437
|
+
" / ",
|
|
7438
|
+
/* @__PURE__ */ jsx(
|
|
7439
|
+
"button",
|
|
7440
|
+
{
|
|
7441
|
+
type: "button",
|
|
7442
|
+
onClick: () => setConfirmPrune(false),
|
|
7443
|
+
className: "qa-text-accent qa-tap",
|
|
7444
|
+
style: { background: "transparent", border: "none", cursor: "pointer" },
|
|
7445
|
+
children: t("no")
|
|
7446
|
+
}
|
|
7447
|
+
)
|
|
7448
|
+
] }) : /* @__PURE__ */ jsxs(
|
|
7449
|
+
"button",
|
|
7450
|
+
{
|
|
7451
|
+
type: "button",
|
|
7452
|
+
onClick: () => setConfirmPrune(true),
|
|
7453
|
+
title: t("keep_only_retest_hint"),
|
|
7454
|
+
className: "qa-tap qa-inline-flex qa-items-center qa-gap-1 qa-text-lo",
|
|
7455
|
+
style: { background: "transparent", border: "none", cursor: "pointer" },
|
|
7456
|
+
children: [
|
|
7457
|
+
/* @__PURE__ */ jsx(Icon, { name: "Trash", size: 11 }),
|
|
7458
|
+
t("keep_only_retest", { n: noteCounts.fixed })
|
|
7459
|
+
]
|
|
7460
|
+
}
|
|
7461
|
+
) })
|
|
7273
7462
|
] });
|
|
7274
7463
|
}
|
|
7275
7464
|
function Section({
|
|
@@ -7805,249 +7994,9 @@ function CredentialsSection() {
|
|
|
7805
7994
|
})
|
|
7806
7995
|
] });
|
|
7807
7996
|
}
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
group,
|
|
7812
|
-
checked,
|
|
7813
|
-
toggle,
|
|
7814
|
-
pick: pick2,
|
|
7815
|
-
onWalkFrom
|
|
7816
|
-
}) {
|
|
7817
|
-
const { lang, t, guideFailed, evidenceByStep } = useQa();
|
|
7818
|
-
const { id, color = DEFAULT_LANE_COLOR, steps: steps2 } = group;
|
|
7819
|
-
const done = steps2.filter((s) => checked.has(keyOf(id, s.path))).length;
|
|
7820
|
-
const pct = steps2.length > 0 ? Math.round(done / steps2.length * 100) : 0;
|
|
7821
|
-
const uncoveredRedCount = steps2.filter(
|
|
7822
|
-
(s) => s.risk === "red" && !checked.has(keyOf(id, s.path))
|
|
7823
|
-
).length;
|
|
7824
|
-
return /* @__PURE__ */ jsxs("div", { className: "qa-rounded-xl qa-border qa-border-subtle qa-bg-2 qa-p-3 qa-elev-1", children: [
|
|
7825
|
-
/* @__PURE__ */ jsxs("div", { className: "qa-mb-2 qa-flex qa-items-center qa-gap-2", children: [
|
|
7826
|
-
/* @__PURE__ */ jsx(
|
|
7827
|
-
"span",
|
|
7828
|
-
{
|
|
7829
|
-
className: "qa-h-2.5 qa-w-2.5 qa-rounded-full",
|
|
7830
|
-
style: { background: color }
|
|
7831
|
-
}
|
|
7832
|
-
),
|
|
7833
|
-
/* @__PURE__ */ jsx("span", { className: "qa-text-sm qa-font-bold qa-text-hi", children: pick2(group.role) }),
|
|
7834
|
-
/* @__PURE__ */ jsxs("span", { className: "qa-ms-auto qa-text-11 qa-font-medium qa-text-slate-400", children: [
|
|
7835
|
-
done,
|
|
7836
|
-
"/",
|
|
7837
|
-
steps2.length
|
|
7838
|
-
] }),
|
|
7839
|
-
uncoveredRedCount > 0 && /* @__PURE__ */ jsx(
|
|
7840
|
-
"span",
|
|
7841
|
-
{
|
|
7842
|
-
className: "qa-bg-danger-tint qa-text-danger qa-rounded qa-px-1 qa-text-10 qa-font-medium",
|
|
7843
|
-
title: lang === "ar" ? `${uncoveredRedCount} \u0645\u0646\u0637\u0642\u0629 \u062D\u0645\u0631\u0627\u0621 \u063A\u064A\u0631 \u0645\u063A\u0637\u0627\u0629` : `${uncoveredRedCount} uncovered red zone(s)`,
|
|
7844
|
-
children: lang === "ar" ? `\u0623\u062D\u0645\u0631: ${uncoveredRedCount}` : `red: ${uncoveredRedCount}`
|
|
7845
|
-
}
|
|
7846
|
-
)
|
|
7847
|
-
] }),
|
|
7848
|
-
/* @__PURE__ */ jsx(
|
|
7849
|
-
"div",
|
|
7850
|
-
{
|
|
7851
|
-
className: "qa-mb-3 qa-h-1.5 qa-overflow-hidden qa-rounded-full",
|
|
7852
|
-
style: { background: `${color}22` },
|
|
7853
|
-
children: /* @__PURE__ */ jsx(
|
|
7854
|
-
"div",
|
|
7855
|
-
{
|
|
7856
|
-
className: "qa-h-full qa-rounded-full qa-transition-all",
|
|
7857
|
-
style: { width: `${pct}%`, background: color }
|
|
7858
|
-
}
|
|
7859
|
-
)
|
|
7860
|
-
}
|
|
7861
|
-
),
|
|
7862
|
-
/* @__PURE__ */ jsxs("ol", { className: "qa-relative qa-ms-1.5", children: [
|
|
7863
|
-
/* @__PURE__ */ jsx(
|
|
7864
|
-
"span",
|
|
7865
|
-
{
|
|
7866
|
-
className: "qa-absolute qa-top-1 qa-bottom-0 qa-w-px",
|
|
7867
|
-
style: { insetInlineStart: "7px", background: `${color}40`, bottom: "4px" }
|
|
7868
|
-
}
|
|
7869
|
-
),
|
|
7870
|
-
steps2.map((s, i) => {
|
|
7871
|
-
const k = keyOf(id, s.path);
|
|
7872
|
-
const on = checked.has(k);
|
|
7873
|
-
const failed = guideFailed.has(k);
|
|
7874
|
-
const evidence = evidenceByStep.get(k);
|
|
7875
|
-
const evidenceCount = evidence ? evidence.length : 0;
|
|
7876
|
-
const riskColor = s.risk ? RISK_COLORS[s.risk] : RISK_COLORS.none;
|
|
7877
|
-
const dotTitle = !s.risk ? lang === "ar" ? "\u0644\u0645 \u064A\u062A\u0645 \u062A\u0642\u064A\u064A\u0645 \u0627\u0644\u0645\u062E\u0627\u0637\u0631 \u0628\u0639\u062F" : "not graded yet" : s.riskWhy ?? s.risk;
|
|
7878
|
-
return /* @__PURE__ */ jsxs("li", { className: "qa-relative qa-mb-2 qa-last-mb-0", children: [
|
|
7879
|
-
/* @__PURE__ */ jsx(
|
|
7880
|
-
"button",
|
|
7881
|
-
{
|
|
7882
|
-
onClick: () => onWalkFrom(k),
|
|
7883
|
-
title: t("walk_take_me", { path: s.path }),
|
|
7884
|
-
"aria-label": t("walk_take_me", { path: s.path }),
|
|
7885
|
-
className: "qa-tap-icon qa-absolute qa-rounded-lg qa-text-mid qa-hover-text-slate-600",
|
|
7886
|
-
style: {
|
|
7887
|
-
top: 0,
|
|
7888
|
-
insetInlineEnd: 0,
|
|
7889
|
-
background: "transparent",
|
|
7890
|
-
border: "none",
|
|
7891
|
-
cursor: "pointer",
|
|
7892
|
-
zIndex: 2
|
|
7893
|
-
},
|
|
7894
|
-
children: /* @__PURE__ */ jsx(Icon, { name: "Play", size: 12 })
|
|
7895
|
-
}
|
|
7896
|
-
),
|
|
7897
|
-
/* @__PURE__ */ jsxs(
|
|
7898
|
-
"button",
|
|
7899
|
-
{
|
|
7900
|
-
onClick: () => toggle(k),
|
|
7901
|
-
className: `qa-flex qa-w-full qa-items-start qa-gap-2.5 qa-rounded-lg qa-p-1 qa-text-start qa-hover-bg-black-3${failed ? " qa-bg-danger-tint" : ""}`,
|
|
7902
|
-
style: { background: failed ? void 0 : "transparent", border: "none", cursor: "pointer" },
|
|
7903
|
-
children: [
|
|
7904
|
-
/* @__PURE__ */ jsxs(
|
|
7905
|
-
"span",
|
|
7906
|
-
{
|
|
7907
|
-
className: "qa-relative qa-z-1 qa-mt-0.5 qa-flex qa-h-4 qa-w-4 qa-shrink-0 qa-items-center qa-justify-center qa-rounded-full qa-border-2 qa-transition",
|
|
7908
|
-
style: {
|
|
7909
|
-
borderColor: failed ? "var(--qa-danger)" : color,
|
|
7910
|
-
background: on ? color : failed ? "var(--qa-danger-tint)" : "var(--qa-surface-1)",
|
|
7911
|
-
zIndex: 1
|
|
7912
|
-
},
|
|
7913
|
-
children: [
|
|
7914
|
-
on && /* @__PURE__ */ jsx(Icon, { name: "Check", size: 10, strokeWidth: 3, className: "qa-text-white" }),
|
|
7915
|
-
!on && failed && /* @__PURE__ */ jsx(Icon, { name: "AlertTriangle", size: 9, strokeWidth: 2.5, className: "qa-text-danger" })
|
|
7916
|
-
]
|
|
7917
|
-
}
|
|
7918
|
-
),
|
|
7919
|
-
/* @__PURE__ */ jsxs("span", { className: "qa-min-w-0", children: [
|
|
7920
|
-
/* @__PURE__ */ jsxs("span", { className: "qa-flex qa-items-center qa-gap-1", children: [
|
|
7921
|
-
/* @__PURE__ */ jsx(
|
|
7922
|
-
"code",
|
|
7923
|
-
{
|
|
7924
|
-
className: "qa-rounded qa-px-1 qa-text-11 qa-font-semibold qa-dir-ltr qa-text-hi",
|
|
7925
|
-
style: {
|
|
7926
|
-
background: failed ? "var(--qa-danger-tint)" : `${color}14`,
|
|
7927
|
-
textDecoration: on ? "line-through" : "none",
|
|
7928
|
-
opacity: on ? 0.55 : 1
|
|
7929
|
-
},
|
|
7930
|
-
children: s.path
|
|
7931
|
-
}
|
|
7932
|
-
),
|
|
7933
|
-
/* @__PURE__ */ jsx(
|
|
7934
|
-
"span",
|
|
7935
|
-
{
|
|
7936
|
-
className: "qa-inline-block qa-rounded-full qa-shrink-0",
|
|
7937
|
-
style: {
|
|
7938
|
-
width: "6px",
|
|
7939
|
-
height: "6px",
|
|
7940
|
-
background: riskColor,
|
|
7941
|
-
flexShrink: 0
|
|
7942
|
-
},
|
|
7943
|
-
title: dotTitle
|
|
7944
|
-
}
|
|
7945
|
-
)
|
|
7946
|
-
] }),
|
|
7947
|
-
/* @__PURE__ */ jsx(
|
|
7948
|
-
"span",
|
|
7949
|
-
{
|
|
7950
|
-
className: "qa-mt-0.5 qa-block qa-text-11 qa-leading-relaxed qa-text-slate-500",
|
|
7951
|
-
style: { opacity: on ? 0.5 : 1 },
|
|
7952
|
-
children: pick2(s.what)
|
|
7953
|
-
}
|
|
7954
|
-
),
|
|
7955
|
-
evidenceCount > 0 && /* @__PURE__ */ jsx("span", { className: "qa-mt-1 qa-inline-flex qa-items-center qa-rounded qa-bg-accent-tint qa-text-accent qa-px-1 qa-text-10 qa-font-medium", children: t("evidence_n", { n: evidenceCount }) }),
|
|
7956
|
-
evidenceCount === 0 && on && /* @__PURE__ */ jsx("span", { className: "qa-mt-1 qa-inline-flex qa-items-center qa-rounded qa-bg-warn-tint qa-text-warn qa-px-1 qa-text-10 qa-font-medium", children: t("no_evidence") })
|
|
7957
|
-
] })
|
|
7958
|
-
]
|
|
7959
|
-
}
|
|
7960
|
-
)
|
|
7961
|
-
] }, `${k}-${i}`);
|
|
7962
|
-
})
|
|
7963
|
-
] })
|
|
7964
|
-
] });
|
|
7965
|
-
}
|
|
7966
|
-
function GuideSection() {
|
|
7967
|
-
const {
|
|
7968
|
-
guideChecked,
|
|
7969
|
-
toggleGuide,
|
|
7970
|
-
t,
|
|
7971
|
-
journey,
|
|
7972
|
-
journeyIsGeneric,
|
|
7973
|
-
pick: pick2,
|
|
7974
|
-
lang,
|
|
7975
|
-
startTestAlong,
|
|
7976
|
-
startWalk,
|
|
7977
|
-
testAlongSteps
|
|
7978
|
-
} = useQa();
|
|
7979
|
-
const all = journey.flatMap((g) => g.steps.map((s) => keyOf(g.id, s.path)));
|
|
7980
|
-
const done = all.filter((k) => guideChecked.has(k)).length;
|
|
7981
|
-
const pct = all.length > 0 ? Math.round(done / all.length * 100) : 0;
|
|
7982
|
-
const coverage = computeCoverage(journey, guideChecked);
|
|
7983
|
-
return /* @__PURE__ */ jsxs("div", { className: "qa-space-y-3", children: [
|
|
7984
|
-
journeyIsGeneric && /* @__PURE__ */ jsx(
|
|
7985
|
-
"p",
|
|
7986
|
-
{
|
|
7987
|
-
className: "qa-m-0 qa-rounded-xl qa-border qa-border-dashed qa-border-subtle qa-p-2 qa-text-10 qa-text-mid qa-leading-relaxed",
|
|
7988
|
-
"data-qa-generic-plan": "true",
|
|
7989
|
-
children: t("journey_generic")
|
|
7990
|
-
}
|
|
7991
|
-
),
|
|
7992
|
-
/* @__PURE__ */ jsxs("div", { className: "qa-rounded-xl qa-border qa-border-accent qa-bg-accent-tint qa-p-3 qa-elev-1", children: [
|
|
7993
|
-
coverage.red.total > 0 && /* @__PURE__ */ jsxs("div", { className: "qa-mb-1 qa-flex qa-items-center qa-gap-1.5 qa-text-11", children: [
|
|
7994
|
-
/* @__PURE__ */ jsx("span", { className: "qa-bg-danger-tint qa-text-danger qa-rounded qa-px-1 qa-font-bold", children: lang === "ar" ? "\u0623\u062D\u0645\u0631" : "RED" }),
|
|
7995
|
-
/* @__PURE__ */ jsxs("span", { className: "qa-dir-ltr qa-font-semibold qa-text-hi", children: [
|
|
7996
|
-
coverage.red.covered,
|
|
7997
|
-
"/",
|
|
7998
|
-
coverage.red.total,
|
|
7999
|
-
" ",
|
|
8000
|
-
lang === "ar" ? "\u0645\u063A\u0637\u0649" : "covered"
|
|
8001
|
-
] })
|
|
8002
|
-
] }),
|
|
8003
|
-
/* @__PURE__ */ jsxs("div", { className: "qa-flex qa-items-center qa-justify-between qa-text-sm qa-font-semibold qa-text-hi", children: [
|
|
8004
|
-
/* @__PURE__ */ jsx("span", { children: t("journey_title") }),
|
|
8005
|
-
/* @__PURE__ */ jsxs("span", { className: "qa-dir-ltr", children: [
|
|
8006
|
-
done,
|
|
8007
|
-
"/",
|
|
8008
|
-
all.length,
|
|
8009
|
-
" \xB7 ",
|
|
8010
|
-
pct,
|
|
8011
|
-
"%"
|
|
8012
|
-
] })
|
|
8013
|
-
] }),
|
|
8014
|
-
/* @__PURE__ */ jsx("div", { className: "qa-mt-2 qa-h-2 qa-overflow-hidden qa-rounded-full qa-bg-3", children: /* @__PURE__ */ jsx(
|
|
8015
|
-
"div",
|
|
8016
|
-
{
|
|
8017
|
-
className: "qa-h-full qa-rounded-full qa-bg-accent qa-transition-all",
|
|
8018
|
-
style: { width: `${pct}%` }
|
|
8019
|
-
}
|
|
8020
|
-
) }),
|
|
8021
|
-
/* @__PURE__ */ jsx("div", { className: "qa-mt-2 qa-flex qa-justify-end", children: /* @__PURE__ */ jsxs(
|
|
8022
|
-
"button",
|
|
8023
|
-
{
|
|
8024
|
-
type: "button",
|
|
8025
|
-
onClick: startTestAlong,
|
|
8026
|
-
disabled: all.length === 0,
|
|
8027
|
-
className: "qa-tap qa-inline-flex qa-items-center qa-gap-1.5 qa-rounded-full qa-bg-accent qa-border-0 qa-cursor-pointer qa-px-3 qa-py-1 qa-text-xs qa-font-semibold qa-focus-ring",
|
|
8028
|
-
children: [
|
|
8029
|
-
/* @__PURE__ */ jsx(Icon, { name: "Play", size: 13 }),
|
|
8030
|
-
t("start_walkthrough")
|
|
8031
|
-
]
|
|
8032
|
-
}
|
|
8033
|
-
) })
|
|
8034
|
-
] }),
|
|
8035
|
-
journey.map((g) => /* @__PURE__ */ jsx(
|
|
8036
|
-
Lane,
|
|
8037
|
-
{
|
|
8038
|
-
group: g,
|
|
8039
|
-
checked: guideChecked,
|
|
8040
|
-
toggle: toggleGuide,
|
|
8041
|
-
onWalkFrom: (key) => {
|
|
8042
|
-
const at = testAlongSteps.findIndex((step) => step.key === key);
|
|
8043
|
-
startWalk("plan", at === -1 ? 0 : at);
|
|
8044
|
-
},
|
|
8045
|
-
pick: pick2
|
|
8046
|
-
},
|
|
8047
|
-
g.id
|
|
8048
|
-
))
|
|
8049
|
-
] });
|
|
8050
|
-
}
|
|
7997
|
+
|
|
7998
|
+
// src/lib/features.ts
|
|
7999
|
+
var GUIDE_TAB_ENABLED = false;
|
|
8051
8000
|
function isCoarsePointer() {
|
|
8052
8001
|
if (typeof window === "undefined") return false;
|
|
8053
8002
|
try {
|
|
@@ -8071,11 +8020,15 @@ function useCoarsePointer() {
|
|
|
8071
8020
|
}, []);
|
|
8072
8021
|
return coarse;
|
|
8073
8022
|
}
|
|
8074
|
-
var
|
|
8023
|
+
var ALL_TABS = [
|
|
8075
8024
|
{ key: "notes", labelKey: "tab_notes", icon: "StickyNote" },
|
|
8076
8025
|
{ key: "logins", labelKey: "tab_logins", icon: "KeyRound" },
|
|
8077
8026
|
{ key: "guide", labelKey: "tab_guide", icon: "Map" }
|
|
8078
8027
|
];
|
|
8028
|
+
var TABS = ALL_TABS.filter((tab) => tab.key !== "guide" || GUIDE_TAB_ENABLED);
|
|
8029
|
+
function visibleTab(tab) {
|
|
8030
|
+
return tab === "guide" && !GUIDE_TAB_ENABLED ? "notes" : tab;
|
|
8031
|
+
}
|
|
8079
8032
|
function todayName() {
|
|
8080
8033
|
return `qa-notes-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}`;
|
|
8081
8034
|
}
|
|
@@ -8110,7 +8063,7 @@ var PANEL_TRANSITION_WITH_LIFT = "opacity 200ms cubic-bezier(0.4,0,0.2,1), trans
|
|
|
8110
8063
|
function QaPanel() {
|
|
8111
8064
|
const {
|
|
8112
8065
|
isOpen,
|
|
8113
|
-
activeTab,
|
|
8066
|
+
activeTab: storedTab,
|
|
8114
8067
|
setActiveTab,
|
|
8115
8068
|
notes,
|
|
8116
8069
|
exportZip,
|
|
@@ -8141,6 +8094,7 @@ function QaPanel() {
|
|
|
8141
8094
|
panelCollapsed,
|
|
8142
8095
|
setPanelCollapsed
|
|
8143
8096
|
} = useQa();
|
|
8097
|
+
const activeTab = visibleTab(storedTab);
|
|
8144
8098
|
const [confirmClear, setConfirmClear] = useState(false);
|
|
8145
8099
|
const [naming, setNaming] = useState(false);
|
|
8146
8100
|
const [filename, setFilename] = useState("");
|
|
@@ -8508,7 +8462,7 @@ function QaPanel() {
|
|
|
8508
8462
|
) })
|
|
8509
8463
|
] }),
|
|
8510
8464
|
!simpleMode && activeTab === "logins" && /* @__PURE__ */ jsx(CredentialsSection, {}),
|
|
8511
|
-
!simpleMode &&
|
|
8465
|
+
!simpleMode && GUIDE_TAB_ENABLED
|
|
8512
8466
|
] })
|
|
8513
8467
|
] }),
|
|
8514
8468
|
settingsOpen && /* @__PURE__ */ jsx(SettingsSheet, { onClose: () => setSettingsOpen(false) }),
|
|
@@ -10365,5 +10319,5 @@ function Qapture({ config }) {
|
|
|
10365
10319
|
}
|
|
10366
10320
|
|
|
10367
10321
|
export { Qapture, deleteQaDatabase, initQaStudio };
|
|
10368
|
-
//# sourceMappingURL=chunk-
|
|
10369
|
-
//# sourceMappingURL=chunk-
|
|
10322
|
+
//# sourceMappingURL=chunk-2JX7YU2P.js.map
|
|
10323
|
+
//# sourceMappingURL=chunk-2JX7YU2P.js.map
|