Files
FabledCurator/extension/options/options.html
T
Claude 8214afee1e
CI / lint (push) Successful in 3s
extension / lint (push) Successful in 38s
CI / frontend-build (push) Successful in 40s
CI / backend-lint-and-test (push) Successful in 2m58s
CI / integration (push) Successful in 4m56s
fix(extension): normalize FC URL so credential push doesn't 405
The stored apiUrl was required to already carry the `/api` suffix, since
api.js builds requests as `${baseUrl}/credentials`. The options label read
"FC base URL", so entering the instance root -- the natural reading --
sent every request one path segment short: POST /credentials hit the Vue
SPA catch-all and came back 405, and GET /extension/manifest 404'd.

Worse, Test Connection reported success on it: the catch-all answers GET
/credentials with 200 HTML, so `r.ok` was true and the only affordance
meant to catch this misconfiguration actively masked it.

Normalize instead of validate (rules 92, 26):

- New lib/url.js: normalizeApiUrl / webRootFromApiUrl, one source shared
  by the background client and the options page. Accepts either the
  instance root or the API root.
- api.js normalizes on read, so configs already stored in the broken form
  heal themselves without the operator reopening Settings.
- options.js stores the canonical form, echoes back what it saved, and
  the test now asserts a JSON content-type -- killing the false green.
- 404/405 in request() now names the URL and points at the setting.
- Options label/placeholder state that both forms work.

Version 1.0.9 -> 1.0.10 in BOTH manifest.json and package.json; build.yml
resolves the release version from package.json, and a stale value there
would hit the cached ext-1.0.9 asset and republish the old XPI unsigned
against the new code.

Refs #2393

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 19:37:38 -04:00

46 lines
1.9 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>FabledCurator — Settings</title>
<style>
body { font: 14px/1.4 system-ui, sans-serif; max-width: 520px; margin: 32px auto; padding: 0 16px; }
h1 { font-family: Georgia, serif; font-size: 20px; }
label { display: block; font-weight: 500; margin: 16px 0 6px; }
input { width: 100%; padding: 8px; box-sizing: border-box; font: inherit; }
.hint { color: #666; font-size: 12px; margin-top: 4px; }
.row { display: flex; gap: 8px; margin-top: 16px; }
button { padding: 8px 16px; cursor: pointer; font: inherit; }
button.primary { background: #F4BA7A; color: #14171A; border: none; border-radius: 4px; }
button.test { background: none; border: 1px solid #ccc; border-radius: 4px; }
.status { margin-top: 16px; padding: 8px 12px; border-radius: 4px; }
.status.ok { background: #DFF5DF; color: #2B6A2B; }
.status.err { background: #FBE1E1; color: #862525; }
</style>
</head>
<body>
<h1>FabledCurator extension</h1>
<label for="api-url">FC instance URL</label>
<input id="api-url" type="url" placeholder="http://curator.example.com" />
<div class="hint">
Your FabledCurator address — with or without the trailing <code>/api</code>; both work.
Find it on FC → Settings → Maintenance → Browser extension.
</div>
<label for="api-key">Extension API key</label>
<input id="api-key" type="password" placeholder="paste from FC Settings card" />
<div class="hint">Generate or rotate on FC → Settings → Maintenance → Browser extension.</div>
<div class="row">
<button class="primary" id="save-btn">Save</button>
<button class="test" id="test-btn">Test connection</button>
</div>
<div id="status" class="status" style="display:none;"></div>
<script src="../lib/url.js"></script>
<script src="options.js"></script>
</body>
</html>