mirror of
https://github.com/jwetzell/showbridge-webui.git
synced 2026-08-19 05:03:57 +00:00
relayout folders
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
.cdk-drag-placeholder {
|
||||
opacity: 0;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
@if (paramFormControl && paramInfo?.schema) {
|
||||
@if (arrayValue) {
|
||||
<div cdkDropList (cdkDropListDropped)="dropItem($event)" [cdkDropListData]="arrayValue">
|
||||
@for (item of arrayValue; track trackByIndex(i, item); let i = $index) {
|
||||
<div cdkDrag class="flex my-2 mr-2 items-center">
|
||||
<label for="item-{{ i }}" class="text-white mr-1 hover:cursor-move" cdkDragHandle
|
||||
>{{ i }}:</label
|
||||
>
|
||||
<!-- @if (paramInfo?.schema.items.type === 'object') {
|
||||
<app-params-form
|
||||
[paramsSchema]="paramInfo?.schema.items"
|
||||
[data]="item"
|
||||
(updated)="updateItem(i, $event)"
|
||||
></app-params-form>
|
||||
} -->
|
||||
@if (paramInfo?.schema.items.type !== 'object') {
|
||||
<!-- TODO(jwetzell): add input validation using info from schema -->
|
||||
<input
|
||||
id="item-{{ i }}"
|
||||
class="pl-1 border-2 border-gray-200 border-solid rounded-sm text-white"
|
||||
[(ngModel)]="arrayValue[i]"
|
||||
[placeholder]="paramInfo?.placeholder"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
(input)="valueUpdated()"
|
||||
/>
|
||||
}
|
||||
@if (i >= minItems) {
|
||||
<div
|
||||
class="flex items-center justify-center hover:cursor-pointer bg-red-400 rounded-sm ml-1"
|
||||
matTooltip="Remove"
|
||||
>
|
||||
<mat-icon (click)="deleteItem(i)">remove</mat-icon>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (!arrayIsMaxed()) {
|
||||
<div
|
||||
class="w-full bg-gray-400 flex items-center justify-center rounded-sm hover:cursor-pointer hover:bg-gray-300"
|
||||
(click)="addItem()"
|
||||
matTooltip="Add Item"
|
||||
>
|
||||
<mat-icon class="scale-100">add</mat-icon>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { Component, inject, Input, OnInit } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { ParamInfo } from '../../models/form.model';
|
||||
import { ListsService } from '../../services/lists.service';
|
||||
import { SchemaService } from '../../services/schema.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-array-form',
|
||||
templateUrl: './array-form.component.html',
|
||||
styleUrl: './array-form.component.css',
|
||||
imports: [MatIconModule, FormsModule, CdkDrag, CdkDropList],
|
||||
standalone: true,
|
||||
})
|
||||
export class ArrayFormComponent implements OnInit {
|
||||
@Input() paramFormControl?: any;
|
||||
@Input() paramInfo?: ParamInfo;
|
||||
|
||||
minItems: number = 0;
|
||||
maxItems: number = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
arrayValue: any[] | undefined;
|
||||
|
||||
private schemaService = inject(SchemaService);
|
||||
public listsService = inject(ListsService);
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.paramFormControl && this.paramInfo?.schema) {
|
||||
if (!Array.isArray(this.paramFormControl.value)) {
|
||||
this.arrayValue = this.schemaService.parseStringToArray(
|
||||
this.paramFormControl.value,
|
||||
this.paramInfo.schema,
|
||||
);
|
||||
} else {
|
||||
this.arrayValue = this.paramFormControl.value;
|
||||
}
|
||||
|
||||
if (this.paramInfo.schema.minItems) {
|
||||
this.minItems = parseInt(this.paramInfo?.schema.minItems);
|
||||
}
|
||||
|
||||
if (this.paramInfo.schema.maxItems) {
|
||||
this.maxItems = parseInt(this.paramInfo?.schema.maxItems);
|
||||
}
|
||||
}
|
||||
this.ensureArrayMin();
|
||||
}
|
||||
|
||||
dropItem(event: CdkDragDrop<any | undefined>) {
|
||||
if (this.arrayValue !== undefined) {
|
||||
moveItemInArray(this.arrayValue, event.previousIndex, event.currentIndex);
|
||||
this.valueUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
deleteItem(index: number) {
|
||||
this.arrayValue?.splice(index, 1);
|
||||
this.valueUpdated();
|
||||
}
|
||||
|
||||
ensureArrayMin() {
|
||||
if (this.arrayValue === undefined) {
|
||||
this.arrayValue = [];
|
||||
}
|
||||
if (this.arrayValue.length < this.minItems) {
|
||||
for (let i = 0; i <= this.minItems - this.arrayValue.length; i += 1) {
|
||||
this.arrayValue.push(null);
|
||||
}
|
||||
this.valueUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
arrayIsMaxed() {
|
||||
if (this.arrayValue) {
|
||||
return this.arrayValue?.length >= this.maxItems;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
addItem() {
|
||||
if (this.arrayValue === undefined) {
|
||||
this.arrayValue = [];
|
||||
}
|
||||
|
||||
if (!this.arrayIsMaxed()) {
|
||||
this.arrayValue.push(null);
|
||||
}
|
||||
|
||||
this.valueUpdated();
|
||||
// this.updated.emit(true);
|
||||
}
|
||||
|
||||
valueUpdated() {
|
||||
if (this.arrayValue) {
|
||||
this.paramFormControl.setValue(
|
||||
this.schemaService.cleanArray(this.arrayValue, this.paramInfo?.schema?.items),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
trackByIndex(index: number, obj: any): any {
|
||||
return index;
|
||||
}
|
||||
|
||||
// NOTE(jwetzel): this is only needed for object item types
|
||||
updateItem(index: number, value: any) {
|
||||
if (this.arrayValue) {
|
||||
this.arrayValue[index] = value;
|
||||
this.valueUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
@if (config() && schemaService.schemasLoaded()) {
|
||||
<app-module-list [modules]="config()?.modules" (modulesChange)="modulesUpdated($event)"></app-module-list>
|
||||
<app-route-list [routes]="config()?.routes" [moduleIds]="moduleIds()" (routesChange)="routesUpdated($event)"></app-route-list>
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { Component, computed, inject, model } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { Config, ModuleConfiguration, RouteConfiguration } from '../../models/config.models';
|
||||
import { SchemaService } from '../../services/schema.service';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { ModuleListComponent } from '../module-list/module-list.component';
|
||||
import { RouteListComponent } from '../route-list.component/route-list.component';
|
||||
import { ConfigService } from '../../services/config.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-config',
|
||||
imports: [
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
ModuleListComponent,
|
||||
RouteListComponent,
|
||||
],
|
||||
templateUrl: './config.component.html',
|
||||
styleUrl: './config.component.css',
|
||||
})
|
||||
export class ConfigComponent {
|
||||
config = computed<Config | undefined>(() => this.configService.currentlyShownConfig());
|
||||
|
||||
modules = computed(() => this.config()?.modules ?? []);
|
||||
routes = computed(() => this.config()?.routes ?? []);
|
||||
|
||||
moduleIds = computed(() => {
|
||||
const config = this.config();
|
||||
if (config !== undefined && config.modules !== undefined) {
|
||||
return config.modules.map((module) => module.id!) ?? [];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
public configService = inject(ConfigService);
|
||||
public schemaService = inject(SchemaService);
|
||||
|
||||
modulesUpdated(modules: ModuleConfiguration[] | undefined) {
|
||||
if (modules === undefined) {
|
||||
console.error('modules is undefined, not updating');
|
||||
return;
|
||||
}
|
||||
this.configService.currentlyShownConfig.update((config) => {
|
||||
if (config) {
|
||||
return {
|
||||
...config,
|
||||
modules: modules,
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
||||
routesUpdated(routes: RouteConfiguration[] | undefined) {
|
||||
if (routes === undefined) {
|
||||
console.error('routes is undefined, not updating');
|
||||
return;
|
||||
}
|
||||
this.configService.currentlyShownConfig.update((config) => {
|
||||
if (config) {
|
||||
return {
|
||||
...config,
|
||||
routes: routes,
|
||||
};
|
||||
}
|
||||
return config;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center">
|
||||
@if (schemaService.moduleTypes.length > 0) {
|
||||
<div
|
||||
matTooltip="Add Module"
|
||||
class="flex items-center justify-center w-10 h-10 bg-transparent hover:bg-gray-700 hover:cursor-pointer text-blue-400"
|
||||
[matMenuTriggerFor]="addModuleMenu"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</div>
|
||||
<mat-menu #addModuleMenu="matMenu">
|
||||
@for (moduleType of schemaService.moduleTypes; track moduleType) {
|
||||
<button mat-menu-item (click)="addModule(moduleType.type)">
|
||||
<span>{{ moduleType.name }}</span>
|
||||
</button>
|
||||
}
|
||||
</mat-menu>
|
||||
}
|
||||
<div class="text-white">Modules</div>
|
||||
</div>
|
||||
<div class="flex-grow overflow-x-hidden overflow-y-auto gap-1.5">
|
||||
@for (module of modules(); track module; let i = $index) {
|
||||
<div class="m-2">
|
||||
<app-module
|
||||
[path]="`modules/${i}`"
|
||||
(moduleChange)="moduleUpdated(i, $event)"
|
||||
[module]="module"
|
||||
(delete)="deleteModule(i)"
|
||||
></app-module>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #addModuleMenu>
|
||||
@if (schemaService.moduleTypes.length > 0) {
|
||||
<div cdkMenu class="context-menu">
|
||||
@for (moduleType of schemaService.moduleTypes; track moduleType) {
|
||||
<button cdkMenuItem class="context-menu-item" (click)="addModule(moduleType.type)">
|
||||
<span>{{ moduleType.name }}</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</ng-template>
|
||||
@@ -0,0 +1,77 @@
|
||||
import { Component, inject, model } from '@angular/core';
|
||||
import { ModuleComponent } from '../module/module.component';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ModuleConfiguration } from '../../models/config.models';
|
||||
import { SchemaService } from '../../services/schema.service';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { RouteComponent } from '../route/route.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-module-list',
|
||||
imports: [
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
ModuleComponent
|
||||
],
|
||||
templateUrl: './module-list.component.html',
|
||||
styleUrl: './module-list.component.css',
|
||||
})
|
||||
export class ModuleListComponent {
|
||||
modules = model<ModuleConfiguration[]>();
|
||||
public schemaService = inject(SchemaService);
|
||||
|
||||
private snackBar = inject(MatSnackBar);
|
||||
|
||||
moduleUpdated(index: number, module: ModuleConfiguration | undefined) {
|
||||
if (module === undefined) {
|
||||
console.error('module is undefined, not updating');
|
||||
return;
|
||||
}
|
||||
this.modules.update((modules) => {
|
||||
if (modules) {
|
||||
modules[index].id = module.id;
|
||||
modules[index].type = module.type;
|
||||
if (module.params !== undefined) {
|
||||
modules[index].params = module.params;
|
||||
}
|
||||
return [...modules];
|
||||
}
|
||||
return modules;
|
||||
});
|
||||
}
|
||||
|
||||
addModule(moduleType: string) {
|
||||
const moduleTemplate = this.schemaService.getSkeletonForModule(moduleType);
|
||||
this.modules.update((modules) => {
|
||||
if (modules) {
|
||||
if (!modules) {
|
||||
modules = [];
|
||||
}
|
||||
modules?.push(moduleTemplate);
|
||||
return [...modules];
|
||||
}
|
||||
return modules;
|
||||
});
|
||||
this.snackBar.open('Module Added', 'Dismiss', {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
deleteModule(index: number) {
|
||||
this.modules.update((modules) => {
|
||||
if (modules) {
|
||||
modules?.splice(index, 1);
|
||||
return [...modules];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
this.snackBar.open('Module Removed', 'Dismiss', {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
@if (module() && schema()) {
|
||||
<div
|
||||
class="flex flex-col bg-gray-800 border-2 {{
|
||||
isInError() ? 'border-red-500' : 'border-gray-600'
|
||||
}} border-solid w-full h-full"
|
||||
>
|
||||
<div class="flex items-center justify-center border-gray-600 border-b-2">
|
||||
<div class="flex-grow ml-1 mr-3 text-white">
|
||||
{{ schema().title || module()?.type }}
|
||||
</div>
|
||||
<div class="flex items-center justify-center" (click)="delete.emit()">
|
||||
<mat-icon class="!text-red-500">close</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<form [formGroup]="formGroup" class="h-full">
|
||||
<div class="m-2">
|
||||
<div class="flex items-center m-1">
|
||||
<label class="mr-2 text-white"> ID: </label>
|
||||
<input
|
||||
type="text"
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm"
|
||||
[placeholder]="'module-1'"
|
||||
[formControlName]="'id'"
|
||||
/>
|
||||
<mat-icon class="!text-white" matTooltip="String">abc</mat-icon>
|
||||
@if (!formGroup.controls['id'].valid) {
|
||||
<!-- TODO(jwetzell): better error displaying -->
|
||||
<div class="ml-2 text-red-500">{{ formGroup.controls['id'].errors | json }}</div>
|
||||
}
|
||||
</div>
|
||||
<app-params-form
|
||||
[paramsSchema]="schema()?.properties?.params"
|
||||
[data]="params()"
|
||||
(updated)="paramsUpdated($event)"
|
||||
></app-params-form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import { Component, computed, inject, input, model, output } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { ModuleConfiguration } from '../../models/config.models';
|
||||
import { SchemaService } from '../../services/schema.service';
|
||||
import { ParamsFormComponent } from '../params-form/params-form.component';
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
|
||||
@Component({
|
||||
selector: 'app-module',
|
||||
imports: [
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
ParamsFormComponent,
|
||||
ReactiveFormsModule,
|
||||
MatMenuModule,
|
||||
MatTooltipModule,
|
||||
JsonPipe,
|
||||
],
|
||||
templateUrl: './module.component.html',
|
||||
styleUrl: './module.component.css',
|
||||
})
|
||||
export class ModuleComponent {
|
||||
path = input<string>('');
|
||||
module = model<ModuleConfiguration>();
|
||||
delete = output<void>();
|
||||
|
||||
params = computed(() => this.module()!.params);
|
||||
id = computed(() => this.module()!.id);
|
||||
|
||||
schema = computed(() => {
|
||||
return this.module()?.type
|
||||
? this.schemaService.getSchemaForModuleType(this.module()!.type)
|
||||
: undefined;
|
||||
});
|
||||
|
||||
formGroup: FormGroup = new FormGroup({
|
||||
id: new FormControl('', [Validators.required]),
|
||||
type: new FormControl(''),
|
||||
});
|
||||
|
||||
private schemaService = inject(SchemaService);
|
||||
|
||||
ngOnInit(): void {
|
||||
this.formGroup.patchValue({
|
||||
id: this.module()?.id,
|
||||
type: this.module()?.type,
|
||||
});
|
||||
|
||||
this.formGroup.valueChanges.subscribe((value) => {
|
||||
this.module.update((module) => {
|
||||
if (module) {
|
||||
module.id = value.id;
|
||||
module.type = value.type;
|
||||
return {
|
||||
...module,
|
||||
id: module.id,
|
||||
type: module.type,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
paramsUpdated(params: any) {
|
||||
this.module.update((module) => {
|
||||
if (module !== undefined && module.params !== undefined) {
|
||||
module.params = params;
|
||||
return {
|
||||
...module,
|
||||
params: module.params,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
deleteMe() {
|
||||
this.delete.emit();
|
||||
}
|
||||
|
||||
isInError(): boolean {
|
||||
const path = this.path();
|
||||
if (path) {
|
||||
return this.schemaService.errorPaths.includes(path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
input::placeholder {
|
||||
color: #d2d2d2;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
select {
|
||||
background-color: #424242;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
@if (paramsSchema && paramsFormInfo) {
|
||||
@if (paramsOptions.length > 1) {
|
||||
<mat-tab-group
|
||||
dynamicHeight
|
||||
[selectedIndex]="paramsOptionsSelectedIndex"
|
||||
(selectedTabChange)="paramsOptionsTabSelected($event)"
|
||||
>
|
||||
@for (paramsOption of paramsOptions; track paramsOption) {
|
||||
<mat-tab [label]="paramsOption.display"></mat-tab>
|
||||
}
|
||||
</mat-tab-group>
|
||||
}
|
||||
<form [formGroup]="paramsFormInfo.formGroup">
|
||||
<div class="flex flex-col">
|
||||
@for (key of paramKeys(); track key) {
|
||||
<div class="flex items-center m-1">
|
||||
@if (getParamInfo(key); as paramInfo) {
|
||||
<label class="mr-2 text-white"> {{ paramInfo.display }}: </label>
|
||||
@switch (paramInfo.type) {
|
||||
@case ('boolean') {
|
||||
<input type="checkbox" [formControlName]="paramInfo.key" />
|
||||
}
|
||||
@case ('number') {
|
||||
@if (!paramInfo.options) {
|
||||
<input
|
||||
type="number"
|
||||
[placeholder]="paramInfo.placeholder"
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm"
|
||||
[formControlName]="paramInfo.key"
|
||||
/>
|
||||
} @else {
|
||||
<select
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm"
|
||||
[formControlName]="paramInfo.key"
|
||||
>
|
||||
@for (option of paramInfo.options; track option) {
|
||||
<option [value]="option">
|
||||
{{ option }}
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
<mat-icon class="!text-white">123</mat-icon>
|
||||
}
|
||||
@case ('integer') {
|
||||
@if (!paramInfo.options) {
|
||||
<input
|
||||
type="number"
|
||||
[placeholder]="paramInfo.placeholder"
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm"
|
||||
[formControlName]="paramInfo.key"
|
||||
/>
|
||||
} @else {
|
||||
<select
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm"
|
||||
[formControlName]="paramInfo.key"
|
||||
>
|
||||
@for (option of paramInfo.options; track option) {
|
||||
<option [value]="option">
|
||||
{{ option }}
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
<mat-icon class="!text-white" matTooltip="Number">123</mat-icon>
|
||||
}
|
||||
@case ('string') {
|
||||
@if (!paramInfo.options) {
|
||||
<input
|
||||
type="text"
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm"
|
||||
[placeholder]="paramInfo.placeholder"
|
||||
[formControlName]="paramInfo.key"
|
||||
/>
|
||||
} @else {
|
||||
<select
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm"
|
||||
[formControlName]="paramInfo.key"
|
||||
>
|
||||
@for (option of paramInfo.options; track option) {
|
||||
<option [value]="option">
|
||||
{{ option }}
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
}
|
||||
<mat-icon class="!text-white" matTooltip="String">abc</mat-icon>
|
||||
}
|
||||
@case ('array') {
|
||||
<app-array-form
|
||||
[paramFormControl]="paramsFormInfo.formGroup.get(paramInfo.key)"
|
||||
[paramInfo]="paramInfo"
|
||||
></app-array-form>
|
||||
<mat-icon class="!text-white" matTooltip="Item list">data_array</mat-icon>
|
||||
}
|
||||
@case ('object') {
|
||||
<!-- TODO(jwetzell): figure out how to display objects-->
|
||||
<input
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm"
|
||||
[formControlName]="paramInfo.key"
|
||||
[placeholder]="paramInfo.placeholder"
|
||||
/>
|
||||
<mat-icon class="!text-white" matTooltip="JSON">data_object</mat-icon>
|
||||
}
|
||||
@default {
|
||||
<input
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm"
|
||||
[formControlName]="paramInfo.key"
|
||||
/>
|
||||
}
|
||||
}
|
||||
@if (paramInfo.hint) {
|
||||
<div class="flex items-center justify-center">
|
||||
<mat-icon [matTooltip]="paramInfo.hint" class="ml-2 !text-white">
|
||||
help_outline
|
||||
</mat-icon>
|
||||
</div>
|
||||
}
|
||||
@if (!paramsFormInfo.formGroup.controls[key].valid) {
|
||||
<!-- TODO(jwetzell): better error displaying -->
|
||||
<div class="ml-2 text-red-500">
|
||||
{{ paramsFormInfo.formGroup.controls[key].errors | json }}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</form>
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { Component, inject, Input, OnInit, output } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatTabChangeEvent, MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { SomeJSONSchema } from 'ajv/dist/types/json-schema';
|
||||
import { cloneDeep, has } from 'lodash-es';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { ParamInfo, ParamsFormInfo } from '../../models/form.model';
|
||||
import { SchemaService } from '../../services/schema.service';
|
||||
import { ArrayFormComponent } from '../array-form/array-form.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-params-form',
|
||||
templateUrl: './params-form.component.html',
|
||||
styleUrls: ['./params-form.component.css'],
|
||||
imports: [
|
||||
MatIconModule,
|
||||
MatTooltipModule,
|
||||
JsonPipe,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
ReactiveFormsModule,
|
||||
ArrayFormComponent,
|
||||
MatTabsModule,
|
||||
],
|
||||
standalone: true,
|
||||
})
|
||||
export class ParamsFormComponent implements OnInit {
|
||||
@Input() paramsSchema?: SomeJSONSchema;
|
||||
@Input() data?: any;
|
||||
updated = output<any>();
|
||||
|
||||
paramsFormInfo?: ParamsFormInfo;
|
||||
|
||||
formGroupSubscription?: Subscription;
|
||||
paramsOptions: {
|
||||
display: string;
|
||||
paramsFormInfo: ParamsFormInfo;
|
||||
keys: string[];
|
||||
schema: SomeJSONSchema;
|
||||
}[] = [];
|
||||
paramsOptionsSelectedIndex: number = 0;
|
||||
|
||||
private schemaService = inject(SchemaService);
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.paramsSchema) {
|
||||
if (this.paramsSchema.properties) {
|
||||
this.paramsFormInfo = this.schemaService.getFormInfoFromParamsSchema(this.paramsSchema);
|
||||
} else if (this.paramsSchema.oneOf) {
|
||||
this.paramsOptions = this.paramsSchema.oneOf.map((oneOf: any, index: number) => {
|
||||
const paramsOption = {
|
||||
display: oneOf.title ? oneOf.title : `Option ${index + 1}`,
|
||||
schema: oneOf,
|
||||
paramsFormInfo: this.schemaService.getFormInfoFromParamsSchema(oneOf),
|
||||
};
|
||||
return {
|
||||
...paramsOption,
|
||||
keys: Object.keys(paramsOption.paramsFormInfo.formGroup.controls),
|
||||
};
|
||||
});
|
||||
const matchingSchemaIndex = this.schemaService.matchParamsDataToSchema(
|
||||
this.data,
|
||||
this.paramsOptions.map((paramsOption) => paramsOption.schema),
|
||||
);
|
||||
|
||||
this.paramsOptionsSelectedIndex = matchingSchemaIndex;
|
||||
this.paramsFormInfo = this.paramsOptions[matchingSchemaIndex].paramsFormInfo;
|
||||
this.paramsSchema = this.paramsOptions[matchingSchemaIndex].schema;
|
||||
} else {
|
||||
console.error('params is not a singular or oneOf');
|
||||
console.error(this.paramsSchema);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.data && this.paramsFormInfo?.formGroup) {
|
||||
// NOTE(jwetzell): prepare data for form patching
|
||||
const dataToPatch = cloneDeep(this.data);
|
||||
Object.entries(this.paramsFormInfo.paramsInfo).forEach(([paramKey, paramInfo]) => {
|
||||
if (has(dataToPatch, paramKey)) {
|
||||
switch (paramInfo.type) {
|
||||
case 'object':
|
||||
dataToPatch[paramKey] = JSON.stringify(dataToPatch[paramKey]);
|
||||
break;
|
||||
case 'array':
|
||||
dataToPatch[paramKey] = dataToPatch[paramKey]
|
||||
.map((item: any) => {
|
||||
switch (typeof item) {
|
||||
case 'object':
|
||||
return JSON.stringify(item);
|
||||
|
||||
default:
|
||||
return item;
|
||||
}
|
||||
})
|
||||
.join(',');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.paramsFormInfo.formGroup.patchValue(dataToPatch);
|
||||
}
|
||||
|
||||
this.formGroupSubscription = this.paramsFormInfo?.formGroup.valueChanges.subscribe((value) => {
|
||||
this.formUpdated();
|
||||
});
|
||||
}
|
||||
|
||||
paramsOptionsTabSelected(event: MatTabChangeEvent) {
|
||||
// NOTE(jwetzell): no longer interested in the old formGroup valueChanges
|
||||
if (this.formGroupSubscription) {
|
||||
this.formGroupSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
const paramsOption = this.paramsOptions[event.index];
|
||||
|
||||
this.paramsSchema = paramsOption.schema;
|
||||
this.paramsFormInfo = paramsOption.paramsFormInfo;
|
||||
|
||||
// NOTE(jwetzell): modify params that should change from the data when switch paramOptions
|
||||
Object.entries(this.paramsFormInfo.paramsInfo).forEach(([paramKey, paramInfo]) => {
|
||||
if (this.data !== undefined) {
|
||||
if (paramInfo.isConst) {
|
||||
if (this.data[paramKey]) {
|
||||
delete this.data[paramKey];
|
||||
}
|
||||
}
|
||||
|
||||
if (paramInfo.default) {
|
||||
if (this.data[paramKey] !== undefined && this.data[paramKey] !== paramInfo.default) {
|
||||
this.data[paramKey] = paramInfo.default;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const allowedParamKeys = Object.keys(this.paramsSchema?.properties);
|
||||
if (this.data) {
|
||||
// NOTE(jwetzell): remove keys that aren't allowed in the new params variation
|
||||
Object.keys(this.data).forEach((paramKey) => {
|
||||
if (allowedParamKeys && !allowedParamKeys.includes(paramKey)) {
|
||||
delete this.data[paramKey];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.paramsFormInfo.formGroup) {
|
||||
this.formGroupSubscription = this.paramsFormInfo.formGroup.valueChanges.subscribe((value) => {
|
||||
this.formUpdated();
|
||||
});
|
||||
}
|
||||
|
||||
if (this.data && this.paramsFormInfo.formGroup) {
|
||||
this.paramsFormInfo.formGroup.patchValue(this.data);
|
||||
}
|
||||
}
|
||||
|
||||
formUpdated() {
|
||||
if (this.paramsSchema) {
|
||||
const params = this.schemaService.cleanParams(
|
||||
this.paramsSchema,
|
||||
this.paramsFormInfo?.formGroup.value,
|
||||
);
|
||||
this.updated.emit(params);
|
||||
} else {
|
||||
console.error('params-form: no paramsSchema loaded');
|
||||
}
|
||||
}
|
||||
|
||||
paramKeys() {
|
||||
if (this.paramsFormInfo) {
|
||||
return Object.keys(this.paramsFormInfo?.formGroup.controls);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
getParamInfo(key: string): ParamInfo | undefined {
|
||||
return this.paramsFormInfo?.paramsInfo[key];
|
||||
}
|
||||
|
||||
getParamValue(key: string) {
|
||||
if (this.paramsSchema) {
|
||||
const params = this.schemaService.cleanParams(
|
||||
this.paramsSchema,
|
||||
this.paramsFormInfo?.formGroup.value,
|
||||
);
|
||||
return params[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
@if (processor() && schema()) {
|
||||
<div class="flex items-start m-2 w-fit">
|
||||
<div
|
||||
class="flex flex-col bg-gray-800 border-2 {{
|
||||
isInError() ? 'border-red-500' : 'border-gray-600'
|
||||
}} border-solid w-fit h-full"
|
||||
>
|
||||
<div class="flex items-center justify-center border-gray-600 border-b-2">
|
||||
<div class="flex-grow ml-1 mr-3 text-white">
|
||||
{{ schema()?.title || processor()?.type }}
|
||||
</div>
|
||||
<div class="flex items-center justify-center" (click)="delete.emit()">
|
||||
<mat-icon class="!text-red-500">close</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
@if (hasParams()) {
|
||||
<div>
|
||||
<app-params-form
|
||||
[paramsSchema]="schema()?.properties?.params"
|
||||
[data]="params()"
|
||||
(updated)="paramsUpdated($event)"
|
||||
></app-params-form>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { Component, computed, inject, input, model, output, signal } from '@angular/core';
|
||||
import { ProcessorConfiguration } from '../../models/config.models';
|
||||
import { SchemaService } from '../../services/schema.service';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { ParamsFormComponent } from '../params-form/params-form.component';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-processor',
|
||||
imports: [MatIconModule, ParamsFormComponent, ReactiveFormsModule],
|
||||
templateUrl: './processor.component.html',
|
||||
styleUrl: './processor.component.css',
|
||||
})
|
||||
export class ProcessorComponent {
|
||||
path = input<string>('');
|
||||
processor = model<ProcessorConfiguration>();
|
||||
delete = output<void>();
|
||||
|
||||
params = computed(() => this.processor()!.params);
|
||||
|
||||
schema = computed(() => {
|
||||
return this.processor()?.type
|
||||
? this.schemaService.getSchemaForProcessorType(this.processor()!.type)
|
||||
: undefined;
|
||||
});
|
||||
|
||||
hasParams = computed(() => {
|
||||
const schema = this.schema();
|
||||
return (
|
||||
schema !== undefined &&
|
||||
schema.properties !== undefined &&
|
||||
schema.properties.params !== undefined
|
||||
);
|
||||
});
|
||||
private schemaService = inject(SchemaService);
|
||||
|
||||
paramsUpdated(params: any) {
|
||||
this.processor.update((processor) => {
|
||||
if (processor !== undefined) {
|
||||
if (params !== undefined){
|
||||
return {
|
||||
...processor,
|
||||
params: params,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...processor,
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
deleteMe() {
|
||||
this.delete.emit();
|
||||
}
|
||||
|
||||
isInError(): boolean {
|
||||
const path = this.path();
|
||||
if (path) {
|
||||
return this.schemaService.errorPaths.includes(path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
matTooltip="Add Route"
|
||||
class="flex items-center justify-center w-10 h-10 bg-transparent hover:bg-gray-700 hover:cursor-pointer text-blue-400"
|
||||
(click)="addRoute()"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</div>
|
||||
<div class="text-white">Routes</div>
|
||||
</div>
|
||||
<div class="flex-grow overflow-x-hidden overflow-y-auto gap-1.5">
|
||||
@for (route of routes(); track route; let i = $index) {
|
||||
<div class="m-2">
|
||||
<app-route
|
||||
[path]="`routes/${i}`"
|
||||
(routeChange)="routeUpdated(i, $event)"
|
||||
[route]="route"
|
||||
[moduleIds]="moduleIds() || []"
|
||||
(delete)="deleteRoute(i)"
|
||||
></app-route>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,72 @@
|
||||
import { Component, inject, input, model } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { ModuleConfiguration, RouteConfiguration } from '../../models/config.models';
|
||||
import { SchemaService } from '../../services/schema.service';
|
||||
import { RouteComponent } from '../route/route.component';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
|
||||
@Component({
|
||||
selector: 'app-route-list',
|
||||
imports: [
|
||||
RouteComponent,
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
],
|
||||
templateUrl: './route-list.component.html',
|
||||
styleUrl: './route-list.component.css',
|
||||
})
|
||||
export class RouteListComponent {
|
||||
|
||||
routes = model<RouteConfiguration[]>();
|
||||
moduleIds = input<string[]>();
|
||||
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;
|
||||
});
|
||||
this.snackBar.open('Route Removed', 'Dismiss', {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
routeUpdated(index: number, route: RouteConfiguration | undefined) {
|
||||
if (route === undefined) {
|
||||
console.error('route is undefined, not updating');
|
||||
return;
|
||||
}
|
||||
this.routes.update((routes) => {
|
||||
if (routes) {
|
||||
routes[index].input = route.input;
|
||||
routes[index].output = route.output;
|
||||
return [...routes];
|
||||
}
|
||||
return routes;
|
||||
});
|
||||
}
|
||||
|
||||
addRoute() {
|
||||
const routeTemplate = this.schemaService.getSkeletonForRoute();
|
||||
this.routes.update((routes) => {
|
||||
if (!routes) {
|
||||
routes = [];
|
||||
}
|
||||
routes?.push(routeTemplate);
|
||||
return [...routes];
|
||||
});
|
||||
this.snackBar.open('Route Added', 'Dismiss', {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
input::placeholder {
|
||||
color: #d2d2d2;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
select {
|
||||
background-color: #424242;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
@if (route()) {
|
||||
<!-- <div class="flex items-start m-2 w-fit border-2 border-red-500"> -->
|
||||
<div
|
||||
class="flex flex-col bg-gray-800 border-2 {{
|
||||
isInError() ? 'border-red-500' : 'border-gray-600'
|
||||
}} border-solid w-full h-full"
|
||||
>
|
||||
<div class="flex items-center justify-end border-gray-600 border-b-2">
|
||||
<div class="flex-grow text-left ml-2 text-white">Route {{ index() }}</div>
|
||||
<div class="flex items-center justify-center hover:bg-gray-700" (click)="delete.emit()">
|
||||
<mat-icon class="!text-red-500">close</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<form [formGroup]="formGroup">
|
||||
<div class="m-2">
|
||||
<div class="flex items-center m-1">
|
||||
<label class="mr-2 text-white"> Input: </label>
|
||||
<select
|
||||
class="pl-1 border-2 border-gray-200 text-white border-solid rounded-sm w-full"
|
||||
formControlName="input"
|
||||
>
|
||||
@for (option of moduleIds(); track option) {
|
||||
<option [value]="option">
|
||||
{{ option }}
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
@if (!formGroup.controls['input'].valid) {
|
||||
<!-- TODO(jwetzell): better error displaying -->
|
||||
<div class="ml-2 text-red-500">{{ formGroup.controls['input'].errors | json }}</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div>
|
||||
<div class="flex items-center">
|
||||
@if (schemaService.processorTypes.length > 0) {
|
||||
<div
|
||||
matTooltip="Add Processor"
|
||||
class="flex items-center justify-center w-10 h-10 bg-transparent hover:bg-gray-700 hover:cursor-pointer text-blue-400"
|
||||
[matMenuTriggerFor]="addProcessorMenu"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</div>
|
||||
<mat-menu #addProcessorMenu="matMenu">
|
||||
@for (processorType of schemaService.processorTypes; track processorType) {
|
||||
<button mat-menu-item (click)="addProcessor(processorType.type)">
|
||||
<span>{{ processorType.name }}</span>
|
||||
</button>
|
||||
}
|
||||
</mat-menu>
|
||||
}
|
||||
<div class="text-md text-white text-center">Processors</div>
|
||||
</div>
|
||||
@if (processors() !== undefined && processors()!.length > 0) {
|
||||
<div class="border-2 border-gray-500 m-2">
|
||||
@for (processor of processors(); track processor; let i = $index) {
|
||||
<div cdkDrag>
|
||||
<app-processor
|
||||
[path]="path() + '/processors/' + i"
|
||||
(processorChange)="processorUpdated(i, $event)"
|
||||
[processor]="processor"
|
||||
(delete)="deleteProcessor(i)"
|
||||
></app-processor>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
|
||||
<ng-template #addProcessorMenu>
|
||||
@if (schemaService.processorTypes.length > 0) {
|
||||
<div cdkMenu class="context-menu">
|
||||
@for (processorType of schemaService.processorTypes; track processorType) {
|
||||
<button cdkMenuItem class="context-menu-item" (click)="addProcessor(processorType.type)">
|
||||
<span>{{ processorType.name }}</span>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</ng-template>
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
import { Component, computed, inject, input, model, output } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { ProcessorConfiguration, RouteConfiguration } from '../../models/config.models';
|
||||
import { SchemaService } from '../../services/schema.service';
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { ProcessorComponent } from '../processor/processor.component';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
|
||||
@Component({
|
||||
selector: 'app-route',
|
||||
imports: [
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
ReactiveFormsModule,
|
||||
MatMenuModule,
|
||||
JsonPipe,
|
||||
ProcessorComponent,
|
||||
MatTooltipModule,
|
||||
],
|
||||
templateUrl: './route.component.html',
|
||||
styleUrl: './route.component.css',
|
||||
})
|
||||
export class RouteComponent {
|
||||
path = input<string>('');
|
||||
|
||||
index = computed(() => {
|
||||
const path = this.path();
|
||||
if (path) {
|
||||
const parts = path.split('/');
|
||||
const lastPart = parts[parts.length - 1];
|
||||
return parseInt(lastPart, 10);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
route = model<RouteConfiguration>();
|
||||
moduleIds = input<string[]>([]);
|
||||
delete = output<void>();
|
||||
|
||||
processors = computed(() => {
|
||||
const route = this.route();
|
||||
if (route) {
|
||||
return route.processors;
|
||||
}
|
||||
return [];
|
||||
});
|
||||
|
||||
formGroup: FormGroup = new FormGroup({
|
||||
input: new FormControl('', [Validators.required]),
|
||||
});
|
||||
|
||||
public schemaService = inject(SchemaService);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
|
||||
ngOnInit(): void {
|
||||
this.formGroup.patchValue({
|
||||
input: this.route()?.input,
|
||||
});
|
||||
|
||||
this.formGroup.valueChanges.subscribe((value) => {
|
||||
this.route.update((route) => {
|
||||
if (route) {
|
||||
route.input = value.input;
|
||||
return {
|
||||
...route,
|
||||
input: route.input,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
isInError(): boolean {
|
||||
const path = this.path();
|
||||
if (path) {
|
||||
return this.schemaService.errorPaths.includes(path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
addProcessor(processorType: string) {
|
||||
const processorTemplate = this.schemaService.getSkeletonForProcessor(processorType);
|
||||
this.route.update((route) => {
|
||||
if (route) {
|
||||
if (!route.processors) {
|
||||
route.processors = [];
|
||||
}
|
||||
route.processors?.push(processorTemplate);
|
||||
return {
|
||||
...route,
|
||||
processors: route.processors,
|
||||
};
|
||||
}
|
||||
return route;
|
||||
});
|
||||
this.snackBar.open('Processor Added', 'Dismiss', {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
processorUpdated(index: number, processor: ProcessorConfiguration | undefined) {
|
||||
if (processor === undefined) {
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
deleteProcessor(index: number) {
|
||||
this.route.update((route) => {
|
||||
if (route && route.processors) {
|
||||
route?.processors?.splice(index, 1);
|
||||
return {
|
||||
...route,
|
||||
processors: route.processors,
|
||||
};
|
||||
}
|
||||
return route;
|
||||
});
|
||||
this.snackBar.open('Processor Removed', 'Dismiss', {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user