From d7ec59f566c6ae19af449f35d942ea85e5d07298 Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Thu, 13 Jun 2024 13:59:57 +0200 Subject: [PATCH 1/9] chore(ME): Rework sidebar and routing --- apps/metadata-editor/src/app/app.routes.ts | 49 +++++-- .../dashboard-menu.component.html | 127 +++++++++++------- .../dashboard/sidebar/sidebar.component.html | 2 +- apps/metadata-editor/src/styles.css | 4 +- translations/de.json | 9 +- translations/en.json | 9 +- translations/es.json | 9 +- translations/fr.json | 9 +- translations/it.json | 9 +- translations/nl.json | 9 +- translations/pt.json | 9 +- translations/sk.json | 9 +- 12 files changed, 181 insertions(+), 73 deletions(-) diff --git a/apps/metadata-editor/src/app/app.routes.ts b/apps/metadata-editor/src/app/app.routes.ts index 2821b0f579..3f04d31ab3 100644 --- a/apps/metadata-editor/src/app/app.routes.ts +++ b/apps/metadata-editor/src/app/app.routes.ts @@ -3,7 +3,6 @@ import { DashboardPageComponent } from './dashboard/dashboard-page.component' import { SignInPageComponent } from './sign-in/sign-in-page.component' import { EditPageComponent } from './edit/edit-page.component' import { EditRecordResolver } from './edit-record.resolver' -import { MyOrgRecordsComponent } from './records/my-org-records/my-org-records.component' import { MyRecordsComponent } from './records/my-records/my-records.component' import { MyDraftComponent } from './records/my-draft/my-draft.component' import { MyLibraryComponent } from './records/my-library/my-library.component' @@ -12,9 +11,9 @@ import { MyOrgUsersComponent } from './my-org-users/my-org-users.component' import { NewRecordResolver } from './new-record.resolver' export const appRoutes: Route[] = [ - { path: '', component: DashboardPageComponent, pathMatch: 'prefix' }, + { path: '', redirectTo: 'catalog/search', pathMatch: 'prefix' }, { - path: 'records', + path: 'catalog', component: DashboardPageComponent, outlet: 'primary', children: [ @@ -24,11 +23,39 @@ export const appRoutes: Route[] = [ pathMatch: 'prefix', }, { - path: 'my-org', - title: 'My Organisation', - component: MyOrgRecordsComponent, + path: 'discussion', + component: SearchRecordsComponent, + pathMatch: 'prefix', + }, + { + path: 'calendar', + component: SearchRecordsComponent, + pathMatch: 'prefix', + }, + { + path: 'contacts', + component: SearchRecordsComponent, + pathMatch: 'prefix', + }, + { + path: 'thesaurus', + component: SearchRecordsComponent, + pathMatch: 'prefix', + }, + { + path: 'search', + title: 'Search Records', + component: SearchRecordsComponent, pathMatch: 'prefix', }, + ], + }, + { + path: 'my-space', + component: DashboardPageComponent, + outlet: 'primary', + title: 'My space', + children: [ { path: 'my-records', title: 'My Records', @@ -42,17 +69,11 @@ export const appRoutes: Route[] = [ pathMatch: 'prefix', }, { - path: 'my-library', - title: 'My Library', + path: 'templates', + title: 'Templates', component: MyLibraryComponent, pathMatch: 'prefix', }, - { - path: 'search', - title: 'Search Records', - component: SearchRecordsComponent, - pathMatch: 'prefix', - }, ], }, { diff --git a/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.html b/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.html index c723ebc1a9..53ce9e6db6 100644 --- a/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.html +++ b/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.html @@ -1,50 +1,81 @@ -
- - home - dashboard.records.myOrg - + diff --git a/apps/metadata-editor/src/app/dashboard/sidebar/sidebar.component.html b/apps/metadata-editor/src/app/dashboard/sidebar/sidebar.component.html index 311cd19287..7487ff5bf0 100644 --- a/apps/metadata-editor/src/app/dashboard/sidebar/sidebar.component.html +++ b/apps/metadata-editor/src/app/dashboard/sidebar/sidebar.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/apps/metadata-editor/src/styles.css b/apps/metadata-editor/src/styles.css index 85c4ae6deb..29fec93421 100644 --- a/apps/metadata-editor/src/styles.css +++ b/apps/metadata-editor/src/styles.css @@ -16,10 +16,10 @@ body { @apply rounded px-9 py-3 flex gap-3 items-center hover:opacity-80 transition-opacity; } .btn-active { - @apply bg-blue-50 text-blue-600; + @apply bg-neutral-200 text-blue-600 font-bold; } .menu-title { - @apply text-xl px-9 py-3; + @apply text-2xl px-9 py-3; } .mat-mdc-button-base { diff --git a/translations/de.json b/translations/de.json index 09c2b7b2e1..00eda3bf01 100644 --- a/translations/de.json +++ b/translations/de.json @@ -1,4 +1,5 @@ { + "Add Layer As": "", "button.login": "", "catalog.figures.datasets": "{count, plural, =0{Datensätze} one{Datensatz} other{Datensätze}}", "catalog.figures.organisations": "{count, plural, =0{Organisationen} one{Organisation} other{Organisationen}}", @@ -17,16 +18,22 @@ "chart.type.line": "Liniendiagramm", "chart.type.lineSmooth": "Geglättes Liniendiagramm", "chart.type.pie": "Kreisdiagramm", + "dashboard.catalog.allRecords": "Metadatenkatalog", + "dashboard.catalog.calendar": "Kalender", + "dashboard.catalog.contacts": "Kontakte", + "dashboard.catalog.discussion": "Diskussion", + "dashboard.catalog.thesaurus": "Thesaurus", "dashboard.createRecord": "Neuer Eintrag", + "dashboard.labels.catalog": "Katalog", "dashboard.labels.mySpace": "Mein Bereich", "dashboard.records.all": "Katalog", "dashboard.records.hasDraft": "", "dashboard.records.myDraft": "Meine Entwürfe", "dashboard.records.myLibrary": "Meine Bibliothek", - "dashboard.records.myOrg": "Meine Organisation", "dashboard.records.myRecords": "Meine Datensätze", "dashboard.records.publishedRecords": "{count, plural, =1{veröffentlichter Datensatz} other{veröffentlichte Datensätze}}", "dashboard.records.search": "Suche nach \"{searchText}\"", + "dashboard.records.templates": "Vorlagen", "dashboard.records.userDetail": "Name", "dashboard.records.userEmail": "E-Mail", "dashboard.records.username": "Benutzername", diff --git a/translations/en.json b/translations/en.json index decd8703df..f2e8e6f693 100644 --- a/translations/en.json +++ b/translations/en.json @@ -1,4 +1,5 @@ { + "Add Layer As": "", "button.login": "Log in", "catalog.figures.datasets": "{count, plural, =0{datasets} one{dataset} other{datasets}}", "catalog.figures.organisations": "{count, plural, =0{organisations} one{organisation} other{organisations}}", @@ -17,16 +18,22 @@ "chart.type.line": "line chart", "chart.type.lineSmooth": "smooth line chart", "chart.type.pie": "pie chart", + "dashboard.catalog.allRecords": "Metadata records", + "dashboard.catalog.calendar": "Calendar", + "dashboard.catalog.contacts": "Contacts", + "dashboard.catalog.discussion": "Discussion", + "dashboard.catalog.thesaurus": "Thesaurus", "dashboard.createRecord": "New record", + "dashboard.labels.catalog": "Catalog", "dashboard.labels.mySpace": "My space", "dashboard.records.all": "Metadata records", "dashboard.records.hasDraft": "draft", "dashboard.records.myDraft": "My drafts", "dashboard.records.myLibrary": "My library", - "dashboard.records.myOrg": "Organization", "dashboard.records.myRecords": "My Records", "dashboard.records.publishedRecords": "{count, plural, =1{published record} other{published records}}", "dashboard.records.search": "Search for \"{searchText}\"", + "dashboard.records.templates": "Templates", "dashboard.records.userDetail": "Name", "dashboard.records.userEmail": "Email", "dashboard.records.username": "Username", diff --git a/translations/es.json b/translations/es.json index bfcabb53e0..0b6f6ef077 100644 --- a/translations/es.json +++ b/translations/es.json @@ -1,4 +1,5 @@ { + "Add Layer As": "", "button.login": "", "catalog.figures.datasets": "conjuntos de datos", "catalog.figures.organisations": "organizaciones", @@ -17,16 +18,22 @@ "chart.type.line": "gráfico de líneas", "chart.type.lineSmooth": "gráfico de líneas suave", "chart.type.pie": "gráfico circular", + "dashboard.catalog.allRecords": "", + "dashboard.catalog.calendar": "", + "dashboard.catalog.contacts": "", + "dashboard.catalog.discussion": "", + "dashboard.catalog.thesaurus": "", "dashboard.createRecord": "", + "dashboard.labels.catalog": "Catálogo", "dashboard.labels.mySpace": "Mi espacio", "dashboard.records.all": "Catálogo", "dashboard.records.hasDraft": "", "dashboard.records.myDraft": "Mis borradores", "dashboard.records.myLibrary": "Mi biblioteca", - "dashboard.records.myOrg": "Organización", "dashboard.records.myRecords": "Mis Registros", "dashboard.records.publishedRecords": "", "dashboard.records.search": "Buscar \"{searchText}\"", + "dashboard.records.templates": "", "dashboard.records.userDetail": "", "dashboard.records.userEmail": "", "dashboard.records.username": "", diff --git a/translations/fr.json b/translations/fr.json index d00892ecdf..b3fd3ec487 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -1,4 +1,5 @@ { + "Add Layer As": "", "button.login": "Se connecter", "catalog.figures.datasets": "{count, plural, =0{données} one{donnée} other{données}}", "catalog.figures.organisations": "{count, plural, =0{organisations} one{organisation} other{organisations}}", @@ -17,16 +18,22 @@ "chart.type.line": "ligne", "chart.type.lineSmooth": "ligne lisse", "chart.type.pie": "camembert", + "dashboard.catalog.allRecords": "Fiches de métadonnée", + "dashboard.catalog.calendar": "Calendrier", + "dashboard.catalog.contacts": "Annuaire", + "dashboard.catalog.discussion": "Discussions", + "dashboard.catalog.thesaurus": "Thesaurus", "dashboard.createRecord": "Nouvel enregistrement", + "dashboard.labels.catalog": "Catalogue", "dashboard.labels.mySpace": "Mon espace", "dashboard.records.all": "Catalogue", "dashboard.records.hasDraft": "brouillon", "dashboard.records.myDraft": "Mes brouillons", "dashboard.records.myLibrary": "Ma bibliothèque", - "dashboard.records.myOrg": "Mon organisation", "dashboard.records.myRecords": "Mes fiches publiées", "dashboard.records.publishedRecords": "{count, plural, =1{donnée publiée} other{données publiées}}", "dashboard.records.search": "Résultats pour \"{searchText}\"", + "dashboard.records.templates": "Modèles pré-remplis", "dashboard.records.userDetail": "Nom", "dashboard.records.userEmail": "Email", "dashboard.records.username": "Nom d'utilisateur", diff --git a/translations/it.json b/translations/it.json index e6f5695378..f5fdf505fb 100644 --- a/translations/it.json +++ b/translations/it.json @@ -1,4 +1,5 @@ { + "Add Layer As": "", "button.login": "", "catalog.figures.datasets": "{count, plural, =0{datasets} one{dataset} other{datasets}}", "catalog.figures.organisations": "{count, plural, =0{organizzazioni} one{organizzazione} other{organizzazioni}}", @@ -17,16 +18,22 @@ "chart.type.line": "grafico a linee", "chart.type.lineSmooth": "grafico a linea liscia", "chart.type.pie": "grafico a torta", + "dashboard.catalog.allRecords": "", + "dashboard.catalog.calendar": "", + "dashboard.catalog.contacts": "", + "dashboard.catalog.discussion": "", + "dashboard.catalog.thesaurus": "", "dashboard.createRecord": "Crea un record", + "dashboard.labels.catalog": "Catalogo", "dashboard.labels.mySpace": "Il mio spazio", "dashboard.records.all": "Catalogo", "dashboard.records.hasDraft": "", "dashboard.records.myDraft": "Le mie bozze", "dashboard.records.myLibrary": "La mia biblioteca", - "dashboard.records.myOrg": "La mia organizzazione", "dashboard.records.myRecords": "I miei dati", "dashboard.records.publishedRecords": "dati pubblicati", "dashboard.records.search": "Risultati per \"{searchText}\"", + "dashboard.records.templates": "", "dashboard.records.userDetail": "Nome", "dashboard.records.userEmail": "Email", "dashboard.records.username": "Nome utente", diff --git a/translations/nl.json b/translations/nl.json index e915d50ce0..8fd6367af8 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -1,4 +1,5 @@ { + "Add Layer As": "", "button.login": "", "catalog.figures.datasets": "datasets", "catalog.figures.organisations": "organisaties", @@ -17,16 +18,22 @@ "chart.type.line": "lijndiagram", "chart.type.lineSmooth": "glad lijndiagram", "chart.type.pie": "cirkeldiagram", + "dashboard.catalog.allRecords": "", + "dashboard.catalog.calendar": "", + "dashboard.catalog.contacts": "", + "dashboard.catalog.discussion": "", + "dashboard.catalog.thesaurus": "", "dashboard.createRecord": "", + "dashboard.labels.catalog": "Catalogus", "dashboard.labels.mySpace": "Mijn ruimte", "dashboard.records.all": "Catalogus", "dashboard.records.hasDraft": "", "dashboard.records.myDraft": "Mijn concepten", "dashboard.records.myLibrary": "Mijn bibliotheek", - "dashboard.records.myOrg": "Organisatie", "dashboard.records.myRecords": "Mijn Records", "dashboard.records.publishedRecords": "", "dashboard.records.search": "Zoeken naar \"{searchText}\"", + "dashboard.records.templates": "", "dashboard.records.userDetail": "", "dashboard.records.userEmail": "", "dashboard.records.username": "", diff --git a/translations/pt.json b/translations/pt.json index 3d1571aac1..ef5340e5c4 100644 --- a/translations/pt.json +++ b/translations/pt.json @@ -1,4 +1,5 @@ { + "Add Layer As": "", "button.login": "", "catalog.figures.datasets": "conjuntos de dados", "catalog.figures.organisations": "organizações", @@ -17,16 +18,22 @@ "chart.type.line": "gráfico de linha", "chart.type.lineSmooth": "gráfico de linha suave", "chart.type.pie": "gráfico de pizza", + "dashboard.catalog.allRecords": "", + "dashboard.catalog.calendar": "", + "dashboard.catalog.contacts": "", + "dashboard.catalog.discussion": "", + "dashboard.catalog.thesaurus": "", "dashboard.createRecord": "", + "dashboard.labels.catalog": "Catálogo", "dashboard.labels.mySpace": "Meu espaço", "dashboard.records.all": "Catálogo", "dashboard.records.hasDraft": "", "dashboard.records.myDraft": "Meus rascunhos", "dashboard.records.myLibrary": "Minha biblioteca", - "dashboard.records.myOrg": "Organização", "dashboard.records.myRecords": "Meus Registros", "dashboard.records.publishedRecords": "", "dashboard.records.search": "Buscar por \"{searchText}\"", + "dashboard.records.templates": "", "dashboard.records.userDetail": "", "dashboard.records.userEmail": "", "dashboard.records.username": "", diff --git a/translations/sk.json b/translations/sk.json index f7116abc16..b961a05d12 100644 --- a/translations/sk.json +++ b/translations/sk.json @@ -1,4 +1,5 @@ { + "Add Layer As": "", "button.login": "", "catalog.figures.datasets": "{count, plural, =0{datasety} one{dataset} other{datasety}}", "catalog.figures.organisations": "{count, plural, =0{organizácie} one{organizácia} other{organizácie}}", @@ -17,16 +18,22 @@ "chart.type.line": "čiarový graf", "chart.type.lineSmooth": "vyhladený čiarový graf", "chart.type.pie": "koláčový graf", + "dashboard.catalog.allRecords": "", + "dashboard.catalog.calendar": "", + "dashboard.catalog.contacts": "", + "dashboard.catalog.discussion": "", + "dashboard.catalog.thesaurus": "", "dashboard.createRecord": "", + "dashboard.labels.catalog": "Katalóg", "dashboard.labels.mySpace": "Môj priestor", "dashboard.records.all": "Katalóg", "dashboard.records.hasDraft": "", "dashboard.records.myDraft": "Moje koncepty", "dashboard.records.myLibrary": "Moja knižnica", - "dashboard.records.myOrg": "Organizácia", "dashboard.records.myRecords": "Moje záznamy", "dashboard.records.publishedRecords": "{count, plural, =1{zverejnený záznam} other{zverejnených záznamov}}", "dashboard.records.search": "Hľadať \"{searchText}\"", + "dashboard.records.templates": "", "dashboard.records.userDetail": "Meno", "dashboard.records.userEmail": "Email", "dashboard.records.username": "Užívateľské meno", From 280bbe6ecba6f7781a68291391f6b83f20c6f6cf Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Thu, 13 Jun 2024 18:27:08 +0200 Subject: [PATCH 2/9] fix(e2e): Fix route to /catalog --- apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts | 14 +++++++------- apps/metadata-editor/src/app/router.service.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts b/apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts index 0908f40c8e..89322e4ee5 100644 --- a/apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts +++ b/apps/metadata-editor-e2e/src/e2e/dashboard.cy.ts @@ -2,7 +2,7 @@ describe('dashboard', () => { let pageOne describe('pagination', () => { it('should display different results on click on arrow', () => { - cy.visit('/records/search') + cy.visit('/catalog/search') cy.get('gn-ui-results-table') .find('.table-row-cell') .first() @@ -13,7 +13,7 @@ describe('dashboard', () => { }) //TODO remove skip when dump contains more than 15 records it.skip('should display different results on click on specific page and change url', () => { - cy.visit('/records/search?_page=2') + cy.visit('/catalog/search?_page=2') cy.get('gn-ui-pagination-buttons').find('gn-ui-button').eq(1).click() cy.get('gn-ui-results-table') .find('.table-row-cell') @@ -36,8 +36,8 @@ describe('dashboard', () => { }) describe('sorting', () => { - it('should order the result list on click', () => { - cy.visit('/records/search') + it.only('should order the result list on click', () => { + cy.visit('/catalog/search') cy.get('gn-ui-results-table') .find('.table-row-cell') .eq(1) @@ -65,7 +65,7 @@ describe('dashboard', () => { describe('checkboxes', () => { it('should show the correct amount of selected records when they are selected', () => { - cy.visit('/records/search') + cy.visit('/catalog/search') cy.get('gn-ui-results-table') .find('.table-row-cell') .get('gn-ui-checkbox') @@ -75,7 +75,7 @@ describe('dashboard', () => { }) it('should show nothing when none are selected', () => { - cy.visit('/records/search') + cy.visit('/catalog/search') cy.get('gn-ui-results-table') .find('.table-row-cell') .get('gn-ui-checkbox') @@ -87,7 +87,7 @@ describe('dashboard', () => { }) it('should select all records when the "select all" checkbox is checked', () => { - cy.visit('/records/search') + cy.visit('/catalog/search') cy.get('gn-ui-results-table') .find('.table-row-cell') .get('gn-ui-checkbox') diff --git a/apps/metadata-editor/src/app/router.service.ts b/apps/metadata-editor/src/app/router.service.ts index 5a1b48121d..368f6fbc84 100644 --- a/apps/metadata-editor/src/app/router.service.ts +++ b/apps/metadata-editor/src/app/router.service.ts @@ -14,7 +14,7 @@ export class EditorRouterService { } getSearchRoute(): string { - return 'records/search' + return 'catalog/search' } getDatahubSearchRoute(): string { From bed04f527d41ddb869b7459c76f2ed229c5e45a1 Mon Sep 17 00:00:00 2001 From: Angelika Kinas Date: Thu, 13 Jun 2024 18:47:36 +0200 Subject: [PATCH 3/9] fix(e2e): Readd org-page, fix test --- apps/metadata-editor-e2e/src/e2e/my-org.cy.ts | 6 ++---- apps/metadata-editor/src/app/app.routes.ts | 6 ++++++ .../app/records/my-org-records/my-org-records.component.ts | 5 ++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/metadata-editor-e2e/src/e2e/my-org.cy.ts b/apps/metadata-editor-e2e/src/e2e/my-org.cy.ts index a730895c2d..14ddf94cf9 100644 --- a/apps/metadata-editor-e2e/src/e2e/my-org.cy.ts +++ b/apps/metadata-editor-e2e/src/e2e/my-org.cy.ts @@ -5,8 +5,7 @@ describe('my-org', () => { method: 'GET', url: '/geonetwork/srv/api/userselections/0/101', }).as('dataGetFirst') - cy.visit(`/records/my-org`) - cy.get('md-editor-dashboard-menu').find('a').first().click() + cy.visit(`/catalog/my-org`) cy.wait('@dataGetFirst').its('response.statusCode').should('equal', 200) }) describe('my-org display', () => { @@ -31,8 +30,7 @@ describe('my-org', () => { }) }) it('should access the user list page and show my-org users', () => { - cy.visit(`/records/my-org`) - cy.get('md-editor-dashboard-menu').find('a').first().click() + cy.visit(`/catalog/my-org`) cy.get('[data-cy=link-to-users]').click() cy.url().should('include', '/users/my-org') cy.get('gn-ui-interactive-table .contents').should('have.length.above', 1) diff --git a/apps/metadata-editor/src/app/app.routes.ts b/apps/metadata-editor/src/app/app.routes.ts index 3f04d31ab3..878df29ce9 100644 --- a/apps/metadata-editor/src/app/app.routes.ts +++ b/apps/metadata-editor/src/app/app.routes.ts @@ -8,6 +8,7 @@ import { MyDraftComponent } from './records/my-draft/my-draft.component' import { MyLibraryComponent } from './records/my-library/my-library.component' import { SearchRecordsComponent } from './records/search-records/search-records-list.component' import { MyOrgUsersComponent } from './my-org-users/my-org-users.component' +import { MyOrgRecordsComponent } from './records/my-org-records/my-org-records.component' import { NewRecordResolver } from './new-record.resolver' export const appRoutes: Route[] = [ @@ -48,6 +49,11 @@ export const appRoutes: Route[] = [ component: SearchRecordsComponent, pathMatch: 'prefix', }, + { + path: 'my-org', + title: 'My Organisation', + component: MyOrgRecordsComponent, + }, ], }, { diff --git a/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts b/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts index 6fee469372..4f9d13e364 100644 --- a/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts +++ b/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts @@ -1,4 +1,4 @@ -import { Component, OnDestroy } from '@angular/core' +import { Component } from '@angular/core' import { CommonModule } from '@angular/common' import { TranslateModule } from '@ngx-translate/core' import { RecordsListComponent } from '../records-list.component' @@ -7,7 +7,6 @@ import { SearchFacade } from '@geonetwork-ui/feature/search' import { Organization } from '@geonetwork-ui/common/domain/model/record' import { OrganizationsServiceInterface } from '@geonetwork-ui/common/domain/organizations.service.interface' import { EditorRouterService } from '../../router.service' -import { UserModel } from '@geonetwork-ui/common/domain/model/user/user.model' import { take } from 'rxjs' @Component({ @@ -49,7 +48,7 @@ export class MyOrgRecordsComponent { this.router.getDatahubSearchRoute(), window.location.toString() ) - + console.log('url', url) url.searchParams.append('publisher', this.orgName) return url.toString() } From e0cc676ebf57aec92fb56ce280c7d5780734c7e5 Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Sun, 16 Jun 2024 22:46:36 +0200 Subject: [PATCH 4/9] refactor(search): split results-table component in smart and UI components --- libs/feature/search/src/index.ts | 2 +- ... => results-table-container.component.css} | 0 .../results-table-container.component.html | 9 + .../results-table-container.component.spec.ts | 135 +++++++++++ .../results-table-container.component.ts | 49 ++++ .../results-table.component.spec.ts | 227 ------------------ .../results-table/results-table.component.ts | 171 ------------- libs/ui/search/src/index.ts | 1 + .../results-table/results-table.component.css | 0 .../results-table.component.html | 16 +- .../results-table.component.spec.ts | 152 ++++++++++++ .../results-table/results-table.component.ts | 138 +++++++++++ 12 files changed, 493 insertions(+), 407 deletions(-) rename libs/feature/search/src/lib/results-table/{results-table.component.css => results-table-container.component.css} (100%) create mode 100644 libs/feature/search/src/lib/results-table/results-table-container.component.html create mode 100644 libs/feature/search/src/lib/results-table/results-table-container.component.spec.ts create mode 100644 libs/feature/search/src/lib/results-table/results-table-container.component.ts delete mode 100644 libs/feature/search/src/lib/results-table/results-table.component.spec.ts delete mode 100644 libs/feature/search/src/lib/results-table/results-table.component.ts create mode 100644 libs/ui/search/src/lib/results-table/results-table.component.css rename libs/{feature => ui}/search/src/lib/results-table/results-table.component.html (91%) create mode 100644 libs/ui/search/src/lib/results-table/results-table.component.spec.ts create mode 100644 libs/ui/search/src/lib/results-table/results-table.component.ts diff --git a/libs/feature/search/src/index.ts b/libs/feature/search/src/index.ts index 0234a5cedb..f6103754e3 100644 --- a/libs/feature/search/src/index.ts +++ b/libs/feature/search/src/index.ts @@ -21,4 +21,4 @@ export * from './lib/results-hits-number/results-hits.container.component' export * from './lib/results-layout/results-layout.component' export * from './lib/sort-by/sort-by.component' export * from './lib/state/container/search-state.container.directive' -export * from './lib/results-table/results-table.component' +export * from './lib/results-table/results-table-container.component' diff --git a/libs/feature/search/src/lib/results-table/results-table.component.css b/libs/feature/search/src/lib/results-table/results-table-container.component.css similarity index 100% rename from libs/feature/search/src/lib/results-table/results-table.component.css rename to libs/feature/search/src/lib/results-table/results-table-container.component.css diff --git a/libs/feature/search/src/lib/results-table/results-table-container.component.html b/libs/feature/search/src/lib/results-table/results-table-container.component.html new file mode 100644 index 0000000000..0853ac710e --- /dev/null +++ b/libs/feature/search/src/lib/results-table/results-table-container.component.html @@ -0,0 +1,9 @@ + diff --git a/libs/feature/search/src/lib/results-table/results-table-container.component.spec.ts b/libs/feature/search/src/lib/results-table/results-table-container.component.spec.ts new file mode 100644 index 0000000000..0c663abd04 --- /dev/null +++ b/libs/feature/search/src/lib/results-table/results-table-container.component.spec.ts @@ -0,0 +1,135 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing' +import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures' +import { ResultsTableContainerComponent } from './results-table-container.component' +import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record' +import { By } from '@angular/platform-browser' +import { BehaviorSubject } from 'rxjs' +import { SearchFacade } from '../state/search.facade' +import { SearchService } from '../utils/service/search.service' +import { SelectionService } from '@geonetwork-ui/api/repository' +import { TranslateModule } from '@ngx-translate/core' +import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' + +class SearchFacadeMock { + results$ = new BehaviorSubject(DATASET_RECORDS) + resultsHits$ = new BehaviorSubject(1000) + setConfigRequestFields = jest.fn(() => this) + setSortBy = jest.fn(() => this) + sortBy$ = new BehaviorSubject(['asc', 'updateDate']) +} +class SearchServiceMock { + setPage = jest.fn() + setSortBy = jest.fn() +} +class SelectionServiceMock { + selectRecords = jest.fn() + deselectRecords = jest.fn() + clearSelection = jest.fn() + selectedRecordsIdentifiers$ = new BehaviorSubject([]) +} +class RecordsRepositoryMock { + recordHasDraft = jest.fn(() => false) +} + +describe('ResultsTableContainerComponent', () => { + let component: ResultsTableContainerComponent + let searchFacade: SearchFacadeMock + let searchService: SearchServiceMock + let selectionService: SelectionServiceMock + let fixture: ComponentFixture + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot()], + providers: [ + { + provide: SearchFacade, + useClass: SearchFacadeMock, + }, + { + provide: SearchService, + useClass: SearchServiceMock, + }, + { + provide: SelectionService, + useClass: SelectionServiceMock, + }, + { + provide: RecordsRepositoryInterface, + useClass: RecordsRepositoryMock, + }, + ], + }).compileComponents() + + fixture = TestBed.createComponent(ResultsTableContainerComponent) + searchFacade = TestBed.inject(SearchFacade) as any + searchService = TestBed.inject(SearchService) as any + selectionService = TestBed.inject(SelectionService) as any + component = fixture.componentInstance + fixture.detectChanges() + }) + + it('should create', () => { + expect(component).toBeTruthy() + }) + + describe('sorting', () => { + describe('#setSortBy', () => { + it('calls the facade to change sort order', () => { + component.handleSortByChange('title', 'asc') + expect(searchService.setSortBy).toHaveBeenCalledWith(['asc', 'title']) + }) + }) + }) + + describe('selection', () => { + beforeEach(() => { + searchFacade.results$.next([ + { + uniqueIdentifier: '1', + }, + { + uniqueIdentifier: '2', + }, + { + uniqueIdentifier: '3', + }, + ] as any) + }) + + describe('#handleRecordSelectedChange', () => { + it('should call selectRecords when checkbox is clicked', () => { + const record = { uniqueIdentifier: '1' } + component.handleRecordsSelectedChange([record as CatalogRecord], true) + expect(selectionService.selectRecords).toHaveBeenCalledWith([record]) + }) + }) + }) + + describe('clicking on a dataset', () => { + let clickedRecord: CatalogRecord + + beforeEach(() => { + clickedRecord = null + component.recordClick.subscribe((r) => (clickedRecord = r)) + }) + + it('emits a recordClick event', () => { + const tableRow = fixture.debugElement.queryAll( + By.css('.table-row-cell') + )[1].nativeElement as HTMLDivElement + tableRow.parentElement.click() + expect(clickedRecord).toEqual(DATASET_RECORDS[0]) + }) + }) + + describe('#hasDraft', () => { + it('calls the repository service', () => { + const record = DATASET_RECORDS[0] + component.hasDraft(record) + expect( + TestBed.inject(RecordsRepositoryInterface).recordHasDraft + ).toHaveBeenCalledWith('my-dataset-001') + }) + }) +}) diff --git a/libs/feature/search/src/lib/results-table/results-table-container.component.ts b/libs/feature/search/src/lib/results-table/results-table-container.component.ts new file mode 100644 index 0000000000..10c076e4c4 --- /dev/null +++ b/libs/feature/search/src/lib/results-table/results-table-container.component.ts @@ -0,0 +1,49 @@ +import { Component, EventEmitter, Output } from '@angular/core' +import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record' +import { SearchFacade } from '../state/search.facade' +import { SelectionService } from '@geonetwork-ui/api/repository' +import { SearchService } from '../utils/service/search.service' +import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' +import { ResultsTableComponent } from '@geonetwork-ui/ui/search' +import { CommonModule } from '@angular/common' + +@Component({ + selector: 'gn-ui-results-table-container', + templateUrl: './results-table-container.component.html', + styleUrls: ['./results-table-container.component.css'], + standalone: true, + imports: [CommonModule, ResultsTableComponent], +}) +export class ResultsTableContainerComponent { + @Output() recordClick = new EventEmitter() + + records$ = this.searchFacade.results$ + selectedRecords$ = this.selectionService.selectedRecordsIdentifiers$ + sortBy$ = this.searchFacade.sortBy$ + + hasDraft = (record: CatalogRecord): boolean => + this.recordsRepository.recordHasDraft(record.uniqueIdentifier) + + constructor( + private searchFacade: SearchFacade, + private searchService: SearchService, + private selectionService: SelectionService, + private recordsRepository: RecordsRepositoryInterface + ) {} + + handleRecordClick(item: unknown) { + this.recordClick.emit(item as CatalogRecord) + } + + handleSortByChange(col: string, order: 'asc' | 'desc') { + this.searchService.setSortBy([order, col]) + } + + handleRecordsSelectedChange(records: CatalogRecord[], selected: boolean) { + if (!selected) { + this.selectionService.deselectRecords(records) + } else { + this.selectionService.selectRecords(records) + } + } +} diff --git a/libs/feature/search/src/lib/results-table/results-table.component.spec.ts b/libs/feature/search/src/lib/results-table/results-table.component.spec.ts deleted file mode 100644 index e45273531b..0000000000 --- a/libs/feature/search/src/lib/results-table/results-table.component.spec.ts +++ /dev/null @@ -1,227 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing' -import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures' -import { ResultsTableComponent } from './results-table.component' -import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record' -import { By } from '@angular/platform-browser' -import { BehaviorSubject, firstValueFrom } from 'rxjs' -import { SearchFacade } from '../state/search.facade' -import { SearchService } from '../utils/service/search.service' -import { SelectionService } from '@geonetwork-ui/api/repository' -import { TranslateModule } from '@ngx-translate/core' -import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' - -class SearchFacadeMock { - results$ = new BehaviorSubject(DATASET_RECORDS) - resultsHits$ = new BehaviorSubject(1000) - setConfigRequestFields = jest.fn(() => this) - setSortBy = jest.fn(() => this) - sortBy$ = new BehaviorSubject(['asc', 'updateDate']) -} -class SearchServiceMock { - setPage = jest.fn() - setSortBy = jest.fn() -} -class SelectionServiceMock { - selectRecords = jest.fn() - deselectRecords = jest.fn() - clearSelection = jest.fn() - selectedRecordsIdentifiers$ = new BehaviorSubject([]) -} -class RecordsRepositoryMock { - recordHasDraft = jest.fn(() => false) -} - -describe('ResultsTableComponent', () => { - let component: ResultsTableComponent - let searchFacade: SearchFacadeMock - let searchService: SearchServiceMock - let selectionService: SelectionServiceMock - let fixture: ComponentFixture - - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [TranslateModule.forRoot()], - providers: [ - { - provide: SearchFacade, - useClass: SearchFacadeMock, - }, - { - provide: SearchService, - useClass: SearchServiceMock, - }, - { - provide: SelectionService, - useClass: SelectionServiceMock, - }, - { - provide: RecordsRepositoryInterface, - useClass: RecordsRepositoryMock, - }, - ], - }).compileComponents() - - fixture = TestBed.createComponent(ResultsTableComponent) - searchFacade = TestBed.inject(SearchFacade) as any - searchService = TestBed.inject(SearchService) as any - selectionService = TestBed.inject(SelectionService) as any - component = fixture.componentInstance - fixture.detectChanges() - }) - - it('should create', () => { - expect(component).toBeTruthy() - }) - - describe('get a list of formats and sorts them depending on priority', () => { - it('returns a list of unique formats', () => { - expect(component.getRecordFormats(DATASET_RECORDS[0])).toEqual([ - 'geojson', - 'shp', - 'pdf', - ]) - }) - }) - describe('get the badge color for given format', () => { - it('returns the color for its format', () => { - expect( - component.getBadgeColor( - component.getRecordFormats(DATASET_RECORDS[0])[0] - ) - ).toEqual('#1e5180') // geojson - }) - }) - - describe('sorting', () => { - describe('#setSortBy', () => { - it('calls the facade to change sort order', () => { - component.setSortBy('title', 'asc') - expect(searchService.setSortBy).toHaveBeenCalledWith(['asc', 'title']) - }) - }) - describe('#isSortedBy', () => { - it('returns null if not sorted by this column', async () => { - searchFacade.sortBy$.next(['desc', 'owner']) - const sort = await firstValueFrom(component.isSortedBy('title')) - expect(sort).toBe(null) - }) - it('returns the sort order if the current sortBy is for this column', async () => { - searchFacade.sortBy$.next(['desc', 'title']) - const sort = await firstValueFrom(component.isSortedBy('title')) - expect(sort).toBe('desc') - }) - it('returns true if the current sortBy is for this column (multiple sorts)', async () => { - searchFacade.sortBy$.next([ - ['asc', 'score'], - ['desc', 'title'], - ]) - expect(await firstValueFrom(component.isSortedBy('title'))).toBe('desc') - expect(await firstValueFrom(component.isSortedBy('score'))).toBe('asc') - expect(await firstValueFrom(component.isSortedBy('owner'))).toBe(null) - }) - }) - }) - - describe('selection', () => { - beforeEach(() => { - searchFacade.results$.next([ - { - uniqueIdentifier: '1', - }, - { - uniqueIdentifier: '2', - }, - { - uniqueIdentifier: '3', - }, - ] as any) - }) - - describe('#isChecked', () => { - it('should return true when the record is in the selectedRecords array', async () => { - selectionService.selectedRecordsIdentifiers$.next(['1', '2']) - const record = { uniqueIdentifier: '2' } as CatalogRecord - expect(await firstValueFrom(component.isChecked(record))).toBe(true) - }) - - it('should return false when the record is not in the selectedRecords array', async () => { - selectionService.selectedRecordsIdentifiers$.next(['1', '2', '3']) - const record = { uniqueIdentifier: '4' } as CatalogRecord - expect(await firstValueFrom(component.isChecked(record))).toBe(false) - }) - }) - - describe('#handleRecordSelectedChange', () => { - it('should call selectRecords when checkbox is clicked', () => { - const record = { uniqueIdentifier: '1' } - component.handleRecordSelectedChange(true, record as CatalogRecord) - expect(selectionService.selectRecords).toHaveBeenCalledWith([record]) - }) - }) - - describe('#isAllSelected', () => { - it('returns true if all records in the page are selected', async () => { - selectionService.selectedRecordsIdentifiers$.next([ - '1', - '2', - '3', - '4', - '5', - ]) - expect(await firstValueFrom(component.isAllSelected())).toBe(true) - }) - it('returns false otherwise', async () => { - selectionService.selectedRecordsIdentifiers$.next(['1']) - expect(await firstValueFrom(component.isAllSelected())).toBe(false) - }) - }) - - describe('#isSomeSelected', () => { - it('returns false if all records in the page are selected', async () => { - selectionService.selectedRecordsIdentifiers$.next([ - '1', - '2', - '3', - '4', - '5', - ]) - expect(await firstValueFrom(component.isSomeSelected())).toBe(false) - }) - it('returns true if one or more records in the page is selected', async () => { - selectionService.selectedRecordsIdentifiers$.next(['2', '3']) - expect(await firstValueFrom(component.isSomeSelected())).toBe(true) - }) - it('returns false if no record in the page is selected', async () => { - selectionService.selectedRecordsIdentifiers$.next(['4', '5']) - expect(await firstValueFrom(component.isSomeSelected())).toBe(false) - }) - }) - }) - - describe('clicking on a dataset', () => { - let clickedRecord: CatalogRecord - - beforeEach(() => { - clickedRecord = null - component.recordClick.subscribe((r) => (clickedRecord = r)) - }) - - it('emits a recordClick event', () => { - const tableRow = fixture.debugElement.queryAll( - By.css('.table-row-cell') - )[1].nativeElement as HTMLDivElement - tableRow.parentElement.click() - expect(clickedRecord).toEqual(DATASET_RECORDS[0]) - }) - }) - - describe('#hasDraft', () => { - it('calls the repository service', () => { - const record = DATASET_RECORDS[0] - component.hasDraft(record) - expect( - TestBed.inject(RecordsRepositoryInterface).recordHasDraft - ).toHaveBeenCalledWith('my-dataset-001') - }) - }) -}) diff --git a/libs/feature/search/src/lib/results-table/results-table.component.ts b/libs/feature/search/src/lib/results-table/results-table.component.ts deleted file mode 100644 index 299427b28c..0000000000 --- a/libs/feature/search/src/lib/results-table/results-table.component.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { Component, EventEmitter, Output } from '@angular/core' -import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record' -import { - FileFormat, - getBadgeColor, - getFileFormat, - getFormatPriority, -} from '@geonetwork-ui/util/shared' -import { BadgeComponent, UiInputsModule } from '@geonetwork-ui/ui/inputs' -import { - InteractiveTableColumnComponent, - InteractiveTableComponent, -} from '@geonetwork-ui/ui/layout' -import { MatIconModule } from '@angular/material/icon' -import { TranslateModule } from '@ngx-translate/core' -import { SearchFacade } from '../state/search.facade' -import { SelectionService } from '@geonetwork-ui/api/repository' -import { combineLatest, firstValueFrom, Observable } from 'rxjs' -import { CommonModule } from '@angular/common' -import { map, take } from 'rxjs/operators' -import { FieldSort } from '@geonetwork-ui/common/domain/model/search' -import { SearchService } from '../utils/service/search.service' -import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' - -@Component({ - selector: 'gn-ui-results-table', - templateUrl: './results-table.component.html', - styleUrls: ['./results-table.component.css'], - standalone: true, - imports: [ - CommonModule, - UiInputsModule, - InteractiveTableComponent, - InteractiveTableColumnComponent, - MatIconModule, - TranslateModule, - BadgeComponent, - ], -}) -export class ResultsTableComponent { - @Output() recordClick = new EventEmitter() - - records$ = this.searchFacade.results$ - selectedRecords$ = this.selectionService.selectedRecordsIdentifiers$ - - constructor( - private searchFacade: SearchFacade, - private searchService: SearchService, - private selectionService: SelectionService, - private recordsRepository: RecordsRepositoryInterface - ) {} - - dateToString(date: Date): string { - return date?.toLocaleDateString(undefined, { - year: 'numeric', - month: 'long', - day: 'numeric', - timeZone: 'UTC', - }) - } - - getStatus(isPublishedToAll: boolean | unknown) { - return isPublishedToAll ? 'published' : 'not published' - } - - getRecordFormats(record: CatalogRecord): FileFormat[] { - if (record.kind === 'service' || !('distributions' in record)) { - return [] - } - const formats = Array.from( - new Set( - record.distributions.map((distribution) => getFileFormat(distribution)) - ) - ).filter((format) => !!format) - formats.sort((a, b) => getFormatPriority(b) - getFormatPriority(a)) - return formats - } - - formatUserInfo(userInfo: string | unknown): string { - const infos = (typeof userInfo === 'string' ? userInfo : '').split('|') - if (infos && infos.length === 4) { - return `${infos[2]} ${infos[1]}` - } - return undefined - } - - getBadgeColor(format: FileFormat): string { - return getBadgeColor(format) - } - - handleRecordClick(item: unknown) { - this.recordClick.emit(item as CatalogRecord) - } - - setSortBy(col: string, order: 'asc' | 'desc') { - this.searchService.setSortBy([order, col]) - } - - isSortedBy(col: string): Observable<'asc' | 'desc' | null> { - return this.searchFacade.sortBy$.pipe( - take(1), - map((sortOrder) => { - const sortArray = Array.isArray(sortOrder[0]) - ? (sortOrder as FieldSort[]) - : ([sortOrder] as FieldSort[]) - for (const sort of sortArray) { - if (sort[1] === col) { - return sort[0] - } - } - return null - }) - ) - } - - isChecked(record: CatalogRecord): Observable { - return this.selectedRecords$.pipe( - take(1), - map((selectedRecords) => { - return selectedRecords.includes(record.uniqueIdentifier) - }) - ) - } - - handleRecordSelectedChange(selected: boolean, record: CatalogRecord) { - if (!selected) { - this.selectionService.deselectRecords([record]) - } else { - this.selectionService.selectRecords([record]) - } - } - - async toggleSelectAll() { - const records = await firstValueFrom(this.records$) - if (await firstValueFrom(this.isAllSelected())) { - this.selectionService.deselectRecords(records) - } else { - this.selectionService.selectRecords(records) - } - } - - isAllSelected(): Observable { - return combineLatest([this.records$, this.selectedRecords$]).pipe( - take(1), - map(([records, selectedRecords]) => { - return records.every((record) => - selectedRecords.includes(record.uniqueIdentifier) - ) - }) - ) - } - - isSomeSelected(): Observable { - return combineLatest([this.records$, this.selectedRecords$]).pipe( - take(1), - map(([records, selectedRecords]) => { - const allSelected = records.every((record) => - selectedRecords.includes(record.uniqueIdentifier) - ) - const someSelected = records.some((record) => - selectedRecords.includes(record.uniqueIdentifier) - ) - return !allSelected && someSelected - }) - ) - } - - hasDraft(record: CatalogRecord): boolean { - return this.recordsRepository.recordHasDraft(record.uniqueIdentifier) - } -} diff --git a/libs/ui/search/src/index.ts b/libs/ui/search/src/index.ts index 9d2763fafd..b35e869c35 100644 --- a/libs/ui/search/src/index.ts +++ b/libs/ui/search/src/index.ts @@ -17,3 +17,4 @@ export * from './lib/record-preview-title/record-preview-title.component' export * from './lib/record-metric/record-metric.component' export * from './lib/results-list-item/results-list-item.component' export * from './lib/results-hits-number/results-hits-number.component' +export * from './lib/results-table/results-table.component' diff --git a/libs/ui/search/src/lib/results-table/results-table.component.css b/libs/ui/search/src/lib/results-table/results-table.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/feature/search/src/lib/results-table/results-table.component.html b/libs/ui/search/src/lib/results-table/results-table.component.html similarity index 91% rename from libs/feature/search/src/lib/results-table/results-table.component.html rename to libs/ui/search/src/lib/results-table/results-table.component.html index 27c50e1217..1b0e3d1225 100644 --- a/libs/feature/search/src/lib/results-table/results-table.component.html +++ b/libs/ui/search/src/lib/results-table/results-table.component.html @@ -1,13 +1,13 @@ @@ -37,7 +37,7 @@
{{ item.title }} @@ -110,7 +110,7 @@ diff --git a/libs/ui/search/src/lib/results-table/results-table.component.spec.ts b/libs/ui/search/src/lib/results-table/results-table.component.spec.ts new file mode 100644 index 0000000000..d940a4a614 --- /dev/null +++ b/libs/ui/search/src/lib/results-table/results-table.component.spec.ts @@ -0,0 +1,152 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing' +import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures' +import { ResultsTableComponent } from './results-table.component' +import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record' +import { By } from '@angular/platform-browser' +import { TranslateModule } from '@ngx-translate/core' + +describe('ResultsTableComponent', () => { + let component: ResultsTableComponent + let fixture: ComponentFixture + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [TranslateModule.forRoot()], + }).compileComponents() + + fixture = TestBed.createComponent(ResultsTableComponent) + component = fixture.componentInstance + component.records = DATASET_RECORDS + fixture.detectChanges() + }) + + it('should create', () => { + expect(component).toBeTruthy() + }) + + describe('get a list of formats and sorts them depending on priority', () => { + it('returns a list of unique formats', () => { + expect(component.getRecordFormats(DATASET_RECORDS[0])).toEqual([ + 'geojson', + 'shp', + 'pdf', + ]) + }) + }) + describe('get the badge color for given format', () => { + it('returns the color for its format', () => { + expect( + component.getBadgeColor( + component.getRecordFormats(DATASET_RECORDS[0])[0] + ) + ).toEqual('#1e5180') // geojson + }) + }) + + describe('sorting', () => { + describe('#isSortedBy', () => { + it('returns null if not sorted by this column', () => { + component.sortOrder = ['desc', 'owner'] + const sort = component.isSortedBy('title') + expect(sort).toBe(null) + }) + it('returns the sort order if the current sortBy is for this column', () => { + component.sortOrder = ['desc', 'title'] + const sort = component.isSortedBy('title') + expect(sort).toBe('desc') + }) + it('returns true if the current sortBy is for this column (multiple sorts)', () => { + component.sortOrder = [ + ['asc', 'score'], + ['desc', 'title'], + ] + expect(component.isSortedBy('title')).toBe('desc') + expect(component.isSortedBy('score')).toBe('asc') + expect(component.isSortedBy('owner')).toBe(null) + }) + }) + }) + + describe('selection', () => { + beforeEach(() => { + component.records = [ + { + uniqueIdentifier: '1', + }, + { + uniqueIdentifier: '2', + }, + { + uniqueIdentifier: '3', + }, + ] as any + }) + + describe('#isChecked', () => { + it('should return true when the record is in the selectedRecords array', () => { + component.selectedRecordsIdentifiers = ['1', '2'] + const record = { uniqueIdentifier: '2' } as CatalogRecord + expect(component.isChecked(record)).toBe(true) + }) + + it('should return false when the record is not in the selectedRecords array', () => { + component.selectedRecordsIdentifiers = ['1', '2', '3'] + const record = { uniqueIdentifier: '4' } as CatalogRecord + expect(component.isChecked(record)).toBe(false) + }) + }) + + describe('#handleRecordSelectedChange', () => { + it('should call selectRecords when checkbox is clicked', () => { + const record = { uniqueIdentifier: '1' } + let emitted = null + component.recordsSelectedChange.subscribe((e) => (emitted = e)) + component.handleRecordSelectedChange(true, record as CatalogRecord) + expect(emitted).toEqual([[record], true]) + }) + }) + + describe('#isAllSelected', () => { + it('returns true if all records in the page are selected', () => { + component.selectedRecordsIdentifiers = ['1', '2', '3', '4', '5'] + expect(component.isAllSelected()).toBe(true) + }) + it('returns false otherwise', () => { + component.selectedRecordsIdentifiers = ['1'] + expect(component.isAllSelected()).toBe(false) + }) + }) + + describe('#isSomeSelected', () => { + it('returns false if all records in the page are selected', () => { + component.selectedRecordsIdentifiers = ['1', '2', '3', '4', '5'] + expect(component.isSomeSelected()).toBe(false) + }) + it('returns true if one or more records in the page is selected', () => { + component.selectedRecordsIdentifiers = ['2', '3'] + expect(component.isSomeSelected()).toBe(true) + }) + it('returns false if no record in the page is selected', () => { + component.selectedRecordsIdentifiers = ['4', '5'] + expect(component.isSomeSelected()).toBe(false) + }) + }) + }) + + describe('clicking on a dataset', () => { + let clickedRecord: CatalogRecord + + beforeEach(() => { + clickedRecord = null + component.recordClick.subscribe((r) => (clickedRecord = r)) + }) + + it('emits a recordClick event', () => { + const tableRow = fixture.debugElement.queryAll( + By.css('.table-row-cell') + )[1].nativeElement as HTMLDivElement + tableRow.parentElement.click() + expect(clickedRecord).toEqual(DATASET_RECORDS[0]) + }) + }) +}) diff --git a/libs/ui/search/src/lib/results-table/results-table.component.ts b/libs/ui/search/src/lib/results-table/results-table.component.ts new file mode 100644 index 0000000000..6752d70fdc --- /dev/null +++ b/libs/ui/search/src/lib/results-table/results-table.component.ts @@ -0,0 +1,138 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core' +import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record' +import { + FileFormat, + getBadgeColor, + getFileFormat, + getFormatPriority, +} from '@geonetwork-ui/util/shared' +import { BadgeComponent, UiInputsModule } from '@geonetwork-ui/ui/inputs' +import { + InteractiveTableColumnComponent, + InteractiveTableComponent, +} from '@geonetwork-ui/ui/layout' +import { MatIconModule } from '@angular/material/icon' +import { TranslateModule } from '@ngx-translate/core' +import { CommonModule } from '@angular/common' +import { + FieldSort, + SortByField, +} from '@geonetwork-ui/common/domain/model/search' + +@Component({ + selector: 'gn-ui-results-table', + templateUrl: './results-table.component.html', + styleUrls: ['./results-table.component.css'], + standalone: true, + imports: [ + CommonModule, + UiInputsModule, + InteractiveTableComponent, + InteractiveTableColumnComponent, + MatIconModule, + TranslateModule, + BadgeComponent, + ], +}) +export class ResultsTableComponent { + @Input() records: CatalogRecord[] = [] + @Input() selectedRecordsIdentifiers: string[] = [] + @Input() sortOrder: SortByField = null + @Input() recordHasDraft: (record: CatalogRecord) => boolean = () => false + + // emits the column (field) as well as the order + @Output() sortByChange = new EventEmitter<[string, 'asc' | 'desc']>() + @Output() recordClick = new EventEmitter() + @Output() recordsSelectedChange = new EventEmitter< + [CatalogRecord[], boolean] + >() + + dateToString(date: Date): string { + return date?.toLocaleDateString(undefined, { + year: 'numeric', + month: 'long', + day: 'numeric', + timeZone: 'UTC', + }) + } + + getStatus(isPublishedToAll: boolean | unknown) { + return isPublishedToAll ? 'published' : 'not published' + } + + getRecordFormats(record: CatalogRecord): FileFormat[] { + if (record.kind === 'service' || !('distributions' in record)) { + return [] + } + const formats = Array.from( + new Set( + record.distributions.map((distribution) => getFileFormat(distribution)) + ) + ).filter((format) => !!format) + formats.sort((a, b) => getFormatPriority(b) - getFormatPriority(a)) + return formats + } + + formatUserInfo(userInfo: string | unknown): string { + const infos = (typeof userInfo === 'string' ? userInfo : '').split('|') + if (infos && infos.length === 4) { + return `${infos[2]} ${infos[1]}` + } + return undefined + } + + getBadgeColor(format: FileFormat): string { + return getBadgeColor(format) + } + + handleRecordClick(item: unknown) { + this.recordClick.emit(item as CatalogRecord) + } + + setSortBy(col: string, order: 'asc' | 'desc') { + this.sortByChange.emit([col, order]) + } + + isSortedBy(col: string): 'desc' | 'asc' | null { + if (!this.sortOrder) { + return null + } + const sortArray = Array.isArray(this.sortOrder[0]) + ? (this.sortOrder as FieldSort[]) + : ([this.sortOrder] as FieldSort[]) + for (const sort of sortArray) { + if (sort[1] === col) { + return sort[0] + } + } + return null + } + + isChecked(record: CatalogRecord): boolean { + return this.selectedRecordsIdentifiers.includes(record.uniqueIdentifier) + } + + handleRecordSelectedChange(selected: boolean, record: CatalogRecord) { + this.recordsSelectedChange.emit([[record], selected]) + } + + async toggleSelectAll() { + this.recordsSelectedChange.emit([this.records, !this.isAllSelected()]) + } + + isAllSelected(): boolean { + return this.records.every((record) => + this.selectedRecordsIdentifiers.includes(record.uniqueIdentifier) + ) + } + + isSomeSelected(): boolean { + const allSelected = this.records.every((record) => + this.selectedRecordsIdentifiers.includes(record.uniqueIdentifier) + ) + const someSelected = this.records.some((record) => + this.selectedRecordsIdentifiers.includes(record.uniqueIdentifier) + ) + return !allSelected && someSelected + } +} From 456a1f0b9c38dfbb3ec8b2ed77a1f89e427cb184 Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Sun, 16 Jun 2024 22:58:45 +0200 Subject: [PATCH 5/9] feat(repository): add a method to get all drafts --- jest.setup.ts | 13 +++++-- .../src/lib/gn4/gn4-repository.spec.ts | 34 +++++++++++++++++++ .../repository/src/lib/gn4/gn4-repository.ts | 14 ++++++++ libs/api/repository/src/test-setup.ts | 1 + .../records-repository.interface.ts | 3 ++ 5 files changed, 63 insertions(+), 2 deletions(-) diff --git a/jest.setup.ts b/jest.setup.ts index 2bf88161fb..4ecc30487a 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -20,10 +20,19 @@ class LocalStorageRefStub { return key in this.store ? this.store[key] : null }), setItem: jest.fn((key: string, value: string) => { + this.mockLocalStorage[key] = `${value}` // we're also saving it here to be able to get it with {...localStorage} this.store[key] = `${value}` }), - removeItem: jest.fn((key: string) => delete this.store[key]), - clear: jest.fn(() => (this.store = {})), + removeItem: jest.fn((key: string) => { + delete this.mockLocalStorage[key] + delete this.store[key] + }), + clear: jest.fn(() => { + for (const key in this.store) { + delete this.mockLocalStorage[key] + } + this.store = {} + }), } public getLocalStorage() { return this.mockLocalStorage diff --git a/libs/api/repository/src/lib/gn4/gn4-repository.spec.ts b/libs/api/repository/src/lib/gn4/gn4-repository.spec.ts index 02c2089b57..3853a2e45f 100644 --- a/libs/api/repository/src/lib/gn4/gn4-repository.spec.ts +++ b/libs/api/repository/src/lib/gn4/gn4-repository.spec.ts @@ -444,4 +444,38 @@ describe('Gn4Repository', () => { }) }) }) + + describe('#getAllDrafts', () => { + beforeEach(async () => { + window.localStorage.clear() + // save 3 drafts + await firstValueFrom( + repository.saveRecordAsDraft({ + ...DATASET_RECORD_SIMPLE, + uniqueIdentifier: 'DRAFT-1', + }) + ) + await firstValueFrom( + repository.saveRecordAsDraft({ + ...DATASET_RECORD_SIMPLE, + uniqueIdentifier: 'DRAFT-2', + }) + ) + await firstValueFrom( + repository.saveRecordAsDraft({ + ...DATASET_RECORD_SIMPLE, + uniqueIdentifier: 'DRAFT-3', + }) + ) + }) + it('returns all drafts', async () => { + const drafts = await lastValueFrom(repository.getAllDrafts()) + expect(drafts.length).toBe(3) + expect(drafts.map((d) => d.uniqueIdentifier)).toEqual([ + 'DRAFT-1', + 'DRAFT-2', + 'DRAFT-3', + ]) + }) + }) }) diff --git a/libs/api/repository/src/lib/gn4/gn4-repository.ts b/libs/api/repository/src/lib/gn4/gn4-repository.ts index 036c0bd7cc..fa17388957 100644 --- a/libs/api/repository/src/lib/gn4/gn4-repository.ts +++ b/libs/api/repository/src/lib/gn4/gn4-repository.ts @@ -302,4 +302,18 @@ export class Gn4Repository implements RecordsRepositoryInterface { ) !== null ) } + + // generated by copilot + getAllDrafts(): Observable { + const items = { ...window.localStorage } + const drafts = Object.keys(items) + .filter((key) => key.startsWith('geonetwork-ui-draft-')) + .map((key) => window.localStorage.getItem(key)) + .filter((draft) => draft !== null) + return from( + Promise.all( + drafts.map((draft) => findConverterForDocument(draft).readRecord(draft)) + ) + ) + } } diff --git a/libs/api/repository/src/test-setup.ts b/libs/api/repository/src/test-setup.ts index 90bc5062ea..4c58ab7724 100644 --- a/libs/api/repository/src/test-setup.ts +++ b/libs/api/repository/src/test-setup.ts @@ -1 +1,2 @@ import 'jest-preset-angular/setup-jest' +import '../../../../jest.setup' diff --git a/libs/common/domain/src/lib/repository/records-repository.interface.ts b/libs/common/domain/src/lib/repository/records-repository.interface.ts index ee59fadea0..a8cc83aca2 100644 --- a/libs/common/domain/src/lib/repository/records-repository.interface.ts +++ b/libs/common/domain/src/lib/repository/records-repository.interface.ts @@ -52,4 +52,7 @@ export abstract class RecordsRepositoryInterface { abstract clearRecordDraft(uniqueIdentifier: string): void abstract recordHasDraft(uniqueIdentifier: string): boolean + + /** will return all pending drafts, both published and not published */ + abstract getAllDrafts(): Observable } From ea3ab3a35213e00e24d181bfad4d5435448c3bb3 Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Sun, 16 Jun 2024 23:05:45 +0200 Subject: [PATCH 6/9] feat(ME): show drafts count in sidebar --- .../dashboard-menu.component.html | 3 +++ .../dashboard-menu.component.ts | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.html b/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.html index 53ce9e6db6..ed67fe8b72 100644 --- a/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.html +++ b/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.html @@ -67,6 +67,9 @@ > edit_note dashboard.records.myDraft + {{ + draftsCount$ | async + }} drafts.length)) + + constructor(private recordsRepository: RecordsRepositoryInterface) {} +} From a7b5e41e4e648b744ee593a6155ac2446e85fa28 Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Sun, 16 Jun 2024 23:06:39 +0200 Subject: [PATCH 7/9] feat(ME): adapt existing pages to use results-table-container --- .../my-org-records.component.ts | 1 - .../app/records/records-list.component.html | 19 +++++++++++++------ .../src/app/records/records-list.component.ts | 6 ++++-- .../search-records-list.component.html | 4 ++-- .../search-records-list.component.ts | 6 ++---- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts b/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts index 4f9d13e364..eb6e675179 100644 --- a/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts +++ b/apps/metadata-editor/src/app/records/my-org-records/my-org-records.component.ts @@ -48,7 +48,6 @@ export class MyOrgRecordsComponent { this.router.getDatahubSearchRoute(), window.location.toString() ) - console.log('url', url) url.searchParams.append('publisher', this.orgName) return url.toString() } diff --git a/apps/metadata-editor/src/app/records/records-list.component.html b/apps/metadata-editor/src/app/records/records-list.component.html index cb63129efb..7b214aa574 100644 --- a/apps/metadata-editor/src/app/records/records-list.component.html +++ b/apps/metadata-editor/src/app/records/records-list.component.html @@ -1,4 +1,4 @@ -
+
-
-

{{ title }}

+
+

+ {{ title }} +

+
+ +
@@ -43,10 +48,12 @@

{{ title }}

-
- + + >
- + >
diff --git a/apps/metadata-editor/src/app/records/search-records/search-records-list.component.ts b/apps/metadata-editor/src/app/records/search-records/search-records-list.component.ts index b2bdd73645..7bd7ee44b8 100644 --- a/apps/metadata-editor/src/app/records/search-records/search-records-list.component.ts +++ b/apps/metadata-editor/src/app/records/search-records/search-records-list.component.ts @@ -1,11 +1,10 @@ import { CommonModule } from '@angular/common' import { Component } from '@angular/core' import { - ResultsTableComponent, + ResultsTableContainerComponent, SearchFacade, SearchService, } from '@geonetwork-ui/feature/search' -import { RecordsListComponent } from '../records-list.component' import { TranslateModule } from '@ngx-translate/core' import { map } from 'rxjs/operators' import { Router } from '@angular/router' @@ -24,9 +23,8 @@ import { MatIconModule } from '@angular/material/icon' imports: [ CommonModule, TranslateModule, - RecordsListComponent, RecordsCountComponent, - ResultsTableComponent, + ResultsTableContainerComponent, UiElementsModule, UiInputsModule, MatIconModule, From c2d94512e6fcd67403b2b54d5497ca15dc0b0a3c Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Sun, 16 Jun 2024 23:06:55 +0200 Subject: [PATCH 8/9] feat(ME): show drafts on draft page --- .../records/my-draft/my-draft.component.html | 19 ++++++++-- .../records/my-draft/my-draft.component.ts | 35 ++++++++++++++++--- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/apps/metadata-editor/src/app/records/my-draft/my-draft.component.html b/apps/metadata-editor/src/app/records/my-draft/my-draft.component.html index 48f670e775..de8be72269 100644 --- a/apps/metadata-editor/src/app/records/my-draft/my-draft.component.html +++ b/apps/metadata-editor/src/app/records/my-draft/my-draft.component.html @@ -1,2 +1,17 @@ - - +
+
+

+ dashboard.records.myDraft +

+
+ +
+ +
+
diff --git a/apps/metadata-editor/src/app/records/my-draft/my-draft.component.ts b/apps/metadata-editor/src/app/records/my-draft/my-draft.component.ts index 36c10fe8ae..cd9d312037 100644 --- a/apps/metadata-editor/src/app/records/my-draft/my-draft.component.ts +++ b/apps/metadata-editor/src/app/records/my-draft/my-draft.component.ts @@ -2,17 +2,44 @@ import { Component } from '@angular/core' import { CommonModule } from '@angular/common' import { TranslateModule } from '@ngx-translate/core' import { RecordsListComponent } from '../records-list.component' -import { SearchFacade } from '@geonetwork-ui/feature/search' +import { ResultsTableContainerComponent } from '@geonetwork-ui/feature/search' +import { ButtonComponent } from '@geonetwork-ui/ui/inputs' +import { MatIconModule } from '@angular/material/icon' +import { RecordsCountComponent } from '../records-count/records-count.component' +import { UiElementsModule } from '@geonetwork-ui/ui/elements' +import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' +import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record' +import { Router } from '@angular/router' +import { ResultsTableComponent } from '@geonetwork-ui/ui/search' +import { startWith } from 'rxjs' @Component({ selector: 'md-editor-my-my-draft', templateUrl: './my-draft.component.html', styleUrls: ['./my-draft.component.css'], standalone: true, - imports: [CommonModule, TranslateModule, RecordsListComponent], + imports: [ + CommonModule, + TranslateModule, + RecordsListComponent, + ButtonComponent, + MatIconModule, + RecordsCountComponent, + ResultsTableContainerComponent, + UiElementsModule, + ResultsTableComponent, + ], }) export class MyDraftComponent { - constructor(public searchFacade: SearchFacade) { - this.searchFacade.resetSearch() + records$ = this.recordsRepository.getAllDrafts().pipe(startWith([])) + hasDraft = () => true + + constructor( + private router: Router, + public recordsRepository: RecordsRepositoryInterface + ) {} + + editRecord(record: CatalogRecord) { + this.router.navigate(['/edit', record.uniqueIdentifier]) } } From 41386e7e4063d5ae9f4ce2ebefe504b643abfc3b Mon Sep 17 00:00:00 2001 From: Olivia Guyot Date: Mon, 17 Jun 2024 00:11:55 +0200 Subject: [PATCH 9/9] chore(ME): fix tests --- .../dashboard-menu.component.spec.ts | 10 +++++++++ .../sidebar/sidebar.component.spec.ts | 10 +++++++++ .../my-draft/my-draft.component.spec.ts | 22 +++++++++---------- .../records/records-list.component.spec.ts | 17 +++++++++----- .../search-records-list.component.spec.ts | 8 +++---- 5 files changed, 47 insertions(+), 20 deletions(-) diff --git a/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.spec.ts b/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.spec.ts index 823b8eb3af..2e04d1d6f7 100644 --- a/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.spec.ts +++ b/apps/metadata-editor/src/app/dashboard/dashboard-menu/dashboard-menu.component.spec.ts @@ -4,6 +4,12 @@ import { ActivatedRoute } from '@angular/router' import { TranslateModule } from '@ngx-translate/core' import { of } from 'rxjs' import { DashboardMenuComponent } from './dashboard-menu.component' +import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures' +import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' + +class RecordsRepositoryMock { + getAllDrafts = jest.fn().mockReturnValue(of(DATASET_RECORDS)) +} describe('DashboardMenuComponent', () => { let component: DashboardMenuComponent @@ -17,6 +23,10 @@ describe('DashboardMenuComponent', () => { provide: ActivatedRoute, useValue: { params: of({ id: 1 }) }, }, + { + provide: RecordsRepositoryInterface, + useClass: RecordsRepositoryMock, + }, ], schemas: [NO_ERRORS_SCHEMA], }).compileComponents() diff --git a/apps/metadata-editor/src/app/dashboard/sidebar/sidebar.component.spec.ts b/apps/metadata-editor/src/app/dashboard/sidebar/sidebar.component.spec.ts index b036c7dd07..08fcdb3314 100644 --- a/apps/metadata-editor/src/app/dashboard/sidebar/sidebar.component.spec.ts +++ b/apps/metadata-editor/src/app/dashboard/sidebar/sidebar.component.spec.ts @@ -4,6 +4,12 @@ import { of } from 'rxjs' import { SidebarComponent } from './sidebar.component' import { ActivatedRoute } from '@angular/router' import { TranslateModule } from '@ngx-translate/core' +import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures' +import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' + +class RecordsRepositoryMock { + getAllDrafts = jest.fn().mockReturnValue(of(DATASET_RECORDS)) +} describe('SidebarComponent', () => { let component: SidebarComponent @@ -17,6 +23,10 @@ describe('SidebarComponent', () => { provide: ActivatedRoute, useValue: { params: of({ id: 1 }) }, }, + { + provide: RecordsRepositoryInterface, + useClass: RecordsRepositoryMock, + }, ], schemas: [NO_ERRORS_SCHEMA], }) diff --git a/apps/metadata-editor/src/app/records/my-draft/my-draft.component.spec.ts b/apps/metadata-editor/src/app/records/my-draft/my-draft.component.spec.ts index b6f7b1ba75..4c42919839 100644 --- a/apps/metadata-editor/src/app/records/my-draft/my-draft.component.spec.ts +++ b/apps/metadata-editor/src/app/records/my-draft/my-draft.component.spec.ts @@ -1,9 +1,11 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { MyDraftComponent } from './my-draft.component' -import { SearchFacade } from '@geonetwork-ui/feature/search' import { Component, importProvidersFrom } from '@angular/core' import { TranslateModule } from '@ngx-translate/core' import { RecordsListComponent } from '../records-list.component' +import { of } from 'rxjs' +import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures' +import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface' @Component({ selector: 'md-editor-records-list', @@ -12,22 +14,21 @@ import { RecordsListComponent } from '../records-list.component' }) export class MockRecordsListComponent {} -class SearchFacadeMock { - resetSearch = jest.fn() +class RecordsRepositoryMock { + getAllDrafts = jest.fn().mockReturnValue(of(DATASET_RECORDS)) } describe('MyDraftComponent', () => { let component: MyDraftComponent let fixture: ComponentFixture - let searchFacade: SearchFacade beforeEach(() => { TestBed.configureTestingModule({ providers: [ importProvidersFrom(TranslateModule.forRoot()), { - provide: SearchFacade, - useClass: SearchFacadeMock, + provide: RecordsRepositoryInterface, + useClass: RecordsRepositoryMock, }, ], }).overrideComponent(MyDraftComponent, { @@ -38,7 +39,6 @@ describe('MyDraftComponent', () => { imports: [MockRecordsListComponent], }, }) - searchFacade = TestBed.inject(SearchFacade) fixture = TestBed.createComponent(MyDraftComponent) component = fixture.componentInstance fixture.detectChanges() @@ -48,9 +48,9 @@ describe('MyDraftComponent', () => { expect(component).toBeTruthy() }) - describe('filters', () => { - it('clears filters on init', () => { - expect(searchFacade.resetSearch).toHaveBeenCalled() - }) + it('gets all drafts on init', () => { + expect( + TestBed.inject(RecordsRepositoryInterface).getAllDrafts + ).toHaveBeenCalled() }) }) diff --git a/apps/metadata-editor/src/app/records/records-list.component.spec.ts b/apps/metadata-editor/src/app/records/records-list.component.spec.ts index 8ee505a3d7..579cf33780 100644 --- a/apps/metadata-editor/src/app/records/records-list.component.spec.ts +++ b/apps/metadata-editor/src/app/records/records-list.component.spec.ts @@ -8,7 +8,6 @@ import { Router } from '@angular/router' import { BehaviorSubject } from 'rxjs' import { CommonModule } from '@angular/common' import { MatIconModule } from '@angular/material/icon' -import { SelectionService } from '@geonetwork-ui/api/repository' import { DATASET_RECORDS } from '@geonetwork-ui/common/fixtures' const results = [{ md: true }] @@ -17,11 +16,11 @@ const totalPages = 25 @Component({ // eslint-disable-next-line @angular-eslint/component-selector - selector: 'gn-ui-results-table', + selector: 'gn-ui-results-table-container', template: '', standalone: true, }) -export class RecordTableComponent { +export class ResultsTableContainerComponent { @Output() recordClick = new EventEmitter() } @@ -38,6 +37,13 @@ export class PaginationButtonsComponent { @Output() newCurrentPageEvent = new EventEmitter() } +@Component({ + selector: 'md-editor-records-count', + template: '', + standalone: true, +}) +export class RecordsCountComponent {} + class SearchFacadeMock { results$ = new BehaviorSubject(results) currentPage$ = new BehaviorSubject(currentPage) @@ -82,8 +88,9 @@ describe('RecordsListComponent', () => { imports: [ CommonModule, MatIconModule, - RecordTableComponent, + ResultsTableContainerComponent, PaginationButtonsComponent, + RecordsCountComponent, ], }, }) @@ -102,7 +109,7 @@ describe('RecordsListComponent', () => { let table, pagination beforeEach(() => { table = fixture.debugElement.query( - By.directive(RecordTableComponent) + By.directive(ResultsTableContainerComponent) ).componentInstance pagination = fixture.debugElement.query( By.directive(PaginationButtonsComponent) diff --git a/apps/metadata-editor/src/app/records/search-records/search-records-list.component.spec.ts b/apps/metadata-editor/src/app/records/search-records/search-records-list.component.spec.ts index 7d44779e66..600317c1ff 100644 --- a/apps/metadata-editor/src/app/records/search-records/search-records-list.component.spec.ts +++ b/apps/metadata-editor/src/app/records/search-records/search-records-list.component.spec.ts @@ -24,11 +24,11 @@ const totalPages = 25 @Component({ // eslint-disable-next-line @angular-eslint/component-selector - selector: 'gn-ui-results-table', + selector: 'gn-ui-results-table-container', template: '', standalone: true, }) -export class RecordTableComponent { +export class ResultsTableContainerComponent { @Output() recordClick = new EventEmitter() } @@ -103,7 +103,7 @@ describe('SearchRecordsComponent', () => { CommonModule, TranslateModule, MatIconModule, - RecordTableComponent, + ResultsTableContainerComponent, PaginationButtonsComponent, UiInputsModule, RecordsCountComponent, @@ -125,7 +125,7 @@ describe('SearchRecordsComponent', () => { let table, pagination beforeEach(() => { table = fixture.debugElement.query( - By.directive(RecordTableComponent) + By.directive(ResultsTableContainerComponent) ).componentInstance pagination = fixture.debugElement.query( By.directive(PaginationButtonsComponent)