mirror of
https://github.com/jwetzell/showbridge-webui.git
synced 2026-08-23 15:09:01 +00:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 541dfedf78 | |||
| e0f686b08b | |||
| eee372b337 | |||
| 5d54ec8c5c | |||
| 67b5001a14 | |||
| bd162bd675 | |||
| 2ff91356c6 | |||
| 3df630a510 | |||
| cd8a11a805 | |||
| b53c30c5e8 | |||
| 0603e742c6 | |||
| 7330cdc956 | |||
| afe37c9b58 | |||
| 273f8c53d6 | |||
| 53c6f4341a | |||
| f2373ebcf1 | |||
| 02238d7d86 | |||
| 3a016f7b1c | |||
| 840720420e | |||
| 75301bc9fa | |||
| a6ed43ca97 | |||
| 2f757a1afc | |||
| 4439a4e115 | |||
| 2b28ef4f61 | |||
| cf34c0ec1f | |||
| e85446697b | |||
| 283b28e8c1 | |||
| cb4e011fea | |||
| 08af66c378 | |||
| bb76c3b561 | |||
| 8f9d2352c8 | |||
| 95b109de8f | |||
| 53ec3b222a | |||
| a09824ca03 | |||
| f9695c19d6 | |||
| 2396657fc8 | |||
| 83469cc9f2 | |||
| 18e1000da5 | |||
| 17536deff1 | |||
| 450c5d934d | |||
| 088f278bb7 | |||
| 8db22220dd | |||
| d72fc9726a | |||
| 0b86856a71 | |||
| 2ed2418ae1 | |||
| 2576e4902d | |||
| fa2baa71f4 | |||
| 3956290d3d | |||
| a00efa0c5c | |||
| e309df8fe5 | |||
| 6323dd1724 | |||
| 0aa3b23362 | |||
| ac2ced53bf | |||
| b9950c64e7 | |||
| 31f42e696d | |||
| 947fd14364 | |||
| 0a738b5c01 | |||
| 876f41f3c6 | |||
| 903653e4b3 | |||
| 785c1b882c | |||
| 4b1bd29487 | |||
| 70d5578713 | |||
| fca57b0302 | |||
| 69599e688c | |||
| 5e22cbfbdd | |||
| 26631d3bc2 | |||
| 0fc02a46d1 | |||
| 55267ab4db | |||
| 0d09bd534a | |||
| a433b0e036 |
@@ -1,18 +0,0 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: 'npm'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
groups:
|
||||
angular:
|
||||
applies-to: version-updates
|
||||
patterns:
|
||||
- '@angular*'
|
||||
update-types:
|
||||
- 'minor'
|
||||
- 'patch'
|
||||
- package-ecosystem: 'github-actions'
|
||||
directory: '/'
|
||||
schedule:
|
||||
interval: 'weekly'
|
||||
@@ -9,10 +9,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
@@ -4,14 +4,14 @@ on:
|
||||
tags:
|
||||
- 'v*'
|
||||
jobs:
|
||||
build-publish:
|
||||
build-webui:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
cache: 'npm'
|
||||
|
||||
+15
-3
@@ -1,8 +1,20 @@
|
||||
import { test } from '@playwright/test';
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('add module', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.locator('app-module-list').getByText('add').click();
|
||||
await page.getByRole('button', { name: 'Add Module' }).click();
|
||||
await page.getByRole('menuitem', { name: 'HTTP Server' }).click();
|
||||
// TODO(jwetzell): test that the module gets added
|
||||
const module = page.locator('#modules\\.0');
|
||||
await expect(module).toBeVisible();
|
||||
await expect(module).toContainText('HTTP Server');
|
||||
});
|
||||
|
||||
test('remove module', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.getByRole('button', { name: 'Add Module' }).click();
|
||||
await page.getByRole('menuitem', { name: 'HTTP Server' }).click();
|
||||
const module = page.locator('#modules\\.0');
|
||||
await expect(module).toBeVisible();
|
||||
await module.getByRole('button', { name: 'Delete Module' }).click();
|
||||
await expect(module).not.toBeVisible();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('add route', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.getByRole('button', { name: 'Add Route' }).click();
|
||||
await page.getByRole('menuitem', { name: 'HTTP Server' }).click();
|
||||
const route = page.locator('#routes\\.0');
|
||||
await expect(route).toBeVisible();
|
||||
await expect(route).toContainText('Route 0');
|
||||
});
|
||||
|
||||
test('remove route', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.getByRole('button', { name: 'Add Route' }).click();
|
||||
const route = page.locator('#routes\\.0');
|
||||
await expect(route).toBeVisible();
|
||||
await route.getByRole('button', { name: 'Delete Route' }).click();
|
||||
await expect(route).not.toBeVisible();
|
||||
});
|
||||
Generated
+2269
-3227
File diff suppressed because it is too large
Load Diff
+24
-25
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@showbridge/webui",
|
||||
"version": "0.13.1",
|
||||
"version": "0.14.4",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
@@ -26,37 +26,36 @@
|
||||
"dist"
|
||||
],
|
||||
"license": "MIT",
|
||||
"packageManager": "npm@11.6.2",
|
||||
"packageManager": "npm@12.0.2",
|
||||
"dependencies": {
|
||||
"@angular/cdk": "21.2.11",
|
||||
"@angular/common": "21.2.13",
|
||||
"@angular/compiler": "21.2.13",
|
||||
"@angular/core": "21.2.13",
|
||||
"@angular/forms": "21.2.13",
|
||||
"@angular/material": "21.2.11",
|
||||
"@angular/platform-browser": "21.2.13",
|
||||
"@angular/router": "21.2.13",
|
||||
"@angular/cdk": "22.1.2",
|
||||
"@angular/common": "22.1.3",
|
||||
"@angular/compiler": "22.1.3",
|
||||
"@angular/core": "22.1.3",
|
||||
"@angular/forms": "22.1.3",
|
||||
"@angular/material": "22.1.2",
|
||||
"@angular/platform-browser": "22.1.3",
|
||||
"@angular/router": "22.1.3",
|
||||
"ajv": "8.20.0",
|
||||
"js-yaml": "4.1.1",
|
||||
"js-yaml": "5.3.0",
|
||||
"lodash-es": "4.18.1",
|
||||
"rxjs": "7.8.2",
|
||||
"tslib": "2.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/build": "21.2.11",
|
||||
"@angular/cli": "21.2.11",
|
||||
"@angular/compiler-cli": "21.2.13",
|
||||
"@angular/material": "21.2.11",
|
||||
"@playwright/test": "1.60.0",
|
||||
"@tailwindcss/postcss": "4.3.0",
|
||||
"@angular/build": "22.1.4",
|
||||
"@angular/cli": "22.1.4",
|
||||
"@angular/compiler-cli": "22.1.3",
|
||||
"@playwright/test": "1.62.1",
|
||||
"@tailwindcss/postcss": "4.3.3",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"jsdom": "29.1.1",
|
||||
"playwright-ng-schematics": "^21.1.0",
|
||||
"postcss": "8.5.14",
|
||||
"prettier": "3.8.3",
|
||||
"tailwindcss": "4.3.0",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.1.6"
|
||||
"jsdom": "30.0.1",
|
||||
"playwright-ng-schematics": "22.0.3",
|
||||
"postcss": "8.5.26",
|
||||
"prettier": "3.9.6",
|
||||
"tailwindcss": "4.3.3",
|
||||
"typescript": "6.0.3",
|
||||
"vitest": "4.1.11"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,9 +24,13 @@ export default defineConfig({
|
||||
webServer: [
|
||||
{
|
||||
name: 'showbridge',
|
||||
command: 'showbridge --config config.yaml',
|
||||
command: 'showbridge --config config.test.yaml',
|
||||
url: 'http://localhost:8080/health',
|
||||
timeout: 10000,
|
||||
gracefulShutdown: {
|
||||
signal: 'SIGTERM',
|
||||
timeout: 5000,
|
||||
},
|
||||
},
|
||||
],
|
||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||
@@ -36,6 +40,7 @@ export default defineConfig({
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
video: 'retain-on-failure',
|
||||
},
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended"
|
||||
]
|
||||
}
|
||||
+1
-1
@@ -52,7 +52,7 @@
|
||||
<div class="grow overflow-y-auto">
|
||||
<app-module-list
|
||||
[modules]="config()?.modules"
|
||||
(modulesChange)="modulesUpdated($event)"
|
||||
(updated)="modulesUpdated($event)"
|
||||
></app-module-list>
|
||||
<app-route-list
|
||||
[routes]="config()?.routes"
|
||||
|
||||
+2
-1
@@ -1,4 +1,4 @@
|
||||
import { Component, computed, effect, inject } from '@angular/core';
|
||||
import { Component, computed, effect, inject, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
@@ -29,6 +29,7 @@ import { SettingsService } from './services/settings';
|
||||
ConfigPreviewComponent,
|
||||
],
|
||||
templateUrl: './app.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
styleUrl: './app.css',
|
||||
})
|
||||
export class App {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { Component, inject, Input, OnInit } from '@angular/core';
|
||||
import { Component, inject, Input, OnInit, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { ParamInfo } from '../../models/form';
|
||||
@@ -12,6 +12,7 @@ import { parseStringToArray } from '../../utils/params';
|
||||
templateUrl: './array-form.html',
|
||||
styleUrl: './array-form.css',
|
||||
imports: [MatIconModule, FormsModule, CdkDrag, CdkDropList],
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
standalone: true,
|
||||
})
|
||||
export class ArrayFormComponent implements OnInit {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, computed, input } from '@angular/core';
|
||||
import { Component, computed, input, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
@@ -9,6 +9,7 @@ import { Config } from '../../models/config';
|
||||
selector: 'app-config-preview',
|
||||
imports: [MatIconModule, MatButtonModule, MatTooltipModule],
|
||||
templateUrl: './config-preview.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
styleUrl: './config-preview.css',
|
||||
})
|
||||
export class ConfigPreviewComponent {
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
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"
|
||||
role="button"
|
||||
aria-label="Add Module"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</div>
|
||||
@@ -18,14 +20,21 @@
|
||||
}
|
||||
<div class="text-white">Modules</div>
|
||||
</div>
|
||||
<div class="grow overflow-x-hidden overflow-y-auto gap-1.5">
|
||||
<div
|
||||
class="grow overflow-x-hidden overflow-y-auto gap-1.5"
|
||||
cdkDropList
|
||||
(cdkDropListDropped)="drop($event)"
|
||||
[cdkDropListData]="modules()"
|
||||
>
|
||||
@for (module of modules(); track module.id; let i = $index) {
|
||||
<div class="m-2">
|
||||
<div class="m-2" cdkDrag>
|
||||
<app-module
|
||||
[id]="listService.pathToId(`modules/${i}`)"
|
||||
[path]="`modules/${i}`"
|
||||
(moduleChange)="moduleUpdated(i, $event)"
|
||||
[module]="module"
|
||||
(updated)="moduleUpdated(i, $event)"
|
||||
(delete)="deleteModule(i)"
|
||||
[inDragList]="true"
|
||||
></app-module>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,22 +1,36 @@
|
||||
import { Component, inject, model } from '@angular/core';
|
||||
import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import { Component, inject, input, output, ChangeDetectionStrategy } 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 { ModuleConfig } from '../../models/config';
|
||||
import { ListsService } from '../../services/lists';
|
||||
import { SchemaService } from '../../services/schema';
|
||||
import { ModuleComponent } from '../module/module';
|
||||
|
||||
@Component({
|
||||
selector: 'app-module-list',
|
||||
imports: [MatMenuModule, MatIconModule, MatButtonModule, MatTooltipModule, ModuleComponent],
|
||||
imports: [
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
ModuleComponent,
|
||||
CdkDrag,
|
||||
CdkDropList,
|
||||
],
|
||||
templateUrl: './module-list.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
styleUrl: './module-list.css',
|
||||
})
|
||||
export class ModuleListComponent {
|
||||
modules = model<ModuleConfig[]>();
|
||||
modules = input<ModuleConfig[]>();
|
||||
updated = output<ModuleConfig[]>();
|
||||
public schemaService = inject(SchemaService);
|
||||
public listService = inject(ListsService);
|
||||
|
||||
private snackBar = inject(MatSnackBar);
|
||||
|
||||
@@ -25,46 +39,51 @@ export class ModuleListComponent {
|
||||
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;
|
||||
});
|
||||
const currentModules = this.modules();
|
||||
if (currentModules === undefined) {
|
||||
console.error('modules is undefined, cannot update');
|
||||
return;
|
||||
}
|
||||
currentModules[index] = cloneDeep(module);
|
||||
this.updated.emit(cloneDeep(currentModules));
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
const currentModules = this.modules() || [];
|
||||
if (currentModules === undefined) {
|
||||
console.error('modules is undefined, cannot update');
|
||||
return;
|
||||
}
|
||||
currentModules.push(moduleTemplate);
|
||||
this.updated.emit(cloneDeep(currentModules));
|
||||
this.snackBar.open('Module Added', 'Dismiss', {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
deleteModule(index: number) {
|
||||
this.modules.update((modules) => {
|
||||
if (modules) {
|
||||
modules?.splice(index, 1);
|
||||
return [...modules];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
const currentModules = this.modules();
|
||||
if (currentModules === undefined) {
|
||||
console.error('modules is undefined, cannot delete');
|
||||
return;
|
||||
}
|
||||
currentModules.splice(index, 1);
|
||||
this.updated.emit(cloneDeep(currentModules));
|
||||
this.snackBar.open('Module Removed', 'Dismiss', {
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
|
||||
drop(event: CdkDragDrop<ModuleConfig[] | undefined>) {
|
||||
if (event.previousContainer === event.container) {
|
||||
const currentModules = this.modules();
|
||||
if (currentModules === undefined) {
|
||||
console.error('modules is undefined, not updating');
|
||||
return;
|
||||
}
|
||||
moveItemInArray(currentModules, event.previousIndex, event.currentIndex);
|
||||
this.updated.emit(cloneDeep(currentModules));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
}} border-solid w-full h-full"
|
||||
>
|
||||
<div class="flex items-center justify-center">
|
||||
@if (inDragList()) {
|
||||
<div
|
||||
cdkDragHandle
|
||||
class="flex items-center justify-center bg-transparent hover:bg-gray-700 hover:cursor-move text-blue-400"
|
||||
>
|
||||
<mat-icon>drag_indicator</mat-icon>
|
||||
</div>
|
||||
}
|
||||
<div class="flex items-center">
|
||||
<mat-icon [style.color]="inputIndicatorColor()" matTooltip="Input Indicator"
|
||||
>keyboard_arrow_down</mat-icon
|
||||
@@ -20,6 +28,8 @@
|
||||
<div
|
||||
class="flex items-center justify-center hover:bg-gray-700 hover:cursor-pointer"
|
||||
(click)="delete.emit()"
|
||||
role="button"
|
||||
aria-label="Delete Module"
|
||||
>
|
||||
<mat-icon class="text-red-500!">close</mat-icon>
|
||||
</div>
|
||||
@@ -66,4 +76,119 @@
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *cdkDragPreview 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-full h-full"
|
||||
>
|
||||
<div class="flex items-center justify-center">
|
||||
@if (inDragList()) {
|
||||
<div
|
||||
cdkDragHandle
|
||||
class="flex items-center justify-center bg-transparent hover:bg-gray-700 hover:cursor-move text-blue-400"
|
||||
>
|
||||
<mat-icon>drag_indicator</mat-icon>
|
||||
</div>
|
||||
}
|
||||
<div class="flex items-center">
|
||||
<mat-icon [style.color]="inputIndicatorColor()" matTooltip="Input Indicator"
|
||||
>keyboard_arrow_down</mat-icon
|
||||
>
|
||||
<mat-icon [style.color]="outputIndicatorColor()" matTooltip="Output Indicator"
|
||||
>keyboard_arrow_up</mat-icon
|
||||
>
|
||||
</div>
|
||||
<div class="text-white">
|
||||
{{ schema().title || module()?.type }}
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<div
|
||||
class="flex items-center justify-center hover:bg-gray-700 hover:cursor-pointer"
|
||||
(click)="delete.emit()"
|
||||
>
|
||||
<mat-icon class="text-red-500!">close</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *cdkDragPlaceholder 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-full h-full opacity-30"
|
||||
>
|
||||
<div class="flex items-center justify-center">
|
||||
@if (inDragList()) {
|
||||
<div
|
||||
cdkDragHandle
|
||||
class="flex items-center justify-center bg-transparent hover:bg-gray-700 hover:cursor-move text-blue-400"
|
||||
>
|
||||
<mat-icon>drag_indicator</mat-icon>
|
||||
</div>
|
||||
}
|
||||
<div class="flex items-center">
|
||||
<mat-icon [style.color]="inputIndicatorColor()" matTooltip="Input Indicator"
|
||||
>keyboard_arrow_down</mat-icon
|
||||
>
|
||||
<mat-icon [style.color]="outputIndicatorColor()" matTooltip="Output Indicator"
|
||||
>keyboard_arrow_up</mat-icon
|
||||
>
|
||||
</div>
|
||||
<div class="text-white">
|
||||
{{ schema().title || module()?.type }}
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<div
|
||||
class="flex items-center justify-center hover:bg-gray-700 hover:cursor-pointer"
|
||||
(click)="delete.emit()"
|
||||
>
|
||||
<mat-icon class="text-red-500!">close</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="bg-gray-600 h-0.5 border-0" />
|
||||
<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>
|
||||
@if (moduleConfigErrors().length > 0) {
|
||||
<div class="m-2 p-2 border-2 border-red-500">
|
||||
<div class="flex items-center mb-2 text-red-500">
|
||||
<mat-icon>error</mat-icon>
|
||||
<span class="ml-1">Module Errors</span>
|
||||
</div>
|
||||
@for (error of moduleConfigErrors(); track $index) {
|
||||
<div class="ml-4 mb-1 text-white">
|
||||
{{ error.error }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import { CdkDragHandle, CdkDragPlaceholder, CdkDragPreview } from '@angular/cdk/drag-drop';
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { Component, computed, inject, input, model, output, signal } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
input,
|
||||
output,
|
||||
signal,
|
||||
ChangeDetectionStrategy,
|
||||
} 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 { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { debounceTime, tap } from 'rxjs';
|
||||
import { ModuleConfig } from '../../models/config';
|
||||
import { ConfigService } from '../../services/config';
|
||||
@@ -22,8 +32,12 @@ import { ParamsFormComponent } from '../params-form/params-form';
|
||||
MatMenuModule,
|
||||
MatTooltipModule,
|
||||
JsonPipe,
|
||||
CdkDragHandle,
|
||||
CdkDragPreview,
|
||||
CdkDragPlaceholder,
|
||||
],
|
||||
templateUrl: './module.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
styleUrl: './module.css',
|
||||
})
|
||||
export class ModuleComponent {
|
||||
@@ -38,8 +52,10 @@ export class ModuleComponent {
|
||||
return undefined;
|
||||
});
|
||||
|
||||
module = model<ModuleConfig>();
|
||||
inDragList = input<boolean>(false);
|
||||
module = input<ModuleConfig>();
|
||||
delete = output<void>();
|
||||
updated = output<ModuleConfig>();
|
||||
|
||||
params = computed(() => this.module()!.params);
|
||||
id = computed(() => this.module()!.id);
|
||||
@@ -77,18 +93,12 @@ export class ModuleComponent {
|
||||
});
|
||||
|
||||
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;
|
||||
});
|
||||
const currentModule = this.module();
|
||||
if (currentModule) {
|
||||
currentModule.id = value.id;
|
||||
currentModule.type = value.type;
|
||||
this.updated.emit(cloneDeep(currentModule));
|
||||
}
|
||||
});
|
||||
if (this.id() !== undefined) {
|
||||
this.eventsService
|
||||
@@ -117,16 +127,11 @@ export class ModuleComponent {
|
||||
}
|
||||
|
||||
paramsUpdated(params: any) {
|
||||
this.module.update((module) => {
|
||||
if (module !== undefined && module.params !== undefined) {
|
||||
module.params = params;
|
||||
return {
|
||||
...module,
|
||||
params: module.params,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
const currentModule = this.module();
|
||||
if (currentModule && currentModule.params !== undefined) {
|
||||
currentModule.params = params;
|
||||
this.updated.emit(cloneDeep(currentModule));
|
||||
}
|
||||
}
|
||||
|
||||
deleteMe() {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { Component, effect, input, OnDestroy, output } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
effect,
|
||||
input,
|
||||
OnDestroy,
|
||||
output,
|
||||
ChangeDetectionStrategy,
|
||||
} from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
@@ -26,6 +33,7 @@ import { ArrayFormComponent } from '../array-form/array-form';
|
||||
ArrayFormComponent,
|
||||
MatTabsModule,
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
standalone: true,
|
||||
})
|
||||
export class ParamsFormComponent implements OnDestroy {
|
||||
|
||||
@@ -63,13 +63,37 @@
|
||||
<div
|
||||
class="flex flex-col bg-gray-800 border-2 {{
|
||||
isInError() ? 'border-red-500' : 'border-gray-600'
|
||||
}} border-dotted w-fit h-full"
|
||||
}} border-solid w-fit h-full opacity-30"
|
||||
>
|
||||
<div class="flex items-center justify-center">
|
||||
<div class="grow ml-1 mr-3 text-transparent">
|
||||
@if (inDragList()) {
|
||||
<div
|
||||
cdkDragHandle
|
||||
class="flex items-center justify-center bg-transparent hover:bg-gray-700 hover:cursor-move text-blue-400"
|
||||
>
|
||||
<mat-icon>drag_indicator</mat-icon>
|
||||
</div>
|
||||
}
|
||||
<div class="grow ml-1 mr-3 text-white">
|
||||
{{ schema()?.title || processor()?.type }}
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center justify-center hover:bg-gray-700 hover:cursor-pointer"
|
||||
(click)="delete.emit()"
|
||||
>
|
||||
<mat-icon class="text-red-500!">close</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
@if (hasParams()) {
|
||||
<hr class="bg-gray-600 h-0.5 border-0" />
|
||||
<div>
|
||||
<app-params-form
|
||||
[paramsSchema]="schema()?.properties?.params"
|
||||
[data]="params()"
|
||||
(updated)="paramsUpdated($event)"
|
||||
></app-params-form>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CdkDragHandle, CdkDragPlaceholder, CdkDragPreview } from '@angular/cdk/drag-drop';
|
||||
import { Component, computed, inject, input, output } from '@angular/core';
|
||||
import { Component, computed, inject, input, output, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { ProcessorConfig } from '../../models/config';
|
||||
@@ -17,6 +17,7 @@ import { ParamsFormComponent } from '../params-form/params-form';
|
||||
CdkDragPlaceholder,
|
||||
],
|
||||
templateUrl: './processor.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
styleUrl: './processor.css',
|
||||
})
|
||||
export class ProcessorComponent {
|
||||
|
||||
@@ -4,21 +4,30 @@
|
||||
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()"
|
||||
role="button"
|
||||
aria-label="Add Route"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
</div>
|
||||
<div class="text-white">Routes</div>
|
||||
</div>
|
||||
<div class="grow overflow-x-hidden overflow-y-auto gap-1.5">
|
||||
@for (route of routes(); track $index; let i = $index) {
|
||||
<div class="m-2">
|
||||
<div
|
||||
class="grow overflow-x-hidden overflow-y-auto gap-1.5"
|
||||
cdkDropList
|
||||
(cdkDropListDropped)="drop($event)"
|
||||
[cdkDropListData]="routes()"
|
||||
>
|
||||
@for (route of routes(); track route.id; let i = $index) {
|
||||
<div class="m-2" cdkDrag>
|
||||
<app-route
|
||||
[id]="listService.pathToId(`routes/${i}`)"
|
||||
[path]="`routes/${i}`"
|
||||
(updated)="routeUpdated(i, $event)"
|
||||
[route]="route"
|
||||
[moduleIds]="moduleIds() || []"
|
||||
(delete)="deleteRoute(i)"
|
||||
(moveProcessor)="moveProcessorBetweenRoutes($event)"
|
||||
[inDragList]="true"
|
||||
></app-route>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { transferArrayItem } from '@angular/cdk/drag-drop';
|
||||
import { Component, inject, input, output } from '@angular/core';
|
||||
import { A11yModule } from '@angular/cdk/a11y';
|
||||
import {
|
||||
CdkDrag,
|
||||
CdkDragDrop,
|
||||
CdkDropList,
|
||||
moveItemInArray,
|
||||
transferArrayItem,
|
||||
} from '@angular/cdk/drag-drop';
|
||||
import { Component, inject, input, output, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
@@ -7,13 +14,24 @@ import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { RouteConfig } from '../../models/config';
|
||||
import { ListsService } from '../../services/lists';
|
||||
import { SchemaService } from '../../services/schema';
|
||||
import { RouteComponent } from '../route/route';
|
||||
|
||||
@Component({
|
||||
selector: 'app-route-list',
|
||||
imports: [RouteComponent, MatMenuModule, MatIconModule, MatButtonModule, MatTooltipModule],
|
||||
imports: [
|
||||
RouteComponent,
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
CdkDrag,
|
||||
CdkDropList,
|
||||
A11yModule,
|
||||
],
|
||||
templateUrl: './route-list.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
styleUrl: './route-list.css',
|
||||
})
|
||||
export class RouteListComponent {
|
||||
@@ -21,6 +39,7 @@ export class RouteListComponent {
|
||||
moduleIds = input<string[]>();
|
||||
updated = output<RouteConfig[]>();
|
||||
public schemaService = inject(SchemaService);
|
||||
public listService = inject(ListsService);
|
||||
|
||||
private snackBar = inject(MatSnackBar);
|
||||
|
||||
@@ -103,4 +122,16 @@ export class RouteListComponent {
|
||||
|
||||
this.updated.emit(cloneDeep(routes));
|
||||
}
|
||||
|
||||
drop(event: CdkDragDrop<RouteConfig[] | undefined>) {
|
||||
if (event.previousContainer === event.container) {
|
||||
const currentRoutes = this.routes();
|
||||
if (currentRoutes === undefined) {
|
||||
console.error('routes is undefined, not updating');
|
||||
return;
|
||||
}
|
||||
moveItemInArray(currentRoutes, event.previousIndex, event.currentIndex);
|
||||
this.updated.emit(cloneDeep(currentRoutes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
}} border-solid w-full"
|
||||
>
|
||||
<div class="flex items-center justify-end">
|
||||
@if (inDragList()) {
|
||||
<div
|
||||
cdkDragHandle
|
||||
class="flex items-center justify-center bg-transparent hover:bg-gray-700 hover:cursor-move text-blue-400"
|
||||
>
|
||||
<mat-icon>drag_indicator</mat-icon>
|
||||
</div>
|
||||
}
|
||||
<div class="flex items-center">
|
||||
<mat-icon [style.color]="indicatorColor()" matTooltip="Route Indicator"
|
||||
>chevron_right</mat-icon
|
||||
@@ -15,6 +23,8 @@
|
||||
<div
|
||||
class="flex items-center justify-center hover:bg-gray-700 hover:cursor-pointer"
|
||||
(click)="delete.emit()"
|
||||
role="button"
|
||||
aria-label="Delete Route"
|
||||
>
|
||||
<mat-icon class="text-red-500!">close</mat-icon>
|
||||
</div>
|
||||
@@ -66,12 +76,12 @@
|
||||
<div
|
||||
class="border-2 border-gray-500 m-2"
|
||||
cdkDropList
|
||||
[id]="listsService.registerProcessorList(path() + '/processors')"
|
||||
[id]="processorListId()"
|
||||
[cdkDropListConnectedTo]="listsService.processorListIds"
|
||||
(cdkDropListDropped)="drop($event)"
|
||||
[cdkDropListData]="route()?.processors"
|
||||
>
|
||||
@for (processor of processors(); track $index; let i = $index) {
|
||||
@for (processor of processors(); track processor.id; let i = $index) {
|
||||
<div cdkDrag>
|
||||
<app-processor
|
||||
[path]="path() + '/processors/' + i"
|
||||
@@ -115,4 +125,148 @@
|
||||
</div>
|
||||
}
|
||||
</ng-template>
|
||||
|
||||
<div *cdkDragPreview 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-full"
|
||||
>
|
||||
<div class="flex items-center justify-end">
|
||||
@if (inDragList()) {
|
||||
<div
|
||||
cdkDragHandle
|
||||
class="flex items-center justify-center bg-transparent hover:bg-gray-700 hover:cursor-move text-blue-400"
|
||||
>
|
||||
<mat-icon>drag_indicator</mat-icon>
|
||||
</div>
|
||||
}
|
||||
<div class="flex items-center">
|
||||
<mat-icon [style.color]="indicatorColor()" matTooltip="Route Indicator"
|
||||
>chevron_right</mat-icon
|
||||
>
|
||||
</div>
|
||||
<div class="grow text-left ml-2 text-white">Route</div>
|
||||
<div
|
||||
class="flex items-center justify-center hover:bg-gray-700 hover:cursor-pointer"
|
||||
(click)="delete.emit()"
|
||||
>
|
||||
<mat-icon class="text-red-500!">close</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *cdkDragPlaceholder 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-full opacity-30"
|
||||
>
|
||||
<div class="flex items-center justify-end">
|
||||
@if (inDragList()) {
|
||||
<div
|
||||
cdkDragHandle
|
||||
class="flex items-center justify-center bg-transparent hover:bg-gray-700 hover:cursor-move text-blue-400"
|
||||
>
|
||||
<mat-icon>drag_indicator</mat-icon>
|
||||
</div>
|
||||
}
|
||||
<div class="flex items-center">
|
||||
<mat-icon [style.color]="indicatorColor()" matTooltip="Route Indicator"
|
||||
>chevron_right</mat-icon
|
||||
>
|
||||
</div>
|
||||
<div class="grow text-left ml-2 text-white">Route</div>
|
||||
<div
|
||||
class="flex items-center justify-center hover:bg-gray-700 hover:cursor-pointer"
|
||||
(click)="delete.emit()"
|
||||
>
|
||||
<mat-icon class="text-red-500!">close</mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="bg-gray-600 h-0.5 border-0" />
|
||||
<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"
|
||||
cdkDropList
|
||||
[id]="processorListId()"
|
||||
[cdkDropListConnectedTo]="listsService.processorListIds"
|
||||
(cdkDropListDropped)="drop($event)"
|
||||
[cdkDropListData]="route()?.processors"
|
||||
>
|
||||
@for (processor of processors(); track processor.id; let i = $index) {
|
||||
<div cdkDrag>
|
||||
<app-processor
|
||||
[path]="path() + '/processors/' + i"
|
||||
(updated)="processorUpdated(i, $event)"
|
||||
[processor]="processor"
|
||||
(delete)="deleteProcessor(i)"
|
||||
[inDragList]="true"
|
||||
></app-processor>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@if (routeConfigErrors().length > 0) {
|
||||
<div class="m-2 p-2 border-2 border-red-500">
|
||||
<div class="flex items-center mb-2 text-red-500">
|
||||
<mat-icon>error</mat-icon>
|
||||
<span class="ml-1">Route Errors</span>
|
||||
</div>
|
||||
@for (error of routeConfigErrors(); track error.index) {
|
||||
<div class="ml-4 mb-1 text-white">
|
||||
{{ error.error }}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
import { CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray } from '@angular/cdk/drag-drop';
|
||||
import {
|
||||
CdkDrag,
|
||||
CdkDragDrop,
|
||||
CdkDragHandle,
|
||||
CdkDragPlaceholder,
|
||||
CdkDragPreview,
|
||||
CdkDropList,
|
||||
moveItemInArray,
|
||||
} from '@angular/cdk/drag-drop';
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { Component, computed, inject, input, output, signal } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
input,
|
||||
output,
|
||||
signal,
|
||||
ChangeDetectionStrategy,
|
||||
} from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
@@ -27,9 +43,13 @@ import { ProcessorComponent } from '../processor/processor';
|
||||
ProcessorComponent,
|
||||
MatTooltipModule,
|
||||
CdkDrag,
|
||||
CdkDragHandle,
|
||||
CdkDropList,
|
||||
CdkDragPreview,
|
||||
CdkDragPlaceholder,
|
||||
],
|
||||
templateUrl: './route.html',
|
||||
changeDetection: ChangeDetectionStrategy.Eager,
|
||||
styleUrl: './route.css',
|
||||
})
|
||||
export class RouteComponent {
|
||||
@@ -45,6 +65,7 @@ export class RouteComponent {
|
||||
return undefined;
|
||||
});
|
||||
|
||||
inDragList = input<boolean>(false);
|
||||
route = input<RouteConfig>();
|
||||
moduleIds = input<string[]>([]);
|
||||
delete = output<void>();
|
||||
@@ -83,8 +104,14 @@ export class RouteComponent {
|
||||
private configService = inject(ConfigService);
|
||||
public listsService = inject(ListsService);
|
||||
|
||||
public processorListId = signal<string>('');
|
||||
|
||||
indicatorColor = signal<string>('gray');
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.listsService.removeProcessorList(this.path() + '/processors');
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.formGroup.patchValue({
|
||||
input: this.route()?.input,
|
||||
@@ -115,6 +142,7 @@ export class RouteComponent {
|
||||
this.indicatorColor.set('gray');
|
||||
});
|
||||
}
|
||||
this.processorListId.set(this.listsService.registerProcessorList(this.path() + '/processors'));
|
||||
}
|
||||
|
||||
isInError(): boolean {
|
||||
|
||||
@@ -22,11 +22,13 @@ export type ModuleConfig = {
|
||||
};
|
||||
|
||||
export type RouteConfig = {
|
||||
id: string;
|
||||
input?: string;
|
||||
processors?: ProcessorConfig[];
|
||||
};
|
||||
|
||||
export type ProcessorConfig = {
|
||||
id: string;
|
||||
type: string;
|
||||
params?: Record<string, any>;
|
||||
};
|
||||
|
||||
+15
-21
@@ -17,17 +17,18 @@ import { SettingsService } from './settings';
|
||||
})
|
||||
export class ConfigService {
|
||||
pendingConfigIsValid = computed(() => {
|
||||
const config = this.currentlyShownConfig();
|
||||
const config = this._currentlyShownConfig();
|
||||
if (config === undefined) {
|
||||
return false;
|
||||
}
|
||||
return this.schemaService.validate(this.schemaService.configSchemaId, config);
|
||||
});
|
||||
currentlyShownConfig = signal<Config | undefined>(undefined);
|
||||
runningConfig = signal<Config | undefined>(undefined);
|
||||
private runningConfig = signal<Config | undefined>(undefined);
|
||||
private _currentlyShownConfig = signal<Config | undefined>(undefined);
|
||||
readonly currentlyShownConfig = this._currentlyShownConfig.asReadonly();
|
||||
|
||||
configIsDirty = computed(() => {
|
||||
const currentlyShown = this.currentlyShownConfig();
|
||||
const currentlyShown = this._currentlyShownConfig();
|
||||
const running = this.runningConfig();
|
||||
if (currentlyShown === undefined || running === undefined) {
|
||||
return false;
|
||||
@@ -44,7 +45,7 @@ export class ConfigService {
|
||||
|
||||
constructor(private schemaService: SchemaService) {
|
||||
effect(() => {
|
||||
console.log('config state changed', this.currentlyShownConfig());
|
||||
console.log('config state changed', this._currentlyShownConfig());
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
@@ -124,36 +125,29 @@ export class ConfigService {
|
||||
}
|
||||
|
||||
updateCurrentlyShownConfig(config: Config) {
|
||||
if (isEqual(config, this.currentlyShownConfig())) {
|
||||
// NOTE(jwetzell): no update
|
||||
return;
|
||||
}
|
||||
this.currentlyShownConfig.set(cloneDeep(config));
|
||||
this._currentlyShownConfig.set(cloneDeep(config));
|
||||
}
|
||||
|
||||
updateModules(modules: ModuleConfig[]) {
|
||||
const currentConfig = this.currentlyShownConfig();
|
||||
if (!currentConfig) {
|
||||
var newConfig = cloneDeep(this._currentlyShownConfig());
|
||||
if (!newConfig) {
|
||||
console.error('No currently shown config to update modules on');
|
||||
return;
|
||||
}
|
||||
newConfig.modules = cloneDeep(modules);
|
||||
|
||||
this.currentlyShownConfig.set({
|
||||
...currentConfig,
|
||||
modules: modules,
|
||||
});
|
||||
this.updateCurrentlyShownConfig(newConfig);
|
||||
}
|
||||
|
||||
updateRoutes(routes: RouteConfig[]) {
|
||||
const currentConfig = this.currentlyShownConfig();
|
||||
const currentConfig = this._currentlyShownConfig();
|
||||
if (!currentConfig) {
|
||||
console.error('No currently shown config to update routes on');
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentlyShownConfig.set({
|
||||
...currentConfig,
|
||||
routes: routes,
|
||||
});
|
||||
currentConfig.routes = cloneDeep(routes);
|
||||
|
||||
this.updateCurrentlyShownConfig(currentConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,15 @@ export class ListsService {
|
||||
return id;
|
||||
}
|
||||
|
||||
removeProcessorList(path: string | undefined) {
|
||||
if (path === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const id = this.pathToId(path);
|
||||
this.processorListIds = this.processorListIds.filter((listId) => listId !== id);
|
||||
}
|
||||
|
||||
pathToId(path: string) {
|
||||
return path.replaceAll('/', '.');
|
||||
}
|
||||
|
||||
@@ -139,12 +139,16 @@ export class SchemaService {
|
||||
}
|
||||
|
||||
getSkeletonForRoute(): RouteConfig {
|
||||
const template: RouteConfig = {};
|
||||
const template: RouteConfig = {
|
||||
id: crypto.randomUUID(),
|
||||
processors: [],
|
||||
};
|
||||
return template;
|
||||
}
|
||||
|
||||
getSkeletonForProcessor(processorType: string): ProcessorConfig {
|
||||
const template: ProcessorConfig = {
|
||||
id: crypto.randomUUID(),
|
||||
type: processorType,
|
||||
};
|
||||
const itemInfo = this.processorTypes.find((itemInfo) => itemInfo.type === processorType);
|
||||
|
||||
+9
-1
@@ -7,5 +7,13 @@
|
||||
"types": []
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["src/**/*.spec.ts"]
|
||||
"exclude": ["src/**/*.spec.ts"],
|
||||
"angularCompilerOptions": {
|
||||
"extendedDiagnostics": {
|
||||
"checks": {
|
||||
"nullishCoalescingNotNullable": "suppress",
|
||||
"optionalChainNotNullable": "suppress"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user