• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geonetwork / geonetwork-ui / 14619195802

23 Apr 2025 01:19PM UTC coverage: 84.125% (+1.9%) from 82.183%
14619195802

Pull #1226

github

web-flow
Merge 88cfa2203 into 01f702fed
Pull Request #1226: [Datahub] : Feature Catalog - User friendly labels

3309 of 4412 branches covered (75.0%)

Branch coverage included in aggregate %.

44 of 49 new or added lines in 4 files covered. (89.8%)

7 existing lines in 2 files now uncovered.

9616 of 10952 relevant lines covered (87.8%)

271.3 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.37
/libs/ui/dataviz/src/lib/data-table/data-table.component.ts
1
import { ScrollingModule } from '@angular/cdk/scrolling'
1✔
2
import {
1✔
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'
1✔
16
import { MatTableModule } from '@angular/material/table'
1✔
17
import { TranslateModule, TranslateService } from '@ngx-translate/core'
1✔
18
import { DataTableDataSource } from './data-table.data.source'
1✔
19
import { BaseReader, FetchError } from '@geonetwork-ui/data-fetcher'
1✔
20
import {
1✔
21
  MatPaginator,
22
  MatPaginatorIntl,
23
  MatPaginatorModule,
24
} from '@angular/material/paginator'
25
import { CustomMatPaginatorIntl } from './custom.mat.paginator.intl'
1✔
26
import { CommonModule } from '@angular/common'
1✔
27
import { BehaviorSubject, filter, firstValueFrom } from 'rxjs'
1✔
28
import {
1✔
29
  LoadingMaskComponent,
30
  PopupAlertComponent,
31
} from '@geonetwork-ui/ui/widgets'
32
import { LetDirective } from '@ngrx/component'
1✔
33

34
const rowIdPrefix = 'table-item-'
1✔
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 {
1✔
64
  _featureAttributes = []
15✔
65
  @Input() set featureAttributes(value: []) {
NEW
66
    if (value) this._featureAttributes = value
×
67
  }
68
  @Input() set dataset(value: BaseReader) {
69
    this.properties$.next(null)
18✔
70
    this.dataset_ = value
18✔
71
    this.dataset_.load()
18✔
72
    this.setProperties()
18✔
73
  }
74
  @Input() activeId: TableItemId
75
  @Output() selected = new EventEmitter<any>()
15✔
76

77
  @ViewChild(MatSort) sort: MatSort
78
  @ViewChild(MatPaginator) paginator: MatPaginator
79

80
  dataset_: BaseReader
81
  properties$ = new BehaviorSubject<string[]>(null)
15✔
82
  dataSource: DataTableDataSource
83
  headerHeight: number
84
  count: number
85
  loading$ = new BehaviorSubject<boolean>(false)
15✔
86
  error = null
15✔
87

88
  constructor(
89
    private eltRef: ElementRef,
15!
90
    private cdr: ChangeDetectorRef,
15!
91
    private translateService: TranslateService
15✔
92
  ) {}
93

94
  ngOnInit() {
95
    this.dataSource = new DataTableDataSource()
15✔
96
    this.setProperties()
15✔
97
  }
98

99
  ngAfterViewInit() {
100
    this.headerHeight =
14✔
101
      this.eltRef.nativeElement.querySelector('thead').offsetHeight
102
    this.setPagination()
14✔
103
    this.cdr.detectChanges()
14✔
104
  }
105

106
  ngOnChanges() {
107
    this.setPagination()
×
108
  }
109

110
  setSort(sort: MatSort) {
111
    if (!this.dataset_) return
1!
112
    if (!sort.active) {
1!
113
      this.dataset_.orderBy()
×
114
    } else {
115
      this.dataset_.orderBy([sort.direction || 'asc', sort.active])
1!
116
    }
117
    this.readData()
1✔
118
  }
119

120
  setProperties() {
121
    this.dataset_.properties.then((properties) => {
33✔
122
      const updatedProperties = properties.map((p) => {
33✔
123
        if (this._featureAttributes.length) {
99✔
124
          const matchingAttribute = this._featureAttributes.find(
6✔
125
            (attr) => attr.name === p.name
6✔
126
          )
127

128
          if (matchingAttribute && matchingAttribute.code) {
6✔
129
            return matchingAttribute.code
2✔
130
          }
131
          return p.name
4✔
132
        }
133
        return p.name
93✔
134
      })
135

136
      this.properties$.next(updatedProperties)
33✔
137
    })
138
    this.dataset_.info.then((info) => (this.count = info.itemsCount))
33✔
139
  }
140

141
  setPagination() {
142
    if (!this.paginator) return
16!
143
    if (!this.dataset_) return
16!
144
    this.dataset_.limit(
16✔
145
      this.paginator.pageIndex * this.paginator.pageSize,
146
      this.paginator.pageSize
147
    )
148
    this.readData()
16✔
149
  }
150

151
  async readData() {
152
    this.loading$.next(true)
18✔
153
    // wait for properties to be read
154
    const properties = await firstValueFrom(
18✔
155
      this.properties$.pipe(filter((p) => !!p))
21✔
156
    )
157
    const propsWithoutGeom = properties.filter(
18✔
158
      (p) => !p.toLowerCase().startsWith('geom')
54✔
159
    )
160
    this.dataset_.select(...propsWithoutGeom)
18✔
161
    try {
18✔
162
      await this.dataSource.showData(this.dataset_.read())
18✔
163
      this.error = null
17✔
164
    } catch (error) {
165
      this.handleError(error as FetchError | Error)
1✔
166
    }
167
    this.loading$.next(false)
18✔
168
  }
169

170
  scrollToItem(itemId: TableItemId): void {
171
    const row = this.eltRef.nativeElement.querySelector(
×
172
      `#${this.getRowEltId(itemId)}`
173
    )
174
    this.eltRef.nativeElement.scrollTop = row.offsetTop - this.headerHeight
×
175
  }
176

177
  public getRowEltId(id: TableItemId): string {
178
    return rowIdPrefix + id
×
179
  }
180

181
  handleError(error: FetchError | Error) {
182
    this.dataSource.clearData()
1✔
183
    if (error instanceof FetchError) {
1!
184
      this.error = this.translateService.instant(
×
185
        `dataset.error.${error.type}`,
186
        {
187
          info: error.info,
188
        }
189
      )
190
      console.warn(error.message)
×
191
    } else {
192
      this.error = this.translateService.instant(error.message)
1✔
193
      console.warn(error.stack || error)
1!
194
    }
195
  }
196
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc