From 7ec82f5f7836fa0f92583c6263c8eba968ceeb82 Mon Sep 17 00:00:00 2001 From: Martin Ligtenberg Date: Wed, 25 Dec 2024 14:14:07 +0100 Subject: [PATCH] Added initial form for adding connections --- .../src/app/app.routes.ts | 12 ++- .../src/styles.scss | 10 ++ libs/connections/flow/README.md | 7 ++ libs/connections/flow/eslint.config.js | 34 +++++++ libs/connections/flow/jest.config.ts | 21 ++++ libs/connections/flow/project.json | 20 ++++ libs/connections/flow/src/index.ts | 17 ++++ .../src/lib/add-connection.component.html | 38 +++++++ .../src/lib/add-connection.component.scss | 33 +++++++ .../src/lib/add-connection.component.spec.ts | 21 ++++ .../flow/src/lib/add-connection.component.ts | 98 +++++++++++++++++++ libs/connections/flow/src/test-setup.ts | 6 ++ libs/connections/flow/tsconfig.json | 28 ++++++ libs/connections/flow/tsconfig.lib.json | 17 ++++ libs/connections/flow/tsconfig.spec.json | 16 +++ libs/connections/store/README.md | 7 ++ libs/connections/store/eslint.config.js | 34 +++++++ libs/connections/store/jest.config.ts | 21 ++++ libs/connections/store/project.json | 20 ++++ libs/connections/store/src/index.ts | 18 ++++ .../store/src/lib/connections.actions.ts | 17 ++++ .../store/src/lib/connections.effects.ts | 33 +++++++ .../src/lib/connections.internal-actions.ts | 12 +++ .../store/src/lib/connections.selectors.ts | 21 ++++ .../store/src/lib/connections.store.ts | 23 +++++ libs/connections/store/src/test-setup.ts | 6 ++ libs/connections/store/tsconfig.json | 28 ++++++ libs/connections/store/tsconfig.lib.json | 17 ++++ libs/connections/store/tsconfig.spec.json | 16 +++ .../clients/src/lib/administration-client.ts | 8 ++ .../clients/src/lib/connection-manager.ts | 11 ++- .../contracts/src/lib/connection.ts | 5 +- .../src/lib/service-bus-electron-client.ts | 4 + .../server/src/lib/service-bus-server.ts | 8 +- libs/shared/contracts/README.md | 7 ++ libs/shared/contracts/eslint.config.js | 3 + libs/shared/contracts/jest.config.ts | 10 ++ libs/shared/contracts/package.json | 6 ++ libs/shared/contracts/project.json | 16 +++ libs/shared/contracts/src/index.ts | 1 + libs/shared/contracts/src/lib/uuid.ts | 1 + libs/shared/contracts/tsconfig.json | 22 +++++ libs/shared/contracts/tsconfig.lib.json | 10 ++ libs/shared/contracts/tsconfig.spec.json | 15 +++ tsconfig.base.json | 9 ++ 45 files changed, 782 insertions(+), 5 deletions(-) create mode 100644 libs/connections/flow/README.md create mode 100644 libs/connections/flow/eslint.config.js create mode 100644 libs/connections/flow/jest.config.ts create mode 100644 libs/connections/flow/project.json create mode 100644 libs/connections/flow/src/index.ts create mode 100644 libs/connections/flow/src/lib/add-connection.component.html create mode 100644 libs/connections/flow/src/lib/add-connection.component.scss create mode 100644 libs/connections/flow/src/lib/add-connection.component.spec.ts create mode 100644 libs/connections/flow/src/lib/add-connection.component.ts create mode 100644 libs/connections/flow/src/test-setup.ts create mode 100644 libs/connections/flow/tsconfig.json create mode 100644 libs/connections/flow/tsconfig.lib.json create mode 100644 libs/connections/flow/tsconfig.spec.json create mode 100644 libs/connections/store/README.md create mode 100644 libs/connections/store/eslint.config.js create mode 100644 libs/connections/store/jest.config.ts create mode 100644 libs/connections/store/project.json create mode 100644 libs/connections/store/src/index.ts create mode 100644 libs/connections/store/src/lib/connections.actions.ts create mode 100644 libs/connections/store/src/lib/connections.effects.ts create mode 100644 libs/connections/store/src/lib/connections.internal-actions.ts create mode 100644 libs/connections/store/src/lib/connections.selectors.ts create mode 100644 libs/connections/store/src/lib/connections.store.ts create mode 100644 libs/connections/store/src/test-setup.ts create mode 100644 libs/connections/store/tsconfig.json create mode 100644 libs/connections/store/tsconfig.lib.json create mode 100644 libs/connections/store/tsconfig.spec.json create mode 100644 libs/shared/contracts/README.md create mode 100644 libs/shared/contracts/eslint.config.js create mode 100644 libs/shared/contracts/jest.config.ts create mode 100644 libs/shared/contracts/package.json create mode 100644 libs/shared/contracts/project.json create mode 100644 libs/shared/contracts/src/index.ts create mode 100644 libs/shared/contracts/src/lib/uuid.ts create mode 100644 libs/shared/contracts/tsconfig.json create mode 100644 libs/shared/contracts/tsconfig.lib.json create mode 100644 libs/shared/contracts/tsconfig.spec.json diff --git a/apps/servicebus-browser-frontend/src/app/app.routes.ts b/apps/servicebus-browser-frontend/src/app/app.routes.ts index 8762dfe..078c62e 100644 --- a/apps/servicebus-browser-frontend/src/app/app.routes.ts +++ b/apps/servicebus-browser-frontend/src/app/app.routes.ts @@ -1,3 +1,13 @@ import { Route } from '@angular/router'; -export const appRoutes: Route[] = []; +export const appRoutes: Route[] = [ + { + path: 'connections', + loadChildren: () => import('@service-bus-browser/connections-flow').then(m => m.connectionsRoutes) + }, + { + path: '', + redirectTo: 'connections', + pathMatch: 'full' + } +]; diff --git a/apps/servicebus-browser-frontend/src/styles.scss b/apps/servicebus-browser-frontend/src/styles.scss index 1a1863f..a97cdef 100644 --- a/apps/servicebus-browser-frontend/src/styles.scss +++ b/apps/servicebus-browser-frontend/src/styles.scss @@ -4,4 +4,14 @@ head, body { font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; margin: 0; padding: 0; + user-select: none; }/* You can add global styles to this file, and also import other style files */ + +.page-container { + padding: 1rem; +} + +.page-title { + font-size: 1.3rem; + margin: 0 0 0.5rem 0; +} diff --git a/libs/connections/flow/README.md b/libs/connections/flow/README.md new file mode 100644 index 0000000..5be374f --- /dev/null +++ b/libs/connections/flow/README.md @@ -0,0 +1,7 @@ +# @service-bus-browser/connections-flow + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test @service-bus-browser/connections-flow` to execute the unit tests. diff --git a/libs/connections/flow/eslint.config.js b/libs/connections/flow/eslint.config.js new file mode 100644 index 0000000..d36ea77 --- /dev/null +++ b/libs/connections/flow/eslint.config.js @@ -0,0 +1,34 @@ +const nx = require('@nx/eslint-plugin'); +const baseConfig = require('../../../eslint.config.js'); + +module.exports = [ + ...baseConfig, + ...nx.configs['flat/angular'], + ...nx.configs['flat/angular-template'], + { + files: ['**/*.ts'], + rules: { + '@angular-eslint/directive-selector': [ + 'error', + { + type: 'attribute', + prefix: 'lib', + style: 'camelCase', + }, + ], + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: 'lib', + style: 'kebab-case', + }, + ], + }, + }, + { + files: ['**/*.html'], + // Override or add rules here + rules: {}, + }, +]; diff --git a/libs/connections/flow/jest.config.ts b/libs/connections/flow/jest.config.ts new file mode 100644 index 0000000..9273b50 --- /dev/null +++ b/libs/connections/flow/jest.config.ts @@ -0,0 +1,21 @@ +export default { + displayName: '@service-bus-browser/connections-flow', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/libs/connections/flow', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/libs/connections/flow/project.json b/libs/connections/flow/project.json new file mode 100644 index 0000000..72ec450 --- /dev/null +++ b/libs/connections/flow/project.json @@ -0,0 +1,20 @@ +{ + "name": "@service-bus-browser/connections-flow", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/connections/flow/src", + "prefix": "lib", + "projectType": "library", + "tags": [], + "targets": { + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/connections/flow/jest.config.ts" + } + }, + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/connections/flow/src/index.ts b/libs/connections/flow/src/index.ts new file mode 100644 index 0000000..f37e420 --- /dev/null +++ b/libs/connections/flow/src/index.ts @@ -0,0 +1,17 @@ +import { Routes } from '@angular/router'; +import { provideConnectionsState } from '@service-bus-browser/connections-store'; + +export const connectionsRoutes: Routes = [ + { + path: 'add', + loadComponent: () => import('./lib/add-connection.component').then(m => m.AddConnectionComponent), + providers: [ + provideConnectionsState() + ] + }, + { + path: '', + redirectTo: 'add', + pathMatch: 'full' + } +] diff --git a/libs/connections/flow/src/lib/add-connection.component.html b/libs/connections/flow/src/lib/add-connection.component.html new file mode 100644 index 0000000..deccda1 --- /dev/null +++ b/libs/connections/flow/src/lib/add-connection.component.html @@ -0,0 +1,38 @@ +
+

