Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-10439] Vault generator components #11350

Merged
merged 15 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<bit-dialog dialogSize="default">
<bit-dialog dialogSize="default" background="alt">
<span bitDialogTitle>
{{ title }}
</span>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import { DIALOG_DATA, DialogRef } from "@angular/cdk/dialog";
import { DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { NoopAnimationsModule } from "@angular/platform-browser/animations";
import { mock, MockProxy } from "jest-mock-extended";
import { BehaviorSubject } from "rxjs";

import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import {
PasswordGenerationServiceAbstraction,
UsernameGenerationServiceAbstraction,
} from "@bitwarden/generator-legacy";
import { CipherFormGeneratorComponent } from "@bitwarden/vault";

import {
Expand All @@ -18,32 +14,26 @@ import {
WebVaultGeneratorDialogParams,
} from "./web-generator-dialog.component";

@Component({
selector: "vault-cipher-form-generator",
template: "",
standalone: true,
})
class MockCipherFormGenerator {
@Input() type: "password" | "username";
@Output() valueGenerated = new EventEmitter<string>();
}

describe("WebVaultGeneratorDialogComponent", () => {
let component: WebVaultGeneratorDialogComponent;
let fixture: ComponentFixture<WebVaultGeneratorDialogComponent>;

let dialogRef: MockProxy<DialogRef<any>>;
let mockI18nService: MockProxy<I18nService>;
let passwordOptionsSubject: BehaviorSubject<any>;
let usernameOptionsSubject: BehaviorSubject<any>;
let mockPasswordGenerationService: MockProxy<PasswordGenerationServiceAbstraction>;
let mockUsernameGenerationService: MockProxy<UsernameGenerationServiceAbstraction>;

beforeEach(async () => {
dialogRef = mock<DialogRef<any>>();
mockI18nService = mock<I18nService>();
passwordOptionsSubject = new BehaviorSubject([{ type: "password" }]);
usernameOptionsSubject = new BehaviorSubject([{ type: "username" }]);

mockPasswordGenerationService = mock<PasswordGenerationServiceAbstraction>();
mockPasswordGenerationService.getOptions$.mockReturnValue(
passwordOptionsSubject.asObservable(),
);

mockUsernameGenerationService = mock<UsernameGenerationServiceAbstraction>();
mockUsernameGenerationService.getOptions$.mockReturnValue(
usernameOptionsSubject.asObservable(),
);

const mockDialogData: WebVaultGeneratorDialogParams = { type: "password" };

Expand All @@ -66,23 +56,13 @@ describe("WebVaultGeneratorDialogComponent", () => {
provide: PlatformUtilsService,
useValue: mock<PlatformUtilsService>(),
},
{
provide: PasswordGenerationServiceAbstraction,
useValue: mockPasswordGenerationService,
},
{
provide: UsernameGenerationServiceAbstraction,
useValue: mockUsernameGenerationService,
},
{
provide: CipherFormGeneratorComponent,
useValue: {
passwordOptions$: passwordOptionsSubject.asObservable(),
usernameOptions$: usernameOptionsSubject.asObservable(),
},
},
],
}).compileComponents();
})
.overrideComponent(WebVaultGeneratorDialogComponent, {
remove: { imports: [CipherFormGeneratorComponent] },
add: { imports: [MockCipherFormGenerator] },
})
.compileComponents();

fixture = TestBed.createComponent(WebVaultGeneratorDialogComponent);
component = fixture.componentInstance;
Expand Down
36 changes: 36 additions & 0 deletions apps/web/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -9266,6 +9266,42 @@
"editAccess": {
"message": "Edit access"
},
"uppercaseDescription": {
"message": "Include uppercase characters",
"description": "Tooltip for the password generator uppercase character checkbox"
},
"uppercaseLabel": {
"message": "A-Z",
"description": "Label for the password generator uppercase character checkbox"
},
"lowercaseDescription": {
"message": "Include lowercase characters",
"description": "Full description for the password generator lowercase character checkbox"
},
"lowercaseLabel": {
"message": "a-z",
"description": "Label for the password generator lowercase character checkbox"
},
"numbersDescription": {
"message": "Include numbers",
"description": "Full description for the password generator numbers checkbox"
},
"numbersLabel": {
"message": "0-9",
"description": "Label for the password generator numbers checkbox"
},
"specialCharactersDescription": {
"message": "Include special characters",
"description": "Full description for the password generator special characters checkbox"
},
"specialCharactersLabel": {
"message": "!@#$%^&*",
"description": "Label for the password generator special characters checkbox"
},
"avoidAmbiguous": {
"message": "Avoid ambiguous characters",
"description": "Label for the avoid ambiguous characters checkbox."
},
"addAttachment": {
"message": "Add attachment"
},
Expand Down
2 changes: 0 additions & 2 deletions libs/tools/generator/components/src/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { ReactiveFormsModule } from "@angular/forms";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { safeProvider } from "@bitwarden/angular/platform/utils/safe-provider";
import { SafeInjectionToken } from "@bitwarden/angular/services/injection-tokens";
import { JslibServicesModule } from "@bitwarden/angular/services/jslib-services.module";
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { CryptoService } from "@bitwarden/common/platform/abstractions/crypto.service";
import { StateProvider } from "@bitwarden/common/platform/state";
Expand Down Expand Up @@ -43,7 +42,6 @@ const RANDOMIZER = new SafeInjectionToken<Randomizer>("Randomizer");
InputModule,
ItemModule,
JslibModule,
JslibServicesModule,
audreyality marked this conversation as resolved.
Show resolved Hide resolved
ReactiveFormsModule,
SectionComponent,
SectionHeaderComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,62 +1,8 @@
<bit-section>
<!-- Password/Passphrase Toggle -->
<bit-toggle-group
*ngIf="isPassword"
class="tw-w-full tw-justify-center tw-mt-3 tw-mb-5"
(selectedChange)="updatePasswordType($event)"
[selected]="passwordType$ | async"
>
<bit-toggle [value]="'password'">
{{ "password" | i18n }}
</bit-toggle>
<bit-toggle [value]="'passphrase'">
{{ "passphrase" | i18n }}
</bit-toggle>
</bit-toggle-group>

<!-- Generated Password/Passphrase/Username -->
<bit-item>
<bit-item-content>
<bit-color-password [password]="generatedValue"></bit-color-password>
</bit-item-content>
<ng-container slot="end">
<bit-item-action>
<button
type="button"
bitIconButton="bwi-clone"
size="small"
[appCopyClick]="generatedValue"
showToast
[appA11yTitle]="'copyValue' | i18n"
data-testid="copy-value-button"
></button>
</bit-item-action>
<bit-item-action>
<button
type="button"
bitIconButton="bwi-generate"
size="small"
(click)="regenerate$.next()"
[appA11yTitle]="regenerateButtonTitle"
data-testid="regenerate-button"
></button>
</bit-item-action>
</ng-container>
</bit-item>
</bit-section>

<!-- Generator Options -->
<!-- TODO: Replace with Generator Options Component(s) when available
It is expected that the generator options component(s) will internally update the options stored in state
which will trigger regeneration automatically in this dialog.
-->
<bit-section>
<bit-section-header>
<h2 bitTypography="h5">{{ "options" | i18n }}</h2>
</bit-section-header>
<bit-card>
<em bitTypography="body2"
>Placeholder: Replace with Generator Options Component(s) when available</em
>
</bit-card>
</bit-section>
<tools-password-generator
*ngIf="type === 'password'"
(onGenerated)="onCredentialGenerated($event)"
></tools-password-generator>
<tools-username-generator
*ngIf="type === 'username'"
(onGenerated)="onCredentialGenerated($event)"
></tools-username-generator>
Loading
Loading