diff --git a/CHANGELOG.md b/CHANGELOG.md index f9a87f3a2d..27b8efba39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Support for JustInSequence Semantice data model in FE - Added country flags icons to manufacturing Country - new submodelserver related API endpoints for data provisioning /api/submodel/data/{id} +- Added global search field to other parts +- Added possiblity to provide multiple semanticDataModels in filter +- Added two new columns for amount of open Notifications per part in part views (asBuilt) ### Changed - updated IRS helm chart from 6.6.1 to 6.7.2 diff --git a/DEPENDENCIES_FRONTEND b/DEPENDENCIES_FRONTEND index a73b31e670..0a768061f8 100644 --- a/DEPENDENCIES_FRONTEND +++ b/DEPENDENCIES_FRONTEND @@ -1514,12 +1514,12 @@ npm/npmjs/@types/range-parser/1.2.4, MIT, approved, #10795 npm/npmjs/@types/retry/0.12.0, MIT, approved, clearlydefined npm/npmjs/@types/semver/7.3.13, MIT, approved, #4668 npm/npmjs/@types/send/0.17.1, MIT, approved, #10832 -npm/npmjs/@types/serve-index/1.9.1, MIT, approved, clearlydefined +npm/npmjs/@types/serve-index/1.9.1, MIT, approved, #10976 npm/npmjs/@types/serve-static/1.15.1, MIT, approved, #9188 npm/npmjs/@types/set-cookie-parser/2.4.2, MIT, approved, clearlydefined npm/npmjs/@types/sinonjs__fake-timers/8.1.1, MIT, approved, clearlydefined npm/npmjs/@types/sizzle/2.3.3, MIT, approved, clearlydefined -npm/npmjs/@types/sockjs/0.3.33, MIT, approved, clearlydefined +npm/npmjs/@types/sockjs/0.3.33, MIT, approved, #10984 npm/npmjs/@types/testing-library__jasmine-dom/1.3.0, MIT, approved, clearlydefined npm/npmjs/@types/uuid/8.3.4, MIT, approved, clearlydefined npm/npmjs/@types/ws/8.5.4, MIT, approved, #6016 diff --git a/charts/traceability-foss/Chart.yaml b/charts/traceability-foss/Chart.yaml index adea7a26e8..8eb60cbd6f 100644 --- a/charts/traceability-foss/Chart.yaml +++ b/charts/traceability-foss/Chart.yaml @@ -42,7 +42,7 @@ dependencies: condition: pgadmin4.enabled - name: irs-helm repository: https://eclipse-tractusx.github.io/item-relationship-service - version: 6.7.2 + version: 6.8.0 condition: irs-helm.enabled - name: tractusx-connector repository: https://eclipse-tractusx.github.io/tractusx-edc diff --git a/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.model.ts b/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.model.ts index 17fd0366da..bdf17103bc 100644 --- a/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.model.ts +++ b/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.model.ts @@ -63,7 +63,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:0733946c-59c6-41ae-9570-cb43a6e43842", @@ -93,7 +95,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:4a5e9ff6-2d5c-4510-a90e-d55af3ba502f", @@ -131,7 +135,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:1be6ec59-40fb-4993-9836-acb0e284fa03", @@ -166,7 +172,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:1be6ec59-40fb-4993-9836-acb0e284fa01", @@ -196,7 +204,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:d8030bbf-a874-49fb-b2e1-7610f0ccad12", @@ -231,7 +241,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2015-03-07T18:38:12" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:5205f736-8fc2-4585-b869-6bf36842369a", @@ -261,7 +273,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:1be6ec59-40fb-4993-9836-acb0e284fa02", @@ -296,7 +310,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:1be6ec59-40fb-4993-9836-acb0e284fb01", @@ -326,7 +342,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:6b2296cc-26c0-4f38-8a22-092338c36e22", @@ -361,7 +379,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2018-09-28T02:15:57" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:c47b9f8b-48d0-4ef4-8f0b-e965a225cb8d", @@ -391,7 +411,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:f11ddc62-3bd5-468f-b7b0-110fe13ed0cd", @@ -421,7 +443,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:1be6ec59-40fb-4993-9836-acb0e284fb02", @@ -451,7 +475,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, { "id": "urn:uuid:7eeeac86-7b69-444d-81e6-655d0f1513bd", @@ -481,7 +507,9 @@ export const mockBmwAssets = [ "manufacturingDate": "2022-02-04T13:48:54" } } - ] + ], + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }, ] as PartResponse[]; @@ -512,7 +540,9 @@ const MockEmptyPart: PartResponse = { underInvestigation: false, qualityType: QualityType.Ok, van: null, - semanticDataModel: SemanticDataModel.SERIALPART + semanticDataModel: SemanticDataModel.SERIALPART, + qualityAlertsInStatusActive: 0, + qualityInvestigationsInStatusActive: 0, }; diff --git a/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.test.model.ts b/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.test.model.ts index de930bb0dd..08a9303ac9 100644 --- a/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.test.model.ts +++ b/frontend/src/app/mocks/services/parts-mock/partsAsBuilt/partsAsBuilt.test.model.ts @@ -51,7 +51,9 @@ export const MOCK_part_5 = { "manufacturingDate": "2022-02-04T13:48:54", } } - ] + ], + 'qualityAlertsInStatusActive': 0, + 'qualityInvestigationsInStatusActive': 0, }; export const MOCK_part_4 = { @@ -87,7 +89,9 @@ export const MOCK_part_4 = { "manufacturingDate": "2022-02-04T13:48:54", } } - ] + ], + 'qualityAlertsInStatusActive': 0, + 'qualityInvestigationsInStatusActive': 0, }; export const MOCK_part_3 = { @@ -124,7 +128,9 @@ export const MOCK_part_3 = { "manufacturingDate": "2022-02-04T13:48:54", } } - ] + ], + 'qualityAlertsInStatusActive': 0, + 'qualityInvestigationsInStatusActive': 0, }; export const MOCK_part_2 = { @@ -165,7 +171,9 @@ export const MOCK_part_2 = { "manufacturingDate": "2022-02-04T13:48:54", } } - ] + ], + 'qualityAlertsInStatusActive': 0, + 'qualityInvestigationsInStatusActive': 0, }; export const MOCK_part_1 = { @@ -203,7 +211,9 @@ export const MOCK_part_1 = { "manufacturingDate": "2022-02-04T13:48:54", } } - ] + ], + 'qualityAlertsInStatusActive': 0, + 'qualityInvestigationsInStatusActive': 0, }; export const mockAssets: PartsResponse = { diff --git a/frontend/src/app/modules/page/other-parts/core/other-parts.facade.ts b/frontend/src/app/modules/page/other-parts/core/other-parts.facade.ts index 7ae4809717..40dad28e82 100644 --- a/frontend/src/app/modules/page/other-parts/core/other-parts.facade.ts +++ b/frontend/src/app/modules/page/other-parts/core/other-parts.facade.ts @@ -60,33 +60,33 @@ export class OtherPartsFacade { } // TODO: remove OtherPartsService and integrate in PartService - public setCustomerPartsAsBuilt(page = 0, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: AssetAsBuiltFilter): void { + public setCustomerPartsAsBuilt(page = 0, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: AssetAsBuiltFilter, isOrSearch?: boolean): void { this.customerPartsAsBuiltSubscription?.unsubscribe(); - this.customerPartsAsBuiltSubscription = this.otherPartsService.getOtherPartsAsBuilt(page, pageSize, sorting, Owner.CUSTOMER, filter).subscribe({ + this.customerPartsAsBuiltSubscription = this.otherPartsService.getOtherPartsAsBuilt(page, pageSize, sorting, Owner.CUSTOMER, filter, isOrSearch).subscribe({ next: data => (this.otherPartsState.customerPartsAsBuilt = {data}), error: error => (this.otherPartsState.customerPartsAsBuilt = {error}), }); } - public setCustomerPartsAsPlanned(page = 0, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: AssetAsPlannedFilter): void { + public setCustomerPartsAsPlanned(page = 0, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: AssetAsPlannedFilter, isOrSearch?: boolean): void { this.customerPartsAsPlannedSubscription?.unsubscribe(); - this.customerPartsAsPlannedSubscription = this.otherPartsService.getOtherPartsAsPlanned(page, pageSize, sorting, Owner.CUSTOMER, filter).subscribe({ + this.customerPartsAsPlannedSubscription = this.otherPartsService.getOtherPartsAsPlanned(page, pageSize, sorting, Owner.CUSTOMER, filter, isOrSearch).subscribe({ next: data => (this.otherPartsState.customerPartsAsPlanned = {data}), error: error => (this.otherPartsState.customerPartsAsPlanned = {error}), }); } - public setSupplierPartsAsBuilt(page = 0, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: AssetAsBuiltFilter): void { + public setSupplierPartsAsBuilt(page = 0, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: AssetAsBuiltFilter, isOrSearch?: boolean): void { this.supplierPartsAsBuiltSubscription?.unsubscribe(); - this.supplierPartsAsBuiltSubscription = this.otherPartsService.getOtherPartsAsBuilt(page, pageSize, sorting, Owner.SUPPLIER, filter).subscribe({ + this.supplierPartsAsBuiltSubscription = this.otherPartsService.getOtherPartsAsBuilt(page, pageSize, sorting, Owner.SUPPLIER, filter, isOrSearch).subscribe({ next: data => (this.otherPartsState.supplierPartsAsBuilt = {data}), error: error => (this.otherPartsState.supplierPartsAsBuilt = {error}), }); } - public setSupplierPartsAsPlanned(page = 0, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: AssetAsPlannedFilter): void { + public setSupplierPartsAsPlanned(page = 0, pageSize = 50, sorting: TableHeaderSort[] = [], filter?: AssetAsPlannedFilter, isOrSearch?: boolean): void { this.supplierPartsAsPlannedSubscription?.unsubscribe(); - this.supplierPartsAsPlannedSubscription = this.otherPartsService.getOtherPartsAsPlanned(page, pageSize, sorting, Owner.SUPPLIER, filter).subscribe({ + this.supplierPartsAsPlannedSubscription = this.otherPartsService.getOtherPartsAsPlanned(page, pageSize, sorting, Owner.SUPPLIER, filter, isOrSearch).subscribe({ next: data => (this.otherPartsState.supplierPartsAsPlanned = {data}), error: error => (this.otherPartsState.supplierPartsAsPlanned = {error}), }); diff --git a/frontend/src/app/modules/page/other-parts/core/other-parts.service.ts b/frontend/src/app/modules/page/other-parts/core/other-parts.service.ts index eaf59b87b7..dfd8ff1903 100644 --- a/frontend/src/app/modules/page/other-parts/core/other-parts.service.ts +++ b/frontend/src/app/modules/page/other-parts/core/other-parts.service.ts @@ -19,66 +19,69 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -import {HttpParams} from '@angular/common/http'; -import {Injectable} from '@angular/core'; -import {ApiService} from '@core/api/api.service'; -import {Pagination} from '@core/model/pagination.model'; -import {environment} from '@env'; -import {MainAspectType} from '@page/parts/model/mainAspectType.enum'; -import {Owner} from '@page/parts/model/owner.enum'; -import {AssetAsBuiltFilter, AssetAsPlannedFilter, Part, PartsResponse} from '@page/parts/model/parts.model'; -import {PartsAssembler} from '@shared/assembler/parts.assembler'; -import {TableHeaderSort} from '@shared/components/table/table.model'; -import {Observable} from 'rxjs'; -import {map} from 'rxjs/operators'; -import {enrichFilterAndGetUpdatedParams} from "@shared/helper/filter-helper"; +import { HttpParams } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { ApiService } from '@core/api/api.service'; +import { Pagination } from '@core/model/pagination.model'; +import { environment } from '@env'; +import { MainAspectType } from '@page/parts/model/mainAspectType.enum'; +import { Owner } from '@page/parts/model/owner.enum'; +import { AssetAsBuiltFilter, AssetAsPlannedFilter, Part, PartsResponse } from '@page/parts/model/parts.model'; +import { PartsAssembler } from '@shared/assembler/parts.assembler'; +import { TableHeaderSort } from '@shared/components/table/table.model'; +import { enrichFilterAndGetUpdatedParams } from '@shared/helper/filter-helper'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; @Injectable() export class OtherPartsService { - private url = environment.apiUrl; + private url = environment.apiUrl; - constructor(private readonly apiService: ApiService) { - } + constructor(private readonly apiService: ApiService) { + } - public getOtherPartsAsBuilt(page: number, pageSize: number, sorting: TableHeaderSort[], owner: Owner, filter?: AssetAsBuiltFilter): Observable> { - let sort = sorting.map(sortingItem => PartsAssembler.mapSortToApiSort(sortingItem)); - let params = new HttpParams() - .set('page', page) - .set('size', pageSize) - .set('filterOperator', "AND") - .set('filter', "owner,EQUAL," + owner); + public getOtherPartsAsBuilt(page: number, pageSize: number, sorting: TableHeaderSort[], owner: Owner, filter?: AssetAsBuiltFilter, isOrSearch?: boolean): Observable> { + let sort = sorting.map(sortingItem => PartsAssembler.mapSortToApiSort(sortingItem)); + let params = this.buildHttpParams(page, pageSize, isOrSearch, owner); - sort.forEach(sortingItem => { - params = params.append('sort', sortingItem); - }) + sort.forEach(sortingItem => { + params = params.append('sort', sortingItem); + }); - if (filter) { - params = enrichFilterAndGetUpdatedParams(filter, params); - } - return this.apiService - .getBy(`${this.url}/assets/as-built`, params) - .pipe(map(parts => PartsAssembler.assembleOtherParts(parts, MainAspectType.AS_BUILT))); + if (filter) { + params = enrichFilterAndGetUpdatedParams(filter, params); } + return this.apiService + .getBy(`${ this.url }/assets/as-built`, params) + .pipe(map(parts => PartsAssembler.assembleOtherParts(parts, MainAspectType.AS_BUILT))); + } + + public getOtherPartsAsPlanned(page: number, pageSize: number, sorting: TableHeaderSort[], owner: Owner, filter?: AssetAsPlannedFilter, isOrSearch?: boolean): Observable> { + let sort = sorting.map(sortingItem => PartsAssembler.mapSortToApiSort(sortingItem)); - public getOtherPartsAsPlanned(page: number, pageSize: number, sorting: TableHeaderSort[], owner: Owner, filter?: AssetAsPlannedFilter): Observable> { - let sort = sorting.map(sortingItem => PartsAssembler.mapSortToApiSort(sortingItem)); - let params = new HttpParams() - .set('page', page) - .set('size', pageSize) - .set('filterOperator', "AND") - .set('filter', "owner,EQUAL," + owner); - sort.forEach(sortingItem => { - params = params.append('sort', sortingItem); - }) - if (filter) { - params = enrichFilterAndGetUpdatedParams(filter, params); - } + let params = this.buildHttpParams(page, pageSize, isOrSearch, owner); - return this.apiService - .getBy(`${this.url}/assets/as-planned`, params) - .pipe(map(parts => PartsAssembler.assembleOtherParts(parts, MainAspectType.AS_PLANNED))); + sort.forEach(sortingItem => { + params = params.append('sort', sortingItem); + }); + if (filter) { + params = enrichFilterAndGetUpdatedParams(filter, params); } + return this.apiService + .getBy(`${ this.url }/assets/as-planned`, params) + .pipe(map(parts => PartsAssembler.assembleOtherParts(parts, MainAspectType.AS_PLANNED))); + } + + private buildHttpParams(page: number, pageSize: number, isOrSearch: boolean, owner: Owner): HttpParams{ + let filterOperator = isOrSearch ? 'OR' : 'AND'; + return new HttpParams() + .set('page', page) + .set('size', pageSize) + .set('filterOperator', filterOperator) + .set('filter', 'owner,EQUAL,' + owner); + } + } diff --git a/frontend/src/app/modules/page/other-parts/presentation/customer-parts/customer-parts.component.spec.ts b/frontend/src/app/modules/page/other-parts/presentation/customer-parts/customer-parts.component.spec.ts index af621719bf..6d0973ab15 100644 --- a/frontend/src/app/modules/page/other-parts/presentation/customer-parts/customer-parts.component.spec.ts +++ b/frontend/src/app/modules/page/other-parts/presentation/customer-parts/customer-parts.component.spec.ts @@ -21,6 +21,7 @@ import { OtherPartsState } from '@page/other-parts/core/other-parts.state'; import { OtherPartsModule } from '@page/other-parts/other-parts.module'; import { PartsState } from '@page/parts/core/parts.state'; import { MainAspectType } from '@page/parts/model/mainAspectType.enum'; +import { toGlobalSearchAssetFilter } from '@shared/helper/filter-helper'; import { fireEvent, screen, waitFor } from '@testing-library/angular'; import { renderComponent } from '@tests/test-render.utils'; @@ -32,12 +33,12 @@ describe('CustomerPartsComponent', () => { const renderCustomerParts = () => renderComponent(CustomerPartsComponent, { - imports: [OtherPartsModule], - providers: [{ provide: OtherPartsState, useFactory: () => otherPartsState }, { provide: PartsState }], - roles: ['admin', 'wip'], + imports: [ OtherPartsModule ], + providers: [ { provide: OtherPartsState, useFactory: () => otherPartsState }, { provide: PartsState } ], + roles: [ 'admin', 'wip' ], componentInputs: { - bomLifecycle: MainAspectType.AS_BUILT - } + bomLifecycle: MainAspectType.AS_BUILT, + }, }); it('should render part table', async () => { @@ -54,69 +55,117 @@ describe('CustomerPartsComponent', () => { }); it('sort customer parts after name column', async () => { - const {fixture} = await renderCustomerParts(); + const { fixture } = await renderCustomerParts(); const customerPartsComponent = fixture.componentInstance; let nameHeader = await screen.findByText('table.column.name'); fireEvent.click(nameHeader); - expect(customerPartsComponent['tableCustomerAsBuiltSortList']).toEqual([["name", "asc"]]); + expect(customerPartsComponent['tableCustomerAsBuiltSortList']).toEqual([ [ 'name', 'asc' ] ]); }); it('should multisort after column name and semanticModelId', async () => { - const {fixture} = await renderCustomerParts(); + const { fixture } = await renderCustomerParts(); const customerPartsComponent = fixture.componentInstance; let nameHeader = await screen.findByText('table.column.name'); fireEvent.click(nameHeader); - let semanticModelIdHeader = await screen.findByText('table.column.semanticModelId') + let semanticModelIdHeader = await screen.findByText('table.column.semanticModelId'); - await waitFor(() => {fireEvent.keyDown(semanticModelIdHeader, { - ctrlKey: true, - charCode: 17 - })}) + await waitFor(() => { + fireEvent.keyDown(semanticModelIdHeader, { + ctrlKey: true, + charCode: 17, + }); + }); expect(customerPartsComponent['ctrlKeyState']).toBeTruthy(); await waitFor(() => { - fireEvent.click(semanticModelIdHeader) + fireEvent.click(semanticModelIdHeader); }); - await waitFor(() => {fireEvent.keyUp(semanticModelIdHeader, { - ctrlKey: true, - charCode: 17 - })}) + await waitFor(() => { + fireEvent.keyUp(semanticModelIdHeader, { + ctrlKey: true, + charCode: 17, + }); + }); - await waitFor(() => {fireEvent.click(semanticModelIdHeader)}); - expect(customerPartsComponent['tableCustomerAsBuiltSortList']).toEqual([["name", "asc"], ["semanticModelId", "desc"]]); + await waitFor(() => { + fireEvent.click(semanticModelIdHeader); + }); + expect(customerPartsComponent['tableCustomerAsBuiltSortList']).toEqual([ [ 'name', 'asc' ], [ 'semanticModelId', 'desc' ] ]); }); it('should reset sorting on third click', async () => { - const {fixture} = await renderCustomerParts(); + const { fixture } = await renderCustomerParts(); const customerPartsComponent = fixture.componentInstance; customerPartsComponent.bomLifecycle = MainAspectType.AS_BUILT; fixture.detectChanges(); let nameHeader = await screen.findByText('table.column.name'); fireEvent.click(nameHeader); - let semanticModelIdHeader = await screen.findByText('table.column.semanticModelId') + let semanticModelIdHeader = await screen.findByText('table.column.semanticModelId'); - await waitFor(() => {fireEvent.keyDown(semanticModelIdHeader, { - ctrlKey: true, - charCode: 17 - })}) + await waitFor(() => { + fireEvent.keyDown(semanticModelIdHeader, { + ctrlKey: true, + charCode: 17, + }); + }); expect(customerPartsComponent['ctrlKeyState']).toBeTruthy(); await waitFor(() => { - fireEvent.click(semanticModelIdHeader) + fireEvent.click(semanticModelIdHeader); }); - await waitFor(() => {fireEvent.keyUp(semanticModelIdHeader, { - ctrlKey: true, - charCode: 17 - })}) + await waitFor(() => { + fireEvent.keyUp(semanticModelIdHeader, { + ctrlKey: true, + charCode: 17, + }); + }); - await waitFor(() => {fireEvent.click(semanticModelIdHeader)}); - await waitFor(() => {fireEvent.click(semanticModelIdHeader)}); + await waitFor(() => { + fireEvent.click(semanticModelIdHeader); + }); + await waitFor(() => { + fireEvent.click(semanticModelIdHeader); + }); expect(customerPartsComponent['tableCustomerAsBuiltSortList']).toEqual([]); }); + + it('should handle updateCustomerParts null', async () => { + const { fixture } = await renderCustomerParts(); + const customerPartsComponent = fixture.componentInstance; + + const otherPartsFacade = (customerPartsComponent as any)['otherPartsFacade']; + const updateCustomerPartAsBuiltSpy = spyOn(otherPartsFacade, 'setCustomerPartsAsBuilt'); + const updateCustomerPartAsPlannedSpy = spyOn(otherPartsFacade, 'setCustomerPartsAsPlanned'); + + customerPartsComponent.updateCustomerParts(); + + + expect(updateCustomerPartAsBuiltSpy).toHaveBeenCalledWith(); + expect(updateCustomerPartAsPlannedSpy).toHaveBeenCalledWith(); + + }); + + it('should handle updateCustomerParts including search', async () => { + const { fixture } = await renderCustomerParts(); + const customerPartsComponent = fixture.componentInstance; + + const otherPartsFacade = (customerPartsComponent as any)['otherPartsFacade']; + const updateCustomerPartAsBuiltSpy = spyOn(otherPartsFacade, 'setCustomerPartsAsBuilt'); + const updateCustomerPartAsPlannedSpy = spyOn(otherPartsFacade, 'setCustomerPartsAsPlanned'); + + const search = 'test'; + customerPartsComponent.updateCustomerParts(search); + + + expect(updateCustomerPartAsBuiltSpy).toHaveBeenCalledWith(0, 50, [], toGlobalSearchAssetFilter(search, true), true); + expect(updateCustomerPartAsPlannedSpy).toHaveBeenCalledWith(0, 50, [], toGlobalSearchAssetFilter(search, false), true); + + }); + }); diff --git a/frontend/src/app/modules/page/other-parts/presentation/customer-parts/customer-parts.component.ts b/frontend/src/app/modules/page/other-parts/presentation/customer-parts/customer-parts.component.ts index ab47d4222b..235c2f0236 100644 --- a/frontend/src/app/modules/page/other-parts/presentation/customer-parts/customer-parts.component.ts +++ b/frontend/src/app/modules/page/other-parts/presentation/customer-parts/customer-parts.component.ts @@ -18,97 +18,109 @@ ********************************************************************************/ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; -import {Pagination} from '@core/model/pagination.model'; -import {OtherPartsFacade} from '@page/other-parts/core/other-parts.facade'; -import {MainAspectType} from '@page/parts/model/mainAspectType.enum'; -import {Part} from '@page/parts/model/parts.model'; -import {PartTableType, TableEventConfig, TableHeaderSort,} from '@shared/components/table/table.model'; -import {TableSortingUtil} from '@shared/components/table/tableSortingUtil'; -import {View} from '@shared/model/view.model'; -import {PartDetailsFacade} from '@shared/modules/part-details/core/partDetails.facade'; -import {StaticIdService} from '@shared/service/staticId.service'; -import {Observable} from 'rxjs'; -import {toAssetFilter} from "@shared/helper/filter-helper"; +import { Component, Input, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { Pagination } from '@core/model/pagination.model'; +import { OtherPartsFacade } from '@page/other-parts/core/other-parts.facade'; +import { MainAspectType } from '@page/parts/model/mainAspectType.enum'; +import { Part } from '@page/parts/model/parts.model'; +import { PartsTableComponent } from '@shared/components/parts-table/parts-table.component'; +import { PartTableType, TableEventConfig, TableHeaderSort } from '@shared/components/table/table.model'; +import { TableSortingUtil } from '@shared/components/table/tableSortingUtil'; +import { toAssetFilter, toGlobalSearchAssetFilter } from '@shared/helper/filter-helper'; +import { View } from '@shared/model/view.model'; +import { PartDetailsFacade } from '@shared/modules/part-details/core/partDetails.facade'; +import { StaticIdService } from '@shared/service/staticId.service'; +import { Observable } from 'rxjs'; @Component({ - selector: 'app-customer-parts', - templateUrl: './customer-parts.component.html', + selector: 'app-customer-parts', + templateUrl: './customer-parts.component.html', }) export class CustomerPartsComponent implements OnInit, OnDestroy { + @ViewChildren(PartsTableComponent) partsTableComponents: QueryList; - public customerPartsAsBuilt$: Observable>>; - public customerPartsAsPlanned$: Observable>>; + public customerPartsAsBuilt$: Observable>>; + public customerPartsAsPlanned$: Observable>>; - public readonly customerTabLabelId = this.staticIdService.generateId('OtherParts.customerTabLabel'); + public readonly customerTabLabelId = this.staticIdService.generateId('OtherParts.customerTabLabel'); - public tableCustomerAsBuiltSortList: TableHeaderSort[]; - public tableCustomerAsPlannedSortList: TableHeaderSort[]; + public tableCustomerAsBuiltSortList: TableHeaderSort[]; + public tableCustomerAsPlannedSortList: TableHeaderSort[]; - private ctrlKeyState = false; + private ctrlKeyState = false; - @Input() - public bomLifecycle: MainAspectType; + @Input() + public bomLifecycle: MainAspectType; - constructor( - private readonly otherPartsFacade: OtherPartsFacade, - private readonly partDetailsFacade: PartDetailsFacade, - private readonly staticIdService: StaticIdService, - ) { + constructor( + private readonly otherPartsFacade: OtherPartsFacade, + private readonly partDetailsFacade: PartDetailsFacade, + private readonly staticIdService: StaticIdService, + ) { - window.addEventListener('keydown', (event) => { - this.ctrlKeyState = event.ctrlKey; - }); - window.addEventListener('keyup', (event) => { - this.ctrlKeyState = event.ctrlKey; - }); - } + window.addEventListener('keydown', (event) => { + this.ctrlKeyState = event.ctrlKey; + }); + window.addEventListener('keyup', (event) => { + this.ctrlKeyState = event.ctrlKey; + }); + } - public ngOnInit(): void { - if (this.bomLifecycle === MainAspectType.AS_BUILT) { - this.customerPartsAsBuilt$ = this.otherPartsFacade.customerPartsAsBuilt$; - this.tableCustomerAsBuiltSortList = []; - this.otherPartsFacade.setCustomerPartsAsBuilt(); - } else if (this.bomLifecycle === MainAspectType.AS_PLANNED) { - this.customerPartsAsPlanned$ = this.otherPartsFacade.customerPartsAsPlanned$; - this.tableCustomerAsPlannedSortList = []; - this.otherPartsFacade.setCustomerPartsAsPlanned(); - } + public ngOnInit(): void { + if (this.bomLifecycle === MainAspectType.AS_BUILT) { + this.customerPartsAsBuilt$ = this.otherPartsFacade.customerPartsAsBuilt$; + this.tableCustomerAsBuiltSortList = []; + this.otherPartsFacade.setCustomerPartsAsBuilt(); + } else if (this.bomLifecycle === MainAspectType.AS_PLANNED) { + this.customerPartsAsPlanned$ = this.otherPartsFacade.customerPartsAsPlanned$; + this.tableCustomerAsPlannedSortList = []; + this.otherPartsFacade.setCustomerPartsAsPlanned(); } - - filterActivated(isAsBuilt: boolean, assetFilter: any): void { - if (isAsBuilt) { - this.otherPartsFacade.setCustomerPartsAsBuilt(0, 50, [], toAssetFilter(assetFilter, true)) - } else { - this.otherPartsFacade.setCustomerPartsAsPlanned(0, 50, [], toAssetFilter(assetFilter, false)) - } + } + + updateCustomerParts(searchValue?: string): void { + if (searchValue) { + this.otherPartsFacade.setCustomerPartsAsBuilt(0, 50, [], toGlobalSearchAssetFilter(searchValue, true), true); + this.otherPartsFacade.setCustomerPartsAsPlanned(0, 50, [], toGlobalSearchAssetFilter(searchValue, false), true); + } else { + this.otherPartsFacade.setCustomerPartsAsBuilt(); + this.otherPartsFacade.setCustomerPartsAsPlanned(); } + } - public ngOnDestroy(): void { - this.otherPartsFacade.unsubscribeParts(); + filterActivated(isAsBuilt: boolean, assetFilter: any): void { + if (isAsBuilt) { + this.otherPartsFacade.setCustomerPartsAsBuilt(0, 50, [], toAssetFilter(assetFilter, true)); + } else { + this.otherPartsFacade.setCustomerPartsAsPlanned(0, 50, [], toAssetFilter(assetFilter, false)); } + } - public onSelectItem(event: Record): void { - this.partDetailsFacade.selectedPart = event as unknown as Part; - } + public ngOnDestroy(): void { + this.otherPartsFacade.unsubscribeParts(); + } - public onAsBuiltTableConfigChange({page, pageSize, sorting}: TableEventConfig): void { - this.setTableSortingList(sorting, MainAspectType.AS_BUILT); - this.otherPartsFacade.setCustomerPartsAsBuilt(page, pageSize, this.tableCustomerAsBuiltSortList); - } + public onSelectItem(event: Record): void { + this.partDetailsFacade.selectedPart = event as unknown as Part; + } - public onAsPlannedTableConfigChange({page, pageSize, sorting}: TableEventConfig): void { - this.setTableSortingList(sorting, MainAspectType.AS_PLANNED); - this.otherPartsFacade.setCustomerPartsAsPlanned(page, pageSize, this.tableCustomerAsPlannedSortList); - } + public onAsBuiltTableConfigChange({ page, pageSize, sorting }: TableEventConfig): void { + this.setTableSortingList(sorting, MainAspectType.AS_BUILT); + this.otherPartsFacade.setCustomerPartsAsBuilt(page, pageSize, this.tableCustomerAsBuiltSortList); + } - private setTableSortingList(sorting: TableHeaderSort, partTable: MainAspectType): void { - const tableSortList = partTable === MainAspectType.AS_BUILT ? this.tableCustomerAsBuiltSortList : this.tableCustomerAsPlannedSortList; - TableSortingUtil.setTableSortingList(sorting, tableSortList, this.ctrlKeyState); - } + public onAsPlannedTableConfigChange({ page, pageSize, sorting }: TableEventConfig): void { + this.setTableSortingList(sorting, MainAspectType.AS_PLANNED); + this.otherPartsFacade.setCustomerPartsAsPlanned(page, pageSize, this.tableCustomerAsPlannedSortList); + } + + private setTableSortingList(sorting: TableHeaderSort, partTable: MainAspectType): void { + const tableSortList = partTable === MainAspectType.AS_BUILT ? this.tableCustomerAsBuiltSortList : this.tableCustomerAsPlannedSortList; + TableSortingUtil.setTableSortingList(sorting, tableSortList, this.ctrlKeyState); + } - protected readonly MainAspectType = MainAspectType; - protected readonly PartTableType = PartTableType; + protected readonly MainAspectType = MainAspectType; + protected readonly PartTableType = PartTableType; } diff --git a/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.html b/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.html index 1787b3ca50..cf37afcdc6 100644 --- a/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.html +++ b/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.html @@ -19,71 +19,88 @@ SPDX-License-Identifier: Apache-2.0 -->
+
+ +
- +

