diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html
index 80750dc0d8..2ee5ea5037 100644
--- a/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html
+++ b/bitwarden_license/bit-web/src/app/secrets-manager/layout/navigation.component.html
@@ -6,19 +6,31 @@
[text]="'projects' | i18n"
route="projects"
[relativeTo]="route.parent"
- >
+ >
+
+ {{ organizationCounts?.projects }}
+
+
+ >
+
+ {{ organizationCounts?.secrets }}
+
+
+ >
+
+ {{ organizationCounts?.serviceAccounts }}
+
+
org.canAccessSecretsManager;
- protected isAdmin$ = this.route.params.pipe(
- concatMap(
- async (params) => (await this.organizationService.get(params.organizationId))?.isAdmin,
- ),
- );
+ protected isAdmin$: Observable;
+ protected isOrgEnabled$: Observable;
+ protected organizationCounts: OrganizationCounts;
+ private destroy$: Subject = new Subject();
constructor(
protected route: ActivatedRoute,
private organizationService: OrganizationService,
+ private countService: CountService,
+ private projectService: ProjectService,
+ private secretService: SecretService,
+ private serviceAccountService: ServiceAccountService,
+ private portingApiService: SecretsManagerPortingApiService,
) {}
+
+ ngOnInit() {
+ const org$ = this.route.params.pipe(
+ concatMap((params) => this.organizationService.get(params.organizationId)),
+ distinctUntilChanged(),
+ takeUntil(this.destroy$),
+ );
+
+ this.isAdmin$ = org$.pipe(
+ map((org) => org?.isAdmin),
+ takeUntil(this.destroy$),
+ );
+
+ this.isOrgEnabled$ = org$.pipe(
+ map((org) => org?.enabled),
+ takeUntil(this.destroy$),
+ );
+
+ combineLatest([
+ org$,
+ this.projectService.project$.pipe(startWith(null)),
+ this.secretService.secret$.pipe(startWith(null)),
+ this.serviceAccountService.serviceAccount$.pipe(startWith(null)),
+ this.portingApiService.imports$.pipe(startWith(null)),
+ ])
+ .pipe(
+ filter(([org]) => org?.enabled),
+ switchMap(([org]) => this.countService.getOrganizationCounts(org.id)),
+ takeUntil(this.destroy$),
+ )
+ .subscribe((organizationCounts) => {
+ this.organizationCounts = {
+ projects: organizationCounts.projects,
+ secrets: organizationCounts.secrets,
+ serviceAccounts: organizationCounts.serviceAccounts,
+ };
+ });
+ }
+
+ ngOnDestroy(): void {
+ this.destroy$.next();
+ this.destroy$.complete();
+ }
}
diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/models/view/counts.view.ts b/bitwarden_license/bit-web/src/app/secrets-manager/models/view/counts.view.ts
new file mode 100644
index 0000000000..1520c772ec
--- /dev/null
+++ b/bitwarden_license/bit-web/src/app/secrets-manager/models/view/counts.view.ts
@@ -0,0 +1,17 @@
+export type OrganizationCounts = {
+ projects: number;
+ secrets: number;
+ serviceAccounts: number;
+};
+
+export type ProjectCounts = {
+ secrets: number;
+ people: number;
+ serviceAccounts: number;
+};
+
+export type ServiceAccountCounts = {
+ projects: number;
+ people: number;
+ accessTokens: number;
+};
diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.html
index 29cbf78464..a82e35afb6 100644
--- a/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.html
+++ b/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.html
@@ -54,7 +54,7 @@
[projects]="view.latestProjects"
>
0" class="tw-ml-auto tw-mt-4 tw-max-w-max">
- {{ "showingPortionOfTotal" | i18n: view.latestProjects.length : view.allProjects.length }}
+ {{ "showingPortionOfTotal" | i18n: view.latestProjects.length : view.counts.projects }}
{{ "viewAll" | i18n }}
@@ -72,7 +72,7 @@
[secrets]="view.latestSecrets"
>
0" class="tw-ml-auto tw-mt-4 tw-max-w-max">
- {{ "showingPortionOfTotal" | i18n: view.latestSecrets.length : view.allSecrets.length }}
+ {{ "showingPortionOfTotal" | i18n: view.latestSecrets.length : view.counts.secrets }}
{{ "viewAll" | i18n }}
diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts
index 4c057e5698..7073b4c289 100644
--- a/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts
+++ b/bitwarden_license/bit-web/src/app/secrets-manager/overview/overview.component.ts
@@ -21,6 +21,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService } from "@bitwarden/components";
+import { OrganizationCounts } from "../models/view/counts.view";
import { ProjectListView } from "../models/view/project-list.view";
import { SecretListView } from "../models/view/secret-list.view";
import {
@@ -51,6 +52,7 @@ import {
ServiceAccountOperation,
} from "../service-accounts/dialog/service-account-dialog.component";
import { ServiceAccountService } from "../service-accounts/service-account.service";
+import { CountService } from "../shared/counts/count.service";
import { SecretsListComponent } from "../shared/secrets-list.component";
import { SMOnboardingTasks, SMOnboardingTasksService } from "./sm-onboarding-tasks.service";
@@ -87,11 +89,13 @@ export class OverviewComponent implements OnInit, OnDestroy {
latestProjects: ProjectListView[];
latestSecrets: SecretListView[];
tasks: OrganizationTasks;
+ counts: OrganizationCounts;
}>;
constructor(
private route: ActivatedRoute,
private projectService: ProjectService,
+ private countService: CountService,
private secretService: SecretService,
private serviceAccountService: ServiceAccountService,
private dialogService: DialogService,
@@ -148,10 +152,19 @@ export class OverviewComponent implements OnInit, OnDestroy {
share(),
);
+ const counts$ = combineLatest([
+ orgId$,
+ this.secretService.secret$.pipe(startWith(null)),
+ this.projectService.project$.pipe(startWith(null)),
+ ]).pipe(
+ switchMap(([orgId]) => this.countService.getOrganizationCounts(orgId)),
+ share(),
+ );
+
this.view$ = orgId$.pipe(
switchMap((orgId) =>
- combineLatest([projects$, secrets$, serviceAccounts$]).pipe(
- switchMap(async ([projects, secrets, serviceAccounts]) => ({
+ combineLatest([projects$, secrets$, serviceAccounts$, counts$]).pipe(
+ switchMap(async ([projects, secrets, serviceAccounts, counts]) => ({
latestProjects: this.getRecentItems(projects, this.tableSize),
latestSecrets: this.getRecentItems(secrets, this.tableSize),
allProjects: projects,
@@ -162,6 +175,11 @@ export class OverviewComponent implements OnInit, OnDestroy {
createProject: projects.length > 0,
createServiceAccount: serviceAccounts.length > 0,
}),
+ counts: {
+ projects: counts.projects,
+ secrets: counts.secrets,
+ serviceAccounts: counts.serviceAccounts,
+ },
})),
),
),
diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.html
index d95f4392eb..d44d7898ca 100644
--- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.html
+++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.html
@@ -3,10 +3,25 @@
{{ "projects" | i18n }}
- {{ "secrets" | i18n }}
+
+ {{ "secrets" | i18n }}
+
+ {{ projectCounts?.secrets }}
+
+
- {{ "people" | i18n }}
- {{ "machineAccounts" | i18n }}
+
+ {{ "people" | i18n }}
+
+ {{ projectCounts?.people }}
+
+
+
+ {{ "machineAccounts" | i18n }}
+
+ {{ projectCounts?.serviceAccounts }}
+
+
diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.ts
index 07ca32600a..fb7f2d7452 100644
--- a/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.ts
+++ b/bitwarden_license/bit-web/src/app/secrets-manager/projects/project/project.component.ts
@@ -1,5 +1,5 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
-import { ActivatedRoute, Router } from "@angular/router";
+import { ActivatedRoute } from "@angular/router";
import {
combineLatest,
filter,
@@ -13,11 +13,13 @@ import {
} from "rxjs";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
-import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
-import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { DialogService } from "@bitwarden/components";
+import { ProjectCounts } from "../../models/view/counts.view";
import { ProjectView } from "../../models/view/project.view";
+import { SecretService } from "../../secrets/secret.service";
+import { AccessPolicyService } from "../../shared/access-policies/access-policy.service";
+import { CountService } from "../../shared/counts/count.service";
import {
OperationType,
ProjectDialogComponent,
@@ -31,6 +33,7 @@ import { ProjectService } from "../project.service";
})
export class ProjectComponent implements OnInit, OnDestroy {
protected project$: Observable;
+ protected projectCounts: ProjectCounts;
private organizationId: string;
private projectId: string;
@@ -40,11 +43,11 @@ export class ProjectComponent implements OnInit, OnDestroy {
constructor(
private route: ActivatedRoute,
private projectService: ProjectService,
- private router: Router,
+ private secretService: SecretService,
+ private accessPolicyService: AccessPolicyService,
private dialogService: DialogService,
- private platformUtilsService: PlatformUtilsService,
- private i18nService: I18nService,
private organizationService: OrganizationService,
+ private countService: CountService,
) {}
ngOnInit(): void {
@@ -62,13 +65,23 @@ export class ProjectComponent implements OnInit, OnDestroy {
const organization$ = this.route.params.pipe(
concatMap((params) => this.organizationService.get$(params.organizationId)),
);
+ const projectCounts$ = combineLatest([
+ this.route.params,
+ this.secretService.secret$.pipe(startWith(null)),
+ this.accessPolicyService.accessPolicy$.pipe(startWith(null)),
+ ]).pipe(switchMap(([params]) => this.countService.getProjectCounts(params.projectId)));
- combineLatest([projectId$, organization$])
+ combineLatest([projectId$, organization$, projectCounts$])
.pipe(takeUntil(this.destroy$))
- .subscribe(([projectId, organization]) => {
+ .subscribe(([projectId, organization, projectCounts]) => {
this.organizationId = organization.id;
this.projectId = projectId;
this.organizationEnabled = organization.enabled;
+ this.projectCounts = {
+ secrets: projectCounts.secrets,
+ people: projectCounts.people,
+ serviceAccounts: projectCounts.serviceAccounts,
+ };
});
}
diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/people/service-account-people.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/people/service-account-people.component.ts
index 31394f7fec..4603368882 100644
--- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/people/service-account-people.component.ts
+++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/people/service-account-people.component.ts
@@ -8,6 +8,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
import { ValidationService } from "@bitwarden/common/platform/abstractions/validation.service";
import { DialogService } from "@bitwarden/components";
+import { ServiceAccountPeopleAccessPoliciesView } from "../../models/view/access-policies/service-account-people-access-policies.view";
import { AccessPolicySelectorService } from "../../shared/access-policies/access-policy-selector/access-policy-selector.service";
import {
ApItemValueType,
@@ -179,7 +180,7 @@ export class ServiceAccountPeopleComponent implements OnInit, OnDestroy {
private async updateServiceAccountPeopleAccessPolicies(
serviceAccountId: string,
selectedPolicies: ApItemValueType[],
- ) {
+ ): Promise {
const serviceAccountPeopleView = convertToPeopleAccessPoliciesView(selectedPolicies);
return await this.accessPolicyService.putServiceAccountPeopleAccessPolicies(
serviceAccountId,
diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-account.component.html b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-account.component.html
index 00b5201a65..c9ce8d8c64 100644
--- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-account.component.html
+++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-account.component.html
@@ -10,9 +10,24 @@
- {{ "projects" | i18n }}
- {{ "people" | i18n }}
- {{ "accessTokens" | i18n }}
+
+ {{ "projects" | i18n }}
+
+ {{ serviceAccountCounts?.projects }}
+
+
+
+ {{ "people" | i18n }}
+
+ {{ serviceAccountCounts?.people }}
+
+
+
+ {{ "accessTokens" | i18n }}
+
+ {{ serviceAccountCounts?.accessTokens }}
+
+
{{ "eventLogs" | i18n }}