Send layout & search
This commit is contained in:
parent
62a43e536c
commit
6e49c481f0
2
jslib
2
jslib
|
@ -1 +1 @@
|
||||||
Subproject commit d1c46e6bdc9332bcf47acbd235c3a6278e086d8a
|
Subproject commit a16d8f7de7abe63532bcf7452cb7517f9174189a
|
|
@ -15,6 +15,7 @@ import { SsoComponent } from './accounts/sso.component';
|
||||||
import { TwoFactorComponent } from './accounts/two-factor.component';
|
import { TwoFactorComponent } from './accounts/two-factor.component';
|
||||||
|
|
||||||
import { VaultComponent } from './vault/vault.component';
|
import { VaultComponent } from './vault/vault.component';
|
||||||
|
import { SendComponent } from './send/send.component';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: '', redirectTo: '/vault', pathMatch: 'full' },
|
{ path: '', redirectTo: '/vault', pathMatch: 'full' },
|
||||||
|
@ -30,6 +31,11 @@ const routes: Routes = [
|
||||||
{ path: 'hint', component: HintComponent },
|
{ path: 'hint', component: HintComponent },
|
||||||
{ path: 'set-password', component: SetPasswordComponent },
|
{ path: 'set-password', component: SetPasswordComponent },
|
||||||
{ path: 'sso', component: SsoComponent },
|
{ path: 'sso', component: SsoComponent },
|
||||||
|
{
|
||||||
|
path: 'send',
|
||||||
|
component: SendComponent,
|
||||||
|
canActivate: [AuthGuardService],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { AppRoutingModule } from './app-routing.module';
|
||||||
import { ServicesModule } from './services.module';
|
import { ServicesModule } from './services.module';
|
||||||
|
|
||||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||||
|
import { DatePipe } from '@angular/common';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
@ -62,6 +63,10 @@ import { ShareComponent } from './vault/share.component';
|
||||||
import { VaultComponent } from './vault/vault.component';
|
import { VaultComponent } from './vault/vault.component';
|
||||||
import { ViewComponent } from './vault/view.component';
|
import { ViewComponent } from './vault/view.component';
|
||||||
|
|
||||||
|
import { AccessComponent } from './send/access.component';
|
||||||
|
import { AddEditComponent as SendAddEditComponent } from './send/add-edit.component';
|
||||||
|
import { SendComponent } from './send/send.component';
|
||||||
|
|
||||||
import { registerLocaleData } from '@angular/common';
|
import { registerLocaleData } from '@angular/common';
|
||||||
import localeBe from '@angular/common/locales/be';
|
import localeBe from '@angular/common/locales/be';
|
||||||
import localeBg from '@angular/common/locales/bg';
|
import localeBg from '@angular/common/locales/bg';
|
||||||
|
@ -155,6 +160,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
A11yTitleDirective,
|
A11yTitleDirective,
|
||||||
|
AccessComponent,
|
||||||
AddEditComponent,
|
AddEditComponent,
|
||||||
ApiActionDirective,
|
ApiActionDirective,
|
||||||
AppComponent,
|
AppComponent,
|
||||||
|
@ -184,6 +190,8 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||||
RegisterComponent,
|
RegisterComponent,
|
||||||
SearchCiphersPipe,
|
SearchCiphersPipe,
|
||||||
SelectCopyDirective,
|
SelectCopyDirective,
|
||||||
|
SendAddEditComponent,
|
||||||
|
SendComponent,
|
||||||
SetPasswordComponent,
|
SetPasswordComponent,
|
||||||
SettingsComponent,
|
SettingsComponent,
|
||||||
ShareComponent,
|
ShareComponent,
|
||||||
|
@ -209,9 +217,10 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
||||||
PremiumComponent,
|
PremiumComponent,
|
||||||
SettingsComponent,
|
SettingsComponent,
|
||||||
ShareComponent,
|
ShareComponent,
|
||||||
|
SendAddEditComponent,
|
||||||
TwoFactorOptionsComponent,
|
TwoFactorOptionsComponent,
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [DatePipe],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule { }
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div class="details">
|
||||||
|
<div clas="content">
|
||||||
|
<div class="inner-content">
|
||||||
|
<p>Under construction</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,14 @@
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
OnInit,
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-send-access',
|
||||||
|
templateUrl: 'access.component.html',
|
||||||
|
})
|
||||||
|
export class AccessComponent implements OnInit {
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
ngOnInit() { }
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<div class="details">
|
||||||
|
<div clas="content">
|
||||||
|
<div class="inner-content">
|
||||||
|
<p>Under construction</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { DatePipe } from '@angular/common';
|
||||||
|
|
||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||||
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
|
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||||
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
import { SendService } from 'jslib/abstractions/send.service';
|
||||||
|
import { UserService } from 'jslib/abstractions/user.service';
|
||||||
|
|
||||||
|
import { AddEditComponent as BaseAddEditComponent } from 'jslib/angular/components/send/add-edit.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-send-add-edit',
|
||||||
|
templateUrl: 'add-edit.component.html',
|
||||||
|
})
|
||||||
|
export class AddEditComponent extends BaseAddEditComponent {
|
||||||
|
constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
|
||||||
|
environmentService: EnvironmentService, datePipe: DatePipe,
|
||||||
|
sendService: SendService, userService: UserService,
|
||||||
|
messagingService: MessagingService) {
|
||||||
|
super(i18nService, platformUtilsService, environmentService,
|
||||||
|
datePipe, sendService, userService, messagingService);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
<div id="sends" class="vault">
|
||||||
|
<div class="groupings">
|
||||||
|
<div class="mac-bar"></div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="inner-content">
|
||||||
|
<div class="top-content">
|
||||||
|
<h2 class="sr-only">{{'filters' | i18n}}</h2>
|
||||||
|
<ul>
|
||||||
|
<li [ngClass]="{active: selectedAll}">
|
||||||
|
<a href="#" appStopClick appBlurClick (click)="selectAll()">
|
||||||
|
<i class="fa fa-fw fa-th" aria-hidden="true"></i> {{'allSends' | i18n}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<h2>{{'types' | i18n}}</h2>
|
||||||
|
<ul>
|
||||||
|
<li [ngClass]="{active: selectedType === sendType.Text}">
|
||||||
|
<a href="#" appStopClick appBlurClick (click)="selectType(sendType.Text)">
|
||||||
|
<i class="fa fa-fw fa-file-text-o" aria-hidden="true"></i> {{'sendTypeText' | i18n}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li [ngClass]="{active: selectedType === sendType.File}">
|
||||||
|
<a href="#" appStopClick appBlurClick (click)="selectType(sendType.File)">
|
||||||
|
<i class="fa fa-fw fa-file-o" aria-hidden="true"></i> {{'sendTypeFile' | i18n}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-content">
|
||||||
|
<a routerLink="/" class="fa fa-lock btn primary icon-link" title="Bitwarden Vault"></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="items" class="items">
|
||||||
|
<div class="header header-search">
|
||||||
|
<div class="search">
|
||||||
|
<input type="search" placeholder="{{'searchSends' | i18n}}" id="search"
|
||||||
|
[(ngModel)]="searchText" (input)="searchTextChanged()" autocomplete="off" appAutofocus>
|
||||||
|
<i class="fa fa-search" aria-hidden="true"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<div class="list" *ngIf="filteredSends.length" infiniteScroll [infiniteScrollDistance]="1"
|
||||||
|
[infiniteScrollContainer]="'#items .content'" [fromRoot]="true" (scrolled)="loadMore()">
|
||||||
|
<a *ngFor="let s of filteredSends" appStopClick (click)="selectSend(s)"
|
||||||
|
href="#" title="{{'viewItem' | i18n}}"
|
||||||
|
[ngClass]="{'active': s.id === activeSendId}">
|
||||||
|
<div class="icon" aria-hidden="true">
|
||||||
|
<i class="fa fa-fw fa-lg" [ngClass]="s.type == 0 ? 'fa-file-o' : 'fa-file-text-o'"></i>
|
||||||
|
</div>
|
||||||
|
<span class="text">
|
||||||
|
{{s.name}}
|
||||||
|
</span>
|
||||||
|
<span class="detail">{{s.deletionDate | date}}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="no-items" *ngIf="!filteredSends.length">
|
||||||
|
<i class="fa fa-spinner fa-spin fa-3x" *ngIf="!loaded" aria-hidden="true"></i>
|
||||||
|
<ng-container *ngIf="loaded">
|
||||||
|
<i class="fa fa-frown-o fa-4x" aria-hidden="true"></i>
|
||||||
|
<p>{{'noItemsInList' | i18n}}</p>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<button appBlurClick (click)="addSend()" class="block primary" appA11yTitle="{{'addItem' | i18n}}">
|
||||||
|
<i class="fa fa-plus fa-lg" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-send-add-edit *ngIf="action == 'add' || action == 'edit'"></app-send-add-edit>
|
||||||
|
<div class="logo" *ngIf="!action">
|
||||||
|
<div class="content">
|
||||||
|
<div class="inner-content">
|
||||||
|
<img class="logo-image" alt="Bitwarden" aria-hidden="true" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,126 @@
|
||||||
|
import {
|
||||||
|
Component,
|
||||||
|
NgZone,
|
||||||
|
OnInit,
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
import {
|
||||||
|
ActivatedRoute ,
|
||||||
|
Router,
|
||||||
|
} from '@angular/router';
|
||||||
|
|
||||||
|
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||||
|
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||||
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
|
import { SearchService } from 'jslib/abstractions/search.service';
|
||||||
|
import { SendService } from 'jslib/abstractions/send.service';
|
||||||
|
|
||||||
|
import { ModalComponent } from 'jslib/angular/components/modal.component';
|
||||||
|
import { SendComponent as BaseSendComponent } from 'jslib/angular/components/send/send.component';
|
||||||
|
|
||||||
|
import { BroadcasterService } from 'jslib/angular/services/broadcaster.service';
|
||||||
|
|
||||||
|
import { SendType } from 'jslib/enums/sendType';
|
||||||
|
import { SendView } from 'jslib/models/view/sendView';
|
||||||
|
|
||||||
|
enum Action {
|
||||||
|
None = '',
|
||||||
|
Add = 'add',
|
||||||
|
Edit = 'edit',
|
||||||
|
View = 'view',
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-send',
|
||||||
|
templateUrl: 'send.component.html',
|
||||||
|
})
|
||||||
|
export class SendComponent extends BaseSendComponent implements OnInit {
|
||||||
|
sendId: string;
|
||||||
|
modal: ModalComponent = null;
|
||||||
|
action: Action = Action.None;
|
||||||
|
|
||||||
|
constructor(sendService: SendService, i18nService: I18nService,
|
||||||
|
platformUtilsService: PlatformUtilsService, environmentService: EnvironmentService,
|
||||||
|
broadcasterService: BroadcasterService, ngZone: NgZone,
|
||||||
|
private router: Router, private route: ActivatedRoute, searchService: SearchService) {
|
||||||
|
super(sendService, i18nService, platformUtilsService,
|
||||||
|
environmentService, broadcasterService, ngZone, searchService);
|
||||||
|
}
|
||||||
|
|
||||||
|
async load(filter: (send: SendView) => boolean = null) {
|
||||||
|
this.loading = true;
|
||||||
|
this.sends = await this.sendService.getAllDecrypted();
|
||||||
|
|
||||||
|
this.route.queryParams.subscribe(async (params) => {
|
||||||
|
if (params == null) {
|
||||||
|
this.selectedAll = true;
|
||||||
|
await this.reload();
|
||||||
|
} else {
|
||||||
|
const sendView = new SendView();
|
||||||
|
if (params.sendId) {
|
||||||
|
sendView.id = params.sendId;
|
||||||
|
if (params.action === 'edit') {
|
||||||
|
this.editSend(sendView);
|
||||||
|
} else if (params.action === 'view') {
|
||||||
|
// TODO: this
|
||||||
|
// this.viewSend(sendView);
|
||||||
|
}
|
||||||
|
} else if (params.action === 'add') {
|
||||||
|
this.addSend();
|
||||||
|
} else {
|
||||||
|
if (params.files) {
|
||||||
|
sendView.type = SendType.File;
|
||||||
|
this.filter = (s) => {
|
||||||
|
return filter(s) && s.text != null;
|
||||||
|
};
|
||||||
|
this.filter(sendView);
|
||||||
|
} else if (params.text) {
|
||||||
|
sendView.type = SendType.Text;
|
||||||
|
this.filter = (s) => {
|
||||||
|
return filter(s) && s.file != null;
|
||||||
|
};
|
||||||
|
this.filter(sendView);
|
||||||
|
} else {
|
||||||
|
this.selectAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
|
this.loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
addSend() {
|
||||||
|
if (this.action === Action.Add) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.action = Action.Add;
|
||||||
|
this.sendId = null;
|
||||||
|
this.go();
|
||||||
|
}
|
||||||
|
|
||||||
|
editSend(send: SendView) {
|
||||||
|
if (this.action === Action.Edit && this.sendId === send.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.action = Action.Edit;
|
||||||
|
this.sendId = send.id;
|
||||||
|
this.go();
|
||||||
|
}
|
||||||
|
|
||||||
|
private go(queryParams: any = null) {
|
||||||
|
if (queryParams == null) {
|
||||||
|
queryParams = {
|
||||||
|
id: this.sendId,
|
||||||
|
action: this.action,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.router.navigate([], {
|
||||||
|
relativeTo: this.route,
|
||||||
|
queryParams: queryParams,
|
||||||
|
replaceUrl: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,101 +1,106 @@
|
||||||
<div class="mac-bar"></div>
|
<div class="mac-bar"></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="inner-content">
|
<div class="inner-content">
|
||||||
<h2 class="sr-only">{{'filters' | i18n}}</h2>
|
<div class="top-content">
|
||||||
<ul>
|
<h2 class="sr-only">{{'filters' | i18n}}</h2>
|
||||||
<li [ngClass]="{active: selectedAll}">
|
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectAll()">
|
|
||||||
<i class="fa fa-fw fa-th" aria-hidden="true"></i> {{'allItems' | i18n}}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li [ngClass]="{active: selectedFavorites}">
|
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectFavorites()">
|
|
||||||
<i class="fa fa-fw fa-star" aria-hidden="true"></i> {{'favorites' | i18n}}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li [ngClass]="{active: selectedTrash}">
|
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectTrash()">
|
|
||||||
<i class="fa fa-fw fa-trash-o" aria-hidden="true"></i> {{'trash' | i18n}}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h2>{{'types' | i18n}}</h2>
|
|
||||||
<ul>
|
|
||||||
<li [ngClass]="{active: selectedType === cipherType.Login}">
|
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Login)">
|
|
||||||
<i class="fa fa-fw fa-globe" aria-hidden="true"></i> {{'typeLogin' | i18n}}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li [ngClass]="{active: selectedType === cipherType.Card}">
|
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Card)">
|
|
||||||
<i class="fa fa-fw fa-credit-card" aria-hidden="true"></i> {{'typeCard' | i18n}}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li [ngClass]="{active: selectedType === cipherType.Identity}">
|
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Identity)">
|
|
||||||
<i class="fa fa-fw fa-id-card-o" aria-hidden="true"></i> {{'typeIdentity' | i18n}}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li [ngClass]="{active: selectedType === cipherType.SecureNote}">
|
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.SecureNote)">
|
|
||||||
<i class="fa fa-fw fa-sticky-note-o" aria-hidden="true"></i> {{'typeSecureNote' | i18n}}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p *ngIf="!loaded" class="text-muted">{{'loading' | i18n}}</p>
|
|
||||||
<ng-container *ngIf="loaded">
|
|
||||||
<div class="heading">
|
|
||||||
<h2>{{'folders' | i18n}}</h2>
|
|
||||||
<button appBlurClick (click)="addFolder()" appA11yTitle="{{'addFolder' | i18n}}">
|
|
||||||
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<ul>
|
<ul>
|
||||||
<ng-template #recursiveFolders let-folders>
|
<li [ngClass]="{active: selectedAll}">
|
||||||
<li *ngFor="let f of folders"
|
<a href="#" appStopClick appBlurClick (click)="selectAll()">
|
||||||
[ngClass]="{active: selectedFolder && f.node.id === selectedFolderId}">
|
<i class="fa fa-fw fa-th" aria-hidden="true"></i> {{'allItems' | i18n}}
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectFolder(f.node)">
|
</a>
|
||||||
<i *ngIf="f.children.length" class="fa-fw fa" title="{{'toggleCollapse' | i18n}}" aria-hidden="true"
|
</li>
|
||||||
[ngClass]="{'fa-caret-right': isCollapsed(f.node), 'fa-caret-down': !isCollapsed(f.node)}"
|
<li [ngClass]="{active: selectedFavorites}">
|
||||||
(click)="collapse(f.node)" appStopProp></i>
|
<a href="#" appStopClick appBlurClick (click)="selectFavorites()">
|
||||||
<i *ngIf="f.children.length === 0" class="fa-fw fa fa-folder-o" aria-hidden="true"></i>
|
<i class="fa fa-fw fa-star" aria-hidden="true"></i> {{'favorites' | i18n}}
|
||||||
{{f.node.name}}
|
</a>
|
||||||
<span appStopProp appStopClick (click)="editFolder(f.node)" role="button"
|
</li>
|
||||||
appA11yTitle="{{'editFolder' | i18n}}" *ngIf="f.node.id">
|
<li [ngClass]="{active: selectedTrash}">
|
||||||
<i class="fa fa-pencil fa-fw" aria-hidden="true"></i>
|
<a href="#" appStopClick appBlurClick (click)="selectTrash()">
|
||||||
</span>
|
<i class="fa fa-fw fa-trash-o" aria-hidden="true"></i> {{'trash' | i18n}}
|
||||||
</a>
|
</a>
|
||||||
<ul class="fa-ul" *ngIf="f.children.length && !isCollapsed(f.node)">
|
</li>
|
||||||
<ng-container *ngTemplateOutlet="recursiveFolders; context:{ $implicit: f.children }">
|
|
||||||
</ng-container>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ng-template>
|
|
||||||
<ng-container *ngTemplateOutlet="recursiveFolders; context:{ $implicit: nestedFolders }"></ng-container>
|
|
||||||
</ul>
|
</ul>
|
||||||
<div *ngIf="collections && collections.length">
|
<h2>{{'types' | i18n}}</h2>
|
||||||
<h2>{{'collections' | i18n}}</h2>
|
<ul>
|
||||||
|
<li [ngClass]="{active: selectedType === cipherType.Login}">
|
||||||
|
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Login)">
|
||||||
|
<i class="fa fa-fw fa-globe" aria-hidden="true"></i> {{'typeLogin' | i18n}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li [ngClass]="{active: selectedType === cipherType.Card}">
|
||||||
|
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Card)">
|
||||||
|
<i class="fa fa-fw fa-credit-card" aria-hidden="true"></i> {{'typeCard' | i18n}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li [ngClass]="{active: selectedType === cipherType.Identity}">
|
||||||
|
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.Identity)">
|
||||||
|
<i class="fa fa-fw fa-id-card-o" aria-hidden="true"></i> {{'typeIdentity' | i18n}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li [ngClass]="{active: selectedType === cipherType.SecureNote}">
|
||||||
|
<a href="#" appStopClick appBlurClick (click)="selectType(cipherType.SecureNote)">
|
||||||
|
<i class="fa fa-fw fa-sticky-note-o" aria-hidden="true"></i> {{'typeSecureNote' | i18n}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p *ngIf="!loaded" class="text-muted">{{'loading' | i18n}}</p>
|
||||||
|
<ng-container *ngIf="loaded">
|
||||||
|
<div class="heading">
|
||||||
|
<h2>{{'folders' | i18n}}</h2>
|
||||||
|
<button appBlurClick (click)="addFolder()" appA11yTitle="{{'addFolder' | i18n}}">
|
||||||
|
<i class="fa fa-plus fa-fw" aria-hidden="true"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<ng-template #recursiveCollections let-collections>
|
<ng-template #recursiveFolders let-folders>
|
||||||
<li *ngFor="let c of collections" [ngClass]="{active: c.node.id === selectedCollectionId}">
|
<li *ngFor="let f of folders"
|
||||||
<a href="#" appStopClick appBlurClick (click)="selectCollection(c.node)">
|
[ngClass]="{active: selectedFolder && f.node.id === selectedFolderId}">
|
||||||
<i *ngIf="c.children.length" class="fa-fw fa" title="{{'toggleCollapse' | i18n}}" aria-hidden="true"
|
<a href="#" appStopClick appBlurClick (click)="selectFolder(f.node)">
|
||||||
[ngClass]="{'fa-caret-right': isCollapsed(c.node), 'fa-caret-down': !isCollapsed(c.node)}"
|
<i *ngIf="f.children.length" class="fa-fw fa" title="{{'toggleCollapse' | i18n}}" aria-hidden="true"
|
||||||
(click)="collapse(c.node)" appStopProp></i>
|
[ngClass]="{'fa-caret-right': isCollapsed(f.node), 'fa-caret-down': !isCollapsed(f.node)}"
|
||||||
<i *ngIf="c.children.length === 0" class="fa-fw fa fa-cube" aria-hidden="true"></i>
|
(click)="collapse(f.node)" appStopProp></i>
|
||||||
{{c.node.name}}
|
<i *ngIf="f.children.length === 0" class="fa-fw fa fa-folder-o" aria-hidden="true"></i>
|
||||||
|
{{f.node.name}}
|
||||||
|
<span appStopProp appStopClick (click)="editFolder(f.node)" role="button"
|
||||||
|
appA11yTitle="{{'editFolder' | i18n}}" *ngIf="f.node.id">
|
||||||
|
<i class="fa fa-pencil fa-fw" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="fa-ul" *ngIf="c.children.length && !isCollapsed(c.node)">
|
<ul class="fa-ul" *ngIf="f.children.length && !isCollapsed(f.node)">
|
||||||
<ng-container
|
<ng-container *ngTemplateOutlet="recursiveFolders; context:{ $implicit: f.children }">
|
||||||
*ngTemplateOutlet="recursiveCollections; context:{ $implicit: c.children }">
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-container *ngTemplateOutlet="recursiveCollections; context:{ $implicit: nestedCollections }">
|
<ng-container *ngTemplateOutlet="recursiveFolders; context:{ $implicit: nestedFolders }"></ng-container>
|
||||||
</ng-container>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
<div *ngIf="collections && collections.length">
|
||||||
</ng-container>
|
<h2>{{'collections' | i18n}}</h2>
|
||||||
|
<ul>
|
||||||
|
<ng-template #recursiveCollections let-collections>
|
||||||
|
<li *ngFor="let c of collections" [ngClass]="{active: c.node.id === selectedCollectionId}">
|
||||||
|
<a href="#" appStopClick appBlurClick (click)="selectCollection(c.node)">
|
||||||
|
<i *ngIf="c.children.length" class="fa-fw fa" title="{{'toggleCollapse' | i18n}}" aria-hidden="true"
|
||||||
|
[ngClass]="{'fa-caret-right': isCollapsed(c.node), 'fa-caret-down': !isCollapsed(c.node)}"
|
||||||
|
(click)="collapse(c.node)" appStopProp></i>
|
||||||
|
<i *ngIf="c.children.length === 0" class="fa-fw fa fa-cube" aria-hidden="true"></i>
|
||||||
|
{{c.node.name}}
|
||||||
|
</a>
|
||||||
|
<ul class="fa-ul" *ngIf="c.children.length && !isCollapsed(c.node)">
|
||||||
|
<ng-container
|
||||||
|
*ngTemplateOutlet="recursiveCollections; context:{ $implicit: c.children }">
|
||||||
|
</ng-container>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ng-template>
|
||||||
|
<ng-container *ngTemplateOutlet="recursiveCollections; context:{ $implicit: nestedCollections }">
|
||||||
|
</ng-container>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
<div class="bottom-content">
|
||||||
|
<a routerLink="/send" class="fa fa-paper-plane btn primary icon-link" title="Bitwarden Send"></a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
<div id="vault" attr.aria-hidden="{{showingModal}}">
|
<div id="vault" class="vault" attr.aria-hidden="{{showingModal}}">
|
||||||
<app-vault-groupings id="groupings" (onAllClicked)="clearGroupingFilters()" (onFavoritesClicked)="filterFavorites()"
|
<app-vault-groupings id="groupings" class="groupings" (onAllClicked)="clearGroupingFilters()" (onFavoritesClicked)="filterFavorites()"
|
||||||
(onCipherTypeClicked)="filterCipherType($event)" (onFolderClicked)="filterFolder($event.id)"
|
(onCipherTypeClicked)="filterCipherType($event)" (onFolderClicked)="filterFolder($event.id)"
|
||||||
(onAddFolder)="addFolder()" (onEditFolder)="editFolder($event.id)"
|
(onAddFolder)="addFolder()" (onEditFolder)="editFolder($event.id)"
|
||||||
(onCollectionClicked)="filterCollection($event.id)" (onTrashClicked)="filterDeleted()">
|
(onCollectionClicked)="filterCollection($event.id)" (onTrashClicked)="filterDeleted()">
|
||||||
</app-vault-groupings>
|
</app-vault-groupings>
|
||||||
<app-vault-ciphers id="items" [activeCipherId]="cipherId" (onCipherClicked)="viewCipher($event)"
|
<app-vault-ciphers id="items" class="items" [activeCipherId]="cipherId" (onCipherClicked)="viewCipher($event)"
|
||||||
(onCipherRightClicked)="viewCipherMenu($event)" (onAddCipher)="addCipher($event)"
|
(onCipherRightClicked)="viewCipherMenu($event)" (onAddCipher)="addCipher($event)"
|
||||||
(onAddCipherOptions)="addCipherOptions()">
|
(onAddCipherOptions)="addCipherOptions()">
|
||||||
</app-vault-ciphers>
|
</app-vault-ciphers>
|
||||||
<app-vault-view id="details" *ngIf="cipherId && action === 'view'" [cipherId]="cipherId"
|
<app-vault-view id="details" class="details" *ngIf="cipherId && action === 'view'" [cipherId]="cipherId"
|
||||||
(onCloneCipher)="cloneCipher($event)" (onEditCipher)="editCipher($event)"
|
(onCloneCipher)="cloneCipher($event)" (onEditCipher)="editCipher($event)"
|
||||||
(onViewCipherPasswordHistory)="viewCipherPasswordHistory($event)" (onRestoredCipher)="restoredCipher($event)"
|
(onViewCipherPasswordHistory)="viewCipherPasswordHistory($event)" (onRestoredCipher)="restoredCipher($event)"
|
||||||
(onDeletedCipher)="deletedCipher($event)">
|
(onDeletedCipher)="deletedCipher($event)">
|
||||||
</app-vault-view>
|
</app-vault-view>
|
||||||
<app-vault-add-edit id="details" *ngIf="action === 'add' || action === 'edit' || action === 'clone'"
|
<app-vault-add-edit id="addEdit" class="details" *ngIf="action === 'add' || action === 'edit' || action === 'clone'"
|
||||||
[cloneMode]="action === 'clone'"
|
[cloneMode]="action === 'clone'"
|
||||||
[folderId]="action === 'add' && folderId !== 'none' ? folderId : null"
|
[folderId]="action === 'add' && folderId !== 'none' ? folderId : null"
|
||||||
[organizationId]="action === 'add' ? addOrganizationId : null"
|
[organizationId]="action === 'add' ? addOrganizationId : null"
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
(onShareCipher)="shareCipher($event)" (onEditCollections)="cipherCollections($event)"
|
(onShareCipher)="shareCipher($event)" (onEditCollections)="cipherCollections($event)"
|
||||||
(onGeneratePassword)="openPasswordGenerator(true)">
|
(onGeneratePassword)="openPasswordGenerator(true)">
|
||||||
</app-vault-add-edit>
|
</app-vault-add-edit>
|
||||||
<div id="logo" *ngIf="action !== 'add' && action !== 'edit' && action !== 'view' && action !== 'clone'">
|
<div id="logo" class="logo" *ngIf="action !== 'add' && action !== 'edit' && action !== 'view' && action !== 'clone'">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="inner-content">
|
<div class="inner-content">
|
||||||
<img class="logo-image" alt="Bitwarden" aria-hidden="true" />
|
<img class="logo-image" alt="Bitwarden" aria-hidden="true" />
|
||||||
|
|
|
@ -1497,5 +1497,18 @@
|
||||||
},
|
},
|
||||||
"personalOwnershipPolicyInEffect": {
|
"personalOwnershipPolicyInEffect": {
|
||||||
"message": "An organization policy is affecting your ownership options."
|
"message": "An organization policy is affecting your ownership options."
|
||||||
|
},
|
||||||
|
"allSends": {
|
||||||
|
"message": "All Sends"
|
||||||
|
},
|
||||||
|
"sendTypeFile": {
|
||||||
|
"message": "File"
|
||||||
|
},
|
||||||
|
"sendTypeText": {
|
||||||
|
"message": "Text"
|
||||||
|
},
|
||||||
|
"searchSends": {
|
||||||
|
"message": "Search Sends",
|
||||||
|
"description": "'Send' is a noun and the name of a feature called 'Bitwarden Send'. It should not be translated."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@import "variables.scss";
|
@import "variables.scss";
|
||||||
|
|
||||||
.btn, #vault .footer button, .modal-footer button {
|
.btn, .vault .footer button, .modal-footer button {
|
||||||
border-radius: $border-radius;
|
border-radius: $border-radius;
|
||||||
padding: 7px 15px;
|
padding: 7px 15px;
|
||||||
border: 1px solid #000000;
|
border: 1px solid #000000;
|
||||||
|
@ -77,6 +77,16 @@
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.icon-link {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
margin: 5px 2px;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 45px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
|
|
|
@ -33,7 +33,7 @@ html.os_macos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#vault .header-search {
|
.vault .header-search {
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
|
|
||||||
input, i {
|
input, i {
|
||||||
|
@ -41,12 +41,12 @@ html.os_macos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#vault .mac-bar {
|
.vault .mac-bar {
|
||||||
height: 48px;
|
height: 48px;
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
}
|
}
|
||||||
|
|
||||||
#vault > #groupings > .content > .inner-content {
|
.vault > .groupings > .content > .inner-content {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
@import "variables.scss";
|
@import "variables.scss";
|
||||||
|
|
||||||
#vault {
|
.vault {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
> #groupings, > #items, > #details, > #logo {
|
> .groupings, > .items, > .details, > .logo {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> #groupings {
|
> .groupings {
|
||||||
width: 22%;
|
width: 22%;
|
||||||
min-width: 175px;
|
min-width: 175px;
|
||||||
max-width: 250px;
|
max-width: 250px;
|
||||||
|
@ -25,7 +25,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.inner-content {
|
.inner-content {
|
||||||
padding-bottom: 0;
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
justify-content: space-between;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
|
@ -254,7 +258,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> #items {
|
> .items {
|
||||||
width: 28%;
|
width: 28%;
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
max-width: 350px;
|
max-width: 350px;
|
||||||
|
@ -284,7 +288,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> #details {
|
> .details {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
|
@ -316,7 +320,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> #logo {
|
> .logo {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue