mirror of
https://github.com/bitwarden/browser.git
synced 2024-12-22 16:29:09 +01:00
parent
6c21223466
commit
cf74870779
@ -42,32 +42,3 @@ export class ServiceAccountProjectAccessPolicyView extends BaseAccessPolicyView
|
|||||||
grantedProjectId: string;
|
grantedProjectId: string;
|
||||||
grantedProjectName: string;
|
grantedProjectName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ProjectAccessPoliciesView {
|
|
||||||
userAccessPolicies: UserProjectAccessPolicyView[];
|
|
||||||
groupAccessPolicies: GroupProjectAccessPolicyView[];
|
|
||||||
serviceAccountAccessPolicies: ServiceAccountProjectAccessPolicyView[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ProjectPeopleAccessPoliciesView {
|
|
||||||
userAccessPolicies: UserProjectAccessPolicyView[];
|
|
||||||
groupAccessPolicies: GroupProjectAccessPolicyView[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ServiceAccountPeopleAccessPoliciesView {
|
|
||||||
userAccessPolicies: UserServiceAccountAccessPolicyView[];
|
|
||||||
groupAccessPolicies: GroupServiceAccountAccessPolicyView[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ServiceAccountProjectPolicyPermissionDetailsView {
|
|
||||||
accessPolicy: ServiceAccountProjectAccessPolicyView;
|
|
||||||
hasPermission: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ServiceAccountGrantedPoliciesView {
|
|
||||||
grantedProjectPolicies: ServiceAccountProjectPolicyPermissionDetailsView[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ProjectServiceAccountsAccessPoliciesView {
|
|
||||||
serviceAccountAccessPolicies: ServiceAccountProjectAccessPolicyView[];
|
|
||||||
}
|
|
@ -0,0 +1,6 @@
|
|||||||
|
import { GroupProjectAccessPolicyView, UserProjectAccessPolicyView } from "./access-policy.view";
|
||||||
|
|
||||||
|
export class ProjectPeopleAccessPoliciesView {
|
||||||
|
userAccessPolicies: UserProjectAccessPolicyView[];
|
||||||
|
groupAccessPolicies: GroupProjectAccessPolicyView[];
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
import { ServiceAccountProjectAccessPolicyView } from "./access-policy.view";
|
||||||
|
|
||||||
|
export class ProjectServiceAccountsAccessPoliciesView {
|
||||||
|
serviceAccountAccessPolicies: ServiceAccountProjectAccessPolicyView[];
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import { ServiceAccountProjectAccessPolicyView } from "./access-policy.view";
|
||||||
|
|
||||||
|
export class ServiceAccountGrantedPoliciesView {
|
||||||
|
grantedProjectPolicies: ServiceAccountProjectPolicyPermissionDetailsView[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ServiceAccountProjectPolicyPermissionDetailsView {
|
||||||
|
accessPolicy: ServiceAccountProjectAccessPolicyView;
|
||||||
|
hasPermission: boolean;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import {
|
||||||
|
GroupServiceAccountAccessPolicyView,
|
||||||
|
UserServiceAccountAccessPolicyView,
|
||||||
|
} from "./access-policy.view";
|
||||||
|
|
||||||
|
export class ServiceAccountPeopleAccessPoliciesView {
|
||||||
|
userAccessPolicies: UserServiceAccountAccessPolicyView[];
|
||||||
|
groupAccessPolicies: GroupServiceAccountAccessPolicyView[];
|
||||||
|
}
|
@ -7,7 +7,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
|
|
||||||
import { ProjectServiceAccountsAccessPoliciesView } from "../../models/view/access-policy.view";
|
import { ProjectServiceAccountsAccessPoliciesView } from "../../models/view/access-policies/project-service-accounts-access-policies.view";
|
||||||
import {
|
import {
|
||||||
ApItemValueType,
|
ApItemValueType,
|
||||||
convertToProjectServiceAccountsAccessPoliciesView,
|
convertToProjectServiceAccountsAccessPoliciesView,
|
||||||
|
@ -6,7 +6,6 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
|||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
|
||||||
import { ProjectListView } from "../../models/view/project-list.view";
|
import { ProjectListView } from "../../models/view/project-list.view";
|
||||||
import { AccessPolicyService } from "../../shared/access-policies/access-policy.service";
|
|
||||||
import {
|
import {
|
||||||
BulkConfirmationDetails,
|
BulkConfirmationDetails,
|
||||||
BulkConfirmationDialogComponent,
|
BulkConfirmationDialogComponent,
|
||||||
@ -38,7 +37,6 @@ export class ProjectsComponent implements OnInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private projectService: ProjectService,
|
private projectService: ProjectService,
|
||||||
private accessPolicyService: AccessPolicyService,
|
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
) {}
|
) {}
|
||||||
@ -47,7 +45,6 @@ export class ProjectsComponent implements OnInit {
|
|||||||
this.projects$ = combineLatest([
|
this.projects$ = combineLatest([
|
||||||
this.route.params,
|
this.route.params,
|
||||||
this.projectService.project$.pipe(startWith(null)),
|
this.projectService.project$.pipe(startWith(null)),
|
||||||
this.accessPolicyService.projectAccessPolicyChanges$.pipe(startWith(null)),
|
|
||||||
]).pipe(
|
]).pipe(
|
||||||
switchMap(async ([params]) => {
|
switchMap(async ([params]) => {
|
||||||
this.organizationId = params.organizationId;
|
this.organizationId = params.organizationId;
|
||||||
|
@ -7,7 +7,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
|
||||||
|
|
||||||
import { ServiceAccountGrantedPoliciesView } from "../../models/view/access-policy.view";
|
import { ServiceAccountGrantedPoliciesView } from "../../models/view/access-policies/service-account-granted-policies.view";
|
||||||
import {
|
import {
|
||||||
ApItemValueType,
|
ApItemValueType,
|
||||||
convertToServiceAccountGrantedPoliciesView,
|
convertToServiceAccountGrantedPoliciesView,
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
import {
|
import {
|
||||||
ProjectPeopleAccessPoliciesView,
|
|
||||||
UserProjectAccessPolicyView,
|
UserProjectAccessPolicyView,
|
||||||
GroupProjectAccessPolicyView,
|
GroupProjectAccessPolicyView,
|
||||||
ServiceAccountPeopleAccessPoliciesView,
|
|
||||||
UserServiceAccountAccessPolicyView,
|
UserServiceAccountAccessPolicyView,
|
||||||
GroupServiceAccountAccessPolicyView,
|
GroupServiceAccountAccessPolicyView,
|
||||||
|
ServiceAccountProjectAccessPolicyView,
|
||||||
|
} from "../../../../models/view/access-policies/access-policy.view";
|
||||||
|
import { ProjectPeopleAccessPoliciesView } from "../../../../models/view/access-policies/project-people-access-policies.view";
|
||||||
|
import { ProjectServiceAccountsAccessPoliciesView } from "../../../../models/view/access-policies/project-service-accounts-access-policies.view";
|
||||||
|
import {
|
||||||
ServiceAccountGrantedPoliciesView,
|
ServiceAccountGrantedPoliciesView,
|
||||||
ServiceAccountProjectPolicyPermissionDetailsView,
|
ServiceAccountProjectPolicyPermissionDetailsView,
|
||||||
ServiceAccountProjectAccessPolicyView,
|
} from "../../../../models/view/access-policies/service-account-granted-policies.view";
|
||||||
ProjectServiceAccountsAccessPoliciesView,
|
import { ServiceAccountPeopleAccessPoliciesView } from "../../../../models/view/access-policies/service-account-people-access-policies.view";
|
||||||
} from "../../../../models/view/access-policy.view";
|
|
||||||
|
|
||||||
import { ApItemEnum } from "./enums/ap-item.enum";
|
import { ApItemEnum } from "./enums/ap-item.enum";
|
||||||
import { ApPermissionEnum, ApPermissionEnumUtil } from "./enums/ap-permission.enum";
|
import { ApPermissionEnum, ApPermissionEnumUtil } from "./enums/ap-permission.enum";
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||||
import { SelectItemView } from "@bitwarden/components";
|
import { SelectItemView } from "@bitwarden/components";
|
||||||
|
|
||||||
import {
|
import { PotentialGranteeView } from "../../../../models/view/access-policies/potential-grantee.view";
|
||||||
ProjectPeopleAccessPoliciesView,
|
import { ProjectPeopleAccessPoliciesView } from "../../../../models/view/access-policies/project-people-access-policies.view";
|
||||||
ServiceAccountGrantedPoliciesView,
|
import { ProjectServiceAccountsAccessPoliciesView } from "../../../../models/view/access-policies/project-service-accounts-access-policies.view";
|
||||||
ProjectServiceAccountsAccessPoliciesView,
|
import { ServiceAccountGrantedPoliciesView } from "../../../../models/view/access-policies/service-account-granted-policies.view";
|
||||||
ServiceAccountPeopleAccessPoliciesView,
|
import { ServiceAccountPeopleAccessPoliciesView } from "../../../../models/view/access-policies/service-account-people-access-policies.view";
|
||||||
} from "../../../../models/view/access-policy.view";
|
|
||||||
import { PotentialGranteeView } from "../../../../models/view/potential-grantee.view";
|
|
||||||
|
|
||||||
import { ApItemEnum, ApItemEnumUtil } from "./enums/ap-item.enum";
|
import { ApItemEnum, ApItemEnumUtil } from "./enums/ap-item.enum";
|
||||||
import { ApPermissionEnum, ApPermissionEnumUtil } from "./enums/ap-permission.enum";
|
import { ApPermissionEnum, ApPermissionEnumUtil } from "./enums/ap-permission.enum";
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from "@angular/core";
|
||||||
import { Subject } from "rxjs";
|
|
||||||
|
|
||||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||||
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
import { ListResponse } from "@bitwarden/common/models/response/list.response";
|
||||||
@ -9,26 +8,23 @@ import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
|||||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
BaseAccessPolicyView,
|
|
||||||
GroupProjectAccessPolicyView,
|
|
||||||
GroupServiceAccountAccessPolicyView,
|
|
||||||
ProjectAccessPoliciesView,
|
|
||||||
ProjectPeopleAccessPoliciesView,
|
|
||||||
ServiceAccountProjectAccessPolicyView,
|
|
||||||
UserProjectAccessPolicyView,
|
UserProjectAccessPolicyView,
|
||||||
|
GroupProjectAccessPolicyView,
|
||||||
UserServiceAccountAccessPolicyView,
|
UserServiceAccountAccessPolicyView,
|
||||||
ServiceAccountPeopleAccessPoliciesView,
|
GroupServiceAccountAccessPolicyView,
|
||||||
|
ServiceAccountProjectAccessPolicyView,
|
||||||
|
} from "../../models/view/access-policies/access-policy.view";
|
||||||
|
import { PotentialGranteeView } from "../../models/view/access-policies/potential-grantee.view";
|
||||||
|
import { ProjectPeopleAccessPoliciesView } from "../../models/view/access-policies/project-people-access-policies.view";
|
||||||
|
import { ProjectServiceAccountsAccessPoliciesView } from "../../models/view/access-policies/project-service-accounts-access-policies.view";
|
||||||
|
import {
|
||||||
ServiceAccountGrantedPoliciesView,
|
ServiceAccountGrantedPoliciesView,
|
||||||
ProjectServiceAccountsAccessPoliciesView,
|
|
||||||
ServiceAccountProjectPolicyPermissionDetailsView,
|
ServiceAccountProjectPolicyPermissionDetailsView,
|
||||||
} from "../../models/view/access-policy.view";
|
} from "../../models/view/access-policies/service-account-granted-policies.view";
|
||||||
import { PotentialGranteeView } from "../../models/view/potential-grantee.view";
|
import { ServiceAccountPeopleAccessPoliciesView } from "../../models/view/access-policies/service-account-people-access-policies.view";
|
||||||
import { AccessPoliciesCreateRequest } from "../../shared/access-policies/models/requests/access-policies-create.request";
|
|
||||||
import { PeopleAccessPoliciesRequest } from "../../shared/access-policies/models/requests/people-access-policies.request";
|
import { PeopleAccessPoliciesRequest } from "../../shared/access-policies/models/requests/people-access-policies.request";
|
||||||
import { ProjectAccessPoliciesResponse } from "../../shared/access-policies/models/responses/project-access-policies.response";
|
|
||||||
import { ServiceAccountGrantedPoliciesRequest } from "../access-policies/models/requests/service-account-granted-policies.request";
|
import { ServiceAccountGrantedPoliciesRequest } from "../access-policies/models/requests/service-account-granted-policies.request";
|
||||||
|
|
||||||
import { AccessPolicyUpdateRequest } from "./models/requests/access-policy-update.request";
|
|
||||||
import { AccessPolicyRequest } from "./models/requests/access-policy.request";
|
import { AccessPolicyRequest } from "./models/requests/access-policy.request";
|
||||||
import { ProjectServiceAccountsAccessPoliciesRequest } from "./models/requests/project-service-accounts-access-policies.request";
|
import { ProjectServiceAccountsAccessPoliciesRequest } from "./models/requests/project-service-accounts-access-policies.request";
|
||||||
import {
|
import {
|
||||||
@ -49,39 +45,12 @@ import { ServiceAccountProjectPolicyPermissionDetailsResponse } from "./models/r
|
|||||||
providedIn: "root",
|
providedIn: "root",
|
||||||
})
|
})
|
||||||
export class AccessPolicyService {
|
export class AccessPolicyService {
|
||||||
private _projectAccessPolicyChanges$ = new Subject<ProjectAccessPoliciesView>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits when a project access policy is created or deleted.
|
|
||||||
*/
|
|
||||||
readonly projectAccessPolicyChanges$ = this._projectAccessPolicyChanges$.asObservable();
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private cryptoService: CryptoService,
|
private cryptoService: CryptoService,
|
||||||
protected apiService: ApiService,
|
protected apiService: ApiService,
|
||||||
protected encryptService: EncryptService,
|
protected encryptService: EncryptService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
refreshProjectAccessPolicyChanges() {
|
|
||||||
this._projectAccessPolicyChanges$.next(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getProjectAccessPolicies(
|
|
||||||
organizationId: string,
|
|
||||||
projectId: string,
|
|
||||||
): Promise<ProjectAccessPoliciesView> {
|
|
||||||
const r = await this.apiService.send(
|
|
||||||
"GET",
|
|
||||||
"/projects/" + projectId + "/access-policies",
|
|
||||||
null,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
const results = new ProjectAccessPoliciesResponse(r);
|
|
||||||
return await this.createProjectAccessPoliciesView(organizationId, results);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getProjectPeopleAccessPolicies(
|
async getProjectPeopleAccessPolicies(
|
||||||
projectId: string,
|
projectId: string,
|
||||||
): Promise<ProjectPeopleAccessPoliciesView> {
|
): Promise<ProjectPeopleAccessPoliciesView> {
|
||||||
@ -212,43 +181,6 @@ export class AccessPolicyService {
|
|||||||
return await this.createProjectServiceAccountsAccessPoliciesView(result, organizationId);
|
return await this.createProjectServiceAccountsAccessPoliciesView(result, organizationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createProjectAccessPolicies(
|
|
||||||
organizationId: string,
|
|
||||||
projectId: string,
|
|
||||||
projectAccessPoliciesView: ProjectAccessPoliciesView,
|
|
||||||
): Promise<ProjectAccessPoliciesView> {
|
|
||||||
const request = this.getAccessPoliciesCreateRequest(projectAccessPoliciesView);
|
|
||||||
const r = await this.apiService.send(
|
|
||||||
"POST",
|
|
||||||
"/projects/" + projectId + "/access-policies",
|
|
||||||
request,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
const results = new ProjectAccessPoliciesResponse(r);
|
|
||||||
const view = await this.createProjectAccessPoliciesView(organizationId, results);
|
|
||||||
this._projectAccessPolicyChanges$.next(view);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteAccessPolicy(accessPolicyId: string): Promise<void> {
|
|
||||||
await this.apiService.send("DELETE", "/access-policies/" + accessPolicyId, null, true, false);
|
|
||||||
this._projectAccessPolicyChanges$.next(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateAccessPolicy(baseAccessPolicyView: BaseAccessPolicyView): Promise<void> {
|
|
||||||
const payload = new AccessPolicyUpdateRequest();
|
|
||||||
payload.read = baseAccessPolicyView.read;
|
|
||||||
payload.write = baseAccessPolicyView.write;
|
|
||||||
await this.apiService.send(
|
|
||||||
"PUT",
|
|
||||||
"/access-policies/" + baseAccessPolicyView.id,
|
|
||||||
payload,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getPeoplePotentialGrantees(organizationId: string) {
|
async getPeoplePotentialGrantees(organizationId: string) {
|
||||||
const r = await this.apiService.send(
|
const r = await this.apiService.send(
|
||||||
"GET",
|
"GET",
|
||||||
@ -285,11 +217,11 @@ export class AccessPolicyService {
|
|||||||
return await this.createPotentialGranteeViews(organizationId, results.data);
|
return await this.createPotentialGranteeViews(organizationId, results.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async getOrganizationKey(organizationId: string): Promise<SymmetricCryptoKey> {
|
private async getOrganizationKey(organizationId: string): Promise<SymmetricCryptoKey> {
|
||||||
return await this.cryptoService.getOrgKey(organizationId);
|
return await this.cryptoService.getOrgKey(organizationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected getAccessPolicyRequest(
|
private getAccessPolicyRequest(
|
||||||
granteeId: string,
|
granteeId: string,
|
||||||
view:
|
view:
|
||||||
| UserProjectAccessPolicyView
|
| UserProjectAccessPolicyView
|
||||||
@ -305,7 +237,53 @@ export class AccessPolicyService {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createBaseAccessPolicyView(
|
private getServiceAccountGrantedPoliciesRequest(
|
||||||
|
policies: ServiceAccountGrantedPoliciesView,
|
||||||
|
): ServiceAccountGrantedPoliciesRequest {
|
||||||
|
const request = new ServiceAccountGrantedPoliciesRequest();
|
||||||
|
|
||||||
|
request.projectGrantedPolicyRequests = policies.grantedProjectPolicies.map((detailView) => ({
|
||||||
|
grantedId: detailView.accessPolicy.grantedProjectId,
|
||||||
|
read: detailView.accessPolicy.read,
|
||||||
|
write: detailView.accessPolicy.write,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getProjectServiceAccountsAccessPoliciesRequest(
|
||||||
|
policies: ProjectServiceAccountsAccessPoliciesView,
|
||||||
|
): ProjectServiceAccountsAccessPoliciesRequest {
|
||||||
|
const request = new ProjectServiceAccountsAccessPoliciesRequest();
|
||||||
|
|
||||||
|
request.serviceAccountAccessPolicyRequests = policies.serviceAccountAccessPolicies.map((ap) => {
|
||||||
|
return this.getAccessPolicyRequest(ap.serviceAccountId, ap);
|
||||||
|
});
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getPeopleAccessPoliciesRequest(
|
||||||
|
view: ProjectPeopleAccessPoliciesView | ServiceAccountPeopleAccessPoliciesView,
|
||||||
|
): PeopleAccessPoliciesRequest {
|
||||||
|
const request = new PeopleAccessPoliciesRequest();
|
||||||
|
|
||||||
|
if (view.userAccessPolicies?.length > 0) {
|
||||||
|
request.userAccessPolicyRequests = view.userAccessPolicies.map((ap) => {
|
||||||
|
return this.getAccessPolicyRequest(ap.organizationUserId, ap);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view.groupAccessPolicies?.length > 0) {
|
||||||
|
request.groupAccessPolicyRequests = view.groupAccessPolicies.map((ap) => {
|
||||||
|
return this.getAccessPolicyRequest(ap.groupId, ap);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createBaseAccessPolicyView(
|
||||||
response:
|
response:
|
||||||
| UserProjectAccessPolicyResponse
|
| UserProjectAccessPolicyResponse
|
||||||
| UserServiceAccountAccessPolicyResponse
|
| UserServiceAccountAccessPolicyResponse
|
||||||
@ -348,32 +326,6 @@ export class AccessPolicyService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getServiceAccountGrantedPoliciesRequest(
|
|
||||||
policies: ServiceAccountGrantedPoliciesView,
|
|
||||||
): ServiceAccountGrantedPoliciesRequest {
|
|
||||||
const request = new ServiceAccountGrantedPoliciesRequest();
|
|
||||||
|
|
||||||
request.projectGrantedPolicyRequests = policies.grantedProjectPolicies.map((detailView) => ({
|
|
||||||
grantedId: detailView.accessPolicy.grantedProjectId,
|
|
||||||
read: detailView.accessPolicy.read,
|
|
||||||
write: detailView.accessPolicy.write,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getProjectServiceAccountsAccessPoliciesRequest(
|
|
||||||
policies: ProjectServiceAccountsAccessPoliciesView,
|
|
||||||
): ProjectServiceAccountsAccessPoliciesRequest {
|
|
||||||
const request = new ProjectServiceAccountsAccessPoliciesRequest();
|
|
||||||
|
|
||||||
request.serviceAccountAccessPolicyRequests = policies.serviceAccountAccessPolicies.map((ap) => {
|
|
||||||
return this.getAccessPolicyRequest(ap.serviceAccountId, ap);
|
|
||||||
});
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async createServiceAccountGrantedPoliciesView(
|
private async createServiceAccountGrantedPoliciesView(
|
||||||
response: ServiceAccountGrantedPoliciesPermissionDetailsResponse,
|
response: ServiceAccountGrantedPoliciesPermissionDetailsResponse,
|
||||||
organizationId: string,
|
organizationId: string,
|
||||||
@ -413,27 +365,6 @@ export class AccessPolicyService {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async createProjectAccessPoliciesView(
|
|
||||||
organizationId: string,
|
|
||||||
projectAccessPoliciesResponse: ProjectAccessPoliciesResponse,
|
|
||||||
): Promise<ProjectAccessPoliciesView> {
|
|
||||||
const orgKey = await this.getOrganizationKey(organizationId);
|
|
||||||
const view = new ProjectAccessPoliciesView();
|
|
||||||
|
|
||||||
view.userAccessPolicies = projectAccessPoliciesResponse.userAccessPolicies.map((ap) => {
|
|
||||||
return this.createUserProjectAccessPolicyView(ap);
|
|
||||||
});
|
|
||||||
view.groupAccessPolicies = projectAccessPoliciesResponse.groupAccessPolicies.map((ap) => {
|
|
||||||
return this.createGroupProjectAccessPolicyView(ap);
|
|
||||||
});
|
|
||||||
view.serviceAccountAccessPolicies = await Promise.all(
|
|
||||||
projectAccessPoliciesResponse.serviceAccountAccessPolicies.map(async (ap) => {
|
|
||||||
return await this.createServiceAccountProjectAccessPolicyView(orgKey, ap);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
private createProjectPeopleAccessPoliciesView(
|
private createProjectPeopleAccessPoliciesView(
|
||||||
peopleAccessPoliciesResponse: ProjectPeopleAccessPoliciesResponse,
|
peopleAccessPoliciesResponse: ProjectPeopleAccessPoliciesResponse,
|
||||||
): ProjectPeopleAccessPoliciesView {
|
): ProjectPeopleAccessPoliciesView {
|
||||||
@ -462,56 +393,6 @@ export class AccessPolicyService {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getAccessPoliciesCreateRequest(
|
|
||||||
projectAccessPoliciesView: ProjectAccessPoliciesView,
|
|
||||||
): AccessPoliciesCreateRequest {
|
|
||||||
const createRequest = new AccessPoliciesCreateRequest();
|
|
||||||
|
|
||||||
if (projectAccessPoliciesView.userAccessPolicies?.length > 0) {
|
|
||||||
createRequest.userAccessPolicyRequests = projectAccessPoliciesView.userAccessPolicies.map(
|
|
||||||
(ap) => {
|
|
||||||
return this.getAccessPolicyRequest(ap.organizationUserId, ap);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (projectAccessPoliciesView.groupAccessPolicies?.length > 0) {
|
|
||||||
createRequest.groupAccessPolicyRequests = projectAccessPoliciesView.groupAccessPolicies.map(
|
|
||||||
(ap) => {
|
|
||||||
return this.getAccessPolicyRequest(ap.groupId, ap);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (projectAccessPoliciesView.serviceAccountAccessPolicies?.length > 0) {
|
|
||||||
createRequest.serviceAccountAccessPolicyRequests =
|
|
||||||
projectAccessPoliciesView.serviceAccountAccessPolicies.map((ap) => {
|
|
||||||
return this.getAccessPolicyRequest(ap.serviceAccountId, ap);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return createRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
private getPeopleAccessPoliciesRequest(
|
|
||||||
view: ProjectPeopleAccessPoliciesView | ServiceAccountPeopleAccessPoliciesView,
|
|
||||||
): PeopleAccessPoliciesRequest {
|
|
||||||
const request = new PeopleAccessPoliciesRequest();
|
|
||||||
|
|
||||||
if (view.userAccessPolicies?.length > 0) {
|
|
||||||
request.userAccessPolicyRequests = view.userAccessPolicies.map((ap) => {
|
|
||||||
return this.getAccessPolicyRequest(ap.organizationUserId, ap);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (view.groupAccessPolicies?.length > 0) {
|
|
||||||
request.groupAccessPolicyRequests = view.groupAccessPolicies.map((ap) => {
|
|
||||||
return this.getAccessPolicyRequest(ap.groupId, ap);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
private createUserProjectAccessPolicyView(
|
private createUserProjectAccessPolicyView(
|
||||||
response: UserProjectAccessPolicyResponse,
|
response: UserProjectAccessPolicyResponse,
|
||||||
): UserProjectAccessPolicyView {
|
): UserProjectAccessPolicyView {
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
<form [formGroup]="formGroup" [bitSubmit]="submit" class="tw-mt-5">
|
|
||||||
<bit-form-field>
|
|
||||||
<bit-label>{{ label }}</bit-label>
|
|
||||||
<bit-multi-select
|
|
||||||
class="tw-mr-4 tw-w-full"
|
|
||||||
formControlName="multiSelect"
|
|
||||||
[baseItems]="selectItems$ | async"
|
|
||||||
[loading]="loading"
|
|
||||||
></bit-multi-select>
|
|
||||||
<bit-hint>{{ hint }}</bit-hint>
|
|
||||||
<button type="submit" bitButton buttonType="primary" bitFormButton>
|
|
||||||
{{ "add" | i18n }}
|
|
||||||
</button>
|
|
||||||
</bit-form-field>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<ng-container>
|
|
||||||
<bit-table *ngIf="rows$ | async as rows; else spinner">
|
|
||||||
<ng-container header>
|
|
||||||
<tr>
|
|
||||||
<th bitCell colspan="2">{{ columnTitle }}</th>
|
|
||||||
<th bitCell>{{ "permissions" | i18n }}</th>
|
|
||||||
</tr>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-template body>
|
|
||||||
<ng-container *ngIf="rows.length > 0; else empty">
|
|
||||||
<tr bitRow *ngFor="let row of rows">
|
|
||||||
<td bitCell class="tw-w-0 tw-pr-0">
|
|
||||||
<i class="bwi {{ row.icon }} tw-text-muted" aria-hidden="true"></i>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-max-w-sm tw-truncate">{{ row.name }}</td>
|
|
||||||
<td bitCell>
|
|
||||||
<bit-form-field
|
|
||||||
*ngIf="!row.static; else staticPermissions"
|
|
||||||
class="tw-mb-auto tw-inline-block tw-w-auto"
|
|
||||||
>
|
|
||||||
<select bitInput (change)="update($event.target, row)" [disabled]="row.static">
|
|
||||||
<option value="canRead" [selected]="row.read && row.write != true">
|
|
||||||
{{ "canRead" | i18n }}
|
|
||||||
</option>
|
|
||||||
<option value="canReadWrite" [selected]="row.read && row.write">
|
|
||||||
{{ "canReadWrite" | i18n }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</bit-form-field>
|
|
||||||
<ng-template #staticPermissions>
|
|
||||||
<span *ngIf="row.read && row.write != true">{{ "canRead" | i18n }}</span>
|
|
||||||
<span *ngIf="row.read != true && row.write">{{ "canWrite" | i18n }}</span>
|
|
||||||
<span *ngIf="row.read && row.write">{{ "canReadWrite" | i18n }}</span>
|
|
||||||
</ng-template>
|
|
||||||
</td>
|
|
||||||
<td bitCell class="tw-w-0">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
bitIconButton="bwi-close"
|
|
||||||
buttonType="main"
|
|
||||||
size="default"
|
|
||||||
[attr.title]="'remove' | i18n"
|
|
||||||
[attr.aria-label]="'remove' | i18n"
|
|
||||||
[bitAction]="delete(row)"
|
|
||||||
></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</ng-container>
|
|
||||||
</ng-template>
|
|
||||||
</bit-table>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-template #empty>
|
|
||||||
<div class="tw-mt-4 tw-text-center">
|
|
||||||
{{ emptyMessage }}
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template #spinner>
|
|
||||||
<div class="tw-items-center tw-justify-center tw-pt-10 tw-text-center">
|
|
||||||
<i class="bwi bwi-spinner bwi-spin bwi-3x"></i>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
@ -1,194 +0,0 @@
|
|||||||
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
|
||||||
import { FormControl, FormGroup, Validators } from "@angular/forms";
|
|
||||||
import { ActivatedRoute } from "@angular/router";
|
|
||||||
import {
|
|
||||||
combineLatest,
|
|
||||||
firstValueFrom,
|
|
||||||
map,
|
|
||||||
Observable,
|
|
||||||
share,
|
|
||||||
Subject,
|
|
||||||
switchMap,
|
|
||||||
tap,
|
|
||||||
} from "rxjs";
|
|
||||||
|
|
||||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
|
||||||
import { SelectItemView } from "@bitwarden/components/src/multi-select/models/select-item-view";
|
|
||||||
|
|
||||||
import { BaseAccessPolicyView } from "../../models/view/access-policy.view";
|
|
||||||
|
|
||||||
import { AccessPolicyService } from "./access-policy.service";
|
|
||||||
|
|
||||||
export type AccessSelectorRowView = {
|
|
||||||
type: "user" | "group" | "serviceAccount" | "project";
|
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
accessPolicyId: string;
|
|
||||||
read: boolean;
|
|
||||||
write: boolean;
|
|
||||||
icon: string;
|
|
||||||
userId?: string;
|
|
||||||
currentUserInGroup?: boolean;
|
|
||||||
static?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "sm-access-selector",
|
|
||||||
templateUrl: "./access-selector.component.html",
|
|
||||||
})
|
|
||||||
export class AccessSelectorComponent implements OnInit {
|
|
||||||
static readonly userIcon = "bwi-user";
|
|
||||||
static readonly groupIcon = "bwi-family";
|
|
||||||
static readonly serviceAccountIcon = "bwi-wrench";
|
|
||||||
static readonly projectIcon = "bwi-collection";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emits the selected items on submit.
|
|
||||||
*/
|
|
||||||
@Output() onCreateAccessPolicies = new EventEmitter<SelectItemView[]>();
|
|
||||||
@Output() onDeleteAccessPolicy = new EventEmitter<AccessSelectorRowView>();
|
|
||||||
@Output() onUpdateAccessPolicy = new EventEmitter<AccessSelectorRowView>();
|
|
||||||
|
|
||||||
@Input() label: string;
|
|
||||||
@Input() hint: string;
|
|
||||||
@Input() columnTitle: string;
|
|
||||||
@Input() emptyMessage: string;
|
|
||||||
@Input() granteeType: "people" | "serviceAccounts" | "projects";
|
|
||||||
|
|
||||||
protected rows$ = new Subject<AccessSelectorRowView[]>();
|
|
||||||
@Input() private set rows(value: AccessSelectorRowView[]) {
|
|
||||||
const sorted = value.sort((a, b) => {
|
|
||||||
if (a.icon == b.icon) {
|
|
||||||
return a.name.localeCompare(b.name);
|
|
||||||
}
|
|
||||||
if (a.icon == AccessSelectorComponent.userIcon) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
});
|
|
||||||
this.rows$.next(sorted);
|
|
||||||
}
|
|
||||||
|
|
||||||
private maxLength = 15;
|
|
||||||
protected formGroup = new FormGroup({
|
|
||||||
multiSelect: new FormControl([], [Validators.required, Validators.maxLength(this.maxLength)]),
|
|
||||||
});
|
|
||||||
protected loading = true;
|
|
||||||
|
|
||||||
protected selectItems$: Observable<SelectItemView[]> = combineLatest([
|
|
||||||
this.rows$,
|
|
||||||
this.route.params,
|
|
||||||
]).pipe(
|
|
||||||
switchMap(([rows, params]) =>
|
|
||||||
this.getPotentialGrantees(params.organizationId).then((grantees) =>
|
|
||||||
grantees
|
|
||||||
.filter((g) => !rows.some((row) => row.id === g.id))
|
|
||||||
.map((granteeView) => {
|
|
||||||
let icon: string;
|
|
||||||
let listName = granteeView.name;
|
|
||||||
let labelName = granteeView.name;
|
|
||||||
if (granteeView.type === "user") {
|
|
||||||
icon = AccessSelectorComponent.userIcon;
|
|
||||||
if (Utils.isNullOrWhitespace(granteeView.name)) {
|
|
||||||
listName = granteeView.email;
|
|
||||||
labelName = granteeView.email;
|
|
||||||
} else {
|
|
||||||
listName = `${granteeView.name} (${granteeView.email})`;
|
|
||||||
}
|
|
||||||
} else if (granteeView.type === "group") {
|
|
||||||
icon = AccessSelectorComponent.groupIcon;
|
|
||||||
} else if (granteeView.type === "serviceAccount") {
|
|
||||||
icon = AccessSelectorComponent.serviceAccountIcon;
|
|
||||||
} else if (granteeView.type === "project") {
|
|
||||||
icon = AccessSelectorComponent.projectIcon;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
icon: icon,
|
|
||||||
id: granteeView.id,
|
|
||||||
labelName: labelName,
|
|
||||||
listName: listName,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
map((selectItems) => selectItems.sort((a, b) => a.listName.localeCompare(b.listName))),
|
|
||||||
tap(() => {
|
|
||||||
this.loading = false;
|
|
||||||
this.formGroup.reset();
|
|
||||||
this.formGroup.enable();
|
|
||||||
}),
|
|
||||||
share(),
|
|
||||||
);
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private accessPolicyService: AccessPolicyService,
|
|
||||||
private route: ActivatedRoute,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
this.formGroup.disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
submit = async () => {
|
|
||||||
this.formGroup.markAllAsTouched();
|
|
||||||
if (this.formGroup.invalid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.formGroup.disable();
|
|
||||||
this.loading = true;
|
|
||||||
|
|
||||||
this.onCreateAccessPolicies.emit(this.formGroup.value.multiSelect);
|
|
||||||
|
|
||||||
return firstValueFrom(this.selectItems$);
|
|
||||||
};
|
|
||||||
|
|
||||||
async update(target: any, row: AccessSelectorRowView): Promise<void> {
|
|
||||||
if (target.value === "canRead") {
|
|
||||||
row.read = true;
|
|
||||||
row.write = false;
|
|
||||||
} else if (target.value === "canReadWrite") {
|
|
||||||
row.read = true;
|
|
||||||
row.write = true;
|
|
||||||
}
|
|
||||||
this.onUpdateAccessPolicy.emit(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete = (row: AccessSelectorRowView) => async () => {
|
|
||||||
this.loading = true;
|
|
||||||
this.formGroup.disable();
|
|
||||||
this.onDeleteAccessPolicy.emit(row);
|
|
||||||
return firstValueFrom(this.selectItems$);
|
|
||||||
};
|
|
||||||
|
|
||||||
private getPotentialGrantees(organizationId: string) {
|
|
||||||
switch (this.granteeType) {
|
|
||||||
case "people":
|
|
||||||
return this.accessPolicyService.getPeoplePotentialGrantees(organizationId);
|
|
||||||
case "serviceAccounts":
|
|
||||||
return this.accessPolicyService.getServiceAccountsPotentialGrantees(organizationId);
|
|
||||||
case "projects":
|
|
||||||
return this.accessPolicyService.getProjectsPotentialGrantees(organizationId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static getAccessItemType(item: SelectItemView) {
|
|
||||||
switch (item.icon) {
|
|
||||||
case AccessSelectorComponent.userIcon:
|
|
||||||
return "user";
|
|
||||||
case AccessSelectorComponent.groupIcon:
|
|
||||||
return "group";
|
|
||||||
case AccessSelectorComponent.serviceAccountIcon:
|
|
||||||
return "serviceAccount";
|
|
||||||
case AccessSelectorComponent.projectIcon:
|
|
||||||
return "project";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static getBaseAccessPolicyView(row: AccessSelectorRowView) {
|
|
||||||
const view = new BaseAccessPolicyView();
|
|
||||||
view.id = row.accessPolicyId;
|
|
||||||
view.read = row.read;
|
|
||||||
view.write = row.write;
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import { AccessPolicyRequest } from "./access-policy.request";
|
|
||||||
|
|
||||||
export class AccessPoliciesCreateRequest {
|
|
||||||
userAccessPolicyRequests?: AccessPolicyRequest[];
|
|
||||||
groupAccessPolicyRequests?: AccessPolicyRequest[];
|
|
||||||
serviceAccountAccessPolicyRequests?: AccessPolicyRequest[];
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
export class AccessPolicyUpdateRequest {
|
|
||||||
read: boolean;
|
|
||||||
write: boolean;
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
import { BaseResponse } from "@bitwarden/common/models/response/base.response";
|
|
||||||
|
|
||||||
import {
|
|
||||||
GroupProjectAccessPolicyResponse,
|
|
||||||
ServiceAccountProjectAccessPolicyResponse,
|
|
||||||
UserProjectAccessPolicyResponse,
|
|
||||||
} from "./access-policy.response";
|
|
||||||
|
|
||||||
export class ProjectAccessPoliciesResponse extends BaseResponse {
|
|
||||||
userAccessPolicies: UserProjectAccessPolicyResponse[];
|
|
||||||
groupAccessPolicies: GroupProjectAccessPolicyResponse[];
|
|
||||||
serviceAccountAccessPolicies: ServiceAccountProjectAccessPolicyResponse[];
|
|
||||||
|
|
||||||
constructor(response: any) {
|
|
||||||
super(response);
|
|
||||||
const userAccessPolicies = this.getResponseProperty("UserAccessPolicies");
|
|
||||||
this.userAccessPolicies = userAccessPolicies.map(
|
|
||||||
(k: any) => new UserProjectAccessPolicyResponse(k),
|
|
||||||
);
|
|
||||||
const groupAccessPolicies = this.getResponseProperty("GroupAccessPolicies");
|
|
||||||
this.groupAccessPolicies = groupAccessPolicies.map(
|
|
||||||
(k: any) => new GroupProjectAccessPolicyResponse(k),
|
|
||||||
);
|
|
||||||
const serviceAccountAccessPolicies = this.getResponseProperty("ServiceAccountAccessPolicies");
|
|
||||||
this.serviceAccountAccessPolicies = serviceAccountAccessPolicies.map(
|
|
||||||
(k: any) => new ServiceAccountProjectAccessPolicyResponse(k),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,7 +13,6 @@ import { ProductSwitcherModule } from "@bitwarden/web-vault/app/layouts/product-
|
|||||||
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
import { SharedModule } from "@bitwarden/web-vault/app/shared";
|
||||||
|
|
||||||
import { AccessPolicySelectorComponent } from "./access-policies/access-policy-selector/access-policy-selector.component";
|
import { AccessPolicySelectorComponent } from "./access-policies/access-policy-selector/access-policy-selector.component";
|
||||||
import { AccessSelectorComponent } from "./access-policies/access-selector.component";
|
|
||||||
import { BulkConfirmationDialogComponent } from "./dialogs/bulk-confirmation-dialog.component";
|
import { BulkConfirmationDialogComponent } from "./dialogs/bulk-confirmation-dialog.component";
|
||||||
import { BulkStatusDialogComponent } from "./dialogs/bulk-status-dialog.component";
|
import { BulkStatusDialogComponent } from "./dialogs/bulk-status-dialog.component";
|
||||||
import { NewMenuComponent } from "./new-menu.component";
|
import { NewMenuComponent } from "./new-menu.component";
|
||||||
@ -35,7 +34,6 @@ import { SecretsListComponent } from "./secrets-list.component";
|
|||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
AccessPolicySelectorComponent,
|
AccessPolicySelectorComponent,
|
||||||
AccessSelectorComponent,
|
|
||||||
BulkConfirmationDialogComponent,
|
BulkConfirmationDialogComponent,
|
||||||
BulkStatusDialogComponent,
|
BulkStatusDialogComponent,
|
||||||
HeaderModule,
|
HeaderModule,
|
||||||
@ -49,7 +47,6 @@ import { SecretsListComponent } from "./secrets-list.component";
|
|||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
AccessPolicySelectorComponent,
|
AccessPolicySelectorComponent,
|
||||||
AccessSelectorComponent,
|
|
||||||
BulkConfirmationDialogComponent,
|
BulkConfirmationDialogComponent,
|
||||||
BulkStatusDialogComponent,
|
BulkStatusDialogComponent,
|
||||||
BulkStatusDialogComponent,
|
BulkStatusDialogComponent,
|
||||||
|
Loading…
Reference in New Issue
Block a user