fix: harden responsive accessibility contracts
This commit is contained in:
+3
-3
@@ -120,14 +120,14 @@ e89b54e7e3174b4b0a1dcd9058d8344e29431f9d16d0e6bb8d11559b691440a0 2508
|
||||
afef3841a3948b2121f8fba809aae4ea3da71bd2fda86973ba50200a5b1f89b2 14894 src/main/ssh-service.cjs
|
||||
80426e8bdd7259c6ed47d1acb9f6cbbbe4b1075f74c8ce5fd759044d9af09d59 149912 src/main/unraid-deployment-service.cjs
|
||||
b654a9e45044ad32c61fabe4a6d897288615ec83739b53e3241ff881e32f56bd 21677 src/main/update-service.cjs
|
||||
7c0ed496051f33a65312f7acf132eb288ca8260ce4b0b1d4b6f607c1cfac4071 240362 src/renderer/app.js
|
||||
953b027fedcee2c2396ec5c8cf938013f2630d8ef76ab5e917a02d723303234f 241018 src/renderer/app.js
|
||||
16efd2fca83004f781eae40ae0f706a004ce0bddf338dd087b8adf7eb10c1d84 85704 src/renderer/assets/itworx-mark.png
|
||||
813b8cdeecac43794166f3db9d3c5d2c441e0292f9ab7bd465ba136d6201e95d 82476 src/renderer/assets/itworx-wordmark-dark.png
|
||||
094c1b71cc2482a9db250ac175f45f3de68f53277dfbde371a03e61923d00988 75240 src/renderer/assets/itworx-wordmark-light.png
|
||||
813b8cdeecac43794166f3db9d3c5d2c441e0292f9ab7bd465ba136d6201e95d 82476 src/renderer/assets/itworx-wordmark.png
|
||||
fb7ed47f9aac50d9259d7d3c3bb2010c7bfdd2fe8e8e47ca2744bb22f0057d54 830 src/renderer/index.html
|
||||
ae8d6778614077c5f46032035a10fb9803219c14e8bfabefacf1affdec06fb71 62802 src/renderer/mock-bridge.js
|
||||
34ee56ed08dcd1c2295985b9bb419b981598a2699ee8e65394d86f4177f4797b 77647 src/renderer/styles.css
|
||||
45692591428575b518678a6b548c25d3de95f568541e5648b0f06f42c48b5bbf 77872 src/renderer/styles.css
|
||||
0a1e9d9d6cd4d190eb7f85dbc6668d80600b1cf2749cc0c2c51cc428f506f20d 1121 src/shared/clone-target.cjs
|
||||
5d425d5c2f939d0f6beebee7ebb0c77146cb7e318535ba7286ec7081a4dc2269 2497 src/shared/deployment-policy.cjs
|
||||
029e600229714d033c28e2dcb77817aa8269847001782ae0012960e83ffd183f 3057 src/shared/git-status.cjs
|
||||
@@ -156,7 +156,7 @@ e7aebcc0d484a6a59d463d5cb26c11b3ad56e28f6535e7c38a0fe166a41565ea 13690
|
||||
caf98cbd9de9b119dae610ee53fa333a7a11214f34762247452fbb85e8bbf725 2392 tests/log-redaction.test.mjs
|
||||
96432a97d313f331694900bf0a2c21e38c20eac96d59147977aeed9055a9e3ad 2287 tests/partial-staging.test.mjs
|
||||
c0f8f5a3784835f19d9ff1015185ccb385840b6fa1c9ec19f233393a7d952b65 3718 tests/preflight.test.mjs
|
||||
15e05220fd282895b02ea52ceaa38327a61297af8db1484e6d9964e8b03a8fea 9156 tests/renderer-workflow.test.mjs
|
||||
69a86fd630425227bf1e1881fe9b2c8db39a694310948a33cd4074c801326c92 9807 tests/renderer-workflow.test.mjs
|
||||
2b4956fa4df4624a04117737e57ba74020564330ff71303b5746d8ccc881e880 854 tests/repository-matching.test.mjs
|
||||
f679072548554a64974f0452337ce5e7b0c567343c287223770cc0974b905348 1068 tests/repository-monitor.test.mjs
|
||||
75b5b83836c75675bb9a48fe4363fcb8a24fc425e6af6f822d7955c6f3c79eac 2265 tests/repository-service.test.mjs
|
||||
|
||||
+12
-2
@@ -686,7 +686,7 @@ function renderTitlebar() {
|
||||
return `<header class="titlebar">
|
||||
<div class="titlebar-left"><div class="wordmark"><img class="brand-logo" src="./assets/itworx-mark.png" alt="ITWorx.tech"/><span>ForgeFlow</span><small>by ITWorx.tech</small></div><span class="workspace-name">${escapeHtml(title)}</span></div>
|
||||
<div class="titlebar-right">
|
||||
<button class="command-trigger" data-action="open-palette">${icon("search")}<span>Commands</span><kbd>Ctrl K</kbd></button>
|
||||
<button class="command-trigger" data-action="open-palette" aria-label="Open command palette">${icon("search")}<span>Commands</span><kbd>Ctrl K</kbd></button>
|
||||
<div class="search-wrap">${icon("search")}<input id="global-search" class="global-search" value="${attr(ui.search)}" placeholder="Search repositories…" aria-label="Search repositories" /></div>
|
||||
<span class="connection-chip" title="${connected ? `Connected as ${attr(user?.login || "user")}` : "Not connected"}"><span class="dot" style="${connected ? "" : "background:var(--danger)"}"></span>${connected ? escapeHtml(user?.login || "Gitea") : "Offline"}</span>
|
||||
<button class="icon-button" data-action="refresh" title="Refresh repositories">${icon("refresh")}</button>
|
||||
@@ -1208,7 +1208,7 @@ function renderServerInventory() {
|
||||
const candidate = linked
|
||||
? `Linked to ${workload.link?.repositoryFullName || "repository"}`
|
||||
: topCandidate
|
||||
? `${topCandidate.repositoryFullName} suggested · ${topCandidate.confidence}`
|
||||
? `${topCandidate.repositoryFullName} suggested · ${topCandidate.confidence || topCandidate.status || "review required"}`
|
||||
: "No repository candidate; select one manually";
|
||||
const canQuickLink = !linked && topCandidate && ["exact", "strong"].includes(topCandidate.confidence) && Boolean(workload.remoteFolderCandidate);
|
||||
const linkButton = canQuickLink
|
||||
@@ -1618,6 +1618,16 @@ function enhanceRenderedUi() {
|
||||
`<section class="section-block"><div class="section-heading"><div><h2>Operational audit log</h2><span class="meta">Append-only release, pull-request and recovery events</span></div><div class="stack horizontal compact"><button class="button" data-action="load-audit-log">Refresh</button><button class="button" data-action="export-audit-json">Export JSON</button><button class="button" data-action="export-audit-csv">Export CSV</button></div></div><div class="panel">${ui.auditEvents.length ? `<table class="data-table"><thead><tr><th>Time</th><th>Event</th><th>Repository</th><th>Result</th></tr></thead><tbody>${ui.auditEvents.map((item) => `<tr><td>${formatDate(item.timestamp)}</td><td>${escapeHtml(item.event)}</td><td>${escapeHtml(item.details?.repository || "—")}</td><td>${escapeHtml(item.details?.result || item.details?.note || "—")}</td></tr>`).join("")}</tbody></table>` : '<div class="empty-state compact"><p>Load the operational audit log.</p></div>'}</div></section>`,
|
||||
);
|
||||
}
|
||||
document.querySelectorAll("button.icon-button:not([aria-label])").forEach((button) => {
|
||||
const action = String(button.title || button.dataset.action || "Action").replaceAll("-", " ");
|
||||
button.setAttribute("aria-label", action.charAt(0).toUpperCase() + action.slice(1));
|
||||
});
|
||||
document.querySelectorAll(".field > label:not([for])").forEach((label, index) => {
|
||||
const control = label.parentElement?.querySelector("input, select, textarea");
|
||||
if (!control) return;
|
||||
if (!control.id) control.id = `forgeflow-field-${index}`;
|
||||
label.htmlFor = control.id;
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
|
||||
@@ -2818,6 +2818,14 @@ kbd {
|
||||
color: var(--text-faint);
|
||||
font-size: 10px;
|
||||
}
|
||||
.action-panel-body .panel-callout > h2,
|
||||
.action-panel-body .panel-callout > p {
|
||||
display: none;
|
||||
}
|
||||
@media (max-height: 760px) {
|
||||
.palette-backdrop { padding-top: 3vh; }
|
||||
.palette-list { max-height: calc(100vh - 150px); }
|
||||
}
|
||||
.discovery-progress {
|
||||
min-height: 260px;
|
||||
display: grid;
|
||||
|
||||
@@ -265,3 +265,13 @@ test("Git Validator exposes scored best-practice checks and bounded repairs", as
|
||||
assert.match(preload, /gitValidatorScan/);
|
||||
assert.match(preload, /gitValidatorRepair/);
|
||||
});
|
||||
|
||||
test("renderer guards accessible names, labels and uncertain inventory evidence", async () => {
|
||||
const renderer = await readFile(new URL("../src/renderer/app.js", import.meta.url), "utf8");
|
||||
const styles = await readFile(new URL("../src/renderer/styles.css", import.meta.url), "utf8");
|
||||
assert.match(renderer, /button\.icon-button:not\(\[aria-label\]\)/);
|
||||
assert.match(renderer, /\.field > label:not\(\[for\]\)/);
|
||||
assert.match(renderer, /topCandidate\.confidence \|\| topCandidate\.status \|\| "review required"/);
|
||||
assert.match(styles, /\.action-panel-body \.panel-callout > h2/);
|
||||
assert.match(styles, /@media \(max-height: 760px\)/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user