feat: boolean param in dynamic form
This commit is contained in:
@@ -375,11 +375,13 @@ class MonitoringViewComponent extends Component {
|
|||||||
return `
|
return `
|
||||||
<div class="node-card error" data-node-ip="${ip}">
|
<div class="node-card error" data-node-ip="${ip}">
|
||||||
<div class="node-header">
|
<div class="node-header">
|
||||||
<div class="node-title">${hostname || ip}</div>
|
<div class="status-hostname-group">
|
||||||
<div class="node-ip">${ip}</div>
|
<div class="node-status-indicator status-offline">
|
||||||
|
🔴
|
||||||
</div>
|
</div>
|
||||||
<div class="node-status">
|
<div class="node-title">${hostname || ip}</div>
|
||||||
<span class="status-badge error">❌ No Resources</span>
|
</div>
|
||||||
|
<div class="node-ip">${ip}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${labels && Object.keys(labels).length > 0 ? `
|
${labels && Object.keys(labels).length > 0 ? `
|
||||||
@@ -453,17 +455,22 @@ class MonitoringViewComponent extends Component {
|
|||||||
storageUtilization = storageTotal > 0 ? Math.round((storageUsed / storageTotal) * 100) : 0;
|
storageUtilization = storageTotal > 0 ? Math.round((storageUsed / storageTotal) * 100) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const resourceSourceText = resourceSource === 'monitoring' ? '📊 Full Monitoring' :
|
// Determine status indicator based on resource source
|
||||||
resourceSource === 'basic' ? '📋 Basic Data' : '❓ Unknown';
|
const statusIcon = resourceSource === 'monitoring' ? '🟢' :
|
||||||
|
resourceSource === 'basic' ? '🟡' : '🔴';
|
||||||
|
const statusClass = resourceSource === 'monitoring' ? 'status-online' :
|
||||||
|
resourceSource === 'basic' ? 'status-warning' : 'status-offline';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="node-card" data-node-ip="${ip}">
|
<div class="node-card" data-node-ip="${ip}">
|
||||||
<div class="node-header">
|
<div class="node-header">
|
||||||
<div class="node-title">${hostname || ip}</div>
|
<div class="status-hostname-group">
|
||||||
<div class="node-ip">${ip}</div>
|
<div class="node-status-indicator ${statusClass}">
|
||||||
|
${statusIcon}
|
||||||
</div>
|
</div>
|
||||||
<div class="node-status">
|
<div class="node-title">${hostname || ip}</div>
|
||||||
<span class="status-badge ${resourceSource === 'monitoring' ? 'success' : 'warning'}">${resourceSourceText}</span>
|
</div>
|
||||||
|
<div class="node-ip">${ip}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${labels && Object.keys(labels).length > 0 ? `
|
${labels && Object.keys(labels).length > 0 ? `
|
||||||
|
|||||||
@@ -99,12 +99,29 @@ class NodeDetailsComponent extends Component {
|
|||||||
value="${defaultValue}">`;
|
value="${defaultValue}">`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderBooleanComponent(p, formId, pidx) {
|
||||||
|
const defaultValue = p.default !== undefined ? p.default : false;
|
||||||
|
const checked = defaultValue ? 'checked' : '';
|
||||||
|
return `<div class="boolean-input-container">
|
||||||
|
<input id="${formId}-field-${pidx}"
|
||||||
|
data-param-name="${p.name}"
|
||||||
|
data-param-location="${p.location || 'body'}"
|
||||||
|
data-param-type="${p.type || 'boolean'}"
|
||||||
|
data-param-required="${p.required ? '1' : '0'}"
|
||||||
|
class="param-input boolean-checkbox"
|
||||||
|
type="checkbox"
|
||||||
|
${checked}>
|
||||||
|
<label for="${formId}-field-${pidx}" class="boolean-label">${p.name}</label>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
// Component map for parameter types
|
// Component map for parameter types
|
||||||
getParameterComponentMap() {
|
getParameterComponentMap() {
|
||||||
const components = {
|
const components = {
|
||||||
select: this.renderSelectComponent,
|
select: this.renderSelectComponent,
|
||||||
color: this.renderColorComponent,
|
color: this.renderColorComponent,
|
||||||
numberRange: this.renderNumberRangeComponent,
|
numberRange: this.renderNumberRangeComponent,
|
||||||
|
boolean: this.renderBooleanComponent,
|
||||||
text: this.renderTextComponent
|
text: this.renderTextComponent
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,7 +136,8 @@ class NodeDetailsComponent extends Component {
|
|||||||
const typeRules = [
|
const typeRules = [
|
||||||
{ condition: () => Array.isArray(p.values) && p.values.length > 1, type: 'select' },
|
{ condition: () => Array.isArray(p.values) && p.values.length > 1, type: 'select' },
|
||||||
{ condition: () => p.type === 'color', type: 'color' },
|
{ condition: () => p.type === 'color', type: 'color' },
|
||||||
{ condition: () => p.type === 'numberRange', type: 'numberRange' }
|
{ condition: () => p.type === 'numberRange', type: 'numberRange' },
|
||||||
|
{ condition: () => p.type === 'boolean', type: 'boolean' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const matchedRule = typeRules.find(rule => rule.condition());
|
const matchedRule = typeRules.find(rule => rule.condition());
|
||||||
@@ -616,6 +634,10 @@ class NodeDetailsComponent extends Component {
|
|||||||
const rgbDisplay = input.parentElement.querySelector('.color-rgb-display');
|
const rgbDisplay = input.parentElement.querySelector('.color-rgb-display');
|
||||||
value = rgbDisplay ? rgbDisplay.value : this.hexToRgbInt(input.value);
|
value = rgbDisplay ? rgbDisplay.value : this.hexToRgbInt(input.value);
|
||||||
}
|
}
|
||||||
|
// For boolean type, convert checkbox checked state to boolean
|
||||||
|
else if (input.dataset.paramType === 'boolean' && input.type === 'checkbox') {
|
||||||
|
value = input.checked;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
name: input.dataset.paramName,
|
name: input.dataset.paramName,
|
||||||
location: input.dataset.paramLocation || 'body',
|
location: input.dataset.paramLocation || 'body',
|
||||||
@@ -626,7 +648,7 @@ class NodeDetailsComponent extends Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Required validation
|
// Required validation
|
||||||
const missing = params.filter(p => p.required && (!p.value || String(p.value).trim() === ''));
|
const missing = params.filter(p => p.required && (p.type === 'boolean' ? false : (!p.value || String(p.value).trim() === '')));
|
||||||
if (missing.length > 0) {
|
if (missing.length > 0) {
|
||||||
resultEl.style.display = 'block';
|
resultEl.style.display = 'block';
|
||||||
resultEl.innerHTML = `
|
resultEl.innerHTML = `
|
||||||
|
|||||||
@@ -749,6 +749,7 @@ p {
|
|||||||
background: rgba(76, 175, 80, 0.3);
|
background: rgba(76, 175, 80, 0.3);
|
||||||
color: var(--accent-success);
|
color: var(--accent-success);
|
||||||
border: 1px solid rgba(76, 175, 80, 0.5);
|
border: 1px solid rgba(76, 175, 80, 0.5);
|
||||||
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-offline {
|
.status-offline {
|
||||||
@@ -2423,6 +2424,56 @@ select.param-input:focus {
|
|||||||
background-size: 12px 12px;
|
background-size: 12px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Boolean checkbox styling */
|
||||||
|
.boolean-input-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.param-input.boolean-checkbox {
|
||||||
|
width: auto;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--border-primary);
|
||||||
|
border-radius: 4px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
appearance: none;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.param-input.boolean-checkbox:checked {
|
||||||
|
background: var(--accent-primary);
|
||||||
|
border-color: var(--accent-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.param-input.boolean-checkbox:checked::after {
|
||||||
|
content: '✓';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
color: white;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.param-input.boolean-checkbox:focus {
|
||||||
|
border-color: rgba(139, 92, 246, 0.5);
|
||||||
|
box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.boolean-label {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
.endpoint-params.none {
|
.endpoint-params.none {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user