{{'page.asBuiltParts' | i18n }}

- - - - {{ 'pageOtherParts.tab.supplier' | i18n }} - + + + + {{ 'pageOtherParts.tab.supplier' | i18n }} + - - + + - - - {{ 'pageOtherParts.tab.customer' | i18n }} - + + + {{ 'pageOtherParts.tab.customer' | i18n }} + - - - + + +

{{'page.asPlannedParts' | i18n }}

- - - - {{ 'pageOtherParts.tab.supplier' | i18n }} - + + + + {{ 'pageOtherParts.tab.supplier' | i18n }} + - - + + - - - {{ 'pageOtherParts.tab.customer' | i18n }} - + + + {{ 'pageOtherParts.tab.customer' | i18n }} + - - - + + +
- +
diff --git a/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.scss b/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.scss index 622c0c0b04..634bf8268f 100644 --- a/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.scss +++ b/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.scss @@ -24,6 +24,10 @@ height: 72vh; } +.parts-search-input-wrapper { + padding: 20px; +} + .app-bom-lifecycle-activator-container { grid-column: 1 / span 2; /* This will make it span both columns */ width: 100%; diff --git a/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.spec.ts b/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.spec.ts index 07e70bb4c9..6242b37b6d 100644 --- a/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.spec.ts +++ b/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.spec.ts @@ -20,6 +20,8 @@ ********************************************************************************/ import { OtherPartsState } from '@page/other-parts/core/other-parts.state'; +import { CustomerPartsComponent } from '@page/other-parts/presentation/customer-parts/customer-parts.component'; +import { SupplierPartsComponent } from '@page/other-parts/presentation/supplier-parts/supplier-parts.component'; import { PartsState } from '@page/parts/core/parts.state'; import { MainAspectType } from '@page/parts/model/mainAspectType.enum'; import { PartsAssembler } from '@shared/assembler/parts.assembler'; @@ -45,15 +47,16 @@ describe('Other Parts', () => { let otherPartsState: OtherPartsState; let formatPartSemanticToCamelCase: FormatPartSemanticDataModelToCamelCasePipe; beforeEach(() => { - otherPartsState = new OtherPartsState() + otherPartsState = new OtherPartsState(); formatPartSemanticToCamelCase = new FormatPartSemanticDataModelToCamelCasePipe(); }); const renderOtherParts = ({ roles = [] } = {}) => renderComponent(OtherPartsComponent, { - imports: [OtherPartsModule], - providers: [{ provide: OtherPartsState, useFactory: () => otherPartsState }, { provide: PartsState }], + declarations: [ SupplierPartsComponent, CustomerPartsComponent ], + imports: [ OtherPartsModule ], + providers: [ { provide: OtherPartsState, useFactory: () => otherPartsState }, { provide: PartsState } ], roles, }); @@ -80,7 +83,7 @@ describe('Other Parts', () => { }); it('should render selected parts information', async () => { - await renderOtherParts({ roles: ['user'] }); + await renderOtherParts({ roles: [ 'user' ] }); await screen.findByTestId('table-component--test-id'); const selectedPartsInfo = await screen.getByText('page.selectedParts.info'); @@ -106,9 +109,9 @@ describe('Other Parts', () => { let formatPartSemanticToCamelCase: FormatPartSemanticDataModelToCamelCasePipe; beforeEach(() => { formatPartSemanticToCamelCase = new FormatPartSemanticDataModelToCamelCasePipe(); - }) + }); it('should request supplier parts if first tab is selected', async () => { - await renderOtherParts({ roles: ['user'] }); + await renderOtherParts({ roles: [ 'user' ] }); fireEvent.click(screen.getAllByText('pageOtherParts.tab.supplier')[0]); await waitFor(() => expect(screen.getByText('table.column.manufacturer')).toBeInTheDocument()); @@ -136,7 +139,7 @@ describe('Other Parts', () => { }); it('should request customer parts if second tab is selected', async () => { - const fixture = await renderOtherParts({ roles: ['user'] }); + const fixture = await renderOtherParts({ roles: [ 'user' ] }); let tabs = screen.getAllByText('pageOtherParts.tab.customer'); fireEvent.click(tabs[0]); @@ -164,5 +167,81 @@ describe('Other Parts', () => { }), ); }); + + it('should clear filters and call partsFacade methods with search value', async () => { + + const { fixture } = await renderOtherParts(); + const { componentInstance } = fixture; + // Arrange + const searchValue = 'searchTerm'; + + const updateSupplierPartsSpy = spyOn( + SupplierPartsComponent.prototype, + 'updateSupplierParts', + ); + + const updateCustomerPartsSpy = spyOn( + CustomerPartsComponent.prototype, + 'updateCustomerParts', + ); + + componentInstance.searchControl.setValue(searchValue); + + + // Act + componentInstance.triggerPartSearch(); + + // Assert + expect(updateSupplierPartsSpy).toHaveBeenCalledWith(searchValue); + expect(updateCustomerPartsSpy).toHaveBeenCalledWith(searchValue); + }); + + it('should reset form on search', async () => { + const { fixture } = await renderOtherParts(); + const { componentInstance } = fixture; + // Mock the necessary data and components + componentInstance.supplierPartsComponents = [ + { + updateSupplierParts: jasmine.createSpy('updateSupplierParts'), // + partsTableComponents: [ + { + multiSelectAutocompleteComponent: { + theSearchElement: 'test', // Mock theSearchElement to be truthy + }, + filterFormGroup: { + reset: jasmine.createSpy('reset'), // Spy on reset method + }, + }, + ], + }, + ] as any; + + componentInstance.customerPartsComponents = [ + { + updateCustomerParts: jasmine.createSpy('updateCustomerParts'), + partsTableComponents: [ + { + multiSelectAutocompleteComponent: { + theSearchElement: 'test', // Mock theSearchElement to be truthy + }, + filterFormGroup: { + reset: jasmine.createSpy('reset'), // Spy on reset method + }, + }, + ], + }, + ] as any; + + // Call the method + componentInstance.triggerPartSearch(); + + // Expectations + expect(componentInstance.supplierPartsComponents[0].partsTableComponents[0].filterFormGroup.reset).toHaveBeenCalled(); + expect(componentInstance.customerPartsComponents[0].partsTableComponents[0].filterFormGroup.reset).toHaveBeenCalled(); + + }); + + }); }); + diff --git a/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.ts b/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.ts index 0bf819aeb9..5b2d202290 100644 --- a/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.ts +++ b/frontend/src/app/modules/page/other-parts/presentation/other-parts.component.ts @@ -19,53 +19,107 @@ * SPDX-License-Identifier: Apache-2.0 ********************************************************************************/ -import {Component, OnDestroy} from '@angular/core'; -import {MatTabChangeEvent} from '@angular/material/tabs'; -import {OtherPartsFacade} from '@page/other-parts/core/other-parts.facade'; -import {PartDetailsFacade} from '@shared/modules/part-details/core/partDetails.facade'; -import {StaticIdService} from '@shared/service/staticId.service'; -import {MainAspectType} from "@page/parts/model/mainAspectType.enum"; -import {BomLifecycleSize} from "@shared/components/bom-lifecycle-activator/bom-lifecycle-activator.model"; -import {BomLifecycleSettingsService, UserSettingView} from "@shared/service/bom-lifecycle-settings.service"; +import { Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { FormControl, FormGroup } from '@angular/forms'; +import { MatTabChangeEvent } from '@angular/material/tabs'; +import { OtherPartsFacade } from '@page/other-parts/core/other-parts.facade'; +import { CustomerPartsComponent } from '@page/other-parts/presentation/customer-parts/customer-parts.component'; +import { SupplierPartsComponent } from '@page/other-parts/presentation/supplier-parts/supplier-parts.component'; +import { MainAspectType } from '@page/parts/model/mainAspectType.enum'; +import { BomLifecycleSize } from '@shared/components/bom-lifecycle-activator/bom-lifecycle-activator.model'; +import { ToastService } from '@shared/components/toasts/toast.service'; +import { PartDetailsFacade } from '@shared/modules/part-details/core/partDetails.facade'; +import { BomLifecycleSettingsService, UserSettingView } from '@shared/service/bom-lifecycle-settings.service'; +import { StaticIdService } from '@shared/service/staticId.service'; @Component({ - selector: 'app-other-parts', - templateUrl: './other-parts.component.html', - styleUrls: ['./other-parts.component.scss'], + selector: 'app-other-parts', + templateUrl: './other-parts.component.html', + styleUrls: [ './other-parts.component.scss' ], }) -export class OtherPartsComponent implements OnDestroy { +export class OtherPartsComponent implements OnDestroy, OnInit { - public selectedTab = 0; - public showStartInvestigationArray = [true, false]; + public selectedTab = 0; + public showStartInvestigationArray = [ true, false ]; - public readonly supplierTabLabelId = this.staticIdService.generateId('OtherParts.supplierTabLabel'); - public readonly customerTabLabelId = this.staticIdService.generateId('OtherParts.customerTabLabel'); + public readonly supplierTabLabelId = this.staticIdService.generateId('OtherParts.supplierTabLabel'); + public readonly customerTabLabelId = this.staticIdService.generateId('OtherParts.customerTabLabel'); + public searchFormGroup = new FormGroup({}); + public searchControl: FormControl; + @ViewChildren(SupplierPartsComponent) supplierPartsComponents: QueryList; + @ViewChildren(CustomerPartsComponent) customerPartsComponents: QueryList; - constructor( - private readonly otherPartsFacade: OtherPartsFacade, - private readonly partDetailsFacade: PartDetailsFacade, - private readonly staticIdService: StaticIdService, - public userSettings: BomLifecycleSettingsService - ) { + constructor( + private readonly otherPartsFacade: OtherPartsFacade, + private readonly partDetailsFacade: PartDetailsFacade, + private readonly staticIdService: StaticIdService, + public userSettings: BomLifecycleSettingsService, + public toastService: ToastService, + ) { + } - } + ngOnInit(): void { + this.searchFormGroup.addControl('partSearch', new FormControl([])); + this.searchControl = this.searchFormGroup.get('partSearch') as unknown as FormControl; + } - public bomLifecycleSize: BomLifecycleSize = this.userSettings.getSize(UserSettingView.OTHER_PARTS); - public ngOnDestroy(): void { - this.otherPartsFacade.unsubscribeParts(); - } + public bomLifecycleSize: BomLifecycleSize = this.userSettings.getSize(UserSettingView.OTHER_PARTS); + + public ngOnDestroy(): void { + this.otherPartsFacade.unsubscribeParts(); + } + + triggerPartSearch() { - public onTabChange({index}: MatTabChangeEvent): void { - this.selectedTab = index; - this.partDetailsFacade.selectedPart = null; + this.resetFilterAndShowToast(); + + const searchValue = this.searchFormGroup.get('partSearch').value; + + for (const supplierPartsComponent of this.supplierPartsComponents) { + supplierPartsComponent.updateSupplierParts(searchValue); + } + for (const customerPartsComponent of this.customerPartsComponents) { + customerPartsComponent.updateCustomerParts(searchValue); } + } - public handleTableActivationEvent(bomLifecycleSize: BomLifecycleSize) { - this.bomLifecycleSize = bomLifecycleSize; + + private resetFilterAndShowToast() { + let filterSet = false; + + for (const supplierPartsComponent of this.supplierPartsComponents) { + for (const partsTableComponent of supplierPartsComponent.partsTableComponents) { + if (partsTableComponent.multiSelectAutocompleteComponent.theSearchElement) { + filterSet = true; + partsTableComponent.filterFormGroup.reset(); + } + } + } + for (const customerPartsComponent of this.customerPartsComponents) { + for (const partsTableComponent of customerPartsComponent.partsTableComponents) { + if (partsTableComponent.multiSelectAutocompleteComponent.theSearchElement) { + filterSet = true; + partsTableComponent.filterFormGroup.reset(); + } + } } + if (filterSet) { + this.toastService.info('parts.input.global-search.toastInfo'); + } + return filterSet; + } + + public onTabChange({ index }: MatTabChangeEvent): void { + this.selectedTab = index; + this.partDetailsFacade.selectedPart = null; + } + + public handleTableActivationEvent(bomLifecycleSize: BomLifecycleSize) { + this.bomLifecycleSize = bomLifecycleSize; + } - protected readonly MainAspectType = MainAspectType; - protected readonly UserSettingView = UserSettingView; + protected readonly MainAspectType = MainAspectType; + protected readonly UserSettingView = UserSettingView; } diff --git a/frontend/src/app/modules/page/other-parts/presentation/supplier-parts/supplier-parts.component.spec.ts b/frontend/src/app/modules/page/other-parts/presentation/supplier-parts/supplier-parts.component.spec.ts index 3d9f5ae233..b2c5495856 100644 --- a/frontend/src/app/modules/page/other-parts/presentation/supplier-parts/supplier-parts.component.spec.ts +++ b/frontend/src/app/modules/page/other-parts/presentation/supplier-parts/supplier-parts.component.spec.ts @@ -23,6 +23,7 @@ import { OtherPartsModule } from '@page/other-parts/other-parts.module'; import { PartsState } from '@page/parts/core/parts.state'; import { MainAspectType } from '@page/parts/model/mainAspectType.enum'; import { PartsAssembler } from '@shared/assembler/parts.assembler'; +import { toGlobalSearchAssetFilter } from '@shared/helper/filter-helper'; import { fireEvent, screen, waitFor } from '@testing-library/angular'; import { getTableCheckbox, renderComponent } from '@tests/test-render.utils'; import { OTHER_PARTS_MOCK_6 } from '../../../../../mocks/services/otherParts-mock/otherParts.test.model'; @@ -35,12 +36,12 @@ describe('SupplierPartsComponent', () => { const renderSupplierParts = ({ roles = [] } = {}) => renderComponent(SupplierPartsComponent, { - imports: [OtherPartsModule], - providers: [{ provide: OtherPartsState, useFactory: () => otherPartsState }, { provide: PartsState }], + imports: [ OtherPartsModule ], + providers: [ { provide: OtherPartsState, useFactory: () => otherPartsState }, { provide: PartsState } ], roles, componentInputs: { - bomLifecycle: MainAspectType.AS_BUILT - } + bomLifecycle: MainAspectType.AS_BUILT, + }, }); it('should render part table', async () => { @@ -59,7 +60,7 @@ describe('SupplierPartsComponent', () => { }); it('should add item to current list and then remove', async () => { - const { fixture } = await renderSupplierParts({ roles: ['user'] }); + const { fixture } = await renderSupplierParts({ roles: [ 'user' ] }); const expectedPart = PartsAssembler.assembleOtherPart(OTHER_PARTS_MOCK_6, MainAspectType.AS_BUILT); // first click to check checkbox @@ -67,7 +68,7 @@ describe('SupplierPartsComponent', () => { const selectedText_1 = await waitFor(() => screen.getByText('page.selectedParts.info')); expect(selectedText_1).toBeInTheDocument(); - expect(fixture.componentInstance.currentSelectedItems).toEqual([expectedPart]); + expect(fixture.componentInstance.currentSelectedItems).toEqual([ expectedPart ]); // second click to uncheck checkbox fireEvent.click(await getTableCheckbox(screen, 0)); @@ -83,7 +84,7 @@ describe('SupplierPartsComponent', () => { const expectedPart = PartsAssembler.assembleOtherPart(OTHER_PARTS_MOCK_6, MainAspectType.AS_BUILT); fixture.componentInstance.addItemToSelection(expectedPart); - expect(fixture.componentInstance.currentSelectedItems).toEqual([expectedPart]); + expect(fixture.componentInstance.currentSelectedItems).toEqual([ expectedPart ]); }); it('test removeItemFromSelection method', async () => { @@ -91,7 +92,7 @@ describe('SupplierPartsComponent', () => { const expectedPart = PartsAssembler.assembleOtherPart(OTHER_PARTS_MOCK_6, MainAspectType.AS_BUILT); - fixture.componentInstance.currentSelectedItems = [expectedPart]; + fixture.componentInstance.currentSelectedItems = [ expectedPart ]; fixture.componentInstance.removeItemFromSelection(expectedPart); expect(fixture.componentInstance.currentSelectedItems).toEqual([]); @@ -102,74 +103,124 @@ describe('SupplierPartsComponent', () => { const expectedPart = PartsAssembler.assembleOtherPart(OTHER_PARTS_MOCK_6, MainAspectType.AS_BUILT); - fixture.componentInstance.currentSelectedItems = [expectedPart]; + fixture.componentInstance.currentSelectedItems = [ expectedPart ]; fixture.componentInstance.clearSelected(); expect(fixture.componentInstance.currentSelectedItems).toEqual([]); - }) + }); it('sort supplier parts after name column', async () => { - const {fixture} = await renderSupplierParts({ roles: ['admin'] }); + const { fixture } = await renderSupplierParts({ roles: [ 'admin' ] }); const supplierPartsComponent = fixture.componentInstance; let nameHeader = await screen.findByText('table.column.name'); fireEvent.click(nameHeader); - expect(supplierPartsComponent['tableSupplierAsBuiltSortList']).toEqual([["name", "asc"]]); + expect(supplierPartsComponent['tableSupplierAsBuiltSortList']).toEqual([ [ 'name', 'asc' ] ]); }); it('should multisort after column name and semanticModelId', async () => { - const {fixture} = await renderSupplierParts({ roles: ['admin'] }); + const { fixture } = await renderSupplierParts({ roles: [ 'admin' ] }); const supplierPartsComponent = fixture.componentInstance; let nameHeader = await screen.findByText('table.column.name'); fireEvent.click(nameHeader); - let semanticModelIdHeader = await screen.findByText('table.column.semanticModelId') + let semanticModelIdHeader = await screen.findByText('table.column.semanticModelId'); - await waitFor(() => {fireEvent.keyDown(semanticModelIdHeader, { - ctrlKey: true, - charCode: 17 - })}) + await waitFor(() => { + fireEvent.keyDown(semanticModelIdHeader, { + ctrlKey: true, + charCode: 17, + }); + }); expect(supplierPartsComponent['ctrlKeyState']).toBeTruthy(); await waitFor(() => { - fireEvent.click(semanticModelIdHeader) + fireEvent.click(semanticModelIdHeader); }); - await waitFor(() => {fireEvent.keyUp(semanticModelIdHeader, { - ctrlKey: true, - charCode: 17 - })}) + await waitFor(() => { + fireEvent.keyUp(semanticModelIdHeader, { + ctrlKey: true, + charCode: 17, + }); + }); - await waitFor(() => {fireEvent.click(semanticModelIdHeader)}); - expect(supplierPartsComponent['tableSupplierAsBuiltSortList']).toEqual([["name", "asc"], ["semanticModelId", "desc"]]); + await waitFor(() => { + fireEvent.click(semanticModelIdHeader); + }); + expect(supplierPartsComponent['tableSupplierAsBuiltSortList']).toEqual([ [ 'name', 'asc' ], [ 'semanticModelId', 'desc' ] ]); }); it('should reset sorting on third click', async () => { - const {fixture} = await renderSupplierParts({ roles: ['admin'] }); + const { fixture } = await renderSupplierParts({ roles: [ 'admin' ] }); const supplierPartsComponent = fixture.componentInstance; let nameHeader = await screen.findByText('table.column.name'); fireEvent.click(nameHeader); - let semanticModelIdHeader = await screen.findByText('table.column.semanticModelId') + let semanticModelIdHeader = await screen.findByText('table.column.semanticModelId'); - await waitFor(() => {fireEvent.keyDown(semanticModelIdHeader, { - ctrlKey: true, - charCode: 17 - })}) + await waitFor(() => { + fireEvent.keyDown(semanticModelIdHeader, { + ctrlKey: true, + charCode: 17, + }); + }); expect(supplierPartsComponent['ctrlKeyState']).toBeTruthy(); await waitFor(() => { - fireEvent.click(semanticModelIdHeader) + fireEvent.click(semanticModelIdHeader); }); - await waitFor(() => {fireEvent.keyUp(semanticModelIdHeader, { - ctrlKey: true, - charCode: 17 - })}) + await waitFor(() => { + fireEvent.keyUp(semanticModelIdHeader, { + ctrlKey: true, + charCode: 17, + }); + }); - await waitFor(() => {fireEvent.click(semanticModelIdHeader)}); - await waitFor(() => {fireEvent.click(semanticModelIdHeader)}); + await waitFor(() => { + fireEvent.click(semanticModelIdHeader); + }); + await waitFor(() => { + fireEvent.click(semanticModelIdHeader); + }); expect(supplierPartsComponent['tableSupplierAsBuiltSortList']).toEqual([]); }); + + it('should handle updateSupplierParts null', async () => { + const { fixture } = await renderSupplierParts(); + const supplierPartsComponent = fixture.componentInstance; + + const otherPartsFacade = (supplierPartsComponent as any)['otherPartsFacade']; + const updateSupplierPartAsBuiltSpy = spyOn(otherPartsFacade, 'setSupplierPartsAsBuilt'); + const updateSupplierPartAsPlannedSpy = spyOn(otherPartsFacade, 'setSupplierPartsAsPlanned'); + + supplierPartsComponent.updateSupplierParts(); + + + expect(updateSupplierPartAsBuiltSpy).toHaveBeenCalledWith(); + expect(updateSupplierPartAsPlannedSpy).toHaveBeenCalledWith(); + + }); + + it('should handle updateCustomerParts including search', async () => { + const { fixture } = await renderSupplierParts(); + const supplierPartsComponent = fixture.componentInstance; + + const otherPartsFacade = (supplierPartsComponent as any)['otherPartsFacade']; + const updateSupplierPartAsBuiltSpy = spyOn(otherPartsFacade, 'setSupplierPartsAsBuilt'); + const updateSupplierPartAsPlannedSpy = spyOn(otherPartsFacade, 'setSupplierPartsAsPlanned'); + + + const search = 'test'; + supplierPartsComponent.updateSupplierParts(search); + + + expect(updateSupplierPartAsBuiltSpy).toHaveBeenCalledWith(0, 50, [], toGlobalSearchAssetFilter(search, true), true); + expect(updateSupplierPartAsPlannedSpy).toHaveBeenCalledWith(0, 50, [], toGlobalSearchAssetFilter(search, false), true); + + }); + + }); diff --git a/frontend/src/app/modules/page/other-parts/presentation/supplier-parts/supplier-parts.component.ts b/frontend/src/app/modules/page/other-parts/presentation/supplier-parts/supplier-parts.component.ts index 754520bfea..ad6fc51b05 100644 --- a/frontend/src/app/modules/page/other-parts/presentation/supplier-parts/supplier-parts.component.ts +++ b/frontend/src/app/modules/page/other-parts/presentation/supplier-parts/supplier-parts.component.ts @@ -18,141 +18,154 @@ ********************************************************************************/ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; -import {Pagination} from '@core/model/pagination.model'; -import {OtherPartsFacade} from '@page/other-parts/core/other-parts.facade'; -import {MainAspectType} from '@page/parts/model/mainAspectType.enum'; -import {Part, SemanticDataModel} from '@page/parts/model/parts.model'; -import {PartTableType, TableEventConfig, TableHeaderSort,} from '@shared/components/table/table.model'; -import {TableSortingUtil} from '@shared/components/table/tableSortingUtil'; -import {View} from '@shared/model/view.model'; -import {PartDetailsFacade} from '@shared/modules/part-details/core/partDetails.facade'; -import {StaticIdService} from '@shared/service/staticId.service'; -import {BehaviorSubject, Observable, Subject} from 'rxjs'; -import {toAssetFilter} from "@shared/helper/filter-helper"; +import { Component, Input, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core'; +import { Pagination } from '@core/model/pagination.model'; +import { OtherPartsFacade } from '@page/other-parts/core/other-parts.facade'; +import { MainAspectType } from '@page/parts/model/mainAspectType.enum'; +import { Part, SemanticDataModel } from '@page/parts/model/parts.model'; +import { PartsTableComponent } from '@shared/components/parts-table/parts-table.component'; +import { PartTableType, TableEventConfig, TableHeaderSort } from '@shared/components/table/table.model'; +import { TableSortingUtil } from '@shared/components/table/tableSortingUtil'; +import { toAssetFilter, toGlobalSearchAssetFilter } from '@shared/helper/filter-helper'; +import { View } from '@shared/model/view.model'; +import { PartDetailsFacade } from '@shared/modules/part-details/core/partDetails.facade'; +import { StaticIdService } from '@shared/service/staticId.service'; +import { BehaviorSubject, Observable, Subject } from 'rxjs'; @Component({ - selector: 'app-supplier-parts', - templateUrl: './supplier-parts.component.html', - styleUrls: ['../other-parts.component.scss'], + selector: 'app-supplier-parts', + templateUrl: './supplier-parts.component.html', + styleUrls: [ '../other-parts.component.scss' ], }) export class SupplierPartsComponent implements OnInit, OnDestroy { - public supplierPartsAsBuilt$: Observable>>; - public supplierPartsAsPlanned$: Observable>>; - - public readonly deselectPartTrigger$ = new Subject(); - public readonly addPartTrigger$ = new Subject(); - - public readonly isInvestigationOpen$ = new BehaviorSubject(false); - public selectedItems: Array = []; - - public readonly supplierTabLabelId = this.staticIdService.generateId('OtherParts.supplierTabLabel'); - - public tableSupplierAsBuiltSortList: TableHeaderSort[]; - public tableSupplierAsPlannedSortList: TableHeaderSort[]; - - private ctrlKeyState = false; - - @Input() - public bomLifecycle: MainAspectType; - - constructor( - private readonly otherPartsFacade: OtherPartsFacade, - private readonly partDetailsFacade: PartDetailsFacade, - private readonly staticIdService: StaticIdService, - ) { - - window.addEventListener('keydown', (event) => { - this.ctrlKeyState = event.ctrlKey; - }); - window.addEventListener('keyup', (event) => { - this.ctrlKeyState = event.ctrlKey; - }); - } - - public get currentSelectedItems(): Part[] { - - this.selectedItems = this.selectedItems.map(part => { - return { - ...part, - semanticDataModel: SemanticDataModel[part.semanticDataModel.toUpperCase() as keyof typeof SemanticDataModel], - }; - }); - return this.selectedItems || []; - } - - public set currentSelectedItems(parts: Part[]) { - this.selectedItems = parts; + public supplierPartsAsBuilt$: Observable>>; + public supplierPartsAsPlanned$: Observable>>; + + public readonly deselectPartTrigger$ = new Subject(); + public readonly addPartTrigger$ = new Subject(); + + public readonly isInvestigationOpen$ = new BehaviorSubject(false); + public selectedItems: Array = []; + + public readonly supplierTabLabelId = this.staticIdService.generateId('OtherParts.supplierTabLabel'); + + public tableSupplierAsBuiltSortList: TableHeaderSort[]; + public tableSupplierAsPlannedSortList: TableHeaderSort[]; + + private ctrlKeyState = false; + + @Input() + public bomLifecycle: MainAspectType; + + @ViewChildren(PartsTableComponent) partsTableComponents: QueryList; + + constructor( + private readonly otherPartsFacade: OtherPartsFacade, + private readonly partDetailsFacade: PartDetailsFacade, + private readonly staticIdService: StaticIdService, + ) { + + window.addEventListener('keydown', (event) => { + this.ctrlKeyState = event.ctrlKey; + }); + window.addEventListener('keyup', (event) => { + this.ctrlKeyState = event.ctrlKey; + }); + } + + public get currentSelectedItems(): Part[] { + + this.selectedItems = this.selectedItems.map(part => { + return { + ...part, + semanticDataModel: SemanticDataModel[part.semanticDataModel.toUpperCase() as keyof typeof SemanticDataModel], + }; + }); + return this.selectedItems || []; + } + + public set currentSelectedItems(parts: Part[]) { + this.selectedItems = parts; + } + + public ngOnInit(): void { + if (this.bomLifecycle === MainAspectType.AS_BUILT) { + this.supplierPartsAsBuilt$ = this.otherPartsFacade.supplierPartsAsBuilt$; + this.tableSupplierAsBuiltSortList = []; + this.otherPartsFacade.setSupplierPartsAsBuilt(); + } else if (this.bomLifecycle === MainAspectType.AS_PLANNED) { + this.supplierPartsAsPlanned$ = this.otherPartsFacade.supplierPartsAsPlanned$; + this.tableSupplierAsPlannedSortList = []; + this.otherPartsFacade.setSupplierPartsAsPlanned(); } + } - public ngOnInit(): void { - if (this.bomLifecycle === MainAspectType.AS_BUILT) { - this.supplierPartsAsBuilt$ = this.otherPartsFacade.supplierPartsAsBuilt$; - this.tableSupplierAsBuiltSortList = []; - this.otherPartsFacade.setSupplierPartsAsBuilt(); - } else if (this.bomLifecycle === MainAspectType.AS_PLANNED) { - this.supplierPartsAsPlanned$ = this.otherPartsFacade.supplierPartsAsPlanned$; - this.tableSupplierAsPlannedSortList = []; - this.otherPartsFacade.setSupplierPartsAsPlanned(); - } + filterActivated(isAsBuilt: boolean, assetFilter: any): void { + if (isAsBuilt) { + this.otherPartsFacade.setSupplierPartsAsBuilt(0, 50, [], toAssetFilter(assetFilter, true)); + } else { + this.otherPartsFacade.setSupplierPartsAsPlanned(0, 50, [], toAssetFilter(assetFilter, false)); } - - filterActivated(isAsBuilt: boolean, assetFilter: any): void { - if (isAsBuilt) { - this.otherPartsFacade.setSupplierPartsAsBuilt(0, 50, [], toAssetFilter(assetFilter, true)) - } else { - this.otherPartsFacade.setSupplierPartsAsPlanned(0, 50, [], toAssetFilter(assetFilter, false)) - } + } + + updateSupplierParts(searchValue?: string): void { + if (searchValue || searchValue === '') { + this.otherPartsFacade.setSupplierPartsAsBuilt(0, 50, [], toGlobalSearchAssetFilter(searchValue, true), true); + this.otherPartsFacade.setSupplierPartsAsPlanned(0, 50, [], toGlobalSearchAssetFilter(searchValue, false), true); + } else { + this.otherPartsFacade.setSupplierPartsAsBuilt(); + this.otherPartsFacade.setSupplierPartsAsPlanned(); } + } - public ngOnDestroy(): void { - this.otherPartsFacade.unsubscribeParts(); - } + public ngOnDestroy(): void { + this.otherPartsFacade.unsubscribeParts(); + } - public onSelectItem(event: Record): void { - this.partDetailsFacade.selectedPart = event as unknown as Part; - } + public onSelectItem(event: Record): void { + this.partDetailsFacade.selectedPart = event as unknown as Part; + } - public onAsBuiltTableConfigChange({page, pageSize, sorting}: TableEventConfig): void { - this.setTableSortingList(sorting, MainAspectType.AS_BUILT); - this.otherPartsFacade.setSupplierPartsAsBuilt(page, pageSize, this.tableSupplierAsBuiltSortList); - } + public onAsBuiltTableConfigChange({ page, pageSize, sorting }: TableEventConfig): void { + this.setTableSortingList(sorting, MainAspectType.AS_BUILT); + this.otherPartsFacade.setSupplierPartsAsBuilt(page, pageSize, this.tableSupplierAsBuiltSortList); + } - public onAsPlannedTableConfigChange({page, pageSize, sorting}: TableEventConfig): void { - this.setTableSortingList(sorting, MainAspectType.AS_PLANNED); - this.otherPartsFacade.setSupplierPartsAsPlanned(page, pageSize, this.tableSupplierAsPlannedSortList); - } + public onAsPlannedTableConfigChange({ page, pageSize, sorting }: TableEventConfig): void { + this.setTableSortingList(sorting, MainAspectType.AS_PLANNED); + this.otherPartsFacade.setSupplierPartsAsPlanned(page, pageSize, this.tableSupplierAsPlannedSortList); + } - public onMultiSelect(event: unknown[]): void { - this.currentSelectedItems = event as Part[]; - } + public onMultiSelect(event: unknown[]): void { + this.currentSelectedItems = event as Part[]; + } - public removeItemFromSelection(part: Part): void { - this.deselectPartTrigger$.next([part]); - this.currentSelectedItems = this.currentSelectedItems.filter(({id}) => id !== part.id); - } + public removeItemFromSelection(part: Part): void { + this.deselectPartTrigger$.next([ part ]); + this.currentSelectedItems = this.currentSelectedItems.filter(({ id }) => id !== part.id); + } - public clearSelected(): void { - this.deselectPartTrigger$.next(this.currentSelectedItems); - this.currentSelectedItems = []; - } + public clearSelected(): void { + this.deselectPartTrigger$.next(this.currentSelectedItems); + this.currentSelectedItems = []; + } - public addItemToSelection(part: Part): void { - this.addPartTrigger$.next(part); - this.currentSelectedItems = [...this.currentSelectedItems, part]; - } + public addItemToSelection(part: Part): void { + this.addPartTrigger$.next(part); + this.currentSelectedItems = [ ...this.currentSelectedItems, part ]; + } - public submit(): void { - this.isInvestigationOpen$.next(false); - } + public submit(): void { + this.isInvestigationOpen$.next(false); + } - private setTableSortingList(sorting: TableHeaderSort, partTable: MainAspectType): void { - const tableSortList = partTable === MainAspectType.AS_BUILT ? this.tableSupplierAsBuiltSortList : this.tableSupplierAsPlannedSortList; - TableSortingUtil.setTableSortingList(sorting, tableSortList, this.ctrlKeyState); - } + private setTableSortingList(sorting: TableHeaderSort, partTable: MainAspectType): void { + const tableSortList = partTable === MainAspectType.AS_BUILT ? this.tableSupplierAsBuiltSortList : this.tableSupplierAsPlannedSortList; + TableSortingUtil.setTableSortingList(sorting, tableSortList, this.ctrlKeyState); + } - protected readonly MainAspectType = MainAspectType; - protected readonly PartTableType = PartTableType; + protected readonly MainAspectType = MainAspectType; + protected readonly PartTableType = PartTableType; } diff --git a/frontend/src/app/modules/page/parts/model/parts.model.ts b/frontend/src/app/modules/page/parts/model/parts.model.ts index 810c89f922..8cda20e428 100644 --- a/frontend/src/app/modules/page/parts/model/parts.model.ts +++ b/frontend/src/app/modules/page/parts/model/parts.model.ts @@ -63,6 +63,10 @@ export interface Part { psFunction: string; functionValidFrom?: string; functionValidUntil?: string; + + // count of notifications + activeAlerts: number; + activeInvestigations: number; } export interface PartResponse { @@ -82,7 +86,11 @@ export interface PartResponse { van: string; semanticDataModel: SemanticDataModel; classification: string; - detailAspectModels: DetailAspectModel[] + detailAspectModels: DetailAspectModel[]; + + // TODO: Delete ? flag when AsPlanned Parts do not return the props anymore + qualityAlertsInStatusActive?: number; + qualityInvestigationsInStatusActive?: number; } @@ -129,7 +137,7 @@ export interface AssetAsBuiltFilter { classification?: string, nameAtCustomer?: string, semanticModelId?: string, - semanticDataModel?: string, + semanticDataModel?: string[], manufacturingDate?: string, manufacturingCountry?: string } @@ -141,7 +149,7 @@ export interface AssetAsPlannedFilter { manufacturer?: string, manufacturerPartId?: string, classification?: string, - semanticDataModel?: string, + semanticDataModel?: string[], semanticModelId?: string, validityPeriodFrom?: string, validityPeriodTo?: string, diff --git a/frontend/src/app/modules/page/parts/presentation/parts.component.ts b/frontend/src/app/modules/page/parts/presentation/parts.component.ts index 02fd4f8623..a13ea34a73 100644 --- a/frontend/src/app/modules/page/parts/presentation/parts.component.ts +++ b/frontend/src/app/modules/page/parts/presentation/parts.component.ts @@ -23,7 +23,7 @@ import {AfterViewInit, Component, OnDestroy, OnInit, QueryList, ViewChildren} fr import {Pagination} from '@core/model/pagination.model'; import {PartsFacade} from '@page/parts/core/parts.facade'; import {MainAspectType} from '@page/parts/model/mainAspectType.enum'; -import {Part} from '@page/parts/model/parts.model'; +import {AssetAsBuiltFilter, AssetAsPlannedFilter, Part} from '@page/parts/model/parts.model'; import {PartTableType, TableEventConfig, TableHeaderSort,} from '@shared/components/table/table.model'; import {View} from '@shared/model/view.model'; import {PartDetailsFacade} from '@shared/modules/part-details/core/partDetails.facade'; @@ -57,6 +57,7 @@ export class PartsComponent implements OnInit, OnDestroy, AfterViewInit { public tableAsBuiltSortList: TableHeaderSort[]; public tableAsPlannedSortList: TableHeaderSort[]; + public DEFAULT_PAGE_SIZE = 50; public ctrlKeyState = false; @ViewChildren(PartsTableComponent) partsTableComponents: QueryList; @@ -86,6 +87,8 @@ export class PartsComponent implements OnInit, OnDestroy, AfterViewInit { public searchFormGroup = new FormGroup({}); public searchControl: FormControl; + assetFilter: AssetAsBuiltFilter | AssetAsPlannedFilter; + public ngOnInit(): void { this.partsFacade.setPartsAsBuilt(); this.partsFacade.setPartsAsPlanned(); @@ -94,25 +97,22 @@ export class PartsComponent implements OnInit, OnDestroy, AfterViewInit { } filterActivated(isAsBuilt: boolean, assetFilter: any): void { + this.assetFilter = assetFilter; if (isAsBuilt) { - this.partsFacade.setPartsAsBuilt(0, 50, [], toAssetFilter(assetFilter, true)); + this.partsFacade.setPartsAsBuilt(0, this.DEFAULT_PAGE_SIZE, this.tableAsBuiltSortList, toAssetFilter(this.assetFilter, true)); } else { - this.partsFacade.setPartsAsPlanned(0, 50, [], toAssetFilter(assetFilter, false)); + this.partsFacade.setPartsAsPlanned(0, this.DEFAULT_PAGE_SIZE, this.tableAsPlannedSortList, toAssetFilter(this.assetFilter, false)); } } triggerPartSearch() { - let filterSet = false; - this.resetLocalFilters(filterSet); - if (filterSet) { - this.toastService.info("parts.input.global-search.toastInfo"); - } + this.resetFilterAndShowToast(); const searchValue = this.searchFormGroup.get("partSearch").value; if (searchValue && searchValue !== "") { - this.partsFacade.setPartsAsPlanned(0, 50, [], toGlobalSearchAssetFilter(searchValue, false), true); - this.partsFacade.setPartsAsBuilt(0, 50, [], toGlobalSearchAssetFilter(searchValue, true), true); + this.partsFacade.setPartsAsPlanned(0, this.DEFAULT_PAGE_SIZE, this.tableAsBuiltSortList, toGlobalSearchAssetFilter(searchValue, false), true); + this.partsFacade.setPartsAsBuilt(0, this.DEFAULT_PAGE_SIZE, this.tableAsPlannedSortList, toGlobalSearchAssetFilter(searchValue, true), true); } else { this.partsFacade.setPartsAsBuilt(); this.partsFacade.setPartsAsPlanned(); @@ -121,11 +121,11 @@ export class PartsComponent implements OnInit, OnDestroy, AfterViewInit { } - private resetLocalFilters(filterIsSet: boolean) { + private resetFilterAndShowToast() { for (const partTableComponent of this.partsTableComponents) { - if (partTableComponent.multiSelectAutocompleteComponent.theSearchElement) { - filterIsSet = true; + if (partTableComponent.filterFormGroup.dirty) { partTableComponent.filterFormGroup.reset(); + this.toastService.info("parts.input.global-search.toastInfo"); } } } @@ -144,12 +144,33 @@ export class PartsComponent implements OnInit, OnDestroy, AfterViewInit { public onAsBuiltTableConfigChange({page, pageSize, sorting}: TableEventConfig): void { this.setTableSortingList(sorting, MainAspectType.AS_BUILT); - this.partsFacade.setPartsAsBuilt(page, pageSize, this.tableAsBuiltSortList); + + let pageSizeValue = this.DEFAULT_PAGE_SIZE; + if (pageSize !== 0) { + pageSizeValue = pageSize; + } + + if (this.assetFilter) { + this.partsFacade.setPartsAsBuilt(0, pageSizeValue, this.tableAsBuiltSortList, toAssetFilter(this.assetFilter, true)); + } else { + this.partsFacade.setPartsAsBuilt(page, pageSizeValue, this.tableAsBuiltSortList); + } + } public onAsPlannedTableConfigChange({page, pageSize, sorting}: TableEventConfig): void { - this.setTableSortingList(sorting, MainAspectType.AS_PLANNED); - this.partsFacade.setPartsAsPlanned(page, pageSize, this.tableAsPlannedSortList); + + let pageSizeValue = this.DEFAULT_PAGE_SIZE; + if (pageSize !== 0) { + pageSizeValue = pageSize; + } + + if (this.assetFilter) { + this.partsFacade.setPartsAsPlanned(0, pageSizeValue, this.tableAsPlannedSortList, toAssetFilter(this.assetFilter, true)); + } else { + this.partsFacade.setPartsAsPlanned(page, pageSizeValue, this.tableAsPlannedSortList); + } + } public handleTableActivationEvent(bomLifecycleSize: BomLifecycleSize) { diff --git a/frontend/src/app/modules/shared/assembler/parts.assembler.ts b/frontend/src/app/modules/shared/assembler/parts.assembler.ts index e415487edf..190b52d44a 100644 --- a/frontend/src/app/modules/shared/assembler/parts.assembler.ts +++ b/frontend/src/app/modules/shared/assembler/parts.assembler.ts @@ -103,6 +103,11 @@ export class PartsAssembler { psFunction: psFunction, functionValidFrom: functionValidFrom, functionValidUntil: functionValidUntil, + + // count of notifications + activeAlerts: partResponse.qualityAlertsInStatusActive, + activeInvestigations: partResponse.qualityInvestigationsInStatusActive, + } return mappedPart; @@ -231,6 +236,8 @@ export class PartsAssembler { ['psFunction', 'function'], ['functionValidFrom', 'functionValidFrom'], ['functionValidUntil', 'functionValidUntil'], + [ 'activeAlerts', 'qualityAlertsInStatusActive' ], + [ 'activeInvestigations', 'qualityInvestigationsInStatusActive' ], ]); diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/sass/_variables.scss b/frontend/src/app/modules/shared/components/country-flag-generator/sass/_variables.scss index ae9e32d82f..d8039ebe02 100644 --- a/frontend/src/app/modules/shared/components/country-flag-generator/sass/_variables.scss +++ b/frontend/src/app/modules/shared/components/country-flag-generator/sass/_variables.scss @@ -1,4 +1,4 @@ -$flag-icon-css-path: "../flags" !default; +$flag-icon-css-path: "/assets/images/flags" !default; $flag-icon-rect-path: "/4x3" !default; $countries: ( diff --git a/frontend/src/app/modules/shared/components/multi-select-autocomplete/multi-select-autocomplete.component.html b/frontend/src/app/modules/shared/components/multi-select-autocomplete/multi-select-autocomplete.component.html index 36a2b779b4..f4207c838a 100644 --- a/frontend/src/app/modules/shared/components/multi-select-autocomplete/multi-select-autocomplete.component.html +++ b/frontend/src/app/modules/shared/components/multi-select-autocomplete/multi-select-autocomplete.component.html @@ -37,7 +37,7 @@ {{onDisplayString()}} {{this.theSearchElement}} + [style.display]="shouldHideTextSearchOptionField() ? 'none': 'flex'">{{this.theSearchElement}} {{option[display]}} diff --git a/frontend/src/app/modules/shared/components/multi-select-autocomplete/multi-select-autocomplete.component.ts b/frontend/src/app/modules/shared/components/multi-select-autocomplete/multi-select-autocomplete.component.ts index b7b573feb7..5e5c3062f2 100644 --- a/frontend/src/app/modules/shared/components/multi-select-autocomplete/multi-select-autocomplete.component.ts +++ b/frontend/src/app/modules/shared/components/multi-select-autocomplete/multi-select-autocomplete.component.ts @@ -68,6 +68,10 @@ export class MultiSelectAutocompleteComponent implements OnChanges { selectAllChecked = false; displayString = ''; + shouldHideTextSearchOptionField():boolean{ + return !this.textSearch || this.textSearch && (this.theSearchElement === null || this.theSearchElement === ''); + } + ngOnChanges(): void { this.filteredOptions = this.options; if (this.selectedOptions) { diff --git a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.html b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.html index 48e6478b2f..7cf2ce4e94 100644 --- a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.html +++ b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.html @@ -99,16 +99,10 @@

{{ 'table.noResultFound' | i18n }}

- - - - - - @@ -153,50 +147,6 @@

{{ 'table.noResultFound' | i18n }}

- - - - {{ tableConfig?.header?.[column] | i18n }} - - - -
- - {{ (i + 1) + "." }}{{ item[1] === 'asc' ? '↑' : item[1] === 'desc' ? '↓' : '' }} -
-
-
-
- - - - - - - -
-
- {{ 'table.noResultFound' | i18n }} - + + + + > + + + + + + notification_important + + + + + inbox + + + + + + + + + diff --git a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.scss b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.scss index 79e1c1c339..e6131b9d68 100644 --- a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.scss +++ b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.scss @@ -109,6 +109,24 @@ table { padding: 0 10px; } +.table--notification--cell { + display: flex; + align-items: center; +} + +.table--notification--cell--content { + flex: 1; +} + +.table--notification--cell--content--icon { + flex: 8; +} + + +.table--notification--icon { + color: #888888; +} + .table--selected__container { position: sticky; top: 0; diff --git a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.spec.ts b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.spec.ts index 5be560583f..f486a60355 100644 --- a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.spec.ts +++ b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.spec.ts @@ -132,6 +132,8 @@ describe('PartsTableComponent', () => { 'filterSemanticDataModel', 'filterManufacturingDate', 'filterManufacturingCountry', + 'filterActiveAlerts', + 'filterActiveInvestigations', ]); }); diff --git a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.ts b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.ts index 950c9037d4..27e0689ac2 100644 --- a/frontend/src/app/modules/shared/components/parts-table/parts-table.component.ts +++ b/frontend/src/app/modules/shared/components/parts-table/parts-table.component.ts @@ -148,6 +148,8 @@ export class PartsTableComponent implements OnInit { 'filterSemanticDataModel', 'filterManufacturingDate', 'filterManufacturingCountry', + 'filterActiveAlerts', + 'filterActiveInvestigations', ]; private readonly displayedColumnsAsPlanned: string[] = [ @@ -183,6 +185,8 @@ export class PartsTableComponent implements OnInit { 'semanticDataModel', 'manufacturingDate', 'manufacturingCountry', + 'activeAlerts', + 'activeInvestigations', ]; @@ -218,6 +222,8 @@ export class PartsTableComponent implements OnInit { semanticDataModel: true, manufacturingDate: true, manufacturingCountry: true, + activeAlerts: true, + activeInvestigations: true, }; @@ -266,6 +272,8 @@ export class PartsTableComponent implements OnInit { 'filterPartId', 'filterSemanticModelId', 'filterManufacturingDate', + 'filterActiveAlerts', + 'filterActiveInvestigations', ]; @@ -277,6 +285,8 @@ export class PartsTableComponent implements OnInit { 'filterPartId', 'filterSemanticModelId', 'filterManufacturingDate', + 'filterActiveAlerts', + 'filterActiveInvestigations', ]; private readonly displayedColumnsAsBuiltCustomerForTable: string[] = [ @@ -287,6 +297,8 @@ export class PartsTableComponent implements OnInit { 'partId', 'semanticModelId', 'manufacturingDate', + 'activeAlerts', + 'activeInvestigations', ]; @@ -296,7 +308,9 @@ export class PartsTableComponent implements OnInit { manufacturer: true, partId: true, semanticModelId: true, - manufacturingDate: true + manufacturingDate: true, + activeAlerts: true, + activeInvestigations: true, }; private readonly displayedColumnsAsPlannedCustomerForTable: string[] = [ @@ -325,6 +339,8 @@ export class PartsTableComponent implements OnInit { 'partId', 'semanticModelId', 'manufacturingDate', + 'activeAlerts', + 'activeInvestigations', ]; private readonly sortableColumnsAsBuiltSupplier: Record = { @@ -334,7 +350,8 @@ export class PartsTableComponent implements OnInit { partId: true, semanticModelId: true, manufacturingDate: true, - + activeAlerts: true, + activeInvestigations: true, }; private readonly displayedColumnsAsPlannedSupplierForTable: string[] = [ @@ -445,6 +462,8 @@ export class PartsTableComponent implements OnInit { {filterKey: 'semanticDataModel', headerKey: 'filterSemanticDataModel', isTextSearch: false, option: this.semanticDataModelOptions}, {filterKey: 'manufacturingDate', headerKey: 'filterManufacturingDate', isTextSearch: true, option: this.optionTextSearch}, {filterKey: 'manufacturingCountry', headerKey: 'filterManufacturingCountry', isTextSearch: true, option: this.optionTextSearch}, + {filterKey: 'activeAlerts', headerKey: 'filterActiveAlerts', isTextSearch: true, option: this.optionTextSearch}, + {filterKey: 'activeInvestigations', headerKey: 'filterActiveInvestigations', isTextSearch: true, option: this.optionTextSearch}, ]; @@ -462,6 +481,8 @@ export class PartsTableComponent implements OnInit { semanticDataModel: new FormControl([]), manufacturingDate: new FormControl([]), manufacturingCountry: new FormControl([]), + activeAlerts: new FormControl([]), + activeInvestigations: new FormControl([]), }; assetAsPlannedFilterFormGroup = { @@ -508,7 +529,9 @@ export class PartsTableComponent implements OnInit { manufacturerName: new FormControl([]), manufacturerPartId: new FormControl([]), semanticModelId: new FormControl([]), - manufacturingDate: new FormControl([]) + manufacturingDate: new FormControl([]), + activeAlerts: new FormControl([]), + activeInvestigations: new FormControl([]), }; assetAsBuiltCustomerFilterFormGroup = { @@ -518,7 +541,9 @@ export class PartsTableComponent implements OnInit { manufacturerName: new FormControl([]), manufacturerPartId: new FormControl([]), semanticModelId: new FormControl([]), - manufacturingDate: new FormControl([]) + manufacturingDate: new FormControl([]), + activeAlerts: new FormControl([]), + activeInvestigations: new FormControl([]), }; private readonly assetAsPlannedCustomerFilterConfiguration: any[] = [ @@ -548,6 +573,8 @@ export class PartsTableComponent implements OnInit { {filterKey: 'manufacturerPartId', headerKey: 'filterPartId', isTextSearch: true, option: this.optionTextSearch}, {filterKey: 'semanticModelId', headerKey: 'filterSemanticModelId', isTextSearch: true, option: this.optionTextSearch}, {filterKey: 'manufacturingDate', headerKey: 'filterManufacturingDate', isTextSearch: true, option: this.optionTextSearch}, + {filterKey: 'activeAlerts', headerKey: 'filterActiveAlerts', isTextSearch: true, option: this.optionTextSearch}, + {filterKey: 'activeInvestigations', headerKey: 'filterActiveInvestigations', isTextSearch: true, option: this.optionTextSearch}, ]; @@ -558,7 +585,10 @@ export class PartsTableComponent implements OnInit { {filterKey: 'manufacturerName', headerKey: 'filterManufacturer', isTextSearch: true, option: this.optionTextSearch}, {filterKey: 'manufacturerPartId', headerKey: 'filterPartId', isTextSearch: true, option: this.optionTextSearch}, {filterKey: 'semanticModelId', headerKey: 'filterSemanticModelId', isTextSearch: true, option: this.optionTextSearch}, - {filterKey: 'manufacturingDate', headerKey: 'filterManufacturingDate', isTextSearch: true, option: this.optionTextSearch}]; + {filterKey: 'manufacturingDate', headerKey: 'filterManufacturingDate', isTextSearch: true, option: this.optionTextSearch}, + {filterKey: 'activeAlerts', headerKey: 'filterActiveAlerts', isTextSearch: true, option: this.optionTextSearch}, + {filterKey: 'activeInvestigations', headerKey: 'filterActiveInvestigations', isTextSearch: true, option: this.optionTextSearch}, + ]; private readonly assetAsPlannedFilterConfiguration: any[] = [ diff --git a/frontend/src/app/modules/shared/helper/filter-helper.ts b/frontend/src/app/modules/shared/helper/filter-helper.ts index 6cd8138b31..2c0723a01a 100644 --- a/frontend/src/app/modules/shared/helper/filter-helper.ts +++ b/frontend/src/app/modules/shared/helper/filter-helper.ts @@ -26,21 +26,24 @@ import {HttpParams} from "@angular/common/http"; export function enrichFilterAndGetUpdatedParams(filter: AssetAsBuiltFilter, params: HttpParams): HttpParams { + const semanticDataModelKey = "semanticDataModel"; for (const key in filter) { - - const value = filter[key]; - if (value.length !== 0) { - // Modify this line to format the filter - let operator: string; - if (key === "semanticDataModel") { - operator = getFilterOperatorValue(FilterOperator.EQUAL); - } else if (key.toLowerCase().includes('date')) { - operator = getFilterOperatorValue(FilterOperator.AT_LOCAL_DATE); - } else { - operator = getFilterOperatorValue(FilterOperator.STARTS_WITH); + let operator: string; + const filterValues = filter[key]; + if (key !== semanticDataModelKey) { + if (filterValues.length !== 0) { + if (key.toLowerCase().includes('date')) { + operator = getFilterOperatorValue(FilterOperator.AT_LOCAL_DATE); + } else { + operator = getFilterOperatorValue(FilterOperator.STARTS_WITH); + } + params = params.append('filter', `${key},${operator},${filterValues}`); + } + } else { + operator = getFilterOperatorValue(FilterOperator.EQUAL); + for (let value of filterValues) { + params = params.append('filter', `${key},${operator},${value}`); } - params = params.append('filter', `${key},${operator},${value}`); - } } return params; diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ad.svg b/frontend/src/assets/images/flags/4x3/ad.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ad.svg rename to frontend/src/assets/images/flags/4x3/ad.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ae.svg b/frontend/src/assets/images/flags/4x3/ae.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ae.svg rename to frontend/src/assets/images/flags/4x3/ae.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/af.svg b/frontend/src/assets/images/flags/4x3/af.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/af.svg rename to frontend/src/assets/images/flags/4x3/af.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ag.svg b/frontend/src/assets/images/flags/4x3/ag.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ag.svg rename to frontend/src/assets/images/flags/4x3/ag.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ai.svg b/frontend/src/assets/images/flags/4x3/ai.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ai.svg rename to frontend/src/assets/images/flags/4x3/ai.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/al.svg b/frontend/src/assets/images/flags/4x3/al.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/al.svg rename to frontend/src/assets/images/flags/4x3/al.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/am.svg b/frontend/src/assets/images/flags/4x3/am.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/am.svg rename to frontend/src/assets/images/flags/4x3/am.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ao.svg b/frontend/src/assets/images/flags/4x3/ao.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ao.svg rename to frontend/src/assets/images/flags/4x3/ao.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/aq.svg b/frontend/src/assets/images/flags/4x3/aq.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/aq.svg rename to frontend/src/assets/images/flags/4x3/aq.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ar.svg b/frontend/src/assets/images/flags/4x3/ar.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ar.svg rename to frontend/src/assets/images/flags/4x3/ar.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/as.svg b/frontend/src/assets/images/flags/4x3/as.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/as.svg rename to frontend/src/assets/images/flags/4x3/as.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/at.svg b/frontend/src/assets/images/flags/4x3/at.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/at.svg rename to frontend/src/assets/images/flags/4x3/at.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/au.svg b/frontend/src/assets/images/flags/4x3/au.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/au.svg rename to frontend/src/assets/images/flags/4x3/au.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/aw.svg b/frontend/src/assets/images/flags/4x3/aw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/aw.svg rename to frontend/src/assets/images/flags/4x3/aw.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ax.svg b/frontend/src/assets/images/flags/4x3/ax.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ax.svg rename to frontend/src/assets/images/flags/4x3/ax.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/az.svg b/frontend/src/assets/images/flags/4x3/az.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/az.svg rename to frontend/src/assets/images/flags/4x3/az.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ba.svg b/frontend/src/assets/images/flags/4x3/ba.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ba.svg rename to frontend/src/assets/images/flags/4x3/ba.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bb.svg b/frontend/src/assets/images/flags/4x3/bb.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bb.svg rename to frontend/src/assets/images/flags/4x3/bb.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bd.svg b/frontend/src/assets/images/flags/4x3/bd.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bd.svg rename to frontend/src/assets/images/flags/4x3/bd.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/be.svg b/frontend/src/assets/images/flags/4x3/be.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/be.svg rename to frontend/src/assets/images/flags/4x3/be.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bf.svg b/frontend/src/assets/images/flags/4x3/bf.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bf.svg rename to frontend/src/assets/images/flags/4x3/bf.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bg.svg b/frontend/src/assets/images/flags/4x3/bg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bg.svg rename to frontend/src/assets/images/flags/4x3/bg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bh.svg b/frontend/src/assets/images/flags/4x3/bh.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bh.svg rename to frontend/src/assets/images/flags/4x3/bh.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bi.svg b/frontend/src/assets/images/flags/4x3/bi.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bi.svg rename to frontend/src/assets/images/flags/4x3/bi.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bj.svg b/frontend/src/assets/images/flags/4x3/bj.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bj.svg rename to frontend/src/assets/images/flags/4x3/bj.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bl.svg b/frontend/src/assets/images/flags/4x3/bl.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bl.svg rename to frontend/src/assets/images/flags/4x3/bl.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bm.svg b/frontend/src/assets/images/flags/4x3/bm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bm.svg rename to frontend/src/assets/images/flags/4x3/bm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bn.svg b/frontend/src/assets/images/flags/4x3/bn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bn.svg rename to frontend/src/assets/images/flags/4x3/bn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bo.svg b/frontend/src/assets/images/flags/4x3/bo.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bo.svg rename to frontend/src/assets/images/flags/4x3/bo.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bq.svg b/frontend/src/assets/images/flags/4x3/bq.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bq.svg rename to frontend/src/assets/images/flags/4x3/bq.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/br.svg b/frontend/src/assets/images/flags/4x3/br.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/br.svg rename to frontend/src/assets/images/flags/4x3/br.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bs.svg b/frontend/src/assets/images/flags/4x3/bs.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bs.svg rename to frontend/src/assets/images/flags/4x3/bs.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bt.svg b/frontend/src/assets/images/flags/4x3/bt.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bt.svg rename to frontend/src/assets/images/flags/4x3/bt.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bv.svg b/frontend/src/assets/images/flags/4x3/bv.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bv.svg rename to frontend/src/assets/images/flags/4x3/bv.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bw.svg b/frontend/src/assets/images/flags/4x3/bw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bw.svg rename to frontend/src/assets/images/flags/4x3/bw.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/by.svg b/frontend/src/assets/images/flags/4x3/by.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/by.svg rename to frontend/src/assets/images/flags/4x3/by.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bz.svg b/frontend/src/assets/images/flags/4x3/bz.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/bz.svg rename to frontend/src/assets/images/flags/4x3/bz.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ca.svg b/frontend/src/assets/images/flags/4x3/ca.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ca.svg rename to frontend/src/assets/images/flags/4x3/ca.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cc.svg b/frontend/src/assets/images/flags/4x3/cc.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cc.svg rename to frontend/src/assets/images/flags/4x3/cc.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cd.svg b/frontend/src/assets/images/flags/4x3/cd.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cd.svg rename to frontend/src/assets/images/flags/4x3/cd.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cf.svg b/frontend/src/assets/images/flags/4x3/cf.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cf.svg rename to frontend/src/assets/images/flags/4x3/cf.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cg.svg b/frontend/src/assets/images/flags/4x3/cg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cg.svg rename to frontend/src/assets/images/flags/4x3/cg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ch.svg b/frontend/src/assets/images/flags/4x3/ch.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ch.svg rename to frontend/src/assets/images/flags/4x3/ch.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ci.svg b/frontend/src/assets/images/flags/4x3/ci.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ci.svg rename to frontend/src/assets/images/flags/4x3/ci.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ck.svg b/frontend/src/assets/images/flags/4x3/ck.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ck.svg rename to frontend/src/assets/images/flags/4x3/ck.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cl.svg b/frontend/src/assets/images/flags/4x3/cl.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cl.svg rename to frontend/src/assets/images/flags/4x3/cl.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cm.svg b/frontend/src/assets/images/flags/4x3/cm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cm.svg rename to frontend/src/assets/images/flags/4x3/cm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cn.svg b/frontend/src/assets/images/flags/4x3/cn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cn.svg rename to frontend/src/assets/images/flags/4x3/cn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/co.svg b/frontend/src/assets/images/flags/4x3/co.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/co.svg rename to frontend/src/assets/images/flags/4x3/co.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cr.svg b/frontend/src/assets/images/flags/4x3/cr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cr.svg rename to frontend/src/assets/images/flags/4x3/cr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cu.svg b/frontend/src/assets/images/flags/4x3/cu.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cu.svg rename to frontend/src/assets/images/flags/4x3/cu.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cv.svg b/frontend/src/assets/images/flags/4x3/cv.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cv.svg rename to frontend/src/assets/images/flags/4x3/cv.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cw.svg b/frontend/src/assets/images/flags/4x3/cw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cw.svg rename to frontend/src/assets/images/flags/4x3/cw.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cx.svg b/frontend/src/assets/images/flags/4x3/cx.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cx.svg rename to frontend/src/assets/images/flags/4x3/cx.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cy.svg b/frontend/src/assets/images/flags/4x3/cy.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cy.svg rename to frontend/src/assets/images/flags/4x3/cy.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cz.svg b/frontend/src/assets/images/flags/4x3/cz.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/cz.svg rename to frontend/src/assets/images/flags/4x3/cz.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/de.svg b/frontend/src/assets/images/flags/4x3/de.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/de.svg rename to frontend/src/assets/images/flags/4x3/de.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/dj.svg b/frontend/src/assets/images/flags/4x3/dj.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/dj.svg rename to frontend/src/assets/images/flags/4x3/dj.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/dk.svg b/frontend/src/assets/images/flags/4x3/dk.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/dk.svg rename to frontend/src/assets/images/flags/4x3/dk.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/dm.svg b/frontend/src/assets/images/flags/4x3/dm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/dm.svg rename to frontend/src/assets/images/flags/4x3/dm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/do.svg b/frontend/src/assets/images/flags/4x3/do.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/do.svg rename to frontend/src/assets/images/flags/4x3/do.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/dz.svg b/frontend/src/assets/images/flags/4x3/dz.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/dz.svg rename to frontend/src/assets/images/flags/4x3/dz.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ec.svg b/frontend/src/assets/images/flags/4x3/ec.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ec.svg rename to frontend/src/assets/images/flags/4x3/ec.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ee.svg b/frontend/src/assets/images/flags/4x3/ee.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ee.svg rename to frontend/src/assets/images/flags/4x3/ee.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/eg.svg b/frontend/src/assets/images/flags/4x3/eg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/eg.svg rename to frontend/src/assets/images/flags/4x3/eg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/eh.svg b/frontend/src/assets/images/flags/4x3/eh.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/eh.svg rename to frontend/src/assets/images/flags/4x3/eh.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/er.svg b/frontend/src/assets/images/flags/4x3/er.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/er.svg rename to frontend/src/assets/images/flags/4x3/er.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/es-ca.svg b/frontend/src/assets/images/flags/4x3/es-ca.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/es-ca.svg rename to frontend/src/assets/images/flags/4x3/es-ca.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/es.svg b/frontend/src/assets/images/flags/4x3/es.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/es.svg rename to frontend/src/assets/images/flags/4x3/es.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/et.svg b/frontend/src/assets/images/flags/4x3/et.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/et.svg rename to frontend/src/assets/images/flags/4x3/et.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/eu.svg b/frontend/src/assets/images/flags/4x3/eu.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/eu.svg rename to frontend/src/assets/images/flags/4x3/eu.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fi.svg b/frontend/src/assets/images/flags/4x3/fi.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fi.svg rename to frontend/src/assets/images/flags/4x3/fi.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fj.svg b/frontend/src/assets/images/flags/4x3/fj.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fj.svg rename to frontend/src/assets/images/flags/4x3/fj.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fk.svg b/frontend/src/assets/images/flags/4x3/fk.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fk.svg rename to frontend/src/assets/images/flags/4x3/fk.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fm.svg b/frontend/src/assets/images/flags/4x3/fm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fm.svg rename to frontend/src/assets/images/flags/4x3/fm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fo.svg b/frontend/src/assets/images/flags/4x3/fo.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fo.svg rename to frontend/src/assets/images/flags/4x3/fo.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fr.svg b/frontend/src/assets/images/flags/4x3/fr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/fr.svg rename to frontend/src/assets/images/flags/4x3/fr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ga.svg b/frontend/src/assets/images/flags/4x3/ga.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ga.svg rename to frontend/src/assets/images/flags/4x3/ga.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb-eng.svg b/frontend/src/assets/images/flags/4x3/gb-eng.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb-eng.svg rename to frontend/src/assets/images/flags/4x3/gb-eng.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb-nir.svg b/frontend/src/assets/images/flags/4x3/gb-nir.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb-nir.svg rename to frontend/src/assets/images/flags/4x3/gb-nir.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb-sct.svg b/frontend/src/assets/images/flags/4x3/gb-sct.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb-sct.svg rename to frontend/src/assets/images/flags/4x3/gb-sct.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb-wls.svg b/frontend/src/assets/images/flags/4x3/gb-wls.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb-wls.svg rename to frontend/src/assets/images/flags/4x3/gb-wls.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb.svg b/frontend/src/assets/images/flags/4x3/gb.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gb.svg rename to frontend/src/assets/images/flags/4x3/gb.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gd.svg b/frontend/src/assets/images/flags/4x3/gd.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gd.svg rename to frontend/src/assets/images/flags/4x3/gd.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ge.svg b/frontend/src/assets/images/flags/4x3/ge.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ge.svg rename to frontend/src/assets/images/flags/4x3/ge.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gf.svg b/frontend/src/assets/images/flags/4x3/gf.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gf.svg rename to frontend/src/assets/images/flags/4x3/gf.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gg.svg b/frontend/src/assets/images/flags/4x3/gg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gg.svg rename to frontend/src/assets/images/flags/4x3/gg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gh.svg b/frontend/src/assets/images/flags/4x3/gh.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gh.svg rename to frontend/src/assets/images/flags/4x3/gh.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gi.svg b/frontend/src/assets/images/flags/4x3/gi.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gi.svg rename to frontend/src/assets/images/flags/4x3/gi.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gl.svg b/frontend/src/assets/images/flags/4x3/gl.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gl.svg rename to frontend/src/assets/images/flags/4x3/gl.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gm.svg b/frontend/src/assets/images/flags/4x3/gm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gm.svg rename to frontend/src/assets/images/flags/4x3/gm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gn.svg b/frontend/src/assets/images/flags/4x3/gn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gn.svg rename to frontend/src/assets/images/flags/4x3/gn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gp.svg b/frontend/src/assets/images/flags/4x3/gp.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gp.svg rename to frontend/src/assets/images/flags/4x3/gp.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gq.svg b/frontend/src/assets/images/flags/4x3/gq.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gq.svg rename to frontend/src/assets/images/flags/4x3/gq.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gr.svg b/frontend/src/assets/images/flags/4x3/gr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gr.svg rename to frontend/src/assets/images/flags/4x3/gr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gs.svg b/frontend/src/assets/images/flags/4x3/gs.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gs.svg rename to frontend/src/assets/images/flags/4x3/gs.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gt.svg b/frontend/src/assets/images/flags/4x3/gt.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gt.svg rename to frontend/src/assets/images/flags/4x3/gt.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gu.svg b/frontend/src/assets/images/flags/4x3/gu.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gu.svg rename to frontend/src/assets/images/flags/4x3/gu.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gw.svg b/frontend/src/assets/images/flags/4x3/gw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gw.svg rename to frontend/src/assets/images/flags/4x3/gw.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gy.svg b/frontend/src/assets/images/flags/4x3/gy.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/gy.svg rename to frontend/src/assets/images/flags/4x3/gy.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hk.svg b/frontend/src/assets/images/flags/4x3/hk.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hk.svg rename to frontend/src/assets/images/flags/4x3/hk.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hm.svg b/frontend/src/assets/images/flags/4x3/hm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hm.svg rename to frontend/src/assets/images/flags/4x3/hm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hn.svg b/frontend/src/assets/images/flags/4x3/hn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hn.svg rename to frontend/src/assets/images/flags/4x3/hn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hr.svg b/frontend/src/assets/images/flags/4x3/hr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hr.svg rename to frontend/src/assets/images/flags/4x3/hr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ht.svg b/frontend/src/assets/images/flags/4x3/ht.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ht.svg rename to frontend/src/assets/images/flags/4x3/ht.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hu.svg b/frontend/src/assets/images/flags/4x3/hu.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/hu.svg rename to frontend/src/assets/images/flags/4x3/hu.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/id.svg b/frontend/src/assets/images/flags/4x3/id.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/id.svg rename to frontend/src/assets/images/flags/4x3/id.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ie.svg b/frontend/src/assets/images/flags/4x3/ie.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ie.svg rename to frontend/src/assets/images/flags/4x3/ie.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/il.svg b/frontend/src/assets/images/flags/4x3/il.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/il.svg rename to frontend/src/assets/images/flags/4x3/il.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/im.svg b/frontend/src/assets/images/flags/4x3/im.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/im.svg rename to frontend/src/assets/images/flags/4x3/im.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/in.svg b/frontend/src/assets/images/flags/4x3/in.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/in.svg rename to frontend/src/assets/images/flags/4x3/in.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/io.svg b/frontend/src/assets/images/flags/4x3/io.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/io.svg rename to frontend/src/assets/images/flags/4x3/io.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/iq.svg b/frontend/src/assets/images/flags/4x3/iq.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/iq.svg rename to frontend/src/assets/images/flags/4x3/iq.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ir.svg b/frontend/src/assets/images/flags/4x3/ir.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ir.svg rename to frontend/src/assets/images/flags/4x3/ir.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/is.svg b/frontend/src/assets/images/flags/4x3/is.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/is.svg rename to frontend/src/assets/images/flags/4x3/is.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/it.svg b/frontend/src/assets/images/flags/4x3/it.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/it.svg rename to frontend/src/assets/images/flags/4x3/it.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/je.svg b/frontend/src/assets/images/flags/4x3/je.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/je.svg rename to frontend/src/assets/images/flags/4x3/je.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/jm.svg b/frontend/src/assets/images/flags/4x3/jm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/jm.svg rename to frontend/src/assets/images/flags/4x3/jm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/jo.svg b/frontend/src/assets/images/flags/4x3/jo.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/jo.svg rename to frontend/src/assets/images/flags/4x3/jo.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/jp.svg b/frontend/src/assets/images/flags/4x3/jp.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/jp.svg rename to frontend/src/assets/images/flags/4x3/jp.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ke.svg b/frontend/src/assets/images/flags/4x3/ke.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ke.svg rename to frontend/src/assets/images/flags/4x3/ke.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kg.svg b/frontend/src/assets/images/flags/4x3/kg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kg.svg rename to frontend/src/assets/images/flags/4x3/kg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kh.svg b/frontend/src/assets/images/flags/4x3/kh.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kh.svg rename to frontend/src/assets/images/flags/4x3/kh.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ki.svg b/frontend/src/assets/images/flags/4x3/ki.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ki.svg rename to frontend/src/assets/images/flags/4x3/ki.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/km.svg b/frontend/src/assets/images/flags/4x3/km.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/km.svg rename to frontend/src/assets/images/flags/4x3/km.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kn.svg b/frontend/src/assets/images/flags/4x3/kn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kn.svg rename to frontend/src/assets/images/flags/4x3/kn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kp.svg b/frontend/src/assets/images/flags/4x3/kp.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kp.svg rename to frontend/src/assets/images/flags/4x3/kp.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kr.svg b/frontend/src/assets/images/flags/4x3/kr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kr.svg rename to frontend/src/assets/images/flags/4x3/kr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kw.svg b/frontend/src/assets/images/flags/4x3/kw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kw.svg rename to frontend/src/assets/images/flags/4x3/kw.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ky.svg b/frontend/src/assets/images/flags/4x3/ky.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ky.svg rename to frontend/src/assets/images/flags/4x3/ky.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kz.svg b/frontend/src/assets/images/flags/4x3/kz.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/kz.svg rename to frontend/src/assets/images/flags/4x3/kz.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/la.svg b/frontend/src/assets/images/flags/4x3/la.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/la.svg rename to frontend/src/assets/images/flags/4x3/la.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lb.svg b/frontend/src/assets/images/flags/4x3/lb.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lb.svg rename to frontend/src/assets/images/flags/4x3/lb.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lc.svg b/frontend/src/assets/images/flags/4x3/lc.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lc.svg rename to frontend/src/assets/images/flags/4x3/lc.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/li.svg b/frontend/src/assets/images/flags/4x3/li.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/li.svg rename to frontend/src/assets/images/flags/4x3/li.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lk.svg b/frontend/src/assets/images/flags/4x3/lk.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lk.svg rename to frontend/src/assets/images/flags/4x3/lk.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lr.svg b/frontend/src/assets/images/flags/4x3/lr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lr.svg rename to frontend/src/assets/images/flags/4x3/lr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ls.svg b/frontend/src/assets/images/flags/4x3/ls.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ls.svg rename to frontend/src/assets/images/flags/4x3/ls.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lt.svg b/frontend/src/assets/images/flags/4x3/lt.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lt.svg rename to frontend/src/assets/images/flags/4x3/lt.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lu.svg b/frontend/src/assets/images/flags/4x3/lu.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lu.svg rename to frontend/src/assets/images/flags/4x3/lu.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lv.svg b/frontend/src/assets/images/flags/4x3/lv.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/lv.svg rename to frontend/src/assets/images/flags/4x3/lv.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ly.svg b/frontend/src/assets/images/flags/4x3/ly.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ly.svg rename to frontend/src/assets/images/flags/4x3/ly.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ma.svg b/frontend/src/assets/images/flags/4x3/ma.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ma.svg rename to frontend/src/assets/images/flags/4x3/ma.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mc.svg b/frontend/src/assets/images/flags/4x3/mc.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mc.svg rename to frontend/src/assets/images/flags/4x3/mc.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/md.svg b/frontend/src/assets/images/flags/4x3/md.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/md.svg rename to frontend/src/assets/images/flags/4x3/md.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/me.svg b/frontend/src/assets/images/flags/4x3/me.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/me.svg rename to frontend/src/assets/images/flags/4x3/me.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mf.svg b/frontend/src/assets/images/flags/4x3/mf.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mf.svg rename to frontend/src/assets/images/flags/4x3/mf.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mg.svg b/frontend/src/assets/images/flags/4x3/mg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mg.svg rename to frontend/src/assets/images/flags/4x3/mg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mh.svg b/frontend/src/assets/images/flags/4x3/mh.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mh.svg rename to frontend/src/assets/images/flags/4x3/mh.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mk.svg b/frontend/src/assets/images/flags/4x3/mk.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mk.svg rename to frontend/src/assets/images/flags/4x3/mk.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ml.svg b/frontend/src/assets/images/flags/4x3/ml.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ml.svg rename to frontend/src/assets/images/flags/4x3/ml.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mm.svg b/frontend/src/assets/images/flags/4x3/mm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mm.svg rename to frontend/src/assets/images/flags/4x3/mm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mn.svg b/frontend/src/assets/images/flags/4x3/mn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mn.svg rename to frontend/src/assets/images/flags/4x3/mn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mo.svg b/frontend/src/assets/images/flags/4x3/mo.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mo.svg rename to frontend/src/assets/images/flags/4x3/mo.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mp.svg b/frontend/src/assets/images/flags/4x3/mp.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mp.svg rename to frontend/src/assets/images/flags/4x3/mp.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mq.svg b/frontend/src/assets/images/flags/4x3/mq.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mq.svg rename to frontend/src/assets/images/flags/4x3/mq.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mr.svg b/frontend/src/assets/images/flags/4x3/mr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mr.svg rename to frontend/src/assets/images/flags/4x3/mr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ms.svg b/frontend/src/assets/images/flags/4x3/ms.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ms.svg rename to frontend/src/assets/images/flags/4x3/ms.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mt.svg b/frontend/src/assets/images/flags/4x3/mt.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mt.svg rename to frontend/src/assets/images/flags/4x3/mt.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mu.svg b/frontend/src/assets/images/flags/4x3/mu.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mu.svg rename to frontend/src/assets/images/flags/4x3/mu.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mv.svg b/frontend/src/assets/images/flags/4x3/mv.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mv.svg rename to frontend/src/assets/images/flags/4x3/mv.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mw.svg b/frontend/src/assets/images/flags/4x3/mw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mw.svg rename to frontend/src/assets/images/flags/4x3/mw.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mx.svg b/frontend/src/assets/images/flags/4x3/mx.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mx.svg rename to frontend/src/assets/images/flags/4x3/mx.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/my.svg b/frontend/src/assets/images/flags/4x3/my.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/my.svg rename to frontend/src/assets/images/flags/4x3/my.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mz.svg b/frontend/src/assets/images/flags/4x3/mz.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/mz.svg rename to frontend/src/assets/images/flags/4x3/mz.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/na.svg b/frontend/src/assets/images/flags/4x3/na.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/na.svg rename to frontend/src/assets/images/flags/4x3/na.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nc.svg b/frontend/src/assets/images/flags/4x3/nc.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nc.svg rename to frontend/src/assets/images/flags/4x3/nc.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ne.svg b/frontend/src/assets/images/flags/4x3/ne.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ne.svg rename to frontend/src/assets/images/flags/4x3/ne.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nf.svg b/frontend/src/assets/images/flags/4x3/nf.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nf.svg rename to frontend/src/assets/images/flags/4x3/nf.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ng.svg b/frontend/src/assets/images/flags/4x3/ng.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ng.svg rename to frontend/src/assets/images/flags/4x3/ng.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ni.svg b/frontend/src/assets/images/flags/4x3/ni.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ni.svg rename to frontend/src/assets/images/flags/4x3/ni.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nl.svg b/frontend/src/assets/images/flags/4x3/nl.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nl.svg rename to frontend/src/assets/images/flags/4x3/nl.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/no.svg b/frontend/src/assets/images/flags/4x3/no.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/no.svg rename to frontend/src/assets/images/flags/4x3/no.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/np.svg b/frontend/src/assets/images/flags/4x3/np.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/np.svg rename to frontend/src/assets/images/flags/4x3/np.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nr.svg b/frontend/src/assets/images/flags/4x3/nr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nr.svg rename to frontend/src/assets/images/flags/4x3/nr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nu.svg b/frontend/src/assets/images/flags/4x3/nu.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nu.svg rename to frontend/src/assets/images/flags/4x3/nu.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nz.svg b/frontend/src/assets/images/flags/4x3/nz.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/nz.svg rename to frontend/src/assets/images/flags/4x3/nz.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/om.svg b/frontend/src/assets/images/flags/4x3/om.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/om.svg rename to frontend/src/assets/images/flags/4x3/om.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pa.svg b/frontend/src/assets/images/flags/4x3/pa.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pa.svg rename to frontend/src/assets/images/flags/4x3/pa.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pe.svg b/frontend/src/assets/images/flags/4x3/pe.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pe.svg rename to frontend/src/assets/images/flags/4x3/pe.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pf.svg b/frontend/src/assets/images/flags/4x3/pf.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pf.svg rename to frontend/src/assets/images/flags/4x3/pf.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pg.svg b/frontend/src/assets/images/flags/4x3/pg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pg.svg rename to frontend/src/assets/images/flags/4x3/pg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ph.svg b/frontend/src/assets/images/flags/4x3/ph.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ph.svg rename to frontend/src/assets/images/flags/4x3/ph.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pk.svg b/frontend/src/assets/images/flags/4x3/pk.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pk.svg rename to frontend/src/assets/images/flags/4x3/pk.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pl.svg b/frontend/src/assets/images/flags/4x3/pl.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pl.svg rename to frontend/src/assets/images/flags/4x3/pl.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pm.svg b/frontend/src/assets/images/flags/4x3/pm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pm.svg rename to frontend/src/assets/images/flags/4x3/pm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pn.svg b/frontend/src/assets/images/flags/4x3/pn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pn.svg rename to frontend/src/assets/images/flags/4x3/pn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pr.svg b/frontend/src/assets/images/flags/4x3/pr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pr.svg rename to frontend/src/assets/images/flags/4x3/pr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ps.svg b/frontend/src/assets/images/flags/4x3/ps.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ps.svg rename to frontend/src/assets/images/flags/4x3/ps.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pt.svg b/frontend/src/assets/images/flags/4x3/pt.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pt.svg rename to frontend/src/assets/images/flags/4x3/pt.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pw.svg b/frontend/src/assets/images/flags/4x3/pw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/pw.svg rename to frontend/src/assets/images/flags/4x3/pw.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/py.svg b/frontend/src/assets/images/flags/4x3/py.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/py.svg rename to frontend/src/assets/images/flags/4x3/py.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/qa.svg b/frontend/src/assets/images/flags/4x3/qa.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/qa.svg rename to frontend/src/assets/images/flags/4x3/qa.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/re.svg b/frontend/src/assets/images/flags/4x3/re.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/re.svg rename to frontend/src/assets/images/flags/4x3/re.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ro.svg b/frontend/src/assets/images/flags/4x3/ro.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ro.svg rename to frontend/src/assets/images/flags/4x3/ro.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/rs.svg b/frontend/src/assets/images/flags/4x3/rs.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/rs.svg rename to frontend/src/assets/images/flags/4x3/rs.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ru.svg b/frontend/src/assets/images/flags/4x3/ru.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ru.svg rename to frontend/src/assets/images/flags/4x3/ru.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/rw.svg b/frontend/src/assets/images/flags/4x3/rw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/rw.svg rename to frontend/src/assets/images/flags/4x3/rw.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sa.svg b/frontend/src/assets/images/flags/4x3/sa.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sa.svg rename to frontend/src/assets/images/flags/4x3/sa.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sb.svg b/frontend/src/assets/images/flags/4x3/sb.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sb.svg rename to frontend/src/assets/images/flags/4x3/sb.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sc.svg b/frontend/src/assets/images/flags/4x3/sc.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sc.svg rename to frontend/src/assets/images/flags/4x3/sc.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sd.svg b/frontend/src/assets/images/flags/4x3/sd.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sd.svg rename to frontend/src/assets/images/flags/4x3/sd.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/se.svg b/frontend/src/assets/images/flags/4x3/se.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/se.svg rename to frontend/src/assets/images/flags/4x3/se.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sg.svg b/frontend/src/assets/images/flags/4x3/sg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sg.svg rename to frontend/src/assets/images/flags/4x3/sg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sh.svg b/frontend/src/assets/images/flags/4x3/sh.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sh.svg rename to frontend/src/assets/images/flags/4x3/sh.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/si.svg b/frontend/src/assets/images/flags/4x3/si.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/si.svg rename to frontend/src/assets/images/flags/4x3/si.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sj.svg b/frontend/src/assets/images/flags/4x3/sj.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sj.svg rename to frontend/src/assets/images/flags/4x3/sj.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sk.svg b/frontend/src/assets/images/flags/4x3/sk.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sk.svg rename to frontend/src/assets/images/flags/4x3/sk.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sl.svg b/frontend/src/assets/images/flags/4x3/sl.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sl.svg rename to frontend/src/assets/images/flags/4x3/sl.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sm.svg b/frontend/src/assets/images/flags/4x3/sm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sm.svg rename to frontend/src/assets/images/flags/4x3/sm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sn.svg b/frontend/src/assets/images/flags/4x3/sn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sn.svg rename to frontend/src/assets/images/flags/4x3/sn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/so.svg b/frontend/src/assets/images/flags/4x3/so.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/so.svg rename to frontend/src/assets/images/flags/4x3/so.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sr.svg b/frontend/src/assets/images/flags/4x3/sr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sr.svg rename to frontend/src/assets/images/flags/4x3/sr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ss.svg b/frontend/src/assets/images/flags/4x3/ss.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ss.svg rename to frontend/src/assets/images/flags/4x3/ss.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/st.svg b/frontend/src/assets/images/flags/4x3/st.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/st.svg rename to frontend/src/assets/images/flags/4x3/st.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sv.svg b/frontend/src/assets/images/flags/4x3/sv.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sv.svg rename to frontend/src/assets/images/flags/4x3/sv.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sx.svg b/frontend/src/assets/images/flags/4x3/sx.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sx.svg rename to frontend/src/assets/images/flags/4x3/sx.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sy.svg b/frontend/src/assets/images/flags/4x3/sy.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sy.svg rename to frontend/src/assets/images/flags/4x3/sy.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sz.svg b/frontend/src/assets/images/flags/4x3/sz.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/sz.svg rename to frontend/src/assets/images/flags/4x3/sz.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tc.svg b/frontend/src/assets/images/flags/4x3/tc.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tc.svg rename to frontend/src/assets/images/flags/4x3/tc.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/td.svg b/frontend/src/assets/images/flags/4x3/td.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/td.svg rename to frontend/src/assets/images/flags/4x3/td.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tf.svg b/frontend/src/assets/images/flags/4x3/tf.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tf.svg rename to frontend/src/assets/images/flags/4x3/tf.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tg.svg b/frontend/src/assets/images/flags/4x3/tg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tg.svg rename to frontend/src/assets/images/flags/4x3/tg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/th.svg b/frontend/src/assets/images/flags/4x3/th.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/th.svg rename to frontend/src/assets/images/flags/4x3/th.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tj.svg b/frontend/src/assets/images/flags/4x3/tj.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tj.svg rename to frontend/src/assets/images/flags/4x3/tj.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tk.svg b/frontend/src/assets/images/flags/4x3/tk.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tk.svg rename to frontend/src/assets/images/flags/4x3/tk.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tl.svg b/frontend/src/assets/images/flags/4x3/tl.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tl.svg rename to frontend/src/assets/images/flags/4x3/tl.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tm.svg b/frontend/src/assets/images/flags/4x3/tm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tm.svg rename to frontend/src/assets/images/flags/4x3/tm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tn.svg b/frontend/src/assets/images/flags/4x3/tn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tn.svg rename to frontend/src/assets/images/flags/4x3/tn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/to.svg b/frontend/src/assets/images/flags/4x3/to.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/to.svg rename to frontend/src/assets/images/flags/4x3/to.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tr.svg b/frontend/src/assets/images/flags/4x3/tr.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tr.svg rename to frontend/src/assets/images/flags/4x3/tr.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tt.svg b/frontend/src/assets/images/flags/4x3/tt.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tt.svg rename to frontend/src/assets/images/flags/4x3/tt.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tv.svg b/frontend/src/assets/images/flags/4x3/tv.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tv.svg rename to frontend/src/assets/images/flags/4x3/tv.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tw.svg b/frontend/src/assets/images/flags/4x3/tw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tw.svg rename to frontend/src/assets/images/flags/4x3/tw.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tz.svg b/frontend/src/assets/images/flags/4x3/tz.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/tz.svg rename to frontend/src/assets/images/flags/4x3/tz.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ua.svg b/frontend/src/assets/images/flags/4x3/ua.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ua.svg rename to frontend/src/assets/images/flags/4x3/ua.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ug.svg b/frontend/src/assets/images/flags/4x3/ug.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ug.svg rename to frontend/src/assets/images/flags/4x3/ug.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/um.svg b/frontend/src/assets/images/flags/4x3/um.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/um.svg rename to frontend/src/assets/images/flags/4x3/um.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/un.svg b/frontend/src/assets/images/flags/4x3/un.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/un.svg rename to frontend/src/assets/images/flags/4x3/un.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/us.svg b/frontend/src/assets/images/flags/4x3/us.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/us.svg rename to frontend/src/assets/images/flags/4x3/us.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/uy.svg b/frontend/src/assets/images/flags/4x3/uy.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/uy.svg rename to frontend/src/assets/images/flags/4x3/uy.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/uz.svg b/frontend/src/assets/images/flags/4x3/uz.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/uz.svg rename to frontend/src/assets/images/flags/4x3/uz.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/va.svg b/frontend/src/assets/images/flags/4x3/va.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/va.svg rename to frontend/src/assets/images/flags/4x3/va.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vc.svg b/frontend/src/assets/images/flags/4x3/vc.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vc.svg rename to frontend/src/assets/images/flags/4x3/vc.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ve.svg b/frontend/src/assets/images/flags/4x3/ve.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ve.svg rename to frontend/src/assets/images/flags/4x3/ve.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vg.svg b/frontend/src/assets/images/flags/4x3/vg.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vg.svg rename to frontend/src/assets/images/flags/4x3/vg.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vi.svg b/frontend/src/assets/images/flags/4x3/vi.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vi.svg rename to frontend/src/assets/images/flags/4x3/vi.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vn.svg b/frontend/src/assets/images/flags/4x3/vn.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vn.svg rename to frontend/src/assets/images/flags/4x3/vn.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vu.svg b/frontend/src/assets/images/flags/4x3/vu.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/vu.svg rename to frontend/src/assets/images/flags/4x3/vu.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/wf.svg b/frontend/src/assets/images/flags/4x3/wf.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/wf.svg rename to frontend/src/assets/images/flags/4x3/wf.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ws.svg b/frontend/src/assets/images/flags/4x3/ws.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ws.svg rename to frontend/src/assets/images/flags/4x3/ws.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/xk.svg b/frontend/src/assets/images/flags/4x3/xk.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/xk.svg rename to frontend/src/assets/images/flags/4x3/xk.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ye.svg b/frontend/src/assets/images/flags/4x3/ye.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/ye.svg rename to frontend/src/assets/images/flags/4x3/ye.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/yt.svg b/frontend/src/assets/images/flags/4x3/yt.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/yt.svg rename to frontend/src/assets/images/flags/4x3/yt.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/za.svg b/frontend/src/assets/images/flags/4x3/za.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/za.svg rename to frontend/src/assets/images/flags/4x3/za.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/zm.svg b/frontend/src/assets/images/flags/4x3/zm.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/zm.svg rename to frontend/src/assets/images/flags/4x3/zm.svg diff --git a/frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/zw.svg b/frontend/src/assets/images/flags/4x3/zw.svg similarity index 100% rename from frontend/src/app/modules/shared/components/country-flag-generator/flags/4x3/zw.svg rename to frontend/src/assets/images/flags/4x3/zw.svg diff --git a/frontend/src/assets/locales/de/common.json b/frontend/src/assets/locales/de/common.json index 62e6f893f0..3e46a626c4 100644 --- a/frontend/src/assets/locales/de/common.json +++ b/frontend/src/assets/locales/de/common.json @@ -57,7 +57,7 @@ "menuDescription": "Aktionsmenü", "clearPage": "Markierungen auf dieser Seite aufheben", "clearAll": "Alle Markierungen aufheben", - "filterTitle": "Filter",, + "filterTitle" : "Filter", "adminColumn": { "startDate": "Startdatum", "registryLookupStatus": "Status", @@ -95,7 +95,9 @@ "catenaXSiteId": "Standort ID", "psFunction": "Funktion", "functionValidFrom": "Funktion gültig von", - "functionValidUntil": "Funktion gültig bis" + "functionValidUntil" : "Funktion gültig bis", + "activeAlerts" : "Aktive Qualitätswarnungen", + "activeInvestigations" : "Aktive Qualitätsuntersuchungen" } }, "dataLoading": { diff --git a/frontend/src/assets/locales/en/common.json b/frontend/src/assets/locales/en/common.json index 1c3d3608bd..5ca462b9eb 100644 --- a/frontend/src/assets/locales/en/common.json +++ b/frontend/src/assets/locales/en/common.json @@ -94,7 +94,9 @@ "catenaXSiteId": "SiteId", "psFunction": "Function", "functionValidFrom": "Function valid from", - "functionValidUntil": "Function valid until" + "functionValidUntil" : "Function valid until", + "activeAlerts" : "Active Quality alerts", + "activeInvestigations" : "Active Quality investigations" } }, "dataLoading": { diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/model/request/RegisterPolicyRequest.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/model/request/RegisterPolicyRequest.java index 0df1a2fcf5..18dced233e 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/model/request/RegisterPolicyRequest.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/model/request/RegisterPolicyRequest.java @@ -40,7 +40,9 @@ public static RegisterPolicyRequest from(IrsPolicy policy) { Instant.parse(policy.getTtl()), List.of(new Permission( PolicyType.USE, - List.of(new Constraints(List.of(new Constraint("PURPOSE", OperatorType.EQ, List.of(policy.getPolicyId()))), List.of())) + List.of(new Constraints( + List.of(new Constraint("PURPOSE", OperatorType.EQ, List.of(policy.getPolicyId()))), + List.of(new Constraint("PURPOSE", OperatorType.EQ, List.of(policy.getPolicyId()))))) ))); } } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/model/response/relationship/Aspect.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/model/response/relationship/Aspect.java index cb15a7414e..9b871cf6ec 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/model/response/relationship/Aspect.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/irs/model/response/relationship/Aspect.java @@ -47,11 +47,13 @@ public String getAspectName() { } public static List downwardAspectsForAssetsAsBuilt() { - return List.of(BATCH.getAspectName(), SERIAL_PART.getAspectName(), SINGLE_LEVEL_BOM_AS_BUILT.getAspectName(), JUST_IN_SEQUENCE_PART.getAspectName()); + return List.of(BATCH.getAspectName(), SERIAL_PART.getAspectName(), SINGLE_LEVEL_BOM_AS_BUILT.getAspectName(), + JUST_IN_SEQUENCE_PART.getAspectName(), TRACTION_BATTERY_CODE.getAspectName()); } public static List upwardAspectsForAssetsAsBuilt() { - return List.of(BATCH.getAspectName(), SERIAL_PART.getAspectName(), SINGLE_LEVEL_USAGE_AS_BUILT.getAspectName(), JUST_IN_SEQUENCE_PART.getAspectName()); + return List.of(BATCH.getAspectName(), SERIAL_PART.getAspectName(), SINGLE_LEVEL_USAGE_AS_BUILT.getAspectName(), + JUST_IN_SEQUENCE_PART.getAspectName(), TRACTION_BATTERY_CODE.getAspectName()); } public static List downwardAspectsForAssetsAsPlanned() { diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/repository/AssetSpecificationUtil.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/repository/AssetSpecificationUtil.java index b12fcee514..6ccd7d7014 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/repository/AssetSpecificationUtil.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/assets/infrastructure/base/repository/AssetSpecificationUtil.java @@ -27,15 +27,19 @@ import java.util.List; public class AssetSpecificationUtil { + public static Specification combineSpecifications( ArrayList> specifications, SearchCriteriaOperator searchCriteriaOperator) { List> ownerSpecifications = specifications.stream() - .filter(spec -> "owner".equals(spec.getSearchCriteriaFilter().getKey())).toList(); + .filter(AssetSpecificationUtil::isOwnerPredicate).toList(); + + List> semanticDataModelSpecifications = specifications.stream() + .filter(AssetSpecificationUtil::isSemanticDataModelPredicate).toList(); List> otherSpecifications = specifications.stream() - .filter(spec -> !"owner".equals(spec.getSearchCriteriaFilter().getKey())).toList(); + .filter(spec -> !isOwnerPredicate(spec) && !isSemanticDataModelPredicate(spec)).toList(); Specification resultAnd = null; Specification resultOr = null; @@ -44,19 +48,31 @@ public static Specification combineSpecifications( for (BaseSpecification ownerSpecification : ownerSpecifications) { resultAnd = Specification.where(resultAnd).and(ownerSpecification); } - + // Always add semanticDataModel specifications with OR + for (BaseSpecification semanticDataModelSpecification : semanticDataModelSpecifications) { + resultOr = Specification.where(resultOr).or(semanticDataModelSpecification); + } if (searchCriteriaOperator.equals(SearchCriteriaOperator.AND)) { for (BaseSpecification otherSpecification : otherSpecifications) { resultAnd = Specification.where(resultAnd).and(otherSpecification); } } else { for (BaseSpecification otherSpecification : otherSpecifications) { - resultOr = Specification.where(resultOr).and(otherSpecification); + resultOr = Specification.where(resultOr).or(otherSpecification); } } return Specification.where(resultAnd).and(resultOr); } + + private static boolean isOwnerPredicate(BaseSpecification baseSpecification) { + return "owner".equals(baseSpecification.getSearchCriteriaFilter().getKey()); + } + + private static boolean isSemanticDataModelPredicate(BaseSpecification baseSpecification) { + return "semanticDataModel".equals(baseSpecification.getSearchCriteriaFilter().getKey()); + } + } diff --git a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/ApplicationConfig.java b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/ApplicationConfig.java index c44005b60b..a91082bc3b 100644 --- a/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/ApplicationConfig.java +++ b/tx-backend/src/main/java/org/eclipse/tractusx/traceability/common/config/ApplicationConfig.java @@ -21,6 +21,8 @@ package org.eclipse.tractusx.traceability.common.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import io.github.resilience4j.core.registry.EntryAddedEvent; import io.github.resilience4j.core.registry.EntryRemovedEvent; import io.github.resilience4j.core.registry.EntryReplacedEvent; @@ -118,9 +120,11 @@ public ITemplateResolver textTemplateResolver() { @Bean public void registerDecentralRegistryPermissions() { try { + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new JavaTimeModule()); AcceptedPolicy acceptedPolicy = buildAcceptedPolicy(); defaultAcceptedPoliciesProvider.addAcceptedPolicies(List.of(acceptedPolicy)); - log.info("Successfully added permission to irs client lib provider: {}", acceptedPolicy); + log.info("Successfully added permission to irs client lib provider: {}", mapper.writeValueAsString(acceptedPolicy)); } catch (Exception exception) { log.error("Failed to create Irs Policies : ", exception); } @@ -133,7 +137,9 @@ private static AcceptedPolicy buildAcceptedPolicy() { List permissions = List.of( new Permission( PolicyType.USE, - List.of(new Constraints(List.of(new Constraint("PURPOSE", OperatorType.EQ, List.of(ID_TRACE_CONSTRAINT))), List.of())) + List.of(new Constraints( + List.of(new Constraint("PURPOSE", OperatorType.EQ, List.of(ID_TRACE_CONSTRAINT))), + List.of(new Constraint("PURPOSE", OperatorType.EQ, List.of(ID_TRACE_CONSTRAINT))))) ) ); Policy policy = new Policy(ID_TRACE_CONSTRAINT, OffsetDateTime.now(), offsetDateTime, permissions); diff --git a/tx-backend/src/main/resources/application.yml b/tx-backend/src/main/resources/application.yml index fd5d2f73d0..633fadc1aa 100644 --- a/tx-backend/src/main/resources/application.yml +++ b/tx-backend/src/main/resources/application.yml @@ -70,11 +70,6 @@ irs-edc-client: read: PT90S # HTTP read timeout for the submodel client connect: PT90S # HTTP connect timeout for the submodel client - catalog: - policies: - acceptedRightOperands: active # List of comma separated names of the rightOperands to accept. - acceptedLeftOperands: PURPOSE # List of comma separated names of the leftOperands to accept. - server: servlet: context-path: /api @@ -172,10 +167,10 @@ irs: policies: - policyId: "ID 3.0 Trace" - ttl: "2023-09-30T23:59:59.99Z" + ttl: "2024-09-30T23:59:59.99Z" - policyId: "ID 3.1 Trace" - ttl: "2023-09-30T23:59:59.99Z" + ttl: "2024-09-30T23:59:59.99Z" digitalTwinRegistryClient: shellDescriptorTemplate: /shell-descriptors/{aasIdentifier} # The path to retrieve AAS descriptors from the decentral DTR, must contain the placeholder {aasIdentifier} lookupShellsTemplate: /lookup/shells?assetIds={assetIds} # The path to lookup shells from the decentral DTR, must contain the placeholder {assetIds} diff --git a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/AssetAsBuiltControllerFilteringIT.java b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/AssetAsBuiltControllerFilteringIT.java index 853483e82a..66b2294531 100644 --- a/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/AssetAsBuiltControllerFilteringIT.java +++ b/tx-backend/src/test/java/org/eclipse/tractusx/traceability/integration/assets/AssetAsBuiltControllerFilteringIT.java @@ -241,6 +241,26 @@ void givenSemanticDataModelAndManufacturingDateFilterOR_whenCallFilteredEndpoint final String filter = "?filter=manufacturingDate,AT_LOCAL_DATE,2014-11-18&filter=semanticDataModel,EQUAL,SERIALPART"; final String filterOperator = "&filterOperator=OR"; + // then + given() + .header(oAuth2Support.jwtAuthorization(ADMIN)) + .contentType(ContentType.JSON) + .log().all() + .when() + .get("/api/assets/as-built" + filter + filterOperator) + .then() + .log().all() + .statusCode(200) + .body("totalItems", equalTo(13)); + } + + @Test + void givenSemanticDataModelAndManufacturingDateFilterAnd_whenCallFilteredEndpoint_thenReturnExpectedResult() throws JoseException { + // given + assetsSupport.defaultAssetsStored(); + final String filter = "?filter=manufacturingDate,AT_LOCAL_DATE,2014-11-18&filter=semanticDataModel,EQUAL,SERIALPART"; + final String filterOperator = "&filterOperator=AND"; + // then given() .header(oAuth2Support.jwtAuthorization(ADMIN)) @@ -273,4 +293,24 @@ void givenSemanticDataModelAndOwnerOR_whenCallFilteredEndpoint_thenReturnExpecte .statusCode(200) .body("totalItems", equalTo(1)); } + + @Test + void givenSemanticDataModelAsMultipleValuesAndOwnerOR_whenCallFilteredEndpoint_thenReturnExpectedResult() throws JoseException { + // given + assetsSupport.defaultAssetsStored(); + final String filter = "?filter=owner,EQUAL,SUPPLIER&filter=semanticDataModel,EQUAL,SERIALPART&filter=semanticDataModel,EQUAL,BATCH"; + final String filterOperator = "&filterOperator=OR"; + + // then + given() + .header(oAuth2Support.jwtAuthorization(ADMIN)) + .contentType(ContentType.JSON) + .log().all() + .when() + .get("/api/assets/as-built" + filter + filterOperator) + .then() + .log().all() + .statusCode(200) + .body("totalItems", equalTo(12)); + } }