From ab593901189d180672c63c1c691697c5768e7ca1 Mon Sep 17 00:00:00 2001 From: stein Date: Wed, 29 Oct 2025 10:38:42 +0100 Subject: [PATCH 1/4] Delete scheduled task by setting search index schedule to no schedule --- .../search-index-edit.component.ts | 3 ++ .../search-index-scheduling.component.html | 3 +- .../search-index-scheduling.component.ts | 15 ++++------ .../services/search-index.service.ts | 28 +++++++++++++++++-- .../tasks/services/task-monitoring.service.ts | 6 ++-- .../task-details/task-details.component.ts | 5 ++-- .../lib/components/slider/slider.component.ts | 1 - 7 files changed, 41 insertions(+), 20 deletions(-) diff --git a/projects/admin-core/src/lib/search-index/search-index-edit/search-index-edit.component.ts b/projects/admin-core/src/lib/search-index/search-index-edit/search-index-edit.component.ts index 65932ef38..50c277108 100644 --- a/projects/admin-core/src/lib/search-index/search-index-edit/search-index-edit.component.ts +++ b/projects/admin-core/src/lib/search-index/search-index-edit/search-index-edit.component.ts @@ -10,6 +10,7 @@ import { FeatureSourceService } from '../../catalog/services/feature-source.serv import { SearchIndexService } from '../services/search-index.service'; import { ConfirmDialogService } from '@tailormap-viewer/shared'; import { ExtendedFeatureTypeModel } from '../../catalog/models/extended-feature-type.model'; +import { loadTasks } from '../../tasks/state/tasks.actions'; @Component({ selector: 'tm-admin-search-index-edit', @@ -47,6 +48,8 @@ export class SearchIndexEditComponent implements OnInit { public indexing$ = this.indexingSubject.asObservable(); public ngOnInit() { + this.store$.dispatch(loadTasks()); + this.route.paramMap.pipe( takeUntilDestroyed(this.destroyRef), map(params => params.get('searchIndexId')), diff --git a/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.html b/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.html index 275c3fe60..4846a45fc 100644 --- a/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.html +++ b/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.html @@ -19,8 +19,7 @@

