geonetwork-ui 2.4.0-dev.656babc7 → 2.4.0-dev.8f04e899

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 (77) hide show
  1. package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +5 -5
  2. package/esm2022/libs/common/domain/src/lib/repository/records-repository.interface.mjs +1 -1
  3. package/esm2022/libs/feature/dataviz/src/lib/chart-view/chart-view.component.mjs +4 -4
  4. package/esm2022/libs/feature/dataviz/src/lib/feature-dataviz.module.mjs +7 -4
  5. package/esm2022/libs/feature/dataviz/src/lib/table-view/table-view.component.mjs +1 -1
  6. package/esm2022/libs/feature/editor/src/lib/+state/editor.actions.mjs +2 -1
  7. package/esm2022/libs/feature/editor/src/lib/+state/editor.effects.mjs +6 -4
  8. package/esm2022/libs/feature/editor/src/lib/+state/editor.facade.mjs +2 -1
  9. package/esm2022/libs/feature/editor/src/lib/+state/editor.selectors.mjs +2 -2
  10. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.mjs +14 -44
  11. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.mjs +64 -50
  12. package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +12 -35
  13. package/esm2022/libs/feature/editor/src/lib/services/editor.service.mjs +12 -6
  14. package/esm2022/libs/feature/record/src/lib/feature-record.module.mjs +7 -4
  15. package/esm2022/libs/feature/record/src/lib/map-view/map-view.component.mjs +3 -3
  16. package/esm2022/libs/feature/search/src/lib/feature-search.module.mjs +7 -4
  17. package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +3 -3
  18. package/esm2022/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.mjs +59 -26
  19. package/esm2022/libs/ui/inputs/src/lib/ui-inputs.module.mjs +2 -7
  20. package/esm2022/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.mjs +5 -3
  21. package/esm2022/libs/ui/widgets/src/lib/ui-widgets.module.mjs +1 -6
  22. package/fesm2022/geonetwork-ui.mjs +397 -396
  23. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  24. package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
  25. package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +1 -1
  26. package/libs/feature/dataviz/src/lib/feature-dataviz.module.d.ts +2 -1
  27. package/libs/feature/dataviz/src/lib/feature-dataviz.module.d.ts.map +1 -1
  28. package/libs/feature/editor/src/lib/+state/editor.actions.d.ts +1 -0
  29. package/libs/feature/editor/src/lib/+state/editor.actions.d.ts.map +1 -1
  30. package/libs/feature/editor/src/lib/+state/editor.effects.d.ts +1 -1
  31. package/libs/feature/editor/src/lib/+state/editor.effects.d.ts.map +1 -1
  32. package/libs/feature/editor/src/lib/+state/editor.facade.d.ts +1 -0
  33. package/libs/feature/editor/src/lib/+state/editor.facade.d.ts.map +1 -1
  34. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.d.ts +14 -24
  35. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.d.ts.map +1 -1
  36. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.d.ts +6 -6
  37. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.d.ts.map +1 -1
  38. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +5 -10
  39. package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
  40. package/libs/feature/editor/src/lib/services/editor.service.d.ts +1 -1
  41. package/libs/feature/editor/src/lib/services/editor.service.d.ts.map +1 -1
  42. package/libs/feature/record/src/lib/feature-record.module.d.ts +2 -1
  43. package/libs/feature/record/src/lib/feature-record.module.d.ts.map +1 -1
  44. package/libs/feature/search/src/lib/feature-search.module.d.ts +2 -1
  45. package/libs/feature/search/src/lib/feature-search.module.d.ts.map +1 -1
  46. package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts.map +1 -1
  47. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts +7 -4
  48. package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts.map +1 -1
  49. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts +35 -36
  50. package/libs/ui/inputs/src/lib/ui-inputs.module.d.ts.map +1 -1
  51. package/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.d.ts +1 -1
  52. package/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.d.ts.map +1 -1
  53. package/libs/ui/widgets/src/lib/ui-widgets.module.d.ts +10 -11
  54. package/libs/ui/widgets/src/lib/ui-widgets.module.d.ts.map +1 -1
  55. package/package.json +1 -1
  56. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +7 -8
  57. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +1 -1
  58. package/src/libs/feature/dataviz/src/lib/feature-dataviz.module.ts +2 -1
  59. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +2 -0
  60. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +35 -29
  61. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +1 -0
  62. package/src/libs/feature/editor/src/lib/+state/editor.selectors.ts +1 -1
  63. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.html +2 -3
  64. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-keywords/form-field-keywords.component.ts +19 -61
  65. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +95 -86
  66. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +2 -22
  67. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +11 -44
  68. package/src/libs/feature/editor/src/lib/services/editor.service.ts +20 -6
  69. package/src/libs/feature/record/src/lib/feature-record.module.ts +3 -2
  70. package/src/libs/feature/search/src/lib/feature-search.module.ts +2 -1
  71. package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.ts +2 -2
  72. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.css +0 -1
  73. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +23 -19
  74. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +79 -27
  75. package/src/libs/ui/inputs/src/lib/ui-inputs.module.ts +0 -3
  76. package/src/libs/ui/widgets/src/lib/popup-alert/popup-alert.component.ts +4 -0
  77. package/src/libs/ui/widgets/src/lib/ui-widgets.module.ts +0 -3
