[SM-455] add projects and secrets to dashboard page (#4722)
* add projects and secrets to dashboard * add header title * add section component * only show latest projects and secrets * reorganize view model; all view all link * fix i18n; update table styles; add bitSortable to secrets table * apply code reviews * remove basePath input; add viewProjectEvent output * fix style and merge issue * fix route * use absolute route with org id
This commit is contained in:
parent
55741445ec
commit
375c552623
|
@ -6361,6 +6361,22 @@
|
||||||
"userAccessSecretsManager": {
|
"userAccessSecretsManager": {
|
||||||
"message": "This user can access the Secrets Manager Beta"
|
"message": "This user can access the Secrets Manager Beta"
|
||||||
},
|
},
|
||||||
|
"viewAll": {
|
||||||
|
"message": "View all"
|
||||||
|
},
|
||||||
|
"showingPortionOfTotal": {
|
||||||
|
"message": "Showing $PORTION$ of $TOTAL$",
|
||||||
|
"placeholders": {
|
||||||
|
"portion": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "2"
|
||||||
|
},
|
||||||
|
"total": {
|
||||||
|
"content": "$2",
|
||||||
|
"example": "5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"resolveTheErrorsBelowAndTryAgain": {
|
"resolveTheErrorsBelowAndTryAgain": {
|
||||||
"message": "Resolve the errors below and try again."
|
"message": "Resolve the errors below and try again."
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,3 +1,41 @@
|
||||||
<sm-header>
|
<sm-header [title]="organizationName">
|
||||||
<sm-new-menu></sm-new-menu>
|
<sm-new-menu></sm-new-menu>
|
||||||
</sm-header>
|
</sm-header>
|
||||||
|
<div
|
||||||
|
*ngIf="view$ | async as view; else spinner"
|
||||||
|
class="tw-flex tw-flex-col tw-gap-6 [&_sm-header]:tw-hidden"
|
||||||
|
>
|
||||||
|
<sm-section>
|
||||||
|
<h2 slot="summary" class="tw-mb-0 tw-text-2xl tw-font-semibold">{{ "projects" | i18n }}</h2>
|
||||||
|
<sm-projects-list
|
||||||
|
(newProjectEvent)="openNewProjectDialog()"
|
||||||
|
(editProjectEvent)="openEditProject($event)"
|
||||||
|
(deleteProjectEvent)="openDeleteProjectDialog($event)"
|
||||||
|
[projects]="view.latestProjects"
|
||||||
|
></sm-projects-list>
|
||||||
|
<div *ngIf="view.allProjects.length > 0" class="tw-ml-auto tw-mt-4 tw-max-w-max">
|
||||||
|
{{ "showingPortionOfTotal" | i18n: view.latestProjects.length:view.allProjects.length }}
|
||||||
|
<a bitLink routerLink="projects" class="tw-ml-2">{{ "viewAll" | i18n }}</a>
|
||||||
|
</div>
|
||||||
|
</sm-section>
|
||||||
|
<sm-section>
|
||||||
|
<h2 slot="summary" class="tw-mb-0 tw-text-2xl tw-font-semibold">{{ "secrets" | i18n }}</h2>
|
||||||
|
<sm-secrets-list
|
||||||
|
baseRoute="secrets"
|
||||||
|
(deleteSecretsEvent)="openDeleteSecret($event)"
|
||||||
|
(newSecretEvent)="openNewSecretDialog()"
|
||||||
|
(editSecretEvent)="openEditSecret($event)"
|
||||||
|
[secrets]="view.latestSecrets"
|
||||||
|
></sm-secrets-list>
|
||||||
|
<div *ngIf="view.allSecrets.length > 0" class="tw-ml-auto tw-mt-4 tw-max-w-max">
|
||||||
|
{{ "showingPortionOfTotal" | i18n: view.latestSecrets.length:view.allSecrets.length }}
|
||||||
|
<a bitLink routerLink="secrets" class="tw-ml-2">{{ "viewAll" | i18n }}</a>
|
||||||
|
</div>
|
||||||
|
</sm-section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-template #spinner>
|
||||||
|
<div class="tw-items-center tw-justify-center tw-pt-64 tw-text-center">
|
||||||
|
<i class="bwi bwi-spinner bwi-spin bwi-3x"></i>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -1,7 +1,177 @@
|
||||||
import { Component } from "@angular/core";
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
import {
|
||||||
|
combineLatest,
|
||||||
|
combineLatestWith,
|
||||||
|
map,
|
||||||
|
Observable,
|
||||||
|
startWith,
|
||||||
|
Subject,
|
||||||
|
switchMap,
|
||||||
|
takeUntil,
|
||||||
|
} from "rxjs";
|
||||||
|
|
||||||
|
import { OrganizationService } from "@bitwarden/common/abstractions/organization/organization.service.abstraction";
|
||||||
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { ProjectListView } from "../models/view/project-list.view";
|
||||||
|
import { SecretListView } from "../models/view/secret-list.view";
|
||||||
|
import {
|
||||||
|
ProjectDeleteDialogComponent,
|
||||||
|
ProjectDeleteOperation,
|
||||||
|
} from "../projects/dialog/project-delete-dialog.component";
|
||||||
|
import {
|
||||||
|
OperationType,
|
||||||
|
ProjectDialogComponent,
|
||||||
|
ProjectOperation,
|
||||||
|
} from "../projects/dialog/project-dialog.component";
|
||||||
|
import { ProjectService } from "../projects/project.service";
|
||||||
|
import {
|
||||||
|
SecretDeleteDialogComponent,
|
||||||
|
SecretDeleteOperation,
|
||||||
|
} from "../secrets/dialog/secret-delete.component";
|
||||||
|
import { SecretDialogComponent, SecretOperation } from "../secrets/dialog/secret-dialog.component";
|
||||||
|
import { SecretService } from "../secrets/secret.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "sm-overview",
|
selector: "sm-overview",
|
||||||
templateUrl: "./overview.component.html",
|
templateUrl: "./overview.component.html",
|
||||||
})
|
})
|
||||||
export class OverviewComponent {}
|
export class OverviewComponent implements OnInit, OnDestroy {
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
/**
|
||||||
|
* Number of items to show in tables
|
||||||
|
*/
|
||||||
|
private tableSize = 10;
|
||||||
|
private organizationId: string;
|
||||||
|
|
||||||
|
protected organizationName: string;
|
||||||
|
protected view$: Observable<{
|
||||||
|
allProjects: ProjectListView[];
|
||||||
|
allSecrets: SecretListView[];
|
||||||
|
latestProjects: ProjectListView[];
|
||||||
|
latestSecrets: SecretListView[];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private projectService: ProjectService,
|
||||||
|
private dialogService: DialogService,
|
||||||
|
private organizationService: OrganizationService,
|
||||||
|
private secretService: SecretService
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.route.params
|
||||||
|
.pipe(
|
||||||
|
map((params) => this.organizationService.get(params.organizationId)),
|
||||||
|
takeUntil(this.destroy$)
|
||||||
|
)
|
||||||
|
.subscribe((org) => {
|
||||||
|
this.organizationId = org.id;
|
||||||
|
this.organizationName = org.name;
|
||||||
|
});
|
||||||
|
|
||||||
|
const projects$ = this.projectService.project$.pipe(
|
||||||
|
startWith(null),
|
||||||
|
combineLatestWith(this.route.params),
|
||||||
|
switchMap(() => this.getProjects())
|
||||||
|
);
|
||||||
|
|
||||||
|
const secrets$ = this.secretService.secret$.pipe(
|
||||||
|
startWith(null),
|
||||||
|
combineLatestWith(this.route.params),
|
||||||
|
switchMap(() => this.getSecrets())
|
||||||
|
);
|
||||||
|
|
||||||
|
this.view$ = combineLatest([projects$, secrets$]).pipe(
|
||||||
|
map(([projects, secrets]) => {
|
||||||
|
return {
|
||||||
|
allProjects: projects,
|
||||||
|
allSecrets: secrets,
|
||||||
|
latestProjects: this.getRecentItems(projects, this.tableSize),
|
||||||
|
latestSecrets: this.getRecentItems(secrets, this.tableSize),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getRecentItems<T extends { revisionDate: string }[]>(items: T, length: number): T {
|
||||||
|
return items
|
||||||
|
.sort((a, b) => {
|
||||||
|
return new Date(b.revisionDate).getTime() - new Date(a.revisionDate).getTime();
|
||||||
|
})
|
||||||
|
.slice(0, length) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Projects ---
|
||||||
|
|
||||||
|
private async getProjects(): Promise<ProjectListView[]> {
|
||||||
|
return await this.projectService.getProjects(this.organizationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
openEditProject(projectId: string) {
|
||||||
|
this.dialogService.open<unknown, ProjectOperation>(ProjectDialogComponent, {
|
||||||
|
data: {
|
||||||
|
organizationId: this.organizationId,
|
||||||
|
operation: OperationType.Edit,
|
||||||
|
projectId: projectId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openNewProjectDialog() {
|
||||||
|
this.dialogService.open<unknown, ProjectOperation>(ProjectDialogComponent, {
|
||||||
|
data: {
|
||||||
|
organizationId: this.organizationId,
|
||||||
|
operation: OperationType.Add,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openDeleteProjectDialog(event: ProjectListView[]) {
|
||||||
|
this.dialogService.open<unknown, ProjectDeleteOperation>(ProjectDeleteDialogComponent, {
|
||||||
|
data: {
|
||||||
|
projects: event,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Secrets ---
|
||||||
|
|
||||||
|
private async getSecrets(): Promise<SecretListView[]> {
|
||||||
|
return await this.secretService.getSecrets(this.organizationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
openEditSecret(secretId: string) {
|
||||||
|
this.dialogService.open<unknown, SecretOperation>(SecretDialogComponent, {
|
||||||
|
data: {
|
||||||
|
organizationId: this.organizationId,
|
||||||
|
operation: OperationType.Edit,
|
||||||
|
secretId: secretId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openDeleteSecret(secretIds: string[]) {
|
||||||
|
this.dialogService.open<unknown, SecretDeleteOperation>(SecretDeleteDialogComponent, {
|
||||||
|
data: {
|
||||||
|
secretIds: secretIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openNewSecretDialog() {
|
||||||
|
this.dialogService.open<unknown, SecretOperation>(SecretDialogComponent, {
|
||||||
|
data: {
|
||||||
|
organizationId: this.organizationId,
|
||||||
|
operation: OperationType.Add,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,11 @@ import { SecretsManagerSharedModule } from "../shared/sm-shared.module";
|
||||||
|
|
||||||
import { OverviewRoutingModule } from "./overview-routing.module";
|
import { OverviewRoutingModule } from "./overview-routing.module";
|
||||||
import { OverviewComponent } from "./overview.component";
|
import { OverviewComponent } from "./overview.component";
|
||||||
|
import { SectionComponent } from "./section.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [SecretsManagerSharedModule, OverviewRoutingModule],
|
imports: [SecretsManagerSharedModule, OverviewRoutingModule],
|
||||||
declarations: [OverviewComponent],
|
declarations: [OverviewComponent, SectionComponent],
|
||||||
providers: [],
|
providers: [],
|
||||||
})
|
})
|
||||||
export class OverviewModule {}
|
export class OverviewModule {}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<section>
|
||||||
|
<header class="tw-flex tw-max-w-min tw-items-center tw-gap-2">
|
||||||
|
<div><ng-content select="[slot=summary]"></ng-content></div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
[bitIconButton]="open ? 'bwi-angle-up' : 'bwi-angle-down'"
|
||||||
|
(click)="toggle()"
|
||||||
|
[attr.aria-expanded]="open"
|
||||||
|
[attr.aria-controls]="contentId"
|
||||||
|
></button>
|
||||||
|
</header>
|
||||||
|
<div *ngIf="open" [attr.id]="contentId" class="tw-mt-4">
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
|
</section>
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { Component, Input } from "@angular/core";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "sm-section",
|
||||||
|
templateUrl: "./section.component.html",
|
||||||
|
})
|
||||||
|
export class SectionComponent {
|
||||||
|
@Input() open = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UID for `[attr.aria-controls]`
|
||||||
|
*/
|
||||||
|
protected contentId = Math.random().toString(36).substring(2);
|
||||||
|
|
||||||
|
protected toggle() {
|
||||||
|
this.open = !this.open;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,6 @@ import { ProjectPeopleComponent } from "./project/project-people.component";
|
||||||
import { ProjectSecretsComponent } from "./project/project-secrets.component";
|
import { ProjectSecretsComponent } from "./project/project-secrets.component";
|
||||||
import { ProjectServiceAccountsComponent } from "./project/project-service-accounts.component";
|
import { ProjectServiceAccountsComponent } from "./project/project-service-accounts.component";
|
||||||
import { ProjectComponent } from "./project/project.component";
|
import { ProjectComponent } from "./project/project.component";
|
||||||
import { ProjectsListComponent } from "./projects-list/projects-list.component";
|
|
||||||
import { ProjectsRoutingModule } from "./projects-routing.module";
|
import { ProjectsRoutingModule } from "./projects-routing.module";
|
||||||
import { ProjectsComponent } from "./projects/projects.component";
|
import { ProjectsComponent } from "./projects/projects.component";
|
||||||
|
|
||||||
|
@ -19,7 +18,6 @@ import { ProjectsComponent } from "./projects/projects.component";
|
||||||
imports: [SecretsManagerSharedModule, ProjectsRoutingModule, BreadcrumbsModule],
|
imports: [SecretsManagerSharedModule, ProjectsRoutingModule, BreadcrumbsModule],
|
||||||
declarations: [
|
declarations: [
|
||||||
ProjectsComponent,
|
ProjectsComponent,
|
||||||
ProjectsListComponent,
|
|
||||||
ProjectAccessComponent,
|
ProjectAccessComponent,
|
||||||
ProjectDialogComponent,
|
ProjectDialogComponent,
|
||||||
ProjectDeleteDialogComponent,
|
ProjectDeleteDialogComponent,
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
{{ "all" | i18n }}
|
{{ "all" | i18n }}
|
||||||
</label>
|
</label>
|
||||||
</th>
|
</th>
|
||||||
<th bitCell colspan="2" bitSortable="name" default>{{ "name" | i18n }}</th>
|
<th bitCell class="tw-w-full tw-text-left" bitSortable="name" default>{{ "name" | i18n }}</th>
|
||||||
<th bitCell bitSortable="revisionDate">{{ "lastEdited" | i18n }}</th>
|
<th bitCell bitSortable="revisionDate">{{ "lastEdited" | i18n }}</th>
|
||||||
<th bitCell class="tw-w-0">
|
<th bitCell class="tw-w-0">
|
||||||
<button
|
<button
|
||||||
|
@ -54,13 +54,15 @@
|
||||||
[checked]="selection.isSelected(project.id)"
|
[checked]="selection.isSelected(project.id)"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td bitCell class="tw-w-0 tw-pr-0">
|
<td bitCell>
|
||||||
<i class="bwi bwi-collection tw-text-xl tw-text-muted" aria-hidden="true"></i>
|
<div class="tw-flex tw-items-center tw-gap-4 tw-break-all">
|
||||||
|
<i class="bwi bwi-collection tw-text-xl tw-text-muted" aria-hidden="true"></i>
|
||||||
|
<a bitLink [routerLink]="['/sm', project.organizationId, 'projects', project.id]">{{
|
||||||
|
project.name
|
||||||
|
}}</a>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td bitCell class="tw-break-all">
|
<td bitCell class="tw-whitespace-nowrap">{{ project.revisionDate | date: "medium" }}</td>
|
||||||
<a bitLink [routerLink]="[project.id]">{{ project.name }}</a>
|
|
||||||
</td>
|
|
||||||
<td bitCell>{{ project.revisionDate | date: "medium" }}</td>
|
|
||||||
<td bitCell>
|
<td bitCell>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -76,7 +78,7 @@
|
||||||
<i class="bwi bwi-fw bwi-pencil tw-text-xl" aria-hidden="true"></i>
|
<i class="bwi bwi-fw bwi-pencil tw-text-xl" aria-hidden="true"></i>
|
||||||
{{ "editProject" | i18n }}
|
{{ "editProject" | i18n }}
|
||||||
</button>
|
</button>
|
||||||
<a bitMenuItem [routerLink]="project.id">
|
<a bitMenuItem [routerLink]="['/sm', project.organizationId, 'projects', project.id]">
|
||||||
<i class="bwi bwi-fw bwi-eye tw-text-xl" aria-hidden="true"></i>
|
<i class="bwi bwi-fw bwi-eye tw-text-xl" aria-hidden="true"></i>
|
||||||
{{ "viewProject" | i18n }}
|
{{ "viewProject" | i18n }}
|
||||||
</a>
|
</a>
|
|
@ -4,7 +4,7 @@ import { Subject, takeUntil } from "rxjs";
|
||||||
|
|
||||||
import { TableDataSource } from "@bitwarden/components";
|
import { TableDataSource } from "@bitwarden/components";
|
||||||
|
|
||||||
import { ProjectListView } from "../../models/view/project-list.view";
|
import { ProjectListView } from "../models/view/project-list.view";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "sm-projects-list",
|
selector: "sm-projects-list",
|
|
@ -17,7 +17,7 @@
|
||||||
</button>
|
</button>
|
||||||
</sm-no-items>
|
</sm-no-items>
|
||||||
|
|
||||||
<bit-table *ngIf="secrets?.length >= 1">
|
<bit-table *ngIf="secrets?.length >= 1" [dataSource]="dataSource">
|
||||||
<ng-container header>
|
<ng-container header>
|
||||||
<tr>
|
<tr>
|
||||||
<th bitCell class="tw-w-0">
|
<th bitCell class="tw-w-0">
|
||||||
|
@ -31,9 +31,9 @@
|
||||||
{{ "all" | i18n }}
|
{{ "all" | i18n }}
|
||||||
</label>
|
</label>
|
||||||
</th>
|
</th>
|
||||||
<th bitCell colspan="2">{{ "name" | i18n }}</th>
|
<th bitCell class="tw-w-full tw-text-left" bitSortable="name" default>{{ "name" | i18n }}</th>
|
||||||
<th bitCell>{{ "project" | i18n }}</th>
|
<th bitCell>{{ "project" | i18n }}</th>
|
||||||
<th bitCell>{{ "lastEdited" | i18n }}</th>
|
<th bitCell bitSortable="revisionDate">{{ "lastEdited" | i18n }}</th>
|
||||||
<th bitCell class="tw-w-0">
|
<th bitCell class="tw-w-0">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -46,8 +46,8 @@
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template body>
|
<ng-template body let-rows$>
|
||||||
<tr bitRow *ngFor="let secret of secrets">
|
<tr bitRow *ngFor="let secret of rows$ | async">
|
||||||
<td bitCell>
|
<td bitCell>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
|
@ -55,13 +55,13 @@
|
||||||
[checked]="selection.isSelected(secret.id)"
|
[checked]="selection.isSelected(secret.id)"
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td bitCell class="tw-w-0 tw-pr-0">
|
<td bitCell>
|
||||||
<i class="bwi bwi-key tw-text-xl tw-text-muted" aria-hidden="true"></i>
|
<div class="tw-flex tw-items-center tw-gap-4 tw-break-all">
|
||||||
</td>
|
<i class="bwi bwi-key tw-text-xl tw-text-muted" aria-hidden="true"></i>
|
||||||
<td bitCell class="tw-break-all">
|
<button type="button" bitLink (click)="editSecretEvent.emit(secret.id)">
|
||||||
<button type="button" bitLink (click)="editSecretEvent.emit(secret.id)">
|
{{ secret.name }}
|
||||||
{{ secret.name }}
|
</button>
|
||||||
</button>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td bitCell>
|
<td bitCell>
|
||||||
<span
|
<span
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
{{ project.name }}
|
{{ project.name }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td bitCell>{{ secret.revisionDate | date: "medium" }}</td>
|
<td bitCell class="tw-whitespace-nowrap">{{ secret.revisionDate | date: "medium" }}</td>
|
||||||
<td bitCell>
|
<td bitCell>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { SelectionModel } from "@angular/cdk/collections";
|
||||||
import { Component, EventEmitter, Input, OnDestroy, Output } from "@angular/core";
|
import { Component, EventEmitter, Input, OnDestroy, Output } from "@angular/core";
|
||||||
import { Subject, takeUntil } from "rxjs";
|
import { Subject, takeUntil } from "rxjs";
|
||||||
|
|
||||||
|
import { TableDataSource } from "@bitwarden/components";
|
||||||
|
|
||||||
import { SecretListView } from "../models/view/secret-list.view";
|
import { SecretListView } from "../models/view/secret-list.view";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -9,6 +11,8 @@ import { SecretListView } from "../models/view/secret-list.view";
|
||||||
templateUrl: "./secrets-list.component.html",
|
templateUrl: "./secrets-list.component.html",
|
||||||
})
|
})
|
||||||
export class SecretsListComponent implements OnDestroy {
|
export class SecretsListComponent implements OnDestroy {
|
||||||
|
protected dataSource = new TableDataSource<SecretListView>();
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
get secrets(): SecretListView[] {
|
get secrets(): SecretListView[] {
|
||||||
return this._secrets;
|
return this._secrets;
|
||||||
|
@ -16,6 +20,7 @@ export class SecretsListComponent implements OnDestroy {
|
||||||
set secrets(secrets: SecretListView[]) {
|
set secrets(secrets: SecretListView[]) {
|
||||||
this.selection.clear();
|
this.selection.clear();
|
||||||
this._secrets = secrets;
|
this._secrets = secrets;
|
||||||
|
this.dataSource.data = secrets;
|
||||||
}
|
}
|
||||||
private _secrets: SecretListView[];
|
private _secrets: SecretListView[];
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { BulkStatusDialogComponent } from "./dialogs/bulk-status-dialog.componen
|
||||||
import { HeaderComponent } from "./header.component";
|
import { HeaderComponent } from "./header.component";
|
||||||
import { NewMenuComponent } from "./new-menu.component";
|
import { NewMenuComponent } from "./new-menu.component";
|
||||||
import { NoItemsComponent } from "./no-items.component";
|
import { NoItemsComponent } from "./no-items.component";
|
||||||
|
import { ProjectsListComponent } from "./projects-list.component";
|
||||||
import { SecretsListComponent } from "./secrets-list.component";
|
import { SecretsListComponent } from "./secrets-list.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -20,6 +21,7 @@ import { SecretsListComponent } from "./secrets-list.component";
|
||||||
HeaderComponent,
|
HeaderComponent,
|
||||||
NewMenuComponent,
|
NewMenuComponent,
|
||||||
NoItemsComponent,
|
NoItemsComponent,
|
||||||
|
ProjectsListComponent,
|
||||||
SecretsListComponent,
|
SecretsListComponent,
|
||||||
AccessSelectorComponent,
|
AccessSelectorComponent,
|
||||||
],
|
],
|
||||||
|
@ -28,6 +30,7 @@ import { SecretsListComponent } from "./secrets-list.component";
|
||||||
HeaderComponent,
|
HeaderComponent,
|
||||||
NewMenuComponent,
|
NewMenuComponent,
|
||||||
NoItemsComponent,
|
NoItemsComponent,
|
||||||
|
ProjectsListComponent,
|
||||||
SecretsListComponent,
|
SecretsListComponent,
|
||||||
AccessSelectorComponent,
|
AccessSelectorComponent,
|
||||||
],
|
],
|
||||||
|
|
|
@ -7,12 +7,7 @@ import { TableComponent } from "./table.component";
|
||||||
@Component({
|
@Component({
|
||||||
selector: "th[bitSortable]",
|
selector: "th[bitSortable]",
|
||||||
template: `
|
template: `
|
||||||
<button
|
<button [ngClass]="classList" [attr.aria-pressed]="isActive" (click)="setActive()">
|
||||||
class="tw-group"
|
|
||||||
[ngClass]="classList"
|
|
||||||
[attr.aria-pressed]="isActive"
|
|
||||||
(click)="setActive()"
|
|
||||||
>
|
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
<i class="bwi tw-ml-2" [ngClass]="icon"></i>
|
<i class="bwi tw-ml-2" [ngClass]="icon"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -83,6 +78,9 @@ export class SortableComponent implements OnInit {
|
||||||
|
|
||||||
get classList() {
|
get classList() {
|
||||||
return [
|
return [
|
||||||
|
"tw-group",
|
||||||
|
"tw-min-w-max",
|
||||||
|
|
||||||
// Offset to border and padding
|
// Offset to border and padding
|
||||||
"-tw-m-1.5",
|
"-tw-m-1.5",
|
||||||
"tw-font-bold",
|
"tw-font-bold",
|
||||||
|
|
Loading…
Reference in New Issue