mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-02-09 13:46:56 +02:00
implementing search settings
This commit is contained in:
parent
998efcdbf5
commit
5b5affd227
@ -70,6 +70,29 @@ export class AdminMWs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async updateSearchSettings(req: Request, res: Response, next: NextFunction) {
|
||||||
|
if ((typeof req.body === 'undefined') || (typeof req.body.settings === 'undefined')) {
|
||||||
|
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, "settings is needed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
//only updating explicitly set config (not saving config set by the diagnostics)
|
||||||
|
const original = Config.original();
|
||||||
|
await ConfigDiagnostics.testSearchConfig(<ClientConfig.SearchConfig>req.body.settings, original);
|
||||||
|
|
||||||
|
Config.Client.Search = <ClientConfig.SearchConfig>req.body.settings;
|
||||||
|
original.Client.Search = <ClientConfig.SearchConfig>req.body.settings;
|
||||||
|
original.save();
|
||||||
|
await ConfigDiagnostics.runDiagnostics();
|
||||||
|
Logger.info(LOG_TAG, "new config:");
|
||||||
|
Logger.info(LOG_TAG, JSON.stringify(Config, null, '\t'));
|
||||||
|
return next();
|
||||||
|
} catch (err) {
|
||||||
|
return next(new ErrorDTO(ErrorCodes.SETTINGS_ERROR, "Settings error: " + JSON.stringify(err, null, ' '), err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static async updateAuthenticationSettings(req: Request, res: Response, next: NextFunction) {
|
public static async updateAuthenticationSettings(req: Request, res: Response, next: NextFunction) {
|
||||||
if ((typeof req.body === 'undefined') || (typeof req.body.settings === 'undefined')) {
|
if ((typeof req.body === 'undefined') || (typeof req.body.settings === 'undefined')) {
|
||||||
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, "settings is needed"));
|
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, "settings is needed"));
|
||||||
|
@ -2,6 +2,7 @@ import {Config} from "../../common/config/private/Config";
|
|||||||
import {
|
import {
|
||||||
DataBaseConfig,
|
DataBaseConfig,
|
||||||
DatabaseType,
|
DatabaseType,
|
||||||
|
IPrivateConfig,
|
||||||
ThumbnailConfig,
|
ThumbnailConfig,
|
||||||
ThumbnailProcessingLib
|
ThumbnailProcessingLib
|
||||||
} from "../../common/config/private/IPrivateConfig";
|
} from "../../common/config/private/IPrivateConfig";
|
||||||
@ -89,15 +90,15 @@ export class ConfigDiagnostics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static async testSearchConfig(search: ClientConfig.SearchConfig) {
|
static async testSearchConfig(search: ClientConfig.SearchConfig, config: IPrivateConfig) {
|
||||||
if (search.enabled == true && Config.Server.database.type == DatabaseType.memory) {
|
if (search.enabled == true && config.Server.database.type == DatabaseType.memory) {
|
||||||
throw "Memory Database do not support searching";
|
throw "Memory Database do not support searching";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static async testSharingConfig(sharing: ClientConfig.SharingConfig) {
|
static async testSharingConfig(sharing: ClientConfig.SharingConfig, config: IPrivateConfig) {
|
||||||
if (sharing.enabled == true && Config.Server.database.type == DatabaseType.memory) {
|
if (sharing.enabled == true && config.Server.database.type == DatabaseType.memory) {
|
||||||
throw "Memory Database do not support sharing";
|
throw "Memory Database do not support sharing";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,7 +161,7 @@ export class ConfigDiagnostics {
|
|||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ConfigDiagnostics.testSearchConfig(Config.Client.Search);
|
await ConfigDiagnostics.testSearchConfig(Config.Client.Search, Config);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
NotificationManager.warning("Search is not supported with these settings. Disabling temporally. Please adjust the config properly.", err);
|
NotificationManager.warning("Search is not supported with these settings. Disabling temporally. Please adjust the config properly.", err);
|
||||||
Logger.warn(LOG_TAG, "Search is not supported with these settings, switching off..", err);
|
Logger.warn(LOG_TAG, "Search is not supported with these settings, switching off..", err);
|
||||||
@ -168,7 +169,7 @@ export class ConfigDiagnostics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing);
|
await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing, Config);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
NotificationManager.warning("Sharing is not supported with these settings. Disabling temporally. Please adjust the config properly.", err);
|
NotificationManager.warning("Sharing is not supported with these settings. Disabling temporally. Please adjust the config properly.", err);
|
||||||
Logger.warn(LOG_TAG, "Sharing is not supported with these settings, switching off..", err);
|
Logger.warn(LOG_TAG, "Sharing is not supported with these settings, switching off..", err);
|
||||||
|
@ -61,6 +61,12 @@ export class AdminRouter {
|
|||||||
AdminMWs.updateThumbnailSettings,
|
AdminMWs.updateThumbnailSettings,
|
||||||
RenderingMWs.renderOK
|
RenderingMWs.renderOK
|
||||||
);
|
);
|
||||||
|
app.put("/api/settings/search",
|
||||||
|
AuthenticationMWs.authenticate,
|
||||||
|
AuthenticationMWs.authorise(UserRoles.Admin),
|
||||||
|
AdminMWs.updateSearchSettings,
|
||||||
|
RenderingMWs.renderOK
|
||||||
|
);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
|
|
||||||
<settings-usermanager></settings-usermanager>
|
<settings-usermanager></settings-usermanager>
|
||||||
<settings-database></settings-database>
|
<settings-database></settings-database>
|
||||||
<settings-map></settings-map>
|
|
||||||
<settings-thumbnail></settings-thumbnail>
|
<settings-thumbnail></settings-thumbnail>
|
||||||
|
<settings-search></settings-search>
|
||||||
|
<settings-map></settings-map>
|
||||||
</div>
|
</div>
|
||||||
</app-frame>
|
</app-frame>
|
||||||
|
@ -48,6 +48,8 @@ import {InfoPanelLightboxComponent} from "./gallery/lightbox/infopanel/info-pane
|
|||||||
import {MapSettingsComponent} from "./settings/map/map.settings.component";
|
import {MapSettingsComponent} from "./settings/map/map.settings.component";
|
||||||
import {TooltipModule} from "ngx-bootstrap/tooltip";
|
import {TooltipModule} from "ngx-bootstrap/tooltip";
|
||||||
import {ThumbnailSettingsComponent} from "./settings/thumbnail/thumbanil.settings.component";
|
import {ThumbnailSettingsComponent} from "./settings/thumbnail/thumbanil.settings.component";
|
||||||
|
import {SearchSettingsComponent} from "./settings/search/search.settings.component";
|
||||||
|
import {SettingsService} from "./settings/settings.service";
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GoogleMapsConfig {
|
export class GoogleMapsConfig {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
@ -97,6 +99,7 @@ export class GoogleMapsConfig {
|
|||||||
DatabaseSettingsComponent,
|
DatabaseSettingsComponent,
|
||||||
MapSettingsComponent,
|
MapSettingsComponent,
|
||||||
ThumbnailSettingsComponent,
|
ThumbnailSettingsComponent,
|
||||||
|
SearchSettingsComponent,
|
||||||
StringifyRole],
|
StringifyRole],
|
||||||
providers: [
|
providers: [
|
||||||
{provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig},
|
{provide: LAZY_MAPS_API_CONFIG, useClass: GoogleMapsConfig},
|
||||||
@ -111,6 +114,7 @@ export class GoogleMapsConfig {
|
|||||||
NotificationService,
|
NotificationService,
|
||||||
FullScreenService,
|
FullScreenService,
|
||||||
NavigationService,
|
NavigationService,
|
||||||
|
SettingsService,
|
||||||
OverlayService],
|
OverlayService],
|
||||||
|
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
@ -5,15 +5,13 @@ import {Utils} from "../../../../common/Utils";
|
|||||||
import {ErrorDTO} from "../../../../common/entities/Error";
|
import {ErrorDTO} from "../../../../common/entities/Error";
|
||||||
import {NotificationService} from "../../model/notification.service";
|
import {NotificationService} from "../../model/notification.service";
|
||||||
import {NavigationService} from "../../model/navigation.service";
|
import {NavigationService} from "../../model/navigation.service";
|
||||||
import {ISettingsService} from "./abstract.settings.service";
|
import {AbstractSettingsService} from "./abstract.settings.service";
|
||||||
|
|
||||||
|
|
||||||
export abstract class SettingsComponent<T> implements OnInit, OnDestroy {
|
export abstract class SettingsComponent<T> implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@ViewChild('settingsForm') form;
|
@ViewChild('settingsForm') form;
|
||||||
public settings: T = <T>{};
|
|
||||||
public inProgress = false;
|
public inProgress = false;
|
||||||
private original: T = <T>{};
|
|
||||||
public error: string = null;
|
public error: string = null;
|
||||||
public changed: boolean = false;
|
public changed: boolean = false;
|
||||||
private subscription = null;
|
private subscription = null;
|
||||||
@ -21,7 +19,7 @@ export abstract class SettingsComponent<T> implements OnInit, OnDestroy {
|
|||||||
constructor(private name,
|
constructor(private name,
|
||||||
private _authService: AuthenticationService,
|
private _authService: AuthenticationService,
|
||||||
private _navigation: NavigationService,
|
private _navigation: NavigationService,
|
||||||
protected _settingsService: ISettingsService<T>,
|
public _settingsService: AbstractSettingsService<T>,
|
||||||
private notification: NotificationService) {
|
private notification: NotificationService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,11 +29,10 @@ export abstract class SettingsComponent<T> implements OnInit, OnDestroy {
|
|||||||
this._navigation.toLogin();
|
this._navigation.toLogin();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.original = Utils.clone(this.settings);
|
|
||||||
this.getSettings();
|
this.getSettings();
|
||||||
|
|
||||||
this.subscription = this.form.valueChanges.subscribe((data) => {
|
this.subscription = this.form.valueChanges.subscribe((data) => {
|
||||||
this.changed = !Utils.equalsFilter(this.settings, this.original);
|
this.changed = !Utils.equalsFilter(this._settingsService.settings, this._settingsService.original);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,10 +43,7 @@ export abstract class SettingsComponent<T> implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async getSettings() {
|
private async getSettings() {
|
||||||
const s = await this._settingsService.getSettings();
|
await this._settingsService.getSettings();
|
||||||
this.original = Utils.clone(s);
|
|
||||||
this.settings = s;
|
|
||||||
console.log(this.settings);
|
|
||||||
this.changed = false;
|
this.changed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,12 +52,11 @@ export abstract class SettingsComponent<T> implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public async save() {
|
public async save() {
|
||||||
this.inProgress = true;
|
this.inProgress = true;
|
||||||
this.error = "";
|
this.error = "";
|
||||||
try {
|
try {
|
||||||
await this._settingsService.updateSettings(this.settings);
|
await this._settingsService.updateSettings(this._settingsService.settings);
|
||||||
await this.getSettings();
|
await this.getSettings();
|
||||||
this.notification.success(this.name + ' settings saved', "Success");
|
this.notification.success(this.name + ' settings saved', "Success");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -1,4 +1,29 @@
|
|||||||
export interface ISettingsService<T> {
|
import {Utils} from "../../../../common/Utils";
|
||||||
getSettings(): Promise<T>;
|
import {SettingsService} from "../settings.service";
|
||||||
updateSettings(settings: T): Promise<void>;
|
import {IPrivateConfig} from "../../../../common/config/private/IPrivateConfig";
|
||||||
|
export abstract class AbstractSettingsService<T> {
|
||||||
|
public settings: T = <any>{};
|
||||||
|
public original: T = <any>{};
|
||||||
|
|
||||||
|
constructor(protected _settingsService: SettingsService, private sliceFN: (s: IPrivateConfig) => T) {
|
||||||
|
this.original = Utils.clone(this.settings);
|
||||||
|
this._settingsService.settings.subscribe(this.onNewSettings);
|
||||||
|
this.onNewSettings(this._settingsService.settings.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
onNewSettings = (s) => {
|
||||||
|
this.settings = Utils.clone(this.sliceFN(s));
|
||||||
|
this.original = Utils.clone(this.settings);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public getSettings(): Promise<void> {
|
||||||
|
return this._settingsService.getSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
isSupported() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract updateSettings(settings: T): Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -6,20 +6,20 @@
|
|||||||
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||||
<form #settingsForm="ngForm">
|
<form #settingsForm="ngForm">
|
||||||
<p class="title">Type:</p>
|
<p class="title">Type:</p>
|
||||||
<select class="form-control" [(ngModel)]="settings.type" name="type" required>
|
<select class="form-control" [(ngModel)]="_settingsService.settings.type" name="type" required>
|
||||||
<option *ngFor="let type of types" [ngValue]="type.key">{{type.value}}
|
<option *ngFor="let type of types" [ngValue]="type.key">{{type.value}}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<ng-container *ngIf="settings.type == DatabaseType.mysql">
|
<ng-container *ngIf="_settingsService.settings.type == DatabaseType.mysql">
|
||||||
<p class="title">MySQL settings:</p>
|
<p class="title">MySQL settings:</p>
|
||||||
<input type="text" class="form-control" placeholder="Host" autofocus
|
<input type="text" class="form-control" placeholder="Host" autofocus
|
||||||
[(ngModel)]="settings.mysql.host" name="host" required>
|
[(ngModel)]="_settingsService.settings.mysql.host" name="host" required>
|
||||||
<input type="text" class="form-control" placeholder="Database" autofocus
|
<input type="text" class="form-control" placeholder="Database" autofocus
|
||||||
[(ngModel)]="settings.mysql.database" name="database" required>
|
[(ngModel)]="_settingsService.settings.mysql.database" name="database" required>
|
||||||
<input type="text" class="form-control" placeholder="Username"
|
<input type="text" class="form-control" placeholder="Username"
|
||||||
[(ngModel)]="settings.mysql.username" name="username">
|
[(ngModel)]="_settingsService.settings.mysql.username" name="username">
|
||||||
<input type="password" class="form-control" placeholder="Password"
|
<input type="password" class="form-control" placeholder="Password"
|
||||||
[(ngModel)]="settings.mysql.password" name="password">
|
[(ngModel)]="_settingsService.settings.mysql.password" name="password">
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
@ -15,18 +15,15 @@ import {DatabaseSettingsService} from "./database.settings.service";
|
|||||||
providers: [DatabaseSettingsService],
|
providers: [DatabaseSettingsService],
|
||||||
})
|
})
|
||||||
export class DatabaseSettingsComponent extends SettingsComponent<DataBaseConfig> {
|
export class DatabaseSettingsComponent extends SettingsComponent<DataBaseConfig> {
|
||||||
public settings: DataBaseConfig = <DataBaseConfig> {
|
|
||||||
type: DatabaseType.memory,
|
|
||||||
mysql: {}
|
|
||||||
};
|
|
||||||
public types: Array<any> = [];
|
public types: Array<any> = [];
|
||||||
public DatabaseType: any;
|
public DatabaseType: any;
|
||||||
|
|
||||||
constructor(_authService: AuthenticationService,
|
constructor(_authService: AuthenticationService,
|
||||||
_navigation: NavigationService,
|
_navigation: NavigationService,
|
||||||
_dbSettings: DatabaseSettingsService,
|
_settingsService: DatabaseSettingsService,
|
||||||
notification: NotificationService) {
|
notification: NotificationService) {
|
||||||
super("Database", _authService, _navigation, _dbSettings, notification);
|
super("Database", _authService, _navigation, _settingsService, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {NetworkService} from "../../model/network/network.service";
|
import {NetworkService} from "../../model/network/network.service";
|
||||||
import {DataBaseConfig, IPrivateConfig} from "../../../../common/config/private/IPrivateConfig";
|
import {DataBaseConfig} from "../../../../common/config/private/IPrivateConfig";
|
||||||
|
import {AbstractSettingsService} from "../_abstract/abstract.settings.service";
|
||||||
|
import {SettingsService} from "../settings.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DatabaseSettingsService {
|
export class DatabaseSettingsService extends AbstractSettingsService<DataBaseConfig> {
|
||||||
constructor(private _networkService: NetworkService) {
|
constructor(private _networkService: NetworkService,
|
||||||
|
_settingsService: SettingsService) {
|
||||||
|
super(_settingsService, s => s.Server.database);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getSettings(): Promise<DataBaseConfig> {
|
|
||||||
return (await <Promise<IPrivateConfig>>this._networkService.getJson("/settings")).Server.database;
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateSettings(settings: DataBaseConfig): Promise<void> {
|
public updateSettings(settings: DataBaseConfig): Promise<void> {
|
||||||
return this._networkService.putJson("/settings/database", {settings: settings});
|
return this._networkService.putJson("/settings/database", {settings: settings});
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
[switch-disabled]="inProgress"
|
[switch-disabled]="inProgress"
|
||||||
[switch-handle-width]="'100'"
|
[switch-handle-width]="'100'"
|
||||||
[switch-label-width]="'20'"
|
[switch-label-width]="'20'"
|
||||||
[(ngModel)]="settings.enabled">
|
[(ngModel)]="_settingsService.settings.enabled">
|
||||||
</bSwitch>
|
</bSwitch>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
|
|
||||||
<input type="text" class="form-control" placeholder="Google api key" autofocus
|
<input type="text" class="form-control" placeholder="Google api key" autofocus
|
||||||
[(ngModel)]="settings.googleApiKey"
|
[(ngModel)]="_settingsService.settings.googleApiKey"
|
||||||
[disabled]="!settings.enabled"
|
[disabled]="!_settingsService.settings.enabled"
|
||||||
name="googleApiKey" required>
|
name="googleApiKey" required>
|
||||||
<span class="help-block">To show the images on a map, <a
|
<span class="help-block">To show the images on a map, <a
|
||||||
href="https://developers.google.com/maps/documentation/javascript/get-api-key">google api key</a> is need</span>
|
href="https://developers.google.com/maps/documentation/javascript/get-api-key">google api key</a> is need</span>
|
||||||
|
@ -14,16 +14,12 @@ import {ClientConfig} from "../../../../common/config/public/ConfigClass";
|
|||||||
providers: [MapSettingsService],
|
providers: [MapSettingsService],
|
||||||
})
|
})
|
||||||
export class MapSettingsComponent extends SettingsComponent<ClientConfig.MapConfig> {
|
export class MapSettingsComponent extends SettingsComponent<ClientConfig.MapConfig> {
|
||||||
public settings: ClientConfig.MapConfig = <ClientConfig.MapConfig> {
|
|
||||||
enabled: true,
|
|
||||||
googleApiKey: ""
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(_authService: AuthenticationService,
|
constructor(_authService: AuthenticationService,
|
||||||
_navigation: NavigationService,
|
_navigation: NavigationService,
|
||||||
_settingsSettings: MapSettingsService,
|
_settingsService: MapSettingsService,
|
||||||
notification: NotificationService) {
|
notification: NotificationService) {
|
||||||
super("Map", _authService, _navigation, _settingsSettings, notification);
|
super("Map", _authService, _navigation, <any>_settingsService, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {NetworkService} from "../../model/network/network.service";
|
import {NetworkService} from "../../model/network/network.service";
|
||||||
import {IPrivateConfig} from "../../../../common/config/private/IPrivateConfig";
|
|
||||||
import {ClientConfig} from "../../../../common/config/public/ConfigClass";
|
import {ClientConfig} from "../../../../common/config/public/ConfigClass";
|
||||||
|
import {SettingsService} from "../settings.service";
|
||||||
|
import {AbstractSettingsService} from "../_abstract/abstract.settings.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MapSettingsService {
|
export class MapSettingsService extends AbstractSettingsService<ClientConfig.MapConfig> {
|
||||||
constructor(private _networkService: NetworkService) {
|
constructor(private _networkService: NetworkService,
|
||||||
}
|
_settingsService: SettingsService) {
|
||||||
|
super(_settingsService, s => s.Client.Map);
|
||||||
|
|
||||||
public async getSettings(): Promise<ClientConfig.MapConfig> {
|
|
||||||
return (await <Promise<IPrivateConfig>>this._networkService.getJson("/settings")).Client.Map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateSettings(settings: ClientConfig.MapConfig): Promise<void> {
|
public updateSettings(settings: ClientConfig.MapConfig): Promise<void> {
|
||||||
|
73
frontend/app/settings/search/search.settings.component.html
Normal file
73
frontend/app/settings/search/search.settings.component.html
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<form #settingsForm="ngForm">
|
||||||
|
<div class="panel panel-default"
|
||||||
|
[ngClass]="!_settingsService.isSupported()?'panel-warning':''">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title col-sm-4">Search settings</h3>
|
||||||
|
<div class="switch-wrapper col-sm-8">
|
||||||
|
<bSwitch
|
||||||
|
class="switch"
|
||||||
|
name="enabled"
|
||||||
|
[switch-on-color]="'success'"
|
||||||
|
[switch-inverse]="'inverse'"
|
||||||
|
[switch-off-text]="'Disabled'"
|
||||||
|
[switch-on-text]="'Enabled'"
|
||||||
|
[switch-disabled]="inProgress || (!_settingsService.settings.enabled && !_settingsService.isSupported())"
|
||||||
|
[switch-handle-width]="'100'"
|
||||||
|
[switch-label-width]="'20'"
|
||||||
|
[(ngModel)]="_settingsService.settings.enabled">
|
||||||
|
</bSwitch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="autocompleteEnabled">Autocomplete</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<bSwitch
|
||||||
|
id="autocompleteEnabled"
|
||||||
|
class="switch"
|
||||||
|
name="autocompleteEnabled"
|
||||||
|
[switch-on-color]="'primary'"
|
||||||
|
[switch-disabled]="!_settingsService.settings.enabled"
|
||||||
|
[switch-inverse]="'inverse'"
|
||||||
|
[switch-off-text]="'Disabled'"
|
||||||
|
[switch-on-text]="'Enabled'"
|
||||||
|
[switch-handle-width]="'100'"
|
||||||
|
[switch-label-width]="'20'"
|
||||||
|
[(ngModel)]="_settingsService.settings.autocompleteEnabled">
|
||||||
|
</bSwitch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label" for="instantSearchEnabled">Instant search</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<bSwitch
|
||||||
|
id="instantSearchEnabled"
|
||||||
|
class="switch"
|
||||||
|
name="instantSearchEnabled"
|
||||||
|
[switch-on-color]="'primary'"
|
||||||
|
[switch-disabled]="!_settingsService.settings.enabled"
|
||||||
|
[switch-inverse]="'inverse'"
|
||||||
|
[switch-off-text]="'Disabled'"
|
||||||
|
[switch-on-text]="'Enabled'"
|
||||||
|
[switch-handle-width]="'100'"
|
||||||
|
[switch-label-width]="'20'"
|
||||||
|
[(ngModel)]="_settingsService.settings.instantSearchEnabled">
|
||||||
|
</bSwitch>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn btn-success pull-right"
|
||||||
|
[disabled]="!settingsForm.form.valid || !changed || inProgress"
|
||||||
|
(click)="save()">Save
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-default pull-right"
|
||||||
|
(click)="reset()">Reset
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
29
frontend/app/settings/search/search.settings.component.ts
Normal file
29
frontend/app/settings/search/search.settings.component.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import {Component} from "@angular/core";
|
||||||
|
import {SettingsComponent} from "../_abstract/abstract.settings.component";
|
||||||
|
import {AuthenticationService} from "../../model/network/authentication.service";
|
||||||
|
import {NavigationService} from "../../model/navigation.service";
|
||||||
|
import {NotificationService} from "../../model/notification.service";
|
||||||
|
import {ClientConfig} from "../../../../common/config/public/ConfigClass";
|
||||||
|
import {SearchSettingsService} from "./search.settings.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'settings-search',
|
||||||
|
templateUrl: './search.settings.component.html',
|
||||||
|
styleUrls: ['./search.settings.component.css',
|
||||||
|
'./../_abstract/abstract.settings.component.css'],
|
||||||
|
providers: [SearchSettingsService],
|
||||||
|
})
|
||||||
|
export class SearchSettingsComponent extends SettingsComponent<ClientConfig.SearchConfig> {
|
||||||
|
|
||||||
|
constructor(_authService: AuthenticationService,
|
||||||
|
_navigation: NavigationService,
|
||||||
|
_settingsService: SearchSettingsService,
|
||||||
|
notification: NotificationService) {
|
||||||
|
super("Search", _authService, _navigation, _settingsService, notification);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
25
frontend/app/settings/search/search.settings.service.ts
Normal file
25
frontend/app/settings/search/search.settings.service.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {Injectable} from "@angular/core";
|
||||||
|
import {NetworkService} from "../../model/network/network.service";
|
||||||
|
import {DatabaseType} from "../../../../common/config/private/IPrivateConfig";
|
||||||
|
import {ClientConfig} from "../../../../common/config/public/ConfigClass";
|
||||||
|
import {SettingsService} from "../settings.service";
|
||||||
|
import {AbstractSettingsService} from "../_abstract/abstract.settings.service";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class SearchSettingsService extends AbstractSettingsService<ClientConfig.SearchConfig> {
|
||||||
|
constructor(private _networkService: NetworkService,
|
||||||
|
_settingsService: SettingsService) {
|
||||||
|
super(_settingsService, s => s.Client.Search);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public isSupported(): boolean {
|
||||||
|
return this._settingsService.settings.value.Server.database.type != DatabaseType.memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateSettings(settings: ClientConfig.SearchConfig): Promise<void> {
|
||||||
|
return this._networkService.putJson("/settings/search", {settings: settings});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
58
frontend/app/settings/settings.service.ts
Normal file
58
frontend/app/settings/settings.service.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import {Injectable} from "@angular/core";
|
||||||
|
import {BehaviorSubject} from "rxjs/BehaviorSubject";
|
||||||
|
import {DatabaseType, IPrivateConfig, ThumbnailProcessingLib} from "../../../common/config/private/IPrivateConfig";
|
||||||
|
import {NetworkService} from "../model/network/network.service";
|
||||||
|
@Injectable()
|
||||||
|
export class SettingsService {
|
||||||
|
public settings: BehaviorSubject<IPrivateConfig>;
|
||||||
|
|
||||||
|
constructor(private _networkService: NetworkService) {
|
||||||
|
this.settings = new BehaviorSubject<IPrivateConfig>(<any>{
|
||||||
|
Client: {
|
||||||
|
Search: {
|
||||||
|
enabled: true,
|
||||||
|
autocompleteEnabled: true,
|
||||||
|
instantSearchEnabled: true
|
||||||
|
},
|
||||||
|
Thumbnail: {
|
||||||
|
iconSize: 30,
|
||||||
|
thumbnailSizes: []
|
||||||
|
},
|
||||||
|
Sharing: {
|
||||||
|
enabled: true,
|
||||||
|
passwordProtected: true
|
||||||
|
},
|
||||||
|
Map: {
|
||||||
|
enabled: true,
|
||||||
|
googleApiKey: ""
|
||||||
|
}, publicUrl: "",
|
||||||
|
applicationTitle: "",
|
||||||
|
enableCache: true,
|
||||||
|
enableOnScrollRendering: true,
|
||||||
|
enableOnScrollThumbnailPrioritising: true,
|
||||||
|
authenticationRequired: true
|
||||||
|
}, Server: {
|
||||||
|
database: {
|
||||||
|
type: DatabaseType.memory
|
||||||
|
},
|
||||||
|
imagesFolder: "",
|
||||||
|
sharing: {
|
||||||
|
updateTimeout: 2000
|
||||||
|
},
|
||||||
|
enableThreading: true,
|
||||||
|
port: 80,
|
||||||
|
thumbnail: {
|
||||||
|
folder: "",
|
||||||
|
qualityPriority: true,
|
||||||
|
processingLibrary: ThumbnailProcessingLib.sharp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getSettings(): Promise<void> {
|
||||||
|
this.settings.next(await <Promise<IPrivateConfig>>this._networkService.getJson("/settings"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -5,7 +5,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||||
<div [hidden]="settings.server.processingLibrary!=ThumbnailProcessingLib.Jimp" class="alert alert-warning"
|
<div [hidden]="_settingsService.settings.server.processingLibrary!=ThumbnailProcessingLib.Jimp"
|
||||||
|
class="alert alert-warning"
|
||||||
role="alert">It is highly recommended to use hardware accelerated (sharp or gm) lib for thumbnail generation
|
role="alert">It is highly recommended to use hardware accelerated (sharp or gm) lib for thumbnail generation
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -13,12 +14,15 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-2 control-label" for="lib">Thumbnail generation library</label>
|
<label class="col-sm-2 control-label" for="lib">Thumbnail generation library</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<select id="lib" class="form-control" [(ngModel)]="settings.server.processingLibrary" name="type" required>
|
<select id="lib" class="form-control" [(ngModel)]="_settingsService.settings.server.processingLibrary"
|
||||||
|
name="type" required>
|
||||||
<option *ngFor="let type of types" [ngValue]="type.key">{{type.value}}
|
<option *ngFor="let type of types" [ngValue]="type.key">{{type.value}}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<span *ngIf="settings.server.processingLibrary==ThumbnailProcessingLib.sharp" class="help-block">Make sure that sharp node module is installed (npm install sharp)</span>
|
<span *ngIf="_settingsService.settings.server.processingLibrary==ThumbnailProcessingLib.sharp"
|
||||||
<span *ngIf="settings.server.processingLibrary==ThumbnailProcessingLib.gm" class="help-block">Make sure that gm node module and <a
|
class="help-block">Make sure that sharp node module is installed (npm install sharp)</span>
|
||||||
|
<span *ngIf="_settingsService.settings.server.processingLibrary==ThumbnailProcessingLib.gm"
|
||||||
|
class="help-block">Make sure that gm node module and <a
|
||||||
href="http://www.graphicsmagick.org/">GraphicsMagick</a> are installed (npm install sharp)</span>
|
href="http://www.graphicsmagick.org/">GraphicsMagick</a> are installed (npm install sharp)</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -29,7 +33,7 @@
|
|||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="text" class="form-control" placeholder="path"
|
<input type="text" class="form-control" placeholder="path"
|
||||||
id="folder"
|
id="folder"
|
||||||
[(ngModel)]="settings.server.folder"
|
[(ngModel)]="_settingsService.settings.server.folder"
|
||||||
name="path" required>
|
name="path" required>
|
||||||
<span class="help-block">Thumbnails will be saved in this folder. Write access is required</span>
|
<span class="help-block">Thumbnails will be saved in this folder. Write access is required</span>
|
||||||
|
|
||||||
@ -48,7 +52,7 @@
|
|||||||
[switch-on-text]="'High'"
|
[switch-on-text]="'High'"
|
||||||
[switch-handle-width]="'100'"
|
[switch-handle-width]="'100'"
|
||||||
[switch-label-width]="'20'"
|
[switch-label-width]="'20'"
|
||||||
[(ngModel)]="settings.server.qualityPriority">
|
[(ngModel)]="_settingsService.settings.server.qualityPriority">
|
||||||
</bSwitch>
|
</bSwitch>
|
||||||
<span class="help-block">High quality may be slow. Especially with Jimp.</span>
|
<span class="help-block">High quality may be slow. Especially with Jimp.</span>
|
||||||
|
|
||||||
@ -60,7 +64,7 @@
|
|||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
<input type="number" class="form-control" placeholder="30"
|
<input type="number" class="form-control" placeholder="30"
|
||||||
id="icon"
|
id="icon"
|
||||||
[(ngModel)]="settings.client.iconSize"
|
[(ngModel)]="_settingsService.settings.client.iconSize"
|
||||||
min="1"
|
min="1"
|
||||||
max="100"
|
max="100"
|
||||||
step="1"
|
step="1"
|
||||||
|
@ -16,35 +16,24 @@ import {Utils} from "../../../../common/Utils";
|
|||||||
providers: [ThumbnailSettingsService],
|
providers: [ThumbnailSettingsService],
|
||||||
})
|
})
|
||||||
export class ThumbnailSettingsComponent extends SettingsComponent<{ server: ThumbnailConfig, client: ClientConfig.ThumbnailConfig }> {
|
export class ThumbnailSettingsComponent extends SettingsComponent<{ server: ThumbnailConfig, client: ClientConfig.ThumbnailConfig }> {
|
||||||
public settings: { server: ThumbnailConfig, client: ClientConfig.ThumbnailConfig } = <{ server: ThumbnailConfig, client: ClientConfig.ThumbnailConfig }> {
|
|
||||||
server: {
|
|
||||||
folder: "",
|
|
||||||
processingLibrary: ThumbnailProcessingLib.Jimp,
|
|
||||||
qualityPriority: true
|
|
||||||
},
|
|
||||||
client: {
|
|
||||||
iconSize: null,
|
|
||||||
thumbnailSizes: []
|
|
||||||
}
|
|
||||||
};
|
|
||||||
types: Array<any> = [];
|
types: Array<any> = [];
|
||||||
ThumbnailProcessingLib: any;
|
ThumbnailProcessingLib: any;
|
||||||
|
|
||||||
constructor(_authService: AuthenticationService,
|
constructor(_authService: AuthenticationService,
|
||||||
_navigation: NavigationService,
|
_navigation: NavigationService,
|
||||||
_settingsSettings: ThumbnailSettingsService,
|
_settingsService: ThumbnailSettingsService,
|
||||||
notification: NotificationService) {
|
notification: NotificationService) {
|
||||||
super("Thumbnail", _authService, _navigation, _settingsSettings, notification);
|
super("Thumbnail", _authService, _navigation, _settingsService, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
get ThumbnailSizes(): string {
|
get ThumbnailSizes(): string {
|
||||||
return this.settings.client.thumbnailSizes.join("; ");
|
return this._settingsService.settings.client.thumbnailSizes.join("; ");
|
||||||
}
|
}
|
||||||
|
|
||||||
set ThumbnailSizes(value: string) {
|
set ThumbnailSizes(value: string) {
|
||||||
value = value.replace(new RegExp(',', 'g'), ";");
|
value = value.replace(new RegExp(',', 'g'), ";");
|
||||||
value = value.replace(new RegExp(' ', 'g'), ";");
|
value = value.replace(new RegExp(' ', 'g'), ";");
|
||||||
this.settings.client.thumbnailSizes = value.split(";").map(s => parseInt(s)).filter(i => !isNaN(i) && i > 0);
|
this._settingsService.settings.client.thumbnailSizes = value.split(";").map(s => parseInt(s)).filter(i => !isNaN(i) && i > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
import {Injectable} from "@angular/core";
|
import {Injectable} from "@angular/core";
|
||||||
import {NetworkService} from "../../model/network/network.service";
|
import {NetworkService} from "../../model/network/network.service";
|
||||||
import {ClientConfig} from "../../../../common/config/public/ConfigClass";
|
import {ClientConfig} from "../../../../common/config/public/ConfigClass";
|
||||||
import {IPrivateConfig, ThumbnailConfig} from "../../../../common/config/private/IPrivateConfig";
|
import {ThumbnailConfig} from "../../../../common/config/private/IPrivateConfig";
|
||||||
import {ISettingsService} from "../_abstract/abstract.settings.service";
|
import {AbstractSettingsService} from "../_abstract/abstract.settings.service";
|
||||||
|
import {SettingsService} from "../settings.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ThumbnailSettingsService implements ISettingsService<{ server: ThumbnailConfig, client: ClientConfig.ThumbnailConfig }> {
|
export class ThumbnailSettingsService extends AbstractSettingsService<{ server: ThumbnailConfig, client: ClientConfig.ThumbnailConfig }> {
|
||||||
constructor(private _networkService: NetworkService) {
|
constructor(private _networkService: NetworkService,
|
||||||
|
_settingsService: SettingsService) {
|
||||||
|
super(_settingsService, s => ({client: s.Client.Thumbnail, server: s.Server.thumbnail}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getSettings(): Promise<{ server: ThumbnailConfig, client: ClientConfig.ThumbnailConfig }> {
|
|
||||||
const settings = (await <Promise<IPrivateConfig>>this._networkService.getJson("/settings"));
|
|
||||||
return {server: settings.Server.thumbnail, client: settings.Client.Thumbnail};
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateSettings(settings: { server: ThumbnailConfig, client: ClientConfig.ThumbnailConfig }): Promise<void> {
|
public updateSettings(settings: { server: ThumbnailConfig, client: ClientConfig.ThumbnailConfig }): Promise<void> {
|
||||||
return this._networkService.putJson("/settings/thumbnail", {settings: settings});
|
return this._networkService.putJson("/settings/thumbnail", {settings: settings});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user