mirror of
https://github.com/bitwarden/browser
synced 2026-02-22 04:14:04 +00:00
Merge branch 'main' into km/tde-offboarding-fix
This commit is contained in:
@@ -72,6 +72,10 @@ export class ManageTaxInformationComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
markAllAsTouched() {
|
||||
this.formGroup.markAllAsTouched();
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
if (this.startWith) {
|
||||
this.formGroup.controls.country.setValue(this.startWith.country);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Directive, ElementRef, Input, OnInit, Renderer2 } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
selector: "[appA11yTitle]",
|
||||
})
|
||||
export class A11yTitleDirective implements OnInit {
|
||||
@Input() set appA11yTitle(title: string) {
|
||||
this.title = title;
|
||||
this.setAttributes();
|
||||
}
|
||||
|
||||
private title: string;
|
||||
private originalTitle: string | null;
|
||||
private originalAriaLabel: string | null;
|
||||
|
||||
constructor(
|
||||
private el: ElementRef,
|
||||
private renderer: Renderer2,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.originalTitle = this.el.nativeElement.getAttribute("title");
|
||||
this.originalAriaLabel = this.el.nativeElement.getAttribute("aria-label");
|
||||
this.setAttributes();
|
||||
}
|
||||
|
||||
private setAttributes() {
|
||||
if (this.originalTitle === null) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, "title", this.title);
|
||||
}
|
||||
if (this.originalAriaLabel === null) {
|
||||
this.renderer.setAttribute(this.el.nativeElement, "aria-label", this.title);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
import { Component, ElementRef, ViewChild } from "@angular/core";
|
||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
|
||||
import { CopyClickDirective } from "./copy-click.directive";
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<button appCopyClick="no toast shown" #noToast></button>
|
||||
<button appCopyClick="info toast shown" showToast="info" #infoToast></button>
|
||||
<button appCopyClick="success toast shown" showToast #successToast></button>
|
||||
<button appCopyClick="toast with label" showToast valueLabel="Content" #toastWithLabel></button>
|
||||
`,
|
||||
})
|
||||
class TestCopyClickComponent {
|
||||
@ViewChild("noToast") noToastButton: ElementRef<HTMLButtonElement>;
|
||||
@ViewChild("infoToast") infoToastButton: ElementRef<HTMLButtonElement>;
|
||||
@ViewChild("successToast") successToastButton: ElementRef<HTMLButtonElement>;
|
||||
@ViewChild("toastWithLabel") toastWithLabelButton: ElementRef<HTMLButtonElement>;
|
||||
}
|
||||
|
||||
describe("CopyClickDirective", () => {
|
||||
let fixture: ComponentFixture<TestCopyClickComponent>;
|
||||
const copyToClipboard = jest.fn();
|
||||
const showToast = jest.fn();
|
||||
|
||||
beforeEach(async () => {
|
||||
copyToClipboard.mockClear();
|
||||
showToast.mockClear();
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [CopyClickDirective, TestCopyClickComponent],
|
||||
providers: [
|
||||
{
|
||||
provide: I18nService,
|
||||
useValue: {
|
||||
t: (key: string, ...rest: string[]) => {
|
||||
if (rest?.length) {
|
||||
return `${key} ${rest.join("")}`;
|
||||
}
|
||||
return key;
|
||||
},
|
||||
},
|
||||
},
|
||||
{ provide: PlatformUtilsService, useValue: { copyToClipboard } },
|
||||
{ provide: ToastService, useValue: { showToast } },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(TestCopyClickComponent);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it("copies the the value for all variants of toasts ", () => {
|
||||
const noToastButton = fixture.componentInstance.noToastButton.nativeElement;
|
||||
|
||||
noToastButton.click();
|
||||
expect(copyToClipboard).toHaveBeenCalledWith("no toast shown");
|
||||
|
||||
const infoToastButton = fixture.componentInstance.infoToastButton.nativeElement;
|
||||
|
||||
infoToastButton.click();
|
||||
expect(copyToClipboard).toHaveBeenCalledWith("info toast shown");
|
||||
|
||||
const successToastButton = fixture.componentInstance.successToastButton.nativeElement;
|
||||
|
||||
successToastButton.click();
|
||||
expect(copyToClipboard).toHaveBeenCalledWith("success toast shown");
|
||||
});
|
||||
|
||||
it("does not show a toast when showToast is not present", () => {
|
||||
const noToastButton = fixture.componentInstance.noToastButton.nativeElement;
|
||||
|
||||
noToastButton.click();
|
||||
expect(showToast).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows a success toast when showToast is present", () => {
|
||||
const successToastButton = fixture.componentInstance.successToastButton.nativeElement;
|
||||
|
||||
successToastButton.click();
|
||||
expect(showToast).toHaveBeenCalledWith({
|
||||
message: "copySuccessful",
|
||||
title: null,
|
||||
variant: "success",
|
||||
});
|
||||
});
|
||||
|
||||
it("shows the toast variant when set with showToast", () => {
|
||||
const infoToastButton = fixture.componentInstance.infoToastButton.nativeElement;
|
||||
|
||||
infoToastButton.click();
|
||||
expect(showToast).toHaveBeenCalledWith({
|
||||
message: "copySuccessful",
|
||||
title: null,
|
||||
variant: "info",
|
||||
});
|
||||
});
|
||||
|
||||
it('includes label in toast message when "copyLabel" is set', () => {
|
||||
const toastWithLabelButton = fixture.componentInstance.toastWithLabelButton.nativeElement;
|
||||
|
||||
toastWithLabelButton.click();
|
||||
|
||||
expect(showToast).toHaveBeenCalledWith({
|
||||
message: "valueCopied Content",
|
||||
title: null,
|
||||
variant: "success",
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,68 +0,0 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Directive, HostListener, Input } from "@angular/core";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { ToastService, ToastVariant } from "@bitwarden/components";
|
||||
|
||||
@Directive({
|
||||
selector: "[appCopyClick]",
|
||||
})
|
||||
export class CopyClickDirective {
|
||||
private _showToast = false;
|
||||
private toastVariant: ToastVariant = "success";
|
||||
|
||||
constructor(
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private toastService: ToastService,
|
||||
private i18nService: I18nService,
|
||||
) {}
|
||||
|
||||
@Input("appCopyClick") valueToCopy = "";
|
||||
|
||||
/**
|
||||
* When set, the toast displayed will show `<valueLabel> copied`
|
||||
* instead of the default messaging.
|
||||
*/
|
||||
@Input() valueLabel: string;
|
||||
|
||||
/**
|
||||
* When set without a value, a success toast will be shown when the value is copied
|
||||
* @example
|
||||
* ```html
|
||||
* <app-component [appCopyClick]="value to copy" showToast/></app-component>
|
||||
* ```
|
||||
* When set with a value, a toast with the specified variant will be shown when the value is copied
|
||||
*
|
||||
* @example
|
||||
* ```html
|
||||
* <app-component [appCopyClick]="value to copy" showToast="info"/></app-component>
|
||||
* ```
|
||||
*/
|
||||
@Input() set showToast(value: ToastVariant | "") {
|
||||
// When the `showToast` is set without a value, an empty string will be passed
|
||||
if (value === "") {
|
||||
this._showToast = true;
|
||||
} else {
|
||||
this._showToast = true;
|
||||
this.toastVariant = value;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener("click") onClick() {
|
||||
this.platformUtilsService.copyToClipboard(this.valueToCopy);
|
||||
|
||||
if (this._showToast) {
|
||||
const message = this.valueLabel
|
||||
? this.i18nService.t("valueCopied", this.valueLabel)
|
||||
: this.i18nService.t("copySuccessful");
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: this.toastVariant,
|
||||
title: null,
|
||||
message,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,15 +25,15 @@ import {
|
||||
TableModule,
|
||||
ToastModule,
|
||||
TypographyModule,
|
||||
CopyClickDirective,
|
||||
A11yTitleDirective,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { TwoFactorIconComponent } from "./auth/components/two-factor-icon.component";
|
||||
import { DeprecatedCalloutComponent } from "./components/callout.component";
|
||||
import { A11yInvalidDirective } from "./directives/a11y-invalid.directive";
|
||||
import { A11yTitleDirective } from "./directives/a11y-title.directive";
|
||||
import { ApiActionDirective } from "./directives/api-action.directive";
|
||||
import { BoxRowDirective } from "./directives/box-row.directive";
|
||||
import { CopyClickDirective } from "./directives/copy-click.directive";
|
||||
import { CopyTextDirective } from "./directives/copy-text.directive";
|
||||
import { FallbackSrcDirective } from "./directives/fallback-src.directive";
|
||||
import { IfFeatureDirective } from "./directives/if-feature.directive";
|
||||
@@ -83,10 +83,11 @@ import { IconComponent } from "./vault/components/icon.component";
|
||||
LinkModule,
|
||||
IconModule,
|
||||
TextDragDirective,
|
||||
CopyClickDirective,
|
||||
A11yTitleDirective,
|
||||
],
|
||||
declarations: [
|
||||
A11yInvalidDirective,
|
||||
A11yTitleDirective,
|
||||
ApiActionDirective,
|
||||
AutofocusDirective,
|
||||
BoxRowDirective,
|
||||
@@ -105,7 +106,6 @@ import { IconComponent } from "./vault/components/icon.component";
|
||||
StopClickDirective,
|
||||
StopPropDirective,
|
||||
TrueFalseValueDirective,
|
||||
CopyClickDirective,
|
||||
LaunchClickDirective,
|
||||
UserNamePipe,
|
||||
PasswordStrengthComponent,
|
||||
|
||||
@@ -2,6 +2,9 @@ import { Pipe, PipeTransform } from "@angular/core";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
|
||||
/**
|
||||
* @deprecated: Please use the I18nPipe from @bitwarden/ui-common
|
||||
*/
|
||||
@Pipe({
|
||||
name: "i18n",
|
||||
})
|
||||
|
||||
@@ -1,138 +1,4 @@
|
||||
import { Provider } from "@angular/core";
|
||||
import { Constructor, Opaque } from "type-fest";
|
||||
|
||||
import { SafeInjectionToken } from "../../services/injection-tokens";
|
||||
|
||||
/**
|
||||
* The return type of the {@link safeProvider} helper function.
|
||||
* Used to distinguish a type safe provider definition from a non-type safe provider definition.
|
||||
* @deprecated: Please use the SafeProvider & safeProvider from @bitwarden/ui-common
|
||||
*/
|
||||
export type SafeProvider = Opaque<Provider>;
|
||||
|
||||
// TODO: type-fest also provides a type like this when we upgrade >= 3.7.0
|
||||
type AbstractConstructor<T> = abstract new (...args: any) => T;
|
||||
|
||||
type MapParametersToDeps<T> = {
|
||||
[K in keyof T]: AbstractConstructor<T[K]> | SafeInjectionToken<T[K]>;
|
||||
};
|
||||
|
||||
type SafeInjectionTokenType<T> = T extends SafeInjectionToken<infer J> ? J : never;
|
||||
|
||||
/**
|
||||
* Gets the instance type from a constructor, abstract constructor, or SafeInjectionToken
|
||||
*/
|
||||
type ProviderInstanceType<T> =
|
||||
T extends SafeInjectionToken<any>
|
||||
? InstanceType<SafeInjectionTokenType<T>>
|
||||
: T extends Constructor<any> | AbstractConstructor<any>
|
||||
? InstanceType<T>
|
||||
: never;
|
||||
|
||||
/**
|
||||
* Represents a dependency provided with the useClass option.
|
||||
*/
|
||||
type SafeClassProvider<
|
||||
A extends AbstractConstructor<any> | SafeInjectionToken<any>,
|
||||
I extends Constructor<ProviderInstanceType<A>>,
|
||||
D extends MapParametersToDeps<ConstructorParameters<I>>,
|
||||
> = {
|
||||
provide: A;
|
||||
useClass: I;
|
||||
deps: D;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a dependency provided with the useValue option.
|
||||
*/
|
||||
type SafeValueProvider<A extends SafeInjectionToken<any>, V extends SafeInjectionTokenType<A>> = {
|
||||
provide: A;
|
||||
useValue: V;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a dependency provided with the useFactory option.
|
||||
*/
|
||||
type SafeFactoryProvider<
|
||||
A extends AbstractConstructor<any> | SafeInjectionToken<any>,
|
||||
I extends (...args: any) => ProviderInstanceType<A>,
|
||||
D extends MapParametersToDeps<Parameters<I>>,
|
||||
> = {
|
||||
provide: A;
|
||||
useFactory: I;
|
||||
deps: D;
|
||||
multi?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a dependency provided with the useExisting option.
|
||||
*/
|
||||
type SafeExistingProvider<
|
||||
A extends Constructor<any> | AbstractConstructor<any> | SafeInjectionToken<any>,
|
||||
I extends Constructor<ProviderInstanceType<A>> | AbstractConstructor<ProviderInstanceType<A>>,
|
||||
> = {
|
||||
provide: A;
|
||||
useExisting: I;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a dependency where there is no abstract token, the token is the implementation
|
||||
*/
|
||||
type SafeConcreteProvider<
|
||||
I extends Constructor<any>,
|
||||
D extends MapParametersToDeps<ConstructorParameters<I>>,
|
||||
> = {
|
||||
provide: I;
|
||||
deps: D;
|
||||
};
|
||||
|
||||
/**
|
||||
* If useAngularDecorators: true is specified, do not require a deps array.
|
||||
* This is a manual override for where @Injectable decorators are used
|
||||
*/
|
||||
type UseAngularDecorators<T extends { deps: any }> = Omit<T, "deps"> & {
|
||||
useAngularDecorators: true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a type with a deps array that may optionally be overridden with useAngularDecorators
|
||||
*/
|
||||
type AllowAngularDecorators<T extends { deps: any }> = T | UseAngularDecorators<T>;
|
||||
|
||||
/**
|
||||
* A factory function that creates a provider for the ngModule providers array.
|
||||
* This (almost) guarantees type safety for your provider definition. It does nothing at runtime.
|
||||
* Warning: the useAngularDecorators option provides an override where your class uses the Injectable decorator,
|
||||
* however this cannot be enforced by the type system and will not cause an error if the decorator is not used.
|
||||
* @example safeProvider({ provide: MyService, useClass: DefaultMyService, deps: [AnotherService] })
|
||||
* @param provider Your provider object in the usual shape (e.g. using useClass, useValue, useFactory, etc.)
|
||||
* @returns The exact same object without modification (pass-through).
|
||||
*/
|
||||
export const safeProvider = <
|
||||
// types for useClass
|
||||
AClass extends AbstractConstructor<any> | SafeInjectionToken<any>,
|
||||
IClass extends Constructor<ProviderInstanceType<AClass>>,
|
||||
DClass extends MapParametersToDeps<ConstructorParameters<IClass>>,
|
||||
// types for useValue
|
||||
AValue extends SafeInjectionToken<any>,
|
||||
VValue extends SafeInjectionTokenType<AValue>,
|
||||
// types for useFactory
|
||||
AFactory extends AbstractConstructor<any> | SafeInjectionToken<any>,
|
||||
IFactory extends (...args: any) => ProviderInstanceType<AFactory>,
|
||||
DFactory extends MapParametersToDeps<Parameters<IFactory>>,
|
||||
// types for useExisting
|
||||
AExisting extends Constructor<any> | AbstractConstructor<any> | SafeInjectionToken<any>,
|
||||
IExisting extends
|
||||
| Constructor<ProviderInstanceType<AExisting>>
|
||||
| AbstractConstructor<ProviderInstanceType<AExisting>>,
|
||||
// types for no token
|
||||
IConcrete extends Constructor<any>,
|
||||
DConcrete extends MapParametersToDeps<ConstructorParameters<IConcrete>>,
|
||||
>(
|
||||
provider:
|
||||
| AllowAngularDecorators<SafeClassProvider<AClass, IClass, DClass>>
|
||||
| SafeValueProvider<AValue, VValue>
|
||||
| AllowAngularDecorators<SafeFactoryProvider<AFactory, IFactory, DFactory>>
|
||||
| SafeExistingProvider<AExisting, IExisting>
|
||||
| AllowAngularDecorators<SafeConcreteProvider<IConcrete, DConcrete>>
|
||||
| Constructor<unknown>,
|
||||
): SafeProvider => provider as SafeProvider;
|
||||
export { SafeProvider, safeProvider } from "@bitwarden/ui-common";
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||
// This rule bans @ts-expect-error comments without explanation. In this file, we use it to test our types, and
|
||||
// explanation is provided in header comments before each test.
|
||||
|
||||
import { safeProvider } from "./safe-provider";
|
||||
|
||||
class FooFactory {
|
||||
create() {
|
||||
return "thing";
|
||||
}
|
||||
}
|
||||
|
||||
abstract class FooService {
|
||||
createFoo: (str: string) => string;
|
||||
}
|
||||
|
||||
class DefaultFooService implements FooService {
|
||||
constructor(private factory: FooFactory) {}
|
||||
|
||||
createFoo(str: string) {
|
||||
return str ?? this.factory.create();
|
||||
}
|
||||
}
|
||||
|
||||
class BarFactory {
|
||||
create() {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class BarService {
|
||||
createBar: (num: number) => number;
|
||||
}
|
||||
|
||||
class DefaultBarService implements BarService {
|
||||
constructor(private factory: BarFactory) {}
|
||||
|
||||
createBar(num: number) {
|
||||
return num ?? this.factory.create();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class FooBarService {}
|
||||
|
||||
class DefaultFooBarService {
|
||||
constructor(
|
||||
private fooFactory: FooFactory,
|
||||
private barFactory: BarFactory,
|
||||
) {}
|
||||
}
|
||||
|
||||
// useClass happy path with deps
|
||||
safeProvider({
|
||||
provide: FooService,
|
||||
useClass: DefaultFooService,
|
||||
deps: [FooFactory],
|
||||
});
|
||||
|
||||
// useClass happy path with useAngularDecorators
|
||||
safeProvider({
|
||||
provide: FooService,
|
||||
useClass: DefaultFooService,
|
||||
useAngularDecorators: true,
|
||||
});
|
||||
|
||||
// useClass: expect error if implementation does not match abstraction
|
||||
safeProvider({
|
||||
provide: FooService,
|
||||
// @ts-expect-error
|
||||
useClass: DefaultBarService,
|
||||
deps: [BarFactory],
|
||||
});
|
||||
|
||||
// useClass: expect error if deps type does not match
|
||||
safeProvider({
|
||||
provide: FooService,
|
||||
useClass: DefaultFooService,
|
||||
// @ts-expect-error
|
||||
deps: [BarFactory],
|
||||
});
|
||||
|
||||
// useClass: expect error if not enough deps specified
|
||||
safeProvider({
|
||||
provide: FooService,
|
||||
useClass: DefaultFooService,
|
||||
// @ts-expect-error
|
||||
deps: [],
|
||||
});
|
||||
|
||||
// useClass: expect error if too many deps specified
|
||||
safeProvider({
|
||||
provide: FooService,
|
||||
useClass: DefaultFooService,
|
||||
// @ts-expect-error
|
||||
deps: [FooFactory, BarFactory],
|
||||
});
|
||||
|
||||
// useClass: expect error if deps are in the wrong order
|
||||
safeProvider({
|
||||
provide: FooBarService,
|
||||
useClass: DefaultFooBarService,
|
||||
// @ts-expect-error
|
||||
deps: [BarFactory, FooFactory],
|
||||
});
|
||||
|
||||
// useClass: expect error if no deps specified and not using Angular decorators
|
||||
// @ts-expect-error
|
||||
safeProvider({
|
||||
provide: FooService,
|
||||
useClass: DefaultFooService,
|
||||
});
|
||||
@@ -1,6 +1,5 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { InjectionToken } from "@angular/core";
|
||||
import { Observable, Subject } from "rxjs";
|
||||
|
||||
import { LogoutReason } from "@bitwarden/auth/common";
|
||||
@@ -14,17 +13,9 @@ import { Theme } from "@bitwarden/common/platform/enums";
|
||||
import { StateFactory } from "@bitwarden/common/platform/factories/state-factory";
|
||||
import { Message } from "@bitwarden/common/platform/messaging";
|
||||
import { VaultTimeout } from "@bitwarden/common/types/vault-timeout.type";
|
||||
|
||||
declare const tag: unique symbol;
|
||||
/**
|
||||
* A (more) typesafe version of InjectionToken which will more strictly enforce the generic type parameter.
|
||||
* @remarks The default angular implementation does not use the generic type to define the structure of the object,
|
||||
* so the structural type system will not complain about a mismatch in the type parameter.
|
||||
* This is solved by assigning T to an arbitrary private property.
|
||||
*/
|
||||
export class SafeInjectionToken<T> extends InjectionToken<T> {
|
||||
private readonly [tag]: T;
|
||||
}
|
||||
import { SafeInjectionToken } from "@bitwarden/ui-common";
|
||||
// Re-export the SafeInjectionToken from ui-common
|
||||
export { SafeInjectionToken } from "@bitwarden/ui-common";
|
||||
|
||||
export const WINDOW = new SafeInjectionToken<Window>("WINDOW");
|
||||
export const OBSERVABLE_MEMORY_STORAGE = new SafeInjectionToken<
|
||||
|
||||
@@ -293,6 +293,7 @@ import {
|
||||
UserAsymmetricKeysRegenerationApiService,
|
||||
DefaultUserAsymmetricKeysRegenerationApiService,
|
||||
} from "@bitwarden/key-management";
|
||||
import { SafeInjectionToken } from "@bitwarden/ui-common";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
import {
|
||||
VaultExportService,
|
||||
@@ -323,7 +324,6 @@ import {
|
||||
MEMORY_STORAGE,
|
||||
OBSERVABLE_DISK_STORAGE,
|
||||
OBSERVABLE_MEMORY_STORAGE,
|
||||
SafeInjectionToken,
|
||||
SECURE_STORAGE,
|
||||
STATE_FACTORY,
|
||||
SUPPORTS_SECURE_STORAGE,
|
||||
|
||||
@@ -372,11 +372,11 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
if (this.cipher.name == null || this.cipher.name === "") {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("nameRequired"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("nameRequired"),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -385,11 +385,11 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
!this.allowPersonal &&
|
||||
this.cipher.organizationId == null
|
||||
) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("personalOwnershipSubmitError"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("personalOwnershipSubmitError"),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -424,11 +424,11 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
this.formPromise = this.saveCipher(cipher);
|
||||
await this.formPromise;
|
||||
this.cipher.id = cipher.id;
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t(this.editMode && !this.cloneMode ? "editedItem" : "addedItem"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t(this.editMode && !this.cloneMode ? "editedItem" : "addedItem"),
|
||||
});
|
||||
this.onSavedCipher.emit(this.cipher);
|
||||
this.messagingService.send(this.editMode && !this.cloneMode ? "editedCipher" : "addedCipher");
|
||||
return true;
|
||||
@@ -514,11 +514,13 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
try {
|
||||
this.deletePromise = this.deleteCipher();
|
||||
await this.deletePromise;
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t(this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t(
|
||||
this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem",
|
||||
),
|
||||
});
|
||||
this.onDeletedCipher.emit(this.cipher);
|
||||
this.messagingService.send(
|
||||
this.cipher.isDeleted ? "permanentlyDeletedCipher" : "deletedCipher",
|
||||
@@ -538,7 +540,11 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
try {
|
||||
this.restorePromise = this.restoreCipher();
|
||||
await this.restorePromise;
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItem"));
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("restoredItem"),
|
||||
});
|
||||
this.onRestoredCipher.emit(this.cipher);
|
||||
this.messagingService.send("restoredCipher");
|
||||
} catch (e) {
|
||||
@@ -679,13 +685,17 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
this.checkPasswordPromise = null;
|
||||
|
||||
if (matches > 0) {
|
||||
this.platformUtilsService.showToast(
|
||||
"warning",
|
||||
null,
|
||||
this.i18nService.t("passwordExposed", matches.toString()),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "warning",
|
||||
title: null,
|
||||
message: this.i18nService.t("passwordExposed", matches.toString()),
|
||||
});
|
||||
} else {
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("passwordSafe"));
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("passwordSafe"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -779,11 +789,11 @@ export class AddEditComponent implements OnInit, OnDestroy {
|
||||
|
||||
const copyOptions = this.win != null ? { window: this.win } : null;
|
||||
this.platformUtilsService.copyToClipboard(value, copyOptions);
|
||||
this.platformUtilsService.showToast(
|
||||
"info",
|
||||
null,
|
||||
this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "info",
|
||||
title: null,
|
||||
message: this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)),
|
||||
});
|
||||
|
||||
if (typeI18nKey === "password") {
|
||||
void this.eventCollectionService.collectMany(EventType.Cipher_ClientCopiedPassword, [
|
||||
|
||||
@@ -64,21 +64,21 @@ export class AttachmentsComponent implements OnInit {
|
||||
const fileEl = document.getElementById("file") as HTMLInputElement;
|
||||
const files = fileEl.files;
|
||||
if (files == null || files.length === 0) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("selectFile"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("selectFile"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (files[0].size > 524288000) {
|
||||
// 500 MB
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("maxFileSize"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("maxFileSize"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,11 @@ export class AttachmentsComponent implements OnInit {
|
||||
this.cipher = await this.cipherDomain.decrypt(
|
||||
await this.cipherService.getKeyForCipherKeyDecryption(this.cipherDomain, activeUserId),
|
||||
);
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("attachmentSaved"));
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("attachmentSaved"),
|
||||
});
|
||||
this.onUploadedAttachment.emit();
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
@@ -122,7 +126,11 @@ export class AttachmentsComponent implements OnInit {
|
||||
try {
|
||||
this.deletePromises[attachment.id] = this.deleteCipherAttachment(attachment.id);
|
||||
await this.deletePromises[attachment.id];
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedAttachment"));
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("deletedAttachment"),
|
||||
});
|
||||
const i = this.cipher.attachments.indexOf(attachment);
|
||||
if (i > -1) {
|
||||
this.cipher.attachments.splice(i, 1);
|
||||
@@ -142,11 +150,11 @@ export class AttachmentsComponent implements OnInit {
|
||||
}
|
||||
|
||||
if (!this.canAccessAttachments) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("premiumRequired"),
|
||||
this.i18nService.t("premiumRequiredDesc"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("premiumRequired"),
|
||||
message: this.i18nService.t("premiumRequiredDesc"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -171,7 +179,11 @@ export class AttachmentsComponent implements OnInit {
|
||||
a.downloading = true;
|
||||
const response = await fetch(new Request(url, { cache: "no-store" }));
|
||||
if (response.status !== 200) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("errorOccurred"),
|
||||
});
|
||||
a.downloading = false;
|
||||
return;
|
||||
}
|
||||
@@ -195,7 +207,11 @@ export class AttachmentsComponent implements OnInit {
|
||||
// FIXME: Remove when updating file. Eslint update
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (e) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("errorOccurred"),
|
||||
});
|
||||
}
|
||||
|
||||
a.downloading = false;
|
||||
@@ -243,7 +259,11 @@ export class AttachmentsComponent implements OnInit {
|
||||
a.downloading = true;
|
||||
const response = await fetch(new Request(attachment.url, { cache: "no-store" }));
|
||||
if (response.status !== 200) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("errorOccurred"),
|
||||
});
|
||||
a.downloading = false;
|
||||
return;
|
||||
}
|
||||
@@ -281,16 +301,20 @@ export class AttachmentsComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t("attachmentSaved"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("attachmentSaved"),
|
||||
});
|
||||
this.onReuploadedAttachment.emit();
|
||||
// FIXME: Remove when updating file. Eslint update
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (e) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("errorOccurred"),
|
||||
});
|
||||
}
|
||||
|
||||
a.downloading = false;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { FolderApiServiceAbstraction } from "@bitwarden/common/vault/abstractions/folder/folder-api.service.abstraction";
|
||||
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
|
||||
@Directive()
|
||||
@@ -43,6 +43,7 @@ export class FolderAddEditComponent implements OnInit {
|
||||
protected logService: LogService,
|
||||
protected dialogService: DialogService,
|
||||
protected formBuilder: FormBuilder,
|
||||
protected toastService: ToastService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@@ -52,11 +53,11 @@ export class FolderAddEditComponent implements OnInit {
|
||||
async submit(): Promise<boolean> {
|
||||
this.folder.name = this.formGroup.controls.name.value;
|
||||
if (this.folder.name == null || this.folder.name === "") {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("errorOccurred"),
|
||||
this.i18nService.t("nameRequired"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("errorOccurred"),
|
||||
message: this.i18nService.t("nameRequired"),
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -66,11 +67,11 @@ export class FolderAddEditComponent implements OnInit {
|
||||
const folder = await this.folderService.encrypt(this.folder, userKey);
|
||||
this.formPromise = this.folderApiService.save(folder, activeUserId);
|
||||
await this.formPromise;
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t(this.editMode ? "editedFolder" : "addedFolder"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t(this.editMode ? "editedFolder" : "addedFolder"),
|
||||
});
|
||||
this.onSavedFolder.emit(this.folder);
|
||||
return true;
|
||||
} catch (e) {
|
||||
@@ -95,7 +96,11 @@ export class FolderAddEditComponent implements OnInit {
|
||||
const activeUserId = await firstValueFrom(this.activeUserId$);
|
||||
this.deletePromise = this.folderApiService.delete(this.folder.id, activeUserId);
|
||||
await this.deletePromise;
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("deletedFolder"));
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("deletedFolder"),
|
||||
});
|
||||
this.onDeletedFolder.emit(this.folder);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
|
||||
@@ -8,6 +8,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { PasswordHistoryView } from "@bitwarden/common/vault/models/view/password-history.view";
|
||||
import { ToastService } from "@bitwarden/components";
|
||||
|
||||
@Directive()
|
||||
export class PasswordHistoryComponent implements OnInit {
|
||||
@@ -20,6 +21,7 @@ export class PasswordHistoryComponent implements OnInit {
|
||||
protected i18nService: I18nService,
|
||||
protected accountService: AccountService,
|
||||
private win: Window,
|
||||
private toastService: ToastService,
|
||||
) {}
|
||||
|
||||
async ngOnInit() {
|
||||
@@ -29,11 +31,11 @@ export class PasswordHistoryComponent implements OnInit {
|
||||
copy(password: string) {
|
||||
const copyOptions = this.win != null ? { window: this.win } : null;
|
||||
this.platformUtilsService.copyToClipboard(password, copyOptions);
|
||||
this.platformUtilsService.showToast(
|
||||
"info",
|
||||
null,
|
||||
this.i18nService.t("valueCopied", this.i18nService.t("password")),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "info",
|
||||
title: null,
|
||||
message: this.i18nService.t("valueCopied", this.i18nService.t("password")),
|
||||
});
|
||||
}
|
||||
|
||||
protected async init() {
|
||||
|
||||
@@ -12,7 +12,7 @@ import { EnvironmentService } from "@bitwarden/common/platform/abstractions/envi
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { DialogService, SimpleDialogOptions } from "@bitwarden/components";
|
||||
import { DialogService, SimpleDialogOptions, ToastService } from "@bitwarden/components";
|
||||
|
||||
@Directive()
|
||||
export class PremiumComponent implements OnInit {
|
||||
@@ -31,6 +31,7 @@ export class PremiumComponent implements OnInit {
|
||||
protected dialogService: DialogService,
|
||||
private environmentService: EnvironmentService,
|
||||
billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
private toastService: ToastService,
|
||||
accountService: AccountService,
|
||||
) {
|
||||
this.isPremium$ = accountService.activeAccount$.pipe(
|
||||
@@ -51,7 +52,11 @@ export class PremiumComponent implements OnInit {
|
||||
try {
|
||||
this.refreshPromise = this.apiService.refreshIdentityToken();
|
||||
await this.refreshPromise;
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("refreshComplete"));
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("refreshComplete"),
|
||||
});
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ import { AttachmentView } from "@bitwarden/common/vault/models/view/attachment.v
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
|
||||
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { DialogService, ToastService } from "@bitwarden/components";
|
||||
import { KeyService } from "@bitwarden/key-management";
|
||||
import { PasswordRepromptService } from "@bitwarden/vault";
|
||||
|
||||
@@ -115,6 +115,7 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
protected datePipe: DatePipe,
|
||||
protected accountService: AccountService,
|
||||
private billingAccountProfileStateService: BillingAccountProfileStateService,
|
||||
protected toastService: ToastService,
|
||||
private cipherAuthorizationService: CipherAuthorizationService,
|
||||
) {}
|
||||
|
||||
@@ -246,11 +247,13 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
|
||||
try {
|
||||
await this.deleteCipher();
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
null,
|
||||
this.i18nService.t(this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t(
|
||||
this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem",
|
||||
),
|
||||
});
|
||||
this.onDeletedCipher.emit(this.cipher);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
@@ -266,7 +269,11 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
|
||||
try {
|
||||
await this.restoreCipher();
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("restoredItem"));
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("restoredItem"),
|
||||
});
|
||||
this.onRestoredCipher.emit(this.cipher);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
@@ -349,13 +356,17 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
const matches = await this.checkPasswordPromise;
|
||||
|
||||
if (matches > 0) {
|
||||
this.platformUtilsService.showToast(
|
||||
"warning",
|
||||
null,
|
||||
this.i18nService.t("passwordExposed", matches.toString()),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "warning",
|
||||
title: null,
|
||||
message: this.i18nService.t("passwordExposed", matches.toString()),
|
||||
});
|
||||
} else {
|
||||
this.platformUtilsService.showToast("success", null, this.i18nService.t("passwordSafe"));
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
message: this.i18nService.t("passwordSafe"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,11 +396,11 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
|
||||
const copyOptions = this.win != null ? { window: this.win } : null;
|
||||
this.platformUtilsService.copyToClipboard(value, copyOptions);
|
||||
this.platformUtilsService.showToast(
|
||||
"info",
|
||||
null,
|
||||
this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "info",
|
||||
title: null,
|
||||
message: this.i18nService.t("valueCopied", this.i18nService.t(typeI18nKey)),
|
||||
});
|
||||
|
||||
if (typeI18nKey === "password") {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
@@ -422,11 +433,11 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
}
|
||||
|
||||
if (this.cipher.organizationId == null && !this.canAccessPremium) {
|
||||
this.platformUtilsService.showToast(
|
||||
"error",
|
||||
this.i18nService.t("premiumRequired"),
|
||||
this.i18nService.t("premiumRequiredDesc"),
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: this.i18nService.t("premiumRequired"),
|
||||
message: this.i18nService.t("premiumRequiredDesc"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -450,7 +461,11 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
a.downloading = true;
|
||||
const response = await fetch(new Request(url, { cache: "no-store" }));
|
||||
if (response.status !== 200) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("errorOccurred"),
|
||||
});
|
||||
a.downloading = false;
|
||||
return;
|
||||
}
|
||||
@@ -469,7 +484,11 @@ export class ViewComponent implements OnDestroy, OnInit {
|
||||
// FIXME: Remove when updating file. Eslint update
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (e) {
|
||||
this.platformUtilsService.showToast("error", null, this.i18nService.t("errorOccurred"));
|
||||
this.toastService.showToast({
|
||||
variant: "error",
|
||||
title: null,
|
||||
message: this.i18nService.t("errorOccurred"),
|
||||
});
|
||||
}
|
||||
|
||||
a.downloading = false;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"@bitwarden/importer/core": ["../importer/src"],
|
||||
"@bitwarden/key-management": ["../key-management/src"],
|
||||
"@bitwarden/platform": ["../platform/src"],
|
||||
"@bitwarden/ui-common": ["../ui/common/src"],
|
||||
"@bitwarden/vault-export-core": ["../tools/export/vault-export/vault-export-core/src"],
|
||||
"@bitwarden/vault": ["../vault/src"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user