updating settings page

This commit is contained in:
Patrik J. Braun 2019-08-20 12:54:45 +02:00
parent 3633168ee4
commit 2012ec3d91
31 changed files with 313 additions and 60 deletions

View File

@ -74,6 +74,7 @@
"tsConfig": "frontend/tsconfig.spec.json", "tsConfig": "frontend/tsconfig.spec.json",
"scripts": [], "scripts": [],
"styles": [ "styles": [
"./node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/ngx-toastr/toastr.css", "node_modules/ngx-toastr/toastr.css",
"node_modules/bootstrap/dist/css/bootstrap.css", "node_modules/bootstrap/dist/css/bootstrap.css",
"node_modules/open-iconic/font/css/open-iconic-bootstrap.css", "node_modules/open-iconic/font/css/open-iconic-bootstrap.css",

View File

@ -3,7 +3,7 @@ import {ErrorCodes, ErrorDTO} from '../../common/entities/Error';
import {ObjectManagers} from '../model/ObjectManagers'; import {ObjectManagers} from '../model/ObjectManagers';
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, TaskConfig, ThumbnailConfig} from '../../common/config/private/IPrivateConfig';
import {Config} from '../../common/config/private/Config'; import {Config} from '../../common/config/private/Config';
import {ConfigDiagnostics} from '../model/diagnostics/ConfigDiagnostics'; import {ConfigDiagnostics} from '../model/diagnostics/ConfigDiagnostics';
import {ClientConfig} from '../../common/config/public/ConfigClass'; import {ClientConfig} from '../../common/config/public/ConfigClass';
@ -440,6 +440,35 @@ export class AdminMWs {
} }
public static async updateTasksSettings(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 settings: TaskConfig = req.body.settings;
const original = Config.original();
await ConfigDiagnostics.testTasksConfig(settings, original);
Config.Server.tasks = settings;
original.Server.tasks = 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 startTask(req: Request, res: Response, next: NextFunction) { public static startTask(req: Request, res: Response, next: NextFunction) {
try { try {
const id = req.params.id; const id = req.params.id;

View File

@ -3,6 +3,7 @@ import {
DataBaseConfig, DataBaseConfig,
DatabaseType, DatabaseType,
IPrivateConfig, IPrivateConfig,
TaskConfig,
ThumbnailConfig, ThumbnailConfig,
ThumbnailProcessingLib ThumbnailProcessingLib
} from '../../../common/config/private/IPrivateConfig'; } from '../../../common/config/private/IPrivateConfig';
@ -127,6 +128,10 @@ export class ConfigDiagnostics {
} }
static async testTasksConfig(faces: TaskConfig, config: IPrivateConfig) {
}
static async testFacesConfig(faces: ClientConfig.FacesConfig, config: IPrivateConfig) { static async testFacesConfig(faces: ClientConfig.FacesConfig, config: IPrivateConfig) {
if (faces.enabled === true) { if (faces.enabled === true) {
if (config.Server.database.type === DatabaseType.memory) { if (config.Server.database.type === DatabaseType.memory) {
@ -281,6 +286,17 @@ export class ConfigDiagnostics {
Config.Client.Faces.enabled = false; Config.Client.Faces.enabled = false;
} }
try {
await ConfigDiagnostics.testTasksConfig(Config.Server.tasks, Config);
} catch (ex) {
const err: Error = ex;
NotificationManager.warning('Some Tasks are not supported with these settings. Disabling temporally. ' +
'Please adjust the config properly.', err.toString());
Logger.warn(LOG_TAG, 'Some Tasks 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) {

View File

@ -3,6 +3,7 @@ import {TaskProgressDTO} from '../../../common/entities/settings/TaskProgressDTO
import {ITask} from './ITask'; import {ITask} from './ITask';
import {TaskRepository} from './TaskRepository'; import {TaskRepository} from './TaskRepository';
import {Config} from '../../../common/config/private/Config'; import {Config} from '../../../common/config/private/Config';
import {TaskTriggerType} from '../../../common/entities/task/TaskScheduleDTO';
export class TaskManager implements ITaskManager { export class TaskManager implements ITaskManager {
@ -31,6 +32,34 @@ export class TaskManager implements ITaskManager {
return TaskRepository.Instance.getAvailableTasks(); return TaskRepository.Instance.getAvailableTasks();
} }
public runSchedules(): void {
Config.Server.tasks.scheduled.forEach(schedule => {
let nextRun = null;
switch (schedule.trigger.type) {
case TaskTriggerType.scheduled:
nextRun = Date.now() - schedule.trigger.time;
break;
/*case TaskTriggerType.periodic:
//TODo finish it
const getNextDayOfTheWeek = (dayOfWeek: number) => {
const refDate = new Date();
refDate.setHours(0, 0, 0, 0);
refDate.setDate(refDate.getDate() + (dayOfWeek + 7 - refDate.getDay()) % 7);
return refDate;
};
nextRun = Date.now() - schedule.trigger.periodicity;
break;*/
}
if (nextRun != null) {
setTimeout(() => {
this.start(schedule.taskName, schedule.config);
}, nextRun);
}
});
}
protected findTask(taskName: string): ITask<any> { protected findTask(taskName: string): ITask<any> {
return this.getAvailableTasks().find(t => t.Name === taskName); return this.getAvailableTasks().find(t => t.Name === taskName);

View File

@ -174,6 +174,12 @@ export class AdminRouter {
AdminMWs.updateIndexingSettings, AdminMWs.updateIndexingSettings,
RenderingMWs.renderOK RenderingMWs.renderOK
); );
app.put('/api/settings/tasks',
AuthenticationMWs.authenticate,
AuthenticationMWs.authorise(UserRoles.Admin),
AdminMWs.updateTasksSettings,
RenderingMWs.renderOK
);
} }

View File

@ -12,7 +12,7 @@ import * as path from 'path';
import {ConfigLoader} from 'typeconfig'; import {ConfigLoader} from 'typeconfig';
import {Utils} from '../../Utils'; import {Utils} from '../../Utils';
import {UserRoles} from '../../entities/UserDTO'; import {UserRoles} from '../../entities/UserDTO';
import {TaskScheduleDTO, TaskTriggerType} from '../../entities/task/TaskScheduleDTO'; import {TaskScheduleDTO} from '../../entities/task/TaskScheduleDTO';
import {Config} from './Config'; import {Config} from './Config';
/** /**
@ -65,28 +65,7 @@ export class PrivateConfigClass extends PublicConfigClass implements IPrivateCon
listingLimit: 1000 listingLimit: 1000
}, },
tasks: { tasks: {
scheduled: [ scheduled: []
{
priority: 1,
taskName: 'indexing',
config: null,
trigger: {
type: TaskTriggerType.periodic,
time: {
offset: 0,
repeat: 10
}
}
},
{
priority: 2,
taskName: 'Database reset',
config: null,
trigger: {
type: TaskTriggerType.never
}
}
]
} }
}; };
private ConfigLoader: any; private ConfigLoader: any;

View File

@ -12,15 +12,13 @@ export interface NeverTaskTrigger {
export interface ScheduledTaskTrigger extends TaskTrigger { export interface ScheduledTaskTrigger extends TaskTrigger {
type: TaskTriggerType.scheduled; type: TaskTriggerType.scheduled;
time: number; time: number; // data time
} }
export interface PeriodicTaskTrigger extends TaskTrigger { export interface PeriodicTaskTrigger extends TaskTrigger {
type: TaskTriggerType.periodic; type: TaskTriggerType.periodic;
time: { periodicity: number; // 1-7: week days 8+ every x days
offset: number, atTime: number; // day time
repeat: number
};
} }
export interface TaskScheduleDTO { export interface TaskScheduleDTO {

View File

@ -83,6 +83,10 @@ import {ControlsLightboxComponent} from './ui/gallery/lightbox/controls/controls
import {FacesSettingsComponent} from './ui/settings/faces/faces.settings.component'; import {FacesSettingsComponent} from './ui/settings/faces/faces.settings.component';
import {TasksSettingsComponent} from './ui/settings/tasks/tasks.settings.component'; import {TasksSettingsComponent} from './ui/settings/tasks/tasks.settings.component';
import {ScheduledTasksService} from './ui/settings/scheduled-tasks.service'; import {ScheduledTasksService} from './ui/settings/scheduled-tasks.service';
import {TimepickerModule} from 'ngx-bootstrap/timepicker';
import {TimeStampDatePickerComponent} from './ui/utils/timestamp-datepicker/datepicker.component';
import {TimeStampTimePickerComponent} from './ui/utils/timestamp-timepicker/timepicker.component';
@Injectable() @Injectable()
@ -141,7 +145,8 @@ export function translationsFactory(locale: string) {
BsDropdownModule.forRoot(), BsDropdownModule.forRoot(),
SlimLoadingBarModule.forRoot(), SlimLoadingBarModule.forRoot(),
BsDatepickerModule.forRoot(), BsDatepickerModule.forRoot(),
YagaModule YagaModule,
TimepickerModule.forRoot()
], ],
declarations: [AppComponent, declarations: [AppComponent,
LoginComponent, LoginComponent,
@ -151,6 +156,8 @@ export function translationsFactory(locale: string) {
// misc // misc
FrameComponent, FrameComponent,
LanguageComponent, LanguageComponent,
TimeStampDatePickerComponent,
TimeStampTimePickerComponent,
// Gallery // Gallery
GalleryLightboxMediaComponent, GalleryLightboxMediaComponent,
GalleryPhotoLoadingComponent, GalleryPhotoLoadingComponent,

View File

@ -14,7 +14,7 @@ import {Config} from '../../../../common/config/public/Config';
}) })
export class AdminComponent implements OnInit { export class AdminComponent implements OnInit {
simplifiedMode = true; simplifiedMode = false;
text = { text = {
Advanced: 'Advanced', Advanced: 'Advanced',
Simplified: 'Simplified' Simplified: 'Simplified'

View File

@ -74,7 +74,8 @@ export abstract class SettingsComponent<T extends { [key: string]: any }, S exte
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
const key = keys[i]; const key = keys[i];
if (typeof original[key] === 'undefined') { if (typeof original[key] === 'undefined') {
throw new Error('unknown settings: ' + key); console.warn('unknown settings: ' + key);
return false;
} }
if (typeof original[key] === 'object') { if (typeof original[key] === 'object') {
if (this.settingsSame(newSettings[key], original[key]) === false) { if (this.settingsSame(newSettings[key], original[key]) === false) {
@ -88,6 +89,13 @@ export abstract class SettingsComponent<T extends { [key: string]: any }, S exte
return true; return true;
} }
public testSettingChanges() {
// TODO: fix after this issue is fixed: https://github.com/angular/angular/issues/24818
setTimeout(() => {
this.changed = !this.settingsSame(this.settings, this.original);
}, 0);
}
ngOnInit() { ngOnInit() {
if (!this._authService.isAuthenticated() || if (!this._authService.isAuthenticated() ||
this._authService.user.value.role < UserRoles.Admin) { this._authService.user.value.role < UserRoles.Admin) {
@ -98,9 +106,7 @@ export abstract class SettingsComponent<T extends { [key: string]: any }, S exte
// TODO: fix after this issue is fixed: https://github.com/angular/angular/issues/24818 // TODO: fix after this issue is fixed: https://github.com/angular/angular/issues/24818
this._subscription = this.form.valueChanges.subscribe(() => { this._subscription = this.form.valueChanges.subscribe(() => {
setTimeout(() => { this.testSettingChanges();
this.changed = !this.settingsSame(this.settings, this.original);
}, 0);
}); });
} }

View File

@ -1,7 +1,7 @@
<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>
Basic settings <ng-container i18n>Basic settings</ng-container><ng-container *ngIf="changed">*</ng-container>
</h5> </h5>
<div class="card-body"> <div class="card-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>

View File

@ -1,6 +1,6 @@
<div class="card mb-4"> <div class="card mb-4">
<h5 class="card-header" i18n> <h5 class="card-header" i18n>
Database settings <ng-container i18n>Database settings</ng-container><ng-container *ngIf="changed">*</ng-container>
</h5> </h5>
<div class="card-body"> <div class="card-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>

View File

@ -2,7 +2,7 @@
<div class="card mb-4" <div class="card mb-4"
[ngClass]="settings.enabled && !_settingsService.isSupported()?'panel-warning':''"> [ngClass]="settings.enabled && !_settingsService.isSupported()?'panel-warning':''">
<h5 class="card-header"> <h5 class="card-header">
<ng-container i18n>Faces settings</ng-container> <ng-container i18n>Faces settings</ng-container><ng-container *ngIf="changed">*</ng-container>
<div class="switch-wrapper"> <div class="switch-wrapper">
<bSwitch <bSwitch
class="switch" class="switch"

View File

@ -1,7 +1,7 @@
<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>
Folder indexing <ng-container i18n>Folder indexing</ng-container><ng-container *ngIf="changed">*</ng-container>
</h5> </h5>
<div class="card-body"> <div class="card-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>

View File

@ -1,7 +1,7 @@
<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"> <h5 class="card-header">
<ng-container i18n>Map settings</ng-container> <ng-container i18n>Map settings</ng-container><ng-container *ngIf="changed">*</ng-container>
<div class="switch-wrapper"> <div class="switch-wrapper">
<bSwitch <bSwitch
class="switch" class="switch"

View File

@ -1,7 +1,7 @@
<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"> <h5 class="card-header">
<ng-container i18n>Meta file settings</ng-container> <ng-container i18n>Meta file settings</ng-container><ng-container *ngIf="changed">*</ng-container>
<div class="switch-wrapper"> <div class="switch-wrapper">
<bSwitch <bSwitch
class="switch" class="switch"

View File

@ -1,7 +1,7 @@
<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 <ng-container i18n>Other settings</ng-container><ng-container *ngIf="changed">*</ng-container>
</h5> </h5>
<div class="card-body"> <div class="card-body">
<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>

View File

@ -2,7 +2,7 @@
<div class="card mb-4" <div class="card mb-4"
[ngClass]="settings.enabled && !_settingsService.isSupported()?'panel-warning':''"> [ngClass]="settings.enabled && !_settingsService.isSupported()?'panel-warning':''">
<h5 class="card-header"> <h5 class="card-header">
<ng-container i18n>Random Photo settings</ng-container> <ng-container i18n>Random Photo settings</ng-container><ng-container *ngIf="changed">*</ng-container>
<div class="switch-wrapper"> <div class="switch-wrapper">
<bSwitch <bSwitch
class="switch" class="switch"

View File

@ -44,11 +44,15 @@ export class ScheduledTasksService {
if (this.timer != null || this.subscribers === 0) { if (this.timer != null || this.subscribers === 0) {
return; return;
} }
let repeatTime = 5000;
if (Object.values(this.progress.value).length === 0) {
repeatTime = 10000;
}
this.timer = window.setTimeout(async () => { this.timer = window.setTimeout(async () => {
await this.getProgress(); await this.getProgress();
this.timer = null; this.timer = null;
this.getProgressPeriodically(); this.getProgressPeriodically();
}, 5000); }, repeatTime);
} }
private incSubscribers() { private incSubscribers() {

View File

@ -2,7 +2,7 @@
<div class="card mb-4" <div class="card mb-4"
[ngClass]="settings.enabled && !_settingsService.isSupported()?'panel-warning':''"> [ngClass]="settings.enabled && !_settingsService.isSupported()?'panel-warning':''">
<h5 class="card-header"> <h5 class="card-header">
<ng-container i18n>Search settings</ng-container> <ng-container i18n>Search settings</ng-container><ng-container *ngIf="changed">*</ng-container>
<div class="switch-wrapper"> <div class="switch-wrapper">
<bSwitch <bSwitch
class="switch" class="switch"

View File

@ -2,7 +2,7 @@
<div class="card mb-4" <div class="card mb-4"
[ngClass]="settings.enabled && !_settingsService.isSupported()?'panel-warning':''"> [ngClass]="settings.enabled && !_settingsService.isSupported()?'panel-warning':''">
<h5 class="card-header"> <h5 class="card-header">
<ng-container i18n>Share settings</ng-container> <ng-container i18n>Share settings</ng-container><ng-container *ngIf="changed">*</ng-container>
<div class="switch-wrapper"> <div class="switch-wrapper">
<bSwitch <bSwitch
class="switch" class="switch"

View File

@ -1,7 +1,8 @@
<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>
Tasks <ng-container i18n>Tasks</ng-container>
<ng-container *ngIf="changed">*</ng-container>
</h5> </h5>
<div class="card-body"> <div class="card-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>
@ -24,6 +25,36 @@
[ngValue]="availableTask.Name">{{availableTask.Name}} [ngValue]="availableTask.Name">{{availableTask.Name}}
</option> </option>
</select> </select>
<div class="row">
<select class="form-control" [(ngModel)]="schedule.trigger.type"
(ngModelChange)="taskTriggerTypeChanged($event,schedule)"
[name]="'repeatType'+i" required>
<option *ngFor="let taskTrigger of taskTriggerType"
[ngValue]="taskTrigger.key">{{taskTrigger.value}}
</option>
</select>
<app-timestamp-datepicker
[name]="'triggerTime'+i"
*ngIf="schedule.trigger.type== TaskTriggerType.scheduled"
[(timestamp)]="schedule.trigger.time"></app-timestamp-datepicker>
<select *ngIf="schedule.trigger.type== TaskTriggerType.periodic"
class="form-control" [(ngModel)]="schedule.trigger.periodicity" [name]="'periodicity'+i"
required>
<option *ngFor="let period of periods; let i= index"
[ngValue]="i">
<ng-container i18n>every</ng-container>
{{period}}
</option>
</select>
<app-timestamp-timepicker
[name]="'atTime'+i"
(timestampChange)="testSettingChanges()"
*ngIf="schedule.trigger.type== TaskTriggerType.periodic"
[(timestamp)]="schedule.trigger.atTime"></app-timestamp-timepicker>
</div>
</div> </div>
<div> <div>
<button class="btn btn-success" <button class="btn btn-success"
@ -31,7 +62,7 @@
[disabled]="disableButtons" [disabled]="disableButtons"
title="Trigger task run manually" title="Trigger task run manually"
i18n-title i18n-title
(click)="start(schedule)" i18n>Start (click)="start(schedule)" i18n>Start now
</button> </button>
<button class="btn btn-secondary" <button class="btn btn-secondary"
*ngIf="tasksService.progress.value[schedule.taskName]" *ngIf="tasksService.progress.value[schedule.taskName]"
@ -110,6 +141,13 @@
</div> </div>
</div> </div>
</div> </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>
</div> </div>

View File

@ -8,19 +8,29 @@ import {SettingsComponent} from '../_abstract/abstract.settings.component';
import {I18n} from '@ngx-translate/i18n-polyfill'; import {I18n} from '@ngx-translate/i18n-polyfill';
import {ErrorDTO} from '../../../../../common/entities/Error'; import {ErrorDTO} from '../../../../../common/entities/Error';
import {ScheduledTasksService} from '../scheduled-tasks.service'; import {ScheduledTasksService} from '../scheduled-tasks.service';
import {TaskScheduleDTO} from '../../../../../common/entities/task/TaskScheduleDTO'; import {
NeverTaskTrigger,
PeriodicTaskTrigger,
ScheduledTaskTrigger,
TaskScheduleDTO,
TaskTriggerType
} from '../../../../../common/entities/task/TaskScheduleDTO';
import {Utils} from '../../../../../common/Utils';
@Component({ @Component({
selector: 'app-settings-tasks', selector: 'app-settings-tasks',
templateUrl: './tasks.settings.component.html', templateUrl: './tasks.settings.component.html',
styleUrls: ['./tasks.settings.component.css', styleUrls: ['./tasks.settings.component.css',
'./../_abstract/abstract.settings.component.css'], './../_abstract/abstract.settings.component.css'],
providers: [TasksSettingsService], providers: [TasksSettingsService]
}) })
export class TasksSettingsComponent extends SettingsComponent<TaskConfig, TasksSettingsService> export class TasksSettingsComponent extends SettingsComponent<TaskConfig, TasksSettingsService>
implements OnInit, OnDestroy, OnChanges { implements OnInit, OnDestroy, OnChanges {
disableButtons = false; disableButtons = false;
taskTriggerType: { key: number, value: string }[];
TaskTriggerType = TaskTriggerType;
periods: string[] = [];
constructor(_authService: AuthenticationService, constructor(_authService: AuthenticationService,
_navigation: NavigationService, _navigation: NavigationService,
@ -37,7 +47,15 @@ export class TasksSettingsComponent extends SettingsComponent<TaskConfig, TasksS
i18n, i18n,
s => s.Server.tasks); s => s.Server.tasks);
this.hasAvailableSettings = !this.simplifiedMode; this.hasAvailableSettings = !this.simplifiedMode;
this.taskTriggerType = Utils.enumToArray(TaskTriggerType);
this.periods = [this.i18n('Monday'),
this.i18n('Tuesday'),
this.i18n('Wednesday'),
this.i18n('Thursday'),
this.i18n('Friday'),
this.i18n('Saturday'),
this.i18n('Sunday'),
this.i18n('day')];
} }
@ -130,6 +148,34 @@ export class TasksSettingsComponent extends SettingsComponent<TaskConfig, TasksS
} }
update($event: string, trigger: ScheduledTaskTrigger) {
if (!$event) {
return;
}
console.log(typeof $event);
console.log($event);
console.log(new Date($event));
console.log(new Date($event).getTime());
trigger.time = new Date($event).getTime();
}
toDate(time: number) {
return new Date(time);
}
taskTriggerTypeChanged(triggerType: TaskTriggerType, schedule: TaskScheduleDTO) {
schedule.trigger = <NeverTaskTrigger>{type: triggerType};
switch (triggerType) {
case TaskTriggerType.scheduled:
(<ScheduledTaskTrigger><unknown>schedule.trigger).time = (Date.now());
break;
case TaskTriggerType.periodic:
(<PeriodicTaskTrigger><unknown>schedule.trigger).periodicity = null;
(<PeriodicTaskTrigger><unknown>schedule.trigger).atTime = null;
break;
}
}
} }

View File

@ -1,7 +1,7 @@
<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>
Thumbnail settings <ng-container i18n>Thumbnail settings</ng-container><ng-container *ngIf="changed">*</ng-container>
</h5> </h5>
<div class="card-body"> <div class="card-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>

View File

@ -1,7 +1,7 @@
<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"> <h5 class="card-header">
<ng-container i18n>Video settings</ng-container> <ng-container i18n>Video settings</ng-container><ng-container *ngIf="changed">*</ng-container>
<div class="switch-wrapper"> <div class="switch-wrapper">
<bSwitch <bSwitch
class="switch" class="switch"

View File

@ -0,0 +1,8 @@
<input
class="form-control"
[name]="name"
bsDatepicker
[ngModel]="date"
(ngModelChange)="onChange($event)"
[bsConfig]="{ dateInputFormat: 'YYYY.MM.DD, h:mm' }"
required>

View File

@ -0,0 +1,37 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
@Component({
selector: 'app-timestamp-datepicker',
templateUrl: './datepicker.component.html',
})
export class TimeStampDatePickerComponent {
timestampValue = 0;
@Output() timestampChange = new EventEmitter<number>();
date: Date = new Date();
@Input() name: string;
@Input()
public get timestamp() {
return this.timestampValue;
}
public set timestamp(val: number) {
this.date.setTime(val);
if (this.timestampValue === val) {
return;
}
this.timestampValue = val;
this.timestampChange.emit(this.timestampValue);
}
onChange(date: Date | string) {
this.timestamp = (new Date(date)).getTime();
}
}

View File

@ -0,0 +1,10 @@
<timepicker
class="form-control"
[name]="name"
[ngModel]="date"
[showSpinners]="false"
[showMeridian]="false"
[mousewheel]="true"
[arrowkeys]="true"
(ngModelChange)="onChange($event)"
required></timepicker>

View File

@ -0,0 +1,38 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
@Component({
selector: 'app-timestamp-timepicker',
templateUrl: './timepicker.component.html',
})
export class TimeStampTimePickerComponent {
timestampValue = 0;
@Output() timestampChange = new EventEmitter<number>();
date: Date = new Date();
@Input() name: string;
@Input()
public get timestamp() {
return this.timestampValue;
}
public set timestamp(val: number) {
this.date.setTime(val);
if (this.timestampValue === val) {
return;
}
this.timestampValue = val;
this.timestampChange.emit(this.timestampValue);
}
onChange(date: Date | string) {
this.timestamp = (new Date(date)).getTime();
}
}

11
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "pigallery2", "name": "pigallery2",
"version": "1.6.5", "version": "1.7.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -4536,8 +4536,7 @@
"bootstrap": { "bootstrap": {
"version": "4.3.1", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz",
"integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==", "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag=="
"dev": true
}, },
"boxen": { "boxen": {
"version": "3.2.0", "version": "3.2.0",
@ -12243,9 +12242,9 @@
"dev": true "dev": true
}, },
"ngx-bootstrap": { "ngx-bootstrap": {
"version": "5.1.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-5.1.0.tgz", "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-4.3.0.tgz",
"integrity": "sha512-gHmIH1dZcZgbgu9Y88iPa8JaMkSM1QrU1zPDSJIw5TUNXVbwhvi5bzh2ttjvL88agyVWmTHM0mgyntPAgULxCQ==", "integrity": "sha512-ZPS6V2yLEeqB/7KIlVohS8qUdtFa1bgUB/sSPWRcXqOWU3EKhORetZoXG6m2F5ILYDe5hwQvBEjdHPlEz2piOg==",
"dev": true "dev": true
}, },
"ngx-clipboard": { "ngx-clipboard": {

View File

@ -29,6 +29,7 @@
"dependencies": { "dependencies": {
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"body-parser": "1.19.0", "body-parser": "1.19.0",
"bootstrap": "4.1.1",
"cookie-parser": "1.4.4", "cookie-parser": "1.4.4",
"cookie-session": "2.0.0-beta.3", "cookie-session": "2.0.0-beta.3",
"ejs": "2.6.2", "ejs": "2.6.2",
@ -39,6 +40,7 @@
"jdataview": "2.5.0", "jdataview": "2.5.0",
"jimp": "0.6.4", "jimp": "0.6.4",
"locale": "0.1.0", "locale": "0.1.0",
"ngx-bootstrap": "^4.1.1",
"npm-check-updates": "^3.1.20", "npm-check-updates": "^3.1.20",
"reflect-metadata": "0.1.13", "reflect-metadata": "0.1.13",
"sqlite3": "4.0.9", "sqlite3": "4.0.9",