diff --git a/alfa-client/apps/admin/src/main.ts b/alfa-client/apps/admin/src/main.ts index 517ab0538bea573be67b1b8184ec7bb50695c242..ccbd4932ca92f4727fd468ea8d7fcb3495fe003a 100644 --- a/alfa-client/apps/admin/src/main.ts +++ b/alfa-client/apps/admin/src/main.ts @@ -21,18 +21,29 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { EnvironmentModule, loadEnvironment } from '@alfa-client/environment-shared'; -import { enableProdMode, importProvidersFrom, Injectable } from '@angular/core'; -import { isNil } from 'lodash-es'; - +import { ConfigurationService } from '@admin-client/configuration-shared'; +import { + AggregationMappingListResourceService, + AggregationMappingService, + createAggregationMappingResourceService, +} from '@admin-client/reporting-shared'; import { ApiRootModule } from '@alfa-client/api-root-shared'; +import { EnvironmentModule, loadEnvironment } from '@alfa-client/environment-shared'; import { NavigationSharedModule } from '@alfa-client/navigation-shared'; +import { ResourceRepository } from '@alfa-client/tech-shared'; import { registerLocaleData } from '@angular/common'; import { HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import localeDe from '@angular/common/locales/de'; +import { enableProdMode, importProvidersFrom, Injectable } from '@angular/core'; import { bootstrapApplication, BrowserModule } from '@angular/platform-browser'; import { provideAnimations } from '@angular/platform-browser/animations'; -import { ActivatedRouteSnapshot, BaseRouteReuseStrategy, provideRouter, RouteReuseStrategy, withRouterConfig, } from '@angular/router'; +import { + ActivatedRouteSnapshot, + BaseRouteReuseStrategy, + provideRouter, + RouteReuseStrategy, + withRouterConfig, +} from '@angular/router'; import { HttpUnauthorizedInterceptor } from '@authentication'; import { EffectsModule } from '@ngrx/effects'; import { StoreRouterConnectingModule } from '@ngrx/router-store'; @@ -43,6 +54,7 @@ import { ConfigurationsProviders } from 'libs/admin/configuration-shared/src/lib import { PostfachProviders } from 'libs/admin/postfach-shared/src/lib/postfach.providers'; import { SettingsProviders } from 'libs/admin/settings-shared/src/lib/settings.providers'; import { UserProviders } from 'libs/admin/user/src/lib/user.providers'; +import { isNil } from 'lodash-es'; import { AppComponent } from './app/app.component'; import { appRoutes } from './app/app.routes'; import { environment } from './environments/environment'; @@ -73,6 +85,12 @@ loadEnvironment(environment.environmentUrl).then((env) => { PostfachProviders, SettingsProviders, UserProviders, + { + provide: AggregationMappingListResourceService, + useFactory: createAggregationMappingResourceService, + deps: [ResourceRepository, ConfigurationService], + }, + AggregationMappingService, importProvidersFrom( NavigationSharedModule, BrowserModule, diff --git a/alfa-client/libs/admin/reporting-shared/.eslintrc.json b/alfa-client/libs/admin/reporting-shared/.eslintrc.json new file mode 100644 index 0000000000000000000000000000000000000000..7474579d583c598ae092a906b3e6cf1ad3c08a50 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/.eslintrc.json @@ -0,0 +1,33 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts"], + "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"], + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "admin", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "admin", + "style": "kebab-case" + } + ] + } + }, + { + "files": ["*.html"], + "extends": ["plugin:@nx/angular-template"], + "rules": {} + } + ] +} diff --git a/alfa-client/libs/admin/reporting-shared/README.md b/alfa-client/libs/admin/reporting-shared/README.md new file mode 100644 index 0000000000000000000000000000000000000000..be5bb22469ec116a5b8b3d498db669555c92da4e --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/README.md @@ -0,0 +1,7 @@ +# admin-reporting-shared + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test admin-reporting-shared` to execute the unit tests. diff --git a/alfa-client/libs/admin/reporting-shared/jest.config.ts b/alfa-client/libs/admin/reporting-shared/jest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..b4f392a061baff74cb98d86a02f0100960384315 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/jest.config.ts @@ -0,0 +1,21 @@ +export default { + displayName: 'admin-reporting-shared', + preset: '../../../jest.preset.js', + setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], + coverageDirectory: '../../../coverage/libs/admin/reporting-shared', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '<rootDir>/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/alfa-client/libs/admin/reporting-shared/project.json b/alfa-client/libs/admin/reporting-shared/project.json new file mode 100644 index 0000000000000000000000000000000000000000..f7a760900530aff273dc117494292f1e2b028824 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/project.json @@ -0,0 +1,22 @@ +{ + "name": "admin-reporting-shared", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/admin/reporting-shared/src", + "prefix": "admin", + "projectType": "library", + "tags": [], + "targets": { + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "tsConfig": "libs/admin/reporting-shared/tsconfig.spec.json", + "jestConfig": "libs/admin/reporting-shared/jest.config.ts" + } + }, + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"] + } + } +} diff --git a/alfa-client/libs/admin/reporting-shared/src/index.ts b/alfa-client/libs/admin/reporting-shared/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..9ddf4d3f190eb4ad70ea582988cb058322b7b186 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/index.ts @@ -0,0 +1,3 @@ +export * from './lib/aggregation-mapping-resource.service'; +export * from './lib/aggregation-mapping.model'; +export * from './lib/aggregation-mapping.service'; diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..65eb7a8e1680b97f12cdba2556ae8d9d9041883c --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.ts @@ -0,0 +1,26 @@ +import { ConfigurationLinkRel, ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared'; +import { ListResourceServiceConfig, ResourceListService, ResourceRepository } from '@alfa-client/tech-shared'; +import { AggregationMappingListLinkRel } from './aggregation-mapping.linkrel'; +import { AggregationMappingListResource, AggregationMappingResource } from './aggregation-mapping.model'; + +export class AggregationMappingListResourceService extends ResourceListService< + ConfigurationResource, + AggregationMappingListResource, + AggregationMappingResource +> {} + +export function createAggregationMappingResourceService( + repository: ResourceRepository, + configurationService: ConfigurationService, +) { + return new ResourceListService(buildConfig(configurationService), repository); +} + +function buildConfig(configurationService: ConfigurationService): ListResourceServiceConfig<ConfigurationResource> { + return { + baseResource: configurationService.get(), + listLinkRel: ConfigurationLinkRel.AGGREGATION_MAPPINGS, + listResourceListLinkRel: AggregationMappingListLinkRel.LIST, + createLinkRel: AggregationMappingListLinkRel.SELF, + }; +} diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.linkrel.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.linkrel.ts new file mode 100644 index 0000000000000000000000000000000000000000..a4a02bfd7087b105a9d0d2dd816aa2b180a4db9c --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.linkrel.ts @@ -0,0 +1,4 @@ +export enum AggregationMappingListLinkRel { + LIST = 'aggregationMappings', + SELF = 'self', +} diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.model.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..0db6cb4e397768b10781b3c34c9379fc866cec2b --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.model.ts @@ -0,0 +1,20 @@ +import { ListResource } from '@alfa-client/tech-shared'; +import { Resource } from '@ngxp/rest'; + +export interface AggregationMapping { + formIdentifier: FormIdentifier; + mappings: FieldMapping[]; +} + +export interface FormIdentifier { + formEngineName: string; + formId: string; +} + +export interface FieldMapping { + sourcePath: string; + targetPath: string; +} + +export interface AggregationMappingResource extends AggregationMapping, Resource {} +export interface AggregationMappingListResource extends ListResource {} diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..20a8ce6c1ccda133323bac99a671d887e77afb8e --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.ts @@ -0,0 +1,18 @@ +import { StateResource } from '@alfa-client/tech-shared'; +import { Injectable, inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { AggregationMappingListResourceService } from './aggregation-mapping-resource.service'; +import { AggregationMapping, AggregationMappingListResource, AggregationMappingResource } from './aggregation-mapping.model'; + +@Injectable() +export class AggregationMappingService { + readonly listService = inject(AggregationMappingListResourceService); + + public getList(): Observable<StateResource<AggregationMappingListResource>> { + return this.listService.getList(); + } + + public create(toCreate: AggregationMapping): Observable<StateResource<AggregationMappingResource>> { + return this.listService.create(toCreate); + } +} diff --git a/alfa-client/libs/admin/reporting-shared/src/test-setup.ts b/alfa-client/libs/admin/reporting-shared/src/test-setup.ts new file mode 100644 index 0000000000000000000000000000000000000000..c408668266d2fec3a9803c0ec044bc163fb987fe --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/test-setup.ts @@ -0,0 +1,12 @@ +import '@testing-library/jest-dom'; +import 'jest-preset-angular/setup-jest'; + +import { getTestBed } from '@angular/core/testing'; +import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; + +getTestBed().resetTestEnvironment(); +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { + teardown: { destroyAfterEach: false }, + errorOnUnknownProperties: true, + errorOnUnknownElements: true, +}); diff --git a/alfa-client/libs/admin/reporting-shared/test/aggregation-mapping.ts b/alfa-client/libs/admin/reporting-shared/test/aggregation-mapping.ts new file mode 100644 index 0000000000000000000000000000000000000000..6c7c4d6d8c7d37ef208117c9a6a2b750b27f0853 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/test/aggregation-mapping.ts @@ -0,0 +1,35 @@ +import { faker } from '@faker-js/faker'; +import { times } from 'lodash-es'; +import { LinkRelationName } from '../../../tech-shared/src'; +import { toResource } from '../../../tech-shared/test/resource'; +import { AggregationMapping, AggregationMappingListResource, AggregationMappingResource } from '../src'; +import { AggregationMappingListLinkRel } from '../src/lib/aggregation-mapping.linkrel'; + +export function createAggregationMapping(): AggregationMapping { + return { + formIdentifier: { + formEngineName: faker.lorem.word(), + formId: faker.string.uuid(), + }, + mappings: [ + { + sourcePath: faker.lorem.word(), + targetPath: faker.lorem.word(), + }, + ], + }; +} + +export function createAggregationMappingResource(linkRelations: LinkRelationName[] = []): AggregationMappingResource { + return toResource(createAggregationMapping(), linkRelations); +} + +export function createAggregationMappingResources(linkRelations: LinkRelationName[] = []): AggregationMappingResource[] { + return times(10, () => toResource(createAggregationMappingResource(), [...linkRelations])); +} + +export function createAggregationMappingListResource(linkRelations: LinkRelationName[] = []): AggregationMappingListResource { + return toResource({}, [...linkRelations], { + [AggregationMappingListLinkRel.LIST]: createAggregationMappingResources(), + }); +} diff --git a/alfa-client/libs/admin/reporting-shared/tsconfig.json b/alfa-client/libs/admin/reporting-shared/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..8ca9ad312c2bd4dc364383853ddd91a2ed8f86fd --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "target": "es2022" + } +} diff --git a/alfa-client/libs/admin/reporting-shared/tsconfig.lib.json b/alfa-client/libs/admin/reporting-shared/tsconfig.lib.json new file mode 100644 index 0000000000000000000000000000000000000000..8441346f6e5858b2ef4235cb3c3160eda256f94a --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "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/alfa-client/libs/admin/reporting-shared/tsconfig.spec.json b/alfa-client/libs/admin/reporting-shared/tsconfig.spec.json new file mode 100644 index 0000000000000000000000000000000000000000..723782fbd367969806c5992aea882773ab65af8b --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/tsconfig.spec.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"], + "target": "ES2022", + "useDefineForClassFields": false + }, + "files": ["src/test-setup.ts"], + "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"] +} diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html index 40b08d0ce982dce2be5cb06aadd7792daa71a182..28523fbf877b1bfd9eeb103ae56606effeb766d8 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.html @@ -31,3 +31,5 @@ dataTestId="weitere-felder-auswerten-button" ></ods-routing-button> </div> + +<ng-container *ngIf="listStateResource$ | async"></ng-container> diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts index 0a49089ec852bfd6385d91d975bcfdb957ec1ba7..a2bc7e4bfe5efdec1af21b9ad1da7deaccf1a21f 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.spec.ts @@ -21,11 +21,15 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { existsAsHtmlElement } from '@alfa-client/test-utils'; +import { AggregationMappingListResource, AggregationMappingService } from '@admin-client/reporting-shared'; +import { createStateResource, StateResource } from '@alfa-client/tech-shared'; +import { existsAsHtmlElement, mock, Mock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { RoutingButtonComponent } from '@ods/component'; +import { singleCold } from 'libs/tech-shared/test/marbles'; import { MockComponent } from 'ng-mocks'; import { getDataTestIdAttributeOf } from '../../../../../tech-shared/test/data-test'; +import { createAggregationMappingListResource } from '../../../../reporting-shared/test/aggregation-mapping'; import { StatistikContainerComponent } from './statistik-container.component'; describe('StatistikContainerComponent', () => { @@ -34,24 +38,34 @@ describe('StatistikContainerComponent', () => { const evaluateAdditionalFieldsTestId: string = getDataTestIdAttributeOf('weitere-felder-auswerten-button'); + let aggregationMappingService: Mock<AggregationMappingService>; + beforeEach(async () => { + aggregationMappingService = mock(AggregationMappingService); + await TestBed.configureTestingModule({ imports: [StatistikContainerComponent], declarations: [MockComponent(RoutingButtonComponent)], - }); - }); + }) + .overrideComponent(StatistikContainerComponent, { + set: { + providers: [ + { + provide: AggregationMappingService, + useValue: aggregationMappingService, + }, + ], + }, + }) + .compileComponents(); - beforeEach(() => { fixture = TestBed.createComponent(StatistikContainerComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); - describe('component', () => { - it('should create', () => { - expect(component).toBeTruthy(); - }); + it('should create', () => { + expect(component).toBeTruthy(); }); describe('template', () => { @@ -63,4 +77,26 @@ describe('StatistikContainerComponent', () => { }); }); }); + + describe('on init', () => { + const stateResource: StateResource<AggregationMappingListResource> = createStateResource( + createAggregationMappingListResource(), + ); + + beforeEach(() => { + aggregationMappingService.getList.mockReturnValue(singleCold(stateResource)); + }); + + it('should call service to get list', () => { + component.ngOnInit(); + + expect(aggregationMappingService.getList).toHaveBeenCalled(); + }); + + it('should assign stateResource', () => { + component.ngOnInit(); + + expect(component.listStateResource$).toBeObservable(singleCold(stateResource)); + }); + }); }); diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts index d12285ba6b1af11b7f314763be4632871a4be8cd..90c3515896348b1c1d6ee77ba4f247428e79c4bf 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-container/statistik-container.component.ts @@ -21,17 +21,29 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { AggregationMappingListResource, AggregationMappingService } from '@admin-client/reporting-shared'; import { ROUTES } from '@admin-client/shared'; +import { StateResource } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; -import { Component } from '@angular/core'; +import { Component, inject, OnInit } from '@angular/core'; import { RoutingButtonComponent } from '@ods/component'; +import { Observable } from 'rxjs'; @Component({ selector: 'admin-statistik-container', templateUrl: './statistik-container.component.html', standalone: true, imports: [CommonModule, RoutingButtonComponent], + providers: [AggregationMappingService], }) -export class StatistikContainerComponent { +export class StatistikContainerComponent implements OnInit { + private service = inject(AggregationMappingService); + + public listStateResource$: Observable<StateResource<AggregationMappingListResource>>; + public readonly ROUTES = ROUTES; + + ngOnInit(): void { + this.listStateResource$ = this.service.getList(); + } } diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.spec.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..58a2273cb692762c4f930e583c8c49f210099517 --- /dev/null +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.spec.ts @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2025 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import { AggregationMappingResource, AggregationMappingService } from '@admin-client/reporting-shared'; +import { EMPTY_STRING, StateResource, createStateResource } from '@alfa-client/tech-shared'; +import { Mock, mock } from '@alfa-client/test-utils'; +import { TestBed } from '@angular/core/testing'; +import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { createAggregationMapping, createAggregationMappingResource } from 'libs/admin/reporting-shared/test/aggregation-mapping'; +import { of } from 'rxjs'; +import { StatistikFieldsFormService } from './statistik-fields.formservice'; + +describe('StatistikFieldsFormService', () => { + let formService: StatistikFieldsFormService; + + let service: Mock<AggregationMappingService>; + + beforeEach(() => { + service = mock(AggregationMappingService); + + TestBed.configureTestingModule({ + providers: [StatistikFieldsFormService, { provide: AggregationMappingService, useValue: service }], + }); + + formService = TestBed.inject(StatistikFieldsFormService); + }); + + it('should create', () => { + expect(formService).toBeTruthy(); + }); + + describe('on do submit', () => { + const stateResource: StateResource<AggregationMappingResource> = createStateResource(createAggregationMappingResource()); + + beforeEach(() => { + service.create.mockReturnValue(of(stateResource)); + }); + + it('should call service', () => { + formService.form = <any>createAggregationMapping(); + + formService.submit(); + + expect(service.create).toHaveBeenCalledWith(formService.form.value); + }); + }); + + describe('add mapping', () => { + it('should add mapping control', () => { + formService.addMapping(); + + const mappingFormArray: FormArray = <FormArray>formService.form.controls[StatistikFieldsFormService.FIELD_MAPPINGS]; + expect(mappingFormArray).toHaveLength(2); + expect(mappingFormArray.controls[0].value).toEqual({ sourcePath: EMPTY_STRING }); + }); + }); + + describe('remove mapping', () => { + it('should remove mapping control', () => { + (<FormArray>formService.form.controls[StatistikFieldsFormService.FIELD_MAPPINGS]).push( + new FormGroup({ sourcePath: new FormControl('controlToRemove') }), + ); + + formService.removeMapping(1); + + const mappingFormArray: FormArray = <FormArray>formService.form.controls[StatistikFieldsFormService.FIELD_MAPPINGS]; + expect(mappingFormArray).toHaveLength(1); + expect(mappingFormArray.controls[0].value).toEqual({ sourcePath: EMPTY_STRING }); + }); + }); + + describe('get mappings', () => { + it('should return mappings as array', () => { + const mappings: FormArray = formService.mappings; + + expect(mappings).toHaveLength(1); + expect(mappings.controls[0].value).toEqual({ sourcePath: EMPTY_STRING }); + }); + }); +}); diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.ts index 7f599927eaa4fc4d02a7f3d4309da4c058dc3400..ebcfad677faae62c09e0a1736208caffc70455ce 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields.formservice.ts @@ -1,11 +1,13 @@ +import { AggregationMappingResource, AggregationMappingService } from '@admin-client/reporting-shared'; import { AbstractFormService, EMPTY_STRING, StateResource } from '@alfa-client/tech-shared'; -import { Injectable } from '@angular/core'; +import { inject, Injectable } from '@angular/core'; import { FormArray, FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; -import { Resource } from '@ngxp/rest'; -import { EMPTY, Observable } from 'rxjs'; +import { Observable } from 'rxjs'; @Injectable() -export class StatistikFieldsFormService extends AbstractFormService<Resource> { +export class StatistikFieldsFormService extends AbstractFormService<AggregationMappingResource> { + private service = inject(AggregationMappingService); + public static readonly FIELD_FORM_IDENTIFIER: string = 'formIdentifier'; public static readonly FIELD_FORM_ENGINE_NAME: string = 'formEngineName'; public static readonly FIELD_FORM_ID: string = 'formId'; @@ -22,9 +24,9 @@ export class StatistikFieldsFormService extends AbstractFormService<Resource> { }); } - protected doSubmit(): Observable<StateResource<Resource>> { + protected doSubmit(): Observable<StateResource<AggregationMappingResource>> { console.info('FormValue: ', this.getFormValue()); - return EMPTY; + return this.service.create(this.getFormValue()); } protected getPathPrefix(): string { diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts index 9af26540fdf4031d434bcb3d4000e2a3f56d3c96..d5726c77529ec251188d2323565ad95742986a58 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts @@ -22,11 +22,11 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { CollaborationListResource } from '@alfa-client/collaboration-shared'; -import { SnackBarService } from '@alfa-client/ui'; -import { TestBed } from '@angular/core/testing'; import { CommandLinkRel, CommandResource } from '@alfa-client/command-shared'; import { StateResource, createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; -import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; +import { Mock, mock } from '@alfa-client/test-utils'; +import { SnackBarService } from '@alfa-client/ui'; +import { TestBed } from '@angular/core/testing'; import { UntypedFormBuilder } from '@angular/forms'; import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service'; import { createCollaborationListResource } from 'libs/collaboration-shared/test/collaboration'; @@ -57,7 +57,6 @@ describe('CollaborationRequestFormService', () => { }); formService = TestBed.inject(CollaborationRequestFormService); - TestBed.inject(CollaborationRequestFormService); }); it('should create', () => { diff --git a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts index 76fac14c0bfe11b7f9b97a634e922aad14a417ca..286c17bcc2bd55173d6377e990418ae08a39e0c7 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.spec.ts @@ -29,7 +29,7 @@ import { cold } from 'jest-marbles'; import { DummyLinkRel, DummyListLinkRel } from 'libs/tech-shared/test/dummy'; import { createDummyListResource, createDummyResource, createFilledDummyListResource } from 'libs/tech-shared/test/resource'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { singleCold, singleHot } from '../../../test/marbles'; +import { multipleCold, singleCold, singleHot } from '../../../test/marbles'; import { EMPTY_ARRAY } from '../tech.util'; import { ResourceListService } from './list-resource.service'; import { CreateResourceData, LinkRelationName, ListItemResource, ListResourceServiceConfig } from './resource.model'; @@ -335,11 +335,11 @@ describe('ListResourceService', () => { it('should return value', () => { const returnResource: Resource = createDummyResource(); - resourceRepository.createResource.mockReturnValue(singleHot(returnResource)); + resourceRepository.createResource.mockReturnValue(singleCold(returnResource, '-a')); - const createdResource: Observable<Resource> = service.create(toCreate); + const createdResource: Observable<StateResource<Resource>> = service.create(toCreate); - expect(createdResource).toBeObservable(singleCold(returnResource)); + expect(createdResource).toBeObservable(multipleCold(createEmptyStateResource(true), createStateResource(returnResource))); }); }); diff --git a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts index 50cee3aa72fb828211d7a70dadc5cdca3d5f55c2..373f31cad66bf98042068caa0e14d1a556a10a2e 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/list-resource.service.ts @@ -58,7 +58,7 @@ export class ResourceListService<B extends Resource, T extends ListResource, I e constructor( private config: ListResourceServiceConfig<B>, - private repository: ResourceRepository, + private repository: ResourceRepository<I>, ) {} public getList(): Observable<StateResource<T>> { @@ -105,9 +105,12 @@ export class ResourceListService<B extends Resource, T extends ListResource, I e this.listResource.next(createEmptyStateResource()); } - public create(toCreate: unknown): Observable<Resource> { + public create(toCreate: unknown): Observable<StateResource<I>> { this.verifyBeforeCreation(); - return this.repository.createResource(this.buildCreateResourceData(toCreate, this.config.createLinkRel)); + return this.repository.createResource(this.buildCreateResourceData(toCreate, this.config.createLinkRel)).pipe( + map((listItemResource: I) => createStateResource(listItemResource)), + startWith(createEmptyStateResource<I>(true)), + ); } private verifyBeforeCreation(): void { diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts index d8f90a78eb269f096a4f159237d07926ad130881..52240b5bf13254128feb1c024febb561c5a97d19 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.repository.ts @@ -28,7 +28,7 @@ import { CreateResourceData, LinkRelationName, SaveResourceData } from './resour import { ListResource } from './resource.util'; @Injectable({ providedIn: 'root' }) -export class ResourceRepository { +export class ResourceRepository<T extends Resource = Resource> { static SEARCH_PARAM: string = 'searchBy'; constructor(private resourceFactory: ResourceFactory) {} @@ -45,7 +45,7 @@ export class ResourceRepository { return uri; } - public createResource(createResourceData: CreateResourceData<Resource>): Observable<Resource> { + public createResource(createResourceData: CreateResourceData<Resource>): Observable<T> { return this.resourceFactory.from(createResourceData.resource).post(createResourceData.linkRel, createResourceData.toCreate); } diff --git a/alfa-client/libs/tech-shared/test/marbles.ts b/alfa-client/libs/tech-shared/test/marbles.ts index ea8e04237504cc8104ddb569ce574dd66c6ad362..fecda8769f38a80dd34c693c9ca39bf175a69eef 100644 --- a/alfa-client/libs/tech-shared/test/marbles.ts +++ b/alfa-client/libs/tech-shared/test/marbles.ts @@ -34,3 +34,7 @@ export function singleCold(object: any, frame: string = 'a'): ObservableWithSubs export function singleColdCompleted(object: any, frame: string = 'a'): ObservableWithSubscriptions { return cold(`(${frame}|)`, { a: object }); } + +export function multipleCold(first: any, second: any): ObservableWithSubscriptions { + return cold('ab', { a: first, b: second }); +} diff --git a/alfa-client/tsconfig.base.json b/alfa-client/tsconfig.base.json index 6850f74e4eb7c031308a264a51e8a4782fa9613b..f6bb4c8b2657d8acef026b997d32794971be5656 100644 --- a/alfa-client/tsconfig.base.json +++ b/alfa-client/tsconfig.base.json @@ -22,6 +22,7 @@ "@admin-client/organisations-einheit-shared": ["libs/admin/organisations-einheit-shared/src/index.ts"], "@admin-client/postfach": ["libs/admin/postfach/src/index.ts"], "@admin-client/postfach-shared": ["libs/admin/postfach-shared/src/index.ts"], + "@admin-client/reporting-shared": ["libs/admin/reporting-shared/src/index.ts"], "@admin-client/settings-shared": ["libs/admin/settings-shared/src/index.ts"], "@admin-client/shared": ["libs/admin/shared/src/index.ts"], "@admin-client/statistik": ["libs/admin/statistik/src/index.ts"],