Skip to content

Commit 4ab1ad4

Browse files
author
DavidQ
committed
Load Palette Manager V2 sample preset JSON from launch URL into active palette state - PR_26124_076-palette-manager-url-preset-load
1 parent ddfaa70 commit 4ab1ad4

11 files changed

Lines changed: 478 additions & 366 deletions

File tree

docs/dev/codex_commands.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
1-
# Codex Commands - PR_26124_075-palette-browser-launch-registration-fix
1+
# Codex Commands - PR_26124_076-palette-manager-url-preset-load
22

33
```bash
4-
npx @openai/codex run --model gpt-5.5 --reasoning high "Run full workflow for PR_26124_075-palette-browser-launch-registration-fix. Follow PROJECT_INSTRUCTIONS.md exactly."
4+
npx @openai/codex run --model gpt-5.5 --reasoning high "Run full workflow for PR_26124_076-palette-manager-url-preset-load. Follow PROJECT_INSTRUCTIONS.md exactly."
55
```
66

77
## Validation Commands
88

99
```bash
10-
node --input-type=module <sample metadata registry validation>
11-
node --input-type=module <targeted Samples index launch validation>
10+
node --check tools/palette-manager-v2/main.js
11+
node --check tools/palette-manager-v2/modules/PaletteManagerApp.js
12+
node --check tools/palette-manager-v2/modules/PaletteValidationService.js
13+
node tests/tools/PaletteManagerV2Baseline.test.mjs
14+
node --input-type=module <targeted Palette Manager V2 URL preset validation>
1215
git diff --check
1316
npm run test:workspace-v2
1417
npm run codex:review-artifacts
1518
```
1619

1720
## Playwright
1821

19-
Targeted Samples index launch validation confirms palette-backed samples no longer render `Tool "palette-browser" is not registered in toolRegistry.` and their launch links resolve to Palette Manager V2.
22+
Targeted Palette Manager V2 validation confirms the tool baseline still loads and that a `samplePresetPath` URL loads sample palette JSON into active Palette Manager V2 state.
2023

2124
`npm run test:workspace-v2` failed because `package.json` does not define the `test:workspace-v2` script.
2225

docs/dev/commit_comment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Fix Palette Manager V2 sample launch registration id - PR_26124_075-palette-browser-launch-registration-fix
1+
Load Palette Manager V2 sample presets from URL params - PR_26124_076-palette-manager-url-preset-load
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# PR_26124_076 Palette Manager URL Preset Load Report
2+
3+
## Scope
4+
- `tools/palette-manager-v2/main.js`
5+
- `tools/palette-manager-v2/modules/PaletteManagerApp.js`
6+
- `tools/palette-manager-v2/modules/PaletteValidationService.js`
7+
- PR workflow docs and review artifacts.
8+
9+
## Result
10+
Palette Manager V2 reads `samplePresetPath` on startup, fetches the referenced sample palette JSON, validates through the same import path used by manual JSON import, and renders the loaded swatches in User Palette and Palette JSON.
11+
12+
## Data Handling
13+
- Direct sample palette documents are accepted when they contain top-level `swatches`.
14+
- Swatches are cloned before normalization.
15+
- Missing direct swatch `source` values are filled from direct palette metadata such as `sourceId`.
16+
- The incoming sample JSON object is not mutated.
17+
- Existing wrapped `tools.palette-browser` import/export JSON remains supported.
18+
19+
## Validation
20+
- PASS: changed JavaScript syntax checks.
21+
- PASS: existing Palette Manager V2 Playwright baseline.
22+
- PASS: targeted URL preset validation for sample `0219`.
23+
- PASS: targeted invalid URL preset failure validation.
24+
- PASS: `git diff --check`.
25+
- FAIL: `npm run test:workspace-v2` because `package.json` does not define `test:workspace-v2`.
26+
- SKIPPED: full samples smoke test by instruction.
27+
28+
## Manual Validation
29+
Open Palette Manager V2 with:
30+
31+
`/tools/palette-manager-v2/index.html?sampleId=0219&sampleTitle=Sprite%20Atlas%20Image%20Rendering&samplePresetPath=/samples/phase-02/0219/sample.0219.palette.json`
32+
33+
Expected:
34+
- User Palette shows the six sample swatches.
35+
- Palette JSON shows `tools.palette-browser.swatches`.
36+
- Status indicates the sample preset loaded.
Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
# git status --short
2-
M docs/dev/codex_commands.md
3-
M docs/dev/commit_comment.txt
4-
A docs/dev/reports/PR_26124_075_report.md
5-
A docs/pr/PR_26124_075-palette-browser-launch-registration-fix/APPLY_PR.md
6-
A docs/pr/PR_26124_075-palette-browser-launch-registration-fix/BUILD_PR.md
7-
A docs/pr/PR_26124_075-palette-browser-launch-registration-fix/PLAN_PR.md
8-
M samples/metadata/samples.index.metadata.json
2+
M docs/dev/codex_commands.md
3+
M docs/dev/commit_comment.txt
4+
M tools/palette-manager-v2/main.js
5+
M tools/palette-manager-v2/modules/PaletteManagerApp.js
6+
M tools/palette-manager-v2/modules/PaletteValidationService.js
7+
?? docs/dev/reports/PR_26124_076_report.md
8+
?? docs/pr/PR_26124_076-palette-manager-url-preset-load/
99

