1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 17:53:39 +00:00

[BEEEP] [PM-28239] Migrate generators to standalone (#17386)

* Migrate generators to use standalone and control flow

* Resolve feedback

* Add variable for account

* Fix generators
This commit is contained in:
Oscar Hinton
2025-12-11 12:04:15 +01:00
committed by GitHub
parent 7183d77f7b
commit 267e488390
24 changed files with 481 additions and 288 deletions

View File

@@ -136,6 +136,7 @@ import {
DialogService,
ToastService,
} from "@bitwarden/components";
import { GeneratorServicesModule } from "@bitwarden/generator-components";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import {
BiometricsService,
@@ -743,7 +744,7 @@ const safeProviders: SafeProvider[] = [
];
@NgModule({
imports: [JslibServicesModule],
imports: [JslibServicesModule, GeneratorServicesModule],
declarations: [],
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function
providers: safeProviders,

View File

@@ -102,6 +102,7 @@ import { GlobalStateProvider, StateProvider } from "@bitwarden/common/platform/s
import { SyncService } from "@bitwarden/common/platform/sync";
import { CipherService as CipherServiceAbstraction } from "@bitwarden/common/vault/abstractions/cipher.service";
import { DialogService, ToastService } from "@bitwarden/components";
import { GeneratorServicesModule } from "@bitwarden/generator-components";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import {
KdfConfigService,
@@ -499,7 +500,7 @@ const safeProviders: SafeProvider[] = [
];
@NgModule({
imports: [JslibServicesModule],
imports: [JslibServicesModule, GeneratorServicesModule],
declarations: [],
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function
providers: safeProviders,

View File

@@ -112,6 +112,7 @@ import {
} from "@bitwarden/common/platform/theming/theme-state.service";
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
import { DialogService, ToastService } from "@bitwarden/components";
import { GeneratorServicesModule } from "@bitwarden/generator-components";
import { PasswordGenerationServiceAbstraction } from "@bitwarden/generator-legacy";
import {
KdfConfigService,
@@ -484,7 +485,7 @@ const safeProviders: SafeProvider[] = [
@NgModule({
declarations: [],
imports: [CommonModule, JslibServicesModule],
imports: [CommonModule, JslibServicesModule, GeneratorServicesModule],
// Do not register your dependency here! Add it to the typesafeProviders array using the helper function
providers: safeProviders,
})

View File

@@ -8,15 +8,18 @@ import {
Output,
SimpleChanges,
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
import { map, ReplaySubject, skip, Subject, takeUntil, withLatestFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
import { FormFieldModule } from "@bitwarden/components";
import {
CatchallGenerationOptions,
CredentialGeneratorService,
BuiltIn,
} from "@bitwarden/generator-core";
import { I18nPipe } from "@bitwarden/ui-common";
/** Options group for catchall emails */
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
@@ -24,7 +27,7 @@ import {
@Component({
selector: "tools-catchall-settings",
templateUrl: "catchall-settings.component.html",
standalone: false,
imports: [ReactiveFormsModule, FormFieldModule, JslibModule, I18nPipe],
})
export class CatchallSettingsComponent implements OnInit, OnDestroy, OnChanges {
/** Instantiates the component

View File

@@ -1,8 +1,11 @@
<bit-dialog #dialog background="alt">
<span bitDialogTitle>{{ "generatorHistory" | i18n }}</span>
<ng-container bitDialogContent>
<bit-empty-credential-history *ngIf="!(hasHistory$ | async)" style="display: contents" />
<bit-credential-generator-history [account]="account$ | async" *ngIf="hasHistory$ | async" />
@if (hasHistory$ | async) {
<bit-credential-generator-history [account]="account$ | async" />
} @else {
<bit-empty-credential-history style="display: contents" />
}
</ng-container>
<ng-container bitDialogFooter>
<button

View File

@@ -1,4 +1,5 @@
<bit-item *ngFor="let credential of credentials$ | async">
@for (credential of credentials$ | async; track credential) {
<bit-item>
<bit-item-content>
<bit-color-password class="tw-font-mono" [password]="credential.credential" />
<div slot="secondary">
@@ -19,4 +20,5 @@
</button>
</bit-item-action>
</ng-container>
</bit-item>
</bit-item>
}

View File

@@ -23,7 +23,6 @@ import {
import { AlgorithmsByType, CredentialGeneratorService } from "@bitwarden/generator-core";
import { GeneratedCredential, GeneratorHistoryService } from "@bitwarden/generator-history";
import { GeneratorModule } from "./generator.module";
import { translate } from "./util";
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
@@ -32,13 +31,12 @@ import { translate } from "./util";
selector: "bit-credential-generator-history",
templateUrl: "credential-generator-history.component.html",
imports: [
ColorPasswordModule,
CommonModule,
ColorPasswordModule,
IconButtonModule,
NoItemsModule,
JslibModule,
ItemModule,
GeneratorModule,
],
})
export class CredentialGeneratorHistoryComponent implements OnChanges, OnInit, OnDestroy {

View File

@@ -6,9 +6,11 @@
(selectedChange)="onRootChanged({ nav: $event })"
attr.aria-label="{{ 'type' | i18n }}"
>
<bit-toggle *ngFor="let option of rootOptions$ | async" [value]="option.value">
@for (option of rootOptions$ | async; track option) {
<bit-toggle [value]="option.value">
{{ option.label }}
</bit-toggle>
}
</bit-toggle-group>
<nudge-generator-spotlight></nudge-generator-spotlight>
@@ -40,19 +42,26 @@
></button>
</div>
</bit-card>
<tools-password-settings
@let showAlgorithm = showAlgorithm$ | async;
@let account = account$ | async;
@switch (showAlgorithm?.id) {
@case (Algorithm.password) {
<tools-password-settings
class="tw-mt-6"
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.password"
[account]="account$ | async"
[account]="account"
(onUpdated)="generate('password settings')"
/>
<tools-passphrase-settings
/>
}
@case (Algorithm.passphrase) {
<tools-passphrase-settings
class="tw-mt-6"
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.passphrase"
[account]="account$ | async"
[account]="account"
(onUpdated)="generate('passphrase settings')"
/>
<bit-section *ngIf="(category$ | async) !== 'password'">
/>
}
}
@if ((category$ | async) !== "password") {
<bit-section>
<bit-section-header>
<h2 bitTypography="h6">{{ "options" | i18n }}</h2>
</bit-section-header>
@@ -67,12 +76,13 @@
data-testid="username-type"
>
</bit-select>
<bit-hint *ngIf="!!(credentialTypeHint$ | async)">{{
credentialTypeHint$ | async
}}</bit-hint>
@if (credentialTypeHint$ | async) {
<bit-hint>{{ credentialTypeHint$ | async }}</bit-hint>
}
</bit-form-field>
</form>
<form *ngIf="showForwarder$ | async" [formGroup]="forwarder" class="tw-container">
@if (showForwarder$ | async) {
<form [formGroup]="forwarder" class="tw-container">
<bit-form-field>
<bit-label>{{ "service" | i18n }}</bit-label>
<bit-select
@@ -83,26 +93,29 @@
</bit-select>
</bit-form-field>
</form>
}
@if (showAlgorithm?.id === Algorithm.catchall) {
<tools-catchall-settings
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.catchall"
[account]="account$ | async"
[account]="account"
(onUpdated)="generate('catchall settings')"
/>
<tools-forwarder-settings
*ngIf="!!(forwarderId$ | async)"
[account]="account$ | async"
[forwarder]="forwarderId$ | async"
/>
}
@if (forwarderId$ | async; as forwarderId) {
<tools-forwarder-settings [account]="account" [forwarder]="forwarderId" />
}
@if (showAlgorithm?.id === Algorithm.plusAddress) {
<tools-subaddress-settings
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.plusAddress"
[account]="account$ | async"
[account]="account"
(onUpdated)="generate('subaddress settings')"
/>
}
@if (showAlgorithm?.id === Algorithm.username) {
<tools-username-settings
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.username"
[account]="account$ | async"
[account]="account"
(onUpdated)="generate('username settings')"
/>
}
</bit-card>
</div>
</bit-section>
</bit-section>
}

View File

@@ -1,4 +1,5 @@
import { LiveAnnouncer } from "@angular/cdk/a11y";
import { AsyncPipe } from "@angular/common";
import {
Component,
EventEmitter,
@@ -10,7 +11,7 @@ import {
Output,
SimpleChanges,
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
import {
BehaviorSubject,
catchError,
@@ -27,6 +28,7 @@ import {
withLatestFrom,
} from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -37,7 +39,23 @@ import {
ifEnabledSemanticLoggerProvider,
} from "@bitwarden/common/tools/log";
import { UserId } from "@bitwarden/common/types/guid";
import { ToastService, Option } from "@bitwarden/components";
import {
ToastService,
Option,
BaseCardDirective,
CardComponent,
ColorPasswordComponent,
AriaDisableDirective,
TooltipDirective,
BitIconButtonComponent,
CopyClickDirective,
SectionComponent,
SectionHeaderComponent,
ToggleGroupModule,
TypographyModule,
FormFieldModule,
SelectModule,
} from "@bitwarden/components";
import {
CredentialType,
CredentialGeneratorService,
@@ -55,7 +73,15 @@ import {
Type,
} from "@bitwarden/generator-core";
import { GeneratorHistoryService } from "@bitwarden/generator-history";
import { I18nPipe } from "@bitwarden/ui-common";
import { CatchallSettingsComponent } from "./catchall-settings.component";
import { ForwarderSettingsComponent } from "./forwarder-settings.component";
import { NudgeGeneratorSpotlightComponent } from "./nudge-generator-spotlight.component";
import { PassphraseSettingsComponent } from "./passphrase-settings.component";
import { PasswordSettingsComponent } from "./password-settings.component";
import { SubaddressSettingsComponent } from "./subaddress-settings.component";
import { UsernameSettingsComponent } from "./username-settings.component";
import { translate } from "./util";
// constants used to identify navigation selections that are not
@@ -69,7 +95,32 @@ const NONE_SELECTED = "none";
@Component({
selector: "tools-credential-generator",
templateUrl: "credential-generator.component.html",
standalone: false,
imports: [
ToggleGroupModule,
NudgeGeneratorSpotlightComponent,
BaseCardDirective,
CardComponent,
ColorPasswordComponent,
AriaDisableDirective,
TooltipDirective,
BitIconButtonComponent,
CopyClickDirective,
PasswordSettingsComponent,
PassphraseSettingsComponent,
SectionComponent,
SectionHeaderComponent,
TypographyModule,
ReactiveFormsModule,
FormFieldModule,
SelectModule,
CatchallSettingsComponent,
ForwarderSettingsComponent,
SubaddressSettingsComponent,
UsernameSettingsComponent,
AsyncPipe,
JslibModule,
I18nPipe,
],
})
export class CredentialGeneratorComponent implements OnInit, OnChanges, OnDestroy {
private readonly destroyed = new Subject<void>();

View File

@@ -1,5 +1,6 @@
<form [formGroup]="settings" class="tw-container">
<bit-form-field *ngIf="displayDomain">
@if (displayDomain) {
<bit-form-field>
<bit-label>{{ "forwarderDomainName" | i18n }}</bit-label>
<input
bitInput
@@ -10,7 +11,9 @@
/>
<bit-hint>{{ "forwarderDomainNameHint" | i18n }}</bit-hint>
</bit-form-field>
<bit-form-field *ngIf="displayToken">
}
@if (displayToken) {
<bit-form-field>
<bit-label>{{ "apiKey" | i18n }}</bit-label>
<input bitInput formControlName="token" type="password" (change)="save('password')" />
<button
@@ -21,8 +24,11 @@
(change)="save('token')"
></button>
</bit-form-field>
<bit-form-field *ngIf="displayBaseUrl" disableMargin>
}
@if (displayBaseUrl) {
<bit-form-field disableMargin>
<bit-label>{{ "selfHostBaseUrl" | i18n }}</bit-label>
<input bitInput formControlName="baseUrl" type="text" (change)="save('baseUrl')" />
</bit-form-field>
}
</form>

View File

@@ -8,16 +8,24 @@ import {
Output,
SimpleChanges,
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
import { map, ReplaySubject, skip, Subject, switchAll, takeUntil, withLatestFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
import { VendorId } from "@bitwarden/common/tools/extension";
import {
FormFieldModule,
AriaDisableDirective,
TooltipDirective,
BitIconButtonComponent,
} from "@bitwarden/components";
import {
CredentialGeneratorService,
ForwarderOptions,
GeneratorMetadata,
} from "@bitwarden/generator-core";
import { I18nPipe } from "@bitwarden/ui-common";
const Controls = Object.freeze({
domain: "domain",
@@ -31,7 +39,15 @@ const Controls = Object.freeze({
@Component({
selector: "tools-forwarder-settings",
templateUrl: "forwarder-settings.component.html",
standalone: false,
imports: [
ReactiveFormsModule,
FormFieldModule,
AriaDisableDirective,
TooltipDirective,
BitIconButtonComponent,
JslibModule,
I18nPipe,
],
})
export class ForwarderSettingsComponent implements OnInit, OnChanges, OnDestroy {
/** Instantiates the component

View File

@@ -1,67 +1,13 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { ReactiveFormsModule } from "@angular/forms";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import {
CardComponent,
ColorPasswordModule,
CheckboxModule,
FormFieldModule,
IconButtonModule,
InputModule,
ItemModule,
SectionComponent,
SectionHeaderComponent,
SelectModule,
ToggleGroupModule,
TypographyModule,
} from "@bitwarden/components";
import { CatchallSettingsComponent } from "./catchall-settings.component";
import { CredentialGeneratorComponent } from "./credential-generator.component";
import { ForwarderSettingsComponent } from "./forwarder-settings.component";
import { GeneratorServicesModule } from "./generator-services.module";
import { NudgeGeneratorSpotlightComponent } from "./nudge-generator-spotlight.component";
import { PassphraseSettingsComponent } from "./passphrase-settings.component";
import { PasswordGeneratorComponent } from "./password-generator.component";
import { PasswordSettingsComponent } from "./password-settings.component";
import { SubaddressSettingsComponent } from "./subaddress-settings.component";
import { UsernameGeneratorComponent } from "./username-generator.component";
import { UsernameSettingsComponent } from "./username-settings.component";
/** Shared module containing generator component dependencies */
/** @deprecated Use individual components instead. */
@NgModule({
imports: [
CardComponent,
ColorPasswordModule,
CheckboxModule,
CommonModule,
FormFieldModule,
GeneratorServicesModule,
IconButtonModule,
InputModule,
ItemModule,
JslibModule,
ReactiveFormsModule,
SectionComponent,
SectionHeaderComponent,
SelectModule,
ToggleGroupModule,
TypographyModule,
NudgeGeneratorSpotlightComponent,
],
declarations: [
CatchallSettingsComponent,
CredentialGeneratorComponent,
ForwarderSettingsComponent,
SubaddressSettingsComponent,
PasswordGeneratorComponent,
PassphraseSettingsComponent,
PasswordSettingsComponent,
UsernameGeneratorComponent,
UsernameSettingsComponent,
],
imports: [CredentialGeneratorComponent, PasswordGeneratorComponent, UsernameGeneratorComponent],
exports: [CredentialGeneratorComponent, PasswordGeneratorComponent, UsernameGeneratorComponent],
})
export class GeneratorModule {

View File

@@ -1,5 +1,15 @@
/**
* This file contains the public interface for the generator components library.
*
* Be mindful of what you export here, as those components should be considered stable
* and part of the public API contract.
*/
export { CredentialGeneratorComponent } from "./credential-generator.component";
export { CredentialGeneratorHistoryComponent } from "./credential-generator-history.component";
export { CredentialGeneratorHistoryDialogComponent } from "./credential-generator-history-dialog.component";
export { EmptyCredentialHistoryComponent } from "./empty-credential-history.component";
export { GeneratorModule } from "./generator.module";
export { GeneratorServicesModule, SYSTEM_SERVICE_PROVIDER } from "./generator-services.module";
export { PasswordGeneratorComponent } from "./password-generator.component";
export { UsernameGeneratorComponent } from "./username-generator.component";

View File

@@ -1,4 +1,5 @@
<div class="tw-mb-4" *ngIf="showGeneratorSpotlight$ | async">
@if (showGeneratorSpotlight$ | async) {
<div class="tw-mb-4">
<bit-spotlight
[title]="'generatorNudgeTitle' | i18n"
(onDismiss)="dismissGeneratorSpotlight(NudgeType.GeneratorNudgeStatus)"
@@ -13,4 +14,5 @@
</span>
</p>
</bit-spotlight>
</div>
</div>
}

View File

@@ -1,7 +1,9 @@
<bit-section [disableMargin]="disableMargin">
<bit-section-header *ngIf="showHeader">
@if (showHeader) {
<bit-section-header>
<h6 bitTypography="h6">{{ "options" | i18n }}</h6>
</bit-section-header>
}
<form [formGroup]="settings" class="tw-container">
<div class="tw-mb-4">
<bit-card>
@@ -51,7 +53,9 @@
/>
<bit-label>{{ "includeNumber" | i18n }}</bit-label>
</bit-form-control>
<p *ngIf="policyInEffect" bitTypography="helper">{{ "generatorPolicyInEffect" | i18n }}</p>
@if (policyInEffect) {
<p bitTypography="helper">{{ "generatorPolicyInEffect" | i18n }}</p>
}
</bit-card>
</div>
</form>

View File

@@ -1,4 +1,5 @@
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { AsyncPipe } from "@angular/common";
import {
OnInit,
Input,
@@ -9,9 +10,10 @@ import {
SimpleChanges,
OnChanges,
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
import { skip, takeUntil, Subject, map, withLatestFrom, ReplaySubject, tap } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -20,11 +22,21 @@ import {
disabledSemanticLoggerProvider,
ifEnabledSemanticLoggerProvider,
} from "@bitwarden/common/tools/log";
import {
SectionComponent,
SectionHeaderComponent,
BaseCardDirective,
CardComponent,
TypographyModule,
FormFieldModule,
CheckboxModule,
} from "@bitwarden/components";
import {
CredentialGeneratorService,
PassphraseGenerationOptions,
BuiltIn,
} from "@bitwarden/generator-core";
import { I18nPipe } from "@bitwarden/ui-common";
const Controls = Object.freeze({
numWords: "numWords",
@@ -39,7 +51,19 @@ const Controls = Object.freeze({
@Component({
selector: "tools-passphrase-settings",
templateUrl: "passphrase-settings.component.html",
standalone: false,
imports: [
SectionComponent,
SectionHeaderComponent,
TypographyModule,
ReactiveFormsModule,
BaseCardDirective,
CardComponent,
FormFieldModule,
CheckboxModule,
AsyncPipe,
JslibModule,
I18nPipe,
],
})
export class PassphraseSettingsComponent implements OnInit, OnChanges, OnDestroy {
/** Instantiates the component

View File

@@ -1,15 +1,18 @@
<bit-toggle-group
@if (showCredentialTypes$ | async) {
<bit-toggle-group
fullWidth
class="tw-mb-4"
[selected]="credentialType$ | async"
(selectedChange)="onCredentialTypeChanged($event)"
*ngIf="showCredentialTypes$ | async"
attr.aria-label="{{ 'type' | i18n }}"
>
<bit-toggle *ngFor="let option of passwordOptions$ | async" [value]="option.value">
>
@for (option of passwordOptions$ | async; track option) {
<bit-toggle [value]="option.value">
{{ option.label }}
</bit-toggle>
</bit-toggle-group>
}
</bit-toggle-group>
}
<bit-card class="tw-flex tw-justify-between tw-mb-4">
<div class="tw-grow tw-flex tw-items-center tw-min-w-0">
<bit-color-password class="tw-font-mono" [password]="value$ | async"></bit-color-password>
@@ -37,17 +40,19 @@
></button>
</div>
</bit-card>
<tools-password-settings
@if ((algorithm$ | async)?.id === Algorithm.password) {
<tools-password-settings
class="tw-mt-6"
*ngIf="(algorithm$ | async)?.id === Algorithm.password"
[account]="account$ | async"
[disableMargin]="disableMargin"
(onUpdated)="generate('password settings')"
/>
<tools-passphrase-settings
/>
}
@if ((algorithm$ | async)?.id === Algorithm.passphrase) {
<tools-passphrase-settings
class="tw-mt-6"
*ngIf="(algorithm$ | async)?.id === Algorithm.passphrase"
[account]="account$ | async"
(onUpdated)="generate('passphrase settings')"
[disableMargin]="disableMargin"
/>
/>
}

View File

@@ -1,5 +1,6 @@
import { LiveAnnouncer } from "@angular/cdk/a11y";
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { AsyncPipe } from "@angular/common";
import {
Component,
EventEmitter,
@@ -24,6 +25,7 @@ import {
withLatestFrom,
} from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -33,7 +35,18 @@ import {
ifEnabledSemanticLoggerProvider,
} from "@bitwarden/common/tools/log";
import { UserId } from "@bitwarden/common/types/guid";
import { ToastService, Option } from "@bitwarden/components";
import {
ToastService,
Option,
BaseCardDirective,
CardComponent,
ColorPasswordComponent,
AriaDisableDirective,
TooltipDirective,
BitIconButtonComponent,
CopyClickDirective,
ToggleGroupModule,
} from "@bitwarden/components";
import {
CredentialGeneratorService,
GeneratedCredential,
@@ -49,7 +62,10 @@ import {
Profile,
} from "@bitwarden/generator-core";
import { GeneratorHistoryService } from "@bitwarden/generator-history";
import { I18nPipe } from "@bitwarden/ui-common";
import { PassphraseSettingsComponent } from "./passphrase-settings.component";
import { PasswordSettingsComponent } from "./password-settings.component";
import { toAlgorithmInfo, translate } from "./util";
/** Options group for passwords */
@@ -58,7 +74,21 @@ import { toAlgorithmInfo, translate } from "./util";
@Component({
selector: "tools-password-generator",
templateUrl: "password-generator.component.html",
standalone: false,
imports: [
ToggleGroupModule,
BaseCardDirective,
CardComponent,
ColorPasswordComponent,
AriaDisableDirective,
TooltipDirective,
BitIconButtonComponent,
CopyClickDirective,
PasswordSettingsComponent,
PassphraseSettingsComponent,
AsyncPipe,
JslibModule,
I18nPipe,
],
})
export class PasswordGeneratorComponent implements OnInit, OnChanges, OnDestroy {
constructor(

View File

@@ -1,7 +1,9 @@
<bit-section [disableMargin]="disableMargin">
<bit-section-header *ngIf="showHeader">
@if (showHeader) {
<bit-section-header>
<h2 bitTypography="h6">{{ "options" | i18n }}</h2>
</bit-section-header>
}
<form [formGroup]="settings" class="tw-container">
<div class="tw-mb-4">
<bit-card>
@@ -97,7 +99,9 @@
/>
<bit-label>{{ "avoidAmbiguous" | i18n }}</bit-label>
</bit-form-control>
<p *ngIf="policyInEffect" bitTypography="helper">{{ "generatorPolicyInEffect" | i18n }}</p>
@if (policyInEffect) {
<p bitTypography="helper">{{ "generatorPolicyInEffect" | i18n }}</p>
}
</bit-card>
</div>
</form>

View File

@@ -1,4 +1,5 @@
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { AsyncPipe } from "@angular/common";
import {
OnInit,
Input,
@@ -9,16 +10,27 @@ import {
SimpleChanges,
OnChanges,
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
import { takeUntil, Subject, map, filter, tap, skip, ReplaySubject, withLatestFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import {
SectionComponent,
SectionHeaderComponent,
BaseCardDirective,
CardComponent,
FormFieldModule,
TypographyModule,
CheckboxModule,
} from "@bitwarden/components";
import {
CredentialGeneratorService,
PasswordGenerationOptions,
BuiltIn,
} from "@bitwarden/generator-core";
import { I18nPipe } from "@bitwarden/ui-common";
import { hasRangeOfValues } from "./util";
@@ -39,7 +51,19 @@ const Controls = Object.freeze({
@Component({
selector: "tools-password-settings",
templateUrl: "password-settings.component.html",
standalone: false,
imports: [
SectionComponent,
SectionHeaderComponent,
TypographyModule,
ReactiveFormsModule,
BaseCardDirective,
CardComponent,
FormFieldModule,
CheckboxModule,
AsyncPipe,
JslibModule,
I18nPipe,
],
})
export class PasswordSettingsComponent implements OnInit, OnChanges, OnDestroy {
/** Instantiates the component

View File

@@ -8,15 +8,18 @@ import {
Output,
SimpleChanges,
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
import { map, ReplaySubject, skip, Subject, takeUntil, withLatestFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
import { FormFieldModule } from "@bitwarden/components";
import {
CredentialGeneratorService,
BuiltIn,
SubaddressGenerationOptions,
} from "@bitwarden/generator-core";
import { I18nPipe } from "@bitwarden/ui-common";
/** Options group for plus-addressed emails */
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
@@ -24,7 +27,7 @@ import {
@Component({
selector: "tools-subaddress-settings",
templateUrl: "subaddress-settings.component.html",
standalone: false,
imports: [ReactiveFormsModule, FormFieldModule, JslibModule, I18nPipe],
})
export class SubaddressSettingsComponent implements OnInit, OnChanges, OnDestroy {
/** Instantiates the component

View File

@@ -42,12 +42,13 @@
data-testid="username-type"
>
</bit-select>
<bit-hint *ngIf="!!(credentialTypeHint$ | async)">{{
credentialTypeHint$ | async
}}</bit-hint>
@if (credentialTypeHint$ | async) {
<bit-hint>{{ credentialTypeHint$ | async }}</bit-hint>
}
</bit-form-field>
</form>
<form *ngIf="showForwarder$ | async" [formGroup]="forwarder" class="tw-container">
@if (showForwarder$ | async) {
<form [formGroup]="forwarder" class="tw-container">
<bit-form-field>
<bit-label>{{ "service" | i18n }}</bit-label>
<bit-select
@@ -58,26 +59,24 @@
</bit-select>
</bit-form-field>
</form>
<tools-catchall-settings
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.catchall"
[account]="account$ | async"
(onUpdated)="generate('catchall settings')"
/>
<tools-forwarder-settings
*ngIf="!!(forwarderId$ | async)"
[forwarder]="forwarderId$ | async"
[account]="account$ | async"
/>
}
@let showAlgorithm = showAlgorithm$ | async;
@let account = account$ | async;
@if (showAlgorithm?.id === Algorithm.catchall) {
<tools-catchall-settings [account]="account" (onUpdated)="generate('catchall settings')" />
}
@if (forwarderId$ | async; as forwarderId) {
<tools-forwarder-settings [forwarder]="forwarderId" [account]="account" />
}
@if (showAlgorithm?.id === Algorithm.plusAddress) {
<tools-subaddress-settings
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.plusAddress"
[account]="account$ | async"
[account]="account"
(onUpdated)="generate('subaddress settings')"
/>
<tools-username-settings
*ngIf="(showAlgorithm$ | async)?.id === Algorithm.username"
[account]="account$ | async"
(onUpdated)="generate('username settings')"
/>
}
@if (showAlgorithm?.id === Algorithm.username) {
<tools-username-settings [account]="account" (onUpdated)="generate('username settings')" />
}
</bit-card>
</div>
</bit-section>

View File

@@ -1,5 +1,6 @@
import { LiveAnnouncer } from "@angular/cdk/a11y";
import { coerceBooleanProperty } from "@angular/cdk/coercion";
import { NgClass, AsyncPipe } from "@angular/common";
import {
Component,
EventEmitter,
@@ -11,7 +12,7 @@ import {
Output,
SimpleChanges,
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
import {
BehaviorSubject,
catchError,
@@ -28,6 +29,7 @@ import {
withLatestFrom,
} from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -38,7 +40,22 @@ import {
ifEnabledSemanticLoggerProvider,
} from "@bitwarden/common/tools/log";
import { UserId } from "@bitwarden/common/types/guid";
import { ToastService, Option } from "@bitwarden/components";
import {
ToastService,
Option,
AriaDisableDirective,
BaseCardDirective,
CardComponent,
ColorPasswordComponent,
CopyClickDirective,
BitIconButtonComponent,
TooltipDirective,
SectionComponent,
SectionHeaderComponent,
SelectComponent,
TypographyModule,
FormFieldModule,
} from "@bitwarden/components";
import {
AlgorithmInfo,
CredentialGeneratorService,
@@ -55,7 +72,12 @@ import {
Algorithm,
} from "@bitwarden/generator-core";
import { GeneratorHistoryService } from "@bitwarden/generator-history";
import { I18nPipe } from "@bitwarden/ui-common";
import { CatchallSettingsComponent } from "./catchall-settings.component";
import { ForwarderSettingsComponent } from "./forwarder-settings.component";
import { SubaddressSettingsComponent } from "./subaddress-settings.component";
import { UsernameSettingsComponent } from "./username-settings.component";
import { toAlgorithmInfo, translate } from "./util";
// constants used to identify navigation selections that are not
@@ -69,7 +91,29 @@ const NONE_SELECTED = "none";
@Component({
selector: "tools-username-generator",
templateUrl: "username-generator.component.html",
standalone: false,
imports: [
BaseCardDirective,
CardComponent,
ColorPasswordComponent,
AriaDisableDirective,
TooltipDirective,
BitIconButtonComponent,
CopyClickDirective,
SectionComponent,
SectionHeaderComponent,
TypographyModule,
NgClass,
ReactiveFormsModule,
SelectComponent,
FormFieldModule,
CatchallSettingsComponent,
ForwarderSettingsComponent,
SubaddressSettingsComponent,
UsernameSettingsComponent,
AsyncPipe,
JslibModule,
I18nPipe,
],
})
export class UsernameGeneratorComponent implements OnInit, OnChanges, OnDestroy {
/** Instantiates the username generator

View File

@@ -8,15 +8,18 @@ import {
Output,
SimpleChanges,
} from "@angular/core";
import { FormBuilder } from "@angular/forms";
import { FormBuilder, ReactiveFormsModule } from "@angular/forms";
import { map, ReplaySubject, skip, Subject, takeUntil, withLatestFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { Account } from "@bitwarden/common/auth/abstractions/account.service";
import { FormFieldModule, CheckboxModule } from "@bitwarden/components";
import {
CredentialGeneratorService,
EffUsernameGenerationOptions,
BuiltIn,
} from "@bitwarden/generator-core";
import { I18nPipe } from "@bitwarden/ui-common";
/** Options group for usernames */
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
@@ -24,7 +27,7 @@ import {
@Component({
selector: "tools-username-settings",
templateUrl: "username-settings.component.html",
standalone: false,
imports: [ReactiveFormsModule, FormFieldModule, CheckboxModule, JslibModule, I18nPipe],
})
export class UsernameSettingsComponent implements OnInit, OnChanges, OnDestroy {
/** Instantiates the component