feat(hosts): add host detail page with identity edit, port management and delete

- Repository: add update_host (name, IP, network reassignment with CIDR validation)
- API: get_host_detail (host + resolved network + ports), update_host,
  add_host_port, remove_host_port server functions
- Client: HostDetailPage at /hosts/:id — identity form, ports list with
  per-port Remove button, Add port input, delete confirmation modal with
  navigation back to /hosts on success
- CSS: detail-section cards, port-row list, btn-danger-solid, back-link

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-16 02:21:00 +02:00
parent 0221ce26f9
commit 2a6d925e59
6 changed files with 621 additions and 5 deletions

View File

@@ -1021,6 +1021,39 @@ td.col-actions {
background: var(--accent-hover);
}
/* Solid danger button — used for prominent destructive actions (page header) */
.btn-danger-solid {
background: var(--danger);
color: #fff;
border-color: var(--danger);
font-size: var(--font-sm);
padding: 8px var(--size-md);
font-weight: 500;
}
.btn-danger-solid:hover {
filter: brightness(0.9);
}
/* Left cluster inside page header (back link + title) */
.page-header__left {
display: flex;
align-items: center;
gap: var(--size-md);
}
.back-link {
font-size: var(--font-sm);
color: var(--text-secondary);
text-decoration: none;
white-space: nowrap;
}
.back-link:hover {
color: var(--text);
text-decoration: underline;
}
/* Delete button inside hosts table */
.hosts-page td button {
background: transparent;
@@ -1037,3 +1070,107 @@ td.col-actions {
background: var(--danger-light);
border-color: var(--danger);
}
/* ============================================================
HOST DETAIL PAGE
============================================================ */
.host-detail-page {
max-width: 720px;
}
/* Card-like section grouping related fields */
.detail-section {
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: var(--radius-md);
padding: var(--size-lg);
margin-bottom: var(--size-lg);
}
.detail-section__title {
font-size: var(--font-base);
font-weight: 600;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.05em;
margin: 0 0 var(--size-md);
}
/* Stack of label + input pairs */
.detail-form {
display: flex;
flex-direction: column;
gap: var(--size-md);
}
.detail-field {
display: flex;
flex-direction: column;
gap: var(--size-xs);
font-size: var(--font-sm);
font-weight: 500;
color: var(--text-secondary);
}
.detail-field input,
.detail-field select {
width: 100%;
box-sizing: border-box;
}
/* Save button aligned to the right */
.form-actions {
display: flex;
justify-content: flex-end;
padding-top: var(--size-xs);
}
/* ── Ports list ─────────────────────────────────────────────── */
.port-list {
display: flex;
flex-direction: column;
gap: var(--size-xs);
margin-bottom: var(--size-md);
}
.port-row {
display: flex;
align-items: center;
gap: var(--size-md);
padding: var(--size-sm) var(--size-sm);
border-radius: var(--radius-sm);
background: var(--bg);
border: 1px solid var(--border);
}
.port-row__number {
font-family: var(--font-mono);
font-size: var(--font-sm);
font-weight: 600;
min-width: 4ch;
color: var(--accent);
}
.port-row__desc {
flex: 1;
font-size: var(--font-sm);
color: var(--text-secondary);
}
/* Add port row: input + button side by side */
.port-add-row {
display: flex;
align-items: center;
gap: var(--size-sm);
padding-top: var(--size-sm);
border-top: 1px solid var(--border);
margin-top: var(--size-sm);
flex-wrap: wrap;
}
.port-add-row input[type="number"] {
width: 200px;
flex-shrink: 0;
}