1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-31 00:33:33 +00:00

Remove bulk collection seeder and CipherHealthTest

- Remove bulk-collection-seeder component and its files
- Remove bulk-collection-seeder from routing and module
- Remove CipherHealthTest from reports.ts and reports-home
- Remove cipherHealthTest locale strings
- Keep risk-insights-prototype for access intelligence work

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Tom
2026-01-16 16:17:56 -05:00
parent 656457204c
commit cbd1e64ed0
7 changed files with 0 additions and 254 deletions

View File

@@ -1,77 +0,0 @@
<bit-section>
<bit-section-header>
<h2 bitTypography="h2">Bulk Collection Seeder</h2>
<p bitTypography="body1" class="tw-text-muted">
Create multiple collections at once for testing purposes. Enter one collection name per line.
</p>
</bit-section-header>
<div class="tw-flex tw-flex-col tw-gap-4">
<bit-form-field>
<bit-label>Collection Names (one per line)</bit-label>
<textarea
bitInput
[(ngModel)]="collectionNames"
rows="10"
placeholder="Collection 1&#10;Collection 2&#10;Parent/Child Collection&#10;..."
[disabled]="isProcessing()"
></textarea>
<bit-hint
>Enter collection names, one per line. Use "/" for nested collections (e.g.,
"Parent/Child").</bit-hint
>
</bit-form-field>
<div class="tw-flex tw-gap-2">
<button
bitButton
buttonType="primary"
[disabled]="isProcessing() || !collectionNames.trim()"
(click)="createCollections()"
>
<span *ngIf="!isProcessing()">Create Collections</span>
<span *ngIf="isProcessing()">Creating...</span>
</button>
<button
bitButton
buttonType="secondary"
[disabled]="isProcessing() || !hasRun()"
(click)="clearResults()"
>
Clear Results
</button>
</div>
<div *ngIf="isProcessing() || hasRun()" class="tw-mt-4">
<bit-progress [barWidth]="progress()"></bit-progress>
<p bitTypography="body2" class="tw-mt-2 tw-text-muted">{{ progressMessage() }}</p>
</div>
<div *ngIf="hasRun() && !isProcessing()" class="tw-mt-4">
<h3 bitTypography="h3">Results</h3>
<p bitTypography="body1">
<span class="tw-text-success">{{ successCount }} succeeded</span>
<span *ngIf="failureCount > 0"
>, <span class="tw-text-danger">{{ failureCount }} failed</span></span
>
</p>
<div
*ngIf="results().length > 0"
class="tw-mt-2 tw-max-h-64 tw-overflow-y-auto tw-border tw-border-secondary-300 tw-rounded tw-p-2"
>
<div
*ngFor="let result of results()"
class="tw-flex tw-items-center tw-gap-2 tw-py-1 tw-border-b tw-border-secondary-100 last:tw-border-b-0"
>
<span *ngIf="result.success" class="tw-text-success">&#10003;</span>
<span *ngIf="!result.success" class="tw-text-danger">&#10007;</span>
<span>{{ result.name }}</span>
<span *ngIf="!result.success" class="tw-text-danger tw-text-sm"
>- {{ result.error }}</span
>
</div>
</div>
</div>
</div>
</bit-section>

View File

