jsgui3-server 0.0.148 → 0.0.150
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/agents/Mobile Developer.agent.md +89 -0
- package/.github/workflows/control-scan-manifest-check.yml +31 -0
- package/AGENTS.md +4 -0
- package/README.md +215 -3
- package/admin-ui/client.js +81 -51
- package/admin-ui/v1/admin_auth_service.js +197 -0
- package/admin-ui/v1/admin_user_store.js +71 -0
- package/admin-ui/v1/client.js +17 -0
- package/admin-ui/v1/controls/admin_shell.js +1399 -0
- package/admin-ui/v1/controls/group_box.js +84 -0
- package/admin-ui/v1/controls/stat_card.js +125 -0
- package/admin-ui/v1/server.js +658 -0
- package/admin-ui/v1/utils/formatters.js +68 -0
- package/dev-status.svg +139 -0
- package/docs/admin-extension-guide.md +345 -0
- package/docs/api-reference.md +301 -43
- package/docs/books/adaptive-control-improvements/01-control-candidate-matrix.md +122 -0
- package/docs/books/adaptive-control-improvements/02-tier-1-layout-playbooks.md +207 -0
- package/docs/books/adaptive-control-improvements/03-tier-2-navigation-form-overlay.md +140 -0
- package/docs/books/adaptive-control-improvements/04-cross-cutting-platform-functionality.md +141 -0
- package/docs/books/adaptive-control-improvements/05-styling-theming-density-upgrades.md +114 -0
- package/docs/books/adaptive-control-improvements/06-testing-quality-gates.md +97 -0
- package/docs/books/adaptive-control-improvements/07-delivery-roadmap-and-ownership.md +137 -0
- package/docs/books/adaptive-control-improvements/08-appendix-tier1-acceptance-and-pr-templates.md +261 -0
- package/docs/books/adaptive-control-improvements/README.md +66 -0
- package/docs/books/admin-ui-authentication/01-threat-model-and-goals.md +124 -0
- package/docs/books/admin-ui-authentication/02-session-model-and-token-model.md +75 -0
- package/docs/books/admin-ui-authentication/03-auth-middleware-patterns.md +77 -0
- package/docs/books/admin-ui-authentication/README.md +25 -0
- package/docs/books/creating-a-new-admin-ui/01-introduction-and-vision.md +130 -0
- package/docs/books/creating-a-new-admin-ui/02-architecture-and-data-flow.md +298 -0
- package/docs/books/creating-a-new-admin-ui/03-server-introspection.md +381 -0
- package/docs/books/creating-a-new-admin-ui/04-admin-module-adapter-layer.md +592 -0
- package/docs/books/creating-a-new-admin-ui/05-domain-controls-stat-cards-and-gauges.md +513 -0
- package/docs/books/creating-a-new-admin-ui/06-domain-controls-process-manager.md +544 -0
- package/docs/books/creating-a-new-admin-ui/07-domain-controls-resource-pool-inspector.md +493 -0
- package/docs/books/creating-a-new-admin-ui/08-domain-controls-route-table-and-api-explorer.md +586 -0
- package/docs/books/creating-a-new-admin-ui/09-domain-controls-log-viewer-and-activity-feed.md +490 -0
- package/docs/books/creating-a-new-admin-ui/10-domain-controls-build-status-and-bundle-inspector.md +526 -0
- package/docs/books/creating-a-new-admin-ui/11-domain-controls-configuration-panel.md +808 -0
- package/docs/books/creating-a-new-admin-ui/12-admin-shell-layout-sidebar-navigation.md +210 -0
- package/docs/books/creating-a-new-admin-ui/13-telemetry-integration.md +556 -0
- package/docs/books/creating-a-new-admin-ui/14-realtime-sse-observable-integration.md +485 -0
- package/docs/books/creating-a-new-admin-ui/15-styling-theming-aero-design-system.md +521 -0
- package/docs/books/creating-a-new-admin-ui/16-testing-and-quality-assurance.md +147 -0
- package/docs/books/creating-a-new-admin-ui/17-next-steps-process-resource-roadmap.md +356 -0
- package/docs/books/creating-a-new-admin-ui/README.md +68 -0
- package/docs/books/device-adaptive-composition/01-platform-feature-audit.md +177 -0
- package/docs/books/device-adaptive-composition/02-responsive-composition-model.md +187 -0
- package/docs/books/device-adaptive-composition/03-data-model-vs-view-model.md +231 -0
- package/docs/books/device-adaptive-composition/04-styling-theme-breakpoints.md +234 -0
- package/docs/books/device-adaptive-composition/05-showcase-app-multi-device-assessment.md +193 -0
- package/docs/books/device-adaptive-composition/06-implementation-patterns-and-apis.md +346 -0
- package/docs/books/device-adaptive-composition/07-testing-harness-and-quality-gates.md +265 -0
- package/docs/books/device-adaptive-composition/08-roadmap-and-adoption-plan.md +250 -0
- package/docs/books/device-adaptive-composition/README.md +47 -0
- package/docs/books/jsgui3-bundling-research-book/00-table-of-contents.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/01-pipeline-and-runtime-semantics.md +34 -0
- package/docs/books/jsgui3-bundling-research-book/02-javascript-bundling-core.md +36 -0
- package/docs/books/jsgui3-bundling-research-book/03-style-extraction-and-css-compilation.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/04-static-publishing-and-delivery.md +39 -0
- package/docs/books/jsgui3-bundling-research-book/05-current-limits-and-size-bloat-vectors.md +25 -0
- package/docs/books/jsgui3-bundling-research-book/06-unused-module-elimination-strategy.md +77 -0
- package/docs/books/jsgui3-bundling-research-book/07-jsgui3-html-control-and-mixin-pruning.md +63 -0
- package/docs/books/jsgui3-bundling-research-book/08-test-and-verification-methodology.md +43 -0
- package/docs/books/jsgui3-bundling-research-book/09-roadmap-and-rollout.md +42 -0
- package/docs/books/jsgui3-bundling-research-book/10-further-research-strategies-and-upgrades.md +211 -0
- package/docs/books/jsgui3-bundling-research-book/README.md +35 -0
- package/docs/bundling-system-deep-dive.md +9 -4
- package/docs/comparison-report-express-plex-cpanel.md +549 -0
- package/docs/comprehensive-documentation.md +49 -18
- package/docs/configuration-reference.md +152 -27
- package/docs/core/README.md +19 -0
- package/docs/core/jsgui3-server-core-book/00-table-of-contents.md +21 -0
- package/docs/core/jsgui3-server-core-book/01-startup-readiness-state-machine.md +41 -0
- package/docs/core/jsgui3-server-core-book/02-resource-abstraction-and-lifecycle.md +92 -0
- package/docs/core/jsgui3-server-core-book/03-resource-pool-and-event-topology.md +47 -0
- package/docs/core/jsgui3-server-core-book/04-sse-publisher-semantics.md +41 -0
- package/docs/core/jsgui3-server-core-book/05-serve-factory-resource-wiring.md +46 -0
- package/docs/core/jsgui3-server-core-book/06-e2e-testing-methodology.md +48 -0
- package/docs/core/jsgui3-server-core-book/07-defect-detection-and-hardening-loop.md +47 -0
- package/docs/designs/server-admin-interface-aero.svg +611 -0
- package/docs/publishers-guide.md +59 -4
- package/docs/resources-guide.md +184 -35
- package/docs/simple-server-api-design.md +72 -17
- package/docs/system-architecture.md +18 -14
- package/docs/troubleshooting.md +84 -53
- package/examples/controls/15) window, observable SSE/server.js +6 -1
- package/examples/controls/19) window, auto observable ui/server.js +9 -0
- package/examples/controls/20) window, task manager app/README.md +133 -0
- package/examples/controls/20) window, task manager app/client.js +797 -0
- package/examples/controls/20) window, task manager app/server.js +178 -0
- package/examples/controls/6) window, color_palette/client.js +165 -68
- package/examples/controls/9) window, date picker/client.js +362 -76
- package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +104 -83
- package/examples/jsgui3-html/06) theming/client.js +22 -1
- package/examples/jsgui3-html/10) binding-debugger/client.js +137 -1
- package/http/responders/static/Static_Route_HTTP_Responder.js +52 -34
- package/lab/experiments/capture-color-controls.js +196 -0
- package/lab/results/screenshots/color-controls/full_page.png +0 -0
- package/lab/results/screenshots/color-controls/section_1_color_grid_12x12.png +0 -0
- package/lab/results/screenshots/color-controls/section_2_color_grid_4x2.png +0 -0
- package/lab/results/screenshots/color-controls/section_3_color_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_4_palette_comparison.png +0 -0
- package/lab/results/screenshots/color-controls/section_5_raw_swatches.png +0 -0
- package/lab/results/screenshots/color-controls/section_6_optimized_crayola.png +0 -0
- package/lab/results/screenshots/color-controls/section_7_pastel_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_8_extended_144.png +0 -0
- package/lab/screenshot-utils.js +248 -0
- package/module.js +12 -0
- package/package.json +12 -2
- package/publishers/Publishers.js +4 -3
- package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +5 -5
- package/publishers/http-sse-publisher.js +341 -0
- package/resources/process-resource.js +950 -0
- package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +129 -33
- package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +18 -7
- package/resources/processors/bundlers/js/esbuild/JSGUI3_HTML_Control_Optimizer.js +829 -0
- package/resources/remote-process-resource.js +355 -0
- package/resources/server-resource-pool.js +354 -41
- package/serve-factory.js +442 -259
- package/server.js +288 -13
- package/tests/README.md +71 -4
- package/tests/admin-ui-jsgui-controls.test.js +581 -0
- package/tests/admin-ui-render.test.js +24 -0
- package/tests/assigners.test.js +56 -40
- package/tests/bundling-default-control-elimination.puppeteer.test.js +260 -0
- package/tests/configuration-validation.test.js +21 -18
- package/tests/content-analysis.test.js +7 -6
- package/tests/control-optimizer-cache-behavior.test.js +52 -0
- package/tests/control-scan-manifest-regression.test.js +144 -0
- package/tests/end-to-end.test.js +15 -14
- package/tests/error-handling.test.js +222 -179
- package/tests/fixtures/bundling-default-button-client.js +37 -0
- package/tests/fixtures/bundling-default-window-client.js +34 -0
- package/tests/fixtures/control_scan_manifest_expectations.json +48 -0
- package/tests/fixtures/resource-monitor-client.js +319 -0
- package/tests/helpers/puppeteer-e2e-harness.js +317 -0
- package/tests/http-sse-publisher.test.js +136 -0
- package/tests/performance.test.js +69 -65
- package/tests/process-resource.test.js +138 -0
- package/tests/publishers.test.js +7 -7
- package/tests/remote-process-resource.test.js +160 -0
- package/tests/sass-controls.e2e.test.js +7 -1
- package/tests/serve-resources.test.js +270 -0
- package/tests/serve.test.js +120 -50
- package/tests/server-resource-pool.test.js +106 -0
- package/tests/small-controls-bundle-size.test.js +252 -0
- package/tests/test-runner.js +14 -1
- package/tests/window-examples.puppeteer.test.js +204 -1
- package/tests/window-resource-integration.puppeteer.test.js +585 -0
- package/tests/temp_invalid.js +0 -7
- package/tests/temp_invalid_utf8.js +0 -1
- package/tests/temp_malformed.js +0 -10
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# Chapter 7: Domain Controls — Resource Pool Inspector
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Resource Pool Inspector is a table-based control that lists every resource registered in the server's `Server_Resource_Pool`. It displays resource name, type, health status, and memory usage in a structured table with sortable columns and color-coded type badges.
|
|
6
|
+
|
|
7
|
+
In the design reference, this appears as the "Resource Pool" group box on the right side of the dashboard.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Resource_Table Control
|
|
12
|
+
|
|
13
|
+
### Spec
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
{
|
|
17
|
+
__type_name: 'resource_table',
|
|
18
|
+
title: 'Resource Pool',
|
|
19
|
+
resources: { // Data from /api/admin/resources
|
|
20
|
+
total: 5,
|
|
21
|
+
running: 5,
|
|
22
|
+
items: [
|
|
23
|
+
{
|
|
24
|
+
name: 'Compiler_Babel',
|
|
25
|
+
type: 'Compiler_Resource',
|
|
26
|
+
state: 'ready',
|
|
27
|
+
memory: 42000000
|
|
28
|
+
}
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Visual Anatomy
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
┌─ Resource Pool ──────────────────────────────── [5 / 5] ─┐
|
|
38
|
+
│ │
|
|
39
|
+
│ RESOURCE TYPE STATUS MEM │
|
|
40
|
+
│ ─────────────────────────────────────────────────────── │
|
|
41
|
+
│ ■ Compiler_Babel Compiler_Resource ● Ready 42M│
|
|
42
|
+
│ ■ Compilation_Mgr Compilation_Resource ● Ready 18M│
|
|
43
|
+
│ ■ Session_Store Data_KV_Resource ● Ready 8M│
|
|
44
|
+
│ ■ Template_Pipeline Data_Transform_Res ● Ready 4M│
|
|
45
|
+
│ ■ CSS_Extractor Resource ● Ready 2M│
|
|
46
|
+
│ ─────────────────────────────────────────────────────── │
|
|
47
|
+
│ All resources initialised · Total pool memory: 74 MB │
|
|
48
|
+
└───────────────────────────────────────────────────────────┘
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Constructor
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
class Resource_Table extends jsgui.Control {
|
|
55
|
+
constructor(spec = {}) {
|
|
56
|
+
spec.__type_name = spec.__type_name || 'resource_table';
|
|
57
|
+
super(spec);
|
|
58
|
+
const { context } = this;
|
|
59
|
+
this._resources = spec.resources || { total: 0, items: [] };
|
|
60
|
+
|
|
61
|
+
const compose = () => {
|
|
62
|
+
// Group box with title and counter badge
|
|
63
|
+
const group = new Group_Box({
|
|
64
|
+
context,
|
|
65
|
+
title: spec.title || 'Resource Pool'
|
|
66
|
+
});
|
|
67
|
+
this.add(group);
|
|
68
|
+
this._group = group;
|
|
69
|
+
|
|
70
|
+
// Counter badge (top-right)
|
|
71
|
+
const counter = new controls.div({ context, class: 'resource-counter' });
|
|
72
|
+
const running = this._resources.running || 0;
|
|
73
|
+
const total = this._resources.total || 0;
|
|
74
|
+
counter.add(`${running} / ${total}`);
|
|
75
|
+
this.add(counter);
|
|
76
|
+
this._counter = counter;
|
|
77
|
+
|
|
78
|
+
// Table
|
|
79
|
+
this._render_table();
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
if (!spec.el) { compose(); }
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
_render_table() {
|
|
86
|
+
const { context } = this;
|
|
87
|
+
const items = this._resources.items || [];
|
|
88
|
+
|
|
89
|
+
// Header row
|
|
90
|
+
const header = new controls.div({ context, class: 'resource-table-header' });
|
|
91
|
+
this._group.add(header);
|
|
92
|
+
|
|
93
|
+
const columns = ['RESOURCE', 'TYPE', 'STATUS', 'MEM'];
|
|
94
|
+
columns.forEach(col => {
|
|
95
|
+
const cell = new controls.span({ context, class: 'resource-header-cell' });
|
|
96
|
+
cell.add(col);
|
|
97
|
+
header.add(cell);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Data rows
|
|
101
|
+
const body = new controls.div({ context, class: 'resource-table-body' });
|
|
102
|
+
this._group.add(body);
|
|
103
|
+
this._body = body;
|
|
104
|
+
|
|
105
|
+
items.forEach((item, i) => {
|
|
106
|
+
const row = this._create_row(item, i);
|
|
107
|
+
body.add(row);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Footer
|
|
111
|
+
const footer = new controls.div({ context, class: 'resource-table-footer' });
|
|
112
|
+
const total_mem = items.reduce((sum, r) => sum + (r.memory || 0), 0);
|
|
113
|
+
const all_ready = items.every(r =>
|
|
114
|
+
['ready', 'running', 'on'].includes(r.state)
|
|
115
|
+
);
|
|
116
|
+
footer.add(
|
|
117
|
+
all_ready
|
|
118
|
+
? `All resources initialised · Total pool memory: ${format_bytes(total_mem)}`
|
|
119
|
+
: `${items.filter(r => r.state === 'crashed').length} resource(s) need attention`
|
|
120
|
+
);
|
|
121
|
+
this._group.add(footer);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
_create_row(item, index) {
|
|
125
|
+
const { context } = this;
|
|
126
|
+
const row = new controls.div({ context, class: 'resource-row' });
|
|
127
|
+
|
|
128
|
+
// Type badge (colored square)
|
|
129
|
+
const type_badge = new controls.span({
|
|
130
|
+
context,
|
|
131
|
+
class: `resource-type-badge badge-color-${index % 5}`
|
|
132
|
+
});
|
|
133
|
+
row.add(type_badge);
|
|
134
|
+
|
|
135
|
+
// Name
|
|
136
|
+
const name_cell = new controls.span({ context, class: 'resource-name' });
|
|
137
|
+
name_cell.add(item.name || 'Unnamed');
|
|
138
|
+
row.add(name_cell);
|
|
139
|
+
|
|
140
|
+
// Type
|
|
141
|
+
const type_cell = new controls.span({ context, class: 'resource-type' });
|
|
142
|
+
type_cell.add(item.type || 'Unknown');
|
|
143
|
+
row.add(type_cell);
|
|
144
|
+
|
|
145
|
+
// Status
|
|
146
|
+
const status_cell = new controls.span({ context, class: 'resource-status' });
|
|
147
|
+
const health = new Health_Badge({
|
|
148
|
+
context,
|
|
149
|
+
state: item.state || 'unknown',
|
|
150
|
+
text: this._format_state(item.state)
|
|
151
|
+
});
|
|
152
|
+
status_cell.add(health);
|
|
153
|
+
row.add(status_cell);
|
|
154
|
+
|
|
155
|
+
// Memory
|
|
156
|
+
const mem_cell = new controls.span({ context, class: 'resource-mem' });
|
|
157
|
+
mem_cell.add(item.memory ? format_bytes(item.memory) : '—');
|
|
158
|
+
row.add(mem_cell);
|
|
159
|
+
|
|
160
|
+
return row;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
_format_state(state) {
|
|
164
|
+
if (!state) return 'Unknown';
|
|
165
|
+
return state.charAt(0).toUpperCase() + state.slice(1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
update(resources_data) {
|
|
169
|
+
this._resources = resources_data;
|
|
170
|
+
// Client-side: re-render table body
|
|
171
|
+
if (this._body && this._body.el) {
|
|
172
|
+
this._body.el.innerHTML = '';
|
|
173
|
+
const items = resources_data.items || [];
|
|
174
|
+
items.forEach((item, i) => {
|
|
175
|
+
const row = this._create_row(item, i);
|
|
176
|
+
this._body.add(row);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
if (this._counter && this._counter.el) {
|
|
180
|
+
this._counter.el.innerText = `${resources_data.running || 0} / ${resources_data.total || 0}`;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### CSS
|
|
187
|
+
|
|
188
|
+
```css
|
|
189
|
+
.resource_table {
|
|
190
|
+
position: relative;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.resource-counter {
|
|
194
|
+
position: absolute;
|
|
195
|
+
top: -4px;
|
|
196
|
+
right: 16px;
|
|
197
|
+
font-size: 8px;
|
|
198
|
+
font-weight: 500;
|
|
199
|
+
color: #2A6A2A;
|
|
200
|
+
background: rgba(72, 184, 72, 0.12);
|
|
201
|
+
border: 0.5px solid #48B848;
|
|
202
|
+
border-radius: 3px;
|
|
203
|
+
padding: 2px 8px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.resource-table-header {
|
|
207
|
+
display: grid;
|
|
208
|
+
grid-template-columns: 2fr 2fr 1fr 0.5fr;
|
|
209
|
+
padding: 6px 12px;
|
|
210
|
+
background: #E8E4DC;
|
|
211
|
+
border-top: 0.5px solid #C0B8A8;
|
|
212
|
+
border-bottom: 0.5px solid #C0B8A8;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.resource-header-cell {
|
|
216
|
+
font-size: 9px;
|
|
217
|
+
font-weight: 600;
|
|
218
|
+
color: #606060;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.resource-table-body {
|
|
222
|
+
display: flex;
|
|
223
|
+
flex-direction: column;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.resource-row {
|
|
227
|
+
display: grid;
|
|
228
|
+
grid-template-columns: auto 2fr 2fr 1fr 0.5fr;
|
|
229
|
+
align-items: center;
|
|
230
|
+
gap: 8px;
|
|
231
|
+
padding: 6px 12px;
|
|
232
|
+
border-bottom: 0.5px solid #E0DCD4;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.resource-row:hover {
|
|
236
|
+
background: rgba(68, 136, 204, 0.05);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.resource-type-badge {
|
|
240
|
+
width: 7px;
|
|
241
|
+
height: 7px;
|
|
242
|
+
border-radius: 1.5px;
|
|
243
|
+
display: inline-block;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.badge-color-0 { background: #9070C0; }
|
|
247
|
+
.badge-color-1 { background: #4488CC; }
|
|
248
|
+
.badge-color-2 { background: #48B848; }
|
|
249
|
+
.badge-color-3 { background: #D8A020; }
|
|
250
|
+
.badge-color-4 { background: #4098B8; }
|
|
251
|
+
|
|
252
|
+
.resource-name {
|
|
253
|
+
font-size: 10px;
|
|
254
|
+
font-weight: 500;
|
|
255
|
+
color: #2A4060;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.resource-type {
|
|
259
|
+
font-size: 9px;
|
|
260
|
+
color: #808080;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
.resource-status {
|
|
264
|
+
font-size: 9px;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.resource-mem {
|
|
268
|
+
font-size: 9px;
|
|
269
|
+
color: #808080;
|
|
270
|
+
text-align: right;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.resource-table-footer {
|
|
274
|
+
font-size: 8px;
|
|
275
|
+
color: #908888;
|
|
276
|
+
padding: 8px 4px 0;
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Resource Data Mapping
|
|
283
|
+
|
|
284
|
+
The Resource_Table maps data from `/api/admin/resources`:
|
|
285
|
+
|
|
286
|
+
| API Response Field | Table Column | Rendering |
|
|
287
|
+
|-------------------|-------------|-----------|
|
|
288
|
+
| `item.name` | RESOURCE | Plain text, font-weight 500 |
|
|
289
|
+
| `item.type` | TYPE | Gray text, constructor name |
|
|
290
|
+
| `item.state` | STATUS | Health_Badge with dot + text |
|
|
291
|
+
| `item.memory` | MEM | `format_bytes()` or dash |
|
|
292
|
+
| `item.has_status` | — | Determines if status details available |
|
|
293
|
+
|
|
294
|
+
### Resource Type Color Coding
|
|
295
|
+
|
|
296
|
+
Resources are color-coded by category:
|
|
297
|
+
|
|
298
|
+
| Type Pattern | Color | Badge Class |
|
|
299
|
+
|-------------|-------|-------------|
|
|
300
|
+
| `*Compiler*` | Purple (#9070C0) | `badge-color-0` |
|
|
301
|
+
| `*Compilation*` | Blue (#4488CC) | `badge-color-1` |
|
|
302
|
+
| `Data_KV*` | Green (#48B848) | `badge-color-2` |
|
|
303
|
+
| `Data_Transform*` | Amber (#D8A020) | `badge-color-3` |
|
|
304
|
+
| `Resource` (generic) | Cyan (#4098B8) | `badge-color-4` |
|
|
305
|
+
| Router | Blue (#4488CC) | `badge-color-1` |
|
|
306
|
+
| Publisher | Purple (#9070C0) | `badge-color-0` |
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Resource Detail Expansion
|
|
311
|
+
|
|
312
|
+
When a resource row is clicked, it can expand to show additional details from the resource's `status` property:
|
|
313
|
+
|
|
314
|
+
```javascript
|
|
315
|
+
// Phase 2 feature
|
|
316
|
+
_expand_row(item_name) {
|
|
317
|
+
const resource_status = this._resources.items.find(
|
|
318
|
+
r => r.name === item_name
|
|
319
|
+
)?.status;
|
|
320
|
+
|
|
321
|
+
if (!resource_status) return;
|
|
322
|
+
|
|
323
|
+
// Create detail panel below the row
|
|
324
|
+
const detail = new controls.div({ context: this.context, class: 'resource-detail' });
|
|
325
|
+
|
|
326
|
+
// Format status object as key-value pairs
|
|
327
|
+
Object.entries(resource_status).forEach(([key, value]) => {
|
|
328
|
+
const pair = new controls.div({ context: this.context, class: 'detail-pair' });
|
|
329
|
+
const k = new controls.span({ context: this.context, class: 'detail-key' });
|
|
330
|
+
k.add(key);
|
|
331
|
+
pair.add(k);
|
|
332
|
+
const v = new controls.span({ context: this.context, class: 'detail-value' });
|
|
333
|
+
v.add(typeof value === 'object' ? JSON.stringify(value) : String(value));
|
|
334
|
+
pair.add(v);
|
|
335
|
+
detail.add(pair);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Insert after the row
|
|
339
|
+
// ...
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Detail Panel CSS
|
|
344
|
+
|
|
345
|
+
```css
|
|
346
|
+
.resource-detail {
|
|
347
|
+
background: #F8F6F2;
|
|
348
|
+
border: 1px solid #E0DCD4;
|
|
349
|
+
border-radius: 3px;
|
|
350
|
+
padding: 8px 12px;
|
|
351
|
+
margin: 4px 12px;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.detail-pair {
|
|
355
|
+
display: flex;
|
|
356
|
+
gap: 12px;
|
|
357
|
+
padding: 2px 0;
|
|
358
|
+
font-size: 9px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.detail-key {
|
|
362
|
+
color: #808080;
|
|
363
|
+
min-width: 120px;
|
|
364
|
+
font-weight: 500;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.detail-value {
|
|
368
|
+
color: #2A4060;
|
|
369
|
+
font-family: 'Consolas', monospace;
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Real-Time Updates
|
|
376
|
+
|
|
377
|
+
The Resource_Table listens for pool events via SSE:
|
|
378
|
+
|
|
379
|
+
```javascript
|
|
380
|
+
// In activate()
|
|
381
|
+
const event_source = new EventSource('/api/admin/events');
|
|
382
|
+
|
|
383
|
+
event_source.addEventListener('resource_state_change', (e) => {
|
|
384
|
+
const data = JSON.parse(e.data);
|
|
385
|
+
this._update_resource_state(data.resourceName, data.to);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
event_source.addEventListener('removed', (e) => {
|
|
389
|
+
const data = JSON.parse(e.data);
|
|
390
|
+
this._remove_resource_row(data.resourceName);
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Update is targeted — only the affected row's Health_Badge changes, avoiding a full table re-render.
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Pool Summary Panel
|
|
399
|
+
|
|
400
|
+
In addition to the table, the sidebar shows a miniature pool health summary:
|
|
401
|
+
|
|
402
|
+
```javascript
|
|
403
|
+
class Pool_Health_Summary extends jsgui.Control {
|
|
404
|
+
constructor(spec = {}) {
|
|
405
|
+
spec.__type_name = spec.__type_name || 'pool_health_summary';
|
|
406
|
+
super(spec);
|
|
407
|
+
const { context } = this;
|
|
408
|
+
|
|
409
|
+
const compose = () => {
|
|
410
|
+
const items = spec.items || [];
|
|
411
|
+
items.forEach(item => {
|
|
412
|
+
const row = new controls.div({ context, class: 'health-row' });
|
|
413
|
+
const dot = new Health_Badge({
|
|
414
|
+
context,
|
|
415
|
+
state: item.healthy ? 'running' : 'warning',
|
|
416
|
+
text: item.label
|
|
417
|
+
});
|
|
418
|
+
row.add(dot);
|
|
419
|
+
this.add(row);
|
|
420
|
+
});
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
if (!spec.el) { compose(); }
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Example usage (sidebar):
|
|
429
|
+
```javascript
|
|
430
|
+
const health_summary = new Pool_Health_Summary({
|
|
431
|
+
context,
|
|
432
|
+
items: [
|
|
433
|
+
{ label: 'Server Running', healthy: true },
|
|
434
|
+
{ label: 'Bundle Ready', healthy: true },
|
|
435
|
+
{ label: 'Pool 5/5', healthy: true },
|
|
436
|
+
{ label: '1 Warning', healthy: false }
|
|
437
|
+
]
|
|
438
|
+
});
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## Adapter — `get_resources_tree()` Enhancement
|
|
444
|
+
|
|
445
|
+
The current `Admin_Module.get_resources_tree()` method provides basic data. For the v1 admin UI, it needs to be enhanced:
|
|
446
|
+
|
|
447
|
+
```javascript
|
|
448
|
+
get_resources_tree() {
|
|
449
|
+
const pool = this.server.resource_pool;
|
|
450
|
+
const summary = pool.summary; // Uses the built-in summary getter
|
|
451
|
+
|
|
452
|
+
const items = [];
|
|
453
|
+
pool.resources.each(resource => {
|
|
454
|
+
if (!resource) return;
|
|
455
|
+
|
|
456
|
+
const item = {
|
|
457
|
+
name: resource.name || 'Unnamed',
|
|
458
|
+
type: resource.constructor?.name || 'Unknown',
|
|
459
|
+
state: resource.status?.state || resource.state || 'unknown',
|
|
460
|
+
has_status: typeof resource.status === 'object',
|
|
461
|
+
memory: null
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
// Try to get memory from Process_Resource
|
|
465
|
+
if (typeof resource.memory_usage === 'object') {
|
|
466
|
+
item.memory = resource.memory_usage.rssBytes || null;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Get full status if available
|
|
470
|
+
if (item.has_status) {
|
|
471
|
+
try {
|
|
472
|
+
item.status = resource.status;
|
|
473
|
+
} catch (e) {
|
|
474
|
+
item.status = { error: e.message };
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
items.push(item);
|
|
479
|
+
});
|
|
480
|
+
|
|
481
|
+
return {
|
|
482
|
+
total: summary.total,
|
|
483
|
+
running: summary.running,
|
|
484
|
+
stopped: summary.stopped,
|
|
485
|
+
crashed: summary.crashed,
|
|
486
|
+
unreachable: summary.unreachable,
|
|
487
|
+
by_type: summary.byType,
|
|
488
|
+
items: items
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
This enhancement is a minor change to the existing method — no new platform features required.
|