Skip to content

Commit c5b44c1

Browse files
committed
PR_26175_CHARLIE_015-manual-health-actions
1 parent 850dbfe commit c5b44c1

15 files changed

Lines changed: 838 additions & 288 deletions

admin/system-health.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ <h2>Admin</h2>
4242
<p>Environment Map</p>
4343
<p>Service Health</p>
4444
<p>Configuration Summary</p>
45+
<p>Manual Health Actions</p>
4546
<p>Local API Startup</p>
4647
<p>Database Health</p>
4748
<p>Storage Health</p>
@@ -132,6 +133,35 @@ <h4>Loading</h4>
132133
</tbody>
133134
</table>
134135
</div>
136+
<section class="content-stack" aria-label="Manual health actions">
137+
<div>
138+
<div class="kicker">Current Deployment</div>
139+
<h3>Manual Health Actions</h3>
140+
</div>
141+
<div class="content-cluster">
142+
<button class="btn btn--compact" type="button" data-admin-system-health-action="refresh">Refresh</button>
143+
<button class="btn btn--compact" type="button" data-admin-system-health-action="runtime-check">Run Runtime Check</button>
144+
<button class="btn btn--compact" type="button" data-admin-system-health-action="database-check">Run Database Check</button>
145+
<button class="btn btn--compact" type="button" data-admin-system-health-action="storage-check">Run Storage Check</button>
146+
<button class="btn btn--compact" type="button" data-admin-system-health-action="full-health-check">Run Full Health Check</button>
147+
</div>
148+
<div class="table-wrapper">
149+
<table class="data-table" aria-label="Manual health action results">
150+
<caption>Manual Health Action Results</caption>
151+
<thead>
152+
<tr>
153+
<th scope="col">Action</th>
154+
<th scope="col">Last Checked</th>
155+
<th scope="col">Status</th>
156+
<th scope="col">Result</th>
157+
</tr>
158+
</thead>
159+
<tbody data-admin-system-health-action-rows>
160+
<tr><td>Manual health actions</td><td>not run</td><td data-health-status="PENDING" title="Reason: no manual health action has run yet." aria-label="PENDING: no manual health action has run yet.">PENDING</td><td>Waiting for Admin action.</td></tr>
161+
</tbody>
162+
</table>
163+
</div>
164+
</section>
135165
<div class="table-wrapper">
136166
<table class="data-table" aria-label="Local API startup diagnostics">
137167
<caption>Local API Startup Diagnostics</caption>

assets/theme-v2/js/admin-system-health.js

Lines changed: 102 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
readAdminSystemHealthStatus,
3+
runAdminSystemHealthAction,
34
runAdminSystemHealthStorageConnectivityAction,
45
} from "../../../src/api/admin-system-health-api-client.js";
56
import {
@@ -15,6 +16,7 @@ const STORAGE_DIAGNOSTIC_ACTIONS = Object.freeze([
1516
Object.freeze({ actionId: "storage-read-test-object", key: "read" }),
1617
Object.freeze({ actionId: "storage-delete-test-object", key: "delete" }),
1718
]);
19+
const STORAGE_DIAGNOSTIC_ACTION_KEY_BY_ID = new Map(STORAGE_DIAGNOSTIC_ACTIONS.map((action) => [action.actionId, action.key]));
1820

1921
function asText(value, fallback = "not available") {
2022
return statusText(value, fallback);
@@ -61,6 +63,8 @@ class AdminSystemHealthController {
6163
node,
6264
]));
6365
this.historyRows = root.querySelector("[data-admin-system-health-history-rows]");
66+
this.actionRows = root.querySelector("[data-admin-system-health-action-rows]");
67+
this.actionButtons = Array.from(root.querySelectorAll("[data-admin-system-health-action]"));
6468
this.configurationRows = root.querySelector("[data-admin-system-health-configuration-rows]");
6569
this.serviceCards = root.querySelector("[data-admin-system-health-service-cards]");
6670
this.startupRows = root.querySelector("[data-admin-system-health-startup-rows]");
@@ -71,6 +75,7 @@ class AdminSystemHealthController {
7175
if ((!this.environmentValues.size && !this.dbValues.size && !this.storageValues.size) || document.querySelector("[data-session-access-blocked='admin']") || window.GameFoundrySessionGuard?.blocked === true) {
7276
return;
7377
}
78+
this.bindManualActions();
7479
this.load();
7580
}
7681

