diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts index c9b80fe49d0d2389e5d647eac7bceb37dd55f7b3..38a32fe726c44d6f7c0152e0caec38bfb8c90791 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.spec.ts @@ -315,6 +315,17 @@ describe('VorgangDetailBescheidenResultAttachmentsComponent', () => { expect(component.uploadedAttachments).toEqual([]); }); + it('should leave errors in uploaded', () => { + const error: StateResource<BinaryFileResource> = createStateResource( + createBinaryFileResource(), + ); + component.uploadedAttachments = [error]; + + component.deleteFile(uploadedAttachmentStateResource.resource); + + expect(component.uploadedAttachments).toEqual([error]); + }); + it('should not delete attachment from existing', () => { component.uploadedAttachments = [uploadedAttachmentStateResource]; component.existingAttachments = [existingAttachment]; diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.ts index 084a5361b9ec8460e5cc0f518aeacb535cb47cf9..896a94a92a3a4ca65357269d66de5b83ce1d1730 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result-attachments/vorgang-detail-bescheiden-result-attachments.component.ts @@ -1,16 +1,16 @@ import { BescheidService, UploadFileInProgress } from '@alfa-client/bescheid-shared'; import { BinaryFileResource } from '@alfa-client/binary-file-shared'; import { - StateResource, containsLoading, getSuccessfullyLoaded, hasStateResourceError, isLoaded, isNotNil, + StateResource, } from '@alfa-client/tech-shared'; import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { getUrl } from '@ngxp/rest'; -import { Observable, Subscription, first } from 'rxjs'; +import { first, Observable, Subscription } from 'rxjs'; import { BescheidenFormService } from '../../bescheiden.formservice'; @Component({ @@ -76,10 +76,11 @@ export class VorgangDetailBescheidenResultAttachmentsComponent implements OnDest deleteFile(file: BinaryFileResource): void { this.formService.deleteFile(file); this.uploadedAttachments = this.uploadedAttachments.filter( - (attachment) => getUrl(attachment.resource) !== getUrl(file), + (attachment: StateResource<BinaryFileResource>) => + !hasStateResourceError(attachment) && getUrl(attachment.resource) !== getUrl(file), ); this.existingAttachments = this.existingAttachments.filter( - (attachment) => getUrl(attachment) !== getUrl(file), + (attachment: BinaryFileResource) => getUrl(attachment) !== getUrl(file), ); } } diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts index 4544ff07bbd8a19741c55ccd326b04b64f03fa0c..23297899303c64bb69860ac833aa1ef30de1299a 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.spec.ts @@ -51,11 +51,12 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatIcon } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { NavigationEnd, Router, RouterEvent } from '@angular/router'; import { RouterTestingModule } from '@angular/router/testing'; import { getDataTestClassOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { createVorgangListResource } from 'libs/vorgang-shared/test/vorgang'; import { MockComponent } from 'ng-mocks'; -import { BehaviorSubject, Subject, of } from 'rxjs'; +import { BehaviorSubject, ReplaySubject, Subject, of } from 'rxjs'; import { VorgangSearchAutocompleteOptionsContentComponent } from './vorgang-search-autocomplete-options-content/vorgang-search-autocomplete-options-content.component'; import { VorgangSearchClearButtonComponent } from './vorgang-search-clear-button/vorgang-search-clear-button.component'; import { VorgangSearchComponent } from './vorgang-search.component'; @@ -71,6 +72,13 @@ describe('VorgangSearchComponent', () => { const searchStringSubj: Subject<string> = new BehaviorSubject(EMPTY_STRING); + const routerEvents: ReplaySubject<RouterEvent> = new ReplaySubject<RouterEvent>(); + const routerMock = { + navigate: jest.fn(), + url: '/', + events: routerEvents.asObservable(), + }; + const searchPreviewOption: string = getDataTestClassOf('search-preview-option'); const searchClearButton: string = getDataTestIdOf('vorgang-search-clear-button'); @@ -116,6 +124,10 @@ describe('VorgangSearchComponent', () => { provide: NavigationService, useValue: navigationService, }, + { + provide: Router, + useValue: routerMock, + }, ], }).compileComponents(); }); @@ -154,6 +166,26 @@ describe('VorgangSearchComponent', () => { }); }); + describe('ngOnInit', () => { + it('should set focus if path is "/alle/search"', () => { + component.focus = jest.fn(); + routerEvents.next(new NavigationEnd(1, '/alle/search', '')); + + component.ngOnInit(); + + expect(component.focus).toHaveBeenCalled(); + }); + + it('should not set focus if path is not "/alle/search"', () => { + component.focus = jest.fn(); + routerEvents.next(new NavigationEnd(1, '/alle', '')); + + component.ngOnInit(); + + expect(component.focus).toHaveBeenCalled(); + }); + }); + describe('search clear button', () => { beforeEach(() => { searchStringSubj.next('test'); diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts index cccfbaf8d41ff25b10b39d5643c5e1dfc29c057f..5375e849b6359a8ba54dd883b83ed8da5daae844 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-search-container/vorgang-search/vorgang-search.component.ts @@ -21,15 +21,27 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; -import { MatAutocomplete } from '@angular/material/autocomplete'; -import { MatButton } from '@angular/material/button'; import { StateResource, isNotNil } from '@alfa-client/tech-shared'; import { VorgangHeaderLinkRel, VorgangListLinkRel, VorgangListResource, } from '@alfa-client/vorgang-shared'; +import { + Component, + ElementRef, + EventEmitter, + Input, + OnDestroy, + OnInit, + Output, + ViewChild, +} from '@angular/core'; +import { MatAutocomplete } from '@angular/material/autocomplete'; +import { MatButton } from '@angular/material/button'; +import { Event, NavigationEnd, Router } from '@angular/router'; +import { Subscription, filter } from 'rxjs'; +import { isVorgangSearchRoute } from '../../vorgang-util'; import { VorgangSearchFormService } from './vorgang-search.formservice'; @Component({ @@ -38,7 +50,7 @@ import { VorgangSearchFormService } from './vorgang-search.formservice'; styleUrls: ['./vorgang-search.component.scss'], providers: [VorgangSearchFormService], }) -export class VorgangSearchComponent { +export class VorgangSearchComponent implements OnInit, OnDestroy { @Input() vorgangSearchPreviewList: StateResource<VorgangListResource>; @Input() searchString: string; @@ -49,11 +61,25 @@ export class VorgangSearchComponent { @ViewChild('searchAutoComplete') searchAutoComplete: MatAutocomplete; previouslyEnteredSearchValue: string; + private subscription: Subscription; readonly vorgangHeaderLinkRel = VorgangHeaderLinkRel; readonly vorgangListLinkRel = VorgangListLinkRel; - constructor(public formService: VorgangSearchFormService) {} + constructor( + public formService: VorgangSearchFormService, + public router: Router, + ) {} + + ngOnInit(): void { + this.subscription = this.router.events + .pipe(filter((event: Event) => event instanceof NavigationEnd)) + .subscribe((navigationEnd: Event) => { + if (isVorgangSearchRoute(navigationEnd as NavigationEnd)) { + this.focus(); + } + }); + } submit(): void { this.previouslyEnteredSearchValue = this.formService.getValue(); @@ -93,4 +119,8 @@ export class VorgangSearchComponent { focus(): void { this.searchInput.nativeElement.focus(); } + + ngOnDestroy(): void { + this.subscription.unsubscribe(); + } } diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-util.spec.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-util.spec.ts index 41d1e94862b57a486bf7129415a25a1906781dc3..867a4a51f1399adad41ea276aeee32749513d983 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-util.spec.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-util.spec.ts @@ -23,6 +23,7 @@ */ import { EMPTY_STRING } from '@alfa-client/tech-shared'; import { Antragsteller, Vorgang, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { NavigationEnd } from '@angular/router'; import { createAntragsteller, createEingang, @@ -33,6 +34,7 @@ import { VORGANG_KEIN_AKTENZEICHEN_ZUGEWIESEN, getAktenzeichenText, getEmpfaenger, + isVorgangSearchRoute, } from './vorgang-util'; describe('Vorgang Util', () => { @@ -54,6 +56,24 @@ describe('Vorgang Util', () => { }); }); + describe('isSearchRoute', () => { + it('should return true', () => { + const searchNavigationEnd: NavigationEnd = new NavigationEnd(1, '/alle/search', ''); + + const result: boolean = isVorgangSearchRoute(searchNavigationEnd); + + expect(result).toBeTruthy(); + }); + + it('should return false', () => { + const notSearchNavigationEnd: NavigationEnd = new NavigationEnd(1, '/alle', ''); + + const result: boolean = isVorgangSearchRoute(notSearchNavigationEnd); + + expect(result).toBeTruthy(); + }); + }); + describe('getEmpfaenger', () => { it('should return nachname only if exists', () => { const antragsteller: Antragsteller = { ...createAntragsteller(), vorname: undefined }; diff --git a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-util.ts b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-util.ts index 5d90f07fe9a46e9c19ab44294aab7ffb32f7138b..1181194c857b55b3f777de544d53f1fc4ba1d2f3 100644 --- a/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-util.ts +++ b/alfa-client/libs/vorgang-shared-ui/src/lib/vorgang-util.ts @@ -23,6 +23,7 @@ */ import { EMPTY_STRING } from '@alfa-client/tech-shared'; import { Vorgang, VorgangWithEingangResource } from '@alfa-client/vorgang-shared'; +import { NavigationEnd } from '@angular/router'; export const VORGANG_KEIN_AKTENZEICHEN_ZUGEWIESEN = 'kein Aktenzeichen'; @@ -34,6 +35,10 @@ export function getEmpfaenger(vorgangWithEingangResource: VorgangWithEingangReso return `${getVorname(vorgangWithEingangResource)} ${getNachname(vorgangWithEingangResource)}`.trim(); } +export function isVorgangSearchRoute(navigationEnd: NavigationEnd): boolean { + return navigationEnd.url === '/alle/search'; +} + function getVorname(vorgangWithEingangResource: VorgangWithEingangResource): string { return vorgangWithEingangResource.eingang.antragsteller?.vorname ?? EMPTY_STRING; } diff --git a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/bescheid/ExportBescheidServiceTest.java b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/bescheid/ExportBescheidServiceTest.java index 3b8a9878a24a136481d83652ff7ab0f61090932c..bd8d907e7cc79c9830cebdcb81e4061609657396 100644 --- a/alfa-xdomea/src/test/java/de/ozgcloud/alfa/bescheid/ExportBescheidServiceTest.java +++ b/alfa-xdomea/src/test/java/de/ozgcloud/alfa/bescheid/ExportBescheidServiceTest.java @@ -298,7 +298,7 @@ class ExportBescheidServiceTest { class TestBuildDokumentType { private final BescheidExportInput exportInput = BescheidExportInputTestFactory.create(); private final Bescheid bescheid = BescheidExportInputTestFactory.BESCHEID; - private final List<OzgFile> attachments = BescheidExportInputTestFactory.FILES; + private final List<OzgFile> files = BescheidExportInputTestFactory.FILES; private final String fullName = UserProfileTestFactory.FULLNAME; private MockedStatic<DokumentTypeBuilder> dokumentTypeBuilderMockedStatic; @@ -311,7 +311,7 @@ class ExportBescheidServiceTest { dokumentTypeBuilderMockedStatic.when(DokumentTypeBuilder::builder).thenReturn(dokumentTypeBuilder); when(dokumentTypeBuilder.withBescheid(bescheid)).thenReturn(dokumentTypeBuilder); - when(dokumentTypeBuilder.withFiles(attachments)).thenReturn(dokumentTypeBuilder); + when(dokumentTypeBuilder.withFiles(files)).thenReturn(dokumentTypeBuilder); when(dokumentTypeBuilder.withFullName(fullName)).thenReturn(dokumentTypeBuilder); when(dokumentTypeBuilder.withOrganisationseinheitenId(BescheidExportInputTestFactory.ORGANISATIONSEINHEITEN_ID)) .thenReturn(dokumentTypeBuilder); @@ -342,7 +342,7 @@ class ExportBescheidServiceTest { void shouldBuildWithOzgFiles() { callService(); - verify(dokumentTypeBuilder).withFiles(attachments); + verify(dokumentTypeBuilder).withFiles(files); } @Test