From 03340aee7102f4c296b0e83e732bff7d7f14cf1c Mon Sep 17 00:00:00 2001 From: Alex <55413326+AlexRubik@users.noreply.github.com> Date: Tue, 17 Feb 2026 21:31:08 -0700 Subject: [PATCH] [PM-31163] stabilize table column widths with fixed layout (#18708) * stabilize table column widths with fixed layout (PM-31163) Add layout="fixed" and explicit width classes to report tables to prevent column widths from shifting during virtual scroll. Files changed: - weak-passwords-report.component.html - reused-passwords-report.component.html - exposed-passwords-report.component.html - inactive-two-factor-report.component.html - unsecured-websites-report.component.html * use auto width for name column to fix width calculation (PM-31163) Remove tw-w-1/2 from name column headers. With layout="fixed", the explicit percentages didn't sum to 100%, causing inconsistent column widths. Before: | 48px | 50% | 25% | 25% | = 48px + 100% (overflow) After: | 48px | auto | 25% | 25% | = columns sum correctly Name column now uses auto to fill remaining space. * render headers in Admin Console to fix column widths (PM-31163) Admin Console reports had a very wide icon column because no headers were rendered. Without headers, table-layout: fixed uses data row content to determine column widths, causing inconsistent sizing. Root cause: Three reports had their entire block inside @if (!isAdminConsoleActive), so when isAdminConsoleActive=true (Admin Console), no headers were rendered at all. Before (broken): @if (!isAdminConsoleActive) { Icon Name Owner } After (fixed): Icon Name @if (!isAdminConsoleActive) { Owner } This matches the pattern already used by weak-passwords-report and exposed-passwords-report, which were working correctly. Files changed: - unsecured-websites-report.component.html - reused-passwords-report.component.html - inactive-two-factor-report.component.html Result: - Admin Console now renders headers with correct column widths - Icon column is 48px (tw-w-12) as expected - Owner column properly hidden in Admin Console view * truncate long item names to prevent column overflow - you can hover cursor for tooltip to see full name --- .../exposed-passwords-report.component.html | 12 ++--- .../inactive-two-factor-report.component.html | 46 ++++++++++-------- .../reused-passwords-report.component.html | 48 ++++++++++--------- .../unsecured-websites-report.component.html | 46 ++++++++++-------- .../weak-passwords-report.component.html | 10 ++-- 5 files changed, 87 insertions(+), 75 deletions(-) diff --git a/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html b/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html index 144396d6772..56316fcddee 100644 --- a/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/exposed-passwords-report.component.html @@ -43,16 +43,16 @@ > } } - + - + {{ "name" | i18n }} @if (!isAdminConsoleActive) { - + {{ "owner" | i18n }} } - + {{ "timesExposed" | i18n }} @@ -60,7 +60,7 @@ - + @if (!organization || canManageCipher(row)) { } @else { - {{ row.name }} + {{ row.name }} } @if (!organization && row.organizationId) { } } - - @if (!isAdminConsoleActive) { - - - {{ "name" | i18n }} - {{ "owner" | i18n }} - - - } + + + + {{ "name" | i18n }} + @if (!isAdminConsoleActive) { + {{ "owner" | i18n }} + } + + - + @if (!organization || canManageCipher(row)) { {{ row.name }} } @else { - {{ row.name }} + {{ row.name }} } @if (!organization && row.organizationId) { {{ row.subTitle }} - - @if (!organization) { - - } - + @if (!isAdminConsoleActive) { + + @if (!organization) { + + } + + } @if (cipherDocs.has(row.id)) { diff --git a/apps/web/src/app/dirt/reports/pages/reused-passwords-report.component.html b/apps/web/src/app/dirt/reports/pages/reused-passwords-report.component.html index f08af8bda01..66bd11e7bc3 100644 --- a/apps/web/src/app/dirt/reports/pages/reused-passwords-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/reused-passwords-report.component.html @@ -45,20 +45,20 @@ > } } - - @if (!isAdminConsoleActive) { - - - {{ "name" | i18n }} - {{ "owner" | i18n }} - {{ "timesReused" | i18n }} - - } + + + + {{ "name" | i18n }} + @if (!isAdminConsoleActive) { + {{ "owner" | i18n }} + } + {{ "timesReused" | i18n }} + - + @if (!organization || canManageCipher(row)) { {{ row.name }} } @else { - {{ row.name }} + {{ row.name }} } @if (!organization && row.organizationId) { {{ row.subTitle }} - - @if (!organization) { - - - } - + @if (!isAdminConsoleActive) { + + @if (!organization) { + + + } + + } {{ "reusedXTimes" | i18n: passwordUseMap.get(row.login.password) }} diff --git a/apps/web/src/app/dirt/reports/pages/unsecured-websites-report.component.html b/apps/web/src/app/dirt/reports/pages/unsecured-websites-report.component.html index 810c1e384b0..553c3f2f04e 100644 --- a/apps/web/src/app/dirt/reports/pages/unsecured-websites-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/unsecured-websites-report.component.html @@ -45,19 +45,19 @@ > } } - - @if (!isAdminConsoleActive) { - - - {{ "name" | i18n }} - {{ "owner" | i18n }} - - } + + + + {{ "name" | i18n }} + @if (!isAdminConsoleActive) { + {{ "owner" | i18n }} + } + - + @if (!organization || canManageCipher(row)) { {{ row.name }} } @else { - {{ row.name }} + {{ row.name }} } @if (!organization && row.organizationId) { {{ row.subTitle }} - - @if (!organization) { - - - } - + @if (!isAdminConsoleActive) { + + @if (!organization) { + + + } + + } } diff --git a/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html b/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html index 5a187427b5e..fd5b916e661 100644 --- a/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html +++ b/apps/web/src/app/dirt/reports/pages/weak-passwords-report.component.html @@ -45,12 +45,12 @@ > } } - + - + {{ "name" | i18n }} @if (!isAdminConsoleActive) { - + {{ "owner" | i18n }} } @@ -62,7 +62,7 @@ - + @if (!organization || canManageCipher(row)) { {{ row.name }} } @else { - {{ row.name }} + {{ row.name }} } @if (!organization && row.organizationId) {