From a1d20328eb16dc677bfbde4ed1a619f6375d165c Mon Sep 17 00:00:00 2001 From: Romuald Caplier Date: Thu, 25 Apr 2024 16:21:36 +0200 Subject: [PATCH 01/15] otherLinks is now a list if there is 9 or more items --- apps/datahub/src/app/app.component.html | 2 +- .../record-apis/record-apis.component.html | 84 +++--- .../record-apis/record-apis.component.ts | 5 +- .../record-metadata.component.css | 15 - .../record-metadata.component.html | 15 +- .../record-otherlinks.component.html | 51 ++-- .../record-otherlinks.component.ts | 7 + .../record/src/lib/state/mdview.facade.ts | 16 +- libs/ui/elements/src/index.ts | 2 + .../lib/link-card/link-card.component.html | 2 +- .../src/lib/list-item/list-item.component.css | 0 .../lib/list-item/list-item.component.html | 18 ++ .../lib/list-item/list-item.component.spec.ts | 102 +++++++ .../list-item/list-item.component.stories.ts | 45 +++ .../src/lib/list-item/list-item.component.ts | 21 ++ .../elements/src/lib/list/list.component.css | 32 ++ .../elements/src/lib/list/list.component.html | 65 ++++ .../src/lib/list/list.component.spec.ts | 281 ++++++++++++++++++ .../elements/src/lib/list/list.component.ts | 200 +++++++++++++ .../ui/elements/src/lib/ui-elements.module.ts | 8 + .../src/lib/carousel/carousel.component.css | 3 + .../src/lib/carousel/carousel.component.html | 71 ++++- .../lib/carousel/carousel.component.spec.ts | 4 +- .../src/lib/carousel/carousel.component.ts | 79 ++++- 24 files changed, 996 insertions(+), 132 deletions(-) create mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.css create mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.html create mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.spec.ts create mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.stories.ts create mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.ts create mode 100644 libs/ui/elements/src/lib/list/list.component.css create mode 100644 libs/ui/elements/src/lib/list/list.component.html create mode 100644 libs/ui/elements/src/lib/list/list.component.spec.ts create mode 100644 libs/ui/elements/src/lib/list/list.component.ts diff --git a/apps/datahub/src/app/app.component.html b/apps/datahub/src/app/app.component.html index feeab422eb..a3388896aa 100644 --- a/apps/datahub/src/app/app.component.html +++ b/apps/datahub/src/app/app.component.html @@ -1,6 +1,6 @@
diff --git a/apps/datahub/src/app/record/record-apis/record-apis.component.html b/apps/datahub/src/app/record/record-apis/record-apis.component.html index ee0d3c6694..d6d3b243ff 100644 --- a/apps/datahub/src/app/record/record-apis/record-apis.component.html +++ b/apps/datahub/src/app/record/record-apis/record-apis.component.html @@ -1,27 +1,17 @@ -
-

- record.metadata.api -

+ -
-
-
-
-
-

- record.metadata.api.form.title -