Add connection

+
+
+ + + + +
+
+ +
+ + +
+
+ @if (connectionType() === 'connectionString') { +
+ + + + +
+ } + + +
+ + + +
+
+
diff --git a/libs/connections/flow/src/lib/add-connection.component.scss b/libs/connections/flow/src/lib/add-connection.component.scss new file mode 100644 index 0000000..89c819f --- /dev/null +++ b/libs/connections/flow/src/lib/add-connection.component.scss @@ -0,0 +1,33 @@ +:host{ + display: block; + width: 100%; +} + +.connection-type-option > * { + margin: 0 0 0 0.5em; +} + +.heading { + font-size: 0.7rem; + font-weight: normal; + margin: 0 0 1rem 1rem; + color: var(--p-floatlabel-active-color); +} + +section { + margin: 0 0 1rem 0; +} + +.full-width { + width: 100%; +} + +.actions { + display: flex; + justify-content: flex-end; + margin: 1rem 0 0 0; + + button { + margin: 0 0 0 0.5rem; + } +} diff --git a/libs/connections/flow/src/lib/add-connection.component.spec.ts b/libs/connections/flow/src/lib/add-connection.component.spec.ts new file mode 100644 index 0000000..dd54445 --- /dev/null +++ b/libs/connections/flow/src/lib/add-connection.component.spec.ts @@ -0,0 +1,21 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { AddConnectionComponent } from './add-connection.component'; + +describe('AddConnectionComponent', () => { + let component: AddConnectionComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AddConnectionComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(AddConnectionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/libs/connections/flow/src/lib/add-connection.component.ts b/libs/connections/flow/src/lib/add-connection.component.ts new file mode 100644 index 0000000..cb4e7cc --- /dev/null +++ b/libs/connections/flow/src/lib/add-connection.component.ts @@ -0,0 +1,98 @@ +import { Component, computed, effect, inject, model } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RadioButton } from 'primeng/radiobutton'; +import { FloatLabel } from 'primeng/floatlabel'; +import { InputText } from 'primeng/inputtext'; +import { FormsModule } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { ConnectionsActions } from '@service-bus-browser/connections-store'; +import { ButtonDirective } from 'primeng/button'; +import { Connection } from '@service-bus-browser/service-bus-contracts'; + +@Component({ + selector: 'lib-add-connection', + imports: [ + CommonModule, + RadioButton, + FloatLabel, + InputText, + FormsModule, + ButtonDirective, + ], + templateUrl: './add-connection.component.html', + styleUrl: './add-connection.component.scss', +}) +export class AddConnectionComponent { + store = inject(Store); + + connectionName = model(); + connectionType = model<'connectionString'>('connectionString'); + connectionString = model(); + + connection = computed(() => { + const connectionType = this.connectionType(); + const name = this.connectionName(); + if (connectionType === undefined || name === undefined) { + return undefined; + } + + if (connectionType === 'connectionString') { + const connectionString = this.connectionString(); + + return !connectionString ? undefined : { + id: crypto.randomUUID(), + name: name, + connectionString: connectionString, + type: 'connectionString', + }; + } + + return undefined; + }); + + canSave = computed(() => { + return this.connection() !== undefined; + }); + + constructor() { + effect(() => { + const connectionType = this.connectionType(); + if (connectionType !== 'connectionString') { + this.connectionString.set(undefined); + return; + } + + const connectionString = this.connectionString(); + if (!this.connectionName() && !!connectionString) { + const capture = /.*Endpoint=sb:\/\/([a-z1-9-.]*)\/?;.*/i.exec(connectionString); + if (capture?.[1]) { + this.connectionName.set(capture[1]); + } + } + }); + } + + testConnection() { + const connection = this.connection(); + if (!connection) { + return; + } + + this.store.dispatch(ConnectionsActions.checkConnection({ + connection + })) + } + + save() { + const connection = this.connection(); + if (!connection) { + return; + } + + this.store.dispatch( + ConnectionsActions.addConnection({ + connection: connection + }) + ); + } +} diff --git a/libs/connections/flow/src/test-setup.ts b/libs/connections/flow/src/test-setup.ts new file mode 100644 index 0000000..ea41401 --- /dev/null +++ b/libs/connections/flow/src/test-setup.ts @@ -0,0 +1,6 @@ +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; + +setupZoneTestEnv({ + errorOnUnknownElements: true, + errorOnUnknownProperties: true, +}); diff --git a/libs/connections/flow/tsconfig.json b/libs/connections/flow/tsconfig.json new file mode 100644 index 0000000..fde35ea --- /dev/null +++ b/libs/connections/flow/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "es2022", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/libs/connections/flow/tsconfig.lib.json b/libs/connections/flow/tsconfig.lib.json new file mode 100644 index 0000000..9b49be7 --- /dev/null +++ b/libs/connections/flow/tsconfig.lib.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "src/**/*.spec.ts", + "src/test-setup.ts", + "jest.config.ts", + "src/**/*.test.ts" + ], + "include": ["src/**/*.ts"] +} diff --git a/libs/connections/flow/tsconfig.spec.json b/libs/connections/flow/tsconfig.spec.json new file mode 100644 index 0000000..f858ef7 --- /dev/null +++ b/libs/connections/flow/tsconfig.spec.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "target": "es2016", + "types": ["jest", "node"] + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/libs/connections/store/README.md b/libs/connections/store/README.md new file mode 100644 index 0000000..462a06c --- /dev/null +++ b/libs/connections/store/README.md @@ -0,0 +1,7 @@ +# @service-bus-browser/connections-store + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test @service-bus-browser/connections-store` to execute the unit tests. diff --git a/libs/connections/store/eslint.config.js b/libs/connections/store/eslint.config.js new file mode 100644 index 0000000..d36ea77 --- /dev/null +++ b/libs/connections/store/eslint.config.js @@ -0,0 +1,34 @@ +const nx = require('@nx/eslint-plugin'); +const baseConfig = require('../../../eslint.config.js'); + +module.exports = [ + ...baseConfig, + ...nx.configs['flat/angular'], + ...nx.configs['flat/angular-template'], + { + files: ['**/*.ts'], + rules: { + '@angular-eslint/directive-selector': [ + 'error', + { + type: 'attribute', + prefix: 'lib', + style: 'camelCase', + }, + ], + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: 'lib', + style: 'kebab-case', + }, + ], + }, + }, + { + files: ['**/*.html'], + // Override or add rules here + rules: {}, + }, +]; diff --git a/libs/connections/store/jest.config.ts b/libs/connections/store/jest.config.ts new file mode 100644 index 0000000..24a97e9 --- /dev/null +++ b/libs/connections/store/jest.config.ts @@ -0,0 +1,21 @@ +export default { + displayName: '@service-bus-browser/connections-store', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['/src/test-setup.ts'], + coverageDirectory: '../../../coverage/libs/connections/store', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/libs/connections/store/project.json b/libs/connections/store/project.json new file mode 100644 index 0000000..3f38edd --- /dev/null +++ b/libs/connections/store/project.json @@ -0,0 +1,20 @@ +{ + "name": "@service-bus-browser/connections-store", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/connections/store/src", + "prefix": "lib", + "projectType": "library", + "tags": [], + "targets": { + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/connections/store/jest.config.ts" + } + }, + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/connections/store/src/index.ts b/libs/connections/store/src/index.ts new file mode 100644 index 0000000..45c8515 --- /dev/null +++ b/libs/connections/store/src/index.ts @@ -0,0 +1,18 @@ +import { EnvironmentProviders, Provider } from '@angular/core'; +import { provideState } from '@ngrx/store'; +import { connectionsFeature } from './lib/connections.store'; +import { provideEffects } from '@ngrx/effects'; +import { ConnectionsEffects } from './lib/connections.effects'; + +export * as ConnectionsActions from './lib/connections.actions'; +export * as ConnectionsSelectors from './lib/connections.selectors'; + +export function provideConnectionsState(): ( + | Provider + | EnvironmentProviders + )[] { + return [ + provideState(connectionsFeature), + provideEffects([ConnectionsEffects]), + ]; +} diff --git a/libs/connections/store/src/lib/connections.actions.ts b/libs/connections/store/src/lib/connections.actions.ts new file mode 100644 index 0000000..293ea6a --- /dev/null +++ b/libs/connections/store/src/lib/connections.actions.ts @@ -0,0 +1,17 @@ +import { createAction, props } from '@ngrx/store'; +import { Connection } from '@service-bus-browser/service-bus-contracts'; + +export const addConnection = createAction( + '[Connections] Add Connection', + props<{ connection: Connection }>() +); + +export const checkConnection = createAction( + '[Connections] Check Connection', + props<{ connection: Connection }>() +); + +export const activateConnection = createAction( + '[Connections] Activate Connection', + props<{ connection: Connection }>() +); diff --git a/libs/connections/store/src/lib/connections.effects.ts b/libs/connections/store/src/lib/connections.effects.ts new file mode 100644 index 0000000..2e0b2f6 --- /dev/null +++ b/libs/connections/store/src/lib/connections.effects.ts @@ -0,0 +1,33 @@ +import { inject, Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import * as actions from './connections.actions'; +import * as internalActions from './connections.internal-actions'; +import { ServiceBusElectronClient } from '@service-bus-browser/service-bus-electron-client'; +import { from, map, switchMap } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class ConnectionsEffects { + actions$ = inject(Actions); + serviceBusClient = inject(ServiceBusElectronClient); + + addConnection$ = createEffect( + () => this.actions$.pipe( + ofType(actions.addConnection), + switchMap(({ connection }) => from(this.serviceBusClient.addConnection(connection)).pipe( + map(() => internalActions.connectionAdded({ connectionId: connection.id })) + )), + ), + ) + + testConnection$ = createEffect( + () => this.actions$.pipe( + ofType(actions.checkConnection), + switchMap(({ connection }) => from(this.serviceBusClient.checkConnection(connection)).pipe( + + )), + ), + { dispatch: false } + ) +} diff --git a/libs/connections/store/src/lib/connections.internal-actions.ts b/libs/connections/store/src/lib/connections.internal-actions.ts new file mode 100644 index 0000000..4c271ab --- /dev/null +++ b/libs/connections/store/src/lib/connections.internal-actions.ts @@ -0,0 +1,12 @@ +import { createAction, props } from '@ngrx/store'; +import { UUID } from '@service-bus-browser/shared-contracts'; + +export const connectionActivated = createAction( + '[Connections] Connection Activated', + props<{ connectionId: string }>() +); + +export const connectionAdded = createAction( + '[Connections] Connection Added', + props<{ connectionId: UUID }>() +); diff --git a/libs/connections/store/src/lib/connections.selectors.ts b/libs/connections/store/src/lib/connections.selectors.ts new file mode 100644 index 0000000..67a4952 --- /dev/null +++ b/libs/connections/store/src/lib/connections.selectors.ts @@ -0,0 +1,21 @@ +import { createFeatureSelector, createSelector } from '@ngrx/store'; +import { ConnectionsState, featureKey } from './connections.store'; + +const featureSelector = createFeatureSelector(featureKey); + + +export const selectAllConnections = createSelector( + featureSelector, + (state) => state.allConnections +) + +export const selectActiveConnections = createSelector( + featureSelector, + (state) => state.activeConnections +) + +export const selectInactiveConnections = createSelector( + selectAllConnections, + selectActiveConnections, + (allConnections, activeConnections) => allConnections.filter(connection => !activeConnections.includes(connection)) +) diff --git a/libs/connections/store/src/lib/connections.store.ts b/libs/connections/store/src/lib/connections.store.ts new file mode 100644 index 0000000..9a94cad --- /dev/null +++ b/libs/connections/store/src/lib/connections.store.ts @@ -0,0 +1,23 @@ +import { createFeature, createReducer, on } from '@ngrx/store'; +import { Connection } from '@service-bus-browser/service-bus-contracts'; + +export const featureKey = 'connections'; + +export type ConnectionsState = { + allConnections: Connection[]; + activeConnections: Connection[]; +} + +export const initialState: ConnectionsState = { + allConnections: [], + activeConnections: [] +}; + +const connectionsReducer = createReducer( + initialState, +); + +export const connectionsFeature = createFeature({ + name: featureKey, + reducer: connectionsReducer +}); diff --git a/libs/connections/store/src/test-setup.ts b/libs/connections/store/src/test-setup.ts new file mode 100644 index 0000000..ea41401 --- /dev/null +++ b/libs/connections/store/src/test-setup.ts @@ -0,0 +1,6 @@ +import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; + +setupZoneTestEnv({ + errorOnUnknownElements: true, + errorOnUnknownProperties: true, +}); diff --git a/libs/connections/store/tsconfig.json b/libs/connections/store/tsconfig.json new file mode 100644 index 0000000..fde35ea --- /dev/null +++ b/libs/connections/store/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "es2022", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "extends": "../../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/libs/connections/store/tsconfig.lib.json b/libs/connections/store/tsconfig.lib.json new file mode 100644 index 0000000..9b49be7 --- /dev/null +++ b/libs/connections/store/tsconfig.lib.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "src/**/*.spec.ts", + "src/test-setup.ts", + "jest.config.ts", + "src/**/*.test.ts" + ], + "include": ["src/**/*.ts"] +} diff --git a/libs/connections/store/tsconfig.spec.json b/libs/connections/store/tsconfig.spec.json new file mode 100644 index 0000000..f858ef7 --- /dev/null +++ b/libs/connections/store/tsconfig.spec.json @@ -0,0 +1,16 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "target": "es2016", + "types": ["jest", "node"] + }, + "files": ["src/test-setup.ts"], + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/libs/service-bus/clients/src/lib/administration-client.ts b/libs/service-bus/clients/src/lib/administration-client.ts index 39505ba..fce0207 100644 --- a/libs/service-bus/clients/src/lib/administration-client.ts +++ b/libs/service-bus/clients/src/lib/administration-client.ts @@ -6,6 +6,14 @@ export class AdministrationClient { constructor(private connection: Connection) { } + async checkConnection(): Promise { + const administrationClient = this.getAdministrationClient(); + const queuesPages = administrationClient.listQueues(); + const queues = await queuesPages.next(); + + return !!queues.value; + } + async getQueues(): Promise { const administrationClient = this.getAdministrationClient(); const queuesPages = administrationClient.listQueues(); diff --git a/libs/service-bus/clients/src/lib/connection-manager.ts b/libs/service-bus/clients/src/lib/connection-manager.ts index aebcf80..f8301f9 100644 --- a/libs/service-bus/clients/src/lib/connection-manager.ts +++ b/libs/service-bus/clients/src/lib/connection-manager.ts @@ -6,10 +6,13 @@ export class ConnectionManager { addConnection(connection: Connection) { this.connections[connection.name] = connection; + console.log(`Connection ${connection.name} added`); } - getConnection(name: string): ConnectionClient { - const connection = this.connections[name]; + getConnectionClient(options: {name: string } | {connection: Connection}): ConnectionClient { + const connection = 'connection' in options + ? options.connection + : this.getConnection(options.name); if (!connection) { throw new Error(`Connection ${name} not found`); @@ -21,4 +24,8 @@ export class ConnectionManager { listConnections(): string[] { return Object.keys(this.connections); } + + private getConnection(name: string): Connection { + return this.connections[name]; + } } diff --git a/libs/service-bus/contracts/src/lib/connection.ts b/libs/service-bus/contracts/src/lib/connection.ts index 7350cb3..5b1d6e6 100644 --- a/libs/service-bus/contracts/src/lib/connection.ts +++ b/libs/service-bus/contracts/src/lib/connection.ts @@ -1,9 +1,12 @@ +import { UUID } from '@service-bus-browser/shared-contracts'; + interface ConnectionBase { + id: UUID; type: string; name: string; } -interface ConnectionStringConnection extends ConnectionBase { +export interface ConnectionStringConnection extends ConnectionBase { type: 'connectionString'; connectionString: string; } diff --git a/libs/service-bus/electron-client/src/lib/service-bus-electron-client.ts b/libs/service-bus/electron-client/src/lib/service-bus-electron-client.ts index 47f297d..2d25a55 100644 --- a/libs/service-bus/electron-client/src/lib/service-bus-electron-client.ts +++ b/libs/service-bus/electron-client/src/lib/service-bus-electron-client.ts @@ -18,4 +18,8 @@ export class ServiceBusElectronClient { await serviceBusApi.doRequest('listConnections', {}); return []; } + + async checkConnection(connection: Connection): Promise { + return await serviceBusApi.doRequest('checkConnection', connection) as boolean; + } } diff --git a/libs/service-bus/server/src/lib/service-bus-server.ts b/libs/service-bus/server/src/lib/service-bus-server.ts index cf19e8f..e734466 100644 --- a/libs/service-bus/server/src/lib/service-bus-server.ts +++ b/libs/service-bus/server/src/lib/service-bus-server.ts @@ -11,7 +11,13 @@ const listConnections = async () => { return connectionManager.listConnections(); }; +const checkConnection = async (connection: Connection) => { + const connectionClient = connectionManager.getConnectionClient({ connection }); + return await connectionClient.getAdministrationClient().checkConnection(); +} + export default { addConnection, - listConnections + listConnections, + checkConnection } diff --git a/libs/shared/contracts/README.md b/libs/shared/contracts/README.md new file mode 100644 index 0000000..474d249 --- /dev/null +++ b/libs/shared/contracts/README.md @@ -0,0 +1,7 @@ +# shared-contracts + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test shared-contracts` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/shared/contracts/eslint.config.js b/libs/shared/contracts/eslint.config.js new file mode 100644 index 0000000..07e518f --- /dev/null +++ b/libs/shared/contracts/eslint.config.js @@ -0,0 +1,3 @@ +const baseConfig = require('../../../eslint.config.js'); + +module.exports = [...baseConfig]; diff --git a/libs/shared/contracts/jest.config.ts b/libs/shared/contracts/jest.config.ts new file mode 100644 index 0000000..25a6969 --- /dev/null +++ b/libs/shared/contracts/jest.config.ts @@ -0,0 +1,10 @@ +export default { + displayName: '@service-bus-browser/shared-contracts', + preset: '../../../jest.preset.js', + testEnvironment: 'node', + transform: { + '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], + }, + moduleFileExtensions: ['ts', 'js', 'html'], + coverageDirectory: '../../../coverage/libs/shared/contracts', +}; diff --git a/libs/shared/contracts/package.json b/libs/shared/contracts/package.json new file mode 100644 index 0000000..ee5b027 --- /dev/null +++ b/libs/shared/contracts/package.json @@ -0,0 +1,6 @@ +{ + "name": "@service-bus-browser/shared-contracts", + "version": "0.0.1", + "dependencies": {}, + "private": true +} diff --git a/libs/shared/contracts/project.json b/libs/shared/contracts/project.json new file mode 100644 index 0000000..594b313 --- /dev/null +++ b/libs/shared/contracts/project.json @@ -0,0 +1,16 @@ +{ + "name": "@service-bus-browser/shared-contracts", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/shared/contracts/src", + "projectType": "library", + "tags": [], + "targets": { + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/shared/contracts/jest.config.ts" + } + } + } +} diff --git a/libs/shared/contracts/src/index.ts b/libs/shared/contracts/src/index.ts new file mode 100644 index 0000000..aa429db --- /dev/null +++ b/libs/shared/contracts/src/index.ts @@ -0,0 +1 @@ +export * from './lib/uuid'; diff --git a/libs/shared/contracts/src/lib/uuid.ts b/libs/shared/contracts/src/lib/uuid.ts new file mode 100644 index 0000000..07dd212 --- /dev/null +++ b/libs/shared/contracts/src/lib/uuid.ts @@ -0,0 +1 @@ +export type UUID = `${string}-${string}-${string}-${string}-${string}`; diff --git a/libs/shared/contracts/tsconfig.json b/libs/shared/contracts/tsconfig.json new file mode 100644 index 0000000..0dc79ca --- /dev/null +++ b/libs/shared/contracts/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noPropertyAccessFromIndexSignature": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/shared/contracts/tsconfig.lib.json b/libs/shared/contracts/tsconfig.lib.json new file mode 100644 index 0000000..4befa7f --- /dev/null +++ b/libs/shared/contracts/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/libs/shared/contracts/tsconfig.spec.json b/libs/shared/contracts/tsconfig.spec.json new file mode 100644 index 0000000..ab55b7c --- /dev/null +++ b/libs/shared/contracts/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "moduleResolution": "node10", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index 80b793d..f807bd5 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -15,6 +15,12 @@ "skipDefaultLibCheck": true, "baseUrl": ".", "paths": { + "@service-bus-browser/connections-flow": [ + "libs/connections/flow/src/index.ts" + ], + "@service-bus-browser/connections-store": [ + "libs/connections/store/src/index.ts" + ], "@service-bus-browser/logs-components": [ "libs/logs/components/src/index.ts" ], @@ -37,6 +43,9 @@ "@service-bus-browser/service-bus-server": [ "libs/service-bus/server/src/index.ts" ], + "@service-bus-browser/shared-contracts": [ + "libs/shared/contracts/src/index.ts" + ], "@service-bus-browser/topology-components": [ "libs/topology/components/src/index.ts" ],