page ciphers list for better performance

This commit is contained in:
Kyle Spearrin 2019-03-19 11:34:56 -04:00
parent 8231b6f09f
commit f02debb03b
8 changed files with 293 additions and 14 deletions

2
jslib

@ -1 +1 @@
Subproject commit c02d6f3f6c7f63e6426517383b3e0a0ac8a5cb18
Subproject commit d8f9177c03549667cf6d1e5f30536d010acc7b7d

269
package-lock.json generated
View File

@ -1056,6 +1056,12 @@
"ansi-wrap": "^0.1.0"
}
},
"ansi-escapes": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
"integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
"dev": true
},
"ansi-gray": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
@ -1517,6 +1523,35 @@
}
}
},
"babel-polyfill": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz",
"integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=",
"dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"core-js": "^2.4.0",
"regenerator-runtime": "^0.10.0"
}
},
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"dev": true,
"requires": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
},
"dependencies": {
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
"dev": true
}
}
},
"bach": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz",
@ -2083,6 +2118,12 @@
"supports-color": "^4.0.0"
}
},
"chardet": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
"dev": true
},
"chokidar": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
@ -2212,6 +2253,12 @@
"integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==",
"dev": true
},
"cli-width": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
"dev": true
},
"cliui": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
@ -4188,6 +4235,15 @@
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
"dev": true
},
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
"dev": true,
"requires": {
"iconv-lite": "~0.4.13"
}
},
"end-of-stream": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
@ -4451,6 +4507,17 @@
}
}
},
"external-editor": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
"dev": true,
"requires": {
"chardet": "^0.4.0",
"iconv-lite": "^0.4.17",
"tmp": "^0.0.33"
}
},
"extglob": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
@ -4545,6 +4612,15 @@
"integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==",
"dev": true
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5"
}
},
"file-loader": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-2.0.0.tgz",
@ -6872,6 +6948,87 @@
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"inquirer": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz",
"integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=",
"dev": true,
"requires": {
"ansi-escapes": "^1.1.0",
"chalk": "^1.0.0",
"cli-cursor": "^2.1.0",
"cli-width": "^2.0.0",
"external-editor": "^2.0.1",
"figures": "^2.0.0",
"lodash": "^4.3.0",
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
"rx": "^4.1.0",
"string-width": "^2.0.0",
"strip-ansi": "^3.0.0",
"through": "^2.3.6"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"dev": true,
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
},
"dependencies": {
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
"ansi-regex": "^3.0.0"
}
}
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
}
}
},
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
@ -7124,6 +7281,12 @@
"integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
"dev": true
},
"is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
"dev": true
},
"is-redirect": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
@ -8288,6 +8451,12 @@
"integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==",
"dev": true
},
"mute-stream": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
"dev": true
},
"nan": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz",
@ -8344,6 +8513,15 @@
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
"dev": true
},
"ngx-infinite-scroll": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-7.0.1.tgz",
"integrity": "sha512-be9DAAuabV7VGI06/JUnS6pXC6mcBOzA4+SBCwOcP9WwJ2r5GjdZyOa34ls9hi1MnCOj3zrXLvPKQ/UDp6csIw==",
"dev": true,
"requires": {
"opencollective": "^1.0.3"
}
},
"nice-try": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz",
@ -8367,6 +8545,16 @@
"semver": "^5.4.1"
}
},
"node-fetch": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz",
"integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=",
"dev": true,
"requires": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
}
},
"node-forge": {
"version": "0.7.6",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz",
@ -8817,6 +9005,57 @@
"mimic-fn": "^1.0.0"
}
},
"opencollective": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz",
"integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=",
"dev": true,
"requires": {
"babel-polyfill": "6.23.0",
"chalk": "1.1.3",
"inquirer": "3.0.6",
"minimist": "1.2.0",
"node-fetch": "1.6.3",
"opn": "4.0.2"
},
"dependencies": {
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
}
}
},
"opn": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz",
"integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=",
"dev": true,
"requires": {
"object-assign": "^4.0.1",
"pinkie-promise": "^2.0.0"
}
},
"ora": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/ora/-/ora-1.4.0.tgz",
@ -9749,6 +9988,12 @@
"integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==",
"dev": true
},
"regenerator-runtime": {
"version": "0.10.5",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
"dev": true
},
"regex-cache": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
@ -10029,6 +10274,15 @@
"inherits": "^2.0.1"
}
},
"run-async": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
"integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
"dev": true,
"requires": {
"is-promise": "^2.1.0"
}
},
"run-queue": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
@ -10038,6 +10292,12 @@
"aproba": "^1.1.1"
}
},
"rx": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz",
"integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=",
"dev": true
},
"rxjs": {
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
@ -11254,6 +11514,15 @@
"setimmediate": "^1.0.4"
}
},
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
"dev": true,
"requires": {
"os-tmpdir": "~1.0.2"
}
},
"to-absolute-glob": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",

View File

@ -215,6 +215,7 @@
"gulp-google-webfonts": "^2.0.0",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"ngx-infinite-scroll": "7.0.1",
"node-abi": "^2.5.1",
"node-loader": "^0.6.0",
"node-sass": "^4.9.3",

View File

