adding config ui for faces
This commit is contained in:
parent
384d366cd3
commit
685c406e91
@ -253,6 +253,30 @@ export class AdminMWs {
|
|||||||
return next(new ErrorDTO(ErrorCodes.SETTINGS_ERROR, 'Settings error: ' + JSON.stringify(err, null, ' '), err));
|
return next(new ErrorDTO(ErrorCodes.SETTINGS_ERROR, 'Settings error: ' + JSON.stringify(err, null, ' '), err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public static async updateFacesSettings(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.testFacesConfig(<ClientConfig.FacesConfig>req.body.settings, original);
|
||||||
|
|
||||||
|
Config.Client.Faces = <ClientConfig.FacesConfig>req.body.settings;
|
||||||
|
original.Client.Faces = <ClientConfig.FacesConfig>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) {
|
||||||
|
if (err instanceof Error) {
|
||||||
|
return next(new ErrorDTO(ErrorCodes.SETTINGS_ERROR, 'Settings error: ' + err.toString(), 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) {
|
||||||
|
|||||||
@ -127,6 +127,13 @@ export class ConfigDiagnostics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static async testFacesConfig(faces: ClientConfig.FacesConfig, config: IPrivateConfig) {
|
||||||
|
if (faces.enabled === true &&
|
||||||
|
config.Server.database.type === DatabaseType.memory) {
|
||||||
|
throw new Error('Memory Database do not support faces');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static async testSearchConfig(search: ClientConfig.SearchConfig, config: IPrivateConfig) {
|
static async testSearchConfig(search: ClientConfig.SearchConfig, config: IPrivateConfig) {
|
||||||
if (search.enabled === true &&
|
if (search.enabled === true &&
|
||||||
config.Server.database.type === DatabaseType.memory) {
|
config.Server.database.type === DatabaseType.memory) {
|
||||||
@ -260,6 +267,16 @@ export class ConfigDiagnostics {
|
|||||||
Config.Client.Search.enabled = false;
|
Config.Client.Search.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ConfigDiagnostics.testFacesConfig(Config.Client.Faces, Config);
|
||||||
|
} catch (ex) {
|
||||||
|
const err: Error = ex;
|
||||||
|
NotificationManager.warning('Faces are not supported with these settings. Disabling temporally. ' +
|
||||||
|
'Please adjust the config properly.', err.toString());
|
||||||
|
Logger.warn(LOG_TAG, 'Faces are not supported with these settings, switching off..', err.toString());
|
||||||
|
Config.Client.Faces.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing, Config);
|
await ConfigDiagnostics.testSharingConfig(Config.Client.Sharing, Config);
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
|
|||||||
@ -109,6 +109,12 @@ export class AdminRouter {
|
|||||||
AdminMWs.updateSearchSettings,
|
AdminMWs.updateSearchSettings,
|
||||||
RenderingMWs.renderOK
|
RenderingMWs.renderOK
|
||||||
);
|
);
|
||||||
|
app.put('/api/settings/faces',
|
||||||
|
AuthenticationMWs.authenticate,
|
||||||
|
AuthenticationMWs.authorise(UserRoles.Admin),
|
||||||
|
AdminMWs.updateFacesSettings,
|
||||||
|
RenderingMWs.renderOK
|
||||||
|
);
|
||||||
app.put('/api/settings/share',
|
app.put('/api/settings/share',
|
||||||
AuthenticationMWs.authenticate,
|
AuthenticationMWs.authenticate,
|
||||||
AuthenticationMWs.authorise(UserRoles.Admin),
|
AuthenticationMWs.authorise(UserRoles.Admin),
|
||||||
|
|||||||
@ -80,6 +80,7 @@ import {FaceComponent} from './ui/faces/face/face.component';
|
|||||||
import {VersionService} from './model/version.service';
|
import {VersionService} from './model/version.service';
|
||||||
import { DirectoriesComponent } from './ui/gallery/directories/directories.component';
|
import { DirectoriesComponent } from './ui/gallery/directories/directories.component';
|
||||||
import {ControlsLightboxComponent} from './ui/gallery/lightbox/controls/controls.lightbox.gallery.component';
|
import {ControlsLightboxComponent} from './ui/gallery/lightbox/controls/controls.lightbox.gallery.component';
|
||||||
|
import {FacesSettingsComponent} from './ui/settings/faces/faces.settings.component';
|
||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@ -178,6 +179,7 @@ export function translationsFactory(locale: string) {
|
|||||||
ShareSettingsComponent,
|
ShareSettingsComponent,
|
||||||
RandomPhotoSettingsComponent,
|
RandomPhotoSettingsComponent,
|
||||||
BasicSettingsComponent,
|
BasicSettingsComponent,
|
||||||
|
FacesSettingsComponent,
|
||||||
OtherSettingsComponent,
|
OtherSettingsComponent,
|
||||||
IndexingSettingsComponent,
|
IndexingSettingsComponent,
|
||||||
DuplicateComponent,
|
DuplicateComponent,
|
||||||
|
|||||||
@ -62,6 +62,8 @@
|
|||||||
[simplifiedMode]="simplifiedMode"></app-settings-other>
|
[simplifiedMode]="simplifiedMode"></app-settings-other>
|
||||||
<app-settings-random-photo #random [hidden]="!random.hasAvailableSettings"
|
<app-settings-random-photo #random [hidden]="!random.hasAvailableSettings"
|
||||||
[simplifiedMode]="simplifiedMode"></app-settings-random-photo>
|
[simplifiedMode]="simplifiedMode"></app-settings-random-photo>
|
||||||
|
<app-settings-faces #random [hidden]="!random.hasAvailableSettings"
|
||||||
|
[simplifiedMode]="simplifiedMode"></app-settings-faces>
|
||||||
<app-settings-indexing #indexing [hidden]="!indexing.hasAvailableSettings"
|
<app-settings-indexing #indexing [hidden]="!indexing.hasAvailableSettings"
|
||||||
[simplifiedMode]="simplifiedMode"></app-settings-indexing>
|
[simplifiedMode]="simplifiedMode"></app-settings-indexing>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,3 +2,12 @@ app-face {
|
|||||||
margin: 2px;
|
margin: 2px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-face-msg{
|
||||||
|
height: 100vh;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-face-msg h2{
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
|||||||
@ -4,9 +4,17 @@
|
|||||||
<app-face *ngFor="let person of favourites | async"
|
<app-face *ngFor="let person of favourites | async"
|
||||||
[person]="person"
|
[person]="person"
|
||||||
[size]="size"></app-face>
|
[size]="size"></app-face>
|
||||||
<hr/>
|
<hr *ngIf="(nonFavourites | async).length > 0"/>
|
||||||
<app-face *ngFor="let person of nonFavourites | async"
|
<app-face *ngFor="let person of nonFavourites | async"
|
||||||
[person]="person"
|
[person]="person"
|
||||||
[size]="size"></app-face>
|
[size]="size"></app-face>
|
||||||
|
|
||||||
|
<div class="d-flex no-face-msg"
|
||||||
|
*ngIf="(nonFavourites | async).length == 0 && (favourites | async).length == 0">
|
||||||
|
<div class="flex-fill">
|
||||||
|
<h2>:( <ng-container i18n>No faces to show.</ng-container>
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</app-frame>
|
</app-frame>
|
||||||
|
|||||||
@ -15,10 +15,10 @@
|
|||||||
<li class="nav-item" [routerLinkActive]="['active']">
|
<li class="nav-item" [routerLinkActive]="['active']">
|
||||||
<a class="nav-link"
|
<a class="nav-link"
|
||||||
[routerLink]="['/gallery']"
|
[routerLink]="['/gallery']"
|
||||||
[queryParams]="queryService.getParams()">Gallery</a>
|
[queryParams]="queryService.getParams()" i18n>Gallery</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" [routerLinkActive]="['active']">
|
<li class="nav-item" [routerLinkActive]="['active']" *ngIf="facesEnabled">
|
||||||
<a class="nav-link" [routerLink]="['/faces']">Faces</a>
|
<a class="nav-link" [routerLink]="['/faces']" i18n>Faces</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="navbar-nav navbar-right ml-auto">
|
<ul class="navbar-nav navbar-right ml-auto">
|
||||||
|
|||||||
@ -20,6 +20,7 @@ export class FrameComponent {
|
|||||||
authenticationRequired = false;
|
authenticationRequired = false;
|
||||||
public title: string;
|
public title: string;
|
||||||
collapsed = true;
|
collapsed = true;
|
||||||
|
facesEnabled = Config.Client.Faces.enabled;
|
||||||
|
|
||||||
constructor(private _authService: AuthenticationService,
|
constructor(private _authService: AuthenticationService,
|
||||||
public notificationService: NotificationService,
|
public notificationService: NotificationService,
|
||||||
|
|||||||
@ -57,10 +57,13 @@ export class GalleryPhotoComponent implements IRenderable, OnInit, OnDestroy {
|
|||||||
const metadata = this.gridMedia.media.metadata as PhotoMetadata;
|
const metadata = this.gridMedia.media.metadata as PhotoMetadata;
|
||||||
if ((metadata.keywords && metadata.keywords.length > 0) ||
|
if ((metadata.keywords && metadata.keywords.length > 0) ||
|
||||||
(metadata.faces && metadata.faces.length > 0)) {
|
(metadata.faces && metadata.faces.length > 0)) {
|
||||||
const names: string[] = (metadata.faces || []).map(f => f.name);
|
this.keywords = [];
|
||||||
this.keywords = names.filter((name, index) => names.indexOf(name) === index)
|
if (Config.Client.Faces.enabled) {
|
||||||
.map(n => ({value: n, type: SearchTypes.person}))
|
const names: string[] = (metadata.faces || []).map(f => f.name);
|
||||||
.concat((metadata.keywords || []).map(k => ({value: k, type: SearchTypes.keyword})));
|
this.keywords = names.filter((name, index) => names.indexOf(name) === index)
|
||||||
|
.map(n => ({value: n, type: SearchTypes.person}));
|
||||||
|
}
|
||||||
|
this.keywords = this.keywords.concat((metadata.keywords || []).map(k => ({value: k, type: SearchTypes.keyword})));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,7 +55,7 @@
|
|||||||
[style.left.px]="photoFrameDim.width/2"
|
[style.left.px]="photoFrameDim.width/2"
|
||||||
[style.width.px]="faceContainerDim.width"
|
[style.width.px]="faceContainerDim.width"
|
||||||
[style.height.px]="faceContainerDim.height"
|
[style.height.px]="faceContainerDim.height"
|
||||||
*ngIf="activePhoto && zoom == 1">
|
*ngIf="facesEnabled && activePhoto && zoom == 1">
|
||||||
<a
|
<a
|
||||||
class="face"
|
class="face"
|
||||||
[routerLink]="['/search', face.name, {type: SearchTypes[SearchTypes.person]}]"
|
[routerLink]="['/search', face.name, {type: SearchTypes[SearchTypes.person]}]"
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {filter} from 'rxjs/operators';
|
|||||||
import {PhotoDTO} from '../../../../../../common/entities/PhotoDTO';
|
import {PhotoDTO} from '../../../../../../common/entities/PhotoDTO';
|
||||||
import {GalleryLightboxMediaComponent} from '../media/media.lightbox.gallery.component';
|
import {GalleryLightboxMediaComponent} from '../media/media.lightbox.gallery.component';
|
||||||
import {SearchTypes} from '../../../../../../common/entities/AutoCompleteItem';
|
import {SearchTypes} from '../../../../../../common/entities/AutoCompleteItem';
|
||||||
|
import {Config} from '../../../../../../common/config/public/Config';
|
||||||
|
|
||||||
export enum PlayBackStates {
|
export enum PlayBackStates {
|
||||||
Paused = 1,
|
Paused = 1,
|
||||||
@ -36,6 +37,7 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges {
|
|||||||
@Input() mediaElement: GalleryLightboxMediaComponent;
|
@Input() mediaElement: GalleryLightboxMediaComponent;
|
||||||
@Input() photoFrameDim = {width: 1, height: 1, aspect: 1};
|
@Input() photoFrameDim = {width: 1, height: 1, aspect: 1};
|
||||||
|
|
||||||
|
public readonly facesEnabled = Config.Client.Faces.enabled;
|
||||||
|
|
||||||
public zoom = 1;
|
public zoom = 1;
|
||||||
public playBackState: PlayBackStates = PlayBackStates.Paused;
|
public playBackState: PlayBackStates = PlayBackStates.Paused;
|
||||||
@ -44,6 +46,7 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges {
|
|||||||
public controllersAlwaysOn = false;
|
public controllersAlwaysOn = false;
|
||||||
public controllersVisible = true;
|
public controllersVisible = true;
|
||||||
public drag = {x: 0, y: 0};
|
public drag = {x: 0, y: 0};
|
||||||
|
public SearchTypes = SearchTypes;
|
||||||
private visibilityTimer: number = null;
|
private visibilityTimer: number = null;
|
||||||
private timer: Observable<number>;
|
private timer: Observable<number>;
|
||||||
private timerSub: Subscription;
|
private timerSub: Subscription;
|
||||||
@ -51,8 +54,6 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges {
|
|||||||
private prevZoom = 1;
|
private prevZoom = 1;
|
||||||
private faceContainerDim = {width: 0, height: 0};
|
private faceContainerDim = {width: 0, height: 0};
|
||||||
|
|
||||||
public SearchTypes = SearchTypes;
|
|
||||||
|
|
||||||
constructor(public fullScreenService: FullScreenService) {
|
constructor(public fullScreenService: FullScreenService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -54,6 +54,8 @@ export class GalleryMapLightboxComponent implements OnChanges, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
|
// TODO: remove it once yaga/leaflet-ng2 is fixes.
|
||||||
|
// See issue: https://github.com/yagajs/leaflet-ng2/issues/440
|
||||||
let i = 0;
|
let i = 0;
|
||||||
this.yagaMap.eachLayer(l => {
|
this.yagaMap.eachLayer(l => {
|
||||||
if (i >= 3 || (this.paths.length === 0 && i >= 2)) {
|
if (i >= 3 || (this.paths.length === 0 && i >= 2)) {
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export abstract class SettingsComponent<T extends { [key: string]: any }, S exte
|
|||||||
private readonly _settingsSubscription: Subscription = null;
|
private readonly _settingsSubscription: Subscription = null;
|
||||||
|
|
||||||
protected constructor(private name: string,
|
protected constructor(private name: string,
|
||||||
private _authService: AuthenticationService,
|
protected _authService: AuthenticationService,
|
||||||
private _navigation: NavigationService,
|
private _navigation: NavigationService,
|
||||||
public _settingsService: S,
|
public _settingsService: S,
|
||||||
protected notification: NotificationService,
|
protected notification: NotificationService,
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
.panel-info {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
72
frontend/app/ui/settings/faces/faces.settings.component.html
Normal file
72
frontend/app/ui/settings/faces/faces.settings.component.html
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<form #settingsForm="ngForm">
|
||||||
|
<div class="card mb-4"
|
||||||
|
[ngClass]="settings.enabled && !_settingsService.isSupported()?'panel-warning':''">
|
||||||
|
<h5 class="card-header">
|
||||||
|
<ng-container i18n>Faces settings</ng-container>
|
||||||
|
<div class="switch-wrapper">
|
||||||
|
<bSwitch
|
||||||
|
class="switch"
|
||||||
|
name="enabled"
|
||||||
|
[switch-on-color]="'success'"
|
||||||
|
[switch-inverse]="true"
|
||||||
|
[switch-off-text]="text.Disabled"
|
||||||
|
[switch-on-text]="text.Enabled"
|
||||||
|
[switch-disabled]="inProgress || (!settings.enabled && !_settingsService.isSupported())"
|
||||||
|
[switch-handle-width]="100"
|
||||||
|
[switch-label-width]="20"
|
||||||
|
[(ngModel)]="settings.enabled">
|
||||||
|
</bSwitch>
|
||||||
|
</div>
|
||||||
|
</h5>
|
||||||
|
<div class="card-body">
|
||||||
|
<div [hidden]="!error" class="alert alert-danger" role="alert"><strong>Error: </strong>{{error}}</div>
|
||||||
|
|
||||||
|
<ng-container *ngIf="settings.enabled || _settingsService.isSupported()">
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-2 control-label" for="autocompleteEnabled" i18n>Override keywords</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<bSwitch
|
||||||
|
id="autocompleteEnabled"
|
||||||
|
class="switch"
|
||||||
|
name="autocompleteEnabled"
|
||||||
|
[switch-on-color]="'primary'"
|
||||||
|
[switch-disabled]="!settings.enabled"
|
||||||
|
[switch-inverse]="true"
|
||||||
|
[switch-off-text]="text.Disabled"
|
||||||
|
[switch-on-text]="text.Enabled"
|
||||||
|
[switch-handle-width]="100"
|
||||||
|
[switch-label-width]="20"
|
||||||
|
[(ngModel)]="settings.keywordsToPersons">
|
||||||
|
</bSwitch>
|
||||||
|
<small class="form-text text-muted" i18n>If a photo has the same face (person) name and keyword, the app removes the duplicate, keeping the face only.</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-md-2 control-label" for="writeAccessMinRole" i18n>Face starring right</label>
|
||||||
|
<div class="col-md-10">
|
||||||
|
<select class="form-control" [(ngModel)]="settings.writeAccessMinRole" name="writeAccessMinRole" id="writeAccessMinRole" required>
|
||||||
|
<option *ngFor="let repository of userRoles" [value]="repository.key">{{repository.value}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
<small class="form-text text-muted" i18n>Required minimum right to start (favourite) a face.</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ng-container>
|
||||||
|
<div class="panel-info" *ngIf="(!settings.enabled && !_settingsService.isSupported())" i18n>
|
||||||
|
Faces are not supported with these settings.
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-success float-right"
|
||||||
|
[disabled]="!settingsForm.form.valid || !changed || inProgress"
|
||||||
|
(click)="save()" i18n>Save
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-secondary float-right"
|
||||||
|
(click)="reset()" i18n>Reset
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
40
frontend/app/ui/settings/faces/faces.settings.component.ts
Normal file
40
frontend/app/ui/settings/faces/faces.settings.component.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
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 {FacesSettingsService} from './faces.settings.service';
|
||||||
|
import {I18n} from '@ngx-translate/i18n-polyfill';
|
||||||
|
import {Utils} from '../../../../../common/Utils';
|
||||||
|
import {UserRoles} from '../../../../../common/entities/UserDTO';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-settings-faces',
|
||||||
|
templateUrl: './faces.settings.component.html',
|
||||||
|
styleUrls: ['./faces.settings.component.css',
|
||||||
|
'./../_abstract/abstract.settings.component.css'],
|
||||||
|
providers: [FacesSettingsService],
|
||||||
|
})
|
||||||
|
export class FacesSettingsComponent extends SettingsComponent<ClientConfig.FacesConfig> {
|
||||||
|
|
||||||
|
public userRoles: Array<any> = [];
|
||||||
|
constructor(_authService: AuthenticationService,
|
||||||
|
_navigation: NavigationService,
|
||||||
|
_settingsService: FacesSettingsService,
|
||||||
|
notification: NotificationService,
|
||||||
|
i18n: I18n) {
|
||||||
|
super(i18n('Faces'), _authService, _navigation, _settingsService, notification, i18n, s => s.Client.Faces);
|
||||||
|
|
||||||
|
this.userRoles = Utils
|
||||||
|
.enumToArray(UserRoles)
|
||||||
|
.filter(r => r.key !== UserRoles.LimitedGuest)
|
||||||
|
.filter(r => r.key <= this._authService.user.value.role)
|
||||||
|
.sort((a, b) => a.key - b.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
23
frontend/app/ui/settings/faces/faces.settings.service.ts
Normal file
23
frontend/app/ui/settings/faces/faces.settings.service.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
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 FacesSettingsService extends AbstractSettingsService<ClientConfig.FacesConfig> {
|
||||||
|
constructor(private _networkService: NetworkService,
|
||||||
|
_settingsService: SettingsService) {
|
||||||
|
super(_settingsService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isSupported(): boolean {
|
||||||
|
return this._settingsService.settings.value.Server.database.type !== DatabaseType.memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateSettings(settings: ClientConfig.FacesConfig): Promise<void> {
|
||||||
|
return this._networkService.putJson('/settings/faces', {settings: settings});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user