From 79b84460b0bc58c5a658fa3a0ac53ec01ecee695 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Fri, 6 Mar 2026 18:37:32 -0600 Subject: [PATCH] flatter layout --- src/app/app.config.ts | 6 +- src/app/app.html | 7 +- src/app/app.routes.ts | 14 ++ src/app/app.ts | 7 +- src/app/array-form/array-form.component.html | 4 +- src/app/config/config.component.html | 82 +---------- src/app/config/config.component.ts | 109 +++------------ src/app/module-list/module-list.component.css | 0 .../module-list/module-list.component.html | 45 +++++++ src/app/module-list/module-list.component.ts | 77 +++++++++++ src/app/module/module.component.html | 21 +-- src/app/module/module.component.ts | 8 +- .../params-form/params-form.component.html | 41 +++--- src/app/processor/processor.component.html | 8 +- .../route-list.component.css | 0 .../route-list.component.html | 25 ++++ .../route-list.component.ts | 72 ++++++++++ src/app/route/route.component.html | 127 +++++++++--------- src/app/route/route.component.ts | 16 +++ src/services/schema.service.ts | 8 +- 20 files changed, 396 insertions(+), 281 deletions(-) create mode 100644 src/app/app.routes.ts create mode 100644 src/app/module-list/module-list.component.css create mode 100644 src/app/module-list/module-list.component.html create mode 100644 src/app/module-list/module-list.component.ts create mode 100644 src/app/route-list.component/route-list.component.css create mode 100644 src/app/route-list.component/route-list.component.html create mode 100644 src/app/route-list.component/route-list.component.ts diff --git a/src/app/app.config.ts b/src/app/app.config.ts index 00a2a47..11e4357 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,6 +1,10 @@ import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core'; import { provideRouter } from '@angular/router'; +import { appRoutes } from './app.routes'; export const appConfig: ApplicationConfig = { - providers: [provideBrowserGlobalErrorListeners()], + providers: [ + provideBrowserGlobalErrorListeners(), + provideRouter(appRoutes), + ], }; diff --git a/src/app/app.html b/src/app/app.html index a3b9fb0..d96f9eb 100644 --- a/src/app/app.html +++ b/src/app/app.html @@ -18,13 +18,14 @@ } -
- @if (configService.currentlyShownConfig() && schemaService.schemasLoaded()) { +
+ +
diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts new file mode 100644 index 0000000..5b66db7 --- /dev/null +++ b/src/app/app.routes.ts @@ -0,0 +1,14 @@ +import { Routes } from '@angular/router'; +import { App } from './app'; + +export const appRoutes: Routes = [ + { + path: '', + redirectTo: 'config', + pathMatch: 'full', + }, + { + path: 'config', + loadComponent: () => import('./config/config.component').then((m) => m.ConfigComponent), + }, +]; diff --git a/src/app/app.ts b/src/app/app.ts index cf33509..f206060 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -13,28 +13,27 @@ import { SchemaService } from '../services/schema.service'; import { SettingsService } from '../services/settings.service'; import { ConfigComponent } from './config/config.component'; import * as yaml from 'js-yaml'; +import { RouterOutlet } from '@angular/router'; @Component({ selector: 'app-root', imports: [ - ConfigComponent, MatToolbarModule, MatProgressSpinnerModule, MatIconModule, TimeagoModule, MatMenuModule, MatButtonModule, - ], + RouterOutlet +], templateUrl: './app.html', styleUrl: './app.css', }) export class App { public schemaService = inject(SchemaService); public configService = inject(ConfigService); - private settingsService = inject(SettingsService); private snackBar = inject(MatSnackBar); - private dialog = inject(MatDialog); constructor() { effect(() => { if (this.schemaService.schemasLoaded()) { diff --git a/src/app/array-form/array-form.component.html b/src/app/array-form/array-form.component.html index 6b1d83c..ac2bff1 100644 --- a/src/app/array-form/array-form.component.html +++ b/src/app/array-form/array-form.component.html @@ -3,7 +3,7 @@
@for (item of arrayValue; track trackByIndex(i, item); let i = $index) {
- -
-
- @if (schemaService.moduleTypes.length > 0) { -
- add -
- - @for (moduleType of schemaService.moduleTypes; track moduleType) { - - } - - } -
Modules
-
-
-
- @for (module of modules(); track module; let i = $index) { -
- -
- } -
-
-
-
-
- add -
-
Routes
-
-
-
- @for (route of routes(); track route; let i = $index) { -
- -
- } -
-
-
-} - - - @if (schemaService.moduleTypes.length > 0) { -
- @for (moduleType of schemaService.moduleTypes; track moduleType) { - - } -
- } -
+@if (config() && schemaService.schemasLoaded()) { + + +} \ No newline at end of file diff --git a/src/app/config/config.component.ts b/src/app/config/config.component.ts index 477ad6d..9944e82 100644 --- a/src/app/config/config.component.ts +++ b/src/app/config/config.component.ts @@ -5,25 +5,26 @@ import { MatMenuModule } from '@angular/material/menu'; import { MatSnackBar } from '@angular/material/snack-bar'; import { Config, ModuleConfiguration, RouteConfiguration } from '../../models/config.models'; import { SchemaService } from '../../services/schema.service'; -import { ModuleComponent } from '../module/module.component'; -import { RouteComponent } from '../route/route.component'; 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, - ModuleComponent, - RouteComponent, MatButtonModule, MatTooltipModule, + ModuleListComponent, + RouteListComponent, ], templateUrl: './config.component.html', styleUrl: './config.component.css', }) export class ConfigComponent { - config = model(); + config = computed(() => this.configService.currentlyShownConfig()); modules = computed(() => this.config()?.modules ?? []); routes = computed(() => this.config()?.routes ?? []); @@ -36,109 +37,35 @@ export class ConfigComponent { return []; }); + public configService = inject(ConfigService); public schemaService = inject(SchemaService); - private snackBar = inject(MatSnackBar); - - deleteModule(index: number) { - this.config.update((config) => { - if (config && config.modules) { - config?.modules?.splice(index, 1); - return { - ...config, - modules: config.modules, - }; - } - return config; - }); - this.snackBar.open('Module Removed', 'Dismiss', { - duration: 3000, - }); - } - - deleteRoute(index: number) { - this.config.update((config) => { - if (config && config.routes) { - config?.routes?.splice(index, 1); - return { - ...config, - routes: config.routes, - }; - } - return config; - }); - this.snackBar.open('Route Removed', 'Dismiss', { - duration: 3000, - }); - } - - moduleUpdated(index: number, module: ModuleConfiguration | undefined) { - if (module === undefined) { - console.error('module is undefined, not updating'); + modulesUpdated(modules: ModuleConfiguration[] | undefined) { + if (modules === undefined) { + console.error('modules is undefined, not updating'); return; } - this.config.update((config) => { - if (config && config.modules) { - config.modules[index].id = module.id; - config.modules[index].type = module.type; - if (module.params !== undefined) { - config.modules[index].params = module.params; - } + this.configService.currentlyShownConfig.update((config) => { + if (config) { return { ...config, - modules: config.modules, + modules: modules, }; } return config; }); } - routeUpdated(index: number, route: RouteConfiguration | undefined) { - if (route === undefined) { - console.error('route is undefined, not updating'); + routesUpdated(routes: RouteConfiguration[] | undefined) { + if (routes === undefined) { + console.error('routes is undefined, not updating'); return; } - this.config.update((config) => { - if (config && config.routes) { - config.routes[index].input = route.input; - config.routes[index].output = route.output; - return { - ...config, - routes: config.routes, - }; - } - return config; - }); - } - - addModule(moduleType: string) { - const moduleTemplate = this.schemaService.getSkeletonForModule(moduleType); - this.config.update((config) => { + this.configService.currentlyShownConfig.update((config) => { if (config) { - if (!config.modules) { - config.modules = []; - } - config.modules?.push(moduleTemplate); return { ...config, - modules: config.modules, - }; - } - return config; - }); - } - - addRoute() { - const routeTemplate = this.schemaService.getSkeletonForRoute(); - this.config.update((config) => { - if (config) { - if (!config.routes) { - config.routes = []; - } - config.routes?.push(routeTemplate); - return { - ...config, - routes: config.routes, + routes: routes, }; } return config; diff --git a/src/app/module-list/module-list.component.css b/src/app/module-list/module-list.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/module-list/module-list.component.html b/src/app/module-list/module-list.component.html new file mode 100644 index 0000000..e874663 --- /dev/null +++ b/src/app/module-list/module-list.component.html @@ -0,0 +1,45 @@ +
+
+ @if (schemaService.moduleTypes.length > 0) { +
+ add +
+ + @for (moduleType of schemaService.moduleTypes; track moduleType) { + + } + + } +
Modules
+
+
+ @for (module of modules(); track module; let i = $index) { +
+ +
+ } +
+
+ + + @if (schemaService.moduleTypes.length > 0) { +
+ @for (moduleType of schemaService.moduleTypes; track moduleType) { + + } +
+ } +
diff --git a/src/app/module-list/module-list.component.ts b/src/app/module-list/module-list.component.ts new file mode 100644 index 0000000..c636847 --- /dev/null +++ b/src/app/module-list/module-list.component.ts @@ -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(); + 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, + }); + } +} diff --git a/src/app/module/module.component.html b/src/app/module/module.component.html index d9c07a8..735bd46 100644 --- a/src/app/module/module.component.html +++ b/src/app/module/module.component.html @@ -1,13 +1,12 @@ @if (module() && schema()) { -
-
-
- {{ schema().title }} +
+
+ {{ schema().title || module()?.type }}
close @@ -17,13 +16,18 @@
- + + abc + @if (!formGroup.controls['id'].valid) { + +
{{ formGroup.controls['id'].errors | json }}
+ }
-
} diff --git a/src/app/module/module.component.ts b/src/app/module/module.component.ts index 7cd9e84..7eb9ba8 100644 --- a/src/app/module/module.component.ts +++ b/src/app/module/module.component.ts @@ -1,11 +1,13 @@ import { Component, computed, inject, input, model, output } from '@angular/core'; -import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; +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', @@ -15,6 +17,8 @@ import { ParamsFormComponent } from '../params-form/params-form.component'; ParamsFormComponent, ReactiveFormsModule, MatMenuModule, + MatTooltipModule, + JsonPipe, ], templateUrl: './module.component.html', styleUrl: './module.component.css', @@ -34,7 +38,7 @@ export class ModuleComponent { }); formGroup: FormGroup = new FormGroup({ - id: new FormControl(''), + id: new FormControl('', [Validators.required]), type: new FormControl(''), }); diff --git a/src/app/params-form/params-form.component.html b/src/app/params-form/params-form.component.html index e90b025..3221f44 100644 --- a/src/app/params-form/params-form.component.html +++ b/src/app/params-form/params-form.component.html @@ -1,6 +1,7 @@ @if (paramsSchema && paramsFormInfo) { @if (paramsOptions.length > 1) { @@ -14,7 +15,7 @@ @for (key of paramKeys(); track key) {
@if (getParamInfo(key); as paramInfo) { - + @switch (paramInfo.type) { @case ('boolean') { @@ -24,12 +25,12 @@ } @else { } - 123 + 123 } @case ('integer') { @if (!paramInfo.options) { } @else { } - 123 + 123 } @case ('string') { @if (!paramInfo.options) { } @else { } - abc + abc } @case ('array') { - data_array + data_array } @case ('object') { - data_object + data_object } @default { } } + @if (paramInfo.hint) { +
+ + help_outline + +
+ } @if (!paramsFormInfo.formGroup.controls[key].valid) {
{{ paramsFormInfo.formGroup.controls[key].errors | json }}
} -
- - help_outline - -
}
} diff --git a/src/app/processor/processor.component.html b/src/app/processor/processor.component.html index f316abd..533e255 100644 --- a/src/app/processor/processor.component.html +++ b/src/app/processor/processor.component.html @@ -2,12 +2,12 @@
-
-
- {{ processor()?.type }} +
+
+ {{ schema()?.title || processor()?.type }}
close diff --git a/src/app/route-list.component/route-list.component.css b/src/app/route-list.component/route-list.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/route-list.component/route-list.component.html b/src/app/route-list.component/route-list.component.html new file mode 100644 index 0000000..728f11c --- /dev/null +++ b/src/app/route-list.component/route-list.component.html @@ -0,0 +1,25 @@ +
+
+
+ add +
+
Routes
+
+
+ @for (route of routes(); track route; let i = $index) { +
+ +
+ } +
+
diff --git a/src/app/route-list.component/route-list.component.ts b/src/app/route-list.component/route-list.component.ts new file mode 100644 index 0000000..2bc9230 --- /dev/null +++ b/src/app/route-list.component/route-list.component.ts @@ -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(); + moduleIds = input(); + 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, + }); + } +} diff --git a/src/app/route/route.component.html b/src/app/route/route.component.html index 73313fb..02cdb5c 100644 --- a/src/app/route/route.component.html +++ b/src/app/route/route.component.html @@ -1,77 +1,76 @@ @if (route()) { -
-
-
-
- close -
+ +
+
+
Route {{ index() }}
+
+ close
+
+
+ +
+
+ + + @if (!formGroup.controls['input'].valid) { + +
{{ formGroup.controls['input'].errors | json }}
+ } +
+
+
-
-
-
- - - @if (!formGroup.controls['input'].valid) { - -
{{ formGroup.controls['input'].errors | json }}
- } +
+ @if (schemaService.processorTypes.length > 0) { +
+ add
-
- -
-
Processors
-
- @if (processors() === undefined || processors()?.length === 0) { -
- } @else { - @for (processor of processors(); track processor; let i = $index) { -
- -
+ + @for (processorType of schemaService.processorTypes; track processorType) { + } - } -
+ + } +
Processors
-
-
- @if (schemaService.moduleTypes.length > 0) { -
- add -
- - @for (processorType of schemaService.processorTypes; track processorType) { - + @if (processors() !== undefined && processors()!.length > 0) { +
+ @for (processor of processors(); track processor; let i = $index) { +
+ +
} - - } +
+ }
+ @if (schemaService.processorTypes.length > 0) { diff --git a/src/app/route/route.component.ts b/src/app/route/route.component.ts index c863de6..bf70e47 100644 --- a/src/app/route/route.component.ts +++ b/src/app/route/route.component.ts @@ -8,6 +8,7 @@ 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', @@ -18,12 +19,24 @@ import { MatSnackBar } from '@angular/material/snack-bar'; MatMenuModule, JsonPipe, ProcessorComponent, + MatTooltipModule, ], templateUrl: './route.component.html', styleUrl: './route.component.css', }) export class RouteComponent { path = input(''); + + 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(); moduleIds = input([]); delete = output(); @@ -85,6 +98,9 @@ export class RouteComponent { } return route; }); + this.snackBar.open('Processor Added', 'Dismiss', { + duration: 3000, + }); } processorUpdated(index: number, processor: ProcessorConfiguration | undefined) { diff --git a/src/services/schema.service.ts b/src/services/schema.service.ts index df9c0d8..9f1dda6 100644 --- a/src/services/schema.service.ts +++ b/src/services/schema.service.ts @@ -225,12 +225,12 @@ export class SchemaService { .filter((definition) => definition.properties?.type?.const !== undefined) .map((definition) => { return { - name: definition['title'], + name: definition['title'] || definition.properties?.type?.const, type: definition.properties?.type?.const, schema: definition, }; }), - ['name'], + ['type'], ); } } @@ -247,12 +247,12 @@ export class SchemaService { .filter((definition) => definition.properties?.type?.const !== undefined) .map((definition) => { return { - name: definition['title'], + name: definition['title'] || definition.properties?.type?.const, type: definition.properties?.type?.const, schema: definition, }; }), - ['name'], + ['type'], ); } }