geonetwork-ui 2.5.0-dev.f8f8616a0 → 2.6.0-dev.01d2b5fc0
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.
- package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.mjs +2 -2
- package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +4 -2
- package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +4 -8
- package/esm2022/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.mjs +14 -13
- package/esm2022/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.mjs +2 -2
- package/esm2022/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.mjs +2 -2
- package/esm2022/libs/feature/editor/src/lib/components/import-record/import-record.component.mjs +5 -5
- package/esm2022/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.mjs +5 -3
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.mjs +2 -2
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.mjs +9 -12
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.mjs +2 -2
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.mjs +2 -2
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.mjs +3 -3
- package/esm2022/libs/feature/map/src/lib/add-layer-from-catalog/add-layer-from-catalog.component.mjs +1 -1
- package/esm2022/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.mjs +12 -3
- package/esm2022/libs/ui/dataviz/src/lib/data-table/data-table.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/image-input/image-input.component.mjs +50 -35
- package/esm2022/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.mjs +23 -3
- package/esm2022/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.mjs +53 -7
- package/esm2022/libs/ui/inputs/src/lib/file-input/file-input.component.mjs +2 -2
- package/esm2022/libs/ui/inputs/src/lib/url-input/url-input.component.mjs +10 -3
- package/esm2022/libs/ui/search/src/lib/record-preview-row/record-preview-row.component.mjs +3 -3
- package/esm2022/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.mjs +10 -3
- package/esm2022/translations/de.json +1 -1
- package/esm2022/translations/en.json +1 -1
- package/esm2022/translations/fr.json +1 -1
- package/esm2022/translations/it.json +1 -1
- package/fesm2022/geonetwork-ui.mjs +202 -105
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.d.ts +1 -0
- package/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.d.ts +1 -0
- package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.d.ts.map +1 -1
- package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts +4 -1
- package/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/image-input/image-input.component.d.ts +11 -9
- package/libs/ui/elements/src/lib/image-input/image-input.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts.map +1 -1
- package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts +8 -1
- package/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.d.ts.map +1 -1
- package/libs/ui/inputs/src/lib/url-input/url-input.component.d.ts +5 -3
- package/libs/ui/inputs/src/lib/url-input/url-input.component.d.ts.map +1 -1
- package/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.d.ts +1 -1
- package/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +1 -1
- package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +19 -17
- package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +3 -11
- package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +24 -26
- package/src/libs/common/fixtures/src/lib/records.fixtures.ts +90 -0
- package/src/libs/feature/editor/src/lib/components/import-record/import-record.component.ts +3 -3
- package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html +1 -0
- package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts +2 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.html +1 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts-for-resource/form-field-contacts-for-resource.component.ts +10 -11
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +1 -1
- package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.html +2 -0
- package/src/libs/feature/search/src/lib/fuzzy-search/fuzzy-search.component.ts +6 -0
- package/src/libs/ui/dataviz/src/lib/data-table/data-table.component.html +3 -1
- package/src/libs/ui/elements/src/lib/image-input/image-input.component.html +20 -15
- package/src/libs/ui/elements/src/lib/image-input/image-input.component.ts +49 -35
- package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.html +21 -9
- package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.ts +13 -0
- package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +36 -19
- package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +43 -2
- package/src/libs/ui/inputs/src/lib/url-input/url-input.component.ts +8 -1
- package/src/libs/ui/search/src/lib/record-preview-row/record-preview-row.component.html +1 -1
- package/src/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.html +36 -11
- package/src/libs/ui/widgets/src/lib/progress-bar/progress-bar.component.ts +9 -1
- package/translations/de.json +1 -1
- package/translations/en.json +1 -1
- package/translations/fr.json +1 -1
- package/translations/it.json +1 -1
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
provideNgIconsConfig,
|
|
41
41
|
} from '@ng-icons/core'
|
|
42
42
|
import { iconoirPlus } from '@ng-icons/iconoir'
|
|
43
|
+
import { RoleValues } from '../../../../../../../../../libs/common/domain/src/lib/model/record'
|
|
43
44
|
|
|
44
45
|
@Component({
|
|
45
46
|
selector: 'gn-ui-form-field-contacts-for-resource',
|
|
@@ -72,15 +73,11 @@ export class FormFieldContactsForResourceComponent
|
|
|
72
73
|
@Output() valueChange: EventEmitter<Individual[]> = new EventEmitter()
|
|
73
74
|
|
|
74
75
|
contactsForRessourceByRole: Map<Role, Individual[]> = new Map()
|
|
76
|
+
roleValues = RoleValues
|
|
75
77
|
|
|
76
|
-
rolesToPick: Role[] =
|
|
77
|
-
'
|
|
78
|
-
|
|
79
|
-
'owner',
|
|
80
|
-
'point_of_contact',
|
|
81
|
-
'author',
|
|
82
|
-
'publisher',
|
|
83
|
-
]
|
|
78
|
+
rolesToPick: Role[] = this.roleValues.filter(
|
|
79
|
+
(role) => role !== 'other' && role !== 'unspecified'
|
|
80
|
+
)
|
|
84
81
|
|
|
85
82
|
roleSectionsToDisplay: Role[] = []
|
|
86
83
|
|
|
@@ -178,9 +175,11 @@ export class FormFieldContactsForResourceComponent
|
|
|
178
175
|
* gn-ui-autocomplete
|
|
179
176
|
*/
|
|
180
177
|
displayWithFn: (user: UserModel) => string = (user) =>
|
|
181
|
-
|
|
182
|
-
user.
|
|
183
|
-
|
|
178
|
+
user.name
|
|
179
|
+
? `${user.name} ${user.surname} ${
|
|
180
|
+
user.organisation ? `(${user.organisation})` : ''
|
|
181
|
+
}`
|
|
182
|
+
: ``
|
|
184
183
|
|
|
185
184
|
/**
|
|
186
185
|
* gn-ui-autocomplete
|
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
(itemSelected)="handleItemSelection($event)"
|
|
6
6
|
(inputSubmitted)="handleInputSubmission($event)"
|
|
7
7
|
(inputCleared)="handleInputCleared()"
|
|
8
|
+
(isSearchActive)="handleSearchActive($event)"
|
|
8
9
|
[value]="searchInputValue$ | async"
|
|
9
10
|
[preventCompleteOnSelection]="true"
|
|
10
11
|
[autoFocus]="autoFocus"
|
|
11
12
|
[allowSubmit]="true"
|
|
12
13
|
[forceTrackPosition]="forceTrackPosition"
|
|
14
|
+
[enterButton]="enterButton"
|
|
13
15
|
></gn-ui-autocomplete>
|
|
@@ -29,8 +29,10 @@ export class FuzzySearchComponent implements OnInit {
|
|
|
29
29
|
@ViewChild(AutocompleteComponent) autocomplete: AutocompleteComponent
|
|
30
30
|
@Input() autoFocus = false
|
|
31
31
|
@Input() forceTrackPosition = false
|
|
32
|
+
@Input() enterButton = false
|
|
32
33
|
@Output() itemSelected = new EventEmitter<CatalogRecord>()
|
|
33
34
|
@Output() inputSubmitted = new EventEmitter<string>()
|
|
35
|
+
@Output() isSearchActive = new EventEmitter<boolean>()
|
|
34
36
|
searchInputValue$: Observable<{ title: string }>
|
|
35
37
|
|
|
36
38
|
displayWithFn: (record: CatalogRecord) => string = (record) => record.title
|
|
@@ -85,4 +87,8 @@ export class FuzzySearchComponent implements OnInit {
|
|
|
85
87
|
this.searchService.updateFilters({ any: '' })
|
|
86
88
|
}
|
|
87
89
|
}
|
|
90
|
+
|
|
91
|
+
handleSearchActive(event: boolean) {
|
|
92
|
+
this.isSearchActive.emit(event)
|
|
93
|
+
}
|
|
88
94
|
}
|
|
@@ -32,7 +32,9 @@
|
|
|
32
32
|
mat-row
|
|
33
33
|
*matRowDef="let row; columns: properties"
|
|
34
34
|
(click)="selected.emit(row)"
|
|
35
|
-
[class.active]="
|
|
35
|
+
[class.active]="
|
|
36
|
+
activeId !== undefined && activeId !== null && row.id === activeId
|
|
37
|
+
"
|
|
36
38
|
></tr>
|
|
37
39
|
</table>
|
|
38
40
|
<gn-ui-loading-mask
|
|
@@ -11,10 +11,13 @@
|
|
|
11
11
|
[value]="altText ?? ''"
|
|
12
12
|
(valueChange)="handleAltTextChange($event)"
|
|
13
13
|
extraClass="gn-ui-editor-textarea"
|
|
14
|
-
[disabled]="true"
|
|
15
14
|
></gn-ui-text-input>
|
|
16
15
|
<div class="flex flex-row gap-2 mt-2">
|
|
17
|
-
<gn-ui-button
|
|
16
|
+
<gn-ui-button
|
|
17
|
+
type="gray"
|
|
18
|
+
(buttonClick)="handleDelete()"
|
|
19
|
+
data-cy="delete-image"
|
|
20
|
+
>
|
|
18
21
|
<ng-icon class="me-1 text-primary" name="iconoirBin"></ng-icon>
|
|
19
22
|
{{ 'input.image.delete' | translate }}
|
|
20
23
|
</gn-ui-button>
|
|
@@ -38,20 +41,17 @@
|
|
|
38
41
|
[ngClass]="{
|
|
39
42
|
'border-primary-lighter bg-primary-white': dragFilesOver,
|
|
40
43
|
'border-gray-300': !dragFilesOver,
|
|
41
|
-
'cursor-pointer hover:border-gray-500':
|
|
42
|
-
!isUploadInProgress && !uploadError && !showUrlInput && !disabled,
|
|
44
|
+
'cursor-pointer hover:border-gray-500': !getIsActionBlocked(),
|
|
43
45
|
'cursor-not-allowed': disabled,
|
|
44
46
|
}"
|
|
45
|
-
[attr.tabindex]="
|
|
46
|
-
isUploadInProgress || uploadError || showUrlInput || disabled ? null : 0
|
|
47
|
-
"
|
|
47
|
+
[attr.tabindex]="getIsActionBlocked() ? null : 0"
|
|
48
48
|
(keydown.enter)="fileInput.click()"
|
|
49
49
|
(dragFilesOver)="handleDragFilesOver($event)"
|
|
50
50
|
(dropFiles)="handleDropFiles($event)"
|
|
51
51
|
>
|
|
52
52
|
<div
|
|
53
53
|
class="w-14 h-14 rounded-md bg-gray-50 grid"
|
|
54
|
-
*ngIf="!isUploadInProgress && !
|
|
54
|
+
*ngIf="!isUploadInProgress && !imageFileError"
|
|
55
55
|
>
|
|
56
56
|
<ng-icon
|
|
57
57
|
*ngIf="!dragFilesOver"
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
</div>
|
|
67
67
|
|
|
68
68
|
<div
|
|
69
|
-
*ngIf="isUploadInProgress && !
|
|
69
|
+
*ngIf="isUploadInProgress && !imageFileError"
|
|
70
70
|
class="w-14 h-14 grid items-center justify-center relative"
|
|
71
71
|
>
|
|
72
72
|
<div class="text-gray-100 absolute">
|
|
@@ -88,19 +88,23 @@
|
|
|
88
88
|
<span class="text-sm text-main font-bold">{{ uploadProgress }}%</span>
|
|
89
89
|
</div>
|
|
90
90
|
|
|
91
|
-
<div class="w-14 h-14 rounded-md bg-gray-50 grid" *ngIf="
|
|
91
|
+
<div class="w-14 h-14 rounded-md bg-gray-50 grid" *ngIf="imageFileError">
|
|
92
92
|
<ng-icon
|
|
93
93
|
name="iconoirMediaImageXmark"
|
|
94
94
|
class="place-self-center text-rose-500"
|
|
95
|
+
data-cy="imgErrorIcon"
|
|
95
96
|
></ng-icon>
|
|
96
97
|
</div>
|
|
97
98
|
|
|
98
99
|
<div class="flex flex-col items-center gap-1">
|
|
99
|
-
<p class="font-medium"
|
|
100
|
+
<p class="font-medium" data-cy="imgInputMsgPrimary">
|
|
101
|
+
{{ getPrimaryText() | translate }}
|
|
102
|
+
</p>
|
|
100
103
|
<p
|
|
101
104
|
class="text-sm"
|
|
105
|
+
data-cy="imgInputMsgSecondary"
|
|
102
106
|
[class]="
|
|
103
|
-
isUploadInProgress
|
|
107
|
+
isUploadInProgress
|
|
104
108
|
? 'font-bold text-blue-500 cursor-pointer'
|
|
105
109
|
: 'font-medium text-gray-500'
|
|
106
110
|
"
|
|
@@ -111,17 +115,17 @@
|
|
|
111
115
|
</div>
|
|
112
116
|
<input
|
|
113
117
|
#fileInput
|
|
118
|
+
accept="image/*"
|
|
114
119
|
type="file"
|
|
115
120
|
class="hidden"
|
|
116
121
|
(change)="handleFileInput($event)"
|
|
117
|
-
[disabled]="
|
|
118
|
-
showUrlInput || isUploadInProgress || uploadError || disabled
|
|
119
|
-
"
|
|
122
|
+
[disabled]="isUploadInProgress || disabled"
|
|
120
123
|
/>
|
|
121
124
|
</label>
|
|
122
125
|
|
|
123
126
|
<div *ngIf="!showUrlInput" class="flex-none mt-2">
|
|
124
127
|
<gn-ui-button
|
|
128
|
+
data-cy="imgUrlBtn"
|
|
125
129
|
(buttonClick)="displayUrlInput()"
|
|
126
130
|
type="gray"
|
|
127
131
|
[disabled]="disabled"
|
|
@@ -135,6 +139,7 @@
|
|
|
135
139
|
<gn-ui-url-input
|
|
136
140
|
*ngIf="showUrlInput"
|
|
137
141
|
class="mt-3.5"
|
|
142
|
+
data-cy="imgUrlInput"
|
|
138
143
|
(uploadClick)="downloadUrl($event)"
|
|
139
144
|
[disabled]="isUploadInProgress || disabled"
|
|
140
145
|
>
|
|
@@ -66,9 +66,22 @@ import { ImageOverlayPreviewComponent } from '../image-overlay-preview/image-ove
|
|
|
66
66
|
],
|
|
67
67
|
})
|
|
68
68
|
export class ImageInputComponent {
|
|
69
|
-
|
|
69
|
+
private _altText?: string
|
|
70
|
+
|
|
70
71
|
@Input() previewUrl?: string
|
|
71
|
-
@Input()
|
|
72
|
+
@Input()
|
|
73
|
+
get altText(): string | undefined {
|
|
74
|
+
return this._altText
|
|
75
|
+
}
|
|
76
|
+
set altText(value: string | undefined) {
|
|
77
|
+
if (value !== 'KO' && this._altText === 'KO') {
|
|
78
|
+
//This is a dataset rollback after upload error
|
|
79
|
+
this.resetErrors()
|
|
80
|
+
}
|
|
81
|
+
this._altText = value
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Input() maxSizeMB: number
|
|
72
85
|
@Input() uploadProgress?: number
|
|
73
86
|
@Input() uploadError?: boolean
|
|
74
87
|
@Input() disabled?: boolean = false
|
|
@@ -80,11 +93,9 @@ export class ImageInputComponent {
|
|
|
80
93
|
|
|
81
94
|
dragFilesOver = false
|
|
82
95
|
showUrlInput = false
|
|
83
|
-
|
|
96
|
+
imageFileError = this.uploadError
|
|
84
97
|
showAltTextInput = false
|
|
85
|
-
|
|
86
|
-
lastUploadType?: 'file' | 'url'
|
|
87
|
-
lastUploadContent?: string | File
|
|
98
|
+
pendingAltText: string
|
|
88
99
|
|
|
89
100
|
get isUploadInProgress() {
|
|
90
101
|
return this.uploadProgress !== undefined
|
|
@@ -95,8 +106,12 @@ export class ImageInputComponent {
|
|
|
95
106
|
private cd: ChangeDetectorRef
|
|
96
107
|
) {}
|
|
97
108
|
|
|
109
|
+
getIsActionBlocked() {
|
|
110
|
+
return this.isUploadInProgress || this.disabled
|
|
111
|
+
}
|
|
112
|
+
|
|
98
113
|
getPrimaryText() {
|
|
99
|
-
if (this.
|
|
114
|
+
if (this.imageFileError) {
|
|
100
115
|
return marker('input.image.uploadErrorLabel')
|
|
101
116
|
}
|
|
102
117
|
if (this.uploadProgress) {
|
|
@@ -106,8 +121,8 @@ export class ImageInputComponent {
|
|
|
106
121
|
}
|
|
107
122
|
|
|
108
123
|
getSecondaryText() {
|
|
109
|
-
if (this.
|
|
110
|
-
return
|
|
124
|
+
if (this.imageFileError) {
|
|
125
|
+
return '\u00A0' // (only to keep same spacing, next step is to handle "Retry")
|
|
111
126
|
}
|
|
112
127
|
if (this.uploadProgress) {
|
|
113
128
|
return marker('input.image.uploadProgressCancel')
|
|
@@ -123,19 +138,26 @@ export class ImageInputComponent {
|
|
|
123
138
|
}
|
|
124
139
|
|
|
125
140
|
handleDropFiles(files: File[]) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
141
|
+
this.resetErrors()
|
|
142
|
+
const validFiles = this.filterTypeImage(files)
|
|
143
|
+
if (validFiles.length > 0) {
|
|
144
|
+
this.showUrlInput = false
|
|
145
|
+
this.resizeAndEmit(validFiles[0])
|
|
146
|
+
} else {
|
|
147
|
+
this.imageFileError = true
|
|
148
|
+
this.handleAltTextChange('KO')
|
|
131
149
|
}
|
|
132
150
|
}
|
|
133
151
|
|
|
134
152
|
handleFileInput(event: Event) {
|
|
153
|
+
this.resetErrors()
|
|
135
154
|
const inputFiles = Array.from((event.target as HTMLInputElement).files)
|
|
136
155
|
const validFiles = this.filterTypeImage(inputFiles)
|
|
137
156
|
if (validFiles.length > 0) {
|
|
138
157
|
this.resizeAndEmit(validFiles[0])
|
|
158
|
+
} else {
|
|
159
|
+
this.imageFileError = true
|
|
160
|
+
this.handleAltTextChange('KO')
|
|
139
161
|
}
|
|
140
162
|
}
|
|
141
163
|
|
|
@@ -145,9 +167,8 @@ export class ImageInputComponent {
|
|
|
145
167
|
}
|
|
146
168
|
|
|
147
169
|
async downloadUrl(url: string) {
|
|
148
|
-
this.
|
|
170
|
+
this.resetErrors()
|
|
149
171
|
const name = url.split('/').pop()
|
|
150
|
-
|
|
151
172
|
try {
|
|
152
173
|
const response = await firstValueFrom(
|
|
153
174
|
this.http.head(url, { observe: 'response' })
|
|
@@ -164,47 +185,41 @@ export class ImageInputComponent {
|
|
|
164
185
|
this.fileChange.emit(file)
|
|
165
186
|
},
|
|
166
187
|
error: () => {
|
|
167
|
-
this.
|
|
188
|
+
this.imageFileError = true
|
|
189
|
+
this.handleAltTextChange('KO')
|
|
168
190
|
this.cd.markForCheck()
|
|
169
191
|
this.urlChange.emit(url)
|
|
170
192
|
},
|
|
171
193
|
})
|
|
172
194
|
}
|
|
173
195
|
} catch {
|
|
174
|
-
this.
|
|
196
|
+
this.imageFileError = true
|
|
197
|
+
this.handleAltTextChange('KO')
|
|
175
198
|
this.cd.markForCheck()
|
|
176
199
|
return
|
|
177
200
|
}
|
|
178
201
|
}
|
|
179
202
|
|
|
180
203
|
handleSecondaryTextClick(event: Event) {
|
|
181
|
-
if (this.
|
|
182
|
-
this.
|
|
183
|
-
} else if (this.uploadProgress) {
|
|
184
|
-
this.handleCancel()
|
|
204
|
+
if (this.uploadProgress) {
|
|
205
|
+
this.handleCancelUpload()
|
|
185
206
|
event.preventDefault()
|
|
186
207
|
}
|
|
187
208
|
}
|
|
188
209
|
|
|
189
|
-
|
|
210
|
+
handleCancelUpload() {
|
|
190
211
|
this.uploadCancel.emit()
|
|
191
212
|
}
|
|
192
213
|
|
|
193
|
-
handleRetry() {
|
|
194
|
-
switch (this.lastUploadType) {
|
|
195
|
-
case 'file':
|
|
196
|
-
this.fileChange.emit(this.lastUploadContent as File)
|
|
197
|
-
break
|
|
198
|
-
case 'url':
|
|
199
|
-
this.urlChange.emit(this.lastUploadContent as string)
|
|
200
|
-
break
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
214
|
handleDelete() {
|
|
205
215
|
this.delete.emit()
|
|
206
216
|
}
|
|
207
217
|
|
|
218
|
+
resetErrors() {
|
|
219
|
+
this.imageFileError = false
|
|
220
|
+
this.uploadError = false
|
|
221
|
+
}
|
|
222
|
+
|
|
208
223
|
toggleAltTextInput() {
|
|
209
224
|
this.showAltTextInput = !this.showAltTextInput
|
|
210
225
|
}
|
|
@@ -212,7 +227,6 @@ export class ImageInputComponent {
|
|
|
212
227
|
handleAltTextChange(altText: string) {
|
|
213
228
|
this.altTextChange.emit(altText)
|
|
214
229
|
}
|
|
215
|
-
|
|
216
230
|
private filterTypeImage(files: File[]) {
|
|
217
231
|
return files.filter((file) => {
|
|
218
232
|
return file.type.startsWith('image/')
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
<div *ngIf="metadataQualityDisplay" class="mb-6 metadata-quality">
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
2
|
+
<div
|
|
3
|
+
class="flex items-center"
|
|
4
|
+
[class]="smaller ? 'leading-[8px] min-w-[120px]' : 'min-w-[200px]'"
|
|
5
|
+
>
|
|
6
|
+
<gn-ui-progress-bar
|
|
7
|
+
tabindex="0"
|
|
8
|
+
[value]="qualityScore"
|
|
9
|
+
[type]="'light'"
|
|
10
|
+
class="flex-grow"
|
|
11
|
+
></gn-ui-progress-bar>
|
|
12
|
+
<gn-ui-popover
|
|
13
|
+
[content]="popoverItems"
|
|
14
|
+
theme="light-border"
|
|
15
|
+
[class]="smaller ? 'ml-2' : 'ml-2 mt-1'"
|
|
16
|
+
>
|
|
17
|
+
<ng-icon
|
|
18
|
+
name="matInfoOutline"
|
|
19
|
+
class="flex-shrink-0 text-gray-600"
|
|
20
|
+
></ng-icon>
|
|
21
|
+
</gn-ui-popover>
|
|
22
|
+
</div>
|
|
11
23
|
</div>
|
|
12
24
|
<ng-template #popoverItems>
|
|
13
25
|
<div class="p-2 py-4">
|
|
@@ -16,6 +16,9 @@ import {
|
|
|
16
16
|
} from '../../../../../../libs/ui/widgets/src'
|
|
17
17
|
import { CommonModule } from '@angular/common'
|
|
18
18
|
import { TranslateModule } from '@ngx-translate/core'
|
|
19
|
+
import { NgIcon } from '@ng-icons/core'
|
|
20
|
+
import { matInfoOutline } from '@ng-icons/material-icons/outline'
|
|
21
|
+
import { provideIcons, provideNgIconsConfig } from '@ng-icons/core'
|
|
19
22
|
|
|
20
23
|
@Component({
|
|
21
24
|
selector: 'gn-ui-metadata-quality',
|
|
@@ -29,6 +32,16 @@ import { TranslateModule } from '@ngx-translate/core'
|
|
|
29
32
|
ProgressBarComponent,
|
|
30
33
|
MetadataQualityItemComponent,
|
|
31
34
|
TranslateModule,
|
|
35
|
+
NgIcon,
|
|
36
|
+
],
|
|
37
|
+
providers: [
|
|
38
|
+
provideIcons({
|
|
39
|
+
matInfoOutline,
|
|
40
|
+
}),
|
|
41
|
+
provideNgIconsConfig({
|
|
42
|
+
size: '1.2em',
|
|
43
|
+
strokeWidth: '1.5px',
|
|
44
|
+
}),
|
|
32
45
|
],
|
|
33
46
|
})
|
|
34
47
|
export class MetadataQualityComponent implements OnChanges {
|
|
@@ -5,31 +5,48 @@
|
|
|
5
5
|
>
|
|
6
6
|
<ng-icon name="iconoirSearch" class="text-primary search"></ng-icon>
|
|
7
7
|
</div>
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
8
|
+
<div class="flex flex-row">
|
|
9
|
+
<input
|
|
10
|
+
#searchInput
|
|
11
|
+
type="text"
|
|
12
|
+
class="gn-ui-text-input"
|
|
13
|
+
(input)="handleInput($event)"
|
|
14
|
+
[placeholder]="placeholder"
|
|
15
|
+
[formControl]="control"
|
|
16
|
+
[matAutocomplete]="auto"
|
|
17
|
+
(keyup.enter)="handleEnter(searchInput.value)"
|
|
18
|
+
[ngClass]="{
|
|
19
|
+
'text-primary': searchActive && enterButton,
|
|
20
|
+
'text-gray-900': !searchActive,
|
|
21
|
+
'px-[--icon-width]': !allowSubmit,
|
|
22
|
+
}"
|
|
23
|
+
/>
|
|
24
|
+
<gn-ui-button
|
|
25
|
+
type="gray"
|
|
26
|
+
*ngIf="searchInput.value && displayEnterBtn"
|
|
27
|
+
extraClass="w-32 h-8 !opacity-100"
|
|
28
|
+
[ngStyle]="{ left: enterBtnPosition + 'px' }"
|
|
29
|
+
class="absolute"
|
|
30
|
+
disabled="true"
|
|
31
|
+
>
|
|
32
|
+
<ng-icon
|
|
33
|
+
name="iconoirLongArrowDownLeft"
|
|
34
|
+
class="!w-4 text-gray-900 font-bold"
|
|
35
|
+
></ng-icon>
|
|
36
|
+
<span translate class="text-bold text-gray-900 font-bold">
|
|
37
|
+
Enter to search
|
|
38
|
+
</span>
|
|
39
|
+
</gn-ui-button>
|
|
40
|
+
</div>
|
|
20
41
|
<gn-ui-button
|
|
21
|
-
type="
|
|
22
|
-
extraClass="
|
|
23
|
-
allowSubmit
|
|
24
|
-
? 'right-[calc(var(--icon-width)+var(--icon-padding))]'
|
|
25
|
-
: 'right-[--icon-padding]'
|
|
26
|
-
}}"
|
|
42
|
+
type="primary"
|
|
43
|
+
[extraClass]="getExtraClass()"
|
|
27
44
|
data-test="clear-btn"
|
|
28
45
|
*ngIf="searchInput.value"
|
|
29
46
|
aria-label="Clear"
|
|
30
47
|
(buttonClick)="clear()"
|
|
31
48
|
>
|
|
32
|
-
<ng-icon name="matClose"></ng-icon>
|
|
49
|
+
<ng-icon class="text-white" name="matClose"></ng-icon>
|
|
33
50
|
</gn-ui-button>
|
|
34
51
|
<gn-ui-button
|
|
35
52
|
type="light"
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
provideIcons,
|
|
42
42
|
provideNgIconsConfig,
|
|
43
43
|
} from '@ng-icons/core'
|
|
44
|
-
import { iconoirSearch } from '@ng-icons/iconoir'
|
|
44
|
+
import { iconoirLongArrowDownLeft, iconoirSearch } from '@ng-icons/iconoir'
|
|
45
45
|
import { matClose } from '@ng-icons/material-icons/baseline'
|
|
46
46
|
|
|
47
47
|
export type AutocompleteItem = unknown
|
|
@@ -65,9 +65,10 @@ export type AutocompleteItem = unknown
|
|
|
65
65
|
provideIcons({
|
|
66
66
|
iconoirSearch,
|
|
67
67
|
matClose,
|
|
68
|
+
iconoirLongArrowDownLeft,
|
|
68
69
|
}),
|
|
69
70
|
provideNgIconsConfig({
|
|
70
|
-
size: '1.
|
|
71
|
+
size: '1.75rem',
|
|
71
72
|
}),
|
|
72
73
|
],
|
|
73
74
|
})
|
|
@@ -75,6 +76,7 @@ export class AutocompleteComponent
|
|
|
75
76
|
implements OnInit, AfterViewInit, OnDestroy, OnChanges
|
|
76
77
|
{
|
|
77
78
|
@Input() placeholder: string
|
|
79
|
+
@Input() enterButton = false
|
|
78
80
|
@Input() action: (value: string) => Observable<AutocompleteItem[]>
|
|
79
81
|
@Input() value?: AutocompleteItem
|
|
80
82
|
@Input() clearOnSelection = false
|
|
@@ -87,6 +89,7 @@ export class AutocompleteComponent
|
|
|
87
89
|
@Output() itemSelected = new EventEmitter<AutocompleteItem>()
|
|
88
90
|
@Output() inputSubmitted = new EventEmitter<string>()
|
|
89
91
|
@Output() inputCleared = new EventEmitter<void>()
|
|
92
|
+
@Output() isSearchActive = new EventEmitter<boolean>()
|
|
90
93
|
@ViewChild(MatAutocompleteTrigger) triggerRef: MatAutocompleteTrigger
|
|
91
94
|
@ViewChild(MatAutocomplete) autocomplete: MatAutocomplete
|
|
92
95
|
@ViewChild('searchInput') inputRef: ElementRef<HTMLInputElement>
|
|
@@ -101,15 +104,36 @@ export class AutocompleteComponent
|
|
|
101
104
|
subscription = new Subscription()
|
|
102
105
|
private lastPosition: DOMRect | null = null
|
|
103
106
|
private intervalIdPosition: number | undefined
|
|
107
|
+
enterBtnPosition = 0
|
|
108
|
+
searchActive = false
|
|
104
109
|
|
|
105
110
|
@Input() displayWithFn: (item: AutocompleteItem) => string = (item) =>
|
|
106
111
|
item.toString()
|
|
107
112
|
|
|
113
|
+
get displayEnterBtn() {
|
|
114
|
+
return this.enterButton && this.allowSubmit && !this.searchActive
|
|
115
|
+
}
|
|
116
|
+
|
|
108
117
|
displayWithFnInternal = (item?: AutocompleteItem) => {
|
|
109
118
|
if (item === null || item === undefined) return null
|
|
110
119
|
return this.displayWithFn(item)
|
|
111
120
|
}
|
|
112
121
|
|
|
122
|
+
getExtraClass(): string {
|
|
123
|
+
if (this.allowSubmit) {
|
|
124
|
+
if (this.enterButton) {
|
|
125
|
+
return 'border rounded-lg absolute w-8 h-8 right-[calc(var(--icon-width)+var(--icon-padding))] inset-y-[--icon-padding]'
|
|
126
|
+
} else {
|
|
127
|
+
return 'border rounded-lg absolute w-8 h-8 right-[calc(var(--icon-width)+0.25*var(--icon-width))] inset-y-[calc(0.25*var(--icon-width))]'
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
if (!this.enterButton) {
|
|
131
|
+
return 'border rounded-lg absolute w-8 h-8 right-2 inset-y-2'
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return 'border rounded-lg absolute w-8 h-8'
|
|
135
|
+
}
|
|
136
|
+
|
|
113
137
|
constructor(private cdRef: ChangeDetectorRef) {}
|
|
114
138
|
ngOnChanges(changes: SimpleChanges): void {
|
|
115
139
|
const { value } = changes
|
|
@@ -117,6 +141,13 @@ export class AutocompleteComponent
|
|
|
117
141
|
const previousTextValue = this.displayWithFnInternal(value.previousValue)
|
|
118
142
|
const currentTextValue = this.displayWithFnInternal(value.currentValue)
|
|
119
143
|
if (previousTextValue !== currentTextValue) {
|
|
144
|
+
if (currentTextValue) {
|
|
145
|
+
this.searchActive = true
|
|
146
|
+
this.isSearchActive.emit(true)
|
|
147
|
+
} else {
|
|
148
|
+
this.searchActive = false
|
|
149
|
+
this.isSearchActive.emit(false)
|
|
150
|
+
}
|
|
120
151
|
this.updateInputValue(value.currentValue)
|
|
121
152
|
}
|
|
122
153
|
}
|
|
@@ -256,6 +287,8 @@ export class AutocompleteComponent
|
|
|
256
287
|
|
|
257
288
|
clear(): void {
|
|
258
289
|
this.inputRef.nativeElement.value = ''
|
|
290
|
+
this.searchActive = false
|
|
291
|
+
this.isSearchActive.emit(false)
|
|
259
292
|
this.inputCleared.emit()
|
|
260
293
|
this.selectionSubject
|
|
261
294
|
.pipe(take(1))
|
|
@@ -265,6 +298,8 @@ export class AutocompleteComponent
|
|
|
265
298
|
|
|
266
299
|
handleEnter(any: string) {
|
|
267
300
|
if (!this.cancelEnter && this.allowSubmit) {
|
|
301
|
+
this.isSearchActive.emit(true)
|
|
302
|
+
this.searchActive = true
|
|
268
303
|
this.inputSubmitted.emit(any)
|
|
269
304
|
}
|
|
270
305
|
}
|
|
@@ -294,4 +329,10 @@ export class AutocompleteComponent
|
|
|
294
329
|
this.control.setValue('')
|
|
295
330
|
}
|
|
296
331
|
}
|
|
332
|
+
|
|
333
|
+
handleInput(event: InputEvent) {
|
|
334
|
+
this.searchActive = false
|
|
335
|
+
this.isSearchActive.emit(false)
|
|
336
|
+
this.enterBtnPosition = event.target['value'].length * 8 + 80
|
|
337
|
+
}
|
|
297
338
|
}
|
|
@@ -31,7 +31,7 @@ import { iconoirArrowUp, iconoirLink } from '@ng-icons/iconoir'
|
|
|
31
31
|
],
|
|
32
32
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
33
33
|
})
|
|
34
|
-
export class UrlInputComponent {
|
|
34
|
+
export class UrlInputComponent implements OnChanges {
|
|
35
35
|
@Input() set value(v: string) {
|
|
36
36
|
// we're making sure to only update the input if the URL representation of it has changed; otherwise we keep it identical
|
|
37
37
|
// to avoid glitches when starting to write a URL and having some characters added/replaced automatically
|
|
@@ -48,6 +48,7 @@ export class UrlInputComponent {
|
|
|
48
48
|
@Input() placeholder = 'https://'
|
|
49
49
|
@Input() disabled: boolean
|
|
50
50
|
@Input() showValidateButton = true
|
|
51
|
+
@Input() resetUrlOnChange: number
|
|
51
52
|
|
|
52
53
|
/**
|
|
53
54
|
* This will emit null if the field is emptied
|
|
@@ -59,6 +60,12 @@ export class UrlInputComponent {
|
|
|
59
60
|
|
|
60
61
|
constructor(private cd: ChangeDetectorRef) {}
|
|
61
62
|
|
|
63
|
+
ngOnChanges(changes: SimpleChanges) {
|
|
64
|
+
if (changes['resetUrlOnChange']) {
|
|
65
|
+
this.inputValue = ''
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
62
69
|
handleInput(event: Event) {
|
|
63
70
|
const value = (event.target as HTMLInputElement).value
|
|
64
71
|
this.inputValue = value
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
class="col-start-2 row-start-4 sm:row-start-3 absolute right-[4em] sm:right-[5em]"
|
|
65
65
|
>
|
|
66
66
|
<gn-ui-metadata-quality
|
|
67
|
-
smaller="true"
|
|
67
|
+
[smaller]="true"
|
|
68
68
|
[metadata]="record"
|
|
69
69
|
[metadataQualityDisplay]="metadataQualityDisplay"
|
|
70
70
|
></gn-ui-metadata-quality>
|