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.
Files changed (154) hide show
  1. package/.github/agents/Mobile Developer.agent.md +89 -0
  2. package/.github/workflows/control-scan-manifest-check.yml +31 -0
  3. package/AGENTS.md +4 -0
  4. package/README.md +215 -3
  5. package/admin-ui/client.js +81 -51
  6. package/admin-ui/v1/admin_auth_service.js +197 -0
  7. package/admin-ui/v1/admin_user_store.js +71 -0
  8. package/admin-ui/v1/client.js +17 -0
  9. package/admin-ui/v1/controls/admin_shell.js +1399 -0
  10. package/admin-ui/v1/controls/group_box.js +84 -0
  11. package/admin-ui/v1/controls/stat_card.js +125 -0
  12. package/admin-ui/v1/server.js +658 -0
  13. package/admin-ui/v1/utils/formatters.js +68 -0
  14. package/dev-status.svg +139 -0
  15. package/docs/admin-extension-guide.md +345 -0
  16. package/docs/api-reference.md +301 -43
  17. package/docs/books/adaptive-control-improvements/01-control-candidate-matrix.md +122 -0
  18. package/docs/books/adaptive-control-improvements/02-tier-1-layout-playbooks.md +207 -0
  19. package/docs/books/adaptive-control-improvements/03-tier-2-navigation-form-overlay.md +140 -0
  20. package/docs/books/adaptive-control-improvements/04-cross-cutting-platform-functionality.md +141 -0
  21. package/docs/books/adaptive-control-improvements/05-styling-theming-density-upgrades.md +114 -0
  22. package/docs/books/adaptive-control-improvements/06-testing-quality-gates.md +97 -0
  23. package/docs/books/adaptive-control-improvements/07-delivery-roadmap-and-ownership.md +137 -0
  24. package/docs/books/adaptive-control-improvements/08-appendix-tier1-acceptance-and-pr-templates.md +261 -0
  25. package/docs/books/adaptive-control-improvements/README.md +66 -0
  26. package/docs/books/admin-ui-authentication/01-threat-model-and-goals.md +124 -0
  27. package/docs/books/admin-ui-authentication/02-session-model-and-token-model.md +75 -0
  28. package/docs/books/admin-ui-authentication/03-auth-middleware-patterns.md +77 -0
  29. package/docs/books/admin-ui-authentication/README.md +25 -0
  30. package/docs/books/creating-a-new-admin-ui/01-introduction-and-vision.md +130 -0
  31. package/docs/books/creating-a-new-admin-ui/02-architecture-and-data-flow.md +298 -0
  32. package/docs/books/creating-a-new-admin-ui/03-server-introspection.md +381 -0
  33. package/docs/books/creating-a-new-admin-ui/04-admin-module-adapter-layer.md +592 -0
  34. package/docs/books/creating-a-new-admin-ui/05-domain-controls-stat-cards-and-gauges.md +513 -0
  35. package/docs/books/creating-a-new-admin-ui/06-domain-controls-process-manager.md +544 -0
  36. package/docs/books/creating-a-new-admin-ui/07-domain-controls-resource-pool-inspector.md +493 -0
  37. package/docs/books/creating-a-new-admin-ui/08-domain-controls-route-table-and-api-explorer.md +586 -0
  38. package/docs/books/creating-a-new-admin-ui/09-domain-controls-log-viewer-and-activity-feed.md +490 -0
  39. package/docs/books/creating-a-new-admin-ui/10-domain-controls-build-status-and-bundle-inspector.md +526 -0
  40. package/docs/books/creating-a-new-admin-ui/11-domain-controls-configuration-panel.md +808 -0
  41. package/docs/books/creating-a-new-admin-ui/12-admin-shell-layout-sidebar-navigation.md +210 -0
  42. package/docs/books/creating-a-new-admin-ui/13-telemetry-integration.md +556 -0
  43. package/docs/books/creating-a-new-admin-ui/14-realtime-sse-observable-integration.md +485 -0
  44. package/docs/books/creating-a-new-admin-ui/15-styling-theming-aero-design-system.md +521 -0
  45. package/docs/books/creating-a-new-admin-ui/16-testing-and-quality-assurance.md +147 -0
  46. package/docs/books/creating-a-new-admin-ui/17-next-steps-process-resource-roadmap.md +356 -0
  47. package/docs/books/creating-a-new-admin-ui/README.md +68 -0
  48. package/docs/books/device-adaptive-composition/01-platform-feature-audit.md +177 -0
  49. package/docs/books/device-adaptive-composition/02-responsive-composition-model.md +187 -0
  50. package/docs/books/device-adaptive-composition/03-data-model-vs-view-model.md +231 -0
  51. package/docs/books/device-adaptive-composition/04-styling-theme-breakpoints.md +234 -0
  52. package/docs/books/device-adaptive-composition/05-showcase-app-multi-device-assessment.md +193 -0
  53. package/docs/books/device-adaptive-composition/06-implementation-patterns-and-apis.md +346 -0
  54. package/docs/books/device-adaptive-composition/07-testing-harness-and-quality-gates.md +265 -0
  55. package/docs/books/device-adaptive-composition/08-roadmap-and-adoption-plan.md +250 -0
  56. package/docs/books/device-adaptive-composition/README.md +47 -0
  57. package/docs/books/jsgui3-bundling-research-book/00-table-of-contents.md +35 -0
  58. package/docs/books/jsgui3-bundling-research-book/01-pipeline-and-runtime-semantics.md +34 -0
  59. package/docs/books/jsgui3-bundling-research-book/02-javascript-bundling-core.md +36 -0
  60. package/docs/books/jsgui3-bundling-research-book/03-style-extraction-and-css-compilation.md +35 -0
  61. package/docs/books/jsgui3-bundling-research-book/04-static-publishing-and-delivery.md +39 -0
  62. package/docs/books/jsgui3-bundling-research-book/05-current-limits-and-size-bloat-vectors.md +25 -0
  63. package/docs/books/jsgui3-bundling-research-book/06-unused-module-elimination-strategy.md +77 -0
  64. package/docs/books/jsgui3-bundling-research-book/07-jsgui3-html-control-and-mixin-pruning.md +63 -0
  65. package/docs/books/jsgui3-bundling-research-book/08-test-and-verification-methodology.md +43 -0
  66. package/docs/books/jsgui3-bundling-research-book/09-roadmap-and-rollout.md +42 -0
  67. package/docs/books/jsgui3-bundling-research-book/10-further-research-strategies-and-upgrades.md +211 -0
  68. package/docs/books/jsgui3-bundling-research-book/README.md +35 -0
  69. package/docs/bundling-system-deep-dive.md +9 -4
  70. package/docs/comparison-report-express-plex-cpanel.md +549 -0
  71. package/docs/comprehensive-documentation.md +49 -18
  72. package/docs/configuration-reference.md +152 -27
  73. package/docs/core/README.md +19 -0
  74. package/docs/core/jsgui3-server-core-book/00-table-of-contents.md +21 -0
  75. package/docs/core/jsgui3-server-core-book/01-startup-readiness-state-machine.md +41 -0
  76. package/docs/core/jsgui3-server-core-book/02-resource-abstraction-and-lifecycle.md +92 -0
  77. package/docs/core/jsgui3-server-core-book/03-resource-pool-and-event-topology.md +47 -0
  78. package/docs/core/jsgui3-server-core-book/04-sse-publisher-semantics.md +41 -0
  79. package/docs/core/jsgui3-server-core-book/05-serve-factory-resource-wiring.md +46 -0
  80. package/docs/core/jsgui3-server-core-book/06-e2e-testing-methodology.md +48 -0
  81. package/docs/core/jsgui3-server-core-book/07-defect-detection-and-hardening-loop.md +47 -0
  82. package/docs/designs/server-admin-interface-aero.svg +611 -0
  83. package/docs/publishers-guide.md +59 -4
  84. package/docs/resources-guide.md +184 -35
  85. package/docs/simple-server-api-design.md +72 -17
  86. package/docs/system-architecture.md +18 -14
  87. package/docs/troubleshooting.md +84 -53
  88. package/examples/controls/15) window, observable SSE/server.js +6 -1
  89. package/examples/controls/19) window, auto observable ui/server.js +9 -0
  90. package/examples/controls/20) window, task manager app/README.md +133 -0
  91. package/examples/controls/20) window, task manager app/client.js +797 -0
  92. package/examples/controls/20) window, task manager app/server.js +178 -0
  93. package/examples/controls/6) window, color_palette/client.js +165 -68
  94. package/examples/controls/9) window, date picker/client.js +362 -76
  95. package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +104 -83
  96. package/examples/jsgui3-html/06) theming/client.js +22 -1
  97. package/examples/jsgui3-html/10) binding-debugger/client.js +137 -1
  98. package/http/responders/static/Static_Route_HTTP_Responder.js +52 -34
  99. package/lab/experiments/capture-color-controls.js +196 -0
  100. package/lab/results/screenshots/color-controls/full_page.png +0 -0
  101. package/lab/results/screenshots/color-controls/section_1_color_grid_12x12.png +0 -0
  102. package/lab/results/screenshots/color-controls/section_2_color_grid_4x2.png +0 -0
  103. package/lab/results/screenshots/color-controls/section_3_color_palette.png +0 -0
  104. package/lab/results/screenshots/color-controls/section_4_palette_comparison.png +0 -0
  105. package/lab/results/screenshots/color-controls/section_5_raw_swatches.png +0 -0
  106. package/lab/results/screenshots/color-controls/section_6_optimized_crayola.png +0 -0
  107. package/lab/results/screenshots/color-controls/section_7_pastel_palette.png +0 -0
  108. package/lab/results/screenshots/color-controls/section_8_extended_144.png +0 -0
  109. package/lab/screenshot-utils.js +248 -0
  110. package/module.js +12 -0
  111. package/package.json +12 -2
  112. package/publishers/Publishers.js +4 -3
  113. package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +5 -5
  114. package/publishers/http-sse-publisher.js +341 -0
  115. package/resources/process-resource.js +950 -0
  116. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +129 -33
  117. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +18 -7
  118. package/resources/processors/bundlers/js/esbuild/JSGUI3_HTML_Control_Optimizer.js +829 -0
  119. package/resources/remote-process-resource.js +355 -0
  120. package/resources/server-resource-pool.js +354 -41
  121. package/serve-factory.js +442 -259
  122. package/server.js +288 -13
  123. package/tests/README.md +71 -4
  124. package/tests/admin-ui-jsgui-controls.test.js +581 -0
  125. package/tests/admin-ui-render.test.js +24 -0
  126. package/tests/assigners.test.js +56 -40
  127. package/tests/bundling-default-control-elimination.puppeteer.test.js +260 -0
  128. package/tests/configuration-validation.test.js +21 -18
  129. package/tests/content-analysis.test.js +7 -6
  130. package/tests/control-optimizer-cache-behavior.test.js +52 -0
  131. package/tests/control-scan-manifest-regression.test.js +144 -0
  132. package/tests/end-to-end.test.js +15 -14
  133. package/tests/error-handling.test.js +222 -179
  134. package/tests/fixtures/bundling-default-button-client.js +37 -0
  135. package/tests/fixtures/bundling-default-window-client.js +34 -0
  136. package/tests/fixtures/control_scan_manifest_expectations.json +48 -0
  137. package/tests/fixtures/resource-monitor-client.js +319 -0
  138. package/tests/helpers/puppeteer-e2e-harness.js +317 -0
  139. package/tests/http-sse-publisher.test.js +136 -0
  140. package/tests/performance.test.js +69 -65
  141. package/tests/process-resource.test.js +138 -0
  142. package/tests/publishers.test.js +7 -7
  143. package/tests/remote-process-resource.test.js +160 -0
  144. package/tests/sass-controls.e2e.test.js +7 -1
  145. package/tests/serve-resources.test.js +270 -0
  146. package/tests/serve.test.js +120 -50
  147. package/tests/server-resource-pool.test.js +106 -0
  148. package/tests/small-controls-bundle-size.test.js +252 -0
  149. package/tests/test-runner.js +14 -1
  150. package/tests/window-examples.puppeteer.test.js +204 -1
  151. package/tests/window-resource-integration.puppeteer.test.js +585 -0
  152. package/tests/temp_invalid.js +0 -7
  153. package/tests/temp_invalid_utf8.js +0 -1
  154. 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.