Schedule @for (option of scheduleOptions; track $index) { + [value]="option.cronExpression"> {{ option.viewValue }} } diff --git a/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.ts b/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.ts index 083b5efa5..998a14dcb 100644 --- a/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.ts +++ b/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.ts @@ -65,15 +65,12 @@ export class SearchIndexSchedulingComponent implements OnInit { filter(() => this.isValidForm()), ) .subscribe(value => { - let schedule: TaskSchedule | undefined = undefined; - if (value.cronExpression) { - schedule = { - ...this.taskSchedule, - cronExpression: value.cronExpression, - description: value.description, - priority: value.priority, - }; - } + const schedule = { + ...this.taskSchedule, + cronExpression: value.cronExpression || '', + description: value.description, + priority: value.priority, + }; const searchIndex: Pick = { schedule: schedule, }; diff --git a/projects/admin-core/src/lib/search-index/services/search-index.service.ts b/projects/admin-core/src/lib/search-index/services/search-index.service.ts index 40a0692d2..078c05a01 100644 --- a/projects/admin-core/src/lib/search-index/services/search-index.service.ts +++ b/projects/admin-core/src/lib/search-index/services/search-index.service.ts @@ -6,8 +6,10 @@ import { AdminSnackbarService } from '../../shared/services/admin-snackbar.servi import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { DebounceHelper } from '@tailormap-viewer/shared'; import { addSearchIndex, deleteSearchIndex, updateSearchIndex } from '../state/search-index.actions'; -import { catchError, concatMap, map, of } from 'rxjs'; +import { catchError, concatMap, map, Observable, of, switchMap, take } from 'rxjs'; import { selectDraftSearchIndex } from '../state/search-index.selectors'; +import { selectTask } from '../../tasks/state/tasks.selectors'; +import { TaskMonitoringService } from '../../tasks/services/task-monitoring.service'; @Injectable({ providedIn: 'root', @@ -18,6 +20,7 @@ export class SearchIndexService { private adminSnackbarService = inject(AdminSnackbarService); private sseService = inject(AdminSseService); private destroyRef = inject(DestroyRef); + private taskMonitoringService = inject(TaskMonitoringService); public listenForSearchIndexChanges() { @@ -42,7 +45,7 @@ export class SearchIndexService { takeUntilDestroyed(this.destroyRef), concatMap(searchIndex => { if (searchIndex) { - return this.updateSearchIndex$(searchIndex.id, searchIndex); + return this.updateSearchIndexAndTask$(searchIndex.id, searchIndex); } return of(null); }), @@ -67,7 +70,26 @@ export class SearchIndexService { ); } - public updateSearchIndex$(id: number, searchIndex: Partial) { + public updateSearchIndexAndTask$(id: number, searchIndex: Partial): Observable { + // If the schedule is being removed, delete the associated task. + // The search index should only be updated after the task is successfully deleted. + if (!searchIndex.schedule || searchIndex.schedule.cronExpression || !searchIndex.schedule.uuid) { + return this.updateSearchIndex$(id, searchIndex); + } + return this.store$.select(selectTask(searchIndex.schedule.uuid)).pipe( + take(1), + switchMap(task => this.taskMonitoringService.deleteTask$(task.uuid, task.type)), + switchMap((response) => { + if (response) { + const searchIndexEmptySchedule: Partial = { ...searchIndex, schedule: undefined }; + return this.updateSearchIndex$(id, searchIndexEmptySchedule); + } + return of(null); + }), + ); + } + + public updateSearchIndex$(id: number, searchIndex: Partial): Observable { return this.adminApiService.updateSearchIndex$({ id, searchIndex }) .pipe( catchError(() => { diff --git a/projects/admin-core/src/lib/tasks/services/task-monitoring.service.ts b/projects/admin-core/src/lib/tasks/services/task-monitoring.service.ts index 1434e6397..9738d64ec 100644 --- a/projects/admin-core/src/lib/tasks/services/task-monitoring.service.ts +++ b/projects/admin-core/src/lib/tasks/services/task-monitoring.service.ts @@ -7,7 +7,9 @@ import { TailormapAdminApiV1Service } from '@tailormap-admin/admin-api'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { AdminSnackbarService } from '../../shared/services/admin-snackbar.service'; -@Injectable() +@Injectable({ + providedIn: 'root', +}) export class TaskMonitoringService { private store$ = inject(Store); private adminApiService = inject(TailormapAdminApiV1Service); @@ -64,7 +66,7 @@ export class TaskMonitoringService { this.adminApiService.stopTask$(this.uuid$.value, this.type$.value).subscribe(); } - public deleteTask(uuid: string, type: string ) { + public deleteTask$(uuid: string, type: string ) { return this.adminApiService.deleteTask$(uuid, type) .pipe( catchError(() => { diff --git a/projects/admin-core/src/lib/tasks/task-details/task-details.component.ts b/projects/admin-core/src/lib/tasks/task-details/task-details.component.ts index 373ab4eb7..660504ca9 100644 --- a/projects/admin-core/src/lib/tasks/task-details/task-details.component.ts +++ b/projects/admin-core/src/lib/tasks/task-details/task-details.component.ts @@ -15,8 +15,7 @@ import { reloadSearchIndexes } from '../../search-index/state/search-index.actio selector: 'tm-admin-task-details', templateUrl: './task-details.component.html', styleUrls: ['./task-details.component.css'], - providers: [TaskMonitoringService], -changeDetection: ChangeDetectionStrategy.OnPush, + changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, }) export class TaskDetailsComponent implements OnInit, OnDestroy { @@ -69,7 +68,7 @@ export class TaskDetailsComponent implements OnInit, OnDestroy { .pipe( take(1), filter(answer => answer), - switchMap(() => this.taskMonitoringService.deleteTask(task.uuid, task.type)), + switchMap(() => this.taskMonitoringService.deleteTask$(task.uuid, task.type)), ) .subscribe((response) => { if (response) { diff --git a/projects/shared/src/lib/components/slider/slider.component.ts b/projects/shared/src/lib/components/slider/slider.component.ts index 5ffa572e9..55f3dbcb9 100644 --- a/projects/shared/src/lib/components/slider/slider.component.ts +++ b/projects/shared/src/lib/components/slider/slider.component.ts @@ -43,7 +43,6 @@ export class SliderComponent implements ControlValueAccessor { @Input() public set betweenValues(betweenValues: {lower: number | null; upper: number | null}) { - console.debug("Setting between values", betweenValues); this.lowerValue = betweenValues.lower ?? this.min; this.upperValue = betweenValues.upper ?? this.max; } From 60cfff5a91762f6acef64cab32aaeacfa8f5eb05 Mon Sep 17 00:00:00 2001 From: stein Date: Fri, 31 Oct 2025 14:53:01 +0100 Subject: [PATCH 2/4] add null check for task --- .../lib/search-index/services/search-index.service.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/projects/admin-core/src/lib/search-index/services/search-index.service.ts b/projects/admin-core/src/lib/search-index/services/search-index.service.ts index 078c05a01..b136b747c 100644 --- a/projects/admin-core/src/lib/search-index/services/search-index.service.ts +++ b/projects/admin-core/src/lib/search-index/services/search-index.service.ts @@ -78,7 +78,12 @@ export class SearchIndexService { } return this.store$.select(selectTask(searchIndex.schedule.uuid)).pipe( take(1), - switchMap(task => this.taskMonitoringService.deleteTask$(task.uuid, task.type)), + switchMap(task => { + if (!task) { + return of(null); + } + return this.taskMonitoringService.deleteTask$(task.uuid, task.type); + }), switchMap((response) => { if (response) { const searchIndexEmptySchedule: Partial = { ...searchIndex, schedule: undefined }; @@ -89,7 +94,7 @@ export class SearchIndexService { ); } - public updateSearchIndex$(id: number, searchIndex: Partial): Observable { + private updateSearchIndex$(id: number, searchIndex: Partial): Observable { return this.adminApiService.updateSearchIndex$({ id, searchIndex }) .pipe( catchError(() => { From a23ae369d4ef9733dce607e3eba0befacab1385e Mon Sep 17 00:00:00 2001 From: stein Date: Fri, 31 Oct 2025 15:31:24 +0100 Subject: [PATCH 3/4] Do not create a new schedule if cron expression is empty --- .../search-index-scheduling.component.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.ts b/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.ts index 998a14dcb..fab289792 100644 --- a/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.ts +++ b/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.ts @@ -65,12 +65,15 @@ export class SearchIndexSchedulingComponent implements OnInit { filter(() => this.isValidForm()), ) .subscribe(value => { - const schedule = { - ...this.taskSchedule, - cronExpression: value.cronExpression || '', - description: value.description, - priority: value.priority, - }; + let schedule: TaskSchedule | undefined = undefined; + if (value.cronExpression || this.taskSchedule) { + schedule = { + ...this.taskSchedule, + cronExpression: value.cronExpression || '', + description: value.description, + priority: value.priority, + }; + } const searchIndex: Pick = { schedule: schedule, }; From e974af92ec7215fcfe7654a3ab81380eae4b71c0 Mon Sep 17 00:00:00 2001 From: stein Date: Fri, 31 Oct 2025 15:32:24 +0100 Subject: [PATCH 4/4] remove old hint --- .../search-index-scheduling.component.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.html b/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.html index 4846a45fc..71d6ab7e1 100644 --- a/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.html +++ b/projects/admin-core/src/lib/search-index/search-index-scheduling/search-index-scheduling.component.html @@ -5,9 +5,6 @@

ScheduleUuid
{{ uuid }}
-
- Deleting the schedule of a search index can be done by deleting the task on the tasks page -
} @else { There is no schedule for this search index yet. }