- +
+ record.metadata.api.form.closeButton +
+ close + + +
+
-
- + diff --git a/apps/datahub/src/app/record/record-apis/record-apis.component.ts b/apps/datahub/src/app/record/record-apis/record-apis.component.ts index 1473720d76..2ee7526939 100644 --- a/apps/datahub/src/app/record/record-apis/record-apis.component.ts +++ b/apps/datahub/src/app/record/record-apis/record-apis.component.ts @@ -12,7 +12,10 @@ export class RecordApisComponent implements OnInit { maxHeight = '0px' opacity = 0 selectedApiLink: DatasetServiceDistribution - constructor(public facade: MdViewFacade) {} + + apiLinks$ = this.facade.apiLinks$ + + constructor(private facade: MdViewFacade) {} ngOnInit(): void { this.setStyle(undefined) diff --git a/apps/datahub/src/app/record/record-metadata/record-metadata.component.css b/apps/datahub/src/app/record/record-metadata/record-metadata.component.css index a92dcd44b6..e3a0105a26 100644 --- a/apps/datahub/src/app/record/record-metadata/record-metadata.component.css +++ b/apps/datahub/src/app/record/record-metadata/record-metadata.component.css @@ -33,18 +33,3 @@ .tab-header-label { @apply uppercase text-sm text-primary opacity-75 hover:text-primary-darker; } - -:host { - --container-outside-width: calc(50vw - 1024px / 2); -} -@media (max-width: 1024px) { - :host { - --container-outside-width: 1rem; - } -} - -:host ::ng-deep gn-ui-carousel { - display: block; - margin-left: calc(-1 * var(--container-outside-width)); - margin-right: calc(-1 * var(--container-outside-width)); -} diff --git a/apps/datahub/src/app/record/record-metadata/record-metadata.component.html b/apps/datahub/src/app/record/record-metadata/record-metadata.component.html index a339208c56..6855889c7c 100644 --- a/apps/datahub/src/app/record/record-metadata/record-metadata.component.html +++ b/apps/datahub/src/app/record/record-metadata/record-metadata.component.html @@ -117,19 +117,20 @@ class="container-lg px-4 lg:mx-auto" *ngIf="displayDownload$ | async" > - + @@ -149,7 +149,7 @@ -
+
+

record.metadata.links

-
- - - arrow_back - - - - - arrow_forward - - -
+
- - + + - + +
diff --git a/libs/feature/record/src/lib/state/mdview.facade.ts b/libs/feature/record/src/lib/state/mdview.facade.ts index 2072d14edd..2086564c30 100644 --- a/libs/feature/record/src/lib/state/mdview.facade.ts +++ b/libs/feature/record/src/lib/state/mdview.facade.ts @@ -32,9 +32,6 @@ export class MdViewFacade { map((uuid) => !!uuid) ) - isLoading$ = this.store.pipe(select(MdViewSelectors.getMetadataIsLoading)) - - isMetadataLoading$ = this.store.pipe( select(MdViewSelectors.getMetadataIsLoading) ) diff --git a/libs/ui/elements/src/lib/list-item/list-item.component.spec.ts b/libs/ui/elements/src/lib/list-item/list-item.component.spec.ts index e3ba8439ac..0c528e3003 100644 --- a/libs/ui/elements/src/lib/list-item/list-item.component.spec.ts +++ b/libs/ui/elements/src/lib/list-item/list-item.component.spec.ts @@ -2,10 +2,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { MatIconModule } from '@angular/material/icon' import { TranslateModule } from '@ngx-translate/core' import { ListItemComponent } from './list-item.component' -import { By } from '@angular/platform-browser' -import { ChangeDetectionStrategy, DebugElement } from '@angular/core' +import { ChangeDetectionStrategy } from '@angular/core' -describe('DownloadsListItemComponent', () => { +describe('ListItemComponent', () => { let component: ListItemComponent let fixture: ComponentFixture @@ -38,65 +37,6 @@ describe('DownloadsListItemComponent', () => { it('should create', () => { expect(component).toBeTruthy() }) - describe('download description', () => { - describe('when has a description', () => { - it('displays the description', () => { - const descElmt = fixture.debugElement.query(By.css('.text-21')) - expect(descElmt.attributes.title).toEqual( - 'A file that contains all roads' - ) - expect(descElmt.nativeElement.textContent.trim()).toEqual( - 'A file that contains all roads' - ) - }) - }) - describe('when has no description', () => { - beforeEach(() => { - delete component.link.description - fixture.detectChanges() - }) - it('displays name', () => { - const descElmt = fixture.debugElement.query(By.css('.text-21')) - - expect(descElmt.attributes.title).toEqual('allroads.geojson') - expect(descElmt.nativeElement.textContent.trim()).toEqual( - 'allroads.geojson' - ) - }) - }) - }) - describe('download format', () => { - let badgeElt: DebugElement - let spans: DebugElement[] - beforeEach(() => { - spans = fixture.debugElement.queryAll(By.css('span')) - badgeElt = spans[0] - }) - it('displays the format in the badge', () => { - expect(badgeElt.nativeElement.textContent.trim()).toEqual('geojson') - }) - it('set the badge color', () => { - expect(badgeElt.styles['background-color']).toEqual('red') - }) - - describe('when it is not Wfs', () => { - it('do not display wfs information', () => { - const spans = fixture.debugElement.queryAll(By.css('span')) - - expect(spans.length).toBe(1) - }) - }) - describe('when it is not Wfs', () => { - beforeEach(() => { - component.isFromWfs = true - fixture.detectChanges() - }) - it('add wfs information', () => { - const spans = fixture.debugElement.queryAll(By.css('span')) - - expect(spans.length).toBe(2) - }) - }) - }) + describe('download description', () => {}) }) diff --git a/libs/ui/elements/src/lib/list/list.component.html b/libs/ui/elements/src/lib/list/list.component.html index 9801cfac30..12335170c2 100644 --- a/libs/ui/elements/src/lib/list/list.component.html +++ b/libs/ui/elements/src/lib/list/list.component.html @@ -1,57 +1,7 @@ -
-
-
- {{ title }} -
-
- - > -
-
- - arrow_back - - - arrow_forward - -
-
- +
- +
+ + + > diff --git a/libs/ui/elements/src/lib/list/list.component.spec.ts b/libs/ui/elements/src/lib/list/list.component.spec.ts index 80db63b5ce..b970fa24a8 100644 --- a/libs/ui/elements/src/lib/list/list.component.spec.ts +++ b/libs/ui/elements/src/lib/list/list.component.spec.ts @@ -6,15 +6,10 @@ import { NO_ERRORS_SCHEMA, } from '@angular/core' import { ComponentFixture, TestBed } from '@angular/core/testing' -import { By } from '@angular/platform-browser' import { LinkClassifierService } from '@geonetwork-ui/util/shared' -import { LINK_FIXTURES } from '@geonetwork-ui/common/fixtures' import { TranslateModule } from '@ngx-translate/core' import { ListComponent } from './list.component' -import { - DatasetDistribution, - DatasetDownloadDistribution, -} from '@geonetwork-ui/common/domain/model/record' +import { DatasetDistribution } from '@geonetwork-ui/common/domain/model/record' @Component({ selector: 'gn-ui-download-item', @@ -27,7 +22,7 @@ class MockDownloadItemComponent { @Input() isFromWfs: boolean } -describe('DownloadsListComponent', () => { +describe('ListComponent', () => { let component: ListComponent let fixture: ComponentFixture let de: DebugElement @@ -56,226 +51,4 @@ describe('DownloadsListComponent', () => { fixture.detectChanges() expect(component).toBeTruthy() }) - - describe('with a non-empty list of downloads', () => { - let items: DebugElement[] - - beforeEach(() => { - component.listItems = [ - LINK_FIXTURES.dataCsv, - LINK_FIXTURES.dataPdf, - LINK_FIXTURES.dataPdf, - ] - fixture.detectChanges() - items = de.queryAll(By.directive(MockDownloadItemComponent)) - }) - it('contains three links', () => { - expect(items.length).toBe(3) - }) - }) - - describe('with an empty list of downloads', () => { - let item: DebugElement - - beforeEach(() => { - component.listItems = [] - fixture.detectChanges() - item = de.query(By.directive(ListComponent)) - }) - it('should not display', () => { - expect(item).toBeNull() - }) - }) - - describe('when link format is unknown', () => { - let items: DebugElement[] - - beforeEach(() => { - component.listItems = [LINK_FIXTURES.unknownFormat] - fixture.detectChanges() - items = de.queryAll(By.directive(MockDownloadItemComponent)) - }) - it('contains one link in "others" section', () => { - expect(items.length).toBe(1) - expect(component.isLinkOfFormat(component.listItems[0], 'others')).toBe( - true - ) - }) - }) - describe('when link mime type is unknown', () => { - let items: DebugElement[] - - beforeEach(() => { - component.listItems = [ - { - ...LINK_FIXTURES.geodataJsonWithMimeType, - mimeType: 'unknown/x-type', - } as DatasetDownloadDistribution, - ] - fixture.detectChanges() - items = de.queryAll(By.directive(MockDownloadItemComponent)) - }) - it('contains one link and mime type is ignored', () => { - expect(items.length).toBe(1) - expect(component.isLinkOfFormat(component.listItems[0], 'json')).toBe( - true - ) - }) - }) - describe('derives color and format from link', () => { - let items: DebugElement[] - - beforeEach(() => { - component.listItems = [LINK_FIXTURES.geodataShpWithMimeType] - fixture.detectChanges() - items = de.queryAll(By.directive(MockDownloadItemComponent)) - }) - it('contains color, isWfs & format', () => { - expect(items.length).toBe(1) - expect(items[0].componentInstance.link).toEqual( - LINK_FIXTURES.geodataShpWithMimeType - ) - expect(items[0].componentInstance.format).toEqual('shp') - expect(items[0].componentInstance.color).toEqual( - expect.stringMatching(/#[0-9a-b]{2,6}/i) - ) - expect(items[0].componentInstance.isFromWfs).toEqual(false) - }) - }) - describe('filtering links', () => { - beforeEach(() => { - component.listItems = [ - LINK_FIXTURES.dataCsv, - LINK_FIXTURES.geodataJsonWithMimeType, - ] - }) - describe('no filter', () => { - beforeEach(() => { - component.activeFilterFormats = ['all'] - fixture.detectChanges() - }) - it('shows all links', () => { - expect(component.filteredListItems).toEqual([ - LINK_FIXTURES.dataCsv, - LINK_FIXTURES.geodataJsonWithMimeType, - ]) - }) - }) - describe('filter on csv', () => { - beforeEach(() => { - component.activeFilterFormats = ['csv'] - fixture.detectChanges() - }) - it('shows only one link', () => { - expect(component.filteredListItems).toEqual([LINK_FIXTURES.dataCsv]) - }) - }) - describe('filter on json and csv', () => { - beforeEach(() => { - component.activeFilterFormats = ['csv', 'json'] - fixture.detectChanges() - }) - it('shows both links including geojson', () => { - expect(component.filteredListItems).toEqual([ - LINK_FIXTURES.dataCsv, - LINK_FIXTURES.geodataJsonWithMimeType, - ]) - }) - }) - describe('filter on shp', () => { - beforeEach(() => { - component.activeFilterFormats = ['shp'] - fixture.detectChanges() - }) - it('shows no link', () => { - expect(component.filteredListItems).toEqual([]) - }) - }) - - describe('toggling formats', () => { - it('removes already enabled formats', () => { - component.activeFilterFormats = ['excel', 'csv', 'shp'] - component.toggleFilterFormat('excel') - expect(component.activeFilterFormats).toEqual(['csv', 'shp']) - }) - it('adds disabled formats', () => { - component.activeFilterFormats = ['excel', 'csv', 'shp'] - component.toggleFilterFormat('json') - expect(component.activeFilterFormats).toEqual([ - 'excel', - 'csv', - 'shp', - 'json', - ]) - }) - it('sets filter to all if disabling the last format', () => { - component.activeFilterFormats = ['excel', 'csv'] - component.toggleFilterFormat('excel') - component.toggleFilterFormat('csv') - expect(component.activeFilterFormats).toEqual(['all']) - }) - it('toggling all disables other formats if disabled', () => { - component.activeFilterFormats = ['excel', 'csv'] - component.toggleFilterFormat('all') - expect(component.activeFilterFormats).toEqual(['all']) - }) - it('toggling all does nothing if already enabled', () => { - component.activeFilterFormats = ['all'] - component.toggleFilterFormat('all') - expect(component.activeFilterFormats).toEqual(['all']) - }) - }) - }) - - describe('filter buttons visibility', () => { - let items: DebugElement[] - describe('csv, json, pdf', () => { - beforeEach(() => { - component.listItems = [ - LINK_FIXTURES.dataCsv, - LINK_FIXTURES.dataJson, - LINK_FIXTURES.dataPdf, - ] - fixture.detectChanges() - items = de.queryAll(By.css('.format-filter')) - }) - it('show only all, csv, json and pdf filters', () => { - const displayedFormats = items.map( - (item) => item.attributes['data-format'] - ) - expect(displayedFormats).toEqual(['all', 'csv', 'json', 'others']) - }) - }) - describe('geojson, shp, excel', () => { - beforeEach(() => { - component.listItems = [ - LINK_FIXTURES.geodataJsonWithMimeType, - LINK_FIXTURES.geodataShp, - LINK_FIXTURES.dataXls, - LINK_FIXTURES.dataXlsx, - ] - fixture.detectChanges() - items = de.queryAll(By.css('.format-filter')) - }) - it('show only all, excel, json and shp filters', () => { - const displayedFormats = items.map( - (item) => item.attributes['data-format'] - ) - expect(displayedFormats).toEqual(['all', 'excel', 'json', 'shp']) - }) - }) - describe('pdf', () => { - beforeEach(() => { - component.listItems = [LINK_FIXTURES.dataPdf] - fixture.detectChanges() - items = de.queryAll(By.css('.format-filter')) - }) - it('show only all and others filters', () => { - const displayedFormats = items.map( - (item) => item.attributes['data-format'] - ) - expect(displayedFormats).toEqual(['all', 'others']) - }) - }) - }) }) diff --git a/libs/ui/elements/src/lib/list/list.component.ts b/libs/ui/elements/src/lib/list/list.component.ts index a69b49cc08..6b7f2e318e 100644 --- a/libs/ui/elements/src/lib/list/list.component.ts +++ b/libs/ui/elements/src/lib/list/list.component.ts @@ -8,13 +8,9 @@ import { ViewChild, } from '@angular/core' import { TranslateService } from '@ngx-translate/core' -import { getBadgeColor, getFileFormat } from '@geonetwork-ui/util/shared' import { DatasetDistribution } from '@geonetwork-ui/common/domain/model/record' import { MatPaginator, PageEvent } from '@angular/material/paginator' -const FILTER_FORMATS = ['all', 'csv', 'excel', 'json', 'shp', 'others'] as const -type FilterFormat = typeof FILTER_FORMATS[number] - @Component({ selector: 'gn-ui-list', templateUrl: './list.component.html', @@ -32,26 +28,13 @@ export class ListComponent implements OnChanges { listLength = 1 listPages = [] - activeFilterFormats: FilterFormat[] = ['all'] - - @Input() previousButtonWidth = 1.4 - @Input() previousButtonHeight = 1.4 - previousButtonStyle = '' - - @Input() nextButtonWidth = 1.4 - @Input() nextButtonHeight = 1.4 - nextButtonStyle = '' - isFirstPage = true isLastPage = false constructor( private readonly translateService: TranslateService, private readonly changeDetector: ChangeDetectorRef - ) { - this.previousButtonStyle = `width: ${this.previousButtonWidth}rem; height: ${this.previousButtonHeight}rem;` - this.nextButtonStyle = `width: ${this.nextButtonWidth}rem; height: ${this.nextButtonHeight}rem;` - } + ) {} ngOnChanges(changes: SimpleChanges): void { const listItems = changes['listItems'] @@ -116,85 +99,10 @@ export class ListComponent implements OnChanges { this.isLastPage = this.currentPage === this.listPages.length - 1 } - // TODO <--------------------------------------------------------------------- TODO: - get filteredListItems(): DatasetDistribution[] { const startIndex = this.currentPage * this.listPageSize const endIndex = startIndex + this.listPageSize - return this.listItems - .filter((link) => - this.activeFilterFormats.some((format) => - this.isLinkOfFormat(link, format) - ) - ) - .slice(startIndex, endIndex) - } - - get visibleFormats(): FilterFormat[] { - return FILTER_FORMATS.filter((format) => - this.listItems.some((link) => this.isLinkOfFormat(link, format)) - ) - } - - toggleFilterFormat(format: FilterFormat): void { - if (format === 'all') { - this.activeFilterFormats = ['all'] - return - } - if (this.isFilterActive(format)) { - this.activeFilterFormats = this.activeFilterFormats.filter( - (f: string) => format !== f - ) - } else { - this.activeFilterFormats = [ - ...this.activeFilterFormats.filter((f) => f !== 'all'), - format, - ] - } - if (this.activeFilterFormats.length === 0) { - this.activeFilterFormats = ['all'] - } - } - - isFilterActive(filter: FilterFormat): boolean { - return this.activeFilterFormats.includes(filter) - } - - getFilterFormatTitle(format: FilterFormat) { - if (format === 'all' || format === 'others') { - return this.translateService.instant(`datahub.search.filter.${format}`) - } - return format - } - - isLinkOfFormat(link: DatasetDistribution, format: FilterFormat): boolean { - if (format === 'all') { - return true - } - if (getFileFormat(link) === null) { - return format === 'others' - } - if (format === 'others') { - const knownFormats = FILTER_FORMATS.filter( - (format) => format !== 'all' && format !== 'others' - ) - return knownFormats.every( - (knownFormat) => !getFileFormat(link).includes(knownFormat) - ) - } - return getFileFormat(link).includes(format) - } - - getLinkFormat(link: DatasetDistribution) { - return getFileFormat(link) - } - - getLinkColor(link: DatasetDistribution) { - return getBadgeColor(getFileFormat(link)) - } - - isFromWfs(link: DatasetDistribution) { - return link.type === 'service' && link.accessServiceProtocol === 'wfs' + return this.listItems.slice(startIndex, endIndex) } } diff --git a/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.css b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.html b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.html new file mode 100644 index 0000000000..9203615ca4 --- /dev/null +++ b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.html @@ -0,0 +1,34 @@ +
+ + + arrow_back + + + + + arrow_forward + + +
diff --git a/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.spec.ts b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.spec.ts new file mode 100644 index 0000000000..4722325bc7 --- /dev/null +++ b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.spec.ts @@ -0,0 +1,73 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing' +import { MatIconModule } from '@angular/material/icon' + +import { PreviousNextButtonsComponent } from './previous-next-buttons.component' +import { TranslateModule } from '@ngx-translate/core' +import { By } from '@angular/platform-browser' +import { DebugElement } from '@angular/core' + +describe('PreviousNextButtonsComponent', () => { + let component: PreviousNextButtonsComponent + let fixture: ComponentFixture + let compiled: DebugElement + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + MatIconModule, + PreviousNextButtonsComponent, + TranslateModule.forRoot(), + ], + }).compileComponents() + }) + + beforeEach(() => { + fixture = TestBed.createComponent(PreviousNextButtonsComponent) + component = fixture.componentInstance + compiled = fixture.debugElement + }) + + it('should create', () => { + expect(component).toBeTruthy() + }) + + describe('onFirstElement', () => { + beforeEach(() => { + component.isFirst = true + component.isLast = false + fixture.detectChanges() + }) + + it('previous button should be disabled', () => { + const previousButton = compiled.query( + By.css('[data-test="previousButton"]') + ) + expect(previousButton.attributes['ng-reflect-disabled']).toEqual('true') + }) + + it("next button shouldn't be disabled", () => { + const nextButton = compiled.query(By.css('[data-test="nextButton"]')) + expect(nextButton.attributes['ng-reflect-disabled']).toEqual('false') + }) + }) + + describe('onLastElement', () => { + beforeEach(() => { + component.isFirst = false + component.isLast = true + fixture.detectChanges() + }) + + it('previous button should be disabled', () => { + const previousButton = compiled.query( + By.css('[data-test="previousButton"]') + ) + expect(previousButton.attributes['ng-reflect-disabled']).toEqual('false') + }) + + it("next button shouldn't be disabled", () => { + const nextButton = compiled.query(By.css('[data-test="nextButton"]')) + expect(nextButton.attributes['ng-reflect-disabled']).toEqual('true') + }) + }) +}) diff --git a/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.stories.ts b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.stories.ts new file mode 100644 index 0000000000..efc14c7116 --- /dev/null +++ b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.stories.ts @@ -0,0 +1,39 @@ +import { Meta, moduleMetadata, StoryObj } from '@storybook/angular' +import { PreviousNextButtonsComponent } from './previous-next-buttons.component' +import { TranslateModule } from '@ngx-translate/core' +import { MatIconModule } from '@angular/material/icon' +import { + TRANSLATE_DEFAULT_CONFIG, + UtilI18nModule, +} from '@geonetwork-ui/util/i18n' + +export default { + title: 'Inputs/PreviousNextButtonsComponent', + component: PreviousNextButtonsComponent, + parameters: { + backgrounds: { + default: 'dark', + }, + }, + decorators: [ + moduleMetadata({ + imports: [ + UtilI18nModule, + TranslateModule.forRoot(TRANSLATE_DEFAULT_CONFIG), + MatIconModule, + ], + }), + ], +} as Meta + +export const Primary: StoryObj = { + args: { + isFirst: true, + isLast: false, + }, + render: (args) => ({ + props: args, + template: + '', + }), +} diff --git a/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.ts b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.ts new file mode 100644 index 0000000000..3546968262 --- /dev/null +++ b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.ts @@ -0,0 +1,32 @@ +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + Output, +} from '@angular/core' +import { ButtonComponent } from '../button/button.component' +import { MatIconModule } from '@angular/material/icon' + +@Component({ + selector: 'gn-ui-previous-next-buttons', + templateUrl: './previous-next-buttons.component.html', + styleUrls: ['./previous-next-buttons.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [ButtonComponent, MatIconModule], +}) +export class PreviousNextButtonsComponent { + @Input() isFirst: boolean + @Input() isLast: boolean + + @Output() directionButtonClicked: EventEmitter = new EventEmitter() + + previousButtonClicked() { + this.directionButtonClicked.next('previous') + } + + nextButtonClicked() { + this.directionButtonClicked.next('next') + } +} diff --git a/libs/ui/inputs/src/lib/ui-inputs.module.ts b/libs/ui/inputs/src/lib/ui-inputs.module.ts index f96f975288..caa3cf44a9 100644 --- a/libs/ui/inputs/src/lib/ui-inputs.module.ts +++ b/libs/ui/inputs/src/lib/ui-inputs.module.ts @@ -33,6 +33,7 @@ import { MatDatepickerModule } from '@angular/material/datepicker' import { MatNativeDateModule } from '@angular/material/core' import { EditableLabelDirective } from './editable-label/editable-label.directive' import { ImageInputComponent } from './image-input/image-input.component' +import { PreviousNextButtonsComponent } from './previous-next-buttons/previous-next-buttons.component' @NgModule({ declarations: [ @@ -73,6 +74,7 @@ import { ImageInputComponent } from './image-input/image-input.component' ImageInputComponent, DropdownSelectorComponent, DateRangePickerComponent, + PreviousNextButtonsComponent, ], exports: [ DropdownSelectorComponent, @@ -93,6 +95,7 @@ import { ImageInputComponent } from './image-input/image-input.component' DateRangePickerComponent, EditableLabelDirective, ImageInputComponent, + PreviousNextButtonsComponent, ], }) export class UiInputsModule {} diff --git a/libs/ui/layout/src/lib/carousel/carousel.component.html b/libs/ui/layout/src/lib/carousel/carousel.component.html index da0fca219f..1252c9de0c 100644 --- a/libs/ui/layout/src/lib/carousel/carousel.component.html +++ b/libs/ui/layout/src/lib/carousel/carousel.component.html @@ -1,36 +1,4 @@
-
-
- {{ title }} -
-
- - arrow_back - - - arrow_forward - -
-
-
+
+
+
+ +
diff --git a/libs/ui/layout/src/lib/carousel/carousel.component.spec.ts b/libs/ui/layout/src/lib/carousel/carousel.component.spec.ts index a78239fd6c..7301cb0d1a 100644 --- a/libs/ui/layout/src/lib/carousel/carousel.component.spec.ts +++ b/libs/ui/layout/src/lib/carousel/carousel.component.spec.ts @@ -34,7 +34,7 @@ jest.mock('embla-carousel', () => { }) @Component({ - template: ` + template: `
`, }) @@ -49,7 +49,8 @@ describe('CarouselComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [CarouselWrapperComponent, CarouselComponent], + declarations: [CarouselWrapperComponent], + imports: [CarouselComponent], }).compileComponents() fixture = TestBed.createComponent(CarouselWrapperComponent) component = fixture.debugElement.query( @@ -82,4 +83,35 @@ describe('CarouselComponent', () => { }) }) }) + + describe('currentStepChange', () => { + it('emits the current step index', () => { + const spy = jest.fn() + component.currentStepChange.subscribe(spy) + component.scrollToStep(2) + expect(spy).toHaveBeenCalledWith(2) + expect(spy).toHaveBeenCalledTimes(1) + }) + }) + + describe('isFirstStep', () => { + it('returns true if the current step is the first one', () => { + expect(component.isFirstStep).toBe(true) + }) + it('returns false if the current step is not the first one', () => { + component.scrollToStep(2) + expect(component.isFirstStep).toBe(false) + }) + }) + + describe('isLastStep', () => { + it('returns true if the current step is the last one', () => { + component.scrollToStep(3) + expect(component.isLastStep).toBe(true) + }) + it('returns false if the current step is not the last one', () => { + component.scrollToStep(1) + expect(component.isLastStep).toBe(false) + }) + }) }) diff --git a/libs/ui/layout/src/lib/carousel/carousel.component.stories.ts b/libs/ui/layout/src/lib/carousel/carousel.component.stories.ts index d777c901e8..c24a9d5a04 100644 --- a/libs/ui/layout/src/lib/carousel/carousel.component.stories.ts +++ b/libs/ui/layout/src/lib/carousel/carousel.component.stories.ts @@ -8,7 +8,8 @@ const meta: Meta = { decorators: [ componentWrapperDecorator( (story) => - `
${story}
` + `

Please note that the carousel will overflow by default; to hide its items, make its container overflow-hidden!

+
${story}
` ), ], } @@ -20,15 +21,15 @@ export const Primary: Story = { render: (args) => ({ props: args, template: ` - +
First box
Second box
-
- Third box +
+ Third box (resize me!)
Fourth box diff --git a/libs/ui/layout/src/lib/carousel/carousel.component.ts b/libs/ui/layout/src/lib/carousel/carousel.component.ts index 85c292f02b..abb751af2a 100644 --- a/libs/ui/layout/src/lib/carousel/carousel.component.ts +++ b/libs/ui/layout/src/lib/carousel/carousel.component.ts @@ -10,37 +10,44 @@ import { ViewChild, } from '@angular/core' import EmblaCarousel, { EmblaCarouselType } from 'embla-carousel' +import { CommonModule } from '@angular/common' @Component({ selector: 'gn-ui-carousel', templateUrl: './carousel.component.html', styleUrls: ['./carousel.component.css'], changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [CommonModule], }) export class CarouselComponent implements AfterViewInit { @ViewChild('carouselOverflowContainer') carouselOverflowContainer: ElementRef @Input() containerClass = '' - @Input() stepsContainerClass = '' + @Input() stepsContainerClass = 'w-full bottom-0 top-auto' + @Output() currentStepChange = new EventEmitter() - @Output() stepsChanged = new EventEmitter() + protected steps: number[] = [] + protected emblaApi: EmblaCarouselType + protected currentStep = 0 - steps: number[] = [] - currentStep = 0 - emblaApi: EmblaCarouselType - - isFirstStep = true - isLastStep = false - - refreshSteps = () => { + protected refreshSteps = () => { this.steps = this.emblaApi.scrollSnapList() this.currentStep = this.emblaApi.selectedScrollSnap() - this.isFirstStep = this.currentStep === 0 - this.isLastStep = this.currentStep === this.steps.length - 1 - this.stepsChanged.emit(this.steps.length) + this.currentStepChange.emit(this.currentStep) this.changeDetector.detectChanges() } + get isFirstStep() { + return this.currentStep === 0 + } + get isLastStep() { + return this.currentStep === this.steps.length - 1 + } + get stepsCount() { + return this.steps.length + } + constructor(private changeDetector: ChangeDetectorRef) {} ngAfterViewInit() { @@ -57,21 +64,15 @@ export class CarouselComponent implements AfterViewInit { .on('select', this.refreshSteps) } - scrollToStep(stepIndex: number) { + public scrollToStep(stepIndex: number) { this.emblaApi.scrollTo(stepIndex) } - /** - * Click on previous arrow - */ public slideToPrevious() { if (this.isFirstStep) return this.emblaApi.scrollPrev() } - /** - * Click on next arrow - */ public slideToNext() { if (this.isLastStep) return this.emblaApi.scrollNext() diff --git a/libs/ui/layout/src/lib/ui-layout.module.ts b/libs/ui/layout/src/lib/ui-layout.module.ts index 69a28b9c8b..5d22fc9ce9 100644 --- a/libs/ui/layout/src/lib/ui-layout.module.ts +++ b/libs/ui/layout/src/lib/ui-layout.module.ts @@ -15,14 +15,12 @@ import { CarouselComponent } from './carousel/carousel.component' StickyHeaderComponent, AnchorLinkDirective, ExpandablePanelButtonComponent, - CarouselComponent, ], exports: [ ExpandablePanelComponent, StickyHeaderComponent, AnchorLinkDirective, ExpandablePanelButtonComponent, - CarouselComponent, ], }) export class UiLayoutModule {} From ae87f68e254d840ce5261fd9c17490aec64db3ec Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Wed, 8 May 2024 11:39:48 +0200 Subject: [PATCH 06/15] feat(ui): add block-list component This component offers simple pagination on a list of blocks --- apps/datahub/src/app/app.module.ts | 7 +- libs/ui/layout/src/index.ts | 1 + .../lib/block-list/block-list.component.css | 23 +++ .../lib/block-list/block-list.component.html | 15 ++ .../block-list/block-list.component.spec.ts | 150 ++++++++++++++++++ .../block-list.component.stories.ts | 44 +++++ .../lib/block-list/block-list.component.ts | 76 +++++++++ 7 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 libs/ui/layout/src/lib/block-list/block-list.component.css create mode 100644 libs/ui/layout/src/lib/block-list/block-list.component.html create mode 100644 libs/ui/layout/src/lib/block-list/block-list.component.spec.ts create mode 100644 libs/ui/layout/src/lib/block-list/block-list.component.stories.ts create mode 100644 libs/ui/layout/src/lib/block-list/block-list.component.ts diff --git a/apps/datahub/src/app/app.module.ts b/apps/datahub/src/app/app.module.ts index 4905fc5500..2baf778115 100644 --- a/apps/datahub/src/app/app.module.ts +++ b/apps/datahub/src/app/app.module.ts @@ -30,7 +30,11 @@ import { UiElementsModule, } from '@geonetwork-ui/ui/elements' import { UiInputsModule } from '@geonetwork-ui/ui/inputs' -import { CarouselComponent, UiLayoutModule } from '@geonetwork-ui/ui/layout' +import { + BlockListComponent, + CarouselComponent, + UiLayoutModule, +} from '@geonetwork-ui/ui/layout' import { UiSearchModule } from '@geonetwork-ui/ui/search' import { getGlobalConfig, @@ -153,6 +157,7 @@ export const metaReducers: MetaReducer[] = !environment.production ? [] : [] UiWidgetsModule, LinkCardComponent, CarouselComponent, + BlockListComponent, ], providers: [ importProvidersFrom(FeatureAuthModule), diff --git a/libs/ui/layout/src/index.ts b/libs/ui/layout/src/index.ts index 9dbf8aec71..358c081b9f 100644 --- a/libs/ui/layout/src/index.ts +++ b/libs/ui/layout/src/index.ts @@ -6,4 +6,5 @@ export * from './lib/form-field-wrapper/form-field-wrapper.component' export * from './lib/interactive-table/interactive-table-column/interactive-table-column.component' export * from './lib/interactive-table/interactive-table.component' export * from './lib/sticky-header/sticky-header.component' +export * from './lib/block-list/block-list.component' export * from './lib/ui-layout.module' diff --git a/libs/ui/layout/src/lib/block-list/block-list.component.css b/libs/ui/layout/src/lib/block-list/block-list.component.css new file mode 100644 index 0000000000..0d37f18585 --- /dev/null +++ b/libs/ui/layout/src/lib/block-list/block-list.component.css @@ -0,0 +1,23 @@ +:host .block-list-container ::ng-deep > * { + flex-shrink: 0; +} + +:host { + position: relative; +} + +.list-page-dot { + width: 6px; + height: 6px; + border-radius: 6px; + position: relative; +} + +.list-page-dot:after { + content: ''; + position: absolute; + left: -7px; + top: -7px; + width: 20px; + height: 20px; +} diff --git a/libs/ui/layout/src/lib/block-list/block-list.component.html b/libs/ui/layout/src/lib/block-list/block-list.component.html new file mode 100644 index 0000000000..56223f920f --- /dev/null +++ b/libs/ui/layout/src/lib/block-list/block-list.component.html @@ -0,0 +1,15 @@ +
+ +
+
+ +
diff --git a/libs/ui/layout/src/lib/block-list/block-list.component.spec.ts b/libs/ui/layout/src/lib/block-list/block-list.component.spec.ts new file mode 100644 index 0000000000..f03b68c977 --- /dev/null +++ b/libs/ui/layout/src/lib/block-list/block-list.component.spec.ts @@ -0,0 +1,150 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing' +import { BlockListComponent } from './block-list.component' +import { Component, Input } from '@angular/core' +import { By } from '@angular/platform-browser' + +@Component({ + template: ` +
+
`, +}) +class BlockListWrapperComponent { + @Input() blocks = [1, 2, 3, 4, 5, 6, 7] +} + +describe('BlockListComponent', () => { + let component: BlockListComponent + let fixture: ComponentFixture + let blockEls: HTMLElement[] + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [BlockListWrapperComponent], + imports: [BlockListComponent], + }).compileComponents() + fixture = TestBed.createComponent(BlockListWrapperComponent) + component = fixture.debugElement.query( + By.directive(BlockListComponent) + ).componentInstance + fixture.detectChanges() + blockEls = fixture.debugElement + .queryAll(By.css('.block')) + .map((el) => el.nativeElement) + }) + + it('should create', () => { + expect(component).toBeTruthy() + }) + + describe('pages computation', () => { + it('shows 5 items per page initially', () => { + const blocksVisibility = blockEls.map((el) => el.style.display !== 'none') + expect(blocksVisibility).toEqual([ + true, + true, + true, + true, + true, + false, + false, + ]) + }) + describe('click on step', () => { + beforeEach(() => { + component.goToPage(1) + }) + it('updates visibility', () => { + const blocksVisibility = blockEls.map( + (el) => el.style.display !== 'none' + ) + expect(blocksVisibility).toEqual([ + false, + false, + false, + false, + false, + true, + true, + ]) + }) + it('emits the selected page', () => { + expect(component['currentPage']).toEqual(1) + }) + }) + describe('custom page size', () => { + beforeEach(() => { + component.pageSize = 3 + component.goToPage(3) + fixture.detectChanges() + }) + it('updates visibility', () => { + const blocksVisibility = blockEls.map( + (el) => el.style.display !== 'none' + ) + expect(blocksVisibility).toEqual([ + false, + false, + false, + false, + false, + false, + true, + ]) + }) + }) + }) + + describe('previousPage', () => { + beforeEach(() => { + component.pageSize = 2 + component.goToPage(2) + component.previousPage() + }) + it('changes to previous page', () => { + expect(component['currentPage']).toEqual(1) + }) + }) + + describe('nextPage', () => { + beforeEach(() => { + component.pageSize = 2 + component.goToPage(1) + component.nextPage() + }) + it('changes to next page', () => { + expect(component['currentPage']).toEqual(2) + }) + }) + + describe('isFirstPage', () => { + beforeEach(() => { + component.pageSize = 3 + }) + it('returns true if the current page is the first one', () => { + expect(component.isFirstPage).toBe(true) + }) + it('returns false if the current page is not the first one', () => { + component.goToPage(1) + expect(component.isFirstPage).toBe(false) + }) + }) + + describe('isLastPage', () => { + beforeEach(() => { + component.pageSize = 3 + }) + it('returns true if the current page is the last one', () => { + component.goToPage(2) + expect(component.isLastPage).toBe(true) + }) + it('returns false if the current page is not the last one', () => { + component.goToPage(1) + expect(component.isLastPage).toBe(false) + }) + }) +}) diff --git a/libs/ui/layout/src/lib/block-list/block-list.component.stories.ts b/libs/ui/layout/src/lib/block-list/block-list.component.stories.ts new file mode 100644 index 0000000000..31f06fdd74 --- /dev/null +++ b/libs/ui/layout/src/lib/block-list/block-list.component.stories.ts @@ -0,0 +1,44 @@ +import type { Meta, StoryObj } from '@storybook/angular' +import { BlockListComponent } from './block-list.component' +import { componentWrapperDecorator } from '@storybook/angular' + +const meta: Meta = { + component: BlockListComponent, + title: 'Layout/BlockListComponent', + decorators: [ + componentWrapperDecorator( + (story) => + `
${story}
` + ), + ], +} +export default meta +type Story = StoryObj< + BlockListComponent & { + blockCount: number + } +> + +export const Primary: Story = { + args: { + pageSize: 5, + blockCount: 17, + }, + render: (args) => ({ + props: { + ...args, + blockList: new Array(args.blockCount).fill(0).map((_, i) => i + 1), + }, + template: ` + +
+ Box {{ block }} +
+
+`, + }), +} diff --git a/libs/ui/layout/src/lib/block-list/block-list.component.ts b/libs/ui/layout/src/lib/block-list/block-list.component.ts new file mode 100644 index 0000000000..a20ae957f0 --- /dev/null +++ b/libs/ui/layout/src/lib/block-list/block-list.component.ts @@ -0,0 +1,76 @@ +import { + AfterContentInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ContentChildren, + ElementRef, + Input, + QueryList, +} from '@angular/core' +import { CommonModule } from '@angular/common' + +@Component({ + selector: 'gn-ui-block-list', + templateUrl: './block-list.component.html', + styleUrls: ['./block-list.component.css'], + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [CommonModule], +}) +export class BlockListComponent implements AfterContentInit { + @Input() pageSize = 5 + @Input() containerClass = '' + @Input() paginationContainerClass = 'w-full bottom-0 top-auto' + @ContentChildren('block', { read: ElementRef }) blocks: QueryList< + ElementRef + > + + protected currentPage = 0 + protected get pages() { + return new Array(this.pagesCount).fill(0).map((_, i) => i) + } + + get isFirstPage() { + return this.currentPage === 0 + } + get isLastPage() { + return this.currentPage === this.pagesCount - 1 + } + get pagesCount() { + return this.blocks ? Math.ceil(this.blocks.length / this.pageSize) : 1 + } + + constructor(private changeDetector: ChangeDetectorRef) {} + + ngAfterContentInit() { + this.blocks.changes.subscribe(this.refreshBlocksVisibility) + this.refreshBlocksVisibility() + } + + protected refreshBlocksVisibility = () => { + this.blocks.forEach((block, index) => { + block.nativeElement.style.display = + index >= this.currentPage * this.pageSize && + index < (this.currentPage + 1) * this.pageSize + ? null + : 'none' + }) + } + + public goToPage(index: number) { + this.currentPage = Math.max(Math.min(index, this.pagesCount - 1), 0) + this.changeDetector.detectChanges() + this.refreshBlocksVisibility() + } + + public previousPage() { + if (this.isFirstPage) return + this.goToPage(this.currentPage - 1) + } + + public nextPage() { + if (this.isLastPage) return + this.goToPage(this.currentPage + 1) + } +} From 5b0dee878e73750e951be1afdac2f356fbb4c5eb Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Wed, 8 May 2024 23:56:23 +0200 Subject: [PATCH 07/15] feat(dh): adapt to work with ui components --- .../record-apis/record-apis.component.html | 10 ++--- .../record-apis/record-apis.component.ts | 18 +++++---- .../record-otherlinks.component.html | 26 ++++++------- .../record-otherlinks.component.ts | 37 +++++++++++++++---- 4 files changed, 55 insertions(+), 36 deletions(-) diff --git a/apps/datahub/src/app/record/record-apis/record-apis.component.html b/apps/datahub/src/app/record/record-apis/record-apis.component.html index 83ecac8a4b..61cec4c40e 100644 --- a/apps/datahub/src/app/record/record-apis/record-apis.component.html +++ b/apps/datahub/src/app/record/record-apis/record-apis.component.html @@ -6,23 +6,19 @@ record.metadata.api

- + 3" + *ngIf="hasPagination" [isFirst]="isFirstStepOrPage" [isLast]="isLastStepOrPage" (directionButtonClicked)="changeStepOrPage($event)" >
- - - + + + + - + > diff --git a/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.ts b/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.ts index 01f5a8b613..97a39cf5a8 100644 --- a/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.ts +++ b/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.ts @@ -1,7 +1,12 @@ -import { Component, ChangeDetectionStrategy, ViewChild } from '@angular/core' +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ViewChild, +} from '@angular/core' import { MdViewFacade } from '@geonetwork-ui/feature/record' -import { CarouselComponent } from '@geonetwork-ui/ui/layout' -import { ListComponent } from '@geonetwork-ui/ui/elements' +import { BlockListComponent, CarouselComponent } from '@geonetwork-ui/ui/layout' @Component({ selector: 'datahub-record-otherlinks', @@ -9,13 +14,16 @@ import { ListComponent } from '@geonetwork-ui/ui/elements' styleUrls: ['./record-otherlinks.component.css'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class RecordOtherlinksComponent { +export class RecordOtherlinksComponent implements AfterViewInit { otherLinks$ = this.facade.otherLinks$ @ViewChild(CarouselComponent) carousel: CarouselComponent - @ViewChild(ListComponent) list: ListComponent + @ViewChild(BlockListComponent) list: BlockListComponent - constructor(public facade: MdViewFacade) {} + constructor( + public facade: MdViewFacade, + private changeDetector: ChangeDetectorRef + ) {} get isFirstStepOrPage() { return this.carousel?.isFirstStep ?? this.list?.isFirstPage ?? true @@ -25,13 +33,26 @@ export class RecordOtherlinksComponent { return this.carousel?.isLastStep ?? this.list?.isLastPage ?? false } + get hasPagination() { + return (this.carousel?.stepsCount || this.list?.pagesCount) > 1 + } + changeStepOrPage(direction: string) { if (direction === 'next') { - this.list?.goToNextPage() + this.list?.nextPage() this.carousel?.slideToNext() } else { this.carousel?.slideToPrevious() - this.list?.goToPreviousPage() + this.list?.previousPage() } } + + updateView() { + this.changeDetector.detectChanges() + } + + ngAfterViewInit() { + // this is required to show the pagination correctly + this.changeDetector.detectChanges() + } } From b3c908b31fa8ef3607e062f25f0729b9c20e5fec Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Thu, 9 May 2024 00:07:36 +0200 Subject: [PATCH 08/15] chore: remove unused list & list-item components --- libs/ui/elements/src/index.ts | 2 - .../src/lib/list-item/list-item.component.css | 0 .../lib/list-item/list-item.component.html | 18 --- .../lib/list-item/list-item.component.spec.ts | 42 ------- .../list-item/list-item.component.stories.ts | 45 -------- .../src/lib/list-item/list-item.component.ts | 21 ---- .../elements/src/lib/list/list.component.css | 32 ------ .../elements/src/lib/list/list.component.html | 27 ----- .../src/lib/list/list.component.spec.ts | 54 --------- .../elements/src/lib/list/list.component.ts | 108 ------------------ .../ui/elements/src/lib/ui-elements.module.ts | 6 - 11 files changed, 355 deletions(-) delete mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.css delete mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.html delete mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.spec.ts delete mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.stories.ts delete mode 100644 libs/ui/elements/src/lib/list-item/list-item.component.ts delete mode 100644 libs/ui/elements/src/lib/list/list.component.css delete mode 100644 libs/ui/elements/src/lib/list/list.component.html delete mode 100644 libs/ui/elements/src/lib/list/list.component.spec.ts delete mode 100644 libs/ui/elements/src/lib/list/list.component.ts diff --git a/libs/ui/elements/src/index.ts b/libs/ui/elements/src/index.ts index 2fa6c1da53..f48507d17b 100644 --- a/libs/ui/elements/src/index.ts +++ b/libs/ui/elements/src/index.ts @@ -3,8 +3,6 @@ export * from './lib/avatar/avatar.component' export * from './lib/content-ghost/content-ghost.component' export * from './lib/download-item/download-item.component' export * from './lib/downloads-list/downloads-list.component' -export * from './lib/list/list.component' -export * from './lib/list-item/list-item.component' export * from './lib/image-overlay-preview/image-overlay-preview.component' export * from './lib/link-card/link-card.component' export * from './lib/markdown-editor/markdown-editor.component' diff --git a/libs/ui/elements/src/lib/list-item/list-item.component.css b/libs/ui/elements/src/lib/list-item/list-item.component.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/ui/elements/src/lib/list-item/list-item.component.html b/libs/ui/elements/src/lib/list-item/list-item.component.html deleted file mode 100644 index 500bfe3fc4..0000000000 --- a/libs/ui/elements/src/lib/list-item/list-item.component.html +++ /dev/null @@ -1,18 +0,0 @@ - -
-
- {{ link.description || link.name }} -
-
-
- open_in_new -
-
diff --git a/libs/ui/elements/src/lib/list-item/list-item.component.spec.ts b/libs/ui/elements/src/lib/list-item/list-item.component.spec.ts deleted file mode 100644 index 0c528e3003..0000000000 --- a/libs/ui/elements/src/lib/list-item/list-item.component.spec.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' -import { MatIconModule } from '@angular/material/icon' -import { TranslateModule } from '@ngx-translate/core' -import { ListItemComponent } from './list-item.component' -import { ChangeDetectionStrategy } from '@angular/core' - -describe('ListItemComponent', () => { - let component: ListItemComponent - let fixture: ComponentFixture - - beforeEach(async () => { - await TestBed.configureTestingModule({ - declarations: [ListItemComponent], - imports: [MatIconModule, TranslateModule.forRoot()], - }) - .overrideComponent(ListItemComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default }, - }) - .compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(ListItemComponent) - component = fixture.componentInstance - component.link = { - name: 'allroads.geojson', - description: 'A file that contains all roads', - url: new URL('https://roads.com/allroads.geojson'), - type: 'download', - } - component.format = 'geojson' - component.color = 'red' - - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) - - describe('download description', () => {}) -}) diff --git a/libs/ui/elements/src/lib/list-item/list-item.component.stories.ts b/libs/ui/elements/src/lib/list-item/list-item.component.stories.ts deleted file mode 100644 index 8fab74d0cb..0000000000 --- a/libs/ui/elements/src/lib/list-item/list-item.component.stories.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - applicationConfig, - componentWrapperDecorator, - Meta, - moduleMetadata, - StoryObj, -} from '@storybook/angular' -import { ListItemComponent } from './list-item.component' -import { BrowserAnimationsModule } from '@angular/platform-browser/animations' -import { TranslateModule } from '@ngx-translate/core' -import { importProvidersFrom } from '@angular/core' -import { MatIcon } from '@angular/material/icon' - -export default { - title: 'Elements/ListItemComponent', - component: ListItemComponent, - decorators: [ - moduleMetadata({ - declarations: [MatIcon], - imports: [TranslateModule.forRoot()], - }), - applicationConfig({ - providers: [importProvidersFrom(BrowserAnimationsModule)], - }), - componentWrapperDecorator( - (story) => `
${story}
` - ), - ], -} as Meta - -export const Primary: StoryObj = { - args: { - link: { - name: 'allroads.geojson', - type: 'download', - description: 'A file that contains all roads', - url: new URL('https://roads.com/allroads.geojson'), - }, - }, - argTypes: { - exportUrl: { - action: 'exportUrl', - }, - }, -} diff --git a/libs/ui/elements/src/lib/list-item/list-item.component.ts b/libs/ui/elements/src/lib/list-item/list-item.component.ts deleted file mode 100644 index df8809136c..0000000000 --- a/libs/ui/elements/src/lib/list-item/list-item.component.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { - Component, - ChangeDetectionStrategy, - Input, - Output, - EventEmitter, -} from '@angular/core' - -@Component({ - selector: 'gn-ui-list-item', - templateUrl: './list-item.component.html', - styleUrls: ['./list-item.component.css'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ListItemComponent { - @Input() link: any - @Input() color: string - @Input() format: string - @Input() isFromWfs: boolean - @Output() exportUrl = new EventEmitter() -} diff --git a/libs/ui/elements/src/lib/list/list.component.css b/libs/ui/elements/src/lib/list/list.component.css deleted file mode 100644 index 2a9121aa44..0000000000 --- a/libs/ui/elements/src/lib/list/list.component.css +++ /dev/null @@ -1,32 +0,0 @@ -:host ::ng-deep .mat-mdc-paginator-range-label { - display: none; -} -:host ::ng-deep .mat-mdc-paginator-navigation-previous, -:host ::ng-deep .mat-mdc-paginator-navigation-next { - display: none; -} - -:host ::ng-deep .mat-mdc-paginator-container { - width: 0; - padding: 0; -} - -.carousel-step-dot { - width: 6px; - height: 6px; - border-radius: 6px; - position: relative; -} - -.carousel-step-dot:after { - content: ''; - position: absolute; - left: -4px; - top: -4px; - width: 14px; - height: 14px; -} - -.previous-page-button { - width: 50px; -} diff --git a/libs/ui/elements/src/lib/list/list.component.html b/libs/ui/elements/src/lib/list/list.component.html deleted file mode 100644 index 12335170c2..0000000000 --- a/libs/ui/elements/src/lib/list/list.component.html +++ /dev/null @@ -1,27 +0,0 @@ -
-
-
- -
-
- -
-
-
- - - > diff --git a/libs/ui/elements/src/lib/list/list.component.spec.ts b/libs/ui/elements/src/lib/list/list.component.spec.ts deleted file mode 100644 index b970fa24a8..0000000000 --- a/libs/ui/elements/src/lib/list/list.component.spec.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { - ChangeDetectionStrategy, - Component, - DebugElement, - Input, - NO_ERRORS_SCHEMA, -} from '@angular/core' -import { ComponentFixture, TestBed } from '@angular/core/testing' -import { LinkClassifierService } from '@geonetwork-ui/util/shared' -import { TranslateModule } from '@ngx-translate/core' -import { ListComponent } from './list.component' -import { DatasetDistribution } from '@geonetwork-ui/common/domain/model/record' - -@Component({ - selector: 'gn-ui-download-item', - template: ``, -}) -class MockDownloadItemComponent { - @Input() link: DatasetDistribution - @Input() color: string - @Input() format: string - @Input() isFromWfs: boolean -} - -describe('ListComponent', () => { - let component: ListComponent - let fixture: ComponentFixture - let de: DebugElement - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot()], - declarations: [ListComponent, MockDownloadItemComponent], - schemas: [NO_ERRORS_SCHEMA], - providers: [LinkClassifierService], - }) - .overrideComponent(ListComponent, { - set: { changeDetection: ChangeDetectionStrategy.Default }, - }) - .compileComponents() - }) - - beforeEach(() => { - fixture = TestBed.createComponent(ListComponent) - component = fixture.componentInstance - component.listItems = [] - de = fixture.debugElement - }) - - it('should create', () => { - fixture.detectChanges() - expect(component).toBeTruthy() - }) -}) diff --git a/libs/ui/elements/src/lib/list/list.component.ts b/libs/ui/elements/src/lib/list/list.component.ts deleted file mode 100644 index 6b7f2e318e..0000000000 --- a/libs/ui/elements/src/lib/list/list.component.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - Input, - OnChanges, - SimpleChanges, - ViewChild, -} from '@angular/core' -import { TranslateService } from '@ngx-translate/core' -import { DatasetDistribution } from '@geonetwork-ui/common/domain/model/record' -import { MatPaginator, PageEvent } from '@angular/material/paginator' - -@Component({ - selector: 'gn-ui-list', - templateUrl: './list.component.html', - styleUrls: ['./list.component.css'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class ListComponent implements OnChanges { - @ViewChild('matPaginator') matPaginator: MatPaginator - - @Input() listItems: any[] - @Input() title = '' - @Input() listPageSize = 1 - - currentPage = 0 - listLength = 1 - listPages = [] - - isFirstPage = true - isLastPage = false - - constructor( - private readonly translateService: TranslateService, - private readonly changeDetector: ChangeDetectorRef - ) {} - - ngOnChanges(changes: SimpleChanges): void { - const listItems = changes['listItems'] - const listItemsValue = listItems.currentValue as any[] - const listHasChanged = listItems.currentValue !== listItems.previousValue - - if (listHasChanged) { - this.listLength = listItemsValue.length - const listPages = Math.ceil(listItemsValue.length / this.listPageSize) - - this.listPages = [] - for (let i = 0; i < listPages; i++) { - this.listPages.push(i) - } - } - this.changeDetector.markForCheck() - } - - /** - * Click on previous arrow - */ - goToPreviousPage() { - if (this.isFirstPage) return - this.matPaginator.previousPage() - this.checkListProperties() - this.changeDetector.markForCheck() - } - - /** - * Click on next arrow - */ - goToNextPage() { - if (this.isLastPage) return - this.matPaginator.nextPage() - this.checkListProperties() - this.changeDetector.markForCheck() - } - - /** - * Click on bottom buttons - * @param newIndex - */ - goToPage(newIndex: number) { - this.currentPage = newIndex - this.matPaginator.pageIndex = newIndex - this.checkListProperties() - this.changeDetector.markForCheck() - } - - /** - * Called internaly by goToNextPage() and goToPreviousPage() - * @param event - */ - pageChanged(event: PageEvent) { - this.currentPage = event.pageIndex - this.checkListProperties() - this.changeDetector.markForCheck() - } - - private checkListProperties() { - this.isFirstPage = this.currentPage === 0 - this.isLastPage = this.currentPage === this.listPages.length - 1 - } - - get filteredListItems(): DatasetDistribution[] { - const startIndex = this.currentPage * this.listPageSize - const endIndex = startIndex + this.listPageSize - - return this.listItems.slice(startIndex, endIndex) - } -} diff --git a/libs/ui/elements/src/lib/ui-elements.module.ts b/libs/ui/elements/src/lib/ui-elements.module.ts index 48cd3dcf80..ff83d14455 100644 --- a/libs/ui/elements/src/lib/ui-elements.module.ts +++ b/libs/ui/elements/src/lib/ui-elements.module.ts @@ -33,8 +33,6 @@ import { MarkdownParserComponent } from './markdown-parser/markdown-parser.compo import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-overlay-preview.component' import { UserFeedbackItemComponent } from './user-feedback-item/user-feedback-item.component' import { TimeSincePipe } from './user-feedback-item/time-since.pipe' -import { ListComponent } from './list/list.component' -import { ListItemComponent } from './list-item/list-item.component' import { MatPaginatorModule } from '@angular/material/paginator' @NgModule({ @@ -60,8 +58,6 @@ import { MatPaginatorModule } from '@angular/material/paginator' ContentGhostComponent, DownloadItemComponent, DownloadsListComponent, - ListComponent, - ListItemComponent, ApiCardComponent, RelatedRecordCardComponent, MetadataContactComponent, @@ -84,8 +80,6 @@ import { MatPaginatorModule } from '@angular/material/paginator' ContentGhostComponent, DownloadItemComponent, DownloadsListComponent, - ListComponent, - ListItemComponent, ApiCardComponent, RelatedRecordCardComponent, MetadataContactComponent, From b6e2babc309ddb51b6319c314d1bb10b16dca2ad Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Thu, 9 May 2024 21:45:32 +0200 Subject: [PATCH 09/15] chore: remove unused/redundant code --- libs/feature/record/src/lib/state/mdview.facade.ts | 12 +++--------- libs/ui/elements/src/lib/ui-elements.module.ts | 2 -- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/libs/feature/record/src/lib/state/mdview.facade.ts b/libs/feature/record/src/lib/state/mdview.facade.ts index 2086564c30..37364de54d 100644 --- a/libs/feature/record/src/lib/state/mdview.facade.ts +++ b/libs/feature/record/src/lib/state/mdview.facade.ts @@ -7,11 +7,9 @@ import { LinkClassifierService, LinkUsage } from '@geonetwork-ui/util/shared' import { DatavizConfigurationModel } from '@geonetwork-ui/common/domain/model/dataviz/dataviz-configuration.model' import { CatalogRecord, - DatasetDistribution, UserFeedback, } from '@geonetwork-ui/common/domain/model/record' import { AvatarServiceInterface } from '@geonetwork-ui/api/repository' -import { Observable } from 'rxjs' @Injectable() /** @@ -48,15 +46,11 @@ export class MdViewFacade { error$ = this.store.pipe(select(MdViewSelectors.getMetadataError)) - related$: Observable = this.store.pipe( - select(MdViewSelectors.getRelated) - ) + related$ = this.store.pipe(select(MdViewSelectors.getRelated)) - chartConfig$: Observable = this.store.pipe( - select(MdViewSelectors.getChartConfig) - ) + chartConfig$ = this.store.pipe(select(MdViewSelectors.getChartConfig)) - allLinks$: Observable = this.metadata$.pipe( + allLinks$ = this.metadata$.pipe( map((record) => ('distributions' in record ? record.distributions : [])) ) diff --git a/libs/ui/elements/src/lib/ui-elements.module.ts b/libs/ui/elements/src/lib/ui-elements.module.ts index ff83d14455..58d85ece10 100644 --- a/libs/ui/elements/src/lib/ui-elements.module.ts +++ b/libs/ui/elements/src/lib/ui-elements.module.ts @@ -33,7 +33,6 @@ import { MarkdownParserComponent } from './markdown-parser/markdown-parser.compo import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-overlay-preview.component' import { UserFeedbackItemComponent } from './user-feedback-item/user-feedback-item.component' import { TimeSincePipe } from './user-feedback-item/time-since.pipe' -import { MatPaginatorModule } from '@angular/material/paginator' @NgModule({ imports: [ @@ -51,7 +50,6 @@ import { MatPaginatorModule } from '@angular/material/paginator' MarkdownParserComponent, ThumbnailComponent, TimeSincePipe, - MatPaginatorModule, ], declarations: [ MetadataInfoComponent, From cb71222d65dc357b19142871430b98ea78a9d9c2 Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Thu, 9 May 2024 21:54:48 +0200 Subject: [PATCH 10/15] chore(ui): simplified html of the prev-next-btns component Also do not include it in the ui-inputs module; as a standalone component, it should be imported wherever this is necessary --- apps/datahub/src/app/app.module.ts | 6 +++++- libs/ui/inputs/src/index.ts | 1 + .../previous-next-buttons.component.css | 6 ++++++ .../previous-next-buttons.component.html | 8 -------- libs/ui/inputs/src/lib/ui-inputs.module.ts | 3 --- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/datahub/src/app/app.module.ts b/apps/datahub/src/app/app.module.ts index 2baf778115..e2b035fad1 100644 --- a/apps/datahub/src/app/app.module.ts +++ b/apps/datahub/src/app/app.module.ts @@ -29,7 +29,10 @@ import { THUMBNAIL_PLACEHOLDER, UiElementsModule, } from '@geonetwork-ui/ui/elements' -import { UiInputsModule } from '@geonetwork-ui/ui/inputs' +import { + PreviousNextButtonsComponent, + UiInputsModule, +} from '@geonetwork-ui/ui/inputs' import { BlockListComponent, CarouselComponent, @@ -158,6 +161,7 @@ export const metaReducers: MetaReducer[] = !environment.production ? [] : [] LinkCardComponent, CarouselComponent, BlockListComponent, + PreviousNextButtonsComponent, ], providers: [ importProvidersFrom(FeatureAuthModule), diff --git a/libs/ui/inputs/src/index.ts b/libs/ui/inputs/src/index.ts index 88f97f9216..1baf8d6f45 100644 --- a/libs/ui/inputs/src/index.ts +++ b/libs/ui/inputs/src/index.ts @@ -19,3 +19,4 @@ export * from './lib/text-area/text-area.component' export * from './lib/text-input/text-input.component' export * from './lib/ui-inputs.module' export * from './lib/viewport-intersector/viewport-intersector.component' +export * from './lib/previous-next-buttons/previous-next-buttons.component' diff --git a/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.css b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.css index e69de29bb2..14ad317ff0 100644 --- a/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.css +++ b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.css @@ -0,0 +1,6 @@ +:host { + --gn-ui-button-rounded: 100%; + --gn-ui-button-width: 8px; + --gn-ui-button-height: 8px; + --gn-ui-button-padding: 12px; +} diff --git a/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.html b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.html index 9203615ca4..d92b9276c0 100644 --- a/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.html +++ b/libs/ui/inputs/src/lib/previous-next-buttons/previous-next-buttons.component.html @@ -1,10 +1,6 @@
Date: Wed, 15 May 2024 23:13:10 +0200 Subject: [PATCH 11/15] feat(ui): keep initial height of the block list when page changes --- .../lib/block-list/block-list.component.html | 7 +++++- .../block-list/block-list.component.spec.ts | 25 ++++++++++++++++++- .../lib/block-list/block-list.component.ts | 14 ++++++++--- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/libs/ui/layout/src/lib/block-list/block-list.component.html b/libs/ui/layout/src/lib/block-list/block-list.component.html index 56223f920f..17e706ddd6 100644 --- a/libs/ui/layout/src/lib/block-list/block-list.component.html +++ b/libs/ui/layout/src/lib/block-list/block-list.component.html @@ -1,4 +1,9 @@ -
+
`, }) @@ -147,4 +147,27 @@ describe('BlockListComponent', () => { expect(component.isLastPage).toBe(false) }) }) + + describe('set initial height as min height, keeps value when height changes', () => { + beforeEach(() => { + Object.defineProperties(component.blockContainer.nativeElement, { + clientHeight: { + value: 150, + }, + }) + fixture.detectChanges() + component.ngAfterViewInit() + Object.defineProperties(component.blockContainer.nativeElement, { + clientHeight: { + value: 50, + }, + }) + fixture.detectChanges() + }) + it('sets the min height of the container according to its initial content', () => { + expect(component.blockContainer.nativeElement.style.minHeight).toBe( + '150px' + ) + }) + }) }) diff --git a/libs/ui/layout/src/lib/block-list/block-list.component.ts b/libs/ui/layout/src/lib/block-list/block-list.component.ts index a20ae957f0..5a0937c761 100644 --- a/libs/ui/layout/src/lib/block-list/block-list.component.ts +++ b/libs/ui/layout/src/lib/block-list/block-list.component.ts @@ -1,5 +1,5 @@ import { - AfterContentInit, + AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, @@ -7,6 +7,7 @@ import { ElementRef, Input, QueryList, + ViewChild, } from '@angular/core' import { CommonModule } from '@angular/common' @@ -18,13 +19,16 @@ import { CommonModule } from '@angular/common' standalone: true, imports: [CommonModule], }) -export class BlockListComponent implements AfterContentInit { +export class BlockListComponent implements AfterViewInit { @Input() pageSize = 5 @Input() containerClass = '' @Input() paginationContainerClass = 'w-full bottom-0 top-auto' @ContentChildren('block', { read: ElementRef }) blocks: QueryList< ElementRef > + @ViewChild('blockContainer') blockContainer: ElementRef + + protected minHeight = 0 protected currentPage = 0 protected get pages() { @@ -43,9 +47,13 @@ export class BlockListComponent implements AfterContentInit { constructor(private changeDetector: ChangeDetectorRef) {} - ngAfterContentInit() { + ngAfterViewInit() { this.blocks.changes.subscribe(this.refreshBlocksVisibility) this.refreshBlocksVisibility() + + // we store the first height as the min-height of the list container + this.minHeight = this.blockContainer.nativeElement.clientHeight + this.changeDetector.detectChanges() } protected refreshBlocksVisibility = () => { From 1ef846f6c3b5ead6e51a52298454f31ab4f4f4f1 Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Thu, 9 May 2024 23:06:22 +0200 Subject: [PATCH 12/15] chore: fix failing tests --- .../record-otherlinks/record-otherlinks.component.spec.ts | 6 +++--- .../elements/src/lib/link-card/link-card.component.spec.ts | 5 +---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.spec.ts b/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.spec.ts index 13ad395a38..bc4d48e632 100644 --- a/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.spec.ts +++ b/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.spec.ts @@ -1,12 +1,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' -import { Subject } from 'rxjs' +import { BehaviorSubject } from 'rxjs' import { RecordOtherlinksComponent } from './record-otherlinks.component' import { MdViewFacade } from '@geonetwork-ui/feature/record' class MdViewFacadeMock { - otherLinks$ = new Subject() + otherLinks$ = new BehaviorSubject([]) } -describe('DataOtherlinksComponent', () => { +describe('RecordOtherlinksComponent', () => { let component: RecordOtherlinksComponent let fixture: ComponentFixture diff --git a/libs/ui/elements/src/lib/link-card/link-card.component.spec.ts b/libs/ui/elements/src/lib/link-card/link-card.component.spec.ts index 1c84cd4b94..95bcdc690e 100644 --- a/libs/ui/elements/src/lib/link-card/link-card.component.spec.ts +++ b/libs/ui/elements/src/lib/link-card/link-card.component.spec.ts @@ -1,7 +1,5 @@ import { NO_ERRORS_SCHEMA } from '@angular/core' import { ComponentFixture, TestBed } from '@angular/core/testing' -import { MatIconModule } from '@angular/material/icon' -import { TranslateModule } from '@ngx-translate/core' import { LinkCardComponent } from './link-card.component' describe('LinkCardComponent', () => { @@ -10,9 +8,8 @@ describe('LinkCardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [LinkCardComponent], schemas: [NO_ERRORS_SCHEMA], - imports: [MatIconModule, TranslateModule.forRoot()], + imports: [LinkCardComponent], }).compileComponents() }) From 0fa453f818e3271020168191cb08fc7bb348e06a Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Thu, 16 May 2024 10:06:18 +0200 Subject: [PATCH 13/15] fix(dh): restore overflow-hidden in API form This was hiding the underlying user feebacks form --- .../src/app/record/record-apis/record-apis.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/datahub/src/app/record/record-apis/record-apis.component.html b/apps/datahub/src/app/record/record-apis/record-apis.component.html index 61cec4c40e..a4bf38449f 100644 --- a/apps/datahub/src/app/record/record-apis/record-apis.component.html +++ b/apps/datahub/src/app/record/record-apis/record-apis.component.html @@ -28,7 +28,7 @@
Date: Thu, 16 May 2024 11:49:00 +0200 Subject: [PATCH 14/15] e2e: attempt to make the login command more reliable --- tools/e2e/commands.ts | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/tools/e2e/commands.ts b/tools/e2e/commands.ts index b3b5ec3cc6..0c06e446e3 100644 --- a/tools/e2e/commands.ts +++ b/tools/e2e/commands.ts @@ -35,18 +35,33 @@ Cypress.Commands.add( }, }) cy.getCookie('XSRF-TOKEN').then((xsrfTokenCookie) => { - cy.request({ - method: 'POST', - url: '/geonetwork/signin', - body: `username=${username}&password=${password}&_csrf=${xsrfTokenCookie.value}`, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - }, - followRedirect: false, - }) + // do the login 2 times because it sometimes doesn't register (?) + for (let i = 0; i < 2; i++) { + cy.request({ + method: 'POST', + url: '/geonetwork/signin', + body: `username=${username}&password=${password}&_csrf=${xsrfTokenCookie.value}`, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + followRedirect: false, + }) + } + }) + cy.request({ + method: 'GET', + url: '/geonetwork/srv/api/me', + headers: { + Accept: 'application/json', + }, + }).then((response) => { + if (response.status !== 200) { + throw new Error('Could not log in to GeoNetwork API 😢') + } + cy.log('Login to GeoNetwork API successful!') }) - if (redirect) return cy.visit('/') - else return cy.window() + if (redirect) cy.visit('/') + return cy.window() } ) From 55e7abf75d9867fc744a30addff0536126ae84e0 Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Thu, 16 May 2024 14:59:07 +0200 Subject: [PATCH 15/15] feat(dh): use ngrxLet to avoid multiple async pipes --- apps/datahub/src/app/app.module.ts | 2 + .../record-otherlinks.component.html | 37 +++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/apps/datahub/src/app/app.module.ts b/apps/datahub/src/app/app.module.ts index e2b035fad1..4cac62f591 100644 --- a/apps/datahub/src/app/app.module.ts +++ b/apps/datahub/src/app/app.module.ts @@ -91,6 +91,7 @@ import { RecordApisComponent } from './record/record-apis/record-apis.component' import { MatTabsModule } from '@angular/material/tabs' import { UiWidgetsModule } from '@geonetwork-ui/ui/widgets' import { RecordUserFeedbacksComponent } from './record/record-user-feedbacks/record-user-feedbacks.component' +import { LetDirective } from '@ngrx/component' export const metaReducers: MetaReducer[] = !environment.production ? [] : [] @@ -162,6 +163,7 @@ export const metaReducers: MetaReducer[] = !environment.production ? [] : [] CarouselComponent, BlockListComponent, PreviousNextButtonsComponent, + LetDirective, ], providers: [ importProvidersFrom(FeatureAuthModule), diff --git a/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.html b/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.html index d6404df489..b97bc8a202 100644 --- a/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.html +++ b/apps/datahub/src/app/record/record-otherlinks/record-otherlinks.component.html @@ -12,29 +12,28 @@ (directionButtonClicked)="changeStepOrPage($event)" >
- - + + + + + + + - - - - -