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

[PM-17819] Replicate ReactiveForms and bit-* component changes to Blocked Domains from Excluded Domains update [PM-13808]. (#13180)

This commit is contained in:
Miles Blackwood
2025-02-19 17:17:00 -05:00
committed by GitHub
parent 23ef1b1688
commit 33e1a6e917
2 changed files with 58 additions and 36 deletions

View File

@@ -20,30 +20,13 @@
<bit-section *ngIf="!isLoading"> <bit-section *ngIf="!isLoading">
<bit-section-header> <bit-section-header>
<h2 bitTypography="h6">{{ "domainsTitle" | i18n }}</h2> <h2 bitTypography="h6">{{ "domainsTitle" | i18n }}</h2>
<span bitTypography="body2" slot="end">{{ blockedDomainsState?.length || 0 }}</span> <span bitTypography="body2" slot="end">{{
blockedDomainsState.length + domainForms.value.length
}}</span>
</bit-section-header> </bit-section-header>
<bit-item *ngFor="let domain of blockedDomainsState; let i = index; trackBy: trackByFunction">
<ng-container *ngIf="blockedDomainsState"> <bit-item-content *ngIf="i < fieldsEditThreshold">
<bit-item <div id="blockedDomain{{ i }}">{{ domain }}</div>
*ngFor="let domain of blockedDomainsState; let i = index; trackBy: trackByFunction"
>
<bit-item-content>
<bit-label *ngIf="i >= fieldsEditThreshold">{{
"websiteItemLabel" | i18n: i + 1
}}</bit-label>
<input
*ngIf="i >= fieldsEditThreshold"
#uriInput
appInputVerbatim
bitInput
id="excludedDomain{{ i }}"
inputmode="url"
name="excludedDomain{{ i }}"
type="text"
(change)="fieldChange()"
[(ngModel)]="blockedDomainsState[i]"
/>
<div id="excludedDomain{{ i }}" *ngIf="i < fieldsEditThreshold">{{ domain }}</div>
</bit-item-content> </bit-item-content>
<button <button
*ngIf="i < fieldsEditThreshold" *ngIf="i < fieldsEditThreshold"
@@ -56,10 +39,31 @@
(click)="removeDomain(i)" (click)="removeDomain(i)"
></button> ></button>
</bit-item> </bit-item>
</ng-container> <form [formGroup]="domainListForm">
<bit-card
formArrayName="domains"
*ngFor="let domain of domainForms.controls; let i = index"
>
<bit-form-field disableMargin>
<bit-label>{{ "websiteItemLabel" | i18n: i + fieldsEditThreshold + 1 }}</bit-label>
<input
bitInput
#uriInput
appInputVerbatim
bitInput
id="blockedDomain{{ i + fieldsEditThreshold }}"
inputmode="url"
name="blockedDomain{{ i + fieldsEditThreshold }}"
type="text"
(change)="fieldChange()"
formControlName="{{ i }}"
/>
</bit-form-field>
</bit-card>
<button bitLink class="tw-pt-2" type="button" linkType="primary" (click)="addNewDomain()"> <button bitLink class="tw-pt-2" type="button" linkType="primary" (click)="addNewDomain()">
<i class="bwi bwi-plus-circle bwi-fw" aria-hidden="true"></i> {{ "addDomain" | i18n }} <i class="bwi bwi-plus-circle bwi-fw" aria-hidden="true"></i> {{ "addDomain" | i18n }}
</button> </button>
</form>
</bit-section> </bit-section>
</div> </div>
<popup-footer slot="footer"> <popup-footer slot="footer">

View File

@@ -7,7 +7,13 @@ import {
AfterViewInit, AfterViewInit,
ViewChildren, ViewChildren,
} from "@angular/core"; } from "@angular/core";
import { FormsModule } from "@angular/forms"; import {
FormsModule,
ReactiveFormsModule,
FormBuilder,
FormGroup,
FormArray,
} from "@angular/forms";
import { RouterModule } from "@angular/router"; import { RouterModule } from "@angular/router";
import { Subject, takeUntil } from "rxjs"; import { Subject, takeUntil } from "rxjs";
@@ -44,6 +50,7 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co
CommonModule, CommonModule,
FormFieldModule, FormFieldModule,
FormsModule, FormsModule,
ReactiveFormsModule,
IconButtonModule, IconButtonModule,
ItemModule, ItemModule,
JslibModule, JslibModule,
@@ -66,6 +73,11 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
isLoading = false; isLoading = false;
blockedDomainsState: string[] = []; blockedDomainsState: string[] = [];
storedBlockedDomains: string[] = []; storedBlockedDomains: string[] = [];
protected domainListForm = new FormGroup({
domains: this.formBuilder.array([]),
});
// How many fields should be non-editable before editable fields // How many fields should be non-editable before editable fields
fieldsEditThreshold: number = 0; fieldsEditThreshold: number = 0;
@@ -75,8 +87,13 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
private domainSettingsService: DomainSettingsService, private domainSettingsService: DomainSettingsService,
private i18nService: I18nService, private i18nService: I18nService,
private toastService: ToastService, private toastService: ToastService,
private formBuilder: FormBuilder,
) {} ) {}
get domainForms() {
return this.domainListForm.get("domains") as FormArray;
}
async ngAfterViewInit() { async ngAfterViewInit() {
this.domainSettingsService.blockedInteractionsUris$ this.domainSettingsService.blockedInteractionsUris$
.pipe(takeUntil(this.destroy$)) .pipe(takeUntil(this.destroy$))
@@ -113,8 +130,7 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
} }
async addNewDomain() { async addNewDomain() {
// add empty field to the Domains list interface this.domainForms.push(this.formBuilder.control(null));
this.blockedDomainsState.push("");
await this.fieldChange(); await this.fieldChange();
} }
@@ -144,7 +160,8 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
this.isLoading = true; this.isLoading = true;
const newBlockedDomainsSaveState: NeverDomains = {}; const newBlockedDomainsSaveState: NeverDomains = {};
const uniqueBlockedDomains = new Set(this.blockedDomainsState);
const uniqueBlockedDomains = new Set([...this.blockedDomainsState, ...this.domainForms.value]);
for (const uri of uniqueBlockedDomains) { for (const uri of uniqueBlockedDomains) {
if (uri && uri !== "") { if (uri && uri !== "") {
@@ -152,7 +169,7 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
if (!validatedHost) { if (!validatedHost) {
this.toastService.showToast({ this.toastService.showToast({
message: this.i18nService.t("excludedDomainsInvalidDomain", uri), message: this.i18nService.t("blockedDomainsInvalidDomain", uri),
title: "", title: "",
variant: "error", variant: "error",
}); });
@@ -190,13 +207,14 @@ export class BlockedDomainsComponent implements AfterViewInit, OnDestroy {
title: "", title: "",
variant: "success", variant: "success",
}); });
this.domainForms.clear();
} catch { } catch {
this.toastService.showToast({ this.toastService.showToast({
message: this.i18nService.t("unexpectedError"), message: this.i18nService.t("unexpectedError"),
title: "", title: "",
variant: "error", variant: "error",
}); });
// Don't reset via `handleStateUpdate` to preserve input values // Don't reset via `handleStateUpdate` to preserve input values
this.isLoading = false; this.isLoading = false;
} }