1010
# git diff --stat
11-
(no output)
11+
docs/dev/codex_commands.md | 13 +++--
12+
docs/dev/commit_comment.txt | 2 +-
13+
tools/palette-manager-v2/main.js | 67 ++++++++++++++++++++++
14+
.../modules/PaletteManagerApp.js | 13 +++--
15+
.../modules/PaletteValidationService.js | 29 +++++++++-
16+
5 files changed, 109 insertions(+), 15 deletions(-)

docs/dev/reports/codex_review.diff

Lines changed: 199 additions & 343 deletions
Large diffs are not rendered by default.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# APPLY_PR - PR_26124_076-palette-manager-url-preset-load
2+
3+
## Summary
4+
Palette Manager V2 now loads sample palette JSON from a `samplePresetPath` URL parameter during startup.
5+
6+
## Applied Changes
7+
- Added startup URL parameter handling in `tools/palette-manager-v2/main.js`.
8+
- Fetches `samplePresetPath` when present and reports visible fetch/JSON failures.
9+
- Reuses `PaletteManagerApp.importPaletteDocument` for URL-loaded preset JSON.
10+
- Extended `PaletteValidationService.extractImportedPaletteDocument` to accept:
11+
- existing wrapped `tools.palette-browser` import/export JSON,
12+
- direct sample palette documents with top-level `swatches`.
13+
- Direct sample palette swatches are cloned and given missing `source` from palette metadata before validation.
14+
- Manual Import JSON behavior remains unchanged.
15+
16+
## Runtime/Data Result
17+
- Launching Palette Manager V2 with sample `0219` URL parameters loads `sample.0219.palette.json` into active Palette Manager V2 memory.
18+
- User Palette renders the loaded sample swatches.
19+
- Palette JSON renders the loaded swatches under `tools.palette-browser`.
20+
- Incoming sample JSON is not mutated.
21+
- Failed fetch or schema validation shows a clear Validation/Error Viewer message and does not silently fallback.
22+
23+
## Validation
24+
- PASS: `node --check tools/palette-manager-v2/main.js`
25+
- PASS: `node --check tools/palette-manager-v2/modules/PaletteManagerApp.js`
26+
- PASS: `node --check tools/palette-manager-v2/modules/PaletteValidationService.js`
27+
- PASS: `node tests/tools/PaletteManagerV2Baseline.test.mjs`
28+
- PASS: targeted Palette Manager V2 URL preset validation for sample `0219`
29+
- PASS: targeted invalid `samplePresetPath` validation shows fetch failure
30+
- PASS: `git diff --check`
31+
- FAIL: `npm run test:workspace-v2` is unavailable because `package.json` does not define a `test:workspace-v2` script.
32+
- SKIPPED: full samples smoke test, by instruction.
33+
34+
## Manual Test
35+
1. Open `/tools/palette-manager-v2/index.html?sampleId=0219&sampleTitle=Sprite%20Atlas%20Image%20Rendering&samplePresetPath=/samples/phase-02/0219/sample.0219.palette.json`.
36+
2. Confirm User Palette contains six sample swatches.
37+
3. Confirm Palette JSON shows `tools.palette-browser.swatches`.
38+
4. Confirm status says the sample preset loaded.
39+
5. Open `/tools/palette-manager-v2/index.html?samplePresetPath=/samples/missing-palette.json`.
40+
6. Confirm Validation/Error Viewer shows a sample preset fetch failure.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# BUILD_PR - PR_26124_076-palette-manager-url-preset-load
2+
3+
## Purpose
4+
Add one scoped Palette Manager V2 startup path that loads and validates sample palette JSON from the `samplePresetPath` URL parameter.
5+
6+
## Scope
7+
- `tools/palette-manager-v2/main.js`
8+
- `tools/palette-manager-v2/modules/PaletteManagerApp.js`
9+
- `tools/palette-manager-v2/modules/PaletteValidationService.js`
10+
- Required PR workflow docs and review artifacts.
11+
12+
## Implementation
13+
1. Add startup URL parameter handling in `main.js`.
14+
2. If `samplePresetPath` is absent, preserve current startup behavior.
15+
3. If `samplePresetPath` is present:
16+
- fetch the JSON path,
17+
- reject failed fetches with a visible validation/error message,
18+
- reject invalid JSON with a visible validation/error message,
19+
- pass parsed JSON to `PaletteManagerApp.importPaletteDocument`.
20+
4. Extend `PaletteValidationService.extractImportedPaletteDocument` so it still accepts wrapped `tools.palette-browser` import JSON and also accepts direct sample palette documents with top-level `swatches`.
21+
5. For direct sample palette documents, clone swatches and populate missing `source` from direct palette metadata before validation; do not mutate the incoming JSON object.
22+
6. Add optional status text parameters to import/reject methods only where needed for startup preset messages.
23+
7. Preserve manual Import JSON behavior and existing export shape.
24+
25+
## Boundaries
26+
- Do not modify workspace/toolState behavior.
27+
- Do not touch sample JSON.
28+
- Do not modify `tools/shared`.
29+
- Do not add fallback/default data.
30+
- Do not add dependencies.
31+
- Do not modify Palette Manager CSS or layout.
32+
- Do not run the full samples smoke test.
33+
34+
## Validation
35+
- Syntax check changed JavaScript files.
36+
- Run targeted Palette Manager V2 Playwright baseline test if present.
37+
- Run targeted URL preset load validation for sample `0219`.
38+
- Run `npm run test:workspace-v2`.
39+
- Run `git diff --check`.
40+
- Skip the full samples smoke test.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# PLAN_PR - PR_26124_076-palette-manager-url-preset-load
2+
3+
## Goal
4+
Load a Palette Manager V2 sample preset when the tool opens with a `samplePresetPath` URL parameter.
5+
6+
## Scope
7+
- `tools/palette-manager-v2/main.js`
8+
- `tools/palette-manager-v2/modules/PaletteManagerApp.js`
9+
- `tools/palette-manager-v2/modules/PaletteValidationService.js`
10+
- Required PR workflow docs and review artifacts.
11+
12+
## Boundaries
13+
- Do not modify workspace/toolState behavior.
14+
- Do not touch sample JSON.
15+
- Do not modify `tools/shared`.
16+
- Do not add fallback/default data.
17+
- Do not add dependencies.
18+
- Do not run the full samples smoke test.
19+
20+
## Implementation Plan
21+
1. Read `URLSearchParams` during Palette Manager V2 startup.
22+
2. When `samplePresetPath` exists, fetch that JSON path.
23+
3. Reject fetch, JSON parse, and schema failures with clear Validation/Error Viewer messages.
24+
4. Reuse the same Palette Manager import validation path used by manual JSON import.
25+
5. Accept direct sample palette documents with top-level `swatches` by normalizing cloned swatches into the active Palette Manager swatch contract without mutating the incoming JSON.
26+
6. Render User Palette, Palette JSON, and validation state from the loaded preset.
27+
7. Preserve manual Import JSON behavior.
28+
29+
## Playwright
30+
- Targeted Palette Manager V2 Playwright validates baseline tool loading and existing palette behaviors.
31+
- Targeted URL preset validation loads sample `0219` through `samplePresetPath` and checks that User Palette and Palette JSON reflect the fetched preset.
32+
- Expected pass behavior: sample preset swatches render in Palette Manager V2 with no runtime errors.
33+
- Expected fail behavior: fetch or validation failure appears in the Validation/Error Viewer and the app does not silently fallback.
34+
- Default requested gate: `npm run test:workspace-v2`
35+
36+
## Manual Validation
37+
1. Open `/tools/palette-manager-v2/index.html?sampleId=0219&sampleTitle=Sprite%20Atlas%20Image%20Rendering&samplePresetPath=/samples/phase-02/0219/sample.0219.palette.json`.
38+
2. Confirm User Palette contains the sample palette swatches.
39+
3. Confirm Palette JSON contains `tools.palette-browser.swatches`.
40+
4. Confirm status indicates the sample preset loaded.
41+
5. Open the same tool with an invalid `samplePresetPath` and confirm a clear validation/error message is shown.