@@ -11,7 +11,7 @@ import {
11
11
  AutocompleteComponent,
12
12
  AutocompleteItem,
13
13
  } from '../../../../../../libs/ui/inputs/src'
14
- import { Observable, firstValueFrom } from 'rxjs'
14
+ import { firstValueFrom, Observable } from 'rxjs'
15
15
  import { map } from 'rxjs/operators'
16
16
  import { SearchFacade } from '../state/search.facade'
17
17
  import { SearchService } from '../utils/service/search.service'
@@ -32,7 +32,7 @@ export class FuzzySearchComponent implements OnInit {
32
32
  @Output() inputSubmitted = new EventEmitter<string>()
33
33
  searchInputValue$: Observable<{ title: string }>
34
34
 
35
- displayWithFn: (record: CatalogRecord) => string = (record) => record?.title
35
+ displayWithFn: (record: CatalogRecord) => string = (record) => record.title
36
36
 
37
37
  autoCompleteAction = (query: string) =>
38
38
  this.recordsRepository
@@ -3,7 +3,6 @@
3
3
  }
4
4
  .clear-btn {
5
5
  width: var(--input-height);
6
- right: var(--input-height);
7
6
  height: 100%;
8
7
  }
9
8
  .search-btn {
@@ -8,23 +8,27 @@
8
8
  [matAutocomplete]="auto"
9
9
  (keyup.enter)="handleEnter(searchInput.value)"
10
10
  />
11
- <button
12
- type="button"
13
- class="text-primary-lightest hover:text-primary hover:bg-gray-50 absolute transition-all duration-100 clear-btn inset-y-0"
14
- *ngIf="searchInput.value"
15
- aria-label="Clear"
16
- (click)="clear()"
17
- >
18
- <mat-icon class="material-symbols-outlined">close</mat-icon>
19
- </button>
20
- <button
21
- type="button"
22
- class="text-primary bg-white hover:text-primary-darkest hover:bg-gray-100 border-gray-300 hover:border-gray-500 absolute transition-all duration-100 search-btn rounded-r inset-y-0 right-0"
23
- aria-label="Trigger search"
24
- (click)="handleClickSearch()"
25
- >
26
- <mat-icon class="material-symbols-outlined">search</mat-icon>
27
- </button>
11
+ <div class="flex flex-row absolute inset-y-0 right-0">
12
+ <button
13
+ type="button"
14
+ class="text-primary-lightest hover:text-primary hover:bg-gray-50 transition-all duration-100 clear-btn"
15
+ *ngIf="searchInput.value"
16
+ aria-label="Clear"
17
+ (click)="clear()"
18
+ >
19
+ <mat-icon class="material-symbols-outlined">close</mat-icon>
20
+ </button>
21
+ <button
22
+ type="button"
23
+ class="text-primary bg-white hover:text-primary-darkest hover:bg-gray-100 border-gray-300 hover:border-gray-500 transition-all duration-100 search-btn rounded-r"
24
+ aria-label="Trigger search"
25
+ *ngIf="allowSubmit"
26
+ data-test="autocomplete-submit-btn"
27
+ (click)="handleClickSearch()"
28
+ >
29
+ <mat-icon class="material-symbols-outlined">search</mat-icon>
30
+ </button>
31
+ </div>
28
32
  <gn-ui-popup-alert
29
33
  *ngIf="error"
30
34
  class="absolute mt-2 w-full top-[100%] left-0"
@@ -39,13 +43,13 @@
39
43
  <mat-autocomplete
40
44
  #auto="matAutocomplete"
41
45
  (optionSelected)="handleSelection($event)"
42
- [displayWith]="displayWithFn"
46
+ [displayWith]="displayWithFnInternal"
43
47
  >
44
48
  <mat-option
45
49
  *ngFor="let suggestion of suggestions$ | async"
46
50
  [value]="suggestion"
47
51
  class="p-2 suggestion"
48
52
  >
49
- {{ displayWithFn(suggestion) }}
53
+ {{ displayWithFnInternal(suggestion) }}
50
54
  </mat-option>
51
55
  </mat-autocomplete>
@@ -13,25 +13,29 @@ import {
13
13
  SimpleChanges,
14
14
  ViewChild,
15
15
  } from '@angular/core'
16
- import { UntypedFormControl } from '@angular/forms'
16
+ import { ReactiveFormsModule, UntypedFormControl } from '@angular/forms'
17
17
  import {
18
18
  MatAutocomplete,
19
+ MatAutocompleteModule,
19
20
  MatAutocompleteSelectedEvent,
20
21
  MatAutocompleteTrigger,
21
22
  } from '@angular/material/autocomplete'
22
- import { merge, Observable, of, ReplaySubject, Subscription } from 'rxjs'
23
+ import { first, merge, Observable, of, ReplaySubject, Subscription } from 'rxjs'
23
24
  import {
24
25
  catchError,
25
26
  debounceTime,
26
27
  distinctUntilChanged,
27
28
  filter,
28
29
  finalize,
29
- first,
30
30
  map,
31
31
  switchMap,
32
32
  take,
33
33
  tap,
34
34
  } from 'rxjs/operators'
35
+ import { MatIconModule } from '@angular/material/icon'
36
+ import { PopupAlertComponent } from '../../../../../../libs/ui/widgets/src'
37
+ import { CommonModule } from '@angular/common'
38
+ import { TranslateModule } from '@ngx-translate/core'
35
39
 
36
40
  export type AutocompleteItem = unknown
37
41
 
@@ -40,6 +44,15 @@ export type AutocompleteItem = unknown
40
44
  templateUrl: './autocomplete.component.html',
41
45
  styleUrls: ['./autocomplete.component.css'],
42
46
  changeDetection: ChangeDetectionStrategy.OnPush,
47
+ standalone: true,
48
+ imports: [
49
+ MatIconModule,
50
+ PopupAlertComponent,
51
+ MatAutocompleteModule,
52
+ CommonModule,
53
+ TranslateModule,
54
+ ReactiveFormsModule,
55
+ ],
43
56
  })
