feat: capability selection

This commit is contained in:
2025-08-28 13:06:17 +02:00
parent de131f955a
commit 9486594199
3 changed files with 42 additions and 5 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 KiB

After

Width:  |  Height:  |  Size: 212 KiB

View File

@@ -872,7 +872,6 @@ class NodeDetailsComponent extends Component {
</div>
<div class="tab-content ${activeTab === 'endpoints' ? 'active' : ''}" id="endpoints-tab">
<h4>Available API Endpoints:</h4>
${nodeStatus.api ? nodeStatus.api.map(endpoint =>
`<div class="endpoint-item">${endpoint.method === 1 ? 'GET' : 'POST'} ${endpoint.uri}</div>`
).join('') : '<div class="endpoint-item">No API endpoints available</div>'}
@@ -907,6 +906,16 @@ 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;
}
const selectorOptions = capabilities.endpoints.map((ep, idx) => {
return `<option value="${idx}" ${idx === selectedIndex ? 'selected' : ''}>${ep.method} ${ep.uri}</option>`;
}).join('');
const items = capabilities.endpoints.map((ep, idx) => {
const formId = `cap-form-${idx}`;
const resultId = `cap-result-${idx}`;
@@ -922,7 +931,7 @@ class NodeDetailsComponent extends Component {
`).join('')}</div>`
: '<div class="capability-params none">No parameters</div>';
return `
<div class="capability-item" data-cap-index="${idx}">
<div class="capability-item" data-cap-index="${idx}" style="display:${idx === selectedIndex ? '' : 'none'};">
<div class="capability-header">
<span class="cap-method">${ep.method}</span>
<span class="cap-uri">${ep.uri}</span>
@@ -940,12 +949,27 @@ class NodeDetailsComponent extends Component {
setTimeout(() => this.setupCapabilitiesEvents(), 0);
return `
<h4>Node Capabilities</h4>
<div class="capability-selector">
<label class="param-name" for="capability-select">Capability</label>
<select id="capability-select" class="param-input">${selectorOptions}</select>
</div>
<div class="capabilities-list">${items}</div>
`;
}
setupCapabilitiesEvents() {
const selector = this.findElement('#capability-select');
if (selector) {
this.addEventListener(selector, 'change', (e) => {
const selected = Number(e.target.value);
const items = Array.from(this.findAllElements('.capability-item'));
items.forEach((el, idx) => {
el.style.display = (idx === selected) ? '' : 'none';
});
this.setUIState('capSelectedIndex', selected);
});
}
const buttons = this.findAllElements('.cap-call-btn');
buttons.forEach(btn => {
this.addEventListener(btn, 'click', async (e) => {
@@ -1029,7 +1053,6 @@ class NodeDetailsComponent extends Component {
`).join('');
return `
<h4>Active Tasks</h4>
${tasksHTML}
`;
} else {

View File

@@ -470,7 +470,6 @@ p {
.tab-content {
display: none;
padding: 1rem 0;
}
.tab-content.active {
@@ -1735,6 +1734,21 @@ p {
gap: 0.75rem;
}
/* Custom dropdown wrapper and arrow for capability selector */
.capability-selector {
display: flex;
align-items: center;
gap: 0.5rem;
}
#capability-select {
padding-right: 2rem;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%23ecf0f1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 9l6 6 6-6"/></svg>');
background-repeat: no-repeat;
background-position: right 0.6rem center;
background-size: 12px 12px;
}
.capability-item {
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.1);