geonetwork-ui 2.4.2 → 2.5.0-dev.6d78023ff

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.mjs +17 -5
  2. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +2 -2
  3. package/esm2022/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.mjs +18 -16
  4. package/esm2022/libs/feature/dataviz/src/lib/table-view/table-view.component.mjs +12 -17
  5. package/esm2022/libs/feature/editor/src/lib/components/wizard-summarize/wizard-summarize.component.mjs +11 -11
  6. package/esm2022/libs/feature/record/src/lib/data-view/data-view.component.mjs +3 -3
  7. package/esm2022/libs/feature/record/src/lib/feature-record.module.mjs +6 -7
  8. package/esm2022/libs/ui/dataviz/src/index.mjs +3 -3
  9. package/esm2022/libs/ui/dataviz/src/lib/data-table/custom.mat.paginator.intl.mjs +51 -0
  10. package/esm2022/libs/ui/dataviz/src/lib/data-table/data-table.component.mjs +133 -0
  11. package/esm2022/libs/ui/dataviz/src/lib/data-table/data-table.data.source.mjs +24 -0
  12. package/esm2022/libs/ui/dataviz/src/lib/data-table/data-table.fixtures.mjs +82 -0
  13. package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +18 -10
  14. package/esm2022/libs/ui/search/src/lib/results-table/results-table.component.mjs +14 -12
  15. package/esm2022/libs/util/data-fetcher/src/index.mjs +3 -1
  16. package/esm2022/libs/util/data-fetcher/src/lib/model.mjs +7 -3
  17. package/esm2022/libs/util/data-fetcher/src/lib/readers/wfs.mjs +20 -2
  18. package/esm2022/libs/util/data-fetcher/src/lib/utils.mjs +3 -3
  19. package/esm2022/libs/util/shared/src/lib/services/date.service.mjs +41 -0
  20. package/esm2022/libs/util/shared/src/lib/services/index.mjs +2 -1
  21. package/esm2022/libs/util/shared/src/lib/utils/temporal-extent-union.mjs +4 -4
  22. package/esm2022/translations/de.json +7 -0
  23. package/esm2022/translations/en.json +7 -0
  24. package/esm2022/translations/es.json +7 -0
  25. package/esm2022/translations/fr.json +7 -0
  26. package/esm2022/translations/it.json +7 -0
  27. package/esm2022/translations/nl.json +7 -0
  28. package/esm2022/translations/pt.json +7 -0
  29. package/fesm2022/geonetwork-ui.mjs +665 -368
  30. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  31. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts +2 -1
  32. package/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.d.ts.map +1 -1
  33. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  34. package/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.d.ts +7 -9
  35. package/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.d.ts.map +1 -1
  36. package/libs/feature/dataviz/src/lib/table-view/table-view.component.d.ts +3 -6
  37. package/libs/feature/dataviz/src/lib/table-view/table-view.component.d.ts.map +1 -1
  38. package/libs/feature/editor/src/lib/components/wizard-summarize/wizard-summarize.component.d.ts +3 -3
  39. package/libs/feature/editor/src/lib/components/wizard-summarize/wizard-summarize.component.d.ts.map +1 -1
  40. package/libs/feature/record/src/lib/feature-record.module.d.ts +2 -2
  41. package/libs/feature/record/src/lib/feature-record.module.d.ts.map +1 -1
  42. package/libs/ui/dataviz/src/index.d.ts +2 -2
  43. package/libs/ui/dataviz/src/index.d.ts.map +1 -1
  44. package/libs/ui/dataviz/src/lib/data-table/custom.mat.paginator.intl.d.ts +14 -0
  45. package/libs/ui/dataviz/src/lib/data-table/custom.mat.paginator.intl.d.ts.map +1 -0
  46. package/libs/ui/dataviz/src/lib/data-table/data-table.component.d.ts +45 -0
  47. package/libs/ui/dataviz/src/lib/data-table/data-table.component.d.ts.map +1 -0
  48. package/libs/ui/dataviz/src/lib/data-table/data-table.data.source.d.ts +12 -0
  49. package/libs/ui/dataviz/src/lib/data-table/data-table.data.source.d.ts.map +1 -0
  50. package/libs/ui/dataviz/src/lib/data-table/data-table.fixtures.d.ts +10 -0
  51. package/libs/ui/dataviz/src/lib/data-table/data-table.fixtures.d.ts.map +1 -0
  52. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts +5 -0
  53. package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts.map +1 -1
  54. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts +3 -2
  55. package/libs/ui/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
  56. package/libs/util/data-fetcher/src/index.d.ts +3 -1
  57. package/libs/util/data-fetcher/src/index.d.ts.map +1 -1
  58. package/libs/util/data-fetcher/src/lib/model.d.ts +1 -1
  59. package/libs/util/data-fetcher/src/lib/model.d.ts.map +1 -1
  60. package/libs/util/data-fetcher/src/lib/readers/wfs.d.ts.map +1 -1
  61. package/libs/util/shared/src/lib/services/date.service.d.ts +13 -0
  62. package/libs/util/shared/src/lib/services/date.service.d.ts.map +1 -0
  63. package/libs/util/shared/src/lib/services/index.d.ts +1 -0
  64. package/libs/util/shared/src/lib/services/index.d.ts.map +1 -1
  65. package/libs/util/shared/src/lib/utils/temporal-extent-union.d.ts +2 -1
  66. package/libs/util/shared/src/lib/utils/temporal-extent-union.d.ts.map +1 -1
  67. package/package.json +1 -1
  68. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +19 -5
  69. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +1 -5
  70. package/src/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.html +3 -3
  71. package/src/libs/feature/dataviz/src/lib/geo-table-view/geo-table-view.component.ts +17 -15
  72. package/src/libs/feature/dataviz/src/lib/table-view/table-view.component.html +4 -3
  73. package/src/libs/feature/dataviz/src/lib/table-view/table-view.component.ts +9 -18
  74. package/src/libs/feature/editor/src/lib/components/wizard-summarize/wizard-summarize.component.ts +3 -4
  75. package/src/libs/feature/record/src/lib/data-view/data-view.component.html +1 -1
  76. package/src/libs/feature/record/src/lib/feature-record.module.ts +6 -4
  77. package/src/libs/ui/dataviz/src/index.ts +2 -2
  78. package/src/libs/ui/dataviz/src/lib/data-table/custom.mat.paginator.intl.ts +52 -0
  79. package/src/libs/ui/dataviz/src/lib/{table/table.component.css → data-table/data-table.component.css} +4 -0
  80. package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.html +67 -0
  81. package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.ts +173 -0
  82. package/src/libs/ui/dataviz/src/lib/data-table/data-table.data.source.ts +33 -0
  83. package/src/libs/ui/dataviz/src/lib/data-table/data-table.fixtures.ts +84 -0
  84. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +3 -3
  85. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +12 -2
  86. package/src/libs/ui/search/src/lib/results-table/results-table.component.ts +4 -2
  87. package/src/libs/util/data-fetcher/src/index.ts +3 -0
  88. package/src/libs/util/data-fetcher/src/lib/model.ts +6 -2
  89. package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +23 -1
  90. package/src/libs/util/data-fetcher/src/lib/utils.ts +2 -2
  91. package/src/libs/util/shared/src/lib/services/date.service.ts +45 -0
  92. package/src/libs/util/shared/src/lib/services/index.ts +1 -0
  93. package/src/libs/util/shared/src/lib/utils/temporal-extent-union.ts +6 -3
  94. package/translations/de.json +7 -0
  95. package/translations/en.json +7 -0
  96. package/translations/es.json +7 -0
  97. package/translations/fr.json +7 -0
  98. package/translations/it.json +7 -0
  99. package/translations/nl.json +7 -0
  100. package/translations/pt.json +7 -0
  101. package/translations/sk.json +7 -0
  102. package/esm2022/libs/ui/dataviz/src/lib/table/table.component.mjs +0 -61
  103. package/esm2022/libs/ui/dataviz/src/lib/table/table.fixtures.mjs +0 -40
  104. package/libs/ui/dataviz/src/lib/table/table.component.d.ts +0 -29
  105. package/libs/ui/dataviz/src/lib/table/table.component.d.ts.map +0 -1
  106. package/libs/ui/dataviz/src/lib/table/table.fixtures.d.ts +0 -11
  107. package/libs/ui/dataviz/src/lib/table/table.fixtures.d.ts.map +0 -1
  108. package/src/libs/ui/dataviz/src/lib/table/table.component.html +0 -40
  109. package/src/libs/ui/dataviz/src/lib/table/table.component.ts +0 -80
  110. package/src/libs/ui/dataviz/src/lib/table/table.fixtures.ts +0 -40