44
57
  export class AutocompleteComponent
45
58
  implements OnInit, AfterViewInit, OnDestroy, OnChanges
@@ -49,6 +62,8 @@ export class AutocompleteComponent
49
62
  @Input() value?: AutocompleteItem
50
63
  @Input() clearOnSelection = false
51
64
  @Input() autoFocus = false
65
+ @Input() minCharacterCount? = 3
66
+ @Input() allowSubmit = true
52
67
  @Output() itemSelected = new EventEmitter<AutocompleteItem>()
53
68
  @Output() inputSubmitted = new EventEmitter<string>()
54
69
  @Output() inputCleared = new EventEmitter<void>()
@@ -57,22 +72,28 @@ export class AutocompleteComponent
57
72
  @ViewChild('searchInput') inputRef: ElementRef<HTMLInputElement>
58
73
 
59
74
  searching: boolean
60
- suggestions$: Observable<AutocompleteItem[]>
61
75
  control = new UntypedFormControl()
62
- subscription = new Subscription()
63
76
  cancelEnter = true
64
77
  selectionSubject = new ReplaySubject<MatAutocompleteSelectedEvent>(1)
65
78
  lastInputValue$ = new ReplaySubject<string>(1)
66
79
  error: string | null = null
80
+ suggestions$: Observable<AutocompleteItem[]>
81
+ subscription = new Subscription()
67
82
 
68
- @Input() displayWithFn: (AutocompleteItem) => string = (item) => item
83
+ @Input() displayWithFn: (item: AutocompleteItem) => string = (item) =>
84
+ item.toString()
85
+
86
+ displayWithFnInternal = (item?: AutocompleteItem) => {
87
+ if (item === null || item === undefined) return null
88
+ return this.displayWithFn(item)
89
+ }
69
90
 
70
91
  constructor(private cdRef: ChangeDetectorRef) {}
71
92
  ngOnChanges(changes: SimpleChanges): void {
72
93
  const { value } = changes
73
94
  if (value) {
74
- const previousTextValue = this.displayWithFn(value.previousValue)
75
- const currentTextValue = this.displayWithFn(value.currentValue)
95
+ const previousTextValue = this.displayWithFnInternal(value.previousValue)
96
+ const currentTextValue = this.displayWithFnInternal(value.currentValue)
76
97
  if (previousTextValue !== currentTextValue) {
77
98
  this.updateInputValue(value.currentValue)
78
99
  }
@@ -80,20 +101,33 @@ export class AutocompleteComponent
80
101
  }
81
102
 
82
103
  ngOnInit(): void {
83
- this.suggestions$ = merge(
104
+ const newValue$ = merge(
105
+ of(''),
106
+ this.inputCleared.pipe(map(() => '')),
84
107
  this.control.valueChanges.pipe(
85
108
  filter((value) => typeof value === 'string'),
86
- filter((value: string) => value.length > 2),
87
- debounceTime(400),
88
109
  distinctUntilChanged(),
89
- tap(() => (this.searching = true))
90
- ),
91
- this.control.valueChanges.pipe(
92
- filter((value) => typeof value === 'object' && value.title),
93
- map((item) => item.title)
110
+ debounceTime(400)
94
111
  )
112
+ )
113
+
114
+ const externalValueChange$ = this.control.valueChanges.pipe(
115
+ filter((value) => typeof value === 'object' && value.title),
116
+ map((item) => item.title)
117
+ )
118
+
119
+ // this observable emits arrays of suggestions loaded using the given action
120
+ const suggestionsFromAction = merge(
121
+ newValue$.pipe(
122
+ filter((value: string) => value.length >= this.minCharacterCount)
123
+ ),
124
+ externalValueChange$
95
125
  ).pipe(
96
- switchMap((value) => (value ? this.action(value) : of([]))),
126
+ tap(() => {
127
+ this.searching = true
128
+ this.error = null
129
+ }),
130
+ switchMap((value) => this.action(value)),
97
131
  catchError((error: Error) => {
98
132
  this.error = error.message
99
133
  return of([])
@@ -101,11 +135,32 @@ export class AutocompleteComponent
101
135
  finalize(() => (this.searching = false))
102
136
  )
103
137
 
104
- this.subscription = this.control.valueChanges.subscribe((any) => {
105
- if (any !== '') {
106
- this.cancelEnter = false
107
- }
108
- })
138
+ this.suggestions$ = merge(
139
+ suggestionsFromAction,
140
+ // if a new value is under the min char count, clear suggestions
141
+ newValue$.pipe(
142
+ filter((value: string) => value.length < this.minCharacterCount),
143
+ map(() => [])
144
+ )
145
+ )
146
+
147
+ // close the panel whenever suggestions are cleared
148
+ this.subscription.add(
149
+ this.suggestions$
150
+ .pipe(filter((suggestions) => suggestions.length === 0))
151
+ .subscribe(() => {
152
+ this.triggerRef?.closePanel()
153
+ })
154
+ )
155
+
156
+ this.subscription.add(
157
+ this.control.valueChanges.subscribe((any) => {
158
+ if (any !== '') {
159
+ this.cancelEnter = false
160
+ }
161
+ })
162
+ )
163
+
109
164
  this.control.valueChanges
110
165
  .pipe(filter((value) => typeof value === 'string'))
111
166
  .subscribe(this.lastInputValue$)
@@ -120,7 +175,7 @@ export class AutocompleteComponent
120
175
  }
121
176
 
122
177
  ngOnDestroy(): void {
123
- this.subscription.unsubscribe()
178
+ this.subscription?.unsubscribe()
124
179
  }
125
180
 
126
181
  updateInputValue(value: AutocompleteItem) {
@@ -139,19 +194,16 @@ export class AutocompleteComponent
139
194
  .pipe(take(1))
140
195
  .subscribe((selection) => selection && selection.option.deselect())
141
196
  this.inputRef.nativeElement.focus()
142
- this.triggerRef.closePanel()
143
197
  }
144
198
 
145
199
  handleEnter(any: string) {
146
- if (!this.cancelEnter) {
200
+ if (!this.cancelEnter && this.allowSubmit) {
147
201
  this.inputSubmitted.emit(any)
148
- this.triggerRef.closePanel()
149
202
  }
150
203
  }
151
204
 
152
205
  handleClickSearch() {
153
206
  this.inputSubmitted.emit(this.inputRef.nativeElement.value)
154
- this.triggerRef.closePanel()
155
207
  }
156
208
 
157
209
  handleSelection(event: MatAutocompleteSelectedEvent) {
@@ -4,7 +4,6 @@ import { UtilSharedModule } from '../../../../../libs/util/shared/src'
4
4
  import { TranslateModule } from '@ngx-translate/core'
5
5
  import { TagInputModule } from 'ngx-chips'
6
6
  import { NgxDropzoneModule } from 'ngx-dropzone'
7
- import { AutocompleteComponent } from './autocomplete/autocomplete.component'
8
7
  import { ButtonComponent } from './button/button.component'
9
8
  import { BadgeComponent } from './badge/badge.component'
10
9
  import { ChipsInputComponent } from './chips-input/chips-input.component'
@@ -37,7 +36,6 @@ import { ImageInputComponent } from './image-input/image-input.component'
37
36
 
38
37
  @NgModule({
39
38
  declarations: [
40
- AutocompleteComponent,
41
39
  TextInputComponent,
42
40
  DragAndDropFileInputComponent,
43
41
  ChipsInputComponent,
@@ -78,7 +76,6 @@ import { ImageInputComponent } from './image-input/image-input.component'
78
76
  ],
79
77
  exports: [
80
78
  DropdownSelectorComponent,
81
- AutocompleteComponent,
82
79
  ButtonComponent,
83
80
  TextInputComponent,
84
81
  DragAndDropFileInputComponent,
@@ -7,12 +7,16 @@ import {
7
7
  OnInit,
8
8
  ViewChild,
9
9
  } from '@angular/core'
10
+ import { CommonModule } from '@angular/common'
11
+ import { MatIconModule } from '@angular/material/icon'
10
12
 
11
13
  @Component({
12
14
  selector: 'gn-ui-popup-alert',
13
15
  templateUrl: './popup-alert.component.html',
14
16
  styleUrls: ['./popup-alert.component.css'],
15
17
  changeDetection: ChangeDetectionStrategy.OnPush,
18
+ standalone: true,
19
+ imports: [CommonModule, MatIconModule],
16
20
  })
17
21
  export class PopupAlertComponent implements OnInit {
18
22
  @Input() icon: string
@@ -9,7 +9,6 @@ import { TagInputModule } from 'ngx-chips'
9
9
  import { FormsModule, ReactiveFormsModule } from '@angular/forms'
10
10
  import { LoadingMaskComponent } from './loading-mask/loading-mask.component'
11
11
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'
12
- import { PopupAlertComponent } from './popup-alert/popup-alert.component'
13
12
  import { MatIconModule } from '@angular/material/icon'
14
13
  import { SpinningLoaderComponent } from './spinning-loader/spinning-loader.component'
15
14
  import { CommonModule } from '@angular/common'
@@ -20,7 +19,6 @@ import { CommonModule } from '@angular/common'
20
19
  ProgressBarComponent,
21
20
  StepBarComponent,
22
21
  LoadingMaskComponent,
23
- PopupAlertComponent,
24
22
  SpinningLoaderComponent,
25
23
  ],
26
24
  imports: [
@@ -38,7 +36,6 @@ import { CommonModule } from '@angular/common'
38
36
  ProgressBarComponent,
39
37
  StepBarComponent,
40
38
  LoadingMaskComponent,
41
- PopupAlertComponent,
42
39
  SpinningLoaderComponent,
43
40
  ],
44
41
  })