updating settings page
This commit is contained in:
parent
3633168ee4
commit
2012ec3d91
@ -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",
|
||||||
@ -131,4 +132,4 @@
|
|||||||
"prefix": "app"
|
"prefix": "app"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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'
|
||||||
|
|||||||
@ -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);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
[name]="name"
|
||||||
|
bsDatepicker
|
||||||
|
[ngModel]="date"
|
||||||
|
(ngModelChange)="onChange($event)"
|
||||||
|
[bsConfig]="{ dateInputFormat: 'YYYY.MM.DD, h:mm' }"
|
||||||
|
required>
|
||||||
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -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>
|
||||||
@ -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
11
package-lock.json
generated
@ -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": {
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user