tools/palette-manager-v2/main.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,72 @@ function reportBootstrapError(error) {
1818
console.error(error);
1919
}
2020

21+
function normalizeSamplePresetPath(samplePresetPath) {
22+
const cleanPath = typeof samplePresetPath === "string"
23+
? samplePresetPath.trim().replace(/\\/g, "/")
24+
: "";
25+
if (!cleanPath || cleanPath.includes("..") || !cleanPath.startsWith("/samples/")) {
26+
return "";
27+
}
28+
return cleanPath;
29+
}
30+
31+
function getSamplePresetLabel(searchParams, samplePresetPath) {
32+
const sampleId = (searchParams.get("sampleId") || "").trim();
33+
const sampleTitle = (searchParams.get("sampleTitle") || "").trim();
34+
if (sampleId && sampleTitle) {
35+
return `sample ${sampleId} (${sampleTitle})`;
36+
}
37+
if (sampleId) {
38+
return `sample ${sampleId}`;
39+
}
40+
if (sampleTitle) {
41+
return sampleTitle;
42+
}
43+
return samplePresetPath;
44+
}
45+
46+
async function loadSamplePresetFromUrl(app) {
47+
const searchParams = new URLSearchParams(window.location.search);
48+
const samplePresetPath = searchParams.get("samplePresetPath");
49+
if (!samplePresetPath) {
50+
return;
51+
}
52+
53+
const presetPath = normalizeSamplePresetPath(samplePresetPath);
54+
if (!presetPath) {
55+
app.rejectImport([`samplePresetPath is invalid: ${samplePresetPath}`], "Sample preset load failed.");
56+
return;
57+
}
58+
59+
let response;
60+
try {
61+
response = await fetch(presetPath, { cache: "no-store" });
62+
} catch (error) {
63+
const message = error instanceof Error ? error.message : String(error);
64+
app.rejectImport([`Sample preset fetch failed for ${presetPath}: ${message}`], "Sample preset load failed.");
65+
return;
66+
}
67+
68+
if (!response.ok) {
69+
app.rejectImport([`Sample preset fetch failed (${response.status}) for ${presetPath}.`], "Sample preset load failed.");
70+
return;
71+
}
72+
73+
let documentValue;
74+
try {
75+
documentValue = await response.json();
76+
} catch {
77+
app.rejectImport([`Sample preset is not valid JSON: ${presetPath}.`], "Sample preset load failed.");
78+
return;
79+
}
80+
81+
app.importPaletteDocument(documentValue, {
82+
failureStatus: "Sample preset load failed.",
83+
successStatus: `Loaded ${getSamplePresetLabel(searchParams, presetPath)} palette preset.`
84+
});
85+
}
86+
2187
try {
2288
const app = new PaletteManagerApp({
2389
documentRef: document,
@@ -27,6 +93,7 @@ try {
2793
});
2894
app.init();
2995
window.paletteManagerV2App = app.getPublicApi();
96+
void loadSamplePresetFromUrl(app);
3097
} catch (error) {
3198
reportBootstrapError(error);
3299
}

tools/palette-manager-v2/modules/PaletteManagerApp.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -998,15 +998,15 @@ export class PaletteManagerApp {
998998
});
999999
}
10001000

