From cdd27aeeb040626904b5866631f2130762e7a905 Mon Sep 17 00:00:00 2001 From: Lorenz Hilpert Date: Thu, 22 May 2025 19:07:00 +0200 Subject: [PATCH] refactor(print): update print dialog component to use new listbox directives test(print): add unit tests for PrintService and PrintReceiptsService feat(print): modify PrintService methods to return promises instead of observables refactor(oms): rename return-print-receipts.service to print-receipts.service and update references chore(ui): remove deprecated ui-list library and integrate listbox components style(ui): add styles for listbox and listbox items test(ui): implement unit tests for listbox directives docs(ui): update README and remove unused files related to ui-list --- .vscode/settings.json | 8 +- apps/isa-app/src/ui.scss | 1 - .../print/src/lib/models/printer.model.ts | 2 - .../print-dialog/print-dialog.component.html | 4 +- .../print-dialog.component.spec.ts | 290 ++++++++++++++++++ .../print-dialog/print-dialog.component.ts | 4 +- .../src/lib/services/print.service.spec.ts | 279 +++++++++++++++++ .../print/src/lib/services/print.service.ts | 56 ++-- .../oms/data-access/src/lib/services/index.ts | 2 +- .../services/print-receipts.service.spec.ts | 68 ++++ .../lib/services/print-receipts.service.ts | 43 +++ .../services/return-print-receipts.service.ts | 25 -- .../lib/services/return-process.service.ts | 4 +- .../return-review-header.component.ts | 1 + .../src/lib/return-review.component.ts | 23 +- .../confirmation-dialog.component.spec.ts} | 0 .../message-dialog.component.spec.ts} | 0 libs/ui/input-controls/src/index.ts | 2 + .../ui/input-controls/src/input-controls.scss | 1 + .../src/lib/listbox/_listbox.scss} | 4 +- .../listbox/listbox-item.directive.spec.ts | 39 +++ .../lib/listbox/listbox-item.directive.ts} | 6 +- .../src/lib/listbox/listbox.directive.spec.ts | 32 ++ .../src/lib/listbox/listbox.directive.ts} | 6 +- libs/ui/list/README.md | 7 - libs/ui/list/eslint.config.mjs | 34 -- libs/ui/list/jest.config.ts | 21 -- libs/ui/list/project.json | 20 -- libs/ui/list/src/index.ts | 2 - .../list/src/lib/text-list-item.component.ts | 0 libs/ui/list/src/list.scss | 1 - libs/ui/list/src/test-setup.ts | 6 - libs/ui/list/tsconfig.json | 28 -- libs/ui/list/tsconfig.lib.json | 17 - libs/ui/list/tsconfig.spec.json | 16 - tsconfig.base.json | 1 - 36 files changed, 814 insertions(+), 239 deletions(-) create mode 100644 libs/common/print/src/lib/print-dialog/print-dialog.component.spec.ts create mode 100644 libs/common/print/src/lib/services/print.service.spec.ts create mode 100644 libs/oms/data-access/src/lib/services/print-receipts.service.spec.ts create mode 100644 libs/oms/data-access/src/lib/services/print-receipts.service.ts delete mode 100644 libs/oms/data-access/src/lib/services/return-print-receipts.service.ts rename libs/ui/{list/src/lib/list.component.ts => dialog/src/lib/confirmation-dialog/confirmation-dialog.component.spec.ts} (100%) rename libs/ui/{list/src/lib/list.examples.ts => dialog/src/lib/message-dialog/message-dialog.component.spec.ts} (100%) rename libs/ui/{list/src/lib/_list.scss => input-controls/src/lib/listbox/_listbox.scss} (90%) create mode 100644 libs/ui/input-controls/src/lib/listbox/listbox-item.directive.spec.ts rename libs/ui/{list/src/lib/text-list-item.directive.ts => input-controls/src/lib/listbox/listbox-item.directive.ts} (83%) create mode 100644 libs/ui/input-controls/src/lib/listbox/listbox.directive.spec.ts rename libs/ui/{list/src/lib/list.directive.ts => input-controls/src/lib/listbox/listbox.directive.ts} (90%) delete mode 100644 libs/ui/list/README.md delete mode 100644 libs/ui/list/eslint.config.mjs delete mode 100644 libs/ui/list/jest.config.ts delete mode 100644 libs/ui/list/project.json delete mode 100644 libs/ui/list/src/index.ts delete mode 100644 libs/ui/list/src/lib/text-list-item.component.ts delete mode 100644 libs/ui/list/src/list.scss delete mode 100644 libs/ui/list/src/test-setup.ts delete mode 100644 libs/ui/list/tsconfig.json delete mode 100644 libs/ui/list/tsconfig.lib.json delete mode 100644 libs/ui/list/tsconfig.spec.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 7db312a2a..2b63b6d10 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -30,9 +30,6 @@ } ], "github.copilot.chat.codeGeneration.instructions": [ - { - "file": ".github/copilot-instructions.md" - }, { "file": "docs/tech-stack.md" }, @@ -50,9 +47,6 @@ } ], "github.copilot.chat.testGeneration.instructions": [ - { - "file": ".github/copilot-instructions.md" - }, { "file": ".github/testing-instructions.md" }, @@ -90,4 +84,6 @@ } ], "nxConsole.generateAiAgentRules": true, + "chat.mcp.enabled": true, + "chat.mcp.discovery.enabled": true } diff --git a/apps/isa-app/src/ui.scss b/apps/isa-app/src/ui.scss index b6c1c86bd..e3ac52d76 100644 --- a/apps/isa-app/src/ui.scss +++ b/apps/isa-app/src/ui.scss @@ -2,5 +2,4 @@ @use "../../../libs/ui/datepicker/src/datepicker.scss"; @use "../../../libs/ui/dialog/src/dialog.scss"; @use "../../../libs/ui/input-controls/src/input-controls.scss"; -@use "../../../libs/ui/list/src/list.scss"; @use "../../../libs/ui/progress-bar/src/lib/progress-bar.scss"; diff --git a/libs/common/print/src/lib/models/printer.model.ts b/libs/common/print/src/lib/models/printer.model.ts index 006a3dd28..01d3f65d0 100644 --- a/libs/common/print/src/lib/models/printer.model.ts +++ b/libs/common/print/src/lib/models/printer.model.ts @@ -13,6 +13,4 @@ export interface Printer extends KeyValueDTOOfStringAndString { selected: boolean; /** Whether this printer is currently enabled for use */ enabled: boolean; - /** Additional information about the printer */ - description: string; } diff --git a/libs/common/print/src/lib/print-dialog/print-dialog.component.html b/libs/common/print/src/lib/print-dialog/print-dialog.component.html index befb6db84..30656a206 100644 --- a/libs/common/print/src/lib/print-dialog/print-dialog.component.html +++ b/libs/common/print/src/lib/print-dialog/print-dialog.component.html @@ -7,7 +7,7 @@ }
@for (printer of data.printers; track printer.key) { - + }
diff --git a/libs/common/print/src/lib/print-dialog/print-dialog.component.spec.ts b/libs/common/print/src/lib/print-dialog/print-dialog.component.spec.ts new file mode 100644 index 000000000..b2431f9f3 --- /dev/null +++ b/libs/common/print/src/lib/print-dialog/print-dialog.component.spec.ts @@ -0,0 +1,290 @@ +import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; +import { + PrintDialogComponent, + PrinterDialogData, +} from './print-dialog.component'; +import { ButtonComponent } from '@isa/ui/buttons'; +import { ListboxDirective, ListboxItemDirective } from '@isa/ui/input-controls'; +import { MockComponent, MockDirective } from 'ng-mocks'; +import { Printer } from '../models'; +import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog'; + +describe('PrintDialogComponent', () => { + let spectator: Spectator; + let component: PrintDialogComponent; + + // Mock printers for testing + const mockPrinters: Printer[] = [ + { + key: 'printer1', + value: 'Printer 1', + selected: false, + enabled: true, + description: 'First test printer', + }, + { + key: 'printer2', + value: 'Printer 2', + selected: true, + enabled: true, + description: 'Second test printer', + }, + { + key: 'printer3', + value: 'Printer 3', + selected: false, + enabled: false, + description: 'Disabled test printer', + }, + ]; + + // Mock print function + const mockPrintFn = jest.fn().mockResolvedValue(undefined); + + // Default dialog data + const defaultData: PrinterDialogData = { + printers: mockPrinters, + print: mockPrintFn, + }; + + // Mock DialogRef + const mockDialogRef = { + close: jest.fn(), + }; + + const createComponent = createComponentFactory({ + component: PrintDialogComponent, + declarations: [ + MockComponent(ButtonComponent), + MockDirective(ListboxDirective), + MockDirective(ListboxItemDirective), + ], + providers: [ + { provide: DialogRef, useValue: mockDialogRef }, + { provide: DIALOG_DATA, useValue: defaultData }, + ], + detectChanges: false, + }); + + beforeEach(() => { + // Reset mocks + mockPrintFn.mockClear(); + mockDialogRef.close.mockClear(); + + // Create component without providing data prop since we provide it via DIALOG_DATA + spectator = createComponent(); + + component = spectator.component; + spectator.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should initialize with the selected printer', () => { + // Assert + expect(component.printer()).toEqual(mockPrinters[1]); // The one with selected: true + }); + + it('should compute selected array correctly with a printer', () => { + // Arrange + const selectedPrinter = mockPrinters[0]; + component.printer.set(selectedPrinter); + + // Act + const result = component.selected(); + + // Assert + expect(result).toEqual([selectedPrinter]); + }); + + it('should compute selected array as empty when no printer is selected', () => { + // Arrange + component.printer.set(undefined); + + // Act + const result = component.selected(); + + // Assert + expect(result).toEqual([]); + }); + + it('should compute canPrint as true when printer is selected and not printing', () => { + // Arrange + component.printer.set(mockPrinters[0]); + component.printing.set(false); + + // Act + const result = component.canPrint(); + + // Assert + expect(result).toBe(true); + }); + + it('should compute canPrint as false when no printer is selected', () => { + // Arrange + component.printer.set(undefined); + component.printing.set(false); + + // Act + const result = component.canPrint(); + + // Assert + expect(result).toBe(false); + }); + + it('should compute canPrint as false when printing is in progress', () => { + // Arrange + component.printer.set(mockPrinters[0]); + component.printing.set(true); + + // Act + const result = component.canPrint(); + + // Assert + expect(result).toBe(false); + }); + + it('should compare printers by key', () => { + // Arrange + const printer1 = { ...mockPrinters[0] }; + const printer2 = { ...mockPrinters[0] }; // Same key as printer1 + const printer3 = { ...mockPrinters[1] }; // Different key + + // Act & Assert + expect(component.compareWith(printer1, printer2)).toBe(true); + expect(component.compareWith(printer1, printer3)).toBe(false); + }); + + it('should select a printer and clear error', () => { + // Arrange + const initialError = new Error('Test error'); + component.error.set(initialError); + const printer = mockPrinters[0]; + + // Act + component.select(printer); + + // Assert + expect(component.printer()).toEqual(printer); + expect(component.error()).toBeUndefined(); + }); + + it('should not print when canPrint is false', async () => { + // Arrange + component.printer.set(undefined); // Makes canPrint() false + const closeSpy = jest.spyOn(component, 'close'); + + // Act + await component.print(); + + // Assert + expect(mockPrintFn).not.toHaveBeenCalled(); + expect(closeSpy).not.toHaveBeenCalled(); + expect(component.printing()).toBe(false); + }); + it('should print and close dialog when print succeeds', async () => { + // Arrange + const selectedPrinter = mockPrinters[0]; + component.printer.set(selectedPrinter); + const closeSpy = jest.spyOn(component, 'close'); + + // Act + await component.print(); + + // Assert + // The printing flag stays true when success happens and dialog is closed + expect(component.printing()).toBe(true); + expect(mockPrintFn).toHaveBeenCalledWith(selectedPrinter); + expect(closeSpy).toHaveBeenCalledWith({ printer: selectedPrinter }); + }); + + it('should handle print errors', async () => { + // Arrange + const selectedPrinter = mockPrinters[0]; + component.printer.set(selectedPrinter); + const testError = new Error('Print failed'); + mockPrintFn.mockRejectedValueOnce(testError); + const closeSpy = jest.spyOn(component, 'close'); + + // Act + await component.print(); + + // Assert + expect(component.printing()).toBe(false); // Reset to false after error + expect(mockPrintFn).toHaveBeenCalledWith(selectedPrinter); + expect(closeSpy).not.toHaveBeenCalled(); + expect(component.error()).toBe(testError); + }); + + it('should format Error objects correctly', () => { + // Arrange + const errorMessage = 'Test error message'; + const testError = new Error(errorMessage); + + // Act + const result = component.formatError(testError); + + // Assert + expect(result).toBe(errorMessage); + }); + + it('should format string errors correctly', () => { + // Arrange + const errorMessage = 'Test error message'; + + // Act + const result = component.formatError(errorMessage); + + // Assert + expect(result).toBe(errorMessage); + }); + + it('should format unknown errors correctly', () => { + // Arrange + const unknownError = { something: 'wrong' }; + + // Act + const result = component.formatError(unknownError); + + // Assert + expect(result).toBe('Unbekannter Fehler'); + }); + + it('should show error message in template when error exists', () => { + // Arrange + const errorMessage = 'Display this error'; + component.error.set(errorMessage); + spectator.detectChanges(); + + // Act + const errorElement = spectator.query('.text-isa-accent-red'); + + // Assert + expect(errorElement).toHaveText(errorMessage); + }); + + it('should display printers in the listbox', () => { + // Arrange & Act + spectator.detectChanges(); + const listboxItems = spectator.queryAll('button[uiListboxItem]'); + + // Assert + expect(listboxItems.length).toBe(mockPrinters.length); + expect(listboxItems[0]).toHaveText(mockPrinters[0].value); + expect(listboxItems[1]).toHaveText(mockPrinters[1].value); + expect(listboxItems[2]).toHaveText(mockPrinters[2].value); + }); + + it('should call close with undefined printer when cancel button is clicked', () => { + // Arrange + const closeSpy = jest.spyOn(component, 'close'); + + // Act + spectator.click('button[color="secondary"]'); + + // Assert + expect(closeSpy).toHaveBeenCalledWith({ printer: undefined }); + }); +}); diff --git a/libs/common/print/src/lib/print-dialog/print-dialog.component.ts b/libs/common/print/src/lib/print-dialog/print-dialog.component.ts index fe5b88b35..ad6f991eb 100644 --- a/libs/common/print/src/lib/print-dialog/print-dialog.component.ts +++ b/libs/common/print/src/lib/print-dialog/print-dialog.component.ts @@ -8,7 +8,7 @@ import { import { Printer } from '../models'; import { ButtonComponent } from '@isa/ui/buttons'; import { DialogContentDirective } from '@isa/ui/dialog'; -import { ListDirective, TextListItemDirective } from '@isa/ui/list'; +import { ListboxDirective, ListboxItemDirective } from '@isa/ui/input-controls'; /** * Input data for the printer dialog component @@ -38,7 +38,7 @@ export interface PrinterDialogResult { selector: 'common-print-dialog', templateUrl: './print-dialog.component.html', changeDetection: ChangeDetectionStrategy.OnPush, - imports: [ButtonComponent, ListDirective, TextListItemDirective], + imports: [ButtonComponent, ListboxDirective, ListboxItemDirective], }) export class PrintDialogComponent extends DialogContentDirective< PrinterDialogData, diff --git a/libs/common/print/src/lib/services/print.service.spec.ts b/libs/common/print/src/lib/services/print.service.spec.ts new file mode 100644 index 000000000..75c8ab137 --- /dev/null +++ b/libs/common/print/src/lib/services/print.service.spec.ts @@ -0,0 +1,279 @@ +import { SpectatorService, createServiceFactory } from '@ngneat/spectator/jest'; +import { PrintService } from './print.service'; +import { Platform } from '@angular/cdk/platform'; +import { + ListResponseArgsOfKeyValueDTOOfStringAndString, + PrintService as PrintApiService, +} from '@generated/swagger/print-api'; +import { of } from 'rxjs'; +import { PrinterType } from '../models'; +import { PrinterDialogResult } from '../print-dialog/print-dialog.component'; + +// Mock dialog function that can be configured in tests +const mockDialogClosedObservable = { + closed: of({ printer: undefined }), +}; +const mockDialogFn = jest.fn().mockReturnValue(mockDialogClosedObservable); + +jest.mock('@isa/ui/dialog', () => ({ + injectDialog: jest.fn().mockImplementation(() => mockDialogFn), +})); + +jest.mock('../print-dialog/print-dialog.component', () => ({ + PrintDialogComponent: jest + .fn() + .mockReturnValue(class MockPrintDialogComponent {}), +})); + +describe('PrintService', () => { + let spectator: SpectatorService; + const createService = createServiceFactory({ + service: PrintService, + mocks: [PrintApiService, Platform], + }); + + beforeEach(() => { + spectator = createService(); + }); + + it('should be created', () => { + expect(spectator.service).toBeTruthy(); + }); + + describe('labelPrinters', () => { + it('should call PrintLabelPrinters and return printers', async () => { + const mockPrinters: ListResponseArgsOfKeyValueDTOOfStringAndString = { + error: false, + result: [ + { + key: 'printer1', + value: 'Printer 1', + }, + { + key: 'printer2', + value: 'Printer 2', + }, + ], + }; + + const printApiService: jest.Mocked = + spectator.inject(PrintApiService); + + printApiService.PrintLabelPrinters.mockReturnValue(of(mockPrinters)); + + const printers = await spectator.service.labelPrinters(); + + expect(printApiService.PrintLabelPrinters).toHaveBeenCalled(); + expect(printers).toEqual(mockPrinters.result); + }); + }); + + describe('officePrinters', () => { + it('should call PrintOfficePrinters and return printers', async () => { + const mockPrinters: ListResponseArgsOfKeyValueDTOOfStringAndString = { + error: false, + result: [ + { + key: 'printer1', + value: 'Printer 1', + }, + { + key: 'printer2', + value: 'Printer 2', + }, + ], + }; + + const printApiService: jest.Mocked = + spectator.inject(PrintApiService); + + printApiService.PrintOfficePrinters.mockReturnValue(of(mockPrinters)); + + const printers = await spectator.service.officePrinters(); + + expect(printApiService.PrintOfficePrinters).toHaveBeenCalled(); + expect(printers).toEqual(mockPrinters.result); + }); + }); + + describe('printers', () => { + it('should call labelPrinters when printerType is LABEL', async () => { + const labelPrintersSpy = jest + .spyOn(spectator.service, 'labelPrinters') + .mockReturnValue(Promise.resolve([])); + await spectator.service.printers(PrinterType.LABEL); + expect(labelPrintersSpy).toHaveBeenCalled(); + }); + + it('should call officePrinters when printerType is OFFICE', async () => { + const officePrintersSpy = jest + .spyOn(spectator.service, 'officePrinters') + .mockReturnValue(Promise.resolve([])); + await spectator.service.printers(PrinterType.OFFICE); + expect(officePrintersSpy).toHaveBeenCalled(); + }); + }); + describe('print', () => { + const mockPrinters = [ + { key: 'printer1', value: 'Printer 1', selected: false, enabled: true }, + { key: 'printer2', value: 'Printer 2', selected: true, enabled: true }, + ]; + + let mockPrint: jest.Mock; + let platform: jest.Mocked; + let printSpy: jest.SpyInstance; + + beforeEach(() => { + mockPrint = jest.fn().mockResolvedValue(undefined); + platform = spectator.inject(Platform); + + // Mock the printers method to return our mock printers + printSpy = jest + .spyOn(spectator.service, 'printers') + .mockResolvedValue(mockPrinters); + + // Reset platform flags before each test + platform.ANDROID = false; + platform.IOS = false; + + // Reset the dialog mock before each test + mockDialogFn.mockClear(); + mockDialogClosedObservable.closed = of({ printer: mockPrinters[1] }); + }); + + it('should fetch printers of the specified type', async () => { + // Act + await spectator.service.print(PrinterType.LABEL, mockPrint); + + // Assert + expect(printSpy).toHaveBeenCalledWith(PrinterType.LABEL); + }); + + it('should attempt direct printing on desktop when a printer is selected', async () => { + // Act + await spectator.service.print(PrinterType.LABEL, mockPrint); + + // Assert + expect(mockPrint).toHaveBeenCalledWith(mockPrinters[1]); + expect(mockDialogFn).not.toHaveBeenCalled(); + }); + + it('should return the selected printer after successful direct print', async () => { + // Act + const result = await spectator.service.print( + PrinterType.LABEL, + mockPrint, + ); + + // Assert + expect(result).toEqual({ printer: mockPrinters[1] }); + }); + + it('should show dialog with error when direct printing fails', async () => { + // Arrange + const printError = new Error('Print failed'); + mockPrint.mockRejectedValueOnce(printError); + + // Act + await spectator.service.print(PrinterType.LABEL, mockPrint); + + // Assert + expect(mockDialogFn).toHaveBeenCalledWith({ + data: { + printers: mockPrinters, + error: printError, + print: mockPrint, + }, + }); + }); + + it('should not attempt direct printing on Android', async () => { + // Arrange + platform.ANDROID = true; + + // Act + await spectator.service.print(PrinterType.LABEL, mockPrint); + + // Assert + expect(mockPrint).not.toHaveBeenCalled(); + expect(mockDialogFn).toHaveBeenCalled(); + }); + + it('should not attempt direct printing on iOS', async () => { + // Arrange + platform.IOS = true; + + // Act + await spectator.service.print(PrinterType.LABEL, mockPrint); + + // Assert + expect(mockPrint).not.toHaveBeenCalled(); + expect(mockDialogFn).toHaveBeenCalled(); + }); + + it('should show print dialog when no printer is selected', async () => { + // Arrange + const printersWithoutSelection = [ + { key: 'printer1', value: 'Printer 1', selected: false, enabled: true }, + { key: 'printer2', value: 'Printer 2', selected: false, enabled: true }, + ]; + + printSpy.mockResolvedValueOnce(printersWithoutSelection); + + // Act + await spectator.service.print(PrinterType.LABEL, mockPrint); + + // Assert + expect(mockPrint).not.toHaveBeenCalled(); + expect(mockDialogFn).toHaveBeenCalled(); + }); + + it('should pass the correct data to the print dialog', async () => { + // Arrange + platform.ANDROID = true; // Force dialog to show + + // Act + await spectator.service.print(PrinterType.LABEL, mockPrint); + + // Assert + expect(mockDialogFn).toHaveBeenCalledWith({ + data: { + printers: mockPrinters, + error: undefined, + print: mockPrint, + }, + }); + }); + + it('should return the printer selected in the dialog', async () => { + // Arrange + platform.ANDROID = true; // Force dialog to show + const selectedPrinter = mockPrinters[0]; + mockDialogClosedObservable.closed = of({ printer: selectedPrinter }); + + // Act + const result = await spectator.service.print( + PrinterType.LABEL, + mockPrint, + ); + + // Assert + expect(result).toEqual({ printer: selectedPrinter }); + }); + + it('should return undefined printer when dialog is cancelled', async () => { + // Arrange + platform.ANDROID = true; // Force dialog to show + mockDialogClosedObservable.closed = of(undefined); + + // Act + const result = await spectator.service.print( + PrinterType.LABEL, + mockPrint, + ); + + // Assert + expect(result).toEqual({ printer: undefined }); + }); + }); +}); diff --git a/libs/common/print/src/lib/services/print.service.ts b/libs/common/print/src/lib/services/print.service.ts index 7b64ee673..1d4ff7766 100644 --- a/libs/common/print/src/lib/services/print.service.ts +++ b/libs/common/print/src/lib/services/print.service.ts @@ -1,7 +1,7 @@ import { inject, Injectable } from '@angular/core'; import { PrintService as PrintApiService } from '@generated/swagger/print-api'; import { Platform } from '@angular/cdk/platform'; -import { firstValueFrom, map, Observable } from 'rxjs'; +import { firstValueFrom, map } from 'rxjs'; import { Printer, PrinterType } from '../models'; import { injectDialog } from '@isa/ui/dialog'; @@ -21,20 +21,30 @@ export class PrintService { * Retrieves a list of available label printers * @returns Observable of label printer array */ - labelPrinters(): Observable { - return this.#printService - .PrintLabelPrinters() - .pipe(map((res) => res.result as Printer[])); + labelPrinters(): Promise { + return firstValueFrom( + this.#printService + .PrintLabelPrinters() + .pipe(map((res) => res.result as Printer[])), + ); } /** * Retrieves a list of available office printers * @returns Observable of office printer array */ - officePrinters(): Observable { - return this.#printService - .PrintOfficePrinters() - .pipe(map((res) => res.result as Printer[])); + officePrinters(): Promise { + return firstValueFrom( + this.#printService + .PrintOfficePrinters() + .pipe(map((res) => res.result as Printer[])), + ); + } + + printers(printerType: PrinterType): Promise { + return printerType === PrinterType.LABEL + ? this.labelPrinters() + : this.officePrinters(); } /** @@ -48,30 +58,26 @@ export class PrintService { */ async print( printerType: PrinterType, - printFn: (printer: Printer) => Promise, + printFn: (printer: Printer) => Promise, ): Promise<{ printer?: Printer }> { // Get the list of printers based on the printer type - const printers$ = - printerType === PrinterType.LABEL - ? this.labelPrinters() - : this.officePrinters(); + const printers = await this.printers(printerType); - const printers = await firstValueFrom(printers$); + const selectedPrinter = printers.find((p) => p.selected); // If the platform is not Android or iOS, we can assume this is stationary devices // and we can try to print directly to the selected printer. // If it fails, we show the print dialog with the error. - let error: unknown | undefined = undefined; - if (!(this.#platform.ANDROID || this.#platform.IOS)) { - const selectedPrinter = printers.find((p) => p.selected); + const directPrintAllowed = + selectedPrinter && !(this.#platform.ANDROID || this.#platform.IOS); - if (selectedPrinter) { - try { - await printFn(selectedPrinter); - return { printer: selectedPrinter }; - } catch (e) { - error = e; - } + let error: unknown | undefined = undefined; + if (directPrintAllowed) { + try { + await printFn(selectedPrinter); + return { printer: selectedPrinter }; + } catch (e) { + error = e; } } diff --git a/libs/oms/data-access/src/lib/services/index.ts b/libs/oms/data-access/src/lib/services/index.ts index f143f1f9a..f604eeb4c 100644 --- a/libs/oms/data-access/src/lib/services/index.ts +++ b/libs/oms/data-access/src/lib/services/index.ts @@ -1,6 +1,6 @@ export * from './return-can-return.service'; export * from './return-details.service'; -export * from './return-print-receipts.service'; +export * from './print-receipts.service'; export * from './return-process.service'; export * from './return-search.service'; export * from './return-task-list.service'; diff --git a/libs/oms/data-access/src/lib/services/print-receipts.service.spec.ts b/libs/oms/data-access/src/lib/services/print-receipts.service.spec.ts new file mode 100644 index 000000000..b0b686033 --- /dev/null +++ b/libs/oms/data-access/src/lib/services/print-receipts.service.spec.ts @@ -0,0 +1,68 @@ +import { SpectatorService, createServiceFactory } from '@ngneat/spectator/jest'; +import { PrintReceiptsService } from './print-receipts.service'; +import { Printer, PrinterType, PrintService } from '@isa/common/print'; +import { OMSPrintService } from '@generated/swagger/print-api'; +import { of } from 'rxjs'; + +describe('PrintReceiptsService', () => { + let spectator: SpectatorService; + + const createService = createServiceFactory({ + service: PrintReceiptsService, + mocks: [OMSPrintService, PrintService], + }); + + let mockPrintService: jest.Mocked; + let mockOmsPrintService: jest.Mocked; + + beforeEach(() => { + spectator = createService(); + mockPrintService = spectator.inject(PrintService); + mockOmsPrintService = spectator.inject(OMSPrintService); + }); + + it('should be created', () => { + expect(spectator.service).toBeTruthy(); + }); + + describe('printReturnReceipts', () => { + it('should throw an error if no return receipt IDs are provided', async () => { + await expect( + spectator.service.printReturnReceipts({ returnReceiptIds: [] }), + ).rejects.toThrow('No return receipt IDs provided'); + }); + + it('should call the print service with the correct parameters', async () => { + const mockReturnReceiptIds = [1, 2, 3]; + + mockPrintService.print.mockImplementation((printerType, callback) => { + expect(printerType).toBe(PrinterType.LABEL); + const mockPrinter: Printer = { + key: 'mockPrinterKey', + value: 'Mock Printer', + selected: true, + enabled: true, + description: 'Mock printer description', + }; + return callback(mockPrinter); + }); + + mockOmsPrintService.OMSPrintReturnReceipt.mockReturnValue( + of({ error: false }), + ); + + await spectator.service.printReturnReceipts({ + returnReceiptIds: mockReturnReceiptIds, + }); + + expect(mockPrintService.print).toHaveBeenCalledWith( + expect.anything(), + expect.any(Function), + ); + expect(mockOmsPrintService.OMSPrintReturnReceipt).toHaveBeenCalledWith({ + printer: expect.any(String), + data: mockReturnReceiptIds, + }); + }); + }); +}); diff --git a/libs/oms/data-access/src/lib/services/print-receipts.service.ts b/libs/oms/data-access/src/lib/services/print-receipts.service.ts new file mode 100644 index 000000000..86f58eb04 --- /dev/null +++ b/libs/oms/data-access/src/lib/services/print-receipts.service.ts @@ -0,0 +1,43 @@ +import { inject, Injectable } from '@angular/core'; +import { OMSPrintService } from '@generated/swagger/print-api'; +import { PrinterType, PrintService } from '@isa/common/print'; +import { firstValueFrom } from 'rxjs'; + +/** + * Service responsible for printing return receipts using the OMS print API. + * + * This service handles the communication with backend printing services and manages + * the print job lifecycle through the common print infrastructure. + */ +@Injectable({ providedIn: 'root' }) +export class PrintReceiptsService { + #omsPrintService = inject(OMSPrintService); + #printService = inject(PrintService); + + /** + * Prints return receipts for the provided receipt IDs. + * + * @param options - The printing options + * @param options.returnReceiptIds - Array of return receipt IDs to print + * @throws {Error} When no return receipt IDs are provided + * @returns A promise that resolves when the print job is complete + */ + async printReturnReceipts({ + returnReceiptIds, + }: { + returnReceiptIds: number[]; + }) { + if (returnReceiptIds.length === 0) { + throw new Error('No return receipt IDs provided'); + } + + return this.#printService.print(PrinterType.LABEL, (printer) => { + return firstValueFrom( + this.#omsPrintService.OMSPrintReturnReceipt({ + printer: printer.key, + data: returnReceiptIds, + }), + ); + }); + } +} diff --git a/libs/oms/data-access/src/lib/services/return-print-receipts.service.ts b/libs/oms/data-access/src/lib/services/return-print-receipts.service.ts deleted file mode 100644 index 2ea7873c9..000000000 --- a/libs/oms/data-access/src/lib/services/return-print-receipts.service.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { inject, Injectable } from '@angular/core'; -import { OMSPrintService } from '@generated/swagger/print-api'; -import { PrinterType, PrintService } from '@isa/common/print'; -import { firstValueFrom } from 'rxjs'; - -@Injectable({ providedIn: 'root' }) -export class ReturnPrintReceiptsService { - #omsPrintService = inject(OMSPrintService); - #printService = inject(PrintService); - - async printReturnReceipts({ - returnReceiptIds, - }: { - returnReceiptIds: number[]; - }) { - return this.#printService.print(PrinterType.LABEL, (printer) => { - return firstValueFrom( - this.#omsPrintService.OMSPrintReturnReceipt({ - printer: printer.key, - data: returnReceiptIds, - }), - ); - }); - } -} diff --git a/libs/oms/data-access/src/lib/services/return-process.service.ts b/libs/oms/data-access/src/lib/services/return-process.service.ts index d77022af3..1f093c2b7 100644 --- a/libs/oms/data-access/src/lib/services/return-process.service.ts +++ b/libs/oms/data-access/src/lib/services/return-process.service.ts @@ -38,7 +38,7 @@ import { ReturnReceiptValuesDTO, } from '@generated/swagger/oms-api'; import { firstValueFrom } from 'rxjs'; -import { ReturnPrintReceiptsService } from './return-print-receipts.service'; +import { PrintReceiptsService } from './print-receipts.service'; import { z } from 'zod'; /** @@ -51,7 +51,7 @@ export class ReturnProcessService { #logger = logger(); #receiptService = inject(ReceiptService); - #printReceiptsService = inject(ReturnPrintReceiptsService); + #printReceiptsService = inject(PrintReceiptsService); /** * Gets active questions in the return process based on previously provided answers. diff --git a/libs/oms/feature/return-review/src/lib/return-review-header/return-review-header.component.ts b/libs/oms/feature/return-review/src/lib/return-review-header/return-review-header.component.ts index 6ce135dbb..226fe7ff4 100644 --- a/libs/oms/feature/return-review/src/lib/return-review-header/return-review-header.component.ts +++ b/libs/oms/feature/return-review/src/lib/return-review-header/return-review-header.component.ts @@ -13,5 +13,6 @@ import { NgIconComponent, provideIcons } from '@ng-icons/core'; providers: [provideIcons({ isaActionPrinter })], }) export class ReturnReviewHeaderComponent { + // TODO: Kann direkt in der Komponente gehandled werden printReceipt = output(); } diff --git a/libs/oms/feature/return-review/src/lib/return-review.component.ts b/libs/oms/feature/return-review/src/lib/return-review.component.ts index 7860b5734..a8d712d24 100644 --- a/libs/oms/feature/return-review/src/lib/return-review.component.ts +++ b/libs/oms/feature/return-review/src/lib/return-review.component.ts @@ -1,8 +1,5 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; -import { - ReturnPrintReceiptsService, - ReturnProcessStore, -} from '@isa/oms/data-access'; +import { PrintReceiptsService, ReturnProcessStore } from '@isa/oms/data-access'; import { injectActivatedProcessId } from '@isa/core/process'; import { ReturnTaskListComponent } from '@isa/oms/shared/task-list'; import { ReturnReviewHeaderComponent } from './return-review-header/return-review-header.component'; @@ -16,21 +13,23 @@ import { ReturnReviewHeaderComponent } from './return-review-header/return-revie imports: [ReturnTaskListComponent, ReturnReviewHeaderComponent], }) export class ReturnReviewComponent { - #printReceiptsService = inject(ReturnPrintReceiptsService); + #printReceiptsService = inject(PrintReceiptsService); #returnProcessStore = inject(ReturnProcessStore); processId = injectActivatedProcessId(); async printReceipt() { const processId = this.processId(); if (processId) { - const receiptId = - this.#returnProcessStore.entityMap()[processId].receiptId; + const receiptIds = this.#returnProcessStore + .entities() + .filter((p) => p.processId === processId && p.returnReceipt?.id) + .map((p) => p.returnReceipt!.id); - if (receiptId) { - await this.#printReceiptsService.printReturnReceipts({ - returnReceiptIds: [receiptId], - }); - } + console.log('receiptIds', this.#returnProcessStore.entities()); + + await this.#printReceiptsService.printReturnReceipts({ + returnReceiptIds: receiptIds, + }); } } } diff --git a/libs/ui/list/src/lib/list.component.ts b/libs/ui/dialog/src/lib/confirmation-dialog/confirmation-dialog.component.spec.ts similarity index 100% rename from libs/ui/list/src/lib/list.component.ts rename to libs/ui/dialog/src/lib/confirmation-dialog/confirmation-dialog.component.spec.ts diff --git a/libs/ui/list/src/lib/list.examples.ts b/libs/ui/dialog/src/lib/message-dialog/message-dialog.component.spec.ts similarity index 100% rename from libs/ui/list/src/lib/list.examples.ts rename to libs/ui/dialog/src/lib/message-dialog/message-dialog.component.spec.ts diff --git a/libs/ui/input-controls/src/index.ts b/libs/ui/input-controls/src/index.ts index 40b22105d..91fb999aa 100644 --- a/libs/ui/input-controls/src/index.ts +++ b/libs/ui/input-controls/src/index.ts @@ -5,6 +5,8 @@ export * from './lib/checkbox/checklist.component'; export * from './lib/core/input-control.directive'; export * from './lib/dropdown/dropdown.component'; export * from './lib/dropdown/dropdown.types'; +export * from './lib/listbox/listbox-item.directive'; +export * from './lib/listbox/listbox.directive'; export * from './lib/text-field/text-field.component'; export * from './lib/text-field/textarea.component'; export * from './lib/chips/chips.component'; diff --git a/libs/ui/input-controls/src/input-controls.scss b/libs/ui/input-controls/src/input-controls.scss index 10f11077d..977899cb7 100644 --- a/libs/ui/input-controls/src/input-controls.scss +++ b/libs/ui/input-controls/src/input-controls.scss @@ -2,5 +2,6 @@ @use "./lib/checkbox/checklist"; @use "./lib/chips/chips"; @use "./lib/dropdown/dropdown"; +@use "./lib/listbox/listbox"; @use "./lib/text-field/text-field"; @use "./lib/text-field/textarea"; diff --git a/libs/ui/list/src/lib/_list.scss b/libs/ui/input-controls/src/lib/listbox/_listbox.scss similarity index 90% rename from libs/ui/list/src/lib/_list.scss rename to libs/ui/input-controls/src/lib/listbox/_listbox.scss index 231840d2a..e380827b6 100644 --- a/libs/ui/list/src/lib/_list.scss +++ b/libs/ui/input-controls/src/lib/listbox/_listbox.scss @@ -1,8 +1,8 @@ -.ui-list { +.ui-listbox { @apply flex flex-col items-stretch w-full; } -.ui-text-list-item { +.ui-listbox-item { @apply flex h-12 px-6 flex-col justify-center items-start gap-[0.65rem] rounded-[.5rem] text-isa-neutral-700 bg-isa-white; @apply isa-text-body-2-bold; diff --git a/libs/ui/input-controls/src/lib/listbox/listbox-item.directive.spec.ts b/libs/ui/input-controls/src/lib/listbox/listbox-item.directive.spec.ts new file mode 100644 index 000000000..03ab84524 --- /dev/null +++ b/libs/ui/input-controls/src/lib/listbox/listbox-item.directive.spec.ts @@ -0,0 +1,39 @@ +import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; +import { ListboxItemDirective } from './listbox-item.directive'; +import { CdkOption } from '@angular/cdk/listbox'; +import { Component } from '@angular/core'; +import { ListboxDirective } from './listbox.directive'; + +@Component({ + selector: 'ui-test-host', + template: ` +
+ +
+ `, + imports: [ListboxDirective, ListboxItemDirective], +}) +class TestHostComponent {} + +describe('ListboxItemDirective', () => { + let spectator: SpectatorHost; + const createHost = createHostFactory(TestHostComponent); + + beforeEach(() => { + spectator = createHost(''); + }); + + it('should create an instance', () => { + expect(spectator.query(ListboxItemDirective)).toBeTruthy(); + }); + + it('should have the ui-listbox-item class', () => { + expect(spectator.query('[uiListboxItem]')).toHaveClass('ui-listbox-item'); + }); + + it('should have CdkOption applied', () => { + const cdkOptionInstance = spectator.query(CdkOption); + + expect(cdkOptionInstance).toBeTruthy(); + }); +}); diff --git a/libs/ui/list/src/lib/text-list-item.directive.ts b/libs/ui/input-controls/src/lib/listbox/listbox-item.directive.ts similarity index 83% rename from libs/ui/list/src/lib/text-list-item.directive.ts rename to libs/ui/input-controls/src/lib/listbox/listbox-item.directive.ts index 5769f606e..3bf183564 100644 --- a/libs/ui/list/src/lib/text-list-item.directive.ts +++ b/libs/ui/input-controls/src/lib/listbox/listbox-item.directive.ts @@ -13,9 +13,9 @@ import { CdkOption } from '@angular/cdk/listbox'; * ``` */ @Directive({ - selector: '[uiTextListItem]', + selector: '[uiListboxItem]', host: { - class: 'ui-text-list-item', + class: 'ui-listbox-item', }, hostDirectives: [ { @@ -24,4 +24,4 @@ import { CdkOption } from '@angular/cdk/listbox'; }, ], }) -export class TextListItemDirective {} +export class ListboxItemDirective {} diff --git a/libs/ui/input-controls/src/lib/listbox/listbox.directive.spec.ts b/libs/ui/input-controls/src/lib/listbox/listbox.directive.spec.ts new file mode 100644 index 000000000..8e387d3a5 --- /dev/null +++ b/libs/ui/input-controls/src/lib/listbox/listbox.directive.spec.ts @@ -0,0 +1,32 @@ +import { + createDirectiveFactory, + SpectatorDirective, +} from '@ngneat/spectator/jest'; +import { ListboxDirective } from './listbox.directive'; +import { CdkListbox } from '@angular/cdk/listbox'; + +describe('ListboxDirective', () => { + let spectator: SpectatorDirective; + + const createDirective = createDirectiveFactory({ + directive: ListboxDirective, + }); + + beforeEach(() => { + spectator = createDirective('
'); + }); + + it('should create an instance', () => { + expect(spectator.directive).toBeTruthy(); + }); + + it('should have the ui-listbox class', () => { + expect(spectator.element).toHaveClass('ui-listbox'); + }); + + it('should have CdkListbox applied', () => { + const cdkListboxInstance = spectator.query(CdkListbox); + + expect(cdkListboxInstance).toBeTruthy(); + }); +}); diff --git a/libs/ui/list/src/lib/list.directive.ts b/libs/ui/input-controls/src/lib/listbox/listbox.directive.ts similarity index 90% rename from libs/ui/list/src/lib/list.directive.ts rename to libs/ui/input-controls/src/lib/listbox/listbox.directive.ts index 58e78fa7f..e2280c388 100644 --- a/libs/ui/list/src/lib/list.directive.ts +++ b/libs/ui/input-controls/src/lib/listbox/listbox.directive.ts @@ -15,9 +15,9 @@ import { CdkListbox } from '@angular/cdk/listbox'; * ``` */ @Directive({ - selector: '[uiList]', + selector: '[uiListbox]', host: { - class: 'ui-list', + class: 'ui-listbox', }, hostDirectives: [ { @@ -31,4 +31,4 @@ import { CdkListbox } from '@angular/cdk/listbox'; }, ], }) -export class ListDirective {} +export class ListboxDirective {} diff --git a/libs/ui/list/README.md b/libs/ui/list/README.md deleted file mode 100644 index f7aace42e..000000000 --- a/libs/ui/list/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# ui-list - -This library was generated with [Nx](https://nx.dev). - -## Running unit tests - -Run `nx test ui-list` to execute the unit tests. diff --git a/libs/ui/list/eslint.config.mjs b/libs/ui/list/eslint.config.mjs deleted file mode 100644 index c68787af3..000000000 --- a/libs/ui/list/eslint.config.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import nx from '@nx/eslint-plugin'; -import baseConfig from '../../../eslint.config.mjs'; - -export default [ - ...baseConfig, - ...nx.configs['flat/angular'], - ...nx.configs['flat/angular-template'], - { - files: ['**/*.ts'], - rules: { - '@angular-eslint/directive-selector': [ - 'error', - { - type: 'attribute', - prefix: 'ui', - style: 'camelCase', - }, - ], - '@angular-eslint/component-selector': [ - 'error', - { - type: 'element', - prefix: 'ui', - style: 'kebab-case', - }, - ], - }, - }, - { - files: ['**/*.html'], - // Override or add rules here - rules: {}, - }, -]; diff --git a/libs/ui/list/jest.config.ts b/libs/ui/list/jest.config.ts deleted file mode 100644 index 50ce48d3f..000000000 --- a/libs/ui/list/jest.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -export default { - displayName: 'ui-list', - preset: '../../../jest.preset.js', - setupFilesAfterEnv: ['/src/test-setup.ts'], - coverageDirectory: '../../../coverage/libs/ui/list', - transform: { - '^.+\\.(ts|mjs|js|html)$': [ - 'jest-preset-angular', - { - tsconfig: '/tsconfig.spec.json', - stringifyContentPathRegex: '\\.(html|svg)$', - }, - ], - }, - transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], - snapshotSerializers: [ - 'jest-preset-angular/build/serializers/no-ng-attributes', - 'jest-preset-angular/build/serializers/ng-snapshot', - 'jest-preset-angular/build/serializers/html-comment', - ], -}; diff --git a/libs/ui/list/project.json b/libs/ui/list/project.json deleted file mode 100644 index bc405b04a..000000000 --- a/libs/ui/list/project.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "ui-list", - "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/ui/list/src", - "prefix": "ui", - "projectType": "library", - "tags": [], - "targets": { - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "libs/ui/list/jest.config.ts" - } - }, - "lint": { - "executor": "@nx/eslint:lint" - } - } -} diff --git a/libs/ui/list/src/index.ts b/libs/ui/list/src/index.ts deleted file mode 100644 index 0df8bdf0b..000000000 --- a/libs/ui/list/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib/list.directive'; -export * from './lib/text-list-item.directive'; diff --git a/libs/ui/list/src/lib/text-list-item.component.ts b/libs/ui/list/src/lib/text-list-item.component.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/libs/ui/list/src/list.scss b/libs/ui/list/src/list.scss deleted file mode 100644 index b405cd97b..000000000 --- a/libs/ui/list/src/list.scss +++ /dev/null @@ -1 +0,0 @@ -@use "./lib/list"; diff --git a/libs/ui/list/src/test-setup.ts b/libs/ui/list/src/test-setup.ts deleted file mode 100644 index ea414013f..000000000 --- a/libs/ui/list/src/test-setup.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone'; - -setupZoneTestEnv({ - errorOnUnknownElements: true, - errorOnUnknownProperties: true, -}); diff --git a/libs/ui/list/tsconfig.json b/libs/ui/list/tsconfig.json deleted file mode 100644 index fde35eab0..000000000 --- a/libs/ui/list/tsconfig.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "compilerOptions": { - "target": "es2022", - "forceConsistentCasingInFileNames": true, - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.lib.json" - }, - { - "path": "./tsconfig.spec.json" - } - ], - "extends": "../../../tsconfig.base.json", - "angularCompilerOptions": { - "enableI18nLegacyMessageIdFormat": false, - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/libs/ui/list/tsconfig.lib.json b/libs/ui/list/tsconfig.lib.json deleted file mode 100644 index 9b49be758..000000000 --- a/libs/ui/list/tsconfig.lib.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "declaration": true, - "declarationMap": true, - "inlineSources": true, - "types": [] - }, - "exclude": [ - "src/**/*.spec.ts", - "src/test-setup.ts", - "jest.config.ts", - "src/**/*.test.ts" - ], - "include": ["src/**/*.ts"] -} diff --git a/libs/ui/list/tsconfig.spec.json b/libs/ui/list/tsconfig.spec.json deleted file mode 100644 index f858ef78c..000000000 --- a/libs/ui/list/tsconfig.spec.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "../../../dist/out-tsc", - "module": "commonjs", - "target": "es2016", - "types": ["jest", "node"] - }, - "files": ["src/test-setup.ts"], - "include": [ - "jest.config.ts", - "src/**/*.test.ts", - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] -} diff --git a/tsconfig.base.json b/tsconfig.base.json index 6a5a4d4ec..ae9d132f8 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -79,7 +79,6 @@ "@isa/ui/input-controls": ["libs/ui/input-controls/src/index.ts"], "@isa/ui/item-rows": ["libs/ui/item-rows/src/index.ts"], "@isa/ui/layout": ["libs/ui/layout/src/index.ts"], - "@isa/ui/list": ["libs/ui/list/src/index.ts"], "@isa/ui/progress-bar": ["libs/ui/progress-bar/src/index.ts"], "@isa/ui/search-bar": ["libs/ui/search-bar/src/index.ts"], "@isa/ui/toolbar": ["libs/ui/toolbar/src/index.ts"],