Merge pull request #1376 from eliykat/feature-edit-excludedDomains
add settings -> Excluded Domains component
This commit is contained in:
commit
d24961e3a0
|
@ -1449,5 +1449,20 @@
|
||||||
},
|
},
|
||||||
"personalOwnershipPolicyInEffect": {
|
"personalOwnershipPolicyInEffect": {
|
||||||
"message": "An organization policy is affecting your ownership options."
|
"message": "An organization policy is affecting your ownership options."
|
||||||
|
},
|
||||||
|
"excludedDomains": {
|
||||||
|
"message": "Excluded Domains"
|
||||||
|
},
|
||||||
|
"excludedDomainsDesc": {
|
||||||
|
"message": "Bitwarden will not ask to save login details for these domains."
|
||||||
|
},
|
||||||
|
"excludedDomainsInvalidDomain": {
|
||||||
|
"message": "$DOMAIN$ is not a valid domain",
|
||||||
|
"placeholders": {
|
||||||
|
"domain": {
|
||||||
|
"content": "$1",
|
||||||
|
"example": "googlecom"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { SsoComponent } from './accounts/sso.component';
|
||||||
import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component';
|
import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component';
|
||||||
import { PasswordGeneratorComponent } from './generator/password-generator.component';
|
import { PasswordGeneratorComponent } from './generator/password-generator.component';
|
||||||
import { PrivateModeComponent } from './private-mode.component';
|
import { PrivateModeComponent } from './private-mode.component';
|
||||||
|
import { ExcludedDomainsComponent } from './settings/excluded-domains.component';
|
||||||
import { ExportComponent } from './settings/export.component';
|
import { ExportComponent } from './settings/export.component';
|
||||||
import { FolderAddEditComponent } from './settings/folder-add-edit.component';
|
import { FolderAddEditComponent } from './settings/folder-add-edit.component';
|
||||||
import { FoldersComponent } from './settings/folders.component';
|
import { FoldersComponent } from './settings/folders.component';
|
||||||
|
@ -200,6 +201,12 @@ const routes: Routes = [
|
||||||
canActivate: [AuthGuardService],
|
canActivate: [AuthGuardService],
|
||||||
data: { state: 'sync' },
|
data: { state: 'sync' },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'excluded-domains',
|
||||||
|
component: ExcludedDomainsComponent,
|
||||||
|
canActivate: [AuthGuardService],
|
||||||
|
data: { state: 'excluded-domains' },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'premium',
|
path: 'premium',
|
||||||
component: PremiumComponent,
|
component: PremiumComponent,
|
||||||
|
|
|
@ -29,6 +29,7 @@ import { AppComponent } from './app.component';
|
||||||
import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component';
|
import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component';
|
||||||
import { PasswordGeneratorComponent } from './generator/password-generator.component';
|
import { PasswordGeneratorComponent } from './generator/password-generator.component';
|
||||||
import { PrivateModeComponent } from './private-mode.component';
|
import { PrivateModeComponent } from './private-mode.component';
|
||||||
|
import { ExcludedDomainsComponent } from './settings/excluded-domains.component';
|
||||||
import { ExportComponent } from './settings/export.component';
|
import { ExportComponent } from './settings/export.component';
|
||||||
import { FolderAddEditComponent } from './settings/folder-add-edit.component';
|
import { FolderAddEditComponent } from './settings/folder-add-edit.component';
|
||||||
import { FoldersComponent } from './settings/folders.component';
|
import { FoldersComponent } from './settings/folders.component';
|
||||||
|
@ -181,6 +182,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||||
ColorPasswordPipe,
|
ColorPasswordPipe,
|
||||||
CurrentTabComponent,
|
CurrentTabComponent,
|
||||||
EnvironmentComponent,
|
EnvironmentComponent,
|
||||||
|
ExcludedDomainsComponent,
|
||||||
ExportComponent,
|
ExportComponent,
|
||||||
FallbackSrcDirective,
|
FallbackSrcDirective,
|
||||||
FolderAddEditComponent,
|
FolderAddEditComponent,
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
<form #form (ngSubmit)="submit()">
|
||||||
|
<header>
|
||||||
|
<div class="left">
|
||||||
|
<a routerLink="/tabs/settings">{{'cancel' | i18n}}</a>
|
||||||
|
</div>
|
||||||
|
<div class="center">
|
||||||
|
<span class="title">{{'excludedDomains' | i18n}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<button type="submit" appBlurClick>{{'save' | i18n}}</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<content>
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-content">
|
||||||
|
<ng-container *ngIf="excludedDomains">
|
||||||
|
<div class="box-content-row box-content-row-multi" appBoxRow
|
||||||
|
*ngFor="let domain of excludedDomains; let i = index; trackBy:trackByFunction">
|
||||||
|
<a href="#" appStopClick (click)="removeUri(i)" appA11yTitle="{{'remove' | i18n}}">
|
||||||
|
<i class="fa fa-minus-circle fa-lg" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
<div class="row-main">
|
||||||
|
<label for="excludedDomain{{i}}">{{'uriPosition' | i18n : (i + 1)}}</label>
|
||||||
|
<input id="excludedDomain{{i}}" name="excludedDomain{{i}}" type="text" [(ngModel)]="domain.uri"
|
||||||
|
placeholder="{{'ex' | i18n}} https://google.com" inputmode="url" appInputVerbatim>
|
||||||
|
<label for="currentUris{{i}}" class="sr-only">
|
||||||
|
{{'currentUri' | i18n}} {{(i + 1)}}
|
||||||
|
</label>
|
||||||
|
<select *ngIf="currentUris && currentUris.length" id="currentUris{{i}}"
|
||||||
|
name="currentUris{{i}}" [(ngModel)]="domain.uri" [hidden]="!domain.showCurrentUris">
|
||||||
|
<option [ngValue]="null">-- {{'select' | i18n}} --</option>
|
||||||
|
<option *ngFor="let u of currentUris" [ngValue]="u">{{u}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="action-buttons">
|
||||||
|
<a *ngIf="currentUris && currentUris.length" class="row-btn" href="#" appStopClick
|
||||||
|
appBlurClick appA11yTitle="{{'toggleCurrentUris' | i18n}}" (click)="toggleUriInput(domain)">
|
||||||
|
<i aria-hidden="true" class="fa fa-lg fa-list"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<a href="#" appStopClick appBlurClick (click)="addUri()"
|
||||||
|
class="box-content-row box-content-row-newmulti">
|
||||||
|
<i class="fa fa-plus-circle fa-fw fa-lg" aria-hidden="true"></i> {{'newUri' | i18n}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="box-footer">
|
||||||
|
{{'excludedDomainsDesc' | i18n}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</content>
|
||||||
|
</form>
|
|
@ -0,0 +1,112 @@
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
NgZone
|
||||||
|
} from '@angular/core';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||||
|
import { ConstantsService } from 'jslib/services/constants.service';
|
||||||
|
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||||
|
|
||||||
|
import { BrowserApi } from '../../browser/browserApi';
|
||||||
|
import { Utils } from 'jslib/misc/utils';
|
||||||
|
|
||||||
|
interface ExcludedDomain {
|
||||||
|
uri: string;
|
||||||
|
showCurrentUris: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BroadcasterSubscriptionId = 'excludedDomains';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-excluded-domains',
|
||||||
|
templateUrl: 'excluded-domains.component.html',
|
||||||
|
})
|
||||||
|
export class ExcludedDomainsComponent implements OnInit, OnDestroy {
|
||||||
|
excludedDomains: ExcludedDomain[] = [];
|
||||||
|
currentUris: string[];
|
||||||
|
loadCurrentUrisTimeout: number;
|
||||||
|
|
||||||
|
constructor(private storageService: StorageService,
|
||||||
|
private i18nService: I18nService, private router: Router,
|
||||||
|
private broadcasterService: BroadcasterService, private ngZone: NgZone,
|
||||||
|
private platformUtilsService: PlatformUtilsService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
async ngOnInit() {
|
||||||
|
const savedDomains = await this.storageService.get<any>(ConstantsService.neverDomainsKey);
|
||||||
|
if (savedDomains) {
|
||||||
|
for (const uri of Object.keys(savedDomains)) {
|
||||||
|
this.excludedDomains.push({ uri: uri, showCurrentUris: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.loadCurrentUris();
|
||||||
|
|
||||||
|
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
||||||
|
this.ngZone.run(async () => {
|
||||||
|
switch (message.command) {
|
||||||
|
case 'tabChanged':
|
||||||
|
case 'windowChanged':
|
||||||
|
if (this.loadCurrentUrisTimeout != null) {
|
||||||
|
window.clearTimeout(this.loadCurrentUrisTimeout);
|
||||||
|
}
|
||||||
|
this.loadCurrentUrisTimeout = window.setTimeout(async () => await this.loadCurrentUris(), 500);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addUri() {
|
||||||
|
this.excludedDomains.push({ uri: '', showCurrentUris: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeUri(i: number) {
|
||||||
|
this.excludedDomains.splice(i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
async submit() {
|
||||||
|
const savedDomains: { [name: string]: null } = {};
|
||||||
|
for (const domain of this.excludedDomains) {
|
||||||
|
if (domain.uri && domain.uri !== '') {
|
||||||
|
const validDomain = Utils.getHostname(domain.uri);
|
||||||
|
if (!validDomain) {
|
||||||
|
this.platformUtilsService.showToast('error', null,
|
||||||
|
this.i18nService.t('excludedDomainsInvalidDomain', domain.uri));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
savedDomains[validDomain] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await this.storageService.save(ConstantsService.neverDomainsKey, savedDomains);
|
||||||
|
this.router.navigate(['/tabs/settings']);
|
||||||
|
}
|
||||||
|
|
||||||
|
trackByFunction(index: number, item: any) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleUriInput(domain: ExcludedDomain) {
|
||||||
|
domain.showCurrentUris = !domain.showCurrentUris;
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadCurrentUris() {
|
||||||
|
const tabs = await BrowserApi.tabsQuery({ windowType: 'normal' });
|
||||||
|
if (tabs) {
|
||||||
|
const uriSet = new Set(tabs.map((tab) => Utils.getHostname(tab.url)));
|
||||||
|
uriSet.delete(null);
|
||||||
|
this.currentUris = Array.from(uriSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,10 @@
|
||||||
<div class="row-main">{{'sync' | i18n}}</div>
|
<div class="row-main">{{'sync' | i18n}}</div>
|
||||||
<i class="fa fa-chevron-right fa-lg row-sub-icon" aria-hidden="true"></i>
|
<i class="fa fa-chevron-right fa-lg row-sub-icon" aria-hidden="true"></i>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="box-content-row box-content-row-flex text-default" routerLink="/excluded-domains">
|
||||||
|
<div class="row-main">{{'excludedDomains' | i18n}}</div>
|
||||||
|
<i class="fa fa-chevron-right fa-lg row-sub-icon" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box list">
|
<div class="box list">
|
||||||
|
|
Loading…
Reference in New Issue