mirror of
https://github.com/bitwarden/browser
synced 2026-02-20 11:24:07 +00:00
[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 <ng-container header> block inside
@if (!isAdminConsoleActive), so when isAdminConsoleActive=true (Admin
Console), no headers were rendered at all.
Before (broken):
@if (!isAdminConsoleActive) {
<ng-container header> <!-- Entire header skipped in Admin Console -->
<th>Icon</th>
<th>Name</th>
<th>Owner</th>
</ng-container>
}
After (fixed):
<ng-container header> <!-- Always render headers -->
<th>Icon</th>
<th>Name</th>
@if (!isAdminConsoleActive) {
<th>Owner</th> <!-- Only Owner is conditional -->
}
</ng-container>
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
This commit is contained in:
@@ -43,16 +43,16 @@
|
||||
></bit-chip-select>
|
||||
}
|
||||
}
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="54">
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="54" layout="fixed">
|
||||
<ng-container header>
|
||||
<th bitCell></th>
|
||||
<th bitCell class="tw-w-12"></th>
|
||||
<th bitCell bitSortable="name">{{ "name" | i18n }}</th>
|
||||
@if (!isAdminConsoleActive) {
|
||||
<th bitCell bitSortable="organizationId">
|
||||
<th bitCell bitSortable="organizationId" class="tw-w-1/4">
|
||||
{{ "owner" | i18n }}
|
||||
</th>
|
||||
}
|
||||
<th bitCell class="tw-text-right" bitSortable="exposedXTimes">
|
||||
<th bitCell class="tw-w-1/4 tw-text-right" bitSortable="exposedXTimes">
|
||||
{{ "timesExposed" | i18n }}
|
||||
</th>
|
||||
</ng-container>
|
||||
@@ -60,7 +60,7 @@
|
||||
<td bitCell>
|
||||
<app-vault-icon [cipher]="row"></app-vault-icon>
|
||||
</td>
|
||||
<td bitCell>
|
||||
<td bitCell class="tw-truncate tw-max-w-0">
|
||||
@if (!organization || canManageCipher(row)) {
|
||||
<a
|
||||
bitLink
|
||||
@@ -72,7 +72,7 @@
|
||||
{{ row.name }}
|
||||
</a>
|
||||
} @else {
|
||||
<span>{{ row.name }}</span>
|
||||
<span title="{{ row.name }}">{{ row.name }}</span>
|
||||
}
|
||||
@if (!organization && row.organizationId) {
|
||||
<i
|
||||
|
||||
@@ -45,20 +45,20 @@
|
||||
></bit-chip-select>
|
||||
}
|
||||
}
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="75">
|
||||
@if (!isAdminConsoleActive) {
|
||||
<ng-container header>
|
||||
<th bitCell></th>
|
||||
<th bitCell>{{ "name" | i18n }}</th>
|
||||
<th bitCell>{{ "owner" | i18n }}</th>
|
||||
<th bitCell></th>
|
||||
</ng-container>
|
||||
}
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="75" layout="fixed">
|
||||
<ng-container header>
|
||||
<th bitCell class="tw-w-12"></th>
|
||||
<th bitCell>{{ "name" | i18n }}</th>
|
||||
@if (!isAdminConsoleActive) {
|
||||
<th bitCell class="tw-w-1/4">{{ "owner" | i18n }}</th>
|
||||
}
|
||||
<th bitCell class="tw-w-1/4"></th>
|
||||
</ng-container>
|
||||
<ng-template bitRowDef let-row>
|
||||
<td bitCell>
|
||||
<app-vault-icon [cipher]="row"></app-vault-icon>
|
||||
</td>
|
||||
<td bitCell>
|
||||
<td bitCell class="tw-truncate tw-max-w-0">
|
||||
@if (!organization || canManageCipher(row)) {
|
||||
<a
|
||||
bitLink
|
||||
@@ -69,7 +69,7 @@
|
||||
>{{ row.name }}</a
|
||||
>
|
||||
} @else {
|
||||
<span>{{ row.name }}</span>
|
||||
<span title="{{ row.name }}">{{ row.name }}</span>
|
||||
}
|
||||
@if (!organization && row.organizationId) {
|
||||
<i
|
||||
@@ -92,16 +92,20 @@
|
||||
<br />
|
||||
<small>{{ row.subTitle }}</small>
|
||||
</td>
|
||||
<td bitCell>
|
||||
@if (!organization) {
|
||||
<app-org-badge
|
||||
[disabled]="disabled"
|
||||
[organizationId]="row.organizationId"
|
||||
[organizationName]="row.organizationId | orgNameFromId: (organizations$ | async)"
|
||||
appStopProp
|
||||
/>
|
||||
}
|
||||
</td>
|
||||
@if (!isAdminConsoleActive) {
|
||||
<td bitCell>
|
||||
@if (!organization) {
|
||||
<app-org-badge
|
||||
[disabled]="disabled"
|
||||
[organizationId]="row.organizationId"
|
||||
[organizationName]="
|
||||
row.organizationId | orgNameFromId: (organizations$ | async)
|
||||
"
|
||||
appStopProp
|
||||
/>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
<td bitCell class="tw-text-right">
|
||||
@if (cipherDocs.has(row.id)) {
|
||||
<a bitBadge href="{{ cipherDocs.get(row.id) }}" target="_blank" rel="noreferrer">
|
||||
|
||||
@@ -45,20 +45,20 @@
|
||||
></bit-chip-select>
|
||||
}
|
||||
}
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="75">
|
||||
@if (!isAdminConsoleActive) {
|
||||
<ng-container header>
|
||||
<th bitCell></th>
|
||||
<th bitCell>{{ "name" | i18n }}</th>
|
||||
<th bitCell>{{ "owner" | i18n }}</th>
|
||||
<th bitCell class="tw-text-right">{{ "timesReused" | i18n }}</th>
|
||||
</ng-container>
|
||||
}
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="75" layout="fixed">
|
||||
<ng-container header>
|
||||
<th bitCell class="tw-w-12"></th>
|
||||
<th bitCell>{{ "name" | i18n }}</th>
|
||||
@if (!isAdminConsoleActive) {
|
||||
<th bitCell class="tw-w-1/4">{{ "owner" | i18n }}</th>
|
||||
}
|
||||
<th bitCell class="tw-w-1/4 tw-text-right">{{ "timesReused" | i18n }}</th>
|
||||
</ng-container>
|
||||
<ng-template bitRowDef let-row>
|
||||
<td bitCell>
|
||||
<app-vault-icon [cipher]="row"></app-vault-icon>
|
||||
</td>
|
||||
<td bitCell>
|
||||
<td bitCell class="tw-truncate tw-max-w-0">
|
||||
@if (!organization || canManageCipher(row)) {
|
||||
<a
|
||||
bitLink
|
||||
@@ -69,7 +69,7 @@
|
||||
>{{ row.name }}</a
|
||||
>
|
||||
} @else {
|
||||
<span>{{ row.name }}</span>
|
||||
<span title="{{ row.name }}">{{ row.name }}</span>
|
||||
}
|
||||
@if (!organization && row.organizationId) {
|
||||
<i
|
||||
@@ -92,17 +92,21 @@
|
||||
<br />
|
||||
<small>{{ row.subTitle }}</small>
|
||||
</td>
|
||||
<td bitCell>
|
||||
@if (!organization) {
|
||||
<app-org-badge
|
||||
[disabled]="disabled"
|
||||
[organizationId]="row.organizationId"
|
||||
[organizationName]="row.organizationId | orgNameFromId: (organizations$ | async)"
|
||||
appStopProp
|
||||
>
|
||||
</app-org-badge>
|
||||
}
|
||||
</td>
|
||||
@if (!isAdminConsoleActive) {
|
||||
<td bitCell>
|
||||
@if (!organization) {
|
||||
<app-org-badge
|
||||
[disabled]="disabled"
|
||||
[organizationId]="row.organizationId"
|
||||
[organizationName]="
|
||||
row.organizationId | orgNameFromId: (organizations$ | async)
|
||||
"
|
||||
appStopProp
|
||||
>
|
||||
</app-org-badge>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
<td bitCell class="tw-text-right">
|
||||
<span bitBadge variant="warning">
|
||||
{{ "reusedXTimes" | i18n: passwordUseMap.get(row.login.password) }}
|
||||
|
||||
@@ -45,19 +45,19 @@
|
||||
></bit-chip-select>
|
||||
}
|
||||
}
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="75">
|
||||
@if (!isAdminConsoleActive) {
|
||||
<ng-container header>
|
||||
<th bitCell></th>
|
||||
<th bitCell>{{ "name" | i18n }}</th>
|
||||
<th bitCell>{{ "owner" | i18n }}</th>
|
||||
</ng-container>
|
||||
}
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="75" layout="fixed">
|
||||
<ng-container header>
|
||||
<th bitCell class="tw-w-12"></th>
|
||||
<th bitCell>{{ "name" | i18n }}</th>
|
||||
@if (!isAdminConsoleActive) {
|
||||
<th bitCell class="tw-w-1/3">{{ "owner" | i18n }}</th>
|
||||
}
|
||||
</ng-container>
|
||||
<ng-template bitRowDef let-row>
|
||||
<td bitCell>
|
||||
<app-vault-icon [cipher]="row"></app-vault-icon>
|
||||
</td>
|
||||
<td bitCell>
|
||||
<td bitCell class="tw-truncate tw-max-w-0">
|
||||
@if (!organization || canManageCipher(row)) {
|
||||
<a
|
||||
bitLink
|
||||
@@ -68,7 +68,7 @@
|
||||
>{{ row.name }}</a
|
||||
>
|
||||
} @else {
|
||||
<span>{{ row.name }}</span>
|
||||
<span title="{{ row.name }}">{{ row.name }}</span>
|
||||
}
|
||||
@if (!organization && row.organizationId) {
|
||||
<i
|
||||
@@ -91,17 +91,21 @@
|
||||
<br />
|
||||
<small>{{ row.subTitle }}</small>
|
||||
</td>
|
||||
<td bitCell>
|
||||
@if (!organization) {
|
||||
<app-org-badge
|
||||
[disabled]="disabled"
|
||||
[organizationId]="row.organizationId"
|
||||
[organizationName]="row.organizationId | orgNameFromId: (organizations$ | async)"
|
||||
appStopProp
|
||||
>
|
||||
</app-org-badge>
|
||||
}
|
||||
</td>
|
||||
@if (!isAdminConsoleActive) {
|
||||
<td bitCell>
|
||||
@if (!organization) {
|
||||
<app-org-badge
|
||||
[disabled]="disabled"
|
||||
[organizationId]="row.organizationId"
|
||||
[organizationName]="
|
||||
row.organizationId | orgNameFromId: (organizations$ | async)
|
||||
"
|
||||
appStopProp
|
||||
>
|
||||
</app-org-badge>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
</ng-template>
|
||||
</bit-table-scroll>
|
||||
}
|
||||
|
||||
@@ -45,12 +45,12 @@
|
||||
></bit-chip-select>
|
||||
}
|
||||
}
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="54">
|
||||
<bit-table-scroll [dataSource]="dataSource" [rowSize]="54" layout="fixed">
|
||||
<ng-container header>
|
||||
<th bitCell></th>
|
||||
<th bitCell class="tw-w-12"></th>
|
||||
<th bitCell bitSortable="name">{{ "name" | i18n }}</th>
|
||||
@if (!isAdminConsoleActive) {
|
||||
<th bitCell bitSortable="organizationId">
|
||||
<th bitCell bitSortable="organizationId" class="tw-w-1/4">
|
||||
{{ "owner" | i18n }}
|
||||
</th>
|
||||
}
|
||||
@@ -62,7 +62,7 @@
|
||||
<td bitCell>
|
||||
<app-vault-icon [cipher]="row"></app-vault-icon>
|
||||
</td>
|
||||
<td bitCell>
|
||||
<td bitCell class="tw-truncate tw-max-w-0">
|
||||
@if (!organization || canManageCipher(row)) {
|
||||
<a
|
||||
bitLink
|
||||
@@ -73,7 +73,7 @@
|
||||
>{{ row.name }}</a
|
||||
>
|
||||
} @else {
|
||||
<span>{{ row.name }}</span>
|
||||
<span title="{{ row.name }}">{{ row.name }}</span>
|
||||
}
|
||||
@if (!organization && row.organizationId) {
|
||||
<i
|
||||
|
||||
Reference in New Issue
Block a user