Implement async manual CSV ingest, unified UI pagination/filters, and serial placeholder strategy
This commit is contained in:
@@ -8,11 +8,30 @@
|
||||
|
||||
<main class="container">
|
||||
<section class="card">
|
||||
<h2>Component Card</h2>
|
||||
<div class="button-row" style="justify-content: space-between; margin-bottom: 16px;">
|
||||
<h2 style="margin: 0;">Component Card</h2>
|
||||
<div class="button-row">
|
||||
<button class="button" id="component-edit-toggle" type="button">Edit</button>
|
||||
<button class="button button-secondary" id="component-edit-cancel" type="button" hidden>Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="meta" id="component-edit-message" style="margin-bottom: 12px;"></div>
|
||||
<div class="meta-grid">
|
||||
<div><span>Vendor Serial</span>{{.Component.VendorSerial}}</div>
|
||||
<div><span>Vendor</span>{{if .Component.Vendor}}{{.Component.Vendor}}{{else}}—{{end}}</div>
|
||||
<div><span>Model</span>{{if .Component.Model}}{{.Component.Model}}{{else}}—{{end}}</div>
|
||||
<div>
|
||||
<span>Vendor Serial</span>
|
||||
<div class="field-value">{{.Component.VendorSerial}}</div>
|
||||
<input class="input field-input" id="component-vendor-serial-input" value="{{.Component.VendorSerial}}" hidden />
|
||||
</div>
|
||||
<div>
|
||||
<span>Vendor</span>
|
||||
<div class="field-value">{{if .Component.Vendor}}{{.Component.Vendor}}{{else}}—{{end}}</div>
|
||||
<input class="input field-input" id="component-vendor-input" value="{{if .Component.Vendor}}{{.Component.Vendor}}{{end}}" hidden />
|
||||
</div>
|
||||
<div>
|
||||
<span>Model</span>
|
||||
<div class="field-value">{{if .Component.Model}}{{.Component.Model}}{{else}}—{{end}}</div>
|
||||
<input class="input field-input" id="component-model-input" value="{{if .Component.Model}}{{.Component.Model}}{{end}}" hidden />
|
||||
</div>
|
||||
<div><span>Status</span><span class="badge {{componentStatusClass .ComponentStatus}}">{{componentStatusText .ComponentStatus}}</span></div>
|
||||
<div><span>Asset</span>{{if .CurrentAssetID}}<a href="/ui/assets/{{.CurrentAssetID}}">{{.CurrentAssetLabel}}</a>{{else}}—{{end}}</div>
|
||||
<div><span>Firmware</span>{{if .ComponentFirmware}}{{.ComponentFirmware}}{{else}}—{{end}}</div>
|
||||
@@ -74,6 +93,95 @@
|
||||
{{end}}
|
||||
</section>
|
||||
</main>
|
||||
<script>
|
||||
const componentEditToggle = document.getElementById('component-edit-toggle');
|
||||
const componentEditCancel = document.getElementById('component-edit-cancel');
|
||||
const componentEditMessage = document.getElementById('component-edit-message');
|
||||
const componentFieldValues = [...document.querySelectorAll('.field-value')];
|
||||
const componentFieldInputs = [...document.querySelectorAll('.field-input')];
|
||||
const componentInputs = {
|
||||
vendorSerial: document.getElementById('component-vendor-serial-input'),
|
||||
vendor: document.getElementById('component-vendor-input'),
|
||||
model: document.getElementById('component-model-input')
|
||||
};
|
||||
const initialComponentForm = {
|
||||
vendorSerial: componentInputs.vendorSerial ? componentInputs.vendorSerial.value : '',
|
||||
vendor: componentInputs.vendor ? componentInputs.vendor.value : '',
|
||||
model: componentInputs.model ? componentInputs.model.value : ''
|
||||
};
|
||||
let componentEditMode = false;
|
||||
|
||||
function setComponentMessage(message) {
|
||||
if (componentEditMessage) {
|
||||
componentEditMessage.textContent = message;
|
||||
}
|
||||
}
|
||||
|
||||
function resetComponentForm() {
|
||||
if (componentInputs.vendorSerial) componentInputs.vendorSerial.value = initialComponentForm.vendorSerial;
|
||||
if (componentInputs.vendor) componentInputs.vendor.value = initialComponentForm.vendor;
|
||||
if (componentInputs.model) componentInputs.model.value = initialComponentForm.model;
|
||||
}
|
||||
|
||||
function setComponentEditMode(enabled) {
|
||||
componentEditMode = enabled;
|
||||
componentFieldValues.forEach((element) => {
|
||||
element.hidden = enabled;
|
||||
});
|
||||
componentFieldInputs.forEach((element) => {
|
||||
element.hidden = !enabled;
|
||||
});
|
||||
if (componentEditToggle) {
|
||||
componentEditToggle.textContent = enabled ? 'Save' : 'Edit';
|
||||
}
|
||||
if (componentEditCancel) {
|
||||
componentEditCancel.hidden = !enabled;
|
||||
}
|
||||
if (!enabled) {
|
||||
setComponentMessage('');
|
||||
}
|
||||
}
|
||||
|
||||
async function saveComponent() {
|
||||
const payload = {
|
||||
vendor_serial: (componentInputs.vendorSerial ? componentInputs.vendorSerial.value : '').trim(),
|
||||
vendor: (componentInputs.vendor ? componentInputs.vendor.value : '').trim(),
|
||||
model: (componentInputs.model ? componentInputs.model.value : '').trim()
|
||||
};
|
||||
if (!payload.vendor_serial) {
|
||||
setComponentMessage('Vendor serial is required.');
|
||||
return;
|
||||
}
|
||||
const response = await fetch('/registry/components/{{.Component.ID}}', {
|
||||
method: 'PUT',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
if (!response.ok) {
|
||||
const body = await response.json().catch(() => ({error: 'Request failed'}));
|
||||
setComponentMessage(body.error || 'Update component failed');
|
||||
return;
|
||||
}
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
if (componentEditToggle) {
|
||||
componentEditToggle.addEventListener('click', async () => {
|
||||
if (!componentEditMode) {
|
||||
setComponentEditMode(true);
|
||||
return;
|
||||
}
|
||||
await saveComponent();
|
||||
});
|
||||
}
|
||||
|
||||
if (componentEditCancel) {
|
||||
componentEditCancel.addEventListener('click', () => {
|
||||
resetComponentForm();
|
||||
setComponentEditMode(false);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
|
||||
Reference in New Issue
Block a user