From fb0c4a78f9c2fc456994611b98c56edae527909f Mon Sep 17 00:00:00 2001 From: Andrei Timar Date: Sun, 21 Jun 2026 19:20:26 +0300 Subject: [PATCH 1/2] feat(UI): add the possibility to add top nav bar and side panel routing UI plugins --- ScriptBeeClient/federation.config.js | 2 +- ScriptBeeClient/package-lock.json | 6 +- ScriptBeeClient/package.json | 2 +- ScriptBeeClient/src/app/app.component.html | 4 + ScriptBeeClient/src/app/app.component.ts | 5 + ScriptBeeClient/src/app/app.config.ts | 4 +- .../project-side-nav-list.component.html | 2 +- .../project-side-nav-list.component.ts | 96 ++++++++++-------- .../plugin/gateway-plugins.service.ts | 97 +++++++++++++++++++ ScriptBeeClient/src/app/types/plugin.ts | 40 ++++++-- 10 files changed, 199 insertions(+), 59 deletions(-) create mode 100644 ScriptBeeClient/src/app/services/plugin/gateway-plugins.service.ts diff --git a/ScriptBeeClient/federation.config.js b/ScriptBeeClient/federation.config.js index 1b20b291..82749737 100644 --- a/ScriptBeeClient/federation.config.js +++ b/ScriptBeeClient/federation.config.js @@ -4,7 +4,7 @@ module.exports = withNativeFederation({ name: 'ScriptBeeUI', shared: { - ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }), + ...shareAll({ singleton: true, strictVersion: false, requiredVersion: 'auto' }), }, skip: ['@angular-architects/native-federation', 'es-module-shims', 'monaco-editor', 'rxjs/ajax', 'rxjs/fetch', 'rxjs/testing', 'rxjs/webSocket'], diff --git a/ScriptBeeClient/package-lock.json b/ScriptBeeClient/package-lock.json index 19167b1b..31643177 100644 --- a/ScriptBeeClient/package-lock.json +++ b/ScriptBeeClient/package-lock.json @@ -22,7 +22,6 @@ "@microsoft/signalr": "^10.0.0", "angular-split": "^20.0.0", "cytoscape": "^3.34.0", - "es-module-shims": "^2.8.1", "monaco-editor": "^0.55.1", "ngx-monaco-editor-v2": "^21.1.4", "rxjs": "~7.8.2", @@ -36,6 +35,7 @@ "@angular/compiler-cli": "^21.2.12", "@vitest/browser-playwright": "^4.1.9", "angular-eslint": "21.3.1", + "es-module-shims": "^2.8.1", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.6", @@ -10402,7 +10402,9 @@ "node_modules/es-module-shims": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-2.8.1.tgz", - "integrity": "sha512-Ztg5TxFCT/ffzmSf/ginHIvSbsneH60X9tpaMBD/jWXHQZT1JJNj8tOO3mRmUT3ar7Qn3YK4EbM1SjJpN5dPBA==" + "integrity": "sha512-Ztg5TxFCT/ffzmSf/ginHIvSbsneH60X9tpaMBD/jWXHQZT1JJNj8tOO3mRmUT3ar7Qn3YK4EbM1SjJpN5dPBA==", + "dev": true, + "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.2", diff --git a/ScriptBeeClient/package.json b/ScriptBeeClient/package.json index 86889ff1..13cefed0 100644 --- a/ScriptBeeClient/package.json +++ b/ScriptBeeClient/package.json @@ -29,7 +29,6 @@ "@microsoft/signalr": "^10.0.0", "angular-split": "^20.0.0", "cytoscape": "^3.34.0", - "es-module-shims": "^2.8.1", "monaco-editor": "^0.55.1", "ngx-monaco-editor-v2": "^21.1.4", "rxjs": "~7.8.2", @@ -37,6 +36,7 @@ }, "devDependencies": { "@angular-architects/native-federation": "^21.2.3", + "es-module-shims": "^2.8.1", "@angular-devkit/build-angular": "^21.2.10", "@angular/build": "^21.2.10", "@angular/cli": "^21.2.10", diff --git a/ScriptBeeClient/src/app/app.component.html b/ScriptBeeClient/src/app/app.component.html index effc0e62..61039bcb 100644 --- a/ScriptBeeClient/src/app/app.component.html +++ b/ScriptBeeClient/src/app/app.component.html @@ -13,6 +13,10 @@ + @for (element of navBarsElements(); track element.path) { + + } + @if (projectState.currentProjectId()) { diff --git a/ScriptBeeClient/src/app/app.component.ts b/ScriptBeeClient/src/app/app.component.ts index 5e9512e1..1819372f 100644 --- a/ScriptBeeClient/src/app/app.component.ts +++ b/ScriptBeeClient/src/app/app.component.ts @@ -10,6 +10,7 @@ import { MatToolbar } from '@angular/material/toolbar'; import { ProjectStateService } from './services/projects/project-state.service'; import { ProjectSideNavListComponent } from './components/navigation/project-side-nav-list/project-side-nav-list.component'; import { ThemeService } from './services/common/theme.service'; +import { GatewayPluginsService } from './services/plugin/gateway-plugins.service'; @Component({ selector: 'app-root', @@ -31,9 +32,13 @@ import { ThemeService } from './services/common/theme.service'; export class AppComponent { private matIconRegistry = inject(MatIconRegistry); private domSanitizer = inject(DomSanitizer); + private gatewayPluginsService = inject(GatewayPluginsService); + themeService = inject(ThemeService); projectState = inject(ProjectStateService); + navBarsElements = this.gatewayPluginsService.topNavigationBarOutlets; + isMenuOpen = signal(localStorage.getItem('isMenuOpen') === 'true'); shouldDisplayMenuHamburger = computed(() => { diff --git a/ScriptBeeClient/src/app/app.config.ts b/ScriptBeeClient/src/app/app.config.ts index 1d788317..b5898faa 100644 --- a/ScriptBeeClient/src/app/app.config.ts +++ b/ScriptBeeClient/src/app/app.config.ts @@ -1,13 +1,15 @@ -import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core'; +import { ApplicationConfig, inject, provideAppInitializer, provideZonelessChangeDetection } from '@angular/core'; import { provideRouter, withComponentInputBinding } from '@angular/router'; import { routes, withErrorNavigation } from './app.routes'; import { provideHttpClient, withInterceptors, withXsrfConfiguration } from '@angular/common/http'; import { provideMonacoEditor } from 'ngx-monaco-editor-v2'; import { clientIdInterceptor } from './utils/client-id.interceptor'; +import { GatewayPluginsService } from './services/plugin/gateway-plugins.service'; export const appConfig: ApplicationConfig = { providers: [ provideZonelessChangeDetection(), + provideAppInitializer(() => inject(GatewayPluginsService).fetchUIPlugins()), provideRouter(routes, withComponentInputBinding(), withErrorNavigation), provideHttpClient( withInterceptors([clientIdInterceptor]), diff --git a/ScriptBeeClient/src/app/components/navigation/project-side-nav-list/project-side-nav-list.component.html b/ScriptBeeClient/src/app/components/navigation/project-side-nav-list/project-side-nav-list.component.html index 976c0cdf..9ac9ba96 100644 --- a/ScriptBeeClient/src/app/components/navigation/project-side-nav-list/project-side-nav-list.component.html +++ b/ScriptBeeClient/src/app/components/navigation/project-side-nav-list/project-side-nav-list.component.html @@ -1 +1 @@ - + diff --git a/ScriptBeeClient/src/app/components/navigation/project-side-nav-list/project-side-nav-list.component.ts b/ScriptBeeClient/src/app/components/navigation/project-side-nav-list/project-side-nav-list.component.ts index f7054402..aae8a9aa 100644 --- a/ScriptBeeClient/src/app/components/navigation/project-side-nav-list/project-side-nav-list.component.ts +++ b/ScriptBeeClient/src/app/components/navigation/project-side-nav-list/project-side-nav-list.component.ts @@ -1,6 +1,7 @@ -import { Component, computed, input } from '@angular/core'; +import { Component, computed, inject, input } from '@angular/core'; import { SideNavListComponent } from '../side-nav-list/side-nav-list.component'; import { NavItem } from '../navItem'; +import { GatewayPluginsService } from '../../../services/plugin/gateway-plugins.service'; @Component({ selector: 'app-project-side-nav-list', @@ -12,47 +13,56 @@ export class ProjectSideNavListComponent { isCollapsed = input.required(); projectId = input.required(); - linkPrefix = computed(() => { - return `/projects/${this.projectId()}`; - }); + linkPrefix = computed(() => `/projects/${this.projectId()}`); + navItems = computed(() => [...defaultNavItems, ...this.pluginNavItems()]); - navItems: NavItem[] = [ - { - link: '/model', - name: 'Model', - icon: 'model_training', - children: [ - { - link: '/upload', - name: 'Upload', - icon: 'upload', - }, - { - link: '/load', - name: 'Load', - icon: 'autorenew', - }, - { - link: '/context', - name: 'Context', - icon: 'account_tree', - }, - ], - }, - { - link: '/analysis', - name: 'Analysis', - icon: 'query_stats', - }, - { - link: '/settings', - name: 'Settings', - icon: 'settings', - }, - { - link: '/plugins', - name: 'Plugins', - icon: 'extension', - }, - ]; + private gatewayPluginsService = inject(GatewayPluginsService); + + private pluginNavItems = computed(() => + this.gatewayPluginsService.sidePanelOutlets().map((outlet) => ({ + link: outlet.path, + name: outlet.label, + icon: outlet.icon, + })) + ); } + +const defaultNavItems: NavItem[] = [ + { + link: '/model', + name: 'Model', + icon: 'model_training', + children: [ + { + link: '/upload', + name: 'Upload', + icon: 'upload', + }, + { + link: '/load', + name: 'Load', + icon: 'autorenew', + }, + { + link: '/context', + name: 'Context', + icon: 'account_tree', + }, + ], + }, + { + link: '/analysis', + name: 'Analysis', + icon: 'query_stats', + }, + { + link: '/settings', + name: 'Settings', + icon: 'settings', + }, + { + link: '/plugins', + name: 'Plugins', + icon: 'extension', + }, +]; diff --git a/ScriptBeeClient/src/app/services/plugin/gateway-plugins.service.ts b/ScriptBeeClient/src/app/services/plugin/gateway-plugins.service.ts new file mode 100644 index 00000000..6b982958 --- /dev/null +++ b/ScriptBeeClient/src/app/services/plugin/gateway-plugins.service.ts @@ -0,0 +1,97 @@ +import { computed, inject, Injectable, signal } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { catchError, map, Observable } from 'rxjs'; +import { + Plugin, + RoutingExtensionPointOutlet, + SidePanelExtensionPointOutlet, + TopNavigationBarExtensionPointOutlet, + UIExtensionPointOutlet, +} from '../../types/plugin'; +import { WebResponse } from '../../types/web-response'; +import { Router, Routes } from '@angular/router'; +import { loadRemoteModule } from '@angular-architects/native-federation'; + +@Injectable({ + providedIn: 'root', +}) +export class GatewayPluginsService { + private http = inject(HttpClient); + private router = inject(Router); + + private uiPlugins = signal([]); + + public topNavigationBarOutlets = computed(() => this.getOutlets(this.uiPlugins(), 'top-navigation-bar')); + public sidePanelOutlets = computed(() => this.getOutlets(this.uiPlugins(), 'side-panel')); + + public fetchUIPlugins(): Observable { + return this.http.get>('/api/plugins/gateway', { params: { kind: 'UI' } }).pipe( + map((response) => { + const plugins = response.data; + this.uiPlugins.set(plugins); + this.updateRoutes(plugins); + }), + catchError((err) => { + console.log('Failed to fetch UI plugins', err); + return []; + }) + ); + } + private updateRoutes(plugins: Plugin[]) { + const topBarRoutes = this.buildRoutesFromPlugins(plugins, 'top-navigation-bar'); + const sidePanelRoutes = this.buildRoutesFromPlugins(plugins, 'side-panel'); + + const updatedProjectRoutesWithPluginSidePanelRoutes = this.router.config.map((route) => { + if (route.path === 'projects/:id') { + return { + ...route, + children: [...sidePanelRoutes, ...(route.children ?? [])], + }; + } + return route; + }); + + this.router.resetConfig([...topBarRoutes, ...updatedProjectRoutesWithPluginSidePanelRoutes]); + } + + private buildRoutesFromPlugins(plugins: Plugin[], type: UIExtensionPointOutlet['type']): Routes { + return plugins.flatMap((plugin) => + plugin.extensionPoints + .filter((ep) => ep.kind === 'UI') + .flatMap((extensionPoint) => { + const pluginRoutes: Routes = extensionPoint.outlets + .filter((outlet) => outlet.type === type) + .map((outlet) => { + return this.buildRouteFromPlugin(extensionPoint.remoteName, outlet); + }); + + return pluginRoutes; + }) + ); + } + + private buildRouteFromPlugin(remoteName: string, outlet: RoutingExtensionPointOutlet) { + if (outlet.nested) { + return { + path: outlet.path.replace(/^\//, ''), + loadChildren: () => + loadRemoteModule(remoteName, outlet.exposedModule).then((m) => { + const exposedRouteName = outlet.exposedModule.replace(/^\.\//, ''); + return m[exposedRouteName]; + }), + }; + } + return { + path: outlet.path.replace(/^\//, ''), + loadComponent: () => loadRemoteModule(remoteName, outlet.exposedModule).then((m) => m[outlet.componentName ?? 'App']), + }; + } + + private getOutlets(plugins: Plugin[], type: T): Extract[] { + return plugins + .flatMap((plugin) => plugin.extensionPoints) + .filter((extensionPoint) => extensionPoint.kind === 'UI') + .flatMap((extensionPoint) => extensionPoint.outlets) + .filter((outlet): outlet is Extract => outlet.type === type); + } +} diff --git a/ScriptBeeClient/src/app/types/plugin.ts b/ScriptBeeClient/src/app/types/plugin.ts index 329b7ccc..ee379583 100644 --- a/ScriptBeeClient/src/app/types/plugin.ts +++ b/ScriptBeeClient/src/app/types/plugin.ts @@ -8,6 +8,14 @@ export interface Plugin { extensionPoints: ExtensionPoint[]; } +type ExtensionPoint = + | HelperFunctionsExtensionPoint + | ScriptGeneratorExtensionPoint + | ScriptRunnerExtensionPoint + | LoaderExtensionPoint + | LinkerExtensionPoint + | UIExtensionPoint; + interface BasicExtensionPoint { kind: PluginKind; entryPoint: string; @@ -39,17 +47,29 @@ interface LinkerExtensionPoint extends BasicExtensionPoint { interface UIExtensionPoint extends BasicExtensionPoint { kind: 'UI'; - port: number; + remoteName: string; remoteEntry: string; + outlets: UIExtensionPointOutlet[]; +} + +export type UIExtensionPointOutlet = TopNavigationBarExtensionPointOutlet | SidePanelExtensionPointOutlet; + +interface BaseUIExtensionPointOutlet { + type: string; +} +export interface RoutingExtensionPointOutlet extends BaseUIExtensionPointOutlet { exposedModule: string; - componentName: string; - uiPluginType: string; + label: string; + path: string; + nested: boolean | undefined; + componentName: string | undefined; } -type ExtensionPoint = - | HelperFunctionsExtensionPoint - | ScriptGeneratorExtensionPoint - | ScriptRunnerExtensionPoint - | LoaderExtensionPoint - | LinkerExtensionPoint - | UIExtensionPoint; +export interface TopNavigationBarExtensionPointOutlet extends RoutingExtensionPointOutlet { + type: 'top-navigation-bar'; +} + +export interface SidePanelExtensionPointOutlet extends RoutingExtensionPointOutlet { + type: 'side-panel'; + icon: string; +} From 0d962d89673b1f666dd6643c36e686b289531501 Mon Sep 17 00:00:00 2001 From: Andrei Timar Date: Sun, 21 Jun 2026 19:27:05 +0300 Subject: [PATCH 2/2] chore(UI): add eslint js as dev dependency --- ScriptBeeClient/package-lock.json | 328 ++++++++++++++++++++++++------ ScriptBeeClient/package.json | 7 +- 2 files changed, 270 insertions(+), 65 deletions(-) diff --git a/ScriptBeeClient/package-lock.json b/ScriptBeeClient/package-lock.json index 31643177..dbb774db 100644 --- a/ScriptBeeClient/package-lock.json +++ b/ScriptBeeClient/package-lock.json @@ -33,10 +33,11 @@ "@angular/build": "^21.2.10", "@angular/cli": "^21.2.10", "@angular/compiler-cli": "^21.2.12", + "@eslint/js": "^10.0.1", "@vitest/browser-playwright": "^4.1.9", "angular-eslint": "21.3.1", "es-module-shims": "^2.8.1", - "eslint": "^10.5.0", + "eslint": "^10.0.3", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-unused-imports": "^4.4.1", @@ -44,7 +45,7 @@ "prettier": "^3.8.4", "prettier-eslint": "^17.1.1", "typescript": "~5.9.3", - "typescript-eslint": "8.61.1", + "typescript-eslint": "8.56.1", "vitest": "^4.1.9" } }, @@ -4389,6 +4390,27 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, + "node_modules/@eslint/js": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-10.0.1.tgz", + "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "eslint": "^10.0.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, "node_modules/@eslint/object-schema": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", @@ -8171,34 +8193,6 @@ "@types/node": "*" } }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.1.tgz", - "integrity": "sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.61.1", - "@typescript-eslint/type-utils": "8.61.1", - "@typescript-eslint/utils": "8.61.1", - "@typescript-eslint/visitor-keys": "8.61.1", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.61.1", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/parser": { "version": "8.61.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.1.tgz", @@ -8277,30 +8271,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.1.tgz", - "integrity": "sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "8.61.1", - "@typescript-eslint/typescript-estree": "8.61.1", - "@typescript-eslint/utils": "8.61.1", - "debug": "^4.4.3", - "ts-api-utils": "^2.5.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/types": { "version": "8.61.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.1.tgz", @@ -16358,15 +16328,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.61.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.1.tgz", - "integrity": "sha512-V7PayAfJokV3pEHgN7/v03D1SpujhRfQtYLbLIiBfDDncdg4PAiRBfoS4cnCANK4jmAPncczi59QO3afiXUlNw==", + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.56.1.tgz", + "integrity": "sha512-U4lM6pjmBX7J5wk4szltF7I1cGBHXZopnAXCMXb3+fZ3B/0Z3hq3wS/CCUB2NZBNAExK92mCU2tEohWuwVMsDQ==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.61.1", - "@typescript-eslint/parser": "8.61.1", - "@typescript-eslint/typescript-estree": "8.61.1", - "@typescript-eslint/utils": "8.61.1" + "@typescript-eslint/eslint-plugin": "8.56.1", + "@typescript-eslint/parser": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -16377,7 +16348,240 @@ }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.1.0" + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.1.tgz", + "integrity": "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/type-utils": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/project-service": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.1.tgz", + "integrity": "sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/utils": "8.56.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.1.tgz", + "integrity": "sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/undici": { diff --git a/ScriptBeeClient/package.json b/ScriptBeeClient/package.json index 13cefed0..16bf0d54 100644 --- a/ScriptBeeClient/package.json +++ b/ScriptBeeClient/package.json @@ -36,14 +36,15 @@ }, "devDependencies": { "@angular-architects/native-federation": "^21.2.3", - "es-module-shims": "^2.8.1", "@angular-devkit/build-angular": "^21.2.10", "@angular/build": "^21.2.10", "@angular/cli": "^21.2.10", "@angular/compiler-cli": "^21.2.12", + "@eslint/js": "^10.0.1", "@vitest/browser-playwright": "^4.1.9", "angular-eslint": "21.3.1", - "eslint": "^10.5.0", + "es-module-shims": "^2.8.1", + "eslint": "^10.0.3", "eslint-config-prettier": "^10.1.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-unused-imports": "^4.4.1", @@ -51,7 +52,7 @@ "prettier": "^3.8.4", "prettier-eslint": "^17.1.1", "typescript": "~5.9.3", - "typescript-eslint": "8.61.1", + "typescript-eslint": "8.56.1", "vitest": "^4.1.9" } }