mirror of
https://github.com/bitwarden/browser
synced 2025-12-18 01:03:35 +00:00
Merge EC-73 Again After Rebase (#4104)
* [EC-73] feat: add inital version of modal using dialog service * [EC-73] feat: create story for dialog * [EC-73] feat: setup story with support for injected data * [EC-73] feat: add inital version of subtitle * [EC-73] feat: add tabs * [EC-73] feat: initial version of collection info form * [EC-73] feat: start of working form * [EC-73] feat: add custom form validator * [EC-73] fix: dialog directive names after rebase * [EC-73] feat: use custom validator * [EC-73] fix: story * [EC-73] feat: allow parent picking * [EC-73] feat: remove tabs to allow for merging * [EC-73] feat: extend story with new and edit dialogs * [EC-73] feat: change title depending on if editing or not * [EC-73] fix: parent not connected to form * [EC-73] feat: add organizationId to dialog data * [EC-73] feat: only allow nesting within collections with access * [EC-73] feat: handle loading with spinner * [EC-73] feat: update collections on submit * [EC-73] feat: reload on save * [EC-73] feat: update story to work with latest changes * [EC-73] feat: always fetch collections from server * [EC-73] fix: do not submit if form invalid * [EC-73] feat: create new collections using new ui * [EC-73] fix: external id not being saved * [EC-73] chore: move calls to separete collection admin service * [EC-73] feat: use new admin views * [EC-73] feat: implement deletion * [EC-73] feat: add support for collection details in service * [EC-73] fix: story * [EC-73] fix: cancel button * [EC-73] feat: re-add tabs * [EC-73] fix: jslib service collection deps * [EC-73] chore: rename component to collection-dialog * [EC-73] chore: clean up collection api service which was replaced * [EC-73] chore: restore collection.service * [EC-73] chore: restore dialog component changes * [EC-73] fix: move subscription to ngOnInit * [EC-73] feat: disable padding when using tabbed content * [EC-73] chore: re-add collections page * [EC-73] chore: move component to shared org module * [EC-73] feat: add empty access selector * [EC-73] feat: add groups to access selector * [EC-73] chore: improve storybook support * [EC-73] feat: tweak item assignment * [EC-73] feat: add support for showing users * [EC-73] feat: use async actions * [EC-73] chore: clean up casting * [EC-73] fix: permissions not loading correctly in access selector * [EC-73] feat: implement saving group permissions * [EC-73] feat: rename to collection access selection view * [EC-73] feat: save users as well * [EC-73] fix: access selector usage * [EC-73] feat: new collection creation * [EC-73] feat: fetch users from collection details * [EC-73] chore: clean up * [EC-73] fix: circular dependency issues * [EC-73] fix: import shared module directly to workaround build issues * [EC-73] fix: missing dependencies in story * [EC-73] chore: move story * [EC-73] feat: hide delete button if no permission * [EC-73] feat: properly handle orgs without groups * [EC-73] fix: use correct functions in template * [EC-73] feat: properly handle non-existing parent * [EC-73] chore: use double ngIf instead of else template * [EC-73] fix: add type to dialog ref * [EC-73] fix: restrict field modifiers * [EC-73] fix: use result enum directly * [EC-73] fix: simplify mapping logic * [EC-73] * [EC-73] feat: add story for free orgs without groups * [EC-73] fix: parametrized i18n * [EC-73] feat: create new shared org module * [EC-73] feat: move collection dialog to shared * [EC-73] feat: move access selector to shared * [EC-73] feat: create core organization module * [EC-73] feat: move collection admin service to web * [EC-73] feat: move collection admin views to web * [EC-73] fix: missing i18n * [EC-73] fix: refactor for type safety * [EC-73] fix: storybook not compiling again * [EC-73] feat: use helper function to open dialog * [EC-73] chore: remove comment * [EC-73] fix: only show delete if in edit mode * [EC-73] chore: remove ngIf else in template * [EC-73] fix: add missing appA11yTitle * [EC-73] chore: rename remove to delete * [EC-73] chore: refactor ngOnInit * [EC-73] fix: dialog position strategy * [EC-73] fix: revert spinner to old way of doing it * Fix remaining errors after rebase/merge * fix: import shared module directly Co-authored-by: Andreas Coroiu <andreas.coroiu@gmail.com>
This commit is contained in:
@@ -3,10 +3,9 @@ import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { ButtonLikeAbstraction } from "../shared/button-like.abstraction";
|
||||
|
||||
import { BitActionDirective } from "./bit-action.directive";
|
||||
import { BitSubmitDirective } from "./bit-submit.directive";
|
||||
|
||||
import { BitActionDirective } from ".";
|
||||
|
||||
/**
|
||||
* This directive has two purposes:
|
||||
*
|
||||
|
||||
@@ -4,7 +4,7 @@ import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
|
||||
import { I18nMockService } from "../utils/i18n-mock.service";
|
||||
|
||||
import { CalloutComponent } from ".";
|
||||
import { CalloutComponent } from "./callout.component";
|
||||
|
||||
describe("Callout", () => {
|
||||
let component: CalloutComponent;
|
||||
|
||||
56
libs/components/src/form-field/bit-validators.stories.ts
Normal file
56
libs/components/src/form-field/bit-validators.stories.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { FormsModule, ReactiveFormsModule, FormBuilder } from "@angular/forms";
|
||||
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
|
||||
import { ButtonModule } from "../button";
|
||||
import { InputModule } from "../input/input.module";
|
||||
import { I18nMockService } from "../utils/i18n-mock.service";
|
||||
|
||||
import { forbiddenCharacters } from "./bit-validators/forbidden-characters.validator";
|
||||
import { BitFormFieldComponent } from "./form-field.component";
|
||||
import { FormFieldModule } from "./form-field.module";
|
||||
|
||||
export default {
|
||||
title: "Component Library/Form/Custom Validators",
|
||||
component: BitFormFieldComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [FormsModule, ReactiveFormsModule, FormFieldModule, InputModule, ButtonModule],
|
||||
providers: [
|
||||
{
|
||||
provide: I18nService,
|
||||
useFactory: () => {
|
||||
return new I18nMockService({
|
||||
inputForbiddenCharacters: (chars) =>
|
||||
`The following characters are not allowed: ${chars}`,
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
parameters: {
|
||||
design: {
|
||||
type: "figma",
|
||||
url: "https://www.figma.com/file/f32LSg3jaegICkMu7rPARm/Tailwind-Component-Library-Update?node-id=1881%3A17689",
|
||||
},
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
const template = `
|
||||
<form [formGroup]="formObj">
|
||||
<bit-form-field>
|
||||
<bit-label>Name</bit-label>
|
||||
<input bitInput formControlName="name" />
|
||||
</bit-form-field>
|
||||
</form>`;
|
||||
|
||||
export const ForbiddenCharacters: Story<BitFormFieldComponent> = (args: BitFormFieldComponent) => ({
|
||||
props: {
|
||||
formObj: new FormBuilder().group({
|
||||
name: ["", forbiddenCharacters(["\\", "/", "@", "#", "$", "%", "^", "&", "*", "(", ")"])],
|
||||
}),
|
||||
},
|
||||
template,
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
import { FormControl } from "@angular/forms";
|
||||
|
||||
import { forbiddenCharacters } from "./forbidden-characters.validator";
|
||||
|
||||
describe("forbiddenCharacters", () => {
|
||||
it("should return no error when input is null", () => {
|
||||
const input = createControl(null);
|
||||
const validate = forbiddenCharacters(["n", "u", "l", "l"]);
|
||||
|
||||
const errors = validate(input);
|
||||
|
||||
expect(errors).toBe(null);
|
||||
});
|
||||
|
||||
it("should return no error when no characters are forbidden", () => {
|
||||
const input = createControl("special characters: \\/@#$%^&*()");
|
||||
const validate = forbiddenCharacters([]);
|
||||
|
||||
const errors = validate(input);
|
||||
|
||||
expect(errors).toBe(null);
|
||||
});
|
||||
|
||||
it("should return no error when input does not contain forbidden characters", () => {
|
||||
const input = createControl("contains no special characters");
|
||||
const validate = forbiddenCharacters(["\\", "/", "@", "#", "$", "%", "^", "&", "*", "(", ")"]);
|
||||
|
||||
const errors = validate(input);
|
||||
|
||||
expect(errors).toBe(null);
|
||||
});
|
||||
|
||||
it("should return error when input contains forbidden characters", () => {
|
||||
const input = createControl("contains / illegal @ characters");
|
||||
const validate = forbiddenCharacters(["\\", "/", "@", "#", "$", "%", "^", "&", "*", "(", ")"]);
|
||||
|
||||
const errors = validate(input);
|
||||
|
||||
expect(errors).not.toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
function createControl(input: string) {
|
||||
return new FormControl(input);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { AbstractControl, FormControl, ValidationErrors, ValidatorFn } from "@angular/forms";
|
||||
|
||||
export function forbiddenCharacters(characters: string[]): ValidatorFn {
|
||||
return (control: AbstractControl): ValidationErrors | null => {
|
||||
if (!(control instanceof FormControl)) {
|
||||
throw new Error("forbiddenCharacters only supports validating FormControls");
|
||||
}
|
||||
|
||||
if (control.value === null || control.value === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const value = String(control.value);
|
||||
|
||||
for (const char of value) {
|
||||
if (characters.includes(char)) {
|
||||
return { forbiddenCharacters: { value: control.value, characters } };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
1
libs/components/src/form-field/bit-validators/index.ts
Normal file
1
libs/components/src/form-field/bit-validators/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { forbiddenCharacters } from "./forbidden-characters.validator";
|
||||
@@ -30,6 +30,8 @@ export class BitErrorComponent {
|
||||
return this.i18nService.t("inputMinLength", this.error[1]?.requiredLength);
|
||||
case "maxlength":
|
||||
return this.i18nService.t("inputMaxLength", this.error[1]?.requiredLength);
|
||||
case "forbiddenCharacters":
|
||||
return this.i18nService.t("inputForbiddenCharacters", this.error[1]?.characters.join(", "));
|
||||
default:
|
||||
// Attempt to show a custom error message.
|
||||
if (this.error[1]?.message) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./form-field.module";
|
||||
export * from "./form-field.component";
|
||||
export * from "./form-field-control";
|
||||
export * as BitValidators from "./bit-validators";
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./multi-select.module";
|
||||
export * from "./models/select-item-view";
|
||||
|
||||
Reference in New Issue
Block a user