Send layout & search

This commit is contained in:
addison 2021-02-03 16:24:49 -05:00
parent 62a43e536c
commit 6e49c481f0
15 changed files with 413 additions and 106 deletions

2
jslib

@ -1 +1 @@
Subproject commit d1c46e6bdc9332bcf47acbd235c3a6278e086d8a Subproject commit a16d8f7de7abe63532bcf7452cb7517f9174189a

View File

@ -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({

View File

@ -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 { }

View File

@ -0,0 +1,7 @@
<div class="details">
<div clas="content">
<div class="inner-content">
<p>Under construction</p>
</div>
</div>
</div>

View File

@ -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() { }
}

View File

@ -0,0 +1,7 @@
<div class="details">
<div clas="content">
<div class="inner-content">
<p>Under construction</p>
</div>
</div>
</div>

View File

@ -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);
}
}

View File

@ -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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>

View File

@ -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,
});
}
}

View File

@ -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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'favorites' | i18n}}
&nbsp;{{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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>&nbsp;{{'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>
&nbsp;{{c.node.name}} <i *ngIf="f.children.length === 0" class="fa-fw fa fa-folder-o" aria-hidden="true"></i>
&nbsp;{{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>
&nbsp;{{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>

View File

@ -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" />

View File

@ -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."
} }
} }

View File

@ -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 {

View File

@ -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;
} }
} }

View File

@ -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;