From d0557a56a22d9ad0e65450f369509aa067b0915b Mon Sep 17 00:00:00 2001 From: Patrick Balsiger Date: Sat, 13 Sep 2025 19:15:38 +0200 Subject: [PATCH] refactor: remove capabilities in favor of endpoints --- index.js | 6 +- public/scripts/api-client.js | 6 +- .../components/NodeDetailsComponent.js | 110 +++++++++--------- public/scripts/view-models.js | 24 ++-- public/styles/main.css | 50 ++++---- src/client/index.js | 6 +- 6 files changed, 98 insertions(+), 104 deletions(-) diff --git a/index.js b/index.js index 984dfb0..3725c9f 100644 --- a/index.js +++ b/index.js @@ -466,7 +466,7 @@ app.get('/api/node/status', async (req, res) => { }); // Proxy endpoint to get node capabilities (optionally for a specific node via ?ip=) -app.get('/api/node/capabilities', async (req, res) => { +app.get('/api/node/endpoints', async (req, res) => { try { const { ip } = req.query; @@ -476,9 +476,9 @@ app.get('/api/node/capabilities', async (req, res) => { const caps = await nodeClient.getCapabilities(); return res.json(caps); } catch (innerError) { - console.error('Error fetching capabilities from specific node:', innerError); + console.error('Error fetching endpoints from specific node:', innerError); return res.status(500).json({ - error: 'Failed to fetch capabilities from node', + error: 'Failed to fetch endpoints from node', message: innerError.message }); } diff --git a/public/scripts/api-client.js b/public/scripts/api-client.js index 4f605d5..4d3b817 100644 --- a/public/scripts/api-client.js +++ b/public/scripts/api-client.js @@ -80,11 +80,11 @@ class ApiClient { return this.request('/api/tasks/status', { method: 'GET', query: ip ? { ip } : undefined }); } - async getCapabilities(ip) { - return this.request('/api/node/capabilities', { method: 'GET', query: ip ? { ip } : undefined }); + async getEndpoints(ip) { + return this.request('/api/node/endpoints', { method: 'GET', query: ip ? { ip } : undefined }); } - async callCapability({ ip, method, uri, params }) { + async callEndpoint({ ip, method, uri, params }) { return this.request('/api/proxy-call', { method: 'POST', body: { ip, method, uri, params } diff --git a/public/scripts/components/NodeDetailsComponent.js b/public/scripts/components/NodeDetailsComponent.js index 5268ba3..cc23619 100644 --- a/public/scripts/components/NodeDetailsComponent.js +++ b/public/scripts/components/NodeDetailsComponent.js @@ -10,13 +10,13 @@ class NodeDetailsComponent extends Component { this.subscribeToProperty('isLoading', this.handleLoadingUpdate.bind(this)); this.subscribeToProperty('error', this.handleErrorUpdate.bind(this)); this.subscribeToProperty('activeTab', this.handleActiveTabUpdate.bind(this)); - this.subscribeToProperty('capabilities', this.handleCapabilitiesUpdate.bind(this)); + this.subscribeToProperty('endpoints', this.handleEndpointsUpdate.bind(this)); } // Handle node status update with state preservation handleNodeStatusUpdate(newStatus, previousStatus) { if (newStatus && !this.viewModel.get('isLoading')) { - this.renderNodeDetails(newStatus, this.viewModel.get('tasks'), this.viewModel.get('capabilities')); + this.renderNodeDetails(newStatus, this.viewModel.get('tasks'), this.viewModel.get('endpoints')); } } @@ -24,7 +24,7 @@ class NodeDetailsComponent extends Component { handleTasksUpdate(newTasks, previousTasks) { const nodeStatus = this.viewModel.get('nodeStatus'); if (nodeStatus && !this.viewModel.get('isLoading')) { - this.renderNodeDetails(nodeStatus, newTasks, this.viewModel.get('capabilities')); + this.renderNodeDetails(nodeStatus, newTasks, this.viewModel.get('endpoints')); } } @@ -48,12 +48,12 @@ class NodeDetailsComponent extends Component { this.updateActiveTab(newTab, previousTab); } - // Handle capabilities update with state preservation - handleCapabilitiesUpdate(newCapabilities, previousCapabilities) { + // Handle endpoints update with state preservation + handleEndpointsUpdate(newEndpoints, previousEndpoints) { const nodeStatus = this.viewModel.get('nodeStatus'); const tasks = this.viewModel.get('tasks'); if (nodeStatus && !this.viewModel.get('isLoading')) { - this.renderNodeDetails(nodeStatus, tasks, newCapabilities); + this.renderNodeDetails(nodeStatus, tasks, newEndpoints); } } @@ -62,7 +62,7 @@ class NodeDetailsComponent extends Component { const tasks = this.viewModel.get('tasks'); const isLoading = this.viewModel.get('isLoading'); const error = this.viewModel.get('error'); - const capabilities = this.viewModel.get('capabilities'); + const endpoints = this.viewModel.get('endpoints'); if (isLoading) { this.renderLoading('
Loading detailed information...
'); @@ -79,10 +79,10 @@ class NodeDetailsComponent extends Component { return; } - this.renderNodeDetails(nodeStatus, tasks, capabilities); + this.renderNodeDetails(nodeStatus, tasks, endpoints); } - renderNodeDetails(nodeStatus, tasks, capabilities) { + renderNodeDetails(nodeStatus, tasks, endpoints) { // Use persisted active tab from the view model, default to 'status' const activeTab = (this.viewModel && typeof this.viewModel.get === 'function' && this.viewModel.get('activeTab')) || 'status'; logger.debug('NodeDetailsComponent: Rendering with activeTab:', activeTab); @@ -92,7 +92,6 @@ class NodeDetailsComponent extends Component {
-
@@ -121,14 +120,9 @@ class NodeDetailsComponent extends Component {
- ${nodeStatus.api ? nodeStatus.api.map(endpoint => - `
${endpoint.method === 1 ? 'GET' : 'POST'} ${endpoint.uri}
` - ).join('') : '
No API endpoints available
'} + ${this.renderEndpointsTab(endpoints)}
-
- ${this.renderCapabilitiesTab(capabilities)} -
${this.renderTasksTab(tasks)} @@ -150,18 +144,18 @@ class NodeDetailsComponent extends Component { this.setupFirmwareUpload(); } - renderCapabilitiesTab(capabilities) { - if (!capabilities || !Array.isArray(capabilities.endpoints) || capabilities.endpoints.length === 0) { + renderEndpointsTab(endpoints) { + if (!endpoints || !Array.isArray(endpoints.endpoints) || endpoints.endpoints.length === 0) { return ` -
-
🧩 No capabilities reported
-
This node did not return any capabilities
+
+
🧩 No endpoints reported
+
This node did not return any endpoints
`; } // Sort endpoints by URI (name), then by method for stable ordering - const endpoints = [...capabilities.endpoints].sort((a, b) => { + const endpointsList = [...endpoints.endpoints].sort((a, b) => { const aUri = String(a.uri || '').toLowerCase(); const bUri = String(b.uri || '').toLowerCase(); if (aUri < bUri) return -1; @@ -171,22 +165,22 @@ class NodeDetailsComponent extends Component { return aMethod.localeCompare(bMethod); }); - const total = endpoints.length; + const total = endpointsList.length; // Preserve selection based on a stable key of method+uri if available - const selectedKey = String(this.getUIState('capSelectedKey') || ''); - let selectedIndex = endpoints.findIndex(ep => `${ep.method} ${ep.uri}` === selectedKey); + const selectedKey = String(this.getUIState('endpointSelectedKey') || ''); + let selectedIndex = endpointsList.findIndex(ep => `${ep.method} ${ep.uri}` === selectedKey); if (selectedIndex === -1) { - selectedIndex = Number(this.getUIState('capSelectedIndex')); + selectedIndex = Number(this.getUIState('endpointSelectedIndex')); if (Number.isNaN(selectedIndex) || selectedIndex < 0 || selectedIndex >= total) { selectedIndex = 0; } } // Compute padding for aligned display in dropdown - const maxMethodLen = endpoints.reduce((m, ep) => Math.max(m, String(ep.method || '').length), 0); + const maxMethodLen = endpointsList.reduce((m, ep) => Math.max(m, String(ep.method || '').length), 0); - const selectorOptions = endpoints.map((ep, idx) => { + const selectorOptions = endpointsList.map((ep, idx) => { const method = String(ep.method || ''); const uri = String(ep.uri || ''); const padCount = Math.max(1, (maxMethodLen - method.length) + 2); @@ -194,12 +188,12 @@ class NodeDetailsComponent extends Component { return ``; }).join(''); - const items = endpoints.map((ep, idx) => { - const formId = `cap-form-${idx}`; - const resultId = `cap-result-${idx}`; + const items = endpointsList.map((ep, idx) => { + const formId = `endpoint-form-${idx}`; + const resultId = `endpoint-result-${idx}`; const params = Array.isArray(ep.params) && ep.params.length > 0 - ? `
${ep.params.map((p, pidx) => ` -