diff --git a/alfa-client/apps/admin/src/app/app.component.spec.ts b/alfa-client/apps/admin/src/app/app.component.spec.ts index baa8c7fcc532a0e859fe596782a94bf7b2257803..cc45121d96c5ad9236bb5a834c42ab4714617175 100644 --- a/alfa-client/apps/admin/src/app/app.component.spec.ts +++ b/alfa-client/apps/admin/src/app/app.component.spec.ts @@ -297,7 +297,7 @@ describe('AppComponent', () => { it('should navigate to statistik if aggregation mapping link exists', () => { component._navigateByConfiguration(createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS])); - expect(router.navigate).toHaveBeenCalledWith(['/statistik']); + expect(router.navigate).toHaveBeenCalledWith(['/aggregation-mapping']); }); it('should navigate to unavailable page if no link exists', () => { diff --git a/alfa-client/apps/admin/src/app/app.component.ts b/alfa-client/apps/admin/src/app/app.component.ts index 909b6cd198bd3ccb91dd61e922abb6a1ed79210c..989a4ad4b3fd75d2767750eb535a8db27a9d6c29 100644 --- a/alfa-client/apps/admin/src/app/app.component.ts +++ b/alfa-client/apps/admin/src/app/app.component.ts @@ -123,7 +123,7 @@ export class AppComponent implements OnInit { if (hasLink(configurationResource, ConfigurationLinkRel.SETTING)) { this.navigate(ROUTES.POSTFACH); } else if (hasLink(configurationResource, ConfigurationLinkRel.AGGREGATION_MAPPINGS)) { - this.navigate(ROUTES.STATISTIK); + this.navigate(ROUTES.AGGREGATION_MAPPING); } else { this.navigate(ROUTES.UNAVAILABLE); } diff --git a/alfa-client/apps/admin/src/app/app.routes.ts b/alfa-client/apps/admin/src/app/app.routes.ts index c5974993c237ec15254220a64157b63ae0f46136..2d21b25201efc7da0c177426aea5f1ccc0feabbf 100644 --- a/alfa-client/apps/admin/src/app/app.routes.ts +++ b/alfa-client/apps/admin/src/app/app.routes.ts @@ -83,7 +83,7 @@ export const appRoutes: Route[] = [ title: 'Unavailable', }, { - path: ROUTES.STATISTIK, + path: ROUTES.AGGREGATION_MAPPING, component: StatistikPageComponent, title: 'Admin | Statistik', runGuardsAndResolvers: 'always', @@ -91,7 +91,15 @@ export const appRoutes: Route[] = [ data: <GuardData>{ linkRelName: ConfigurationLinkRel.AGGREGATION_MAPPINGS }, }, { - path: ROUTES.STATISTIK_NEU, + path: ROUTES.AGGREGATION_MAPPING_NEU, + component: StatistikFieldsFormPageComponent, + title: 'Admin | Statistik weitere Felder auswerten', + runGuardsAndResolvers: 'always', + canActivate: [configurationGuard], + data: <GuardData>{ linkRelName: ConfigurationLinkRel.AGGREGATION_MAPPINGS }, + }, + { + path: ROUTES.AGGREGATION_MAPPING_ID, component: StatistikFieldsFormPageComponent, title: 'Admin | Statistik weitere Felder auswerten', runGuardsAndResolvers: 'always', diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html index 0c1102a4c22c1603d4cc93f6baaaf5fcb2f94d40..c319836e14be9bee1d1314df5f293f09173a12b0 100644 --- a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html +++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.html @@ -4,7 +4,7 @@ </ods-nav-item> } @if (configurationStateResource.resource | hasLink: configurationLinkRel.AGGREGATION_MAPPINGS) { - <ods-nav-item data-test-id="statistik-navigation" caption="Statistik" path="/statistik"> + <ods-nav-item data-test-id="statistik-navigation" caption="Statistik" [path]="'/' + ROUTES.AGGREGATION_MAPPING"> <ods-statistic-icon icon /> </ods-nav-item> } diff --git a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts index 0c9cddefff0b13b58d8dd915f44352b78bd60f2b..c0845f3f13cf83a993f7cbe48f8021d42a2097e2 100644 --- a/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts +++ b/alfa-client/libs/admin/configuration/src/lib/menu-container/menu/menu.component.ts @@ -1,4 +1,5 @@ import { ConfigurationLinkRel, ConfigurationResource } from '@admin-client/configuration-shared'; +import { ROUTES } from '@admin-client/shared'; import { HasLinkPipe, StateResource } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { Component, Input } from '@angular/core'; @@ -14,4 +15,5 @@ export class MenuComponent { @Input() configurationStateResource: StateResource<ConfigurationResource>; public readonly configurationLinkRel = ConfigurationLinkRel; + public readonly ROUTES = ROUTES; } diff --git a/alfa-client/libs/admin/reporting-shared/src/index.ts b/alfa-client/libs/admin/reporting-shared/src/index.ts index 44ab78233d97deaf497e327e28f71c431ae6960e..42e6a9bbe06db6b16da1b80d8f8b7f902c421988 100644 --- a/alfa-client/libs/admin/reporting-shared/src/index.ts +++ b/alfa-client/libs/admin/reporting-shared/src/index.ts @@ -1,3 +1,4 @@ +export * from './lib/aggregation-mapping-list-resource.service'; export * from './lib/aggregation-mapping-resource.service'; export * from './lib/aggregation-mapping.model'; export * from './lib/aggregation-mapping.provider'; diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-list-resource.service.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-list-resource.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..1378b74475c88940614acdf93cd68218ee9927ea --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-list-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 createAggregationMappingListResourceService( + 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-resource.service.spec.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0b2f68fab6d7716bb3e658cf8b848eac3ea1ed50 --- /dev/null +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping-resource.service.spec.ts @@ -0,0 +1,213 @@ +import { AggregationMappingResource } from '@admin-client/reporting-shared'; +import { ROUTES } from '@admin-client/shared'; +import { NavigationService, RouteData } from '@alfa-client/navigation-shared'; +import { + createEmptyStateResource, + createStateResource, + decodeUrlFromEmbedding, + ResourceRepository, + ResourceServiceConfig, + StateResource, +} from '@alfa-client/tech-shared'; +import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; +import { UrlSegment } from '@angular/router'; +import { faker } from '@faker-js/faker'; +import { afterAll, expect } from '@jest/globals'; +import { ResourceUri } from '@ngxp/rest'; +import { Observable, of } from 'rxjs'; +import { createRouteData, createUrlSegment } from '../../../../navigation-shared/test/navigation-test-factory'; +import { singleColdCompleted } from '../../../../tech-shared/test/marbles'; +import { createAggregationMappingResource } from '../../test/aggregation-mapping'; +import * as module from './aggregation-mapping-resource.service'; + +jest.mock('@alfa-client/tech-shared', () => ({ + ...jest.requireActual('@alfa-client/tech-shared'), + decodeUrlFromEmbedding: jest.fn(), +})); + +const decodeUrlFromEmbeddingMock: jest.Mock = decodeUrlFromEmbedding as jest.Mock; + +describe('AggregationMappingResourceService', () => { + let repository: Mock<ResourceRepository>; + let navigationService: Mock<NavigationService>; + + beforeEach(() => { + repository = mock(ResourceRepository); + navigationService = mock(NavigationService); + }); + + describe('build config', () => { + const _getResourceByNavigationRoute: jest.SpyInstance = jest + .spyOn(module, '_getResourceByNavigationRoute') + .mockImplementation(); + + afterAll(() => { + _getResourceByNavigationRoute.mockRestore(); + }); + + it('should get resource by navigation route', () => { + module._buildResourceServiceConfig(useFromMock(repository), useFromMock(navigationService)); + + expect(_getResourceByNavigationRoute).toHaveBeenCalled(); + }); + + it('should have aggregation mapping static resource', () => { + const staticResource: StateResource<AggregationMappingResource> = createStateResource(createAggregationMappingResource()); + _getResourceByNavigationRoute.mockReturnValue(of(staticResource)); + + const config: ResourceServiceConfig<AggregationMappingResource> = module._buildResourceServiceConfig( + useFromMock(repository), + useFromMock(navigationService), + ); + + expect(config.resource).toBeObservable(singleColdCompleted(staticResource)); + }); + }); + + describe('get resource by navigation route', () => { + const routeData: RouteData = createRouteData(); + const _isAggregationMappingEditUrl: jest.SpyInstance = jest + .spyOn(module, '_isAggregationMappingEditUrl') + .mockImplementation(); + const _getAggregationMappingResourceByRoute: jest.SpyInstance = jest + .spyOn(module, '_getAggregationMappingResourceByRoute') + .mockImplementation(); + + beforeEach(() => { + navigationService.getCurrentRouteData.mockReturnValue(of(routeData)); + }); + + afterAll(() => { + _isAggregationMappingEditUrl.mockRestore(); + _getAggregationMappingResourceByRoute.mockRestore(); + }); + + it('should get current route data', () => { + module._getResourceByNavigationRoute(useFromMock(repository), useFromMock(navigationService)).subscribe(); + + expect(navigationService.getCurrentRouteData).toHaveBeenCalled(); + }); + + it('should check if url contains resource uri', () => { + module._getResourceByNavigationRoute(useFromMock(repository), useFromMock(navigationService)).subscribe(); + + expect(_isAggregationMappingEditUrl).toHaveBeenCalled(); + }); + + it('should get aggregation mapping resource by route', () => { + module._getResourceByNavigationRoute(useFromMock(repository), useFromMock(navigationService)).subscribe(); + + expect(_getAggregationMappingResourceByRoute).toHaveBeenCalled(); + }); + + it('should return aggregation mapping by route', () => { + const stateResource: StateResource<AggregationMappingResource> = createStateResource(createAggregationMappingResource()); + _getAggregationMappingResourceByRoute.mockReturnValue(of(stateResource)); + _isAggregationMappingEditUrl.mockReturnValue(true); + + const resourceByRoute$: Observable<StateResource<AggregationMappingResource>> = module._getResourceByNavigationRoute( + useFromMock(repository), + useFromMock(navigationService), + ); + + expect(resourceByRoute$).toBeObservable(singleColdCompleted(stateResource)); + }); + + it('should return empty state resource', () => { + const stateResource: StateResource<AggregationMappingResource> = createEmptyStateResource(); + _isAggregationMappingEditUrl.mockReturnValue(false); + + const resourceByRoute$: Observable<StateResource<AggregationMappingResource>> = module._getResourceByNavigationRoute( + useFromMock(repository), + useFromMock(navigationService), + ); + + expect(resourceByRoute$).toBeObservable(singleColdCompleted(stateResource)); + }); + }); + + describe('is aggregation mapping edit url', () => { + it.each([0, 1, 3])('should return false of wrong number of segments = %d', (numberOfSegments: number) => { + const routeData: RouteData = { + ...createRouteData(), + urlSegments: Array(numberOfSegments).fill(createUrlSegment()), + }; + + expect(module._isAggregationMappingEditUrl(routeData)).toBe(false); + }); + + it('should return false if first path is wrong', () => { + const routeData: RouteData = { + ...createRouteData(), + urlSegments: Array(2).fill(createUrlSegment()), + }; + + expect(module._isAggregationMappingEditUrl(routeData)).toBe(false); + }); + + it('should return false if second path is wrong', () => { + const firstUrlSegment: UrlSegment = createUrlSegment(); + firstUrlSegment.path = ROUTES.AGGREGATION_MAPPING; + const secondUrlSegment: UrlSegment = createUrlSegment(); + secondUrlSegment.path = 'neu'; + const routeData: RouteData = { + ...createRouteData(), + urlSegments: [firstUrlSegment, secondUrlSegment], + }; + + expect(module._isAggregationMappingEditUrl(routeData)).toBe(false); + }); + + it('should return true', () => { + const firstUrlSegment: UrlSegment = createUrlSegment(); + firstUrlSegment.path = ROUTES.AGGREGATION_MAPPING; + const secondUrlSegment: UrlSegment = createUrlSegment(); + secondUrlSegment.path = faker.internet.url(); + const routeData: RouteData = { + ...createRouteData(), + urlSegments: [firstUrlSegment, secondUrlSegment], + }; + + expect(module._isAggregationMappingEditUrl(routeData)).toBe(true); + }); + }); + + describe('get aggregation mapping resource by route', () => { + const firstUrlSegment: UrlSegment = createUrlSegment(); + firstUrlSegment.path = ROUTES.AGGREGATION_MAPPING; + const secondUrlSegment: UrlSegment = createUrlSegment(); + secondUrlSegment.path = faker.internet.url(); + const routeData: RouteData = { + ...createRouteData(), + urlSegments: [firstUrlSegment, secondUrlSegment], + }; + const uri: ResourceUri = faker.internet.url(); + const resource: AggregationMappingResource = createAggregationMappingResource(); + + beforeEach(() => { + decodeUrlFromEmbeddingMock.mockReturnValue(uri); + repository.getResource.mockReturnValue(of(resource)); + }); + + it('should decode url', () => { + module._getAggregationMappingResourceByRoute(useFromMock(repository), routeData); + + expect(decodeUrlFromEmbeddingMock).toHaveBeenCalledWith(secondUrlSegment.path); + }); + + it('should get resource', () => { + module._getAggregationMappingResourceByRoute(useFromMock(repository), routeData); + + expect(repository.getResource).toHaveBeenCalledWith(uri); + }); + + it('should return state resource', () => { + const stateResource$: Observable<StateResource<AggregationMappingResource>> = module._getAggregationMappingResourceByRoute( + useFromMock(repository), + routeData, + ); + + expect(stateResource$).toBeObservable(singleColdCompleted(createStateResource(resource))); + }); + }); +}); 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 index 65eb7a8e1680b97f12cdba2556ae8d9d9041883c..e4937c3eb736c6460a9cd23daaabe5464adb18af 100644 --- 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 @@ -1,26 +1,71 @@ -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'; +import { ROUTES } from '@admin-client/shared'; +import { NavigationService, RouteData } from '@alfa-client/navigation-shared'; +import { + ApiResourceService, + createEmptyStateResource, + createStateResource, + decodeUrlFromEmbedding, + ResourceRepository, + ResourceServiceConfig, + StateResource, +} from '@alfa-client/tech-shared'; +import { UrlSegment } from '@angular/router'; +import { iif, map, Observable, of, switchMap } from 'rxjs'; +import * as module from './aggregation-mapping-resource.service'; +import { AggregationMappingLinkRel } from './aggregation-mapping.linkrel'; +import { AggregationMappingResource } from './aggregation-mapping.model'; -export class AggregationMappingListResourceService extends ResourceListService< - ConfigurationResource, - AggregationMappingListResource, +export class AggregationMappingResourceService extends ApiResourceService< + AggregationMappingResource, AggregationMappingResource > {} export function createAggregationMappingResourceService( repository: ResourceRepository, - configurationService: ConfigurationService, -) { - return new ResourceListService(buildConfig(configurationService), repository); + navigationService: NavigationService, +): AggregationMappingResourceService { + return new AggregationMappingResourceService(_buildResourceServiceConfig(repository, navigationService), repository); } -function buildConfig(configurationService: ConfigurationService): ListResourceServiceConfig<ConfigurationResource> { +export function _buildResourceServiceConfig( + repository: ResourceRepository, + navigationService: NavigationService, +): ResourceServiceConfig<AggregationMappingResource> { + module._getResourceByNavigationRoute(repository, navigationService); return { - baseResource: configurationService.get(), - listLinkRel: ConfigurationLinkRel.AGGREGATION_MAPPINGS, - listResourceListLinkRel: AggregationMappingListLinkRel.LIST, - createLinkRel: AggregationMappingListLinkRel.SELF, + resource: module._getResourceByNavigationRoute(repository, navigationService), + getLinkRel: AggregationMappingLinkRel.SELF, + edit: { linkRel: AggregationMappingLinkRel.SELF }, + delete: { linkRel: AggregationMappingLinkRel.SELF }, }; } + +export function _getResourceByNavigationRoute( + repository: ResourceRepository, + navigationService: NavigationService, +): Observable<StateResource<AggregationMappingResource>> { + return navigationService + .getCurrentRouteData() + .pipe( + switchMap((route: RouteData) => + iif( + () => module._isAggregationMappingEditUrl(route), + module._getAggregationMappingResourceByRoute(repository, route), + of(createEmptyStateResource<AggregationMappingResource>()), + ), + ), + ); +} + +export function _isAggregationMappingEditUrl(route: RouteData): boolean { + const urlSegments: UrlSegment[] = route.urlSegments; + return urlSegments.length === 2 && urlSegments[0].path === ROUTES.AGGREGATION_MAPPING && urlSegments[1].path !== 'neu'; +} + +export function _getAggregationMappingResourceByRoute( + repository: ResourceRepository, + route: RouteData, +): Observable<StateResource<AggregationMappingResource>> { + const uri: string = decodeUrlFromEmbedding(route.urlSegments[1].path); + return repository.getResource(uri).pipe(map((resource: AggregationMappingResource) => createStateResource(resource))); +} 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 index a4a02bfd7087b105a9d0d2dd816aa2b180a4db9c..6aea64156f045b33fd70c20aa2427aaebb4ece32 100644 --- 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 @@ -2,3 +2,7 @@ export enum AggregationMappingListLinkRel { LIST = 'aggregationMappings', SELF = 'self', } + +export enum AggregationMappingLinkRel { + SELF = 'self', +} diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.provider.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.provider.ts index 888d7154e81dbfe53fb7476e4de8835463de6d25..76d294de177ea685a3e9cbd849e5a032f5423101 100644 --- a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.provider.ts +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.provider.ts @@ -1,8 +1,13 @@ +import { NavigationService } from '@alfa-client/navigation-shared'; import { ResourceRepository } from '@alfa-client/tech-shared'; import { Provider } from '@angular/core'; import { ConfigurationService } from 'libs/admin/configuration-shared/src/lib/configuration.service'; import { AggregationMappingListResourceService, + createAggregationMappingListResourceService, +} from './aggregation-mapping-list-resource.service'; +import { + AggregationMappingResourceService, createAggregationMappingResourceService, } from './aggregation-mapping-resource.service'; import { AggregationMappingService } from './aggregation-mapping.service'; @@ -10,8 +15,13 @@ import { AggregationMappingService } from './aggregation-mapping.service'; export const AggregationMappingProvider: Provider[] = [ { provide: AggregationMappingListResourceService, - useFactory: createAggregationMappingResourceService, + useFactory: createAggregationMappingListResourceService, deps: [ResourceRepository, ConfigurationService], }, + { + provide: AggregationMappingResourceService, + useFactory: createAggregationMappingResourceService, + deps: [ResourceRepository, NavigationService], + }, AggregationMappingService, ]; diff --git a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.spec.ts b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.spec.ts index d00e6923b00a28a9022ac67bf1531555e852f713..0846feed2dc535c4cfa67dc22287013d45b967a0 100644 --- a/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.spec.ts +++ b/alfa-client/libs/admin/reporting-shared/src/lib/aggregation-mapping.service.spec.ts @@ -2,26 +2,33 @@ import { createStateResource, StateResource } from '@alfa-client/tech-shared'; import { Mock, mock } from '@alfa-client/test-utils'; import { TestBed } from '@angular/core/testing'; import { expect } from '@jest/globals'; -import { singleCold } from 'libs/tech-shared/test/marbles'; -import { Observable } from 'rxjs'; +import { singleCold, singleColdCompleted } from 'libs/tech-shared/test/marbles'; +import { Observable, of } from 'rxjs'; import { createAggregationMapping, createAggregationMappingListResource, createAggregationMappingResource, } from '../../test/aggregation-mapping'; -import { AggregationMappingListResourceService } from './aggregation-mapping-resource.service'; +import { AggregationMappingListResourceService } from './aggregation-mapping-list-resource.service'; +import { AggregationMappingResourceService } from './aggregation-mapping-resource.service'; import { AggregationMapping, AggregationMappingListResource, AggregationMappingResource } from './aggregation-mapping.model'; import { AggregationMappingService } from './aggregation-mapping.service'; describe('AggregationMappingService', () => { let service: AggregationMappingService; let listResourceService: Mock<AggregationMappingListResourceService>; + let resourceService: Mock<AggregationMappingResourceService>; beforeEach(() => { listResourceService = mock(AggregationMappingListResourceService); + resourceService = mock(AggregationMappingResourceService); TestBed.configureTestingModule({ - providers: [AggregationMappingService, { provide: AggregationMappingListResourceService, useValue: listResourceService }], + providers: [ + AggregationMappingService, + { provide: AggregationMappingListResourceService, useValue: listResourceService }, + { provide: AggregationMappingResourceService, useValue: resourceService }, + ], }); service = TestBed.inject(AggregationMappingService); @@ -87,4 +94,39 @@ describe('AggregationMappingService', () => { expect(listResourceService.refresh).toHaveBeenCalled(); }); }); + + describe('get by current url', () => { + const stateResource = createStateResource(createAggregationMappingResource()); + beforeEach(() => { + resourceService.get = jest.fn().mockReturnValue(of(stateResource)); + }); + + it('should call resource service', () => { + service.getByCurrentUrl(); + + expect(resourceService.get).toHaveBeenCalled(); + }); + + it('should emit resource', () => { + expect(service.getByCurrentUrl()).toBeObservable(singleColdCompleted(stateResource)); + }); + }); + + describe('save', () => { + const aggregationMapping: AggregationMapping = createAggregationMapping(); + const stateResource = createStateResource(createAggregationMappingResource()); + beforeEach(() => { + resourceService.save = jest.fn().mockReturnValue(of(stateResource)); + }); + + it('should call resource service', () => { + service.save(aggregationMapping); + + expect(resourceService.save).toHaveBeenCalledWith(aggregationMapping); + }); + + it('should emit saved state resource', () => { + expect(service.save(aggregationMapping)).toBeObservable(singleColdCompleted(stateResource)); + }); + }); }); 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 index 00402e238cce0455a7a0a25ced6fb70219216d24..19c85af76cad3ee04dd180d4bd7628271e9a3df5 100644 --- 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 @@ -1,12 +1,14 @@ import { StateResource } from '@alfa-client/tech-shared'; import { inject, Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { AggregationMappingListResourceService } from './aggregation-mapping-resource.service'; +import { AggregationMappingListResourceService } from './aggregation-mapping-list-resource.service'; +import { AggregationMappingResourceService } from './aggregation-mapping-resource.service'; import { AggregationMapping, AggregationMappingListResource, AggregationMappingResource } from './aggregation-mapping.model'; @Injectable() export class AggregationMappingService { - readonly listService = inject(AggregationMappingListResourceService); + private readonly listService = inject(AggregationMappingListResourceService); + private readonly resourceService = inject(AggregationMappingResourceService); public getList(): Observable<StateResource<AggregationMappingListResource>> { return this.listService.getList(); @@ -19,4 +21,12 @@ export class AggregationMappingService { public refreshList(): void { this.listService.refresh(); } + + public getByCurrentUrl(): Observable<StateResource<AggregationMappingResource>> { + return this.resourceService.get(); + } + + public save(aggregationMapping: AggregationMapping): Observable<StateResource<AggregationMappingResource>> { + return this.resourceService.save(aggregationMapping); + } } diff --git a/alfa-client/libs/admin/shared/src/lib/routes.ts b/alfa-client/libs/admin/shared/src/lib/routes.ts index 090a9f3a7d82d6c3489bfa5c542b31592c177e06..cf1a2212026d934f4f29b358a7a21b01164c811f 100644 --- a/alfa-client/libs/admin/shared/src/lib/routes.ts +++ b/alfa-client/libs/admin/shared/src/lib/routes.ts @@ -28,6 +28,7 @@ export enum ROUTES { BENUTZER_ID = 'benutzer/:userid', ORGANISATIONSEINHEITEN = 'organisationseinheiten', UNAVAILABLE = 'unavailable', - STATISTIK = 'statistik', - STATISTIK_NEU = 'statistik/neu', + AGGREGATION_MAPPING = 'aggregation-mapping', + AGGREGATION_MAPPING_NEU = 'aggregation-mapping/neu', + AGGREGATION_MAPPING_ID = 'aggregation-mapping/:aggregationMappingId', } diff --git a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.html b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.html index 931f6462619cd1420536a4715b500759de8a70ac..777c081ff0800b3fab3fb01dfd073dd9d770e8d0 100644 --- a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.html +++ b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.html @@ -1,4 +1,4 @@ -<ods-list-item [path]="" [attr.data-test-id]="aggregationMapping.name | convertForDataTest"> +<ods-list-item [path]="aggregationMapping | toResourceUri" [attr.data-test-id]="aggregationMapping.name | convertForDataTest"> <dl class="flex-1 font-semibold"> <dt class="sr-only">Name</dt> <dd data-test-class="fullname">{{ aggregationMapping.name }}</dd> diff --git a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.spec.ts index 7e48ac908db1d0c99b9357fd4744db48841268ff..18d620f575972e8fea06ee9982c0e06d43216f58 100644 --- a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.spec.ts +++ b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.spec.ts @@ -1,21 +1,42 @@ +import { AggregationMappingResource } from '@admin-client/reporting-shared'; +import { ToResourceUriPipe } from '@alfa-client/tech-shared'; +import { getElementFromFixtureByType } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { expect } from '@jest/globals'; +import { ListItemComponent } from '@ods/system'; +import { MockComponent } from 'ng-mocks'; +import { createAggregationMappingResource } from '../../../../../reporting-shared/test/aggregation-mapping'; import { AggregationMappingListItemComponent } from './aggregation-mapping-list-item.component'; describe('AggregationMappingListItemComponent', () => { let component: AggregationMappingListItemComponent; let fixture: ComponentFixture<AggregationMappingListItemComponent>; + const toResourceUriPipe: ToResourceUriPipe = new ToResourceUriPipe(); + const aggregationMappingResource: AggregationMappingResource = createAggregationMappingResource(); + beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [AggregationMappingListItemComponent], + imports: [AggregationMappingListItemComponent, ToResourceUriPipe, MockComponent(ListItemComponent)], }).compileComponents(); fixture = TestBed.createComponent(AggregationMappingListItemComponent); component = fixture.componentInstance; + component.aggregationMapping = aggregationMappingResource; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); + + describe('template', () => { + describe('list item', () => { + it('should have inputs', () => { + const comp: ListItemComponent = getElementFromFixtureByType(fixture, ListItemComponent); + + expect(comp.path).toEqual(toResourceUriPipe.transform(aggregationMappingResource)); + }); + }); + }); }); diff --git a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.ts b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.ts index c022babf739f7b4028ad13adbad87ff078e01082..6880096a779fa36e88b62dba199d952c7d34d9c7 100644 --- a/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.ts +++ b/alfa-client/libs/admin/statistik/src/lib/aggregation-mapping-list/aggregation-mapping-list-item/aggregation-mapping-list-item.component.ts @@ -1,5 +1,5 @@ import { AggregationMappingResource } from '@admin-client/reporting-shared'; -import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; +import { ConvertForDataTestPipe, ToResourceUriPipe } from '@alfa-client/tech-shared'; import { Component, Input } from '@angular/core'; import { ListItemComponent } from '@ods/system'; @@ -7,7 +7,7 @@ import { ListItemComponent } from '@ods/system'; selector: 'admin-aggregation-mapping-list-item', standalone: true, templateUrl: './aggregation-mapping-list-item.component.html', - imports: [ConvertForDataTestPipe, ListItemComponent], + imports: [ConvertForDataTestPipe, ListItemComponent, ToResourceUriPipe], styles: [':host {@apply block}'], }) export class AggregationMappingListItemComponent { 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 bd98c2aaea1352190b8720b6804999d16368a686..434802447a84d958df25655e23f35e255746effb 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 @@ -26,7 +26,7 @@ <h1 class="heading-1" data-test-id="statistik-header-text">Statistik</h1> <ods-routing-button class="my-4 w-fit" - [linkPath]="ROUTES.STATISTIK_NEU" + [linkPath]="ROUTES.AGGREGATION_MAPPING_NEU" text="Weitere Felder auswerten" dataTestId="weitere-felder-auswerten-button" /> diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.html b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.html index f81771fedaf501971ef73be12b7b34bad5ac7fa4..84f59729b87800db58a80cbd887a46bba3970278 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.html +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.html @@ -1,43 +1,45 @@ <h2 class="heading-2" data-test-id="statistik-fields-form-header-text">Felder zur Auswertung hinzufügen</h2> -<div class="flex max-w-4xl flex-col gap-4"> - <form class="form flex-col" [formGroup]="formService.form" class="flex flex-col gap-2"> - <ods-text-editor - [formControlName]="StatistikFieldsFormService.FIELD_NAME" - label="Name *" - placeholder="" - data-test-id="statistik-name-text-editor" - dataTestId="statistik-name" - ></ods-text-editor> - <div [formGroupName]="StatistikFieldsFormService.FIELD_FORM_IDENTIFIER" class="flex flex-col gap-4"> +<ods-spinner [stateResource]="aggregationMappingStateResource$ | async"> + <div class="flex max-w-4xl flex-col gap-4"> + <form class="form flex-col" [formGroup]="formService.form" class="flex flex-col gap-2"> <ods-text-editor - [formControlName]="StatistikFieldsFormService.FIELD_FORM_ENGINE_NAME" - label="Formengine *" - placeholder="Tragen Sie hier die Formengine des Formulars ein." - data-test-id="form-engine-name" - dataTestId="form-engine-name" + [formControlName]="StatistikFieldsFormService.FIELD_NAME" + label="Name *" + placeholder="" + data-test-id="statistik-name-text-editor" + dataTestId="statistik-name" ></ods-text-editor> - <ods-text-editor - [formControlName]="StatistikFieldsFormService.FIELD_FORM_ID" - label="FormID *" - placeholder="Tragen Sie hier die FormID des Formulars ein." - data-test-id="form-id" - dataTestId="form-id" - ></ods-text-editor> - </div> - <admin-statistik-fields-form-mapping /> - </form> - <ods-button - text="Datenfeld hinzufügen" - dataTestId="add-mapping-button" - data-test-id="add-mapping" - (clickEmitter)="formService.addMapping()" - > - <ods-plus-icon icon class="fill-whitetext" /> - </ods-button> + <div [formGroupName]="StatistikFieldsFormService.FIELD_FORM_IDENTIFIER" class="flex flex-col gap-4"> + <ods-text-editor + [formControlName]="StatistikFieldsFormService.FIELD_FORM_ENGINE_NAME" + label="Formengine *" + placeholder="Tragen Sie hier die Formengine des Formulars ein." + data-test-id="form-engine-name" + dataTestId="form-engine-name" + ></ods-text-editor> + <ods-text-editor + [formControlName]="StatistikFieldsFormService.FIELD_FORM_ID" + label="FormID *" + placeholder="Tragen Sie hier die FormID des Formulars ein." + data-test-id="form-id" + dataTestId="form-id" + ></ods-text-editor> + </div> + <admin-statistik-fields-form-mapping /> + </form> + <ods-button + text="Datenfeld hinzufügen" + dataTestId="add-mapping-button" + data-test-id="add-mapping" + (clickEmitter)="formService.addMapping()" + > + <ods-plus-icon icon class="fill-whitetext" /> + </ods-button> - <div class="mt-4 flex gap-4"> - <admin-save-button [successLinkPath]="Routes.STATISTIK" /> - <admin-cancel-button [linkPath]="Routes.STATISTIK" /> + <div class="mt-4 flex gap-4"> + <admin-save-button [successLinkPath]="Routes.AGGREGATION_MAPPING" /> + <admin-cancel-button [linkPath]="Routes.AGGREGATION_MAPPING" /> + </div> </div> -</div> +</ods-spinner> diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.spec.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.spec.ts index fc823f9d6c91b1c46c8fd4a96ca5f3acf90854ee..5dc2a0eafa7308b02ec56dac0011b9866e507cf2 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.spec.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.spec.ts @@ -1,12 +1,24 @@ -import { ADMIN_FORMSERVICE } from '@admin-client/shared'; -import { EMPTY_STRING } from '@alfa-client/tech-shared'; -import { dispatchEventFromFixture, existsAsHtmlElement, mock, Mock, MockEvent } from '@alfa-client/test-utils'; +import { AggregationMappingResource } from '@admin-client/reporting-shared'; +import { ADMIN_FORMSERVICE, ROUTES } from '@admin-client/shared'; +import { createStateResource, EMPTY_STRING, StateResource } from '@alfa-client/tech-shared'; +import { + dispatchEventFromFixture, + existsAsHtmlElement, + getElementFromFixtureByType, + mock, + Mock, + MockEvent, +} from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; +import { expect } from '@jest/globals'; import { TextEditorComponent } from '@ods/component'; import { ButtonComponent, PlusIconComponent } from '@ods/system'; import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; import { getDataTestIdOf } from '../../../../../tech-shared/test/data-test'; +import { singleColdCompleted } from '../../../../../tech-shared/test/marbles'; +import { createAggregationMappingResource } from '../../../../reporting-shared/test/aggregation-mapping'; import { AdminCancelButtonComponent } from '../../../../shared/src/lib/admin-cancel-button/admin-cancel-button.component'; import { AdminSaveButtonComponent } from '../../../../shared/src/lib/admin-save-button/admin-save-button.component'; import { StatistikFieldsFormComponent } from './statistik-fields-form.component'; @@ -21,6 +33,10 @@ describe('AdminStatistikFieldsFormComponent', () => { const formIdInputTestId: string = getDataTestIdOf('form-id'); const addMappingButton: string = getDataTestIdOf('add-mapping'); + const aggregationMappingStateResource: StateResource<AggregationMappingResource> = createStateResource( + createAggregationMappingResource(), + ); + const formBuilder: FormBuilder = new FormBuilder(); let formService: Mock<StatistikFieldsFormService>; @@ -35,6 +51,7 @@ describe('AdminStatistikFieldsFormComponent', () => { }); formService = <any>{ ...mock(StatistikFieldsFormService), form }; + formService.get = jest.fn().mockReturnValue(of(aggregationMappingStateResource)); await TestBed.configureTestingModule({ imports: [ @@ -73,6 +90,16 @@ describe('AdminStatistikFieldsFormComponent', () => { expect(component).toBeTruthy(); }); + describe('component', () => { + it('should get aggregation mapping from form service', () => { + expect(formService.get).toHaveBeenCalled(); + }); + + it('should initial values', () => { + expect(component.aggregationMappingStateResource$).toBeObservable(singleColdCompleted(aggregationMappingStateResource)); + }); + }); + describe('template', () => { describe('form engine input', () => { it('should exists', () => { @@ -109,5 +136,21 @@ describe('AdminStatistikFieldsFormComponent', () => { }); }); }); + + describe('save button', () => { + it('should have link path', () => { + const comp: AdminSaveButtonComponent = getElementFromFixtureByType(fixture, AdminSaveButtonComponent); + + expect(comp.successLinkPath).toEqual(ROUTES.AGGREGATION_MAPPING); + }); + }); + + describe('cancel button', () => { + it('should have link path', () => { + const comp: AdminCancelButtonComponent = getElementFromFixtureByType(fixture, AdminCancelButtonComponent); + + expect(comp.linkPath).toEqual(ROUTES.AGGREGATION_MAPPING); + }); + }); }); }); diff --git a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.ts b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.ts index bd10b259535147a21ed8f6a1913e2365a23a7c1b..9709c01258eddc3fe1cbd5d40854511868e759b4 100644 --- a/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.ts +++ b/alfa-client/libs/admin/statistik/src/lib/statistik-fields-form/statistik-fields-form.component.ts @@ -1,8 +1,12 @@ +import { AggregationMappingResource } from '@admin-client/reporting-shared'; import { ADMIN_FORMSERVICE, AdminCancelButtonComponent, AdminSaveButtonComponent, ROUTES } from '@admin-client/shared'; +import { StateResource } from '@alfa-client/tech-shared'; +import { AsyncPipe } from '@angular/common'; import { Component, inject } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; -import { TextEditorComponent } from '@ods/component'; +import { SpinnerComponent, TextEditorComponent } from '@ods/component'; import { ButtonComponent, PlusIconComponent } from '@ods/system'; +import { Observable } from 'rxjs'; import { StatistikFieldsMappingsFormComponent } from './statistik-fields-mappings-form/statistik-fields-mappings-form.component'; import { StatistikFieldsFormService } from './statistik-fields.formservice'; @@ -18,12 +22,17 @@ import { StatistikFieldsFormService } from './statistik-fields.formservice'; AdminSaveButtonComponent, AdminCancelButtonComponent, StatistikFieldsMappingsFormComponent, + SpinnerComponent, + AsyncPipe, ], providers: [{ provide: ADMIN_FORMSERVICE, useClass: StatistikFieldsFormService }], }) export class StatistikFieldsFormComponent { public readonly formService = <StatistikFieldsFormService>inject(ADMIN_FORMSERVICE); + public readonly aggregationMappingStateResource$: Observable<StateResource<AggregationMappingResource>> = + this.formService.get(); + public readonly StatistikFieldsFormService = StatistikFieldsFormService; public readonly Routes = ROUTES; } 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 index 2bb935d50ef36a1f94a13b522dd2d1e9c4f42179..45f57f4befa81655cdf9ceead88734d1586edb44 100644 --- 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 @@ -26,8 +26,11 @@ import { createStateResource, EMPTY_STRING, StateResource } from '@alfa-client/t import { Mock, mock } from '@alfa-client/test-utils'; import { TestBed } from '@angular/core/testing'; import { FormArray, FormControl, FormGroup } from '@angular/forms'; +import { expect } from '@jest/globals'; import { createAggregationMapping, createAggregationMappingResource } from 'libs/admin/reporting-shared/test/aggregation-mapping'; +import { omit } from 'lodash-es'; import { of } from 'rxjs'; +import { singleColdCompleted } from '../../../../../tech-shared/test/marbles'; import { StatistikFieldsFormService } from './statistik-fields.formservice'; describe('StatistikFieldsFormService', () => { @@ -54,15 +57,26 @@ describe('StatistikFieldsFormService', () => { beforeEach(() => { service.create.mockReturnValue(of(stateResource)); + service.save.mockReturnValue(of(stateResource)); }); - it('should call service', () => { + it('should create', () => { + formService.isPatch = jest.fn().mockReturnValue(false); formService.form = <any>createAggregationMapping(); formService.submit(); expect(service.create).toHaveBeenCalledWith(formService.form.value); }); + + it('should save', () => { + formService.isPatch = jest.fn().mockReturnValue(true); + formService.form = <any>createAggregationMapping(); + + formService.submit(); + + expect(service.save).toHaveBeenCalledWith(formService.form.value); + }); }); describe('add mapping', () => { @@ -109,4 +123,39 @@ describe('StatistikFieldsFormService', () => { }); }); }); + + describe('get', () => { + const stateResource: StateResource<AggregationMappingResource> = createStateResource(createAggregationMappingResource()); + + beforeEach(() => { + service.getByCurrentUrl.mockReturnValue(of(stateResource)); + formService._patchForm = jest.fn(); + }); + + it('should get by current url', () => { + formService.get(); + + expect(service.getByCurrentUrl).toHaveBeenCalled(); + }); + + it('should patch form', () => { + formService.get().subscribe(); + + expect(formService._patchForm).toHaveBeenCalledWith(stateResource.resource); + }); + + it('should emit state resource', () => { + expect(formService.get()).toBeObservable(singleColdCompleted(stateResource)); + }); + }); + + describe('patch form', () => { + const aggregationMappingResource: AggregationMappingResource = createAggregationMappingResource(); + + it('should patch', () => { + formService._patchForm(aggregationMappingResource); + + expect(formService.form.value).toEqual(omit(aggregationMappingResource, '_links')); + }); + }); }); 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 67ecb47a0b7b37eda30cbcb22e9c4ceaadbc921c..75d717dbc1c6290e86d95a5193a9ea99cf6d5384 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,8 +1,8 @@ -import { AggregationMappingResource, AggregationMappingService } from '@admin-client/reporting-shared'; -import { AbstractFormService, EMPTY_STRING, StateResource } from '@alfa-client/tech-shared'; +import { AggregationMappingResource, AggregationMappingService, FieldMapping } from '@admin-client/reporting-shared'; +import { AbstractFormService, EMPTY_STRING, isLoaded, StateResource } from '@alfa-client/tech-shared'; import { inject, Injectable } from '@angular/core'; import { FormArray, FormControl, FormGroup, UntypedFormGroup } from '@angular/forms'; -import { Observable } from 'rxjs'; +import { filter, Observable, tap } from 'rxjs'; @Injectable() export class StatistikFieldsFormService extends AbstractFormService<AggregationMappingResource> { @@ -14,7 +14,7 @@ export class StatistikFieldsFormService extends AbstractFormService<AggregationM public static readonly FIELD_MAPPING_SOURCE_PATH = 'sourcePath'; public static readonly FIELD_MAPPING_TARGET_PATH = 'targetPath'; - private service = inject(AggregationMappingService); + private readonly aggregationMappingService = inject(AggregationMappingService); protected initForm(): UntypedFormGroup { return this.formBuilder.group({ @@ -28,7 +28,10 @@ export class StatistikFieldsFormService extends AbstractFormService<AggregationM } protected doSubmit(): Observable<StateResource<AggregationMappingResource>> { - return this.service.create(this.getFormValue()); + if (this.isPatch()) { + return this.aggregationMappingService.save(this.getFormValue()); + } + return this.aggregationMappingService.create(this.getFormValue()); } protected getPathPrefix(): string { @@ -39,10 +42,10 @@ export class StatistikFieldsFormService extends AbstractFormService<AggregationM this.mappings.push(this.createArrayControl()); } - private createArrayControl(): FormGroup { + private createArrayControl(sourcePath: string = EMPTY_STRING, targetPath: string = EMPTY_STRING): FormGroup { return new FormGroup({ - [StatistikFieldsFormService.FIELD_MAPPING_SOURCE_PATH]: new FormControl(EMPTY_STRING), - [StatistikFieldsFormService.FIELD_MAPPING_TARGET_PATH]: new FormControl(EMPTY_STRING), + [StatistikFieldsFormService.FIELD_MAPPING_SOURCE_PATH]: new FormControl(sourcePath), + [StatistikFieldsFormService.FIELD_MAPPING_TARGET_PATH]: new FormControl(targetPath), }); } @@ -53,4 +56,20 @@ export class StatistikFieldsFormService extends AbstractFormService<AggregationM public get mappings(): FormArray { return this.form.controls[StatistikFieldsFormService.FIELD_MAPPINGS] as FormArray; } + + public get(): Observable<StateResource<AggregationMappingResource>> { + return this.aggregationMappingService.getByCurrentUrl().pipe( + filter(isLoaded), + tap((stateResource: StateResource<AggregationMappingResource>) => this._patchForm(stateResource.resource)), + ); + } + + _patchForm(value: AggregationMappingResource): void { + this.patch(value); + const mappingsFormArray: FormArray = this.form.controls[StatistikFieldsFormService.FIELD_MAPPINGS] as FormArray; + mappingsFormArray.clear(); + value.mappings.forEach((mapping: FieldMapping) => + mappingsFormArray.push(this.createArrayControl(mapping.sourcePath, mapping.targetPath)), + ); + } }