@@ -141,6 +146,20 @@ class AdminSystemHealthController {
141146
this.renderHistoryPending(reason);
142147
}
143148

149+
bindManualActions() {
150+
this.actionButtons.forEach((button) => {
151+
button.addEventListener("click", () => {
152+
this.runManualHealthAction(button.dataset.adminSystemHealthAction);
153+
});
154+
});
155+
}
156+
157+
setManualActionsDisabled(disabled) {
158+
this.actionButtons.forEach((button) => {
159+
button.disabled = disabled;
160+
});
161+
}
162+
144163
renderEnvironmentIdentity(environmentIdentity = {}) {
145164
const reason = environmentIdentity.message || "Current deployment environment identity returned by the safe Admin System Health API.";
146165
this.setEnvironmentValue("name", environmentIdentity.name, "Unknown");
@@ -447,6 +466,71 @@ class AdminSystemHealthController {
447466
return cell;
448467
}
449468

469+
renderManualActionResult(result = {}) {
470+
if (!this.actionRows) {
471+
return;
472+
}
473+
const blocked = result?.secretsExposed === true || result?.secretEditingAllowed === true;
474+
const row = document.createElement("tr");
475+
row.append(
476+
this.createCell(result.label || "Manual health action"),
477+
this.createCell(result.checkedAt || result.lastChecked || "not available"),
478+
this.createStatusCell(blocked ? "PENDING" : result.status, blocked ? "Safe manual action response was blocked because it exposed secret controls." : result.message),
479+
this.createCell(blocked ? "Safe manual action response was blocked." : result.message),
480+
);
481+
this.actionRows.replaceChildren(row);
482+
}
483+
484+
applyManualActionResult(result = {}) {
485+
if (result.statusSnapshot) {
486+
this.renderStatusData(result.statusSnapshot);
487+
}
488+
if (result.runtimeHealth) {
489+
this.renderRuntimeHealth(result.runtimeHealth);
490+
}
491+
if (result.databaseStatus) {
492+
this.renderPostgresStatus(result.databaseStatus);
493+
}
494+
if (result.storageStatus) {
495+
this.renderStorageStatus(result.storageStatus);
496+
}
497+
const storageDiagnostics = Array.isArray(result.storageDiagnostics) ? result.storageDiagnostics : [];
498+
storageDiagnostics.forEach((storageResult) => {
499+
const key = STORAGE_DIAGNOSTIC_ACTION_KEY_BY_ID.get(storageResult.actionId);
500+
if (key) {
501+
this.renderStorageResult(key, storageResult);
502+
}
503+
});
504+
}
505+
506+
runManualHealthAction(actionId) {
507+
if (!actionId) {
508+
return;
509+
}
510+
this.setManualActionsDisabled(true);
511+
this.renderManualActionResult({
512+
checkedAt: new Date().toISOString(),
513+
label: "Manual health action",
514+
message: "Manual health action is running through the safe Admin System Health API.",
515+
status: "PENDING",
516+
});
517+
try {
518+
const result = runAdminSystemHealthAction(actionId);
519+
this.renderManualActionResult(result);
520+
this.applyManualActionResult(result);
521+
} catch (error) {
522+
const message = error instanceof Error ? error.message : "Safe Admin System Health action API is unavailable.";
523+
this.renderManualActionResult({
524+
checkedAt: new Date().toISOString(),
525+
label: "Manual health action",
526+
message,
527+
status: "FAIL",
528+
});
529+
} finally {
530+
this.setManualActionsDisabled(false);
531+
}
532+
}
533+
450534
renderRuntimePending(reason) {
451535
if (!this.runtimeRows) {
452536
return;
@@ -488,23 +572,27 @@ class AdminSystemHealthController {
488572
this.runtimeRows.replaceChildren(fragment);
489573
}
490574

575+
renderStatusData(data = {}) {
576+
if (data?.secretsExposed === true || data?.secretEditingAllowed === true) {
577+
this.renderPending("Safe Admin System Health API refused to render because the response exposed secret controls.");
578+
return;
579+
}
580+
this.renderEnvironmentIdentity(data?.environmentIdentity || {});
581+
this.renderPostgresStatus(data?.databaseStatus || {});
582+
this.renderStartupDiagnostics(data?.localApiStartup || {});
583+
this.renderStorageStatus(data?.storageStatus || {});
584+
this.runStorageDiagnostics();
585+
this.renderRuntimeHealth(data?.runtimeHealth || {});
586+
this.renderServiceHealth(data?.serviceHealth || {});
587+
this.renderConfigurationSummary(data?.configurationSummary || {});
588+
this.renderHealthCheckHistory(data?.healthCheckHistory || []);
589+
this.renderRuntimeEnvironment(data?.runtimeEnvironment || {});
590+
}
591+
491592
load() {
492593
try {
493594
const data = readAdminSystemHealthStatus();
494-
if (data?.secretsExposed === true || data?.secretEditingAllowed === true) {
495-
this.renderPending("Safe Admin System Health API refused to render because the response exposed secret controls.");
496-
return;
497-
}
498-
this.renderEnvironmentIdentity(data?.environmentIdentity || {});
499-
this.renderPostgresStatus(data?.databaseStatus || {});
500-
this.renderStartupDiagnostics(data?.localApiStartup || {});
501-
this.renderStorageStatus(data?.storageStatus || {});
502-
this.runStorageDiagnostics();
503-
this.renderRuntimeHealth(data?.runtimeHealth || {});
504-
this.renderServiceHealth(data?.serviceHealth || {});
505-
this.renderConfigurationSummary(data?.configurationSummary || {});
506-
this.renderHealthCheckHistory(data?.healthCheckHistory || []);
507-
this.renderRuntimeEnvironment(data?.runtimeEnvironment || {});
595+
this.renderStatusData(data);
508596
} catch (error) {
509597
const message = error instanceof Error ? error.message : "Safe Admin System Health API is unavailable.";
510598
this.renderPending(message);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# PR_26175_CHARLIE_015 Branch Validation
2+
3+
## Branch Rules
4+
5+
- PASS: Continued on `pr/26175-CHARLIE-010-system-health-history-and-closeout`.
6+
- PASS: Stacked on PR_26175_CHARLIE_014.
7+
- PASS: No merge was performed.
8+
- PASS: No rebase was performed.
9+
- PASS: No new root branch was created.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# PR_26175_CHARLIE_015 Manual Validation Notes
2+
3+
- Verified all five requested manual action controls are visible on `admin/system-health.html`.
4+
- Verified Run Runtime Check posts to `/api/admin/system-health/action`.
5+
- Verified manual action results are rendered in the action results table.
6+
- Verified storage health action is server-side and current-environment scoped.
7+
- Verified no peer environment health checks were introduced.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# PR_26175_CHARLIE_015 Requirement Checklist
2+
3+
- PASS: Added Refresh control.
4+
- PASS: Added Run Runtime Check control.
5+
- PASS: Added Run Database Check control.
6+
- PASS: Added Run Storage Check control.
7+
- PASS: Added Run Full Health Check control.
8+
- PASS: Actions call API/service contracts.
9+
- PASS: No browser-owned fake health success.
10+
- PASS: Current environment only.
11+
- PASS: Tests were updated.
12+
- PASS: Required reports were generated.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# PR_26175_CHARLIE_015 Validation Report
2+
3+
## Commands
4+
5+
- PASS: `node --check src/dev-runtime/server/local-api-router.mjs`
6+
- PASS: `node --check assets/theme-v2/js/admin-system-health.js`
7+
- PASS: `node --check src/api/admin-system-health-api-client.js`
8+
- PASS: `git diff --check`
9+
- Result: no whitespace errors; CRLF conversion warnings only.
10+
- PASS: `node --test tests/dev-runtime/AdminHealthOperations.test.mjs`
11+
- Result: 4 passed.
12+
- PASS: `npx playwright test tests/playwright/tools/AdminHealthOperationsPage.spec.mjs --workers=1 --reporter=line`
13+
- Result: 3 passed.
14+
15+
## Validation Lane
16+
17+
- Targeted System Health API/unit lane: PASS.
18+
- Targeted System Health Playwright lane: PASS.
19+
- Full samples smoke: not run; not required for this System Health-only slice.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# PR_26175_CHARLIE_015 Manual Health Actions
2+
3+
## Scope
4+
5+
Team: Charlie
6+
7+
Purpose: Add manual current-environment health action controls to Admin System Health Phase 2.
8+
9+
## Changes
10+
11+
- Added `/api/admin/system-health/action` for Refresh, Run Runtime Check, Run Database Check, Run Storage Check, and Run Full Health Check.
12+
- Added manual action buttons and an action result table to `admin/system-health.html`.
13+
- Added client API support for manual health actions.
14+
- Updated the controller so action results render only from server responses.
15+
- Updated API and Playwright System Health tests.
16+
17+
## Architecture Notes
18+
19+
- PASS: Actions call API/service contracts.
20+
- PASS: Browser does not fake successful health.
21+
- PASS: Storage action runs bucket connectivity, list, upload, read, and delete through the current deployment API.
22+
- PASS: Current environment only.
23+
- PASS: No cross-environment checks were added.
24+
25+
## Artifact
26+
27+
- `tmp/PR_26175_CHARLIE_015-manual-health-actions_delta.zip`

docs_build/dev/reports/codex_changed_files.txt

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,30 @@ M admin/system-health.html
33
M assets/theme-v2/js/admin-system-health.js
44
M docs_build/dev/reports/coverage_changed_js_guardrail.txt
55
M docs_build/dev/reports/playwright_v8_coverage_report.txt
6+
M src/api/admin-system-health-api-client.js
67
M src/dev-runtime/server/local-api-router.mjs
78
M tests/dev-runtime/AdminHealthOperations.test.mjs
89
M tests/playwright/tools/AdminHealthOperationsPage.spec.mjs
9-
?? docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary-branch-validation.md
10-
?? docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary-manual-validation-notes.md
11-
?? docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary-requirement-checklist.md
12-
?? docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary-validation.md
13-
?? docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary.md
10+
?? docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions-branch-validation.md
11+
?? docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions-manual-validation-notes.md
12+
?? docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions-requirement-checklist.md
13+
?? docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions-validation.md
14+
?? docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions.md
1415

1516
# git ls-files --others --exclude-standard
16-
docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary-branch-validation.md
17-
docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary-manual-validation-notes.md
18-
docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary-requirement-checklist.md
19-
docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary-validation.md
20-
docs_build/dev/reports/PR_26175_CHARLIE_014-configuration-summary.md
17+
docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions-branch-validation.md
18+
docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions-manual-validation-notes.md
19+
docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions-requirement-checklist.md
20+
docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions-validation.md
21+
docs_build/dev/reports/PR_26175_CHARLIE_015-manual-health-actions.md
2122

2223
# git diff --stat
23-
admin/system-health.html | 16 ++++++
24-
assets/theme-v2/js/admin-system-health.js | 42 +++++++++++++++
25-
.../dev/reports/coverage_changed_js_guardrail.txt | 2 +-
26-
.../dev/reports/playwright_v8_coverage_report.txt | 6 +--
27-
src/dev-runtime/server/local-api-router.mjs | 63 ++++++++++++++++++++++
28-
tests/dev-runtime/AdminHealthOperations.test.mjs | 16 ++++++
29-
.../tools/AdminHealthOperationsPage.spec.mjs | 10 ++++
30-
7 files changed, 151 insertions(+), 4 deletions(-)
24+
admin/system-health.html | 30 ++++++
25+
assets/theme-v2/js/admin-system-health.js | 116 ++++++++++++++++++---
26+
.../dev/reports/coverage_changed_js_guardrail.txt | 3 +-
27+
.../dev/reports/playwright_v8_coverage_report.txt | 12 ++-
28+
src/api/admin-system-health-api-client.js | 10 ++
29+
src/dev-runtime/server/local-api-router.mjs | 92 ++++++++++++++++
30+
tests/dev-runtime/AdminHealthOperations.test.mjs | 38 +++++++
31+
.../tools/AdminHealthOperationsPage.spec.mjs | 10 ++
32+
8 files changed, 291 insertions(+), 20 deletions(-)

0 commit comments

Comments
 (0)