Skip to content

Commit fd16768

Browse files
author
DavidQ
committed
Rename saved session row action to clarify diff and merge usage - PR 11.249
1 parent f811366 commit fd16768

3 files changed

Lines changed: 181 additions & 2 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# PR_11_249 — Session Library Row Action Label Clarification
2+
3+
## Summary
4+
Renamed the saved Session Library row action from `Use in Library` to `Use in Diff/Merge` while keeping Recent Sessions row action unchanged as `Use in Library`.
5+
6+
## Files Changed
7+
- `tools/workspace-v2/index.js`
8+
- `tests/runtime/V2SessionLibraryActionLabel.test.mjs`
9+
10+
## Changes Implemented
11+
- Saved Session Library rows now render:
12+
- `Use in Diff/Merge`
13+
- Recent Sessions rows continue to render:
14+
- `Use in Library`
15+
- Saved-row behavior remains PR_11_248 behavior:
16+
- populate Session ID textbox
17+
- fill Session A if empty
18+
- else fill Session B if empty
19+
- do not overwrite when both selected
20+
- do not duplicate same session across A/B
21+
- immediately re-run selection/button enable-state logic
22+
- Updated saved-row status wording for clarity:
23+
- `Saved session ID ready for Diff/Merge and Library actions: ...`
24+
25+
## Validation Commands Run
26+
```powershell
27+
node --check tools/workspace-v2/index.js
28+
node --check tests/runtime/V2SessionLibraryActionLabel.test.mjs
29+
node tests/runtime/V2SessionLibraryActionLabel.test.mjs
30+
```
31+
32+
## Validation Results
33+
- `node --check tools/workspace-v2/index.js` -> PASS
34+
- `node --check tests/runtime/V2SessionLibraryActionLabel.test.mjs` -> PASS
35+
- `node tests/runtime/V2SessionLibraryActionLabel.test.mjs` -> PASS
36+
- output: `tmp/v2-session-library-action-label-results.json`
37+
- failures: `[]`
38+
39+
## Verified Outcomes
40+
- Session Library rows show `Use in Diff/Merge` -> PASS
41+
- Recent Sessions rows still show `Use in Library` -> PASS
42+
- Saved-row action fills A/B slots correctly -> PASS
43+
- Recent-row action remains textbox-oriented behavior -> PASS
44+
- Diff/Merge button state updates after saved-row action -> PASS
45+
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import assert from "node:assert/strict";
2+
import fs from "node:fs";
3+
import path from "node:path";
4+
import { execFileSync } from "node:child_process";
5+
import { fileURLToPath, pathToFileURL } from "node:url";
6+
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = path.dirname(__filename);
9+
const repoRoot = path.resolve(__dirname, "..", "..");
10+
const jsPath = path.join(repoRoot, "tools", "workspace-v2", "index.js");
11+
const resultsPath = path.join(repoRoot, "tmp", "v2-session-library-action-label-results.json");
12+
13+
function checkSyntax(filePath) {
14+
try {
15+
execFileSync(process.execPath, ["--check", filePath], {
16+
cwd: repoRoot,
17+
stdio: ["ignore", "pipe", "pipe"]
18+
});
19+
return { ok: true, error: "" };
20+
} catch (error) {
21+
return { ok: false, error: (error?.stderr || error?.stdout || error?.message || "").toString().trim() };
22+
}
23+
}
24+
25+
function findById(candidates, id) {
26+
return candidates.find((entry) => entry.id === id) || null;
27+
}
28+
29+
function findByContext(candidates, contextId) {
30+
return candidates.find((entry) => entry.contextId === contextId) || null;
31+
}
32+
33+
function syncSlots(state, contextId) {
34+
const selected = findByContext(state.candidates, contextId);
35+
if (!selected) return false;
36+
const left = findById(state.candidates, state.left);
37+
const right = findById(state.candidates, state.right);
38+
if (!left) {
39+
if (right && right.id === selected.id) return false;
40+
state.left = selected.id;
41+
return true;
42+
}
43+
if (!right) {
44+
if (left.id === selected.id) return false;
45+
state.right = selected.id;
46+
return true;
47+
}
48+
return false;
49+
}
50+
51+
function canRun(left, right, candidates) {
52+
const leftEntry = findById(candidates, left);
53+
const rightEntry = findById(candidates, right);
54+
return Boolean(leftEntry && rightEntry && leftEntry.id !== rightEntry.id);
55+
}
56+
57+
export function run() {
58+
const failures = [];
59+
const jsExists = fs.existsSync(jsPath);
60+
const js = jsExists ? fs.readFileSync(jsPath, "utf8") : "";
61+
const jsSyntax = checkSyntax(jsPath);
62+
const testSyntax = checkSyntax(path.join(repoRoot, "tests", "runtime", "V2SessionLibraryActionLabel.test.mjs"));
63+
64+
if (!jsExists) failures.push("Missing tools/workspace-v2/index.js.");
65+
if (!jsSyntax.ok) failures.push("tools/workspace-v2/index.js failed syntax check.");
66+
if (!testSyntax.ok) failures.push("tests/runtime/V2SessionLibraryActionLabel.test.mjs failed syntax check.");
67+
68+
if (!js.includes("useInLibraryButton.textContent = \"Use in Diff/Merge\";")) {
69+
failures.push("Saved Session Library row action label was not renamed to Use in Diff/Merge.");
70+
}
71+
if (!js.includes("useInLibraryButton.textContent = \"Use in Library\";")) {
72+
failures.push("Recent Sessions row action label should remain Use in Library.");
73+
}
74+
if (!js.includes("Saved session ID ready for Diff/Merge and Library actions:")) {
75+
failures.push("Saved-row status/help text was not updated for Diff/Merge clarity.");
76+
}
77+
78+
const candidates = [
79+
{ id: "library:a", contextId: "a" },
80+
{ id: "library:b", contextId: "b" }
81+
];
82+
const state = { candidates, left: "", right: "" };
83+
syncSlots(state, "a");
84+
if (state.left !== "library:a" || state.right !== "") {
85+
failures.push("Saved-row Use in Diff/Merge should fill Session A first.");
86+
}
87+
syncSlots(state, "b");
88+
if (state.left !== "library:a" || state.right !== "library:b") {
89+
failures.push("Saved-row Use in Diff/Merge should fill Session B second.");
90+
}
91+
const beforeThird = JSON.stringify(state);
92+
syncSlots(state, "a");
93+
if (JSON.stringify(state) !== beforeThird) {
94+
failures.push("Saved-row Use in Diff/Merge should not duplicate same session across A/B.");
95+
}
96+
if (!canRun(state.left, state.right, candidates)) {
97+
failures.push("Diff/Merge should be enabled after valid A/B selection from saved-row action.");
98+
}
99+
100+
const recentActionOnlyTextbox =
101+
js.includes("useSessionIdInLibraryInput(hostContextId)") &&
102+
js.includes("this.sessionNameNode.value = hostContextId.trim();") &&
103+
!js.includes("useSessionIdInLibraryInput(hostContextId);\n this.syncDiffAndMergeSelectionSlotsFromContextId");
104+
if (!recentActionOnlyTextbox) {
105+
failures.push("Recent Use in Library behavior should remain textbox population only.");
106+
}
107+
108+
fs.mkdirSync(path.dirname(resultsPath), { recursive: true });
109+
fs.writeFileSync(resultsPath, `${JSON.stringify({
110+
generatedAt: new Date().toISOString(),
111+
failures,
112+
checks: {
113+
jsExists,
114+
jsSyntax,
115+
testSyntax
116+
},
117+
state
118+
}, null, 2)}\n`, "utf8");
119+
120+
console.log(`v2 session-library action-label results: ${resultsPath}`);
121+
assert.equal(failures.length, 0, `V2 session-library action-label failures: ${failures.join(" | ")}`);
122+
return { failures };
123+
}
124+
125+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
126+
try {
127+
const summary = run();
128+
console.log(JSON.stringify(summary, null, 2));
129+
} catch (error) {
130+
console.error(error);
131+
process.exitCode = 1;
132+
}
133+
}
134+

tools/workspace-v2/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ class WorkspaceV2SessionProducer {
457457
this.copySavedSessionIdToClipboard(sessionName);
458458
});
459459
useInLibraryButton.type = "button";
460-
useInLibraryButton.textContent = "Use in Library";
460+
useInLibraryButton.textContent = "Use in Diff/Merge";
461461
useInLibraryButton.addEventListener("click", () => {
462462
this.useSavedSessionIdInLibraryInput(sessionName);
463463
});
@@ -502,7 +502,7 @@ class WorkspaceV2SessionProducer {
502502
}
503503
this.sessionNameNode.value = sessionId.trim();
504504
this.syncDiffAndMergeSelectionSlotsFromContextId(sessionId.trim());
505-
this.setLibraryStatus(`Saved session ID ready for Library actions: ${sessionId.trim()}`);
505+
this.setLibraryStatus(`Saved session ID ready for Diff/Merge and Library actions: ${sessionId.trim()}`);
506506
}
507507

508508
loadSavedSessionById(sessionId) {

0 commit comments

Comments
 (0)