mirror of
https://github.com/bitwarden/browser
synced 2026-02-02 09:43:29 +00:00
changes suggested by claude
This commit is contained in:
@@ -65,17 +65,19 @@
|
||||
</sm-section>
|
||||
<sm-section>
|
||||
<h2 slot="summary" class="tw-mb-0" bitTypography="h2" noMargin>{{ "secrets" | i18n }}</h2>
|
||||
<sm-secrets-list
|
||||
baseRoute="secrets"
|
||||
(deleteSecretsEvent)="openDeleteSecret($event)"
|
||||
(newSecretEvent)="openNewSecretDialog()"
|
||||
(editSecretEvent)="openEditSecret($event)"
|
||||
(viewSecretEvent)="openViewSecret($event)"
|
||||
(copySecretNameEvent)="copySecretName($event)"
|
||||
(copySecretValueEvent)="copySecretValue($event)"
|
||||
(copySecretUuidEvent)="copySecretUuid($event)"
|
||||
[secrets]="view.latestSecrets"
|
||||
></sm-secrets-list>
|
||||
<div class="tw-overflow-auto">
|
||||
<sm-secrets-list
|
||||
baseRoute="secrets"
|
||||
(deleteSecretsEvent)="openDeleteSecret($event)"
|
||||
(newSecretEvent)="openNewSecretDialog()"
|
||||
(editSecretEvent)="openEditSecret($event)"
|
||||
(viewSecretEvent)="openViewSecret($event)"
|
||||
(copySecretNameEvent)="copySecretName($event)"
|
||||
(copySecretValueEvent)="copySecretValue($event)"
|
||||
(copySecretUuidEvent)="copySecretUuid($event)"
|
||||
[secrets]="view.latestSecrets"
|
||||
></sm-secrets-list>
|
||||
</div>
|
||||
<div *ngIf="view.allSecrets.length > 0" class="tw-ml-auto tw-mt-4 tw-max-w-max">
|
||||
{{ "showingPortionOfTotal" | i18n: view.latestSecrets.length : view.counts.secrets }}
|
||||
<a bitLink routerLink="secrets" class="tw-ml-2">{{ "viewAll" | i18n }}</a>
|
||||
|
||||
@@ -23,126 +23,160 @@
|
||||
</bit-no-items>
|
||||
</ng-container>
|
||||
|
||||
<bit-table-scroll *ngIf="secrets?.length >= 1" [dataSource]="dataSource" [rowSize]="66">
|
||||
<ng-container header>
|
||||
<th bitCell class="tw-w-0">
|
||||
<label class="!tw-mb-0 tw-flex tw-w-fit tw-gap-2 !tw-font-bold !tw-text-muted">
|
||||
<input
|
||||
type="checkbox"
|
||||
(change)="$event ? toggleAll() : null"
|
||||
[checked]="selection.hasValue() && isAllSelected()"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()"
|
||||
/>
|
||||
{{ "all" | i18n }}
|
||||
</label>
|
||||
</th>
|
||||
<th bitCell bitSortable="name" default>{{ "name" | i18n }}</th>
|
||||
<th bitCell bitSortable="projects" [fn]="sortProjects">{{ "project" | i18n }}</th>
|
||||
<th bitCell bitSortable="revisionDate">{{ "lastEdited" | i18n }}</th>
|
||||
<th bitCell class="tw-w-0">
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-ellipsis-v"
|
||||
buttonType="main"
|
||||
[label]="'options' | i18n"
|
||||
[bitMenuTriggerFor]="tableMenu"
|
||||
></button>
|
||||
</th>
|
||||
</ng-container>
|
||||
<ng-template bitRowDef let-row>
|
||||
<td bitCell>
|
||||
<input
|
||||
type="checkbox"
|
||||
(change)="$event ? selection.toggle(row.id) : null"
|
||||
[checked]="selection.isSelected(row.id)"
|
||||
/>
|
||||
</td>
|
||||
<td bitCell>
|
||||
<div class="tw-flex tw-items-center tw-gap-4 tw-break-all">
|
||||
<i class="bwi bwi-key tw-text-muted" aria-hidden="true"></i>
|
||||
<div>
|
||||
<div *ngIf="!trash">
|
||||
<button type="button" bitLink (click)="editSecret(row)">
|
||||
{{ row.name }}
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="trash">{{ row.name }}</div>
|
||||
<div class="tw-text-sm tw-text-muted">
|
||||
{{ row.id }}
|
||||
<cdk-virtual-scroll-viewport
|
||||
*ngIf="secrets?.length >= 1"
|
||||
[itemSize]="rowHeight"
|
||||
bitScrollLayout
|
||||
[style.height]="viewportHeight"
|
||||
class="tw-block"
|
||||
>
|
||||
<bit-table [dataSource]="dataSource">
|
||||
<ng-container header>
|
||||
<tr>
|
||||
<th bitCell class="tw-w-0">
|
||||
<label class="!tw-mb-0 tw-flex tw-w-fit tw-gap-2 !tw-font-bold !tw-text-muted">
|
||||
<input
|
||||
type="checkbox"
|
||||
(change)="$event ? toggleAll() : null"
|
||||
[checked]="selection.hasValue() && isAllSelected()"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected()"
|
||||
/>
|
||||
{{ "all" | i18n }}
|
||||
</label>
|
||||
</th>
|
||||
<th bitCell bitSortable="name" default>{{ "name" | i18n }}</th>
|
||||
<th bitCell bitSortable="projects" [fn]="sortProjects">{{ "project" | i18n }}</th>
|
||||
<th bitCell bitSortable="revisionDate">{{ "lastEdited" | i18n }}</th>
|
||||
<th bitCell class="tw-w-0">
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-ellipsis-v"
|
||||
buttonType="main"
|
||||
[label]="'options' | i18n"
|
||||
[bitMenuTriggerFor]="tableMenu"
|
||||
></button>
|
||||
</th>
|
||||
</tr>
|
||||
</ng-container>
|
||||
<ng-template body let-rows$>
|
||||
<ng-container *cdkVirtualFor="let row of rows$; templateCacheSize: 0">
|
||||
<tr bitRow [ngClass]="rowHeightClass">
|
||||
<td bitCell>
|
||||
<input
|
||||
type="checkbox"
|
||||
(change)="$event ? selection.toggle(row.id) : null"
|
||||
[checked]="selection.isSelected(row.id)"
|
||||
/>
|
||||
</td>
|
||||
<td bitCell>
|
||||
<div class="tw-flex tw-items-center tw-gap-4 tw-break-all">
|
||||
<i class="bwi bwi-key tw-text-muted" aria-hidden="true"></i>
|
||||
<div>
|
||||
<div *ngIf="!trash">
|
||||
<button type="button" bitLink (click)="editSecret(row)">
|
||||
{{ row.name }}
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="trash">{{ row.name }}</div>
|
||||
<div class="tw-text-sm tw-text-muted">
|
||||
{{ row.id }}
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-clone"
|
||||
buttonType="main"
|
||||
size="small"
|
||||
[label]="'copyUuid' | i18n"
|
||||
(click)="copySecretUuidEvent.emit(row.id)"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td bitCell>
|
||||
<span
|
||||
*ngFor="let project of row.projects"
|
||||
bitBadge
|
||||
variant="secondary"
|
||||
class="tw-ml-1"
|
||||
[title]="project.name"
|
||||
maxWidthClass="tw-max-w-60"
|
||||
>
|
||||
{{ project.name }}
|
||||
</span>
|
||||
<span *ngIf="row.projects.length === 0" bitBadge variant="warning" class="tw-ml-1"
|
||||
><i class="bwi bwi-fw bwi-exclamation-triangle tw-mr-1" aria-hidden="true"></i
|
||||
>{{ "unassigned" | i18n }}</span
|
||||
>
|
||||
</td>
|
||||
<td bitCell class="tw-whitespace-nowrap">{{ row.revisionDate | date: "medium" }}</td>
|
||||
<td bitCell>
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-clone"
|
||||
bitIconButton="bwi-ellipsis-v"
|
||||
buttonType="main"
|
||||
size="small"
|
||||
[label]="'copyUuid' | i18n"
|
||||
(click)="copySecretUuidEvent.emit(row.id)"
|
||||
[label]="'options' | i18n"
|
||||
[bitMenuTriggerFor]="secretMenu"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td bitCell>
|
||||
<span
|
||||
*ngFor="let project of row.projects"
|
||||
bitBadge
|
||||
variant="secondary"
|
||||
class="tw-ml-1"
|
||||
[title]="project.name"
|
||||
maxWidthClass="tw-max-w-60"
|
||||
>
|
||||
{{ project.name }}
|
||||
</span>
|
||||
<span *ngIf="row.projects.length === 0" bitBadge variant="warning" class="tw-ml-1"
|
||||
><i class="bwi bwi-fw bwi-exclamation-triangle tw-mr-1" aria-hidden="true"></i
|
||||
>{{ "unassigned" | i18n }}</span
|
||||
>
|
||||
</td>
|
||||
<td bitCell class="tw-whitespace-nowrap">{{ row.revisionDate | date: "medium" }}</td>
|
||||
<td bitCell>
|
||||
<button
|
||||
type="button"
|
||||
bitIconButton="bwi-ellipsis-v"
|
||||
buttonType="main"
|
||||
[label]="'options' | i18n"
|
||||
[bitMenuTriggerFor]="secretMenu"
|
||||
></button>
|
||||
</td>
|
||||
</td>
|
||||
|
||||
<bit-menu #secretMenu>
|
||||
<button type="button" bitMenuItem (click)="editSecret(row)" *ngIf="row.write && !trash">
|
||||
<i class="bwi bwi-fw bwi-pencil" aria-hidden="true"></i>
|
||||
{{ "editSecret" | i18n }}
|
||||
</button>
|
||||
<button type="button" bitMenuItem (click)="copySecretNameEvent.emit(row.name)" *ngIf="!trash">
|
||||
<i class="bwi bwi-fw bwi-clone" aria-hidden="true"></i>
|
||||
{{ "copySecretName" | i18n }}
|
||||
</button>
|
||||
<button type="button" bitMenuItem (click)="copySecretValueEvent.emit(row.id)" *ngIf="!trash">
|
||||
<i class="bwi bwi-fw bwi-clone" aria-hidden="true"></i>
|
||||
{{ "copySecretValue" | i18n }}
|
||||
</button>
|
||||
<button type="button" bitMenuItem (click)="restoreSecretsEvent.emit([row.id])" *ngIf="trash">
|
||||
<i class="bwi bwi-fw bwi-refresh" aria-hidden="true"></i>
|
||||
{{ "restoreSecret" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
*ngIf="viewEventsAllowed$ | async as allowed"
|
||||
(click)="openEventsDialog(row)"
|
||||
>
|
||||
<i class="bwi bwi-fw bwi-billing" aria-hidden="true"></i>
|
||||
<span> {{ "viewEvents" | i18n }} </span>
|
||||
</button>
|
||||
<button type="button" bitMenuItem (click)="deleteSecretsEvent.emit([row])" *ngIf="row.write">
|
||||
<i class="bwi bwi-fw bwi-trash tw-text-danger" aria-hidden="true"></i>
|
||||
<span class="tw-text-danger">{{
|
||||
(trash ? "permanentlyDelete" : "deleteSecret") | i18n
|
||||
}}</span>
|
||||
</button>
|
||||
</bit-menu>
|
||||
</ng-template>
|
||||
</bit-table-scroll>
|
||||
<bit-menu #secretMenu>
|
||||
<button type="button" bitMenuItem (click)="editSecret(row)" *ngIf="row.write && !trash">
|
||||
<i class="bwi bwi-fw bwi-pencil" aria-hidden="true"></i>
|
||||
{{ "editSecret" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="copySecretNameEvent.emit(row.name)"
|
||||
*ngIf="!trash"
|
||||
>
|
||||
<i class="bwi bwi-fw bwi-clone" aria-hidden="true"></i>
|
||||
{{ "copySecretName" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="copySecretValueEvent.emit(row.id)"
|
||||
*ngIf="!trash"
|
||||
>
|
||||
<i class="bwi bwi-fw bwi-clone" aria-hidden="true"></i>
|
||||
{{ "copySecretValue" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="restoreSecretsEvent.emit([row.id])"
|
||||
*ngIf="trash"
|
||||
>
|
||||
<i class="bwi bwi-fw bwi-refresh" aria-hidden="true"></i>
|
||||
{{ "restoreSecret" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
*ngIf="viewEventsAllowed$ | async as allowed"
|
||||
(click)="openEventsDialog(row)"
|
||||
>
|
||||
<i class="bwi bwi-fw bwi-billing" aria-hidden="true"></i>
|
||||
<span> {{ "viewEvents" | i18n }} </span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="deleteSecretsEvent.emit([row])"
|
||||
*ngIf="row.write"
|
||||
>
|
||||
<i class="bwi bwi-fw bwi-trash tw-text-danger" aria-hidden="true"></i>
|
||||
<span class="tw-text-danger">{{
|
||||
(trash ? "permanentlyDelete" : "deleteSecret") | i18n
|
||||
}}</span>
|
||||
</button>
|
||||
</bit-menu>
|
||||
</tr>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</bit-table>
|
||||
</cdk-virtual-scroll-viewport>
|
||||
|
||||
<bit-menu #tableMenu>
|
||||
<button type="button" bitMenuItem (click)="bulkRestoreSecrets()" *ngIf="trash">
|
||||
|
||||
@@ -89,6 +89,22 @@ export class SecretsListComponent implements OnDestroy, OnInit {
|
||||
selection = new SelectionModel<string>(true, []);
|
||||
protected viewEventsAllowed$: Observable<boolean>;
|
||||
protected isAdmin$: Observable<boolean>;
|
||||
protected rowHeight = 66;
|
||||
protected rowHeightClass = `tw-h-[66px]`;
|
||||
|
||||
protected get viewportHeight(): string {
|
||||
if (!this.secrets || this.secrets.length === 0) {
|
||||
return "0px";
|
||||
}
|
||||
// Calculate height: (number of items * row height) + header height + buffer
|
||||
const itemsHeight = this.secrets.length * this.rowHeight;
|
||||
const headerHeight = 65; // Header with borders
|
||||
const buffer = 8; // Small buffer for borders and spacing
|
||||
const totalHeight = itemsHeight + headerHeight + buffer;
|
||||
// Use min() to set exact height, capping at 60vh or 500px for responsive behavior
|
||||
// This ensures the viewport is exactly the size of the content, unless it exceeds the max
|
||||
return `min(${totalHeight}px, 60vh, 500px)`;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ScrollingModule } from "@angular/cdk/scrolling";
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import {
|
||||
@@ -7,6 +8,7 @@ import {
|
||||
SelectModule,
|
||||
NoItemsModule,
|
||||
FormFieldModule,
|
||||
ScrollLayoutDirective,
|
||||
} from "@bitwarden/components";
|
||||
import { CoreOrganizationModule } from "@bitwarden/web-vault/app/admin-console/organizations/core";
|
||||
import { DynamicAvatarComponent } from "@bitwarden/web-vault/app/components/dynamic-avatar.component";
|
||||
@@ -25,6 +27,7 @@ import { SecretsListComponent } from "./secrets-list.component";
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedModule,
|
||||
ScrollingModule,
|
||||
ProductSwitcherModule,
|
||||
MultiSelectModule,
|
||||
CoreOrganizationModule,
|
||||
@@ -35,6 +38,7 @@ import { SecretsListComponent } from "./secrets-list.component";
|
||||
HeaderModule,
|
||||
CardComponent,
|
||||
FormFieldModule,
|
||||
ScrollLayoutDirective,
|
||||
],
|
||||
exports: [
|
||||
AccessPolicySelectorComponent,
|
||||
|
||||
Reference in New Issue
Block a user