style: align all aria pages to canonical TemplatePage layout
CD - Develop / build-and-deploy (push) Failing after 11m51s
CD - Develop / build-and-deploy (push) Failing after 11m51s
- page-right/content-frame/active-filters now match TemplatePage exactly - active-filters gets the blue tinted background box (#f0f4ff, border #d0d9f0) - content-frame uses padding+gap instead of margin-top - page-right gets padding:0.65rem + gap:0.5rem - ThreatEvents restructured with content-frame wrapper and toolbar-count - IocManagement .count renamed to .toolbar-count Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -489,6 +489,8 @@
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
padding: 0.65rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.content-frame {
|
||||
@@ -499,8 +501,9 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
margin-top: 8px;
|
||||
background: white;
|
||||
padding: 1rem;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
/* Filter sidebar — canonical from template */
|
||||
@@ -543,7 +546,8 @@
|
||||
/* Active filter chips */
|
||||
.active-filters {
|
||||
display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
|
||||
margin-bottom: 8px; padding: 0.5rem 0.75rem; flex-shrink: 0;
|
||||
margin-bottom: 1rem; padding: 0.6rem 1rem;
|
||||
background: #f0f4ff; border: 1px solid #d0d9f0; border-radius: 8px; flex-shrink: 0;
|
||||
}
|
||||
.active-filters-label { font-size: var(--font-size-tiny); font-weight: 600; color: #555; margin-right: 0.25rem; }
|
||||
.filter-tag {
|
||||
@@ -563,10 +567,10 @@
|
||||
|
||||
/* Toolbar */
|
||||
.page-main {
|
||||
flex: 1; overflow-y: auto; padding: 16px 24px 24px;
|
||||
flex: 1; overflow-y: auto;
|
||||
min-width: 0; display: flex; flex-direction: column;
|
||||
}
|
||||
.toolbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; flex-shrink: 0; }
|
||||
.toolbar { display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
|
||||
.toolbar-count { font-size: var(--font-size-body-sm); color: #6b7280; }
|
||||
.header-controls { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
|
||||
.btn-manual-refresh {
|
||||
|
||||
@@ -223,7 +223,7 @@
|
||||
<div class="page-main">
|
||||
|
||||
<div class="toolbar">
|
||||
<span class="count">{filteredIocs.length} IOC{filteredIocs.length !== 1 ? 's' : ''}</span>
|
||||
<span class="toolbar-count">{filteredIocs.length} IOC{filteredIocs.length !== 1 ? 's' : ''}</span>
|
||||
<div class="toolbar-right">
|
||||
<button class="btn btn-primary btn-sm" on:click={openAdd}>+ Add IOC</button>
|
||||
</div>
|
||||
@@ -371,14 +371,16 @@
|
||||
.page-right {
|
||||
flex: 1; display: flex; flex-direction: column;
|
||||
overflow: hidden; min-height: 0;
|
||||
padding: 0.65rem; gap: 0.5rem;
|
||||
}
|
||||
.content-frame {
|
||||
flex: 1; border: 1px solid #e5e7eb; border-radius: 8px;
|
||||
overflow: hidden; display: flex; flex-direction: column;
|
||||
min-height: 0; margin-top: 8px; background: white;
|
||||
min-height: 0; background: white;
|
||||
padding: 1rem; gap: 0.75rem;
|
||||
}
|
||||
.page-main {
|
||||
flex: 1; overflow-y: auto; padding: 16px 24px 24px;
|
||||
flex: 1; overflow-y: auto;
|
||||
min-width: 0; display: flex; flex-direction: column;
|
||||
}
|
||||
|
||||
@@ -435,7 +437,8 @@
|
||||
/* Active filter chips */
|
||||
.active-filters {
|
||||
display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
|
||||
margin-bottom: 0; padding: 0.5rem 0.75rem; flex-shrink: 0;
|
||||
margin-bottom: 1rem; padding: 0.6rem 1rem;
|
||||
background: #f0f4ff; border: 1px solid #d0d9f0; border-radius: 8px; flex-shrink: 0;
|
||||
}
|
||||
.active-filters-label { font-size: var(--font-size-tiny); font-weight: 600; color: #555; margin-right: 0.25rem; }
|
||||
.filter-tag {
|
||||
@@ -454,9 +457,9 @@
|
||||
.filter-tag-remove:hover { background: #f44336; color: white; }
|
||||
|
||||
/* Toolbar */
|
||||
.toolbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; flex-shrink: 0; }
|
||||
.toolbar { display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
|
||||
.toolbar-right { display: flex; gap: 0.5rem; }
|
||||
.count { color: #6b7280; font-size: var(--font-size-body-sm); }
|
||||
.toolbar-count { color: #6b7280; font-size: var(--font-size-body-sm); }
|
||||
|
||||
/* Table */
|
||||
.table-card {
|
||||
@@ -552,7 +555,7 @@
|
||||
:global(.dark-mode) .filter-tag { background: #1f2937; border-color: #374151; border-left-color: #3b82f6; color: #e5e5e5; }
|
||||
:global(.dark-mode) .filter-tag-remove { background: #374151; color: #e5e7eb; }
|
||||
|
||||
:global(.dark-mode) .count { color: #9ca3af; }
|
||||
:global(.dark-mode) .toolbar-count { color: #9ca3af; }
|
||||
:global(.dark-mode) .table-card { background: #1f2937; }
|
||||
:global(.dark-mode) thead { background: #111827; }
|
||||
:global(.dark-mode) th { background: #111827; color: #9ca3af; border-bottom-color: #374151; }
|
||||
|
||||
@@ -467,6 +467,8 @@
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
padding: 0.65rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.content-frame {
|
||||
@@ -477,8 +479,9 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
margin-top: 8px;
|
||||
background: white;
|
||||
padding: 1rem;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
/* Filter sidebar — canonical from template */
|
||||
@@ -523,7 +526,8 @@
|
||||
/* Active filter chips */
|
||||
.active-filters {
|
||||
display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem;
|
||||
margin-bottom: 8px; padding: 0.5rem 0.75rem; flex-shrink: 0;
|
||||
margin-bottom: 1rem; padding: 0.6rem 1rem;
|
||||
background: #f0f4ff; border: 1px solid #d0d9f0; border-radius: 8px; flex-shrink: 0;
|
||||
}
|
||||
.active-filters-label { font-size: var(--font-size-tiny); font-weight: 600; color: #555; margin-right: 0.25rem; }
|
||||
.filter-tag {
|
||||
@@ -543,10 +547,10 @@
|
||||
|
||||
/* Toolbar */
|
||||
.page-main {
|
||||
flex: 1; overflow-y: auto; padding: 16px 24px 24px;
|
||||
flex: 1; overflow-y: auto;
|
||||
min-width: 0; display: flex; flex-direction: column;
|
||||
}
|
||||
.toolbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; flex-shrink: 0; }
|
||||
.toolbar { display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
|
||||
.toolbar-count { font-size: var(--font-size-body-sm); color: #6b7280; }
|
||||
|
||||
.header-controls { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; }
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
onDestroy(() => clearInterval(tickInterval));
|
||||
</script>
|
||||
|
||||
<div class="page-wrap">
|
||||
<div class="page-wrapper">
|
||||
<div class="header">
|
||||
<div class="header-text">
|
||||
<h1>Threat Events</h1>
|
||||
@@ -203,19 +203,19 @@
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="page-main">
|
||||
<div class="page-right">
|
||||
{#if hasActiveFilters}
|
||||
<div class="active-filters">
|
||||
<span class="active-filters-label">Filters:</span>
|
||||
{#if severityFilter}
|
||||
<span class="filter-tag" style="border-color:{SEV_COLOR[severityFilter]}">
|
||||
<span class="filter-tag" style="border-left-color:{SEV_COLOR[severityFilter]}">
|
||||
<span class="filter-tag-dot" style="background:{SEV_COLOR[severityFilter]}"></span>
|
||||
Severity: {severityFilter}
|
||||
<button class="filter-tag-remove" on:click={() => { severityFilter = ''; page = 0; load(); }}>×</button>
|
||||
</span>
|
||||
{/if}
|
||||
{#if deviceSearch}
|
||||
<span class="filter-tag" style="border-color:#6b7280">
|
||||
<span class="filter-tag" style="border-left-color:#6b7280">
|
||||
<span class="filter-tag-dot" style="background:#6b7280"></span>
|
||||
Device: {deviceSearch}
|
||||
<button class="filter-tag-remove" on:click={() => { deviceSearch = ''; deviceSearchInput = ''; page = 0; load(); }}>×</button>
|
||||
@@ -224,52 +224,58 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="table-card">
|
||||
<Pagination {page} {totalPages} {totalElements} {size}
|
||||
on:pageChange={e => { page = e.detail.page; load(); }}
|
||||
on:pageSizeChange={e => { size = e.detail.size; page = 0; load(); }} />
|
||||
<div class="table-container">
|
||||
{#if loading}
|
||||
<div class="table-loading">Loading…</div>
|
||||
{:else if events.length === 0}
|
||||
<div class="table-empty">No threat events found{hasActiveFilters ? ' matching current filters' : ''}.</div>
|
||||
{:else}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Severity</th>
|
||||
<th>Signal</th>
|
||||
<th>Device</th>
|
||||
<th>Attack Phase</th>
|
||||
<th>IOC Match</th>
|
||||
<th>Detected</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each events as ev (ev.id)}
|
||||
<div class="content-frame">
|
||||
<div class="toolbar">
|
||||
<span class="toolbar-count">{totalElements} event{totalElements !== 1 ? 's' : ''}</span>
|
||||
<div class="toolbar-right"></div>
|
||||
</div>
|
||||
<div class="table-card">
|
||||
<Pagination {page} {totalPages} {totalElements} {size}
|
||||
on:pageChange={e => { page = e.detail.page; load(); }}
|
||||
on:pageSizeChange={e => { size = e.detail.size; page = 0; load(); }} />
|
||||
<div class="table-container">
|
||||
{#if loading}
|
||||
<div class="table-loading">Loading…</div>
|
||||
{:else if events.length === 0}
|
||||
<div class="table-empty">No threat events found{hasActiveFilters ? ' matching current filters' : ''}.</div>
|
||||
{:else}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="sev-badge" style="background:{SEV_COLOR[ev.severity]}20;color:{SEV_COLOR[ev.severity]};border:1px solid {SEV_COLOR[ev.severity]}40">
|
||||
{ev.severity}
|
||||
</span>
|
||||
</td>
|
||||
<td class="signal-cell" title={ev.signalKey}>{fmtSignal(ev.signalKey)}</td>
|
||||
<td class="mono-cell">{ev.deviceAgentId ?? '—'}</td>
|
||||
<td>{ev.attackPhase ? PHASE_LABEL[ev.attackPhase] ?? ev.attackPhase : '—'}</td>
|
||||
<td class="ioc-cell" title={ev.matchedIoc?.value ?? ''}>
|
||||
{#if ev.matchedIoc}
|
||||
<span class="ioc-type-badge">{ev.matchedIoc.iocType}</span>
|
||||
<span class="ioc-val">{ev.matchedIoc.value}</span>
|
||||
{:else}
|
||||
<span class="muted">—</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="date-cell">{fmt(ev.detectedAt)}</td>
|
||||
<th>Severity</th>
|
||||
<th>Signal</th>
|
||||
<th>Device</th>
|
||||
<th>Attack Phase</th>
|
||||
<th>IOC Match</th>
|
||||
<th>Detected</th>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/if}
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each events as ev (ev.id)}
|
||||
<tr>
|
||||
<td>
|
||||
<span class="sev-badge" style="background:{SEV_COLOR[ev.severity]}20;color:{SEV_COLOR[ev.severity]};border:1px solid {SEV_COLOR[ev.severity]}40">
|
||||
{ev.severity}
|
||||
</span>
|
||||
</td>
|
||||
<td class="signal-cell" title={ev.signalKey}>{fmtSignal(ev.signalKey)}</td>
|
||||
<td class="mono-cell">{ev.deviceAgentId ?? '—'}</td>
|
||||
<td>{ev.attackPhase ? PHASE_LABEL[ev.attackPhase] ?? ev.attackPhase : '—'}</td>
|
||||
<td class="ioc-cell" title={ev.matchedIoc?.value ?? ''}>
|
||||
{#if ev.matchedIoc}
|
||||
<span class="ioc-type-badge">{ev.matchedIoc.iocType}</span>
|
||||
<span class="ioc-val">{ev.matchedIoc.value}</span>
|
||||
{:else}
|
||||
<span class="muted">—</span>
|
||||
{/if}
|
||||
</td>
|
||||
<td class="date-cell">{fmt(ev.detectedAt)}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -277,7 +283,7 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.page-wrap {
|
||||
.page-wrapper {
|
||||
display: flex; flex-direction: column;
|
||||
height: 100%; overflow: hidden;
|
||||
padding: 24px 24px 0;
|
||||
@@ -304,7 +310,7 @@
|
||||
:global(.pulsing) { animation: countdown-pulse 0.8s ease-in-out infinite; }
|
||||
|
||||
.page-body {
|
||||
display: flex; flex: 1; overflow: hidden; min-height: 0;
|
||||
display: flex; flex: 1; overflow: hidden; min-height: 0; margin: 0 0 16px;
|
||||
}
|
||||
|
||||
/* Filter sidebar */
|
||||
@@ -344,7 +350,7 @@
|
||||
.sidebar-clear-all-btn:hover { background: #fecaca; }
|
||||
|
||||
/* Active filters */
|
||||
.active-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-bottom: 8px; padding: 0.5rem 0.75rem; flex-shrink: 0; }
|
||||
.active-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-bottom: 1rem; padding: 0.6rem 1rem; background: #f0f4ff; border: 1px solid #d0d9f0; border-radius: 8px; flex-shrink: 0; }
|
||||
.active-filters-label { font-size: var(--font-size-tiny); font-weight: 600; color: #555; margin-right: 0.25rem; }
|
||||
.filter-tag { display: inline-flex; align-items: center; gap: 0.4rem; padding: 0.3rem 0.6rem; background: white; border: 1px solid #ddd; border-left-width: 3px; border-radius: 4px; font-size: var(--font-size-tiny); font-weight: 500; color: #333; }
|
||||
.filter-tag-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
|
||||
@@ -352,7 +358,11 @@
|
||||
.filter-tag-remove:hover { background: #f44336; color: white; }
|
||||
|
||||
/* Content */
|
||||
.page-main { flex: 1; overflow-y: auto; padding: 16px 24px 24px; min-width: 0; display: flex; flex-direction: column; }
|
||||
.page-right { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-height: 0; padding: 0.65rem; gap: 0.5rem; }
|
||||
.content-frame { flex: 1; border: 1px solid #e5e7eb; border-radius: 8px; overflow: hidden; display: flex; flex-direction: column; min-height: 0; background: white; padding: 1rem; gap: 0.75rem; }
|
||||
.toolbar { display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; }
|
||||
.toolbar-count { font-size: var(--font-size-body-sm); color: #6b7280; }
|
||||
.toolbar-right { display: flex; gap: 0.5rem; }
|
||||
|
||||
.table-card {
|
||||
background: white;
|
||||
@@ -437,6 +447,8 @@
|
||||
:global(.dark-mode) .date-cell { color: #9ca3af; }
|
||||
:global(.dark-mode) .table-loading, :global(.dark-mode) .table-empty { color: #9ca3af; }
|
||||
:global(.dark-mode) .ioc-type-badge { background: #1e3a5f; color: #93c5fd; }
|
||||
:global(.dark-mode) .content-frame { border-color: #374151; background: #1f2937; }
|
||||
:global(.dark-mode) .toolbar-count { color: #9ca3af; }
|
||||
:global(.dark-mode) .active-filters { background: #111827; border-color: #374151; }
|
||||
:global(.dark-mode) .active-filters-label { color: #9ca3af; }
|
||||
:global(.dark-mode) .filter-tag { background: #1f2937; border-color: #374151; color: #e5e5e5; }
|
||||
|
||||
Reference in New Issue
Block a user