|
3253
|
3253
|
.host-alias-remove, .host-alias-add { min-height: 28px; padding: 3px 7px; font-size: 12px; }
|
|
3254
|
3254
|
.host-alias-remove { min-height: 0; padding: 0; border: 0; background: transparent; color: var(--bad); }
|
|
3255
|
3255
|
.host-alias-remove:hover { background: transparent; }
|
|
|
3256
|
+ .iconbtn { min-width: 34px; width: 34px; justify-content: center; padding: 7px; }
|
|
|
3257
|
+ .iconbtn svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
|
|
|
3258
|
+ .host-actions { display: flex; align-items: center; gap: 6px; }
|
|
3256
|
3259
|
.field-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
3257
|
3260
|
.host-cert-cell { min-width: 0; }
|
|
3258
|
3261
|
#page-vhosts .panel-head { align-items: center; padding-block: 10px; }
|
|
3567
|
3570
|
<label>IP<input name="ip" required></label>
|
|
3568
|
3571
|
<label class="span2"><span class="field-head"><span>Aliases</span><button type="button" id="host-add-alias-editor" class="host-alias-add" title="Add alias">+</button></span><textarea name="aliases"></textarea></label>
|
|
3569
|
3572
|
<label>Roles<input name="roles"></label>
|
|
3570
|
|
- <label>Sources<input name="sources"></label>
|
|
3571
|
3573
|
<label>Monitoring<select name="monitoring"><option>pending</option><option>enabled</option><option>disabled</option></select></label>
|
|
3572
|
3574
|
<label>Notes<input name="notes"></label>
|
|
3573
|
3575
|
<div id="host-form-message" class="span2 form-message" aria-live="polite"></div>
|
|
4050
|
4052
|
<td class="host-cert-cell">${renderHostCertificateCell(h)}</td>
|
|
4051
|
4053
|
<td><span class="pill ${cls}">${escapeHtml(h.monitoring || '')}</span></td>
|
|
4052
|
4054
|
<td>${escapeHtml(h.status || '')}</td>
|
|
4053
|
|
- <td><button type="button" data-edit="${escapeHtml(h.id)}">Edit</button></td>
|
|
|
4055
|
+ <td><div class="host-actions">
|
|
|
4056
|
+ <button type="button" class="iconbtn" data-edit="${escapeHtml(h.id)}" title="Edit ${escapeHtml(h.fqdn || h.id || '')}" aria-label="Edit ${escapeHtml(h.fqdn || h.id || '')}">
|
|
|
4057
|
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 1 1 3 3L7 19l-4 1 1-4z"/></svg>
|
|
|
4058
|
+ </button>
|
|
|
4059
|
+ <button type="button" class="iconbtn danger" data-host-delete="${escapeHtml(h.id)}" title="Delete ${escapeHtml(h.fqdn || h.id || '')}" aria-label="Delete ${escapeHtml(h.fqdn || h.id || '')}">
|
|
|
4060
|
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/></svg>
|
|
|
4061
|
+ </button>
|
|
|
4062
|
+ </div></td>
|
|
4054
|
4063
|
</tr>`;
|
|
4055
|
4064
|
}).join('');
|
|
4056
|
4065
|
document.querySelectorAll('[data-edit]').forEach(button => button.addEventListener('click', () => {
|
|
4058
|
4067
|
if (!isAuthLost(e)) msg(e.message);
|
|
4059
|
4068
|
});
|
|
4060
|
4069
|
}));
|
|
4061
|
|
- document.querySelectorAll('[data-host-alias-add]').forEach(button => button.addEventListener('click', () => {
|
|
4062
|
|
- addHostAlias(button.dataset.hostAliasAdd || '').catch(e => {
|
|
|
4070
|
+ document.querySelectorAll('[data-host-delete]').forEach(button => button.addEventListener('click', () => {
|
|
|
4071
|
+ deleteHostInline(button.dataset.hostDelete || '').catch(e => {
|
|
4063
|
4072
|
if (!isAuthLost(e)) msg(e.message);
|
|
4064
|
4073
|
});
|
|
4065
|
4074
|
}));
|
|
4091
|
4100
|
<span class="host-alias-label">${escapeHtml(name)}</span>
|
|
4092
|
4101
|
<button type="button" class="host-alias-remove" data-host-alias-remove="${escapeHtml(host.fqdn || '')}" data-host-alias-name="${escapeHtml(name)}" title="Delete ${escapeHtml(name)}">x</button>
|
|
4093
|
4102
|
</span>`).join('');
|
|
4094
|
|
- const derivedAliases = (host.derived_aliases || []).map(name => `<span class="pill derived host-alias-pill" title="derived alias">
|
|
4095
|
|
- <span class="host-alias-label">${escapeHtml(name)}</span>
|
|
4096
|
|
- </span>`).join('');
|
|
4097
|
4103
|
return `<div class="host-alias-cell">
|
|
4098
|
|
- <div class="host-alias-list">${aliases}${derivedAliases}</div>
|
|
|
4104
|
+ <div class="host-alias-list">${aliases}</div>
|
|
4099
|
4105
|
</div>`;
|
|
4100
|
4106
|
}
|
|
4101
|
4107
|
|
|
4361
|
4367
|
ip: overrides.ip !== undefined ? overrides.ip : (host.ip || ''),
|
|
4362
|
4368
|
aliases,
|
|
4363
|
4369
|
roles: Array.isArray(overrides.roles) ? overrides.roles : (host.roles || []),
|
|
4364
|
|
- sources: Array.isArray(overrides.sources) ? overrides.sources : (host.sources || []),
|
|
|
4370
|
+ sources: [],
|
|
4365
|
4371
|
monitoring: overrides.monitoring !== undefined ? overrides.monitoring : (host.monitoring || 'pending'),
|
|
4366
|
4372
|
notes: overrides.notes !== undefined ? overrides.notes : (host.notes || ''),
|
|
4367
|
4373
|
};
|
|
4435
|
4441
|
await refresh();
|
|
4436
|
4442
|
}
|
|
4437
|
4443
|
|
|
|
4444
|
+ async function deleteHostInline(id) {
|
|
|
4445
|
+ if (!await ensureAuthenticated('Autentifica-te inainte de stergere.')) return;
|
|
|
4446
|
+ const host = state.hosts.find(entry => String(entry.id || '') === String(id || ''));
|
|
|
4447
|
+ if (!host) return;
|
|
|
4448
|
+ if (!confirm(`Delete ${host.fqdn || host.id || id}?`)) return;
|
|
|
4449
|
+ await api('/api/hosts/delete', {
|
|
|
4450
|
+ method: 'POST',
|
|
|
4451
|
+ headers: { 'Content-Type': 'application/json' },
|
|
|
4452
|
+ body: JSON.stringify({ id: host.id || id }),
|
|
|
4453
|
+ });
|
|
|
4454
|
+ if (hostEditorTarget === String(host.id || '')) closeHostForm(true);
|
|
|
4455
|
+ msg(`host ${host.fqdn || host.id || id} deleted`);
|
|
|
4456
|
+ await refresh();
|
|
|
4457
|
+ }
|
|
|
4458
|
+
|
|
4438
|
4459
|
async function setHostCertificateFromSelect(select) {
|
|
4439
|
4460
|
if (!await ensureAuthenticated('Autentifica-te inainte de salvare.')) {
|
|
4440
|
4461
|
select.value = select.dataset.currentCertificate || '';
|
|
4622
|
4643
|
for (const key of ['id', 'fqdn', 'status', 'ip', 'monitoring', 'notes']) hostField(key).value = host[key] || '';
|
|
4623
|
4644
|
hostField('aliases').value = (host.aliases || []).join('\n');
|
|
4624
|
4645
|
hostField('roles').value = (host.roles || []).join(' ');
|
|
4625
|
|
- hostField('sources').value = (host.sources || []).join(' ');
|
|
4626
|
4646
|
activateHostForm(`Edit host ${host.fqdn || host.id || ''}`.trim(), 'edit', id, 'fqdn');
|
|
4627
|
4647
|
}
|
|
4628
|
4648
|
|
|
4937
|
4957
|
setHostFormBusy(true);
|
|
4938
|
4958
|
setHostFormMessage('Saving...');
|
|
4939
|
4959
|
try {
|
|
4940
|
|
- const savedId = hostField('id').value;
|
|
4941
|
4960
|
await api('/api/hosts/upsert', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formObject(event.target)) });
|
|
4942
|
4961
|
msg('host saved');
|
|
4943
|
4962
|
await refresh();
|
|
4944
|
|
- const host = state.hosts.find(entry => entry.id === savedId);
|
|
4945
|
|
- if (host) {
|
|
4946
|
|
- clearHostFormMessage();
|
|
4947
|
|
- for (const key of ['id', 'fqdn', 'status', 'ip', 'monitoring', 'notes']) hostField(key).value = host[key] || '';
|
|
4948
|
|
- hostField('aliases').value = (host.aliases || []).join('\n');
|
|
4949
|
|
- hostField('roles').value = (host.roles || []).join(' ');
|
|
4950
|
|
- hostField('sources').value = (host.sources || []).join(' ');
|
|
4951
|
|
- activateHostForm(`Edit host ${host.fqdn || host.id || ''}`.trim(), 'edit', host.id || '', 'fqdn', false);
|
|
4952
|
|
- } else {
|
|
4953
|
|
- closeHostForm(true);
|
|
4954
|
|
- }
|
|
|
4963
|
+ closeHostForm(true);
|
|
4955
|
4964
|
} catch (e) {
|
|
4956
|
4965
|
if (isAuthLost(e)) return;
|
|
4957
|
4966
|
setHostFormMessage(e.message, true);
|