From 3f0c0cf45c175672ce00638cde307dc7738f5249 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Sun, 17 May 2026 20:54:29 -0500 Subject: [PATCH] allow processors to be moved across routes --- src/app/app.html | 2 +- src/app/components/processor/processor.ts | 32 ++-- src/app/components/route-list/route-list.html | 3 +- src/app/components/route-list/route-list.ts | 91 +++++++---- src/app/components/route/route.html | 4 +- src/app/components/route/route.ts | 141 +++++++++++------- 6 files changed, 173 insertions(+), 100 deletions(-) diff --git a/src/app/app.html b/src/app/app.html index f9e7a0f..90dd221 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -57,7 +57,7 @@
diff --git a/src/app/components/processor/processor.ts b/src/app/components/processor/processor.ts index f0af508..26a89fa 100644 --- a/src/app/components/processor/processor.ts +++ b/src/app/components/processor/processor.ts @@ -1,5 +1,5 @@ import { CdkDragHandle, CdkDragPlaceholder, CdkDragPreview } from '@angular/cdk/drag-drop'; -import { Component, computed, inject, input, model, output } from '@angular/core'; +import { Component, computed, inject, input, output } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { MatIconModule } from '@angular/material/icon'; import { ProcessorConfig } from '../../models/config'; @@ -21,7 +21,7 @@ import { ParamsFormComponent } from '../params-form/params-form'; }) export class ProcessorComponent { path = input(''); - processor = model(); + processor = input(); delete = output(); inDragList = input(false); @@ -34,6 +34,8 @@ export class ProcessorComponent { : undefined; }); + updated = output(); + hasParams = computed(() => { const schema = this.schema(); return ( @@ -45,20 +47,20 @@ export class ProcessorComponent { private schemaService = inject(SchemaService); paramsUpdated(params: any) { - this.processor.update((processor) => { - if (processor !== undefined) { - if (params !== undefined) { - return { - ...processor, - params: params, - }; - } - return { - ...processor, - }; + console.log('Params updated:', params); + const currentProcessor = this.processor(); + if (currentProcessor !== undefined) { + if (params !== undefined) { + this.updated.emit({ + ...currentProcessor, + params: params, + }); + } else { + this.updated.emit({ + ...currentProcessor, + }); } - return undefined; - }); + } } deleteMe() { diff --git a/src/app/components/route-list/route-list.html b/src/app/components/route-list/route-list.html index 459e5cf..6c054db 100644 --- a/src/app/components/route-list/route-list.html +++ b/src/app/components/route-list/route-list.html @@ -14,10 +14,11 @@
} diff --git a/src/app/components/route-list/route-list.ts b/src/app/components/route-list/route-list.ts index 054729c..821b452 100644 --- a/src/app/components/route-list/route-list.ts +++ b/src/app/components/route-list/route-list.ts @@ -1,9 +1,11 @@ -import { Component, inject, input, model } from '@angular/core'; +import { transferArrayItem } from '@angular/cdk/drag-drop'; +import { Component, inject, input, output } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatMenuModule } from '@angular/material/menu'; import { MatSnackBar } from '@angular/material/snack-bar'; import { MatTooltipModule } from '@angular/material/tooltip'; +import { cloneDeep } from 'lodash-es'; import { RouteConfig } from '../../models/config'; import { SchemaService } from '../../services/schema'; import { RouteComponent } from '../route/route'; @@ -15,20 +17,21 @@ import { RouteComponent } from '../route/route'; styleUrl: './route-list.css', }) export class RouteListComponent { - routes = model(); + routes = input(); moduleIds = input(); + updated = output(); public schemaService = inject(SchemaService); private snackBar = inject(MatSnackBar); deleteRoute(index: number) { - this.routes.update((routes) => { - if (routes) { - routes?.splice(index, 1); - return [...routes]; - } - return routes; - }); + const currentRoutes = this.routes(); + if (currentRoutes === undefined) { + console.error('routes is undefined, cannot delete'); + return; + } + currentRoutes.splice(index, 1); + this.updated.emit(cloneDeep(currentRoutes)); this.snackBar.open('Route Removed', 'Dismiss', { duration: 3000, }); @@ -39,29 +42,65 @@ export class RouteListComponent { console.error('route is undefined, not updating'); return; } - this.routes.update((routes) => { - if (routes) { - routes[index].input = route.input; - if (route.processors) { - routes[index].processors = [...route.processors]; - } - return [...routes]; - } - return routes; - }); + const currentRoutes = this.routes(); + if (currentRoutes === undefined) { + console.error('routes is undefined, cannot update'); + return; + } + currentRoutes[index] = cloneDeep(route); + this.updated.emit(cloneDeep(currentRoutes)); } addRoute() { const routeTemplate = this.schemaService.getSkeletonForRoute(); - this.routes.update((routes) => { - if (!routes) { - routes = []; - } - routes?.push(routeTemplate); - return [...routes]; - }); + const currentRoutes = this.routes() || []; + if (currentRoutes === undefined) { + console.error('routes is undefined, cannot update'); + return; + } + currentRoutes.push(routeTemplate); + this.updated.emit(cloneDeep(currentRoutes)); this.snackBar.open('Route Added', 'Dismiss', { duration: 3000, }); } + + moveProcessorBetweenRoutes(event: { + fromRouteIndex: number; + toRouteIndex: number; + fromProcessorIndex: number; + toProcessorIndex: number; + }) { + if (event.fromRouteIndex === event.toRouteIndex) { + console.error( + 'this should be handled by the route component, not moving processor between routes', + ); + return; + } + const routes = this.routes(); + if (routes === undefined) { + console.error('routes is undefined, cannot move processor'); + return; + } + const fromRoute = routes[event.fromRouteIndex]; + const toRoute = routes[event.toRouteIndex]; + if (fromRoute === undefined || toRoute === undefined) { + console.error('fromRoute or toRoute is undefined, cannot move processor'); + return; + } + const fromProcessors = fromRoute.processors; + const toProcessors = toRoute.processors; + if (fromProcessors === undefined || toProcessors === undefined) { + console.error('fromProcessors or toProcessors is undefined, cannot move processor'); + return; + } + transferArrayItem( + fromProcessors, + toProcessors, + event.fromProcessorIndex, + event.toProcessorIndex, + ); + + this.updated.emit(cloneDeep(routes)); + } } diff --git a/src/app/components/route/route.html b/src/app/components/route/route.html index 64e6246..55b27ae 100644 --- a/src/app/components/route/route.html +++ b/src/app/components/route/route.html @@ -66,6 +66,8 @@
@@ -73,7 +75,7 @@
(); + route = input(); moduleIds = input([]); delete = output(); + updated = output(); + moveProcessor = output<{ + fromRouteIndex: number; + toRouteIndex: number; + fromProcessorIndex: number; + toProcessorIndex: number; + }>(); processors = computed(() => { const route = this.route(); @@ -83,15 +91,14 @@ export class RouteComponent { }); this.formGroup.valueChanges.subscribe((value) => { - this.route.update((route) => { - if (route) { - route.input = value.input; - return { - ...route, - input: route.input, - }; - } - return undefined; + const currentRoute = this.route(); + if (currentRoute === undefined) { + console.error('route is undefined, not updating'); + return; + } + this.updated.emit({ + ...currentRoute, + input: value.input, }); }); @@ -120,18 +127,18 @@ export class RouteComponent { addProcessor(processorType: string) { const processorTemplate = this.schemaService.getSkeletonForProcessor(processorType); - this.route.update((route) => { - if (route) { - const processors = route.processors || []; - - processors.push(processorTemplate); - return { - ...route, - processors: [...processors], - }; - } - return route; + const currentRoute = this.route(); + if (currentRoute === undefined) { + console.error('route is undefined, not updating'); + return; + } + const processors = currentRoute.processors || []; + processors.push(processorTemplate); + this.updated.emit({ + ...currentRoute, + processors: cloneDeep(processors), }); + this.snackBar.open('Processor Added', 'Dismiss', { duration: 3000, }); @@ -142,53 +149,75 @@ export class RouteComponent { console.error('processor is undefined, not updating'); return; } - this.route.update((route) => { - if (route && route.processors) { - route.processors[index].type = processor.type; - if (processor.params !== undefined) { - route.processors[index].params = processor.params; - } - return { - ...route, - processors: [...route.processors], - }; - } - return route; + const currentRoute = this.route(); + if (currentRoute === undefined) { + console.error('route is undefined, not updating'); + return; + } + if (currentRoute.processors === undefined) { + console.error('route processors is undefined, not updating'); + return; + } + currentRoute.processors[index].type = processor.type; + if (processor.params !== undefined) { + currentRoute.processors[index].params = processor.params; + } + this.updated.emit({ + ...currentRoute, + processors: cloneDeep(currentRoute.processors), }); } deleteProcessor(index: number) { - this.route.update((route) => { - if (route && route.processors) { - route?.processors?.splice(index, 1); - return { - ...route, - processors: [...route.processors], - }; - } - return route; + const currentRoute = this.route(); + if (currentRoute === undefined) { + console.error('route is undefined, not updating'); + return; + } + if (currentRoute.processors === undefined) { + console.error('route processors is undefined, not updating'); + return; + } + currentRoute.processors.splice(index, 1); + + this.updated.emit({ + ...currentRoute, + processors: cloneDeep(currentRoute.processors), }); + this.snackBar.open('Processor Removed', 'Dismiss', { duration: 3000, }); } drop(event: CdkDragDrop) { - // TODO(jwetzell): support moving between routes if (event.previousContainer === event.container) { - const processors = this.route()?.processors; - if (processors !== undefined) { - moveItemInArray(processors, event.previousIndex, event.currentIndex); - this.route.update((route) => { - if (route) { - return { - ...route, - processors: [...processors], - }; - } - return route; - }); + const currentRoute = this.route(); + if (currentRoute === undefined) { + console.error('route is undefined, not updating'); + return; } + const processors = currentRoute.processors; + if (processors === undefined) { + console.error('route processors is undefined, cannot move processor'); + return; + } + moveItemInArray(processors, event.previousIndex, event.currentIndex); + this.updated.emit({ + ...currentRoute, + processors: cloneDeep(processors), + }); + } else { + const fromRouteIndex = parseInt(event.previousContainer.id.split('.')[1], 10); + const toRouteIndex = parseInt(event.container.id.split('.')[1], 10); + const fromProcessorIndex = event.previousIndex; + const toProcessorIndex = event.currentIndex; + this.moveProcessor.emit({ + fromRouteIndex, + toRouteIndex, + fromProcessorIndex, + toProcessorIndex, + }); } } }