From 4ded40b85cccb6520dc9153e49d1c13cd21cc2bd Mon Sep 17 00:00:00 2001 From: Patrick Balsiger Date: Thu, 28 Aug 2025 21:14:22 +0200 Subject: [PATCH] feat: improve capability dropdown --- public/components.js | 46 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/public/components.js b/public/components.js index 796fdbc..16b5896 100644 --- a/public/components.js +++ b/public/components.js @@ -883,17 +883,41 @@ class NodeDetailsComponent extends Component { `; } - const total = capabilities.endpoints.length; - let selectedIndex = Number(this.getUIState('capSelectedIndex')); - if (Number.isNaN(selectedIndex) || selectedIndex < 0 || selectedIndex >= total) { - selectedIndex = 0; + // Sort endpoints by URI (name), then by method for stable ordering + const endpoints = [...capabilities.endpoints].sort((a, b) => { + const aUri = String(a.uri || '').toLowerCase(); + const bUri = String(b.uri || '').toLowerCase(); + if (aUri < bUri) return -1; + if (aUri > bUri) return 1; + const aMethod = String(a.method || '').toLowerCase(); + const bMethod = String(b.method || '').toLowerCase(); + return aMethod.localeCompare(bMethod); + }); + + const total = endpoints.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); + if (selectedIndex === -1) { + selectedIndex = Number(this.getUIState('capSelectedIndex')); + if (Number.isNaN(selectedIndex) || selectedIndex < 0 || selectedIndex >= total) { + selectedIndex = 0; + } } - const selectorOptions = capabilities.endpoints.map((ep, idx) => { - return ``; + // Compute padding for aligned display in dropdown + const maxMethodLen = endpoints.reduce((m, ep) => Math.max(m, String(ep.method || '').length), 0); + + const selectorOptions = endpoints.map((ep, idx) => { + const method = String(ep.method || ''); + const uri = String(ep.uri || ''); + const padCount = Math.max(1, (maxMethodLen - method.length) + 2); + const spacer = ' '.repeat(padCount); + return ``; }).join(''); - const items = capabilities.endpoints.map((ep, idx) => { + const items = endpoints.map((ep, idx) => { const formId = `cap-form-${idx}`; const resultId = `cap-result-${idx}`; const params = Array.isArray(ep.params) && ep.params.length > 0 @@ -928,7 +952,7 @@ class NodeDetailsComponent extends Component { return `
- +
${items}
`; @@ -944,6 +968,12 @@ class NodeDetailsComponent extends Component { el.style.display = (idx === selected) ? '' : 'none'; }); this.setUIState('capSelectedIndex', selected); + const opt = e.target.selectedOptions && e.target.selectedOptions[0]; + if (opt) { + const method = opt.dataset.method || ''; + const uri = opt.dataset.uri || ''; + this.setUIState('capSelectedKey', `${method} ${uri}`); + } }); }