@ -4,6 +4,7 @@ import 'zone.js/dist/zone';
import { ToasterModule } from 'angular2-toaster';
import { Angulartics2Module } from 'angulartics2';
import { Angulartics2GoogleAnalytics } from 'angulartics2/ga';
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
import { AppRoutingModule } from './app-routing.module';
import { ServicesModule } from './services.module';
@ -136,6 +137,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
},
}),
ToasterModule.forRoot(),
InfiniteScrollModule,
],
declarations: [
AddEditComponent,

View File

@ -6,10 +6,13 @@
</div>
</div>
<div class="content">
<ng-container *ngIf="ciphers">
<div class="list" *ngIf="ciphers.length > 0">
<a *ngFor="let c of ciphers" appStopClick (click)="selectCipher(c)" (contextmenu)="rightClickCipher(c)"
href="#" title="{{'viewItem' | i18n}}" [ngClass]="{'active': c.id === activeCipherId}">
<ng-container *ngIf="(isPaging() ? pagedCiphers : ciphers) as filteredCiphers">
<div class="list" *ngIf="filteredCiphers.length" infiniteScroll [infiniteScrollDistance]="1"
[infiniteScrollContainer]="'#items .content'" [fromRoot]="true" [infiniteScrollDisabled]="!isPaging()"
(scrolled)="loadMore()">
<a *ngFor="let c of filteredCiphers" appStopClick (click)="selectCipher(c)"
(contextmenu)="rightClickCipher(c)" href="#" title="{{'viewItem' | i18n}}"
[ngClass]="{'active': c.id === activeCipherId}">
<app-vault-icon [cipher]="c"></app-vault-icon>
<span class="text">
{{c.name}}
@ -19,7 +22,7 @@
<span class="detail">{{c.subTitle}}</span>
</a>
</div>
<div class="no-items" *ngIf="ciphers.length === 0">
<div class="no-items" *ngIf="!filteredCiphers.length">
<i class="fa fa-spinner fa-spin fa-3x" *ngIf="!loaded"></i>
<ng-container *ngIf="loaded">
<i class="fa fa-frown-o fa-4x"></i>

View File

@ -11,5 +11,6 @@ import { CiphersComponent as BaseCiphersComponent } from 'jslib/angular/componen
export class CiphersComponent extends BaseCiphersComponent {
constructor(searchService: SearchService) {
super(searchService);
this.pageSize = 250;
}
}

View File

@ -7,7 +7,9 @@
{{'share' | i18n}}
</div>
<div class="box-content" *ngIf="!organizations || !organizations.length">
{{'noOrganizationsList' | i18n}}
<div class="box-content-row">
{{'noOrganizationsList' | i18n}}
</div>
</div>
<div class="box-content" *ngIf="organizations && organizations.length">
<div class="box-content-row" appBoxRow>

View File

@ -168,7 +168,7 @@ export class VaultComponent implements OnInit, OnDestroy {
if (params == null) {
this.groupingsComponent.selectedAll = true;
await this.ciphersComponent.load();
await this.ciphersComponent.reload();
} else {
if (params.cipherId) {
const cipherView = new CipherView();
@ -198,7 +198,7 @@ export class VaultComponent implements OnInit, OnDestroy {
await this.filterCollection(params.collectionId);
} else {
this.groupingsComponent.selectedAll = true;
await this.ciphersComponent.load();
await this.ciphersComponent.reload();
}
}
if (queryParamsSub != null) {
@ -422,14 +422,14 @@ export class VaultComponent implements OnInit, OnDestroy {
async clearGroupingFilters() {
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchVault');
await this.ciphersComponent.load();
await this.ciphersComponent.reload();
this.clearFilters();
this.go();
}
async filterFavorites() {
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchFavorites');
await this.ciphersComponent.load((c) => c.favorite);
await this.ciphersComponent.reload((c) => c.favorite);
this.clearFilters();
this.favorites = true;
this.go();
@ -437,7 +437,7 @@ export class VaultComponent implements OnInit, OnDestroy {
async filterCipherType(type: CipherType) {
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchType');
await this.ciphersComponent.load((c) => c.type === type);
await this.ciphersComponent.reload((c) => c.type === type);
this.clearFilters();
this.type = type;
this.go();
@ -446,7 +446,7 @@ export class VaultComponent implements OnInit, OnDestroy {
async filterFolder(folderId: string) {
folderId = folderId === 'none' ? null : folderId;
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchFolder');
await this.ciphersComponent.load((c) => c.folderId === folderId);
await this.ciphersComponent.reload((c) => c.folderId === folderId);
this.clearFilters();
this.folderId = folderId == null ? 'none' : folderId;
this.go();
@ -454,7 +454,8 @@ export class VaultComponent implements OnInit, OnDestroy {
async filterCollection(collectionId: string) {
this.ciphersComponent.searchPlaceholder = this.i18nService.t('searchCollection');
await this.ciphersComponent.load((c) => c.collectionIds != null && c.collectionIds.indexOf(collectionId) > -1);
await this.ciphersComponent.reload((c) => c.collectionIds != null &&
c.collectionIds.indexOf(collectionId) > -1);
this.clearFilters();
this.collectionId = collectionId;
this.updateCollectionProperties();