diff --git a/ui/src/styles/components.css b/ui/src/styles/components.css index 3192eec831d..50e67582af3 100644 --- a/ui/src/styles/components.css +++ b/ui/src/styles/components.css @@ -1820,22 +1820,21 @@ } .data-table-container { - overflow-x: auto; + overflow: auto; + max-height: 70vh; } .data-table { width: 100%; - border-collapse: collapse; + border-collapse: separate; + border-spacing: 0; font-size: 13px; } -.data-table thead { +.data-table th { position: sticky; top: 0; - z-index: 1; -} - -.data-table th { + z-index: 3; padding: 10px 12px; text-align: left; font-weight: 600; @@ -1937,6 +1936,80 @@ background: var(--bg-hover); } +/* Checkbox column */ +.data-table-checkbox-col { + width: 1%; + padding-left: 12px !important; + padding-right: 4px !important; + text-align: center; + vertical-align: middle; + position: sticky; + left: 0; + z-index: 2; +} + +.data-table th.data-table-checkbox-col { + z-index: 4; + background: var(--bg-elevated); +} + +td.data-table-checkbox-col { + background: var(--card); +} + +.data-table tbody tr:hover td.data-table-checkbox-col { + background: var(--bg-hover); +} + +.data-table-checkbox-col input[type="checkbox"] { + width: 16px; + height: 16px; + margin: 0; + accent-color: var(--accent); + cursor: pointer; + vertical-align: middle; +} + +/* Sticky Key column (second column, after checkbox) */ +.data-table .data-table-key-col { + position: sticky; + left: 36px; + z-index: 2; + min-width: 180px; +} + +.data-table th.data-table-key-col { + z-index: 4; + background: var(--bg-elevated); +} + +td.data-table-key-col { + background: var(--card); + box-shadow: 2px 0 4px rgba(0, 0, 0, 0.08); +} + +.data-table tbody tr:hover td.data-table-key-col { + background: var(--bg-hover); +} + +/* Bulk action bar */ +.data-table-bulk-bar { + display: flex; + align-items: center; + gap: 12px; + padding: 8px 12px; + border-bottom: 1px solid var(--border); + background: var(--accent-subtle); + font-size: 13px; + font-weight: 500; + color: var(--text); +} + +.data-table-bulk-bar .btn svg { + width: 14px; + height: 14px; +} + /* Pagination */ .data-table-pagination { display: flex; @@ -1979,93 +2052,6 @@ cursor: not-allowed; } -/* Row actions */ -.data-table-row-actions { - position: relative; -} - -.data-table-row-actions__trigger { - display: inline-flex; - align-items: center; - justify-content: center; - width: 32px; - height: 32px; - border: 1px solid transparent; - border-radius: var(--radius-sm); - background: transparent; - color: var(--muted); - cursor: pointer; - transition: - background var(--duration-fast) ease, - color var(--duration-fast) ease, - border-color var(--duration-fast) ease; -} - -.data-table-row-actions__trigger svg { - width: 16px; - height: 16px; - stroke: currentColor; - fill: none; - stroke-width: 2px; -} - -.data-table-row-actions__trigger:hover { - background: var(--bg-hover); - color: var(--text); - border-color: var(--border); -} - -.data-table-row-actions__menu { - position: absolute; - right: 0; - top: 100%; - z-index: 42; - min-width: 140px; - background: var(--popover); - border: 1px solid var(--border-strong); - border-radius: var(--radius-md); - box-shadow: var(--shadow-md); - padding: 4px; - animation: fade-in var(--duration-fast) ease; -} - -.data-table-row-actions__menu a, -.data-table-row-actions__menu button { - display: block; - width: 100%; - padding: 8px 12px; - font-size: 13px; - text-align: left; - text-decoration: none; - color: var(--text); - background: transparent; - border: none; - border-radius: var(--radius-sm); - cursor: pointer; - transition: background var(--duration-fast) ease; -} - -.data-table-row-actions__menu a:hover, -.data-table-row-actions__menu button:hover { - background: var(--bg-hover); -} - -.data-table-row-actions__menu button.danger { - color: var(--danger); -} - -.data-table-row-actions__menu button.danger:hover { - background: var(--danger-subtle); -} - -/* Click-away overlay for open menus */ -.data-table-overlay { - position: fixed; - inset: 0; - z-index: 40; - background: transparent; -} - /* Inline form fields for filter bars */ .field-inline { display: inline-flex; @@ -4074,6 +4060,29 @@ details[open] > .ov-expandable-toggle::after { } } +/* ── Shared collapse chevron ── */ + +.collapse-chevron { + display: inline-flex; + align-items: center; + justify-content: center; + transition: transform var(--duration-fast) ease; +} + +.collapse-chevron svg { + width: 12px; + height: 12px; + stroke: currentColor; + fill: none; + stroke-width: 1.5px; + stroke-linecap: round; + stroke-linejoin: round; +} + +.collapse-chevron--collapsed { + transform: rotate(-90deg); +} + @media (max-width: 600px) { .ov-cards { grid-template-columns: repeat(2, 1fr); diff --git a/ui/src/styles/layout.mobile.css b/ui/src/styles/layout.mobile.css index 6d943253804..2828b6a4dfc 100644 --- a/ui/src/styles/layout.mobile.css +++ b/ui/src/styles/layout.mobile.css @@ -651,3 +651,113 @@ font-size: 12px; } } + +/* =========================================== + Sessions table – responsive column hiding + =========================================== */ + +/* nth-child is 1-based and includes the checkbox column (col 1). */ + +/* ≤1400px: hide Verbose (col 9) and Reasoning (col 10) */ +@media (max-width: 1400px) { + .data-table th:nth-child(9), + .data-table td:nth-child(9), + .data-table th:nth-child(10), + .data-table td:nth-child(10) { + display: none; + } +} + +/* ≤1100px: also hide Fast (col 8) and Kind (col 4) */ +@media (max-width: 1100px) { + .data-table th:nth-child(4), + .data-table td:nth-child(4), + .data-table th:nth-child(8), + .data-table td:nth-child(8) { + display: none; + } + + .data-table th, + .data-table td { + padding: 8px 10px; + } +} + +/* ≤900px: also hide Thinking (col 7) and Label (col 3) */ +@media (max-width: 900px) { + .data-table th:nth-child(3), + .data-table td:nth-child(3), + .data-table th:nth-child(7), + .data-table td:nth-child(7) { + display: none; + } +} + +/* ≤768px: also hide Tokens (col 6); tighten padding; stack pagination */ +@media (max-width: 768px) { + .data-table th:nth-child(6), + .data-table td:nth-child(6) { + display: none; + } + + .data-table th, + .data-table td { + padding: 8px 6px; + font-size: 12px; + } + + .data-table-pagination { + flex-direction: column; + align-items: stretch; + gap: 8px; + padding: 10px 8px; + } + + .data-table-pagination__info { + text-align: center; + } + + .data-table-pagination__controls { + justify-content: center; + } + + .data-table-search input { + font-size: 14px; + padding: 8px 10px; + } + + .data-table-wrapper { + border-radius: var(--radius-sm); + } + + .session-key-cell { + max-width: 200px; + } + + .session-key-cell .session-link, + .session-key-cell .session-key-display-name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + overflow-wrap: normal; + word-break: normal; + } + + .filters { + flex-wrap: wrap; + gap: 8px; + } +} + +/* ≤500px: tighten further, truncate key column */ +@media (max-width: 500px) { + .data-table th, + .data-table td { + padding: 6px 4px; + font-size: 11px; + } + + .session-key-cell { + max-width: 140px; + } +} diff --git a/ui/src/ui/app-render.ts b/ui/src/ui/app-render.ts index c0535cd6c30..7ccc386de0b 100644 --- a/ui/src/ui/app-render.ts +++ b/ui/src/ui/app-render.ts @@ -70,7 +70,7 @@ import { import { loadLogs } from "./controllers/logs.ts"; import { loadNodes } from "./controllers/nodes.ts"; import { loadPresence } from "./controllers/presence.ts"; -import { deleteSessionAndRefresh, loadSessions, patchSession } from "./controllers/sessions.ts"; +import { deleteSessionsAndRefresh, loadSessions, patchSession } from "./controllers/sessions.ts"; import { installSkill, loadSkills, @@ -477,7 +477,7 @@ export function renderApp(state: AppViewState) { title="${navCollapsed ? t("nav.expand") : t("nav.collapse")}" aria-label="${navCollapsed ? t("nav.expand") : t("nav.collapse")}" > - +