mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-25 12:15:18 +01:00
[SM-1302] Initial config page (#10196)
* Initial config page * Remove project actions * Add copy projectId method to the project page * Update bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/config/config.component.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update bitwarden_license/bit-web/src/app/secrets-manager/shared/projects-list.component.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Update apps/web/src/locales/en/messages.json Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Fix method and string naming * Ensure config component load logic happens after params observed * Remove projectId emitted event * Update bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/config/config.component.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> * Adjust load function * Fix config translation * Remove unnecceary async from copy functions * Add project ID translation key * Update bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/config/config.component.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Simplify load function * Simplify variable definition * Add all machine account projects to the config page * Update bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/config/config.component.ts Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> * Remove unused variable * Remove revision date in config project list --------- Co-authored-by: Maciej Zieniuk <167752252+mzieniukbw@users.noreply.github.com> Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com>
This commit is contained in:
parent
ea025b9026
commit
cf1f7cc61d
@ -9002,6 +9002,24 @@
|
|||||||
"purchasedSeatsRemoved": {
|
"purchasedSeatsRemoved": {
|
||||||
"message": "purchased seats removed"
|
"message": "purchased seats removed"
|
||||||
},
|
},
|
||||||
|
"environmentVariables": {
|
||||||
|
"message": "Environment variables"
|
||||||
|
},
|
||||||
|
"organizationId": {
|
||||||
|
"message": "Organization ID"
|
||||||
|
},
|
||||||
|
"projectIds": {
|
||||||
|
"message": "Project IDs"
|
||||||
|
},
|
||||||
|
"projectId": {
|
||||||
|
"message": "Project ID"
|
||||||
|
},
|
||||||
|
"projectsAccessedByMachineAccount": {
|
||||||
|
"message": "The following projects can be accessed by this machine account."
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"message": "Config"
|
||||||
|
},
|
||||||
"learnMoreAboutEmergencyAccess": {
|
"learnMoreAboutEmergencyAccess": {
|
||||||
"message":"Learn more about emergency access"
|
"message":"Learn more about emergency access"
|
||||||
},
|
},
|
||||||
|
@ -6,4 +6,5 @@ export class ProjectListView {
|
|||||||
revisionDate: string;
|
revisionDate: string;
|
||||||
read: boolean;
|
read: boolean;
|
||||||
write: boolean;
|
write: boolean;
|
||||||
|
linkable: boolean;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +131,7 @@ export class ProjectService {
|
|||||||
);
|
);
|
||||||
projectListView.creationDate = s.creationDate;
|
projectListView.creationDate = s.creationDate;
|
||||||
projectListView.revisionDate = s.revisionDate;
|
projectListView.revisionDate = s.revisionDate;
|
||||||
|
projectListView.linkable = true;
|
||||||
return projectListView;
|
return projectListView;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
<div *ngIf="!loading">
|
||||||
|
<div class="tw-p-6 tw-border tw-border-solid tw-border-secondary-600 tw-rounded">
|
||||||
|
<h2 bitTypography="h2">{{ "environmentVariables" | i18n }}</h2>
|
||||||
|
<div class="tw-flex tw-gap-6 tw-pt-4">
|
||||||
|
<bit-form-field class="tw-w-2/5 tw-min-w-80" tw>
|
||||||
|
<bit-label>{{ "identityUrl" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="text" [(ngModel)]="identityUrl" [disabled]="true" />
|
||||||
|
<button
|
||||||
|
bitSuffix
|
||||||
|
type="button"
|
||||||
|
type="button"
|
||||||
|
bitIconButton="bwi-clone"
|
||||||
|
[bitAction]="copyIdentityUrl"
|
||||||
|
></button>
|
||||||
|
</bit-form-field>
|
||||||
|
<bit-form-field class="tw-w-2/5 tw-min-w-80">
|
||||||
|
<bit-label>{{ "apiUrl" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="text" [(ngModel)]="apiUrl" [disabled]="true" />
|
||||||
|
<button bitSuffix type="button" bitIconButton="bwi-clone" [bitAction]="copyApiUrl"></button>
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
|
<bit-form-field class="tw-w-2/5 tw-min-w-80">
|
||||||
|
<bit-label>{{ "organizationId" | i18n }}</bit-label>
|
||||||
|
<input bitInput type="text" [(ngModel)]="organizationId" [disabled]="true" />
|
||||||
|
<button
|
||||||
|
bitSuffix
|
||||||
|
type="button"
|
||||||
|
bitIconButton="bwi-clone"
|
||||||
|
[bitAction]="copyOrganizationId"
|
||||||
|
></button>
|
||||||
|
</bit-form-field>
|
||||||
|
</div>
|
||||||
|
<div class="tw-pt-12">
|
||||||
|
<h2 slot="summary" class="tw-mb-0" bitTypography="h2" noMargin>{{ "projectIds" | i18n }}</h2>
|
||||||
|
<p *ngIf="!hasProjects" class="tw-mt-6">{{ "projectsNoItemsTitle" | i18n }}</p>
|
||||||
|
<p *ngIf="hasProjects" class="tw-mt-4">{{ "projectsAccessedByMachineAccount" | i18n }}</p>
|
||||||
|
<sm-projects-list
|
||||||
|
class="tw-mt-8"
|
||||||
|
*ngIf="hasProjects"
|
||||||
|
[showMenus]="false"
|
||||||
|
[projects]="projects"
|
||||||
|
></sm-projects-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="loading" class="tw-items-center tw-justify-center tw-pt-64 tw-text-center">
|
||||||
|
<i class="bwi bwi-spinner bwi-spin bwi-3x"></i>
|
||||||
|
</div>
|
@ -0,0 +1,127 @@
|
|||||||
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute, Params } from "@angular/router";
|
||||||
|
import { Subject, concatMap, takeUntil } from "rxjs";
|
||||||
|
|
||||||
|
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
import { ToastService } from "@bitwarden/components";
|
||||||
|
|
||||||
|
import { ProjectListView } from "../../models/view/project-list.view";
|
||||||
|
import { ProjectService } from "../../projects/project.service";
|
||||||
|
import { AccessPolicyService } from "../../shared/access-policies/access-policy.service";
|
||||||
|
|
||||||
|
class ServiceAccountConfig {
|
||||||
|
organizationId: string;
|
||||||
|
serviceAccountId: string;
|
||||||
|
identityUrl: string;
|
||||||
|
apiUrl: string;
|
||||||
|
projects: ProjectListView[];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "sm-service-account-config",
|
||||||
|
templateUrl: "./config.component.html",
|
||||||
|
})
|
||||||
|
export class ServiceAccountConfigComponent implements OnInit, OnDestroy {
|
||||||
|
identityUrl: string;
|
||||||
|
apiUrl: string;
|
||||||
|
organizationId: string;
|
||||||
|
serviceAccountId: string;
|
||||||
|
projects: ProjectListView[];
|
||||||
|
hasProjects = false;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private environmentService: EnvironmentService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private platformUtilsService: PlatformUtilsService,
|
||||||
|
private toastService: ToastService,
|
||||||
|
private i18nService: I18nService,
|
||||||
|
private projectService: ProjectService,
|
||||||
|
private accessPolicyService: AccessPolicyService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
this.route.params
|
||||||
|
.pipe(
|
||||||
|
concatMap(async (params: Params) => {
|
||||||
|
return await this.load(params.organizationId, params.serviceAccountId);
|
||||||
|
}),
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
)
|
||||||
|
.subscribe((smConfig) => {
|
||||||
|
this.identityUrl = smConfig.identityUrl;
|
||||||
|
this.apiUrl = smConfig.apiUrl;
|
||||||
|
this.organizationId = smConfig.organizationId;
|
||||||
|
this.serviceAccountId = smConfig.serviceAccountId;
|
||||||
|
this.projects = smConfig.projects;
|
||||||
|
|
||||||
|
this.hasProjects = smConfig.projects.length > 0;
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async load(organizationId: string, serviceAccountId: string): Promise<ServiceAccountConfig> {
|
||||||
|
const environment = await this.environmentService.getEnvironment();
|
||||||
|
|
||||||
|
const allProjects = await this.projectService.getProjects(organizationId);
|
||||||
|
const policies = await this.accessPolicyService.getServiceAccountGrantedPolicies(
|
||||||
|
organizationId,
|
||||||
|
serviceAccountId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const projects = policies.grantedProjectPolicies.map((policy) => {
|
||||||
|
return {
|
||||||
|
id: policy.accessPolicy.grantedProjectId,
|
||||||
|
name: policy.accessPolicy.grantedProjectName,
|
||||||
|
organizationId: organizationId,
|
||||||
|
linkable: allProjects.some(
|
||||||
|
(project) => project.id === policy.accessPolicy.grantedProjectId,
|
||||||
|
),
|
||||||
|
} as ProjectListView;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
organizationId: organizationId,
|
||||||
|
serviceAccountId: serviceAccountId,
|
||||||
|
identityUrl: environment.getIdentityUrl(),
|
||||||
|
apiUrl: environment.getApiUrl(),
|
||||||
|
projects: projects,
|
||||||
|
} as ServiceAccountConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
copyIdentityUrl = () => {
|
||||||
|
this.platformUtilsService.copyToClipboard(this.identityUrl);
|
||||||
|
this.toastService.showToast({
|
||||||
|
variant: "success",
|
||||||
|
title: null,
|
||||||
|
message: this.i18nService.t("valueCopied", this.i18nService.t("identityUrl")),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
copyApiUrl = () => {
|
||||||
|
this.platformUtilsService.copyToClipboard(this.apiUrl);
|
||||||
|
this.toastService.showToast({
|
||||||
|
variant: "success",
|
||||||
|
title: null,
|
||||||
|
message: this.i18nService.t("valueCopied", this.i18nService.t("apiUrl")),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
copyOrganizationId = () => {
|
||||||
|
this.platformUtilsService.copyToClipboard(this.organizationId);
|
||||||
|
this.toastService.showToast({
|
||||||
|
variant: "success",
|
||||||
|
title: null,
|
||||||
|
message: this.i18nService.t("valueCopied", this.i18nService.t("organizationId")),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
}
|
@ -29,6 +29,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</bit-tab-link>
|
</bit-tab-link>
|
||||||
<bit-tab-link [route]="['events']">{{ "eventLogs" | i18n }}</bit-tab-link>
|
<bit-tab-link [route]="['events']">{{ "eventLogs" | i18n }}</bit-tab-link>
|
||||||
|
<bit-tab-link [route]="['config']">{{ "config" | i18n }}</bit-tab-link>
|
||||||
</bit-tab-nav-bar>
|
</bit-tab-nav-bar>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -2,6 +2,7 @@ import { NgModule } from "@angular/core";
|
|||||||
import { RouterModule, Routes } from "@angular/router";
|
import { RouterModule, Routes } from "@angular/router";
|
||||||
|
|
||||||
import { AccessTokenComponent } from "./access/access-tokens.component";
|
import { AccessTokenComponent } from "./access/access-tokens.component";
|
||||||
|
import { ServiceAccountConfigComponent } from "./config/config.component";
|
||||||
import { ServiceAccountEventsComponent } from "./event-logs/service-accounts-events.component";
|
import { ServiceAccountEventsComponent } from "./event-logs/service-accounts-events.component";
|
||||||
import { serviceAccountAccessGuard } from "./guards/service-account-access.guard";
|
import { serviceAccountAccessGuard } from "./guards/service-account-access.guard";
|
||||||
import { ServiceAccountPeopleComponent } from "./people/service-account-people.component";
|
import { ServiceAccountPeopleComponent } from "./people/service-account-people.component";
|
||||||
@ -40,6 +41,10 @@ const routes: Routes = [
|
|||||||
path: "events",
|
path: "events",
|
||||||
component: ServiceAccountEventsComponent,
|
component: ServiceAccountEventsComponent,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "config",
|
||||||
|
component: ServiceAccountConfigComponent,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -9,6 +9,7 @@ import { AccessTokenComponent } from "./access/access-tokens.component";
|
|||||||
import { AccessTokenCreateDialogComponent } from "./access/dialogs/access-token-create-dialog.component";
|
import { AccessTokenCreateDialogComponent } from "./access/dialogs/access-token-create-dialog.component";
|
||||||
import { AccessTokenDialogComponent } from "./access/dialogs/access-token-dialog.component";
|
import { AccessTokenDialogComponent } from "./access/dialogs/access-token-dialog.component";
|
||||||
import { ExpirationOptionsComponent } from "./access/dialogs/expiration-options.component";
|
import { ExpirationOptionsComponent } from "./access/dialogs/expiration-options.component";
|
||||||
|
import { ServiceAccountConfigComponent } from "./config/config.component";
|
||||||
import { ServiceAccountDeleteDialogComponent } from "./dialog/service-account-delete-dialog.component";
|
import { ServiceAccountDeleteDialogComponent } from "./dialog/service-account-delete-dialog.component";
|
||||||
import { ServiceAccountDialogComponent } from "./dialog/service-account-dialog.component";
|
import { ServiceAccountDialogComponent } from "./dialog/service-account-dialog.component";
|
||||||
import { ServiceAccountEventsComponent } from "./event-logs/service-accounts-events.component";
|
import { ServiceAccountEventsComponent } from "./event-logs/service-accounts-events.component";
|
||||||
@ -28,6 +29,7 @@ import { ServiceAccountsComponent } from "./service-accounts.component";
|
|||||||
AccessTokenDialogComponent,
|
AccessTokenDialogComponent,
|
||||||
ExpirationOptionsComponent,
|
ExpirationOptionsComponent,
|
||||||
ServiceAccountComponent,
|
ServiceAccountComponent,
|
||||||
|
ServiceAccountConfigComponent,
|
||||||
ServiceAccountDeleteDialogComponent,
|
ServiceAccountDeleteDialogComponent,
|
||||||
ServiceAccountDialogComponent,
|
ServiceAccountDialogComponent,
|
||||||
ServiceAccountEventsComponent,
|
ServiceAccountEventsComponent,
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<bit-table *ngIf="projects?.length >= 1" [dataSource]="dataSource">
|
<bit-table *ngIf="projects?.length >= 1" [dataSource]="dataSource">
|
||||||
<ng-container header>
|
<ng-container header>
|
||||||
<tr>
|
<tr>
|
||||||
<th bitCell class="tw-w-0">
|
<th bitCell class="tw-w-0" *ngIf="showMenus">
|
||||||
<label class="!tw-mb-0 tw-flex tw-w-fit tw-gap-2 !tw-font-bold !tw-text-muted">
|
<label class="!tw-mb-0 tw-flex tw-w-fit tw-gap-2 !tw-font-bold !tw-text-muted">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@ -32,7 +32,7 @@
|
|||||||
</label>
|
</label>
|
||||||
</th>
|
</th>
|
||||||
<th bitCell bitSortable="name" default>{{ "name" | i18n }}</th>
|
<th bitCell bitSortable="name" default>{{ "name" | i18n }}</th>
|
||||||
<th bitCell bitSortable="revisionDate">{{ "lastEdited" | i18n }}</th>
|
<th bitCell bitSortable="revisionDate" *ngIf="showMenus">{{ "lastEdited" | i18n }}</th>
|
||||||
<th
|
<th
|
||||||
bitCell
|
bitCell
|
||||||
class="tw-w-0"
|
class="tw-w-0"
|
||||||
@ -45,13 +45,14 @@
|
|||||||
[bitMenuTriggerFor]="tableMenu"
|
[bitMenuTriggerFor]="tableMenu"
|
||||||
[title]="'options' | i18n"
|
[title]="'options' | i18n"
|
||||||
[attr.aria-label]="'options' | i18n"
|
[attr.aria-label]="'options' | i18n"
|
||||||
|
*ngIf="showMenus"
|
||||||
></button>
|
></button>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-template body let-rows$>
|
<ng-template body let-rows$>
|
||||||
<tr bitRow *ngFor="let project of rows$ | async">
|
<tr bitRow *ngFor="let project of rows$ | async">
|
||||||
<td bitCell>
|
<td bitCell *ngIf="showMenus">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
(change)="$event ? selection.toggle(project.id) : null"
|
(change)="$event ? selection.toggle(project.id) : null"
|
||||||
@ -61,12 +62,32 @@
|
|||||||
<td bitCell>
|
<td bitCell>
|
||||||
<div class="tw-flex tw-items-center tw-gap-4 tw-break-all">
|
<div class="tw-flex tw-items-center tw-gap-4 tw-break-all">
|
||||||
<i class="bwi bwi-collection tw-text-muted" aria-hidden="true"></i>
|
<i class="bwi bwi-collection tw-text-muted" aria-hidden="true"></i>
|
||||||
<a bitLink [routerLink]="['/sm', project.organizationId, 'projects', project.id]">{{
|
<div>
|
||||||
project.name
|
<a
|
||||||
}}</a>
|
*ngIf="project.linkable"
|
||||||
|
bitLink
|
||||||
|
[routerLink]="['/sm', project.organizationId, 'projects', project.id]"
|
||||||
|
>{{ project.name }}</a
|
||||||
|
>
|
||||||
|
<span *ngIf="!project.linkable">{{ project.name }}</span>
|
||||||
|
<div class="tw-text-sm tw-text-muted tw-block">
|
||||||
|
{{ project.id }}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
bitIconButton="bwi-clone"
|
||||||
|
buttonType="main"
|
||||||
|
size="small"
|
||||||
|
[title]="'copyUuid' | i18n"
|
||||||
|
[attr.aria-label]="'copyUuid' | i18n"
|
||||||
|
(click)="copyProjectUuidToClipboard(project.id)"
|
||||||
|
></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td bitCell class="tw-whitespace-nowrap">{{ project.revisionDate | date: "medium" }}</td>
|
<td bitCell class="tw-whitespace-nowrap" *ngIf="showMenus">
|
||||||
|
{{ project.revisionDate | date: "medium" }}
|
||||||
|
</td>
|
||||||
<td bitCell>
|
<td bitCell>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@ -75,6 +96,7 @@
|
|||||||
[bitMenuTriggerFor]="projectMenu"
|
[bitMenuTriggerFor]="projectMenu"
|
||||||
[title]="'options' | i18n"
|
[title]="'options' | i18n"
|
||||||
[attr.aria-label]="'options' | i18n"
|
[attr.aria-label]="'options' | i18n"
|
||||||
|
*ngIf="showMenus"
|
||||||
></button>
|
></button>
|
||||||
</td>
|
</td>
|
||||||
<bit-menu #projectMenu>
|
<bit-menu #projectMenu>
|
||||||
|
@ -24,6 +24,8 @@ export class ProjectsListComponent {
|
|||||||
}
|
}
|
||||||
private _projects: ProjectListView[];
|
private _projects: ProjectListView[];
|
||||||
|
|
||||||
|
@Input() showMenus?: boolean = true;
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set search(search: string) {
|
set search(search: string) {
|
||||||
this.selection.clear();
|
this.selection.clear();
|
||||||
@ -33,6 +35,7 @@ export class ProjectsListComponent {
|
|||||||
@Output() editProjectEvent = new EventEmitter<string>();
|
@Output() editProjectEvent = new EventEmitter<string>();
|
||||||
@Output() deleteProjectEvent = new EventEmitter<ProjectListView[]>();
|
@Output() deleteProjectEvent = new EventEmitter<ProjectListView[]>();
|
||||||
@Output() newProjectEvent = new EventEmitter();
|
@Output() newProjectEvent = new EventEmitter();
|
||||||
|
@Output() copiedProjectUUIdEvent = new EventEmitter<string>();
|
||||||
|
|
||||||
selection = new SelectionModel<string>(true, []);
|
selection = new SelectionModel<string>(true, []);
|
||||||
protected dataSource = new TableDataSource<ProjectListView>();
|
protected dataSource = new TableDataSource<ProjectListView>();
|
||||||
@ -90,4 +93,13 @@ export class ProjectsListComponent {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copyProjectUuidToClipboard(id: string) {
|
||||||
|
this.platformUtilsService.copyToClipboard(id);
|
||||||
|
this.platformUtilsService.showToast(
|
||||||
|
"success",
|
||||||
|
null,
|
||||||
|
this.i18nService.t("valueCopied", this.i18nService.t("projectId")),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
CardComponent,
|
||||||
MultiSelectModule,
|
MultiSelectModule,
|
||||||
SearchModule,
|
SearchModule,
|
||||||
SelectModule,
|
SelectModule,
|
||||||
NoItemsModule,
|
NoItemsModule,
|
||||||
|
FormFieldModule,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
import { CoreOrganizationModule } from "@bitwarden/web-vault/app/admin-console/organizations/core";
|
import { CoreOrganizationModule } from "@bitwarden/web-vault/app/admin-console/organizations/core";
|
||||||
import { DynamicAvatarComponent } from "@bitwarden/web-vault/app/components/dynamic-avatar.component";
|
import { DynamicAvatarComponent } from "@bitwarden/web-vault/app/components/dynamic-avatar.component";
|
||||||
@ -31,17 +33,21 @@ import { SecretsListComponent } from "./secrets-list.component";
|
|||||||
DynamicAvatarComponent,
|
DynamicAvatarComponent,
|
||||||
SearchModule,
|
SearchModule,
|
||||||
HeaderModule,
|
HeaderModule,
|
||||||
|
CardComponent,
|
||||||
|
FormFieldModule,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
AccessPolicySelectorComponent,
|
AccessPolicySelectorComponent,
|
||||||
BulkConfirmationDialogComponent,
|
BulkConfirmationDialogComponent,
|
||||||
BulkStatusDialogComponent,
|
BulkStatusDialogComponent,
|
||||||
|
FormFieldModule,
|
||||||
HeaderModule,
|
HeaderModule,
|
||||||
NewMenuComponent,
|
NewMenuComponent,
|
||||||
NoItemsModule,
|
NoItemsModule,
|
||||||
ProjectsListComponent,
|
ProjectsListComponent,
|
||||||
SearchModule,
|
SearchModule,
|
||||||
SecretsListComponent,
|
SecretsListComponent,
|
||||||
|
CardComponent,
|
||||||
SelectModule,
|
SelectModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
],
|
],
|
||||||
|
Loading…
Reference in New Issue
Block a user