@@ -8,7 +8,7 @@ import {
8
8
  ViewChild,
9
9
  } from '@angular/core'
10
10
  import {
11
- TableComponent,
11
+ DataTableComponent,
12
12
  TableItemId,
13
13
  TableItemModel,
14
14
  } from '../../../../../../libs/ui/dataviz/src'
@@ -19,18 +19,19 @@ import {
19
19
  FeatureDetailComponent,
20
20
  MapContainerComponent,
21
21
  } from '../../../../../../libs/ui/map/src'
22
+ import { BaseReader } from '../../../../../../libs/util/data-fetcher/src'
22
23
 
23
24
  @Component({
24
25
  selector: 'gn-ui-geo-table-view',
25
26
  templateUrl: './geo-table-view.component.html',
26
27
  styleUrls: ['./geo-table-view.component.css'],
27
28
  changeDetection: ChangeDetectionStrategy.OnPush,
28
- imports: [TableComponent, MapContainerComponent, FeatureDetailComponent],
29
+ imports: [MapContainerComponent, FeatureDetailComponent, DataTableComponent],
29
30
  standalone: true,
30
31
  })
31
32
  export class GeoTableViewComponent implements OnInit, OnDestroy {
32
- @Input() data: FeatureCollection = { type: 'FeatureCollection', features: [] }
33
- @ViewChild('table') uiTable: TableComponent
33
+ @Input() dataset: BaseReader
34
+ @ViewChild('table') uiTable: DataTableComponent
34
35
  @ViewChild('mapContainer') mapContainer: MapContainerComponent
35
36
 
36
37
  tableData: TableItemModel[]
@@ -39,21 +40,16 @@ export class GeoTableViewComponent implements OnInit, OnDestroy {
39
40
  selection: Feature
40
41
  private subscription = new Subscription()
41
42
 
42
- get features() {
43
- return this.data.features
44
- }
45
-
46
43
  constructor(private changeRef: ChangeDetectorRef) {}
47
44
 
48
- ngOnInit(): void {
49
- this.tableData = this.geojsonToTableData(this.data)
50
- this.mapContext = this.initMapContext()
45
+ async ngOnInit() {
46
+ this.mapContext = await this.initMapContext()
51
47
  }
52
48
 
53
49
  onTableSelect(tableEntry: TableItemModel) {
54
50
  const { id } = tableEntry
55
51
  this.selectionId = id
56
- this.selection = this.getFeatureFromId(id)
52
+ // this.selection = this.getFeatureFromId(id)
57
53
  if (this.selection) {
58
54
  this.animateToFeature(this.selection)
59
55
  }
@@ -77,7 +73,8 @@ export class GeoTableViewComponent implements OnInit, OnDestroy {
77
73
  }))
78
74
  }
79
75
 
80
- private initMapContext(): MapContext {
76
+ private async initMapContext(): Promise<MapContext> {
77
+ this.dataset.selectAll()
81
78
  return {
82
79
  layers: [
83
80
  {
@@ -86,7 +83,11 @@ export class GeoTableViewComponent implements OnInit, OnDestroy {
86
83
  },
87
84
  {
88
85
  type: 'geojson',
89
- data: this.data,
86
+ data: {
87
+ type: 'FeatureCollection',
88
+ // FIXME: we're not getting geojson here
89
+ features: await this.dataset.read(),
90
+ },
90
91
  },
91
92
  ],
92
93
  view: {
@@ -112,7 +113,8 @@ export class GeoTableViewComponent implements OnInit, OnDestroy {
112
113
  }
113
114
 
114
115
  private getFeatureFromId(id: TableItemId) {
115
- return this.features.find((feature) => feature.id === id)
116
+ // FIXME: restore this once we need it?
117
+ // return this.features.find((feature) => feature.id === id)
116
118
  }
117
119
 
118
120
  ngOnDestroy(): void {
@@ -1,10 +1,11 @@
1
1
  <div class="w-full h-full flex flex-col">
2
2
  <div class="relative h-full">
3
- <gn-ui-table
3
+ <gn-ui-data-table
4
+ *ngIf="tableData$ | async as dataset"
4
5
  class="overflow-auto grow"
5
- [data]="tableData$ | async"
6
+ [dataset]="dataset"
6
7
  (selected)="onTableSelect($event)"
7
- ></gn-ui-table>
8
+ ></gn-ui-data-table>
8
9
  <gn-ui-loading-mask
9
10
  *ngIf="loading"
10
11
  class="absolute inset-0"
@@ -3,14 +3,13 @@ import { BehaviorSubject, Observable, of } from 'rxjs'
3
3
  import {
4
4
  catchError,
5
5
  finalize,
6
- map,
7
6
  shareReplay,
8
7
  startWith,
9
8
  switchMap,
10
9
  } from 'rxjs/operators'
11
- import { DataItem, FetchError } from '../../../../../../libs/util/data-fetcher/src'
10
+ import { BaseReader, FetchError } from '../../../../../../libs/util/data-fetcher/src'
12
11
  import { DataService } from '../service/data.service'
13
- import { TableComponent, TableItemModel } from '../../../../../../libs/ui/dataviz/src'
12
+ import { DataTableComponent } from '../../../../../../libs/ui/dataviz/src'
14
13
  import { DatasetOnlineResource } from '../../../../../../libs/common/domain/src/lib/model/record'
15
14
  import { TranslateModule, TranslateService } from '@ngx-translate/core'
16
15
  import {
@@ -26,7 +25,7 @@ import { CommonModule } from '@angular/common'
26
25
  changeDetection: ChangeDetectionStrategy.OnPush,
27
26
  imports: [
28
27
  CommonModule,
29
- TableComponent,
28
+ DataTableComponent,
30
29
  LoadingMaskComponent,
31
30
  PopupAlertComponent,
32
31
  TranslateModule,
@@ -45,25 +44,19 @@ export class TableViewComponent {
45
44
  tableData$ = this.currentLink$.pipe(
46
45
  switchMap((link) => {
47
46
  this.error = null
48
- if (!link) return of([] as TableItemModel[])
47
+ if (!link) return of(undefined)
49
48
  this.loading = true
50
- return this.fetchData(link).pipe(
51
- map((items) =>
52
- items.map((item) => ({
53
- id: item.id,
54
- ...item.properties,
55
- }))
56
- ),
49
+ return this.getDatasetReader(link).pipe(
57
50
  catchError((error) => {
58
51
  this.handleError(error)
59
- return of([] as TableItemModel[])
52
+ return of(undefined)
60
53
  }),
61
54
  finalize(() => {
62
55
  this.loading = false
63
56
  })
64
57
  )
65
58
  }),
66
- startWith([] as TableItemModel[]),
59
+ startWith(undefined),
67
60
  shareReplay(1)
68
61
  )
69
62
 
@@ -72,10 +65,8 @@ export class TableViewComponent {
72
65
  private translateService: TranslateService
73
66
  ) {}
74
67
 
75
- fetchData(link: DatasetOnlineResource): Observable<DataItem[]> {
76
- return this.dataService
77
- .getDataset(link)
78
- .pipe(switchMap((dataset) => dataset.read()))
68
+ getDatasetReader(link: DatasetOnlineResource): Observable<BaseReader> {
69
+ return this.dataService.getDataset(link)
79
70
  }
80
71
 
81
72
  onTableSelect(event) {
@@ -1,6 +1,6 @@
1
1
  import { Component } from '@angular/core'
2
2
  import { WizardService } from '../../services/wizard.service'
3
- import { TranslateService } from '@ngx-translate/core'
3
+ import { DateService } from '../../../../../../../libs/util/shared/src'
4
4
 
5
5
  @Component({
6
6
  selector: 'gn-ui-wizard-summarize',
@@ -28,9 +28,8 @@ export class WizardSummarizeComponent {
28
28
 
29
29
  get createdDate() {
30
30
  const time = this.wizardService.getWizardFieldData('datepicker')
31
- const locale = this.translateService.currentLang
32
31
 
33
- return new Date(Number(time)).toLocaleDateString(locale, {
32
+ return this.dateService.formatDate(new Date(Number(time)), {
34
33
  year: 'numeric',
35
34
  month: 'long',
36
35
  day: 'numeric',
@@ -54,6 +53,6 @@ export class WizardSummarizeComponent {
54
53
 
55
54
  constructor(
56
55
  private wizardService: WizardService,
57
- private translateService: TranslateService
56
+ private dateService: DateService
58
57
  ) {}
59
58
  }
@@ -8,7 +8,7 @@
8
8
  [choices]="choices"
9
9
  (selectValue)="selectLink($event)"
10
10
  ></gn-ui-dropdown-selector>
11
- <div class="relative h-[420px]">
11
+ <div class="relative h-[460px]">
12
12
  <gn-ui-table-view
13
13
  *ngIf="mode === 'table'"
14
14
  [link]="selectedLink$ | async"
@@ -4,7 +4,10 @@ import { StoreModule } from '@ngrx/store'
4
4
  import { EffectsModule } from '@ngrx/effects'
5
5
  import { UiLayoutModule } from '../../../../../libs/ui/layout/src'
6
6
  import { FeatureMapModule } from '../../../../../libs/feature/map/src'
7
- import { UiInputsModule } from '../../../../../libs/ui/inputs/src'
7
+ import {
8
+ DropdownSelectorComponent,
9
+ UiInputsModule,
10
+ } from '../../../../../libs/ui/inputs/src'
8
11
  import { UiElementsModule } from '../../../../../libs/ui/elements/src'
9
12
  import { MdViewFacade } from './state'
10
13
  import { MdViewEffects } from './state/mdview.effects'
@@ -16,9 +19,8 @@ import { MatTabsModule } from '@angular/material/tabs'
16
19
  import { UiWidgetsModule } from '../../../../../libs/ui/widgets/src'
17
20
  import { TranslateModule } from '@ngx-translate/core'
18
21
  import { FeatureCatalogModule } from '../../../../../libs/feature/catalog/src'
19
- import { TableComponent } from '../../../../../libs/ui/dataviz/src'
22
+ import { DataTableComponent } from '../../../../../libs/ui/dataviz/src'
20
23
  import { NgIconsModule, provideNgIconsConfig } from '@ng-icons/core'
21
- import { DropdownSelectorComponent } from '../../../../../libs/ui/inputs/src'
22
24
 
23
25
  @NgModule({
24
26
  imports: [
@@ -33,7 +35,7 @@ import { DropdownSelectorComponent } from '../../../../../libs/ui/inputs/src'
33
35
  MatTabsModule,
34
36
  UiWidgetsModule,
35
37
  TranslateModule,
36
- TableComponent,
38
+ DataTableComponent,
37
39
  NgIconsModule,
38
40
  DropdownSelectorComponent,
39
41
  ],
@@ -1,5 +1,5 @@
1
1
  export * from './lib/ui-dataviz.module'
2
2
  export * from './lib/chart/chart.component'
3
- export * from './lib/table/table.component'
4
- export * from './lib/table/table.fixtures'
3
+ export * from './lib/data-table/data-table.component'
4
+ export * from './lib/data-table/data-table.fixtures'
5
5
  export * from './lib/figure/figure.component'
@@ -0,0 +1,52 @@
1
+ import { Injectable } from '@angular/core'
2
+ import { MatPaginatorIntl } from '@angular/material/paginator'
3
+ import { TranslateService } from '@ngx-translate/core'
4
+ import { Subject } from 'rxjs'
5
+
6
+ @Injectable()
7
+ export class CustomMatPaginatorIntl extends MatPaginatorIntl {
8
+ override changes = new Subject<void>()
9
+
10
+ constructor(private translate: TranslateService) {
11
+ super()
12
+ this.setLabels()
13
+ this.translate.onLangChange.subscribe(() => {
14
+ this.setLabels()
15
+ this.changes.next()
16
+ })
17
+ }
18
+
19
+ setLabels() {
20
+ this.itemsPerPageLabel = this.translate.instant(
21
+ 'table.paginator.itemsPerPage'
22
+ )
23
+ this.nextPageLabel = this.translate.instant('table.paginator.nextPage')
24
+ this.previousPageLabel = this.translate.instant(
25
+ 'table.paginator.previousPage'
26
+ )
27
+ this.firstPageLabel = this.translate.instant('table.paginator.firstPage')
28
+ this.lastPageLabel = this.translate.instant('table.paginator.lastPage')
29
+ this.getRangeLabel = this.getRangeLabelIntl
30
+ this.changes.next()
31
+ }
32
+
33
+ getRangeLabelIntl(page: number, pageSize: number, length: number): string {
34
+ if (length === 0 || pageSize === 0) {
35
+ return this.translate.instant('table.paginator.rangeLabel', {
36
+ startIndex: 0,
37
+ endIndex: 0,
38
+ length,
39
+ })
40
+ }
41
+ const startIndex = page * pageSize
42
+ const endIndex =
43
+ startIndex < length
44
+ ? Math.min(startIndex + pageSize, length)
45
+ : startIndex + pageSize
46
+ return this.translate.instant('table.paginator.rangeLabel', {
47
+ startIndex: startIndex + 1,
48
+ endIndex,
49
+ length,
50
+ })
51
+ }
52
+ }
@@ -30,3 +30,7 @@ tr {
30
30
  .active .mat-mdc-cell {
31
31
  color: var(--color-primary);
32
32
  }
33
+
34
+ .mat-mdc-paginator {
35
+ background: none;
36
+ }
@@ -0,0 +1,67 @@
1
+ <div class="flex flex-col border border-gray-300 rounded-lg bg-white h-full">
2
+ <div class="flex-1 overflow-y-hidden overflow-x-auto rounded-lg relative">
3
+ <table
4
+ mat-table
5
+ [dataSource]="dataSource"
6
+ matSort
7
+ (matSortChange)="setSort($event)"
8
+ [matSortDisableClear]="true"
9
+ *ngrxLet="properties$ as properties"
10
+ >
11
+ <ng-container *ngFor="let prop of properties" [matColumnDef]="prop">
12
+ <th
13
+ mat-header-cell
14
+ *matHeaderCellDef
15
+ mat-sort-header
16
+ class="text-sm text-black bg-white"
17
+ >
18
+ {{ prop }}
19
+ </th>
20
+ <td
21
+ mat-cell
22
+ *matCellDef="let element"
23
+ class="whitespace-nowrap pr-1 truncate"
24
+ >
25
+ {{ element[prop] }}
26
+ </td>
27
+ </ng-container>
28
+
29
+ <tr mat-header-row *matHeaderRowDef="properties; sticky: true"></tr>
30
+ <tr
31
+ [id]="getRowEltId(row.id)"
32
+ mat-row
33
+ *matRowDef="let row; columns: properties"
34
+ (click)="selected.emit(row)"
35
+ [class.active]="row.id === activeId"
36
+ ></tr>
37
+ </table>
38
+ <gn-ui-loading-mask
39
+ *ngIf="loading$ | async"
40
+ class="sticky inset-0"
41
+ [message]="'table.loading.data' | translate"
42
+ ></gn-ui-loading-mask>
43
+ <gn-ui-popup-alert
44
+ *ngIf="error"
45
+ type="warning"
46
+ icon="matErrorOutlineOutline"
47
+ class="absolute m-2 inset-0 z-[100]"
48
+ >
49
+ <span translate>{{ error }}</span>
50
+ </gn-ui-popup-alert>
51
+ </div>
52
+ <div class="flex justify-between items-center overflow-hidden">
53
+ <div class="text-gray-900 px-4 py-2 text-sm">
54
+ <span class="count font-extrabold text-primary">{{ count }}</span
55
+ >&nbsp;<span translate>table.object.count</span>.
56
+ </div>
57
+
58
+ <mat-paginator
59
+ class="my-[-16px]"
60
+ (page)="setPagination()"
61
+ [length]="count"
62
+ [pageSize]="10"
63
+ [showFirstLastButtons]="true"
64
+ [hidePageSize]="true"
65
+ ></mat-paginator>
66
+ </div>
67
+ </div>
@@ -0,0 +1,173 @@
1
+ import { ScrollingModule } from '@angular/cdk/scrolling'
2
+ import {
3
+ AfterViewInit,
4
+ ChangeDetectionStrategy,
5
+ ChangeDetectorRef,
6
+ Component,
7
+ ElementRef,
8
+ EventEmitter,
9
+ Input,
10
+ OnChanges,
11
+ OnInit,
12
+ Output,
13
+ ViewChild,
14
+ } from '@angular/core'
15
+ import { MatSort, MatSortModule } from '@angular/material/sort'
16
+ import { MatTableModule } from '@angular/material/table'
17
+ import { TranslateModule, TranslateService } from '@ngx-translate/core'
18
+ import { DataTableDataSource } from './data-table.data.source'
19
+ import { BaseReader, FetchError } from '../../../../../../libs/util/data-fetcher/src'
20
+ import {
21
+ MatPaginator,
22
+ MatPaginatorIntl,
23
+ MatPaginatorModule,
24
+ } from '@angular/material/paginator'
25
+ import { CustomMatPaginatorIntl } from './custom.mat.paginator.intl'
26
+ import { CommonModule } from '@angular/common'
27
+ import { BehaviorSubject, filter, firstValueFrom } from 'rxjs'
28
+ import {
29
+ LoadingMaskComponent,
30
+ PopupAlertComponent,
31
+ } from '../../../../../../libs/ui/widgets/src'
32
+ import { LetDirective } from '@ngrx/component'
33
+
34
+ const rowIdPrefix = 'table-item-'
35
+
36
+ export type TableItemId = string | number
37
+ type TableItemType = string | number | Date
38
+
39
+ export interface TableItemModel {
40
+ id: TableItemId
41
+ [key: string]: TableItemType
42
+ }
43
+
44
+ @Component({
45
+ standalone: true,
46
+ imports: [
47
+ MatTableModule,
48
+ MatSortModule,
49
+ MatPaginatorModule,
50
+ ScrollingModule,
51
+ TranslateModule,
52
+ CommonModule,
53
+ LoadingMaskComponent,
54
+ PopupAlertComponent,
55
+ LetDirective,
56
+ ],
57
+ providers: [{ provide: MatPaginatorIntl, useClass: CustomMatPaginatorIntl }],
58
+ selector: 'gn-ui-data-table',
59
+ templateUrl: './data-table.component.html',
60
+ styleUrls: ['./data-table.component.css'],
61
+ changeDetection: ChangeDetectionStrategy.OnPush,
62
+ })
63
+ export class DataTableComponent implements OnInit, AfterViewInit, OnChanges {
64
+ @Input() set dataset(value: BaseReader) {
65
+ this.properties$.next(null)
66
+ this.dataset_ = value
67
+ this.dataset_.load()
68
+ this.dataset_.properties.then((properties) =>
69
+ this.properties$.next(properties.map((p) => p.name))
70
+ )
71
+ this.dataset_.info.then((info) => (this.count = info.itemsCount))
72
+ }
73
+ @Input() activeId: TableItemId
74
+ @Output() selected = new EventEmitter<any>()
75
+
76
+ @ViewChild(MatSort) sort: MatSort
77
+ @ViewChild(MatPaginator) paginator: MatPaginator
78
+
79
+ dataset_: BaseReader
80
+ properties$ = new BehaviorSubject<string[]>(null)
81
+ dataSource: DataTableDataSource
82
+ headerHeight: number
83
+ count: number
84
+ loading$ = new BehaviorSubject<boolean>(false)
85
+ error = null
86
+
87
+ constructor(
88
+ private eltRef: ElementRef,
89
+ private cdr: ChangeDetectorRef,
90
+ private translateService: TranslateService
91
+ ) {}
92
+
93
+ ngOnInit() {
94
+ this.dataSource = new DataTableDataSource()
95
+ }
96
+
97
+ ngAfterViewInit() {
98
+ this.headerHeight =
99
+ this.eltRef.nativeElement.querySelector('thead').offsetHeight
100
+ this.setPagination()
101
+ this.cdr.detectChanges()
102
+ }
103
+
104
+ ngOnChanges() {
105
+ this.setPagination()
106
+ }
107
+
108
+ setSort(sort: MatSort) {
109
+ if (!this.dataset_) return
110
+ if (!sort.active) {
111
+ this.dataset_.orderBy()
112
+ } else {
113
+ this.dataset_.orderBy([sort.direction || 'asc', sort.active])
114
+ }
115
+ this.readData()
116
+ }
117
+
118
+ setPagination() {
119
+ if (!this.paginator) return
120
+ if (!this.dataset_) return
121
+ this.dataset_.limit(
122
+ this.paginator.pageIndex * this.paginator.pageSize,
123
+ this.paginator.pageSize
124
+ )
125
+ this.readData()
126
+ }
127
+
128
+ async readData() {
129
+ this.loading$.next(true)
130
+ // wait for properties to be read
131
+ const properties = await firstValueFrom(
132
+ this.properties$.pipe(filter((p) => !!p))
133
+ )
134
+ const propsWithoutGeom = properties.filter(
135
+ (p) => !p.toLowerCase().startsWith('geom')
136
+ )
137
+ this.dataset_.select(...propsWithoutGeom)
138
+ try {
139
+ await this.dataSource.showData(this.dataset_.read())
140
+ this.error = null
141
+ } catch (error) {
142
+ this.handleError(error as FetchError | Error)
143
+ }
144
+ this.loading$.next(false)
145
+ }
146
+
147
+ scrollToItem(itemId: TableItemId): void {
148
+ const row = this.eltRef.nativeElement.querySelector(
149
+ `#${this.getRowEltId(itemId)}`
150
+ )
151
+ this.eltRef.nativeElement.scrollTop = row.offsetTop - this.headerHeight
152
+ }
153
+
154
+ public getRowEltId(id: TableItemId): string {
155
+ return rowIdPrefix + id
156
+ }
157
+
158
+ handleError(error: FetchError | Error) {
159
+ this.dataSource.clearData()
160
+ if (error instanceof FetchError) {
161
+ this.error = this.translateService.instant(
162
+ `dataset.error.${error.type}`,
163
+ {
164
+ info: error.info,
165
+ }
166
+ )
167
+ console.warn(error.message)
168
+ } else {
169
+ this.error = this.translateService.instant(error.message)
170
+ console.warn(error.stack || error)
171
+ }
172
+ }
173
+ }
@@ -0,0 +1,33 @@
1
+ import { DataSource } from '@angular/cdk/collections'
2
+ import { BehaviorSubject, Observable } from 'rxjs'
3
+ import { DataItem } from '../../../../../../libs/util/data-fetcher/src'
4
+ import { map } from 'rxjs/operators'
5
+ import { TableItemModel } from './data-table.component'
6
+
7
+ export class DataTableDataSource implements DataSource<TableItemModel> {
8
+ private dataItems$ = new BehaviorSubject<DataItem[]>([])
9
+
10
+ connect(): Observable<TableItemModel[]> {
11
+ return this.dataItems$.asObservable().pipe(
12
+ map((items) =>
13
+ items.map((item) => ({
14
+ id: item.id,
15
+ ...item.properties,
16
+ }))
17
+ )
18
+ )
19
+ }
20
+
21
+ disconnect(): void {
22
+ this.dataItems$.complete()
23
+ }
24
+
25
+ async showData(itemsPromise: Promise<DataItem[]>) {
26
+ const items = await itemsPromise
27
+ this.dataItems$.next(items)
28
+ }
29
+
30
+ clearData() {
31
+ this.dataItems$.next([])
32
+ }
33
+ }
@@ -0,0 +1,84 @@
1
+ import { DataItem, PropertyInfo } from '../../../../../../libs/util/data-fetcher/src'
2
+
3
+ export const tableItemsFixture = {
4
+ items: [
5
+ {
6
+ type: 'Feature',
7
+ geometry: null,
8
+ properties: {
9
+ id: '0001',
10
+ firstName: 'John',
11
+ lastName: 'Lennon',
12
+ },
13
+ },
14
+ {
15
+ type: 'Feature',
16
+ geometry: null,
17
+ properties: {
18
+ id: '0002',
19
+ firstName: 'Ozzy',
20
+ lastName: 'Osbourne',
21
+ },
22
+ },
23
+ {
24
+ type: 'Feature',
25
+ geometry: null,
26
+ properties: {
27
+ id: '0003',
28
+ firstName: 'Claude',
29
+ lastName: 'François',
30
+ },
31
+ },
32
+ ] as DataItem[],
33
+ properties: [
34
+ { name: 'id', label: 'id', type: 'string' },
35
+ { name: 'firstName', label: 'Firstname', type: 'string' },
36
+ { name: 'lastName', label: 'Lastname', type: 'string' },
37
+ ] as PropertyInfo[],
38
+ }
39
+
40
+ export const someHabTableItemFixture = {
41
+ items: [
42
+ {
43
+ type: 'Feature',
44
+ geometry: null,
45
+ properties: {
46
+ id: '1',
47
+ name: 'France',
48
+ pop: 50500000,
49
+ },
50
+ },
51
+ {
52
+ type: 'Feature',
53
+ geometry: null,
54
+ properties: {
55
+ id: '2',
56
+ name: 'Italy',
57
+ pop: 155878789655,
58
+ },
59
+ },
60
+ {
61
+ type: 'Feature',
62
+ geometry: null,
63
+ properties: {
64
+ id: '3',
65
+ name: 'UK',
66
+ pop: 31522456,
67
+ },
68
+ },
69
+ {
70
+ type: 'Feature',
71
+ geometry: null,
72
+ properties: {
73
+ id: '4',
74
+ name: 'US',
75
+ pop: 3215448888,
76
+ },
77
+ },
78
+ ] as DataItem[],
79
+ properties: [
80
+ { name: 'id', label: 'ID', type: 'string' },
81
+ { name: 'name', label: 'Name', type: 'string' },
82
+ { name: 'pop', label: 'Population', type: 'number' },
83
+ ] as PropertyInfo[],
84
+ }