1001-
rejectImport(errors) {
1002-
this.setActionState(errors, "Import rejected.");
1001+
rejectImport(errors, status = "Import rejected.") {
1002+
this.setActionState(errors, status);
10031003
}
10041004

1005-
importPaletteDocument(documentValue) {
1005+
importPaletteDocument(documentValue, options = {}) {
10061006
const importResult = this.validator.extractImportedPaletteDocument(documentValue);
10071007
if (importResult.errors.length > 0) {
1008-
this.setActionState(importResult.errors, "Import rejected.");
1009-
return;
1008+
this.setActionState(importResult.errors, sanitizeText(options.failureStatus) || "Import rejected.");
1009+
return false;
10101010
}
10111011

10121012
this.state.userSwatches = importResult.swatches.map(cloneSwatch);
@@ -1015,7 +1015,8 @@ export class PaletteManagerApp {
10151015
this.checkedUserSwatchIndexes.clear();
10161016
this.editorControl.clearForm();
10171017
this.resetHistorySnapshot();
1018-
this.setActionState([], `Imported ${this.state.userSwatches.length} user swatches.`);
1018+
this.setActionState([], sanitizeText(options.successStatus) || `Imported ${this.state.userSwatches.length} user swatches.`);
1019+
return true;
10191020
}
10201021

10211022
preparePaletteDocument(blockedStatus) {

0 commit comments

Comments
 (0)