1
0
mirror of https://github.com/xuthus83/pigallery2.git synced 2025-01-14 14:43:17 +08:00

Fixing settings bugs, adding max number of thumbnail rendering thread settings

This commit is contained in:
Patrik J. Braun 2018-11-02 16:24:37 +01:00
parent fd74f761dc
commit 90c04b7f6b
20 changed files with 196 additions and 82 deletions

View File

@ -3,13 +3,14 @@ import {ErrorCodes, ErrorDTO} from '../../common/entities/Error';
import {ObjectManagerRepository} from '../model/ObjectManagerRepository'; import {ObjectManagerRepository} from '../model/ObjectManagerRepository';
import {Logger} from '../Logger'; import {Logger} from '../Logger';
import {SQLConnection} from '../model/sql/SQLConnection'; import {SQLConnection} from '../model/sql/SQLConnection';
import {DataBaseConfig, DatabaseType, IndexingConfig, ThumbnailConfig} from '../../common/config/private/IPrivateConfig'; import {DataBaseConfig, DatabaseType, IndexingConfig, IPrivateConfig, ThumbnailConfig} from '../../common/config/private/IPrivateConfig';
import {Config} from '../../common/config/private/Config'; import {Config} from '../../common/config/private/Config';
import {ConfigDiagnostics} from '../model/ConfigDiagnostics'; import {ConfigDiagnostics} from '../model/ConfigDiagnostics';
import {ClientConfig} from '../../common/config/public/ConfigClass'; import {ClientConfig} from '../../common/config/public/ConfigClass';
import {BasicConfigDTO} from '../../common/entities/settings/BasicConfigDTO'; import {BasicConfigDTO} from '../../common/entities/settings/BasicConfigDTO';
import {OtherConfigDTO} from '../../common/entities/settings/OtherConfigDTO'; import {OtherConfigDTO} from '../../common/entities/settings/OtherConfigDTO';
import {ProjectPath} from '../ProjectPath'; import {ProjectPath} from '../ProjectPath';
import {PrivateConfigClass} from '../../common/config/private/PrivateConfigClass';
const LOG_TAG = '[AdminMWs]'; const LOG_TAG = '[AdminMWs]';
@ -244,18 +245,21 @@ export class AdminMWs {
try { try {
const settings: OtherConfigDTO = req.body.settings; const settings: OtherConfigDTO = req.body.settings;
Config.Client.enableCache = settings.enableCache; Config.Client.Other.enableCache = settings.Client.enableCache;
Config.Client.enableOnScrollRendering = settings.enableOnScrollRendering; Config.Client.Other.enableOnScrollRendering = settings.Client.enableOnScrollRendering;
Config.Client.enableOnScrollThumbnailPrioritising = settings.enableOnScrollThumbnailPrioritising; Config.Client.Other.enableOnScrollThumbnailPrioritising = settings.Client.enableOnScrollThumbnailPrioritising;
Config.Client.defaultPhotoSortingMethod = settings.defaultPhotoSortingMethod; Config.Client.Other.defaultPhotoSortingMethod = settings.Client.defaultPhotoSortingMethod;
Config.Client.Other.NavBar.showItemCount = settings.Client.NavBar.showItemCount;
// only updating explicitly set config (not saving config set by the diagnostics) // only updating explicitly set config (not saving config set by the diagnostics)
const original = Config.original(); const original: PrivateConfigClass = Config.original();
original.Client.enableCache = settings.enableCache; original.Client.Other.enableCache = settings.Client.enableCache;
original.Client.enableOnScrollRendering = settings.enableOnScrollRendering; original.Client.Other.enableOnScrollRendering = settings.Client.enableOnScrollRendering;
original.Client.enableOnScrollThumbnailPrioritising = settings.enableOnScrollThumbnailPrioritising; original.Client.Other.enableOnScrollThumbnailPrioritising = settings.Client.enableOnScrollThumbnailPrioritising;
original.Client.defaultPhotoSortingMethod = settings.defaultPhotoSortingMethod; original.Client.Other.defaultPhotoSortingMethod = settings.Client.defaultPhotoSortingMethod;
original.Server.enableThreading = settings.enableThreading; original.Client.Other.NavBar.showItemCount = settings.Client.NavBar.showItemCount;
original.Server.threading.enable = settings.Server.enable;
original.Server.threading.thumbnailThreads = settings.Server.thumbnailThreads;
original.save(); original.save();
await ConfigDiagnostics.runDiagnostics(); await ConfigDiagnostics.runDiagnostics();
Logger.info(LOG_TAG, 'new config:'); Logger.info(LOG_TAG, 'new config:');

View File

@ -26,18 +26,22 @@ export class ThumbnailGeneratorMWs {
} }
if (Config.Server.enableThreading === true || if (Config.Server.threading.enable === true ||
Config.Server.thumbnail.processingLibrary !== ThumbnailProcessingLib.Jimp) { Config.Server.thumbnail.processingLibrary !== ThumbnailProcessingLib.Jimp) {
Config.Client.concurrentThumbnailGenerations = Math.max(1, os.cpus().length - 1); if (Config.Server.threading.thumbnailThreads > 0) {
Config.Client.Thumbnail.concurrentThumbnailGenerations = Config.Server.threading.thumbnailThreads;
} else {
Config.Client.Thumbnail.concurrentThumbnailGenerations = Math.max(1, os.cpus().length - 1);
}
} else { } else {
Config.Client.concurrentThumbnailGenerations = 1; Config.Client.Thumbnail.concurrentThumbnailGenerations = 1;
} }
if (Config.Server.enableThreading === true && if (Config.Server.threading.enable === true &&
Config.Server.thumbnail.processingLibrary === ThumbnailProcessingLib.Jimp) { Config.Server.thumbnail.processingLibrary === ThumbnailProcessingLib.Jimp) {
this.taskQue = new ThumbnailTH(Config.Client.concurrentThumbnailGenerations); this.taskQue = new ThumbnailTH(Config.Client.Thumbnail.concurrentThumbnailGenerations);
} else { } else {
this.taskQue = new TaskQue(Config.Client.concurrentThumbnailGenerations); this.taskQue = new TaskQue(Config.Client.Thumbnail.concurrentThumbnailGenerations);
} }
this.initDone = true; this.initDone = true;

View File

@ -11,7 +11,7 @@ export class DiskManager {
static threadPool: DiskManagerTH = null; static threadPool: DiskManagerTH = null;
public static init() { public static init() {
if (Config.Server.enableThreading === true) { if (Config.Server.threading.enable === true) {
DiskManager.threadPool = new DiskManagerTH(1); DiskManager.threadPool = new DiskManagerTH(1);
} }
} }
@ -22,7 +22,7 @@ export class DiskManager {
let directory: DirectoryDTO = null; let directory: DirectoryDTO = null;
if (Config.Server.enableThreading === true) { if (Config.Server.threading.enable === true) {
directory = await DiskManager.threadPool.execute(relativeDirectoryName); directory = await DiskManager.threadPool.execute(relativeDirectoryName);
} else { } else {
directory = await DiskMangerWorker.scanDirectory(relativeDirectoryName); directory = await DiskMangerWorker.scanDirectory(relativeDirectoryName);

View File

@ -29,6 +29,22 @@ export class Utils {
} }
/**
*
* @param from
* @param to inclusive
* @returns {Array}
*/
static createRange(from: number, to: number): Array<number> {
const arr = new Array(to - from + 1);
let c = to - from + 1;
while (c--) {
arr[c] = to--;
}
return arr;
}
static concatUrls(...args: Array<string>) { static concatUrls(...args: Array<string>) {
let url = ''; let url = '';
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {

View File

@ -51,12 +51,17 @@ export interface IndexingConfig {
reIndexingSensitivity: ReIndexingSensitivity; reIndexingSensitivity: ReIndexingSensitivity;
} }
export interface ThreadingConfig {
enable: boolean;
thumbnailThreads: number;
}
export interface ServerConfig { export interface ServerConfig {
port: number; port: number;
imagesFolder: string; imagesFolder: string;
thumbnail: ThumbnailConfig; thumbnail: ThumbnailConfig;
threading: ThreadingConfig;
database: DataBaseConfig; database: DataBaseConfig;
enableThreading: boolean;
sharing: SharingConfig; sharing: SharingConfig;
sessionTimeout: number; sessionTimeout: number;
indexing: IndexingConfig; indexing: IndexingConfig;

View File

@ -33,12 +33,15 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
sharing: { sharing: {
updateTimeout: 1000 * 60 * 5 updateTimeout: 1000 * 60 * 5
}, },
threading: {
enable: true,
thumbnailThreads: 0
},
indexing: { indexing: {
folderPreviewSize: 2, folderPreviewSize: 2,
cachedFolderTimeout: 1000 * 60 * 60, cachedFolderTimeout: 1000 * 60 * 60,
reIndexingSensitivity: ReIndexingSensitivity.medium reIndexingSensitivity: ReIndexingSensitivity.medium
}, }
enableThreading: true
}; };
private ConfigLoader: any; private ConfigLoader: any;

View File

@ -28,24 +28,33 @@ export module ClientConfig {
export interface ThumbnailConfig { export interface ThumbnailConfig {
iconSize: number; iconSize: number;
thumbnailSizes: Array<number>; thumbnailSizes: Array<number>;
concurrentThumbnailGenerations: number;
}
export interface NavBarConfig {
showItemCount: boolean;
}
export interface OtherConfig {
enableCache: boolean;
enableOnScrollRendering: boolean;
defaultPhotoSortingMethod: SortingMethods;
enableOnScrollThumbnailPrioritising: boolean;
NavBar: NavBarConfig;
} }
export interface Config { export interface Config {
applicationTitle: string; applicationTitle: string;
publicUrl: string;
urlBase: string;
Thumbnail: ThumbnailConfig; Thumbnail: ThumbnailConfig;
Search: SearchConfig; Search: SearchConfig;
Sharing: SharingConfig; Sharing: SharingConfig;
Map: MapConfig; Map: MapConfig;
RandomPhoto: RandomPhotoConfig; RandomPhoto: RandomPhotoConfig;
concurrentThumbnailGenerations: number; Other: OtherConfig;
enableCache: boolean;
enableOnScrollRendering: boolean;
enableOnScrollThumbnailPrioritising: boolean;
authenticationRequired: boolean; authenticationRequired: boolean;
publicUrl: string;
urlBase: string;
languages: string[]; languages: string[];
defaultPhotoSortingMethod: SortingMethods;
} }
} }
@ -58,6 +67,7 @@ export class PublicConfigClass {
public Client: ClientConfig.Config = { public Client: ClientConfig.Config = {
applicationTitle: 'PiGallery 2', applicationTitle: 'PiGallery 2',
Thumbnail: { Thumbnail: {
concurrentThumbnailGenerations: 1,
thumbnailSizes: [200, 400, 600], thumbnailSizes: [200, 400, 600],
iconSize: 30 iconSize: 30
}, },
@ -81,15 +91,19 @@ export class PublicConfigClass {
RandomPhoto: { RandomPhoto: {
enabled: true enabled: true
}, },
concurrentThumbnailGenerations: 1, Other: {
enableCache: true, enableCache: true,
enableOnScrollRendering: true, enableOnScrollRendering: true,
enableOnScrollThumbnailPrioritising: true, enableOnScrollThumbnailPrioritising: true,
defaultPhotoSortingMethod: SortingMethods.ascDate,
NavBar: {
showItemCount: true
}
},
authenticationRequired: true, authenticationRequired: true,
publicUrl: '', publicUrl: '',
urlBase: '', urlBase: '',
languages: [], languages: []
defaultPhotoSortingMethod: SortingMethods.ascDate
}; };
} }

View File

@ -1,9 +1,7 @@
import {SortingMethods} from '../SortingMethods'; import {ClientConfig} from '../../config/public/ConfigClass';
import {ThreadingConfig} from '../../config/private/IPrivateConfig';
export interface OtherConfigDTO { export interface OtherConfigDTO {
enableCache: boolean; Server: ThreadingConfig;
enableOnScrollRendering: boolean; Client: ClientConfig.OtherConfig;
enableOnScrollThumbnailPrioritising: boolean;
enableThreading: boolean;
defaultPhotoSortingMethod: SortingMethods;
} }

View File

@ -97,7 +97,7 @@ export class GalleryCacheService {
public getDirectory(directoryName: string): DirectoryDTO { public getDirectory(directoryName: string): DirectoryDTO {
if (Config.Client.enableCache === false) { if (Config.Client.Other.enableCache === false) {
return null; return null;
} }
const value = localStorage.getItem(GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directoryName)); const value = localStorage.getItem(GalleryCacheService.CONTENT_PREFIX + Utils.concatUrls(directoryName));
@ -111,7 +111,7 @@ export class GalleryCacheService {
} }
public setDirectory(directory: DirectoryDTO): void { public setDirectory(directory: DirectoryDTO): void {
if (Config.Client.enableCache === false) { if (Config.Client.Other.enableCache === false) {
return; return;
} }
@ -137,7 +137,7 @@ export class GalleryCacheService {
*/ */
public photoUpdated(photo: PhotoDTO): void { public photoUpdated(photo: PhotoDTO): void {
if (Config.Client.enableCache === false) { if (Config.Client.Other.enableCache === false) {
return; return;
} }

View File

@ -26,7 +26,7 @@ export class GalleryService {
private _shareService: ShareService, private _shareService: ShareService,
private navigatoinService: NavigationService) { private navigatoinService: NavigationService) {
this.content = new BehaviorSubject<ContentWrapper>(new ContentWrapper()); this.content = new BehaviorSubject<ContentWrapper>(new ContentWrapper());
this.sorting = new BehaviorSubject<SortingMethods>(Config.Client.defaultPhotoSortingMethod); this.sorting = new BehaviorSubject<SortingMethods>(Config.Client.Other.defaultPhotoSortingMethod);
} }
lastRequest: { directory: string } = { lastRequest: { directory: string } = {

View File

@ -137,7 +137,7 @@ export class GalleryGridComponent implements OnChanges, OnInit, AfterViewInit, O
ngAfterViewInit() { ngAfterViewInit() {
this.lightbox.setGridPhotoQL(this.gridPhotoQL); this.lightbox.setGridPhotoQL(this.gridPhotoQL);
if (Config.Client.enableOnScrollThumbnailPrioritising === true) { if (Config.Client.Other.enableOnScrollThumbnailPrioritising === true) {
this.gridPhotoQL.changes.subscribe(() => { this.gridPhotoQL.changes.subscribe(() => {
this.scrollListenerPhotos = this.gridPhotoQL.filter(pc => pc.ScrollListener); this.scrollListenerPhotos = this.gridPhotoQL.filter(pc => pc.ScrollListener);
}); });
@ -273,7 +273,7 @@ export class GalleryGridComponent implements OnChanges, OnInit, AfterViewInit, O
* @returns {boolean} * @returns {boolean}
*/ */
private shouldRenderMore(offset: number = 0): boolean { private shouldRenderMore(offset: number = 0): boolean {
return Config.Client.enableOnScrollRendering === false || return Config.Client.Other.enableOnScrollRendering === false ||
PageHelper.ScrollY >= (document.body.clientHeight + offset - window.innerHeight) * 0.7 PageHelper.ScrollY >= (document.body.clientHeight + offset - window.innerHeight) * 0.7
|| (document.body.clientHeight + offset) * 0.85 < window.innerHeight; || (document.body.clientHeight + offset) * 0.85 < window.innerHeight;
@ -288,7 +288,7 @@ export class GalleryGridComponent implements OnChanges, OnInit, AfterViewInit, O
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
this.renderPhotos(); this.renderPhotos();
if (Config.Client.enableOnScrollThumbnailPrioritising === true) { if (Config.Client.Other.enableOnScrollThumbnailPrioritising === true) {
this.scrollListenerPhotos.forEach((pc: GalleryPhotoComponent) => { this.scrollListenerPhotos.forEach((pc: GalleryPhotoComponent) => {
pc.onScroll(); pc.onScroll();
}); });

View File

@ -20,7 +20,7 @@
} }
ol { ol {
padding-right: 130px; padding-right: 150px;
} }
.dropdown-menu { .dropdown-menu {

View File

@ -8,10 +8,10 @@
</ol> </ol>
<div class="right-side"> <div class="right-side">
<div class="photos-count" *ngIf="directory.photos.length > 0"> <div class="photos-count" *ngIf="directory.photos.length > 0 && config.Client.Other.NavBar.showItemCount">
{{directory.photos.length}} <span i18n>items</span> {{directory.photos.length}} <span i18n>items</span>
</div> </div>
<div class="divider" *ngIf="directory.photos.length > 0">&nbsp;</div> <div class="divider" *ngIf="directory.photos.length > 0 && config.Client.Other.NavBar.showItemCount">&nbsp;</div>
<div class="btn-group" dropdown placement="bottom right"> <div class="btn-group" dropdown placement="bottom right">
<button id="button-alignment" dropdownToggle type="button" <button id="button-alignment" dropdownToggle type="button"
class="btn btn-default dropdown-toggle" aria-controls="dropdown-alignment" class="btn btn-default dropdown-toggle" aria-controls="dropdown-alignment"

View File

@ -8,6 +8,7 @@ import {QueryService} from '../../model/query.service';
import {GalleryService} from '../gallery.service'; import {GalleryService} from '../gallery.service';
import {Utils} from '../../../../common/Utils'; import {Utils} from '../../../../common/Utils';
import {SortingMethods} from '../../../../common/entities/SortingMethods'; import {SortingMethods} from '../../../../common/entities/SortingMethods';
import {Config} from '../../../../common/config/public/Config';
@Component({ @Component({
selector: 'app-gallery-navbar', selector: 'app-gallery-navbar',
@ -21,6 +22,7 @@ export class GalleryNavigatorComponent implements OnChanges {
routes: Array<NavigatorPath> = []; routes: Array<NavigatorPath> = [];
SortingMethods = SortingMethods; SortingMethods = SortingMethods;
sortingMethodsType: { key: number; value: string }[] = []; sortingMethodsType: { key: number; value: string }[] = [];
config = Config;
constructor(private _authService: AuthenticationService, constructor(private _authService: AuthenticationService,
public queryService: QueryService, public queryService: QueryService,

View File

@ -19,7 +19,7 @@ export class ThumbnailLoaderService {
} }
run = () => { run = () => {
if (this.que.length === 0 || this.runningRequests >= Config.Client.concurrentThumbnailGenerations) { if (this.que.length === 0 || this.runningRequests >= Config.Client.Thumbnail.concurrentThumbnailGenerations) {
return; return;
} }
const task = this.getNextTask(); const task = this.getNextTask();

View File

@ -19,7 +19,7 @@ export abstract class SettingsComponent<T, S extends AbstractSettingsService<T>
@ViewChild('settingsForm') @ViewChild('settingsForm')
form: HTMLFormElement; form: HTMLFormElement;
@Output('hasAvailableSettings') @Output()
hasAvailableSettings = true; hasAvailableSettings = true;
public inProgress = false; public inProgress = false;
@ -61,6 +61,31 @@ export abstract class SettingsComponent<T, S extends AbstractSettingsService<T>
this.ngOnChanges(); this.ngOnChanges();
}; };
settingsSame(newSettings: T, original: T): boolean {
if (typeof original !== 'object' || original == null) {
return newSettings === original;
}
if (!newSettings) {
return false;
}
const keys = Object.keys(newSettings);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (typeof original[key] === 'undefined') {
throw new Error('unknown settings: ' + key);
}
if (typeof original[key] === 'object') {
if (this.settingsSame(newSettings[key], original[key]) === false) {
return false;
}
} else if (newSettings[key] !== original[key]) {
return false;
}
}
return true;
}
ngOnInit() { ngOnInit() {
if (!this._authService.isAuthenticated() || if (!this._authService.isAuthenticated() ||
this._authService.user.value.role < UserRoles.Admin) { this._authService.user.value.role < UserRoles.Admin) {
@ -69,11 +94,11 @@ export abstract class SettingsComponent<T, S extends AbstractSettingsService<T>
} }
this.getSettings(); this.getSettings();
this._subscription = this.form.valueChanges.subscribe((data) => { // TODO: fix after this issue is fixed: https://github.com/angular/angular/issues/24818
if (!data) { this._subscription = this.form.valueChanges.subscribe(() => {
return; setTimeout(() => {
} this.changed = !this.settingsSame(this.settings, this.original);
this.changed = !Utils.equalsFilter(data, this.original); }, 0);
}); });
} }

View File

@ -31,12 +31,12 @@
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-md-2 control-label" for="folder" i18n>Images folder</label> <label class="col-md-2 control-label" for="imagesFolder" i18n>Images folder</label>
<div class="col-md-10"> <div class="col-md-10">
<input type="text" class="form-control" placeholder="path" <input type="text" class="form-control" placeholder="path"
id="folder" id="imagesFolder"
[(ngModel)]="settings.imagesFolder" [(ngModel)]="settings.imagesFolder"
name="folder" required> name="imagesFolder" required>
<small class="form-text text-muted" i18n>Images are loaded from this folder (read permission required)</small> <small class="form-text text-muted" i18n>Images are loaded from this folder (read permission required)</small>
</div> </div>
</div> </div>

View File

@ -1,4 +1,4 @@
<form #settingsForm="ngForm" class="form-horizontal"> <form #settingsForm="ngForm" class="form-horizontal" >
<div class="card mb-4"> <div class="card mb-4">
<h5 class="card-header" i18n> <h5 class="card-header" i18n>
Other settings Other settings
@ -7,20 +7,21 @@
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong i18n>Error: </strong>{{error}}</div> <div [hidden]="!error" class="alert alert-danger" role="alert"><strong i18n>Error: </strong>{{error}}</div>
<div class="form-group row"> <p class="title" i18n>Threads:</p>
<div class="form-group row" >
<label class="col-md-2 control-label" for="enableThreading" i18n>Threading</label> <label class="col-md-2 control-label" for="enableThreading" i18n>Threading</label>
<div class="col-md-10"> <div class="col-md-10">
<bSwitch <bSwitch
id="enableThreading" id="enableThreading"
class="switch" class="switch"
name="enableThreading" name="enable"
[switch-on-color]="'primary'" [switch-on-color]="'primary'"
[switch-inverse]="'inverse'" [switch-inverse]="'inverse'"
[switch-off-text]="text.Disabled" [switch-off-text]="text.Disabled"
[switch-on-text]="text.Enabled" [switch-on-text]="text.Enabled"
[switch-handle-width]="'100'" [switch-handle-width]="'100'"
[switch-label-width]="'20'" [switch-label-width]="'20'"
[(ngModel)]="settings.enableThreading"> [(ngModel)]="settings.Server.enable">
</bSwitch> </bSwitch>
<small class="form-text text-muted" i18n>Runs directory scanning and thumbnail generation (only for Jimp) in a <small class="form-text text-muted" i18n>Runs directory scanning and thumbnail generation (only for Jimp) in a
different thread different thread
@ -28,6 +29,20 @@
</div> </div>
</div> </div>
<div class="form-group row" [hidden]="simplifiedMode || settings.Server.enable == false">
<label class="col-md-2 control-label" for="thumbnailThreads" i18n>Thumbnail threads</label>
<div class="col-md-10">
<select id="thumbnailThreads" class="form-control" [(ngModel)]="settings.Server.thumbnailThreads"
name="Server[thumbnailThreads]" required>
<option [ngValue]="0">auto</option>
<option *ngFor="let i of threads" [ngValue]="i">{{i}}</option>
</select>
<small class="form-text text-muted" i18n>Number of threads that are used to generate thumbnails. If auto, number of CPU cores -1 threads will be used.</small>
</div>
</div>
<p class="title" i18n>Misc:</p>
<div class="form-group row"> <div class="form-group row">
<label class="col-md-2 control-label" for="enableOnScrollThumbnailPrioritising" i18n>Scroll based thumbnail <label class="col-md-2 control-label" for="enableOnScrollThumbnailPrioritising" i18n>Scroll based thumbnail
generation</label> generation</label>
@ -42,7 +57,7 @@
[switch-on-text]="text.Enabled" [switch-on-text]="text.Enabled"
[switch-handle-width]="'100'" [switch-handle-width]="'100'"
[switch-label-width]="'20'" [switch-label-width]="'20'"
[(ngModel)]="settings.enableOnScrollThumbnailPrioritising"> [(ngModel)]="settings.Client.enableOnScrollThumbnailPrioritising">
</bSwitch> </bSwitch>
<small class="form-text text-muted" i18n>Those thumbnails get higher priority that are visible on the screen <small class="form-text text-muted" i18n>Those thumbnails get higher priority that are visible on the screen
</small> </small>
@ -62,7 +77,7 @@
[switch-on-text]="text.Enabled" [switch-on-text]="text.Enabled"
[switch-handle-width]="'100'" [switch-handle-width]="'100'"
[switch-label-width]="'20'" [switch-label-width]="'20'"
[(ngModel)]="settings.enableOnScrollRendering"> [(ngModel)]="settings.Client.enableOnScrollRendering">
</bSwitch> </bSwitch>
<small class="form-text text-muted" i18n>Shows only the required amount of photos at once. Renders more if <small class="form-text text-muted" i18n>Shows only the required amount of photos at once. Renders more if
page bottom is reached page bottom is reached
@ -84,7 +99,7 @@
[switch-on-text]="text.Enabled" [switch-on-text]="text.Enabled"
[switch-handle-width]="'100'" [switch-handle-width]="'100'"
[switch-label-width]="'20'" [switch-label-width]="'20'"
[(ngModel)]="settings.enableCache"> [(ngModel)]="settings.Client.enableCache">
</bSwitch> </bSwitch>
<small class="form-text text-muted" i18n>Caches directory contents and search results for better performance <small class="form-text text-muted" i18n>Caches directory contents and search results for better performance
</small> </small>
@ -92,10 +107,33 @@
</div> </div>
<p class="title" i18n>Navigation bar:</p>
<div class="form-group row">
<label class="col-md-2 control-label" for="showItemCount" [hidden]="simplifiedMode" i18n>Show item count</label>
<div class="col-md-10">
<bSwitch
id="showItemCount"
class="switch"
name="enableCache"
[switch-on-color]="'primary'"
[switch-inverse]="'inverse'"
[switch-off-text]="text.Disabled"
[switch-on-text]="text.Enabled"
[switch-handle-width]="'100'"
[switch-label-width]="'20'"
[(ngModel)]="settings.Client.NavBar.showItemCount">
</bSwitch>
<small class="form-text text-muted" i18n>Show hte number of items (photos) in the folder
</small>
</div>
</div>
<div class="form-group row" [hidden]="simplifiedMode"> <div class="form-group row" [hidden]="simplifiedMode">
<label class="col-md-2 control-label" for="defaultPhotoSortingMethod" i18n>Default photo sorting method</label> <label class="col-md-2 control-label" for="defaultPhotoSortingMethod" i18n>Default photo sorting method</label>
<div class="col-md-10"> <div class="col-md-10">
<select id="defaultPhotoSortingMethod" class="form-control" [(ngModel)]="settings.defaultPhotoSortingMethod" <select id="defaultPhotoSortingMethod" class="form-control" [(ngModel)]="settings.Client.defaultPhotoSortingMethod"
name="defaultPhotoSortingMethod" required> name="defaultPhotoSortingMethod" required>
<option *ngFor="let type of types" [ngValue]="type.key">{{type.key | stringifySorting}} <option *ngFor="let type of types" [ngValue]="type.key">{{type.key | stringifySorting}}
</option> </option>

View File

@ -6,7 +6,6 @@ import {NotificationService} from '../../model/notification.service';
import {OtherSettingsService} from './other.settings.service'; import {OtherSettingsService} from './other.settings.service';
import {OtherConfigDTO} from '../../../../common/entities/settings/OtherConfigDTO'; import {OtherConfigDTO} from '../../../../common/entities/settings/OtherConfigDTO';
import {I18n} from '@ngx-translate/i18n-polyfill'; import {I18n} from '@ngx-translate/i18n-polyfill';
import {ReIndexingSensitivity} from '../../../../common/config/private/IPrivateConfig';
import {Utils} from '../../../../common/Utils'; import {Utils} from '../../../../common/Utils';
import {SortingMethods} from '../../../../common/entities/SortingMethods'; import {SortingMethods} from '../../../../common/entities/SortingMethods';
@ -21,6 +20,7 @@ export class OtherSettingsComponent extends SettingsComponent<OtherConfigDTO> im
types: { key: number; value: string }[] = []; types: { key: number; value: string }[] = [];
threads: number[] = Utils.createRange(1, 100);
constructor(_authService: AuthenticationService, constructor(_authService: AuthenticationService,
_navigation: NavigationService, _navigation: NavigationService,
@ -28,11 +28,8 @@ export class OtherSettingsComponent extends SettingsComponent<OtherConfigDTO> im
notification: NotificationService, notification: NotificationService,
i18n: I18n) { i18n: I18n) {
super(i18n('Other'), _authService, _navigation, _settingsService, notification, i18n, s => ({ super(i18n('Other'), _authService, _navigation, _settingsService, notification, i18n, s => ({
enableThreading: s.Server.enableThreading, Server: s.Server.threading,
enableOnScrollThumbnailPrioritising: s.Client.enableOnScrollThumbnailPrioritising, Client: s.Client.Other
enableOnScrollRendering: s.Client.enableOnScrollRendering,
enableCache: s.Client.enableCache,
defaultPhotoSortingMethod: s.Client.defaultPhotoSortingMethod
})); }));
this.types = Utils.enumToArray(SortingMethods); this.types = Utils.enumToArray(SortingMethods);
this.hasAvailableSettings = !this.simplifiedMode; this.hasAvailableSettings = !this.simplifiedMode;

View File

@ -20,8 +20,8 @@ export class SettingsService {
instantSearchCacheTimeout: 1000 * 60 * 60, instantSearchCacheTimeout: 1000 * 60 * 60,
autocompleteCacheTimeout: 1000 * 60 * 60 autocompleteCacheTimeout: 1000 * 60 * 60
}, },
concurrentThumbnailGenerations: null,
Thumbnail: { Thumbnail: {
concurrentThumbnailGenerations: null,
iconSize: 30, iconSize: 30,
thumbnailSizes: [] thumbnailSizes: []
}, },
@ -36,15 +36,20 @@ export class SettingsService {
RandomPhoto: { RandomPhoto: {
enabled: true enabled: true
}, },
Other: {
enableCache: true,
enableOnScrollRendering: true,
enableOnScrollThumbnailPrioritising: true,
defaultPhotoSortingMethod: SortingMethods.ascDate,
NavBar: {
showItemCount: true
}
},
urlBase: '', urlBase: '',
publicUrl: '', publicUrl: '',
applicationTitle: '', applicationTitle: '',
enableCache: true,
enableOnScrollRendering: true,
enableOnScrollThumbnailPrioritising: true,
authenticationRequired: true, authenticationRequired: true,
languages: [], languages: []
defaultPhotoSortingMethod: SortingMethods.ascDate
}, },
Server: { Server: {
database: { database: {
@ -54,13 +59,16 @@ export class SettingsService {
updateTimeout: 2000 updateTimeout: 2000
}, },
imagesFolder: '', imagesFolder: '',
enableThreading: true,
port: 80, port: 80,
thumbnail: { thumbnail: {
folder: '', folder: '',
qualityPriority: true, qualityPriority: true,
processingLibrary: ThumbnailProcessingLib.sharp processingLibrary: ThumbnailProcessingLib.sharp
}, },
threading: {
enable: true,
thumbnailThreads: 0
},
sessionTimeout: 0, sessionTimeout: 0,
indexing: { indexing: {
cachedFolderTimeout: 0, cachedFolderTimeout: 0,