mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
[PM-5609] passphrase settings component & services (#10535)
This commit is contained in:
@@ -257,8 +257,8 @@ describe("UserStateSubject", () => {
|
||||
|
||||
let actual: TestType = null;
|
||||
subject.subscribe({
|
||||
error: (value) => {
|
||||
actual = value;
|
||||
error: (value: unknown) => {
|
||||
actual = value as any;
|
||||
},
|
||||
});
|
||||
subject.error(expected);
|
||||
@@ -275,8 +275,8 @@ describe("UserStateSubject", () => {
|
||||
|
||||
let actual: TestType = null;
|
||||
subject.subscribe({
|
||||
error: (value) => {
|
||||
actual = value;
|
||||
error: (value: unknown) => {
|
||||
actual = value as any;
|
||||
},
|
||||
});
|
||||
subject.error("expectedError");
|
||||
@@ -415,8 +415,8 @@ describe("UserStateSubject", () => {
|
||||
|
||||
let error = false;
|
||||
subject.subscribe({
|
||||
error: (e) => {
|
||||
error = e;
|
||||
error: (e: unknown) => {
|
||||
error = e as any;
|
||||
},
|
||||
});
|
||||
singleUserId$.next(errorUserId);
|
||||
@@ -434,8 +434,8 @@ describe("UserStateSubject", () => {
|
||||
|
||||
let actual = false;
|
||||
subject.subscribe({
|
||||
error: (e) => {
|
||||
actual = e;
|
||||
error: (e: unknown) => {
|
||||
actual = e as any;
|
||||
},
|
||||
});
|
||||
singleUserId$.error(expected);
|
||||
@@ -454,8 +454,8 @@ describe("UserStateSubject", () => {
|
||||
|
||||
let actual = false;
|
||||
subject.subscribe({
|
||||
error: (e) => {
|
||||
actual = e;
|
||||
error: (e: unknown) => {
|
||||
actual = e as any;
|
||||
},
|
||||
});
|
||||
when$.error(expected);
|
||||
@@ -464,4 +464,14 @@ describe("UserStateSubject", () => {
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("userId", () => {
|
||||
it("returns the userId to which the subject is bound", () => {
|
||||
const state = new FakeSingleUserState<TestType>(SomeUser, { foo: "init" });
|
||||
const singleUserId$ = new Subject<UserId>();
|
||||
const subject = new UserStateSubject(state, { singleUserId$ });
|
||||
|
||||
expect(subject.userId).toEqual(SomeUser);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,6 +15,8 @@ import {
|
||||
ignoreElements,
|
||||
endWith,
|
||||
startWith,
|
||||
Observable,
|
||||
Subscription,
|
||||
} from "rxjs";
|
||||
import { Simplify } from "type-fest";
|
||||
|
||||
@@ -59,7 +61,10 @@ export type UserStateSubjectDependencies<State, Dependency> = Simplify<
|
||||
* @template State the state stored by the subject
|
||||
* @template Dependencies use-specific dependencies provided by the user.
|
||||
*/
|
||||
export class UserStateSubject<State, Dependencies = null> implements SubjectLike<State> {
|
||||
export class UserStateSubject<State, Dependencies = null>
|
||||
extends Observable<State>
|
||||
implements SubjectLike<State>
|
||||
{
|
||||
/**
|
||||
* Instantiates the user state subject
|
||||
* @param state the backing store of the subject
|
||||
@@ -76,6 +81,8 @@ export class UserStateSubject<State, Dependencies = null> implements SubjectLike
|
||||
private state: SingleUserState<State>,
|
||||
private dependencies: UserStateSubjectDependencies<State, Dependencies>,
|
||||
) {
|
||||
super();
|
||||
|
||||
// normalize dependencies
|
||||
const when$ = (this.dependencies.when$ ?? new BehaviorSubject(true)).pipe(
|
||||
distinctUntilChanged(),
|
||||
@@ -114,6 +121,12 @@ export class UserStateSubject<State, Dependencies = null> implements SubjectLike
|
||||
});
|
||||
}
|
||||
|
||||
/** The userId to which the subject is bound.
|
||||
*/
|
||||
get userId() {
|
||||
return this.state.userId;
|
||||
}
|
||||
|
||||
next(value: State) {
|
||||
this.input?.next(value);
|
||||
}
|
||||
@@ -130,7 +143,7 @@ export class UserStateSubject<State, Dependencies = null> implements SubjectLike
|
||||
* @param observer listening for events
|
||||
* @returns the subscription
|
||||
*/
|
||||
subscribe(observer: Partial<Observer<State>> | ((value: State) => void)): Unsubscribable {
|
||||
subscribe(observer?: Partial<Observer<State>> | ((value: State) => void) | null): Subscription {
|
||||
return this.output.subscribe(observer);
|
||||
}
|
||||
|
||||
|
||||
48
libs/common/src/tools/types.ts
Normal file
48
libs/common/src/tools/types.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { Simplify } from "type-fest";
|
||||
|
||||
/** Constraints that are shared by all primitive field types */
|
||||
type PrimitiveConstraint = {
|
||||
/** presence indicates the field is required */
|
||||
required?: true;
|
||||
};
|
||||
|
||||
/** Constraints that are shared by string fields */
|
||||
type StringConstraints = {
|
||||
/** minimum string length. When absent, min length is 0. */
|
||||
minLength?: number;
|
||||
|
||||
/** maximum string length. When absent, max length is unbounded. */
|
||||
maxLength?: number;
|
||||
};
|
||||
|
||||
/** Constraints that are shared by number fields */
|
||||
type NumberConstraints = {
|
||||
/** minimum number value. When absent, min value is unbounded. */
|
||||
min?: number;
|
||||
|
||||
/** maximum number value. When absent, min value is unbounded. */
|
||||
max?: number;
|
||||
|
||||
/** presence indicates the field only accepts integer values */
|
||||
integer?: true;
|
||||
|
||||
/** requires the number be a multiple of the step value */
|
||||
step?: number;
|
||||
};
|
||||
|
||||
/** Utility type that transforms keys of T into their supported
|
||||
* validators.
|
||||
*/
|
||||
export type Constraints<T> = {
|
||||
[Key in keyof T]: Simplify<
|
||||
PrimitiveConstraint &
|
||||
(T[Key] extends string
|
||||
? StringConstraints
|
||||
: T[Key] extends number
|
||||
? NumberConstraints
|
||||
: never)
|
||||
>;
|
||||
};
|
||||
|
||||
/** utility type for methods that evaluate constraints generically. */
|
||||
export type AnyConstraint = PrimitiveConstraint & StringConstraints & NumberConstraints;
|
||||
Reference in New Issue
Block a user