@@ -1,149 +0,0 @@
import { CommonModule } from "@angular/common";
import {
Component,
ChangeDetectionStrategy,
DestroyRef,
inject,
OnInit,
signal,
} from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { FormsModule } from "@angular/forms";
import { ActivatedRoute } from "@angular/router";
import { firstValueFrom } from "rxjs";
import { CollectionAdminService, CollectionAdminView } from "@bitwarden/admin-console/common";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
import {
ButtonModule,
FormFieldModule,
ProgressModule,
SectionComponent,
SectionHeaderComponent,
TypographyModule,
} from "@bitwarden/components";
import { HeaderModule } from "@bitwarden/web-vault/app/layouts/header/header.module";
interface CollectionCreationResult {
name: string;
success: boolean;
error?: string;
id?: CollectionId;
}
@Component({
selector: "app-bulk-collection-seeder",
templateUrl: "./bulk-collection-seeder.component.html",
standalone: true,
imports: [
CommonModule,
FormsModule,
JslibModule,
HeaderModule,
ButtonModule,
FormFieldModule,
ProgressModule,
SectionComponent,
SectionHeaderComponent,
TypographyModule,
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BulkCollectionSeederComponent implements OnInit {
private destroyRef = inject(DestroyRef);
private route = inject(ActivatedRoute);
private collectionAdminService = inject(CollectionAdminService);
private accountService = inject(AccountService);
protected organizationId: OrganizationId | null = null;
protected collectionNames = "";
protected readonly isProcessing = signal(false);
protected readonly progress = signal(0);
protected readonly progressMessage = signal("");
protected readonly results = signal<CollectionCreationResult[]>([]);
protected readonly hasRun = signal(false);
ngOnInit(): void {
this.route.params.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((params) => {
this.organizationId = params["organizationId"] as OrganizationId;
});
}
protected async createCollections(): Promise<void> {
if (!this.organizationId || !this.collectionNames.trim()) {
return;
}
const names = this.collectionNames
.split("\n")
.map((name) => name.trim())
.filter((name) => name.length > 0);
if (names.length === 0) {
return;
}
this.isProcessing.set(true);
this.progress.set(0);
this.results.set([]);
this.hasRun.set(true);
const results: CollectionCreationResult[] = [];
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
for (let i = 0; i < names.length; i++) {
const name = names[i];
this.progressMessage.set(`Creating collection ${i + 1} of ${names.length}: ${name}`);
this.progress.set(Math.round(((i + 1) / names.length) * 100));
try {
const collectionView = new CollectionAdminView({
id: null as unknown as CollectionId,
organizationId: this.organizationId,
name: name,
});
collectionView.groups = [];
collectionView.users = [];
const response = await this.collectionAdminService.create(collectionView, userId);
results.push({
name,
success: true,
id: response.id,
});
} catch (error) {
results.push({
name,
success: false,
error: error instanceof Error ? error.message : String(error),
});
}
this.results.set([...results]);
}
this.progressMessage.set(
`Completed: ${results.filter((r) => r.success).length} of ${names.length} collections created`,
);
this.isProcessing.set(false);
}
protected get successCount(): number {
return this.results().filter((r) => r.success).length;
}
protected get failureCount(): number {
return this.results().filter((r) => !r.success).length;
}
protected clearResults(): void {
this.results.set([]);
this.hasRun.set(false);
this.progress.set(0);
this.progressMessage.set("");
}
}

View File

@@ -21,7 +21,6 @@ import { organizationPermissionsGuard } from "../guards/org-permissions.guard";
import { organizationRedirectGuard } from "../guards/org-redirect.guard";
import { EventsComponent } from "../manage/events.component";
import { BulkCollectionSeederComponent } from "./bulk-collection-seeder/bulk-collection-seeder.component";
import { ReportsHomeComponent } from "./reports-home.component";
import { RiskInsightsPrototypeComponent } from "./risk-insights-prototype/risk-insights-prototype.component";
@@ -92,14 +91,6 @@ const routes: Routes = [
},
canActivate: [isPaidOrgGuard()],
},
{
path: "bulk-collection-seeder",
component: BulkCollectionSeederComponent,
data: {
titleId: "bulkCollectionSeeder",
},
canActivate: [isPaidOrgGuard()],
},
],
},
{

View File

@@ -4,7 +4,6 @@ import { ReportsSharedModule } from "../../../dirt/reports";
import { HeaderModule } from "../../../layouts/header/header.module";
import { SharedModule } from "../../../shared/shared.module";
import { BulkCollectionSeederComponent } from "./bulk-collection-seeder/bulk-collection-seeder.component";
import { OrganizationReportingRoutingModule } from "./organization-reporting-routing.module";
import { ReportsHomeComponent } from "./reports-home.component";
import { RiskInsightsPrototypeComponent } from "./risk-insights-prototype/risk-insights-prototype.component";
@@ -16,7 +15,6 @@ import { RiskInsightsPrototypeComponent } from "./risk-insights-prototype/risk-i
OrganizationReportingRoutingModule,
HeaderModule,
RiskInsightsPrototypeComponent,
BulkCollectionSeederComponent,
],
declarations: [ReportsHomeComponent],
})

View File

@@ -83,10 +83,6 @@ export class ReportsHomeComponent implements OnInit {
? ReportVariant.Enabled
: ReportVariant.RequiresEnterprise,
},
{
...reports[ReportType.CipherHealthTest],
variant: reportRequiresUpgrade,
},
{
...reports[ReportType.RiskInsightsPrototype],
variant: reportRequiresUpgrade,

View File

@@ -20,7 +20,6 @@ export enum ReportType {
Inactive2fa = "inactive2fa",
DataBreach = "dataBreach",
MemberAccessReport = "memberAccessReport",
CipherHealthTest = "cipherHealthTest",
RiskInsightsPrototype = "riskInsightsPrototype",
}
@@ -69,12 +68,6 @@ export const reports: Record<ReportType, ReportWithoutVariant> = {
route: "member-access-report",
icon: UserLockIcon,
},
[ReportType.CipherHealthTest]: {
title: "cipherHealthTest",
description: "cipherHealthTestDesc",
route: "cipher-health-test",
icon: UnlockedIcon,
},
[ReportType.RiskInsightsPrototype]: {
title: "riskInsightsPrototype",
description: "riskInsightsPrototypeDesc",

View File

@@ -10739,12 +10739,6 @@
"memberAccessReportAuthenticationEnabledFalse": {
"message": "Off"
},
"cipherHealthTest": {
"message": "Risk insights diagnostics"
},
"cipherHealthTestDesc": {
"message": "Test password health and member access mapping in parallel. View detailed performance diagnostics and analyze cipher security risks."
},
"riskInsightsPrototype": {
"message": "Risk Insights Prototype"
},