geonetwork-ui 2.4.0-dev.db93b4c4 → 2.4.0-dev.e079151e
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/index.mjs +2 -1
- package/esm2022/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.mjs +5 -5
- package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +30 -2
- package/esm2022/libs/api/metadata-converter/src/lib/iso19139/utils/geometry.mjs +31 -0
- package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +23 -1
- package/esm2022/libs/api/metadata-converter/src/lib/xml-utils.mjs +6 -1
- package/esm2022/libs/api/repository/src/lib/gn4/gn4-repository.mjs +12 -1
- package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
- package/esm2022/libs/common/domain/src/lib/repository/records-repository.interface.mjs +1 -1
- package/esm2022/libs/data-access/gn4/src/openapi/api/records.api.service.mjs +2 -6
- package/esm2022/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.mjs +138 -0
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.mjs +21 -0
- package/esm2022/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.mjs +19 -9
- package/esm2022/libs/feature/editor/src/lib/components/record-form/record-form.component.mjs +2 -1
- package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +12 -2
- package/esm2022/libs/feature/map/src/lib/utils/map-utils.service.mjs +3 -4
- package/esm2022/libs/feature/search/src/lib/results-table/results-table-container.component.mjs +9 -3
- package/esm2022/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.mjs +5 -11
- package/esm2022/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/ui-elements.module.mjs +5 -2
- package/esm2022/libs/ui/elements/src/lib/user-preview/user-preview.component.mjs +3 -3
- package/esm2022/libs/ui/inputs/src/lib/image-input/image-input.component.mjs +11 -5
- package/esm2022/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.mjs +29 -0
- package/esm2022/libs/ui/search/src/lib/results-table/results-table.component.mjs +15 -7
- package/esm2022/libs/ui/widgets/src/index.mjs +2 -1
- package/esm2022/libs/ui/widgets/src/lib/popover/popover.component.mjs +68 -0
- package/esm2022/translations/de.json +11 -17
- package/esm2022/translations/en.json +4 -10
- package/esm2022/translations/es.json +3 -9
- package/esm2022/translations/fr.json +4 -10
- package/esm2022/translations/it.json +4 -10
- package/esm2022/translations/nl.json +3 -9
- package/esm2022/translations/pt.json +3 -9
- package/fesm2022/geonetwork-ui.mjs +440 -131
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/libs/api/metadata-converter/src/index.d.ts +1 -0
- package/libs/api/metadata-converter/src/index.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +8 -1
- package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/iso19139/utils/geometry.d.ts +5 -0
- package/libs/api/metadata-converter/src/lib/iso19139/utils/geometry.d.ts.map +1 -0
- package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts +3 -1
- package/libs/api/metadata-converter/src/lib/iso19139/write-parts.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/xml-utils.d.ts +1 -0
- package/libs/api/metadata-converter/src/lib/xml-utils.d.ts.map +1 -1
- package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts +1 -0
- package/libs/api/repository/src/lib/gn4/gn4-repository.d.ts.map +1 -1
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +2 -1
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
- package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts +9 -0
- package/libs/common/domain/src/lib/repository/records-repository.interface.d.ts.map +1 -1
- package/libs/data-access/gn4/src/openapi/api/records.api.service.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.d.ts +27 -0
- package/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.d.ts +11 -0
- package/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts +5 -1
- package/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/components/record-form/record-form.component.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/fields.config.d.ts +1 -0
- package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -1
- package/libs/feature/map/src/lib/utils/map-utils.service.d.ts.map +1 -1
- package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts +3 -1
- package/libs/feature/search/src/lib/results-table/results-table-container.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/downloads-list/downloads-list.component.d.ts +1 -1
- package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts +0 -3
- package/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/record-api-form/record-api-form.component.d.ts +1 -1
- package/libs/ui/elements/src/lib/ui-elements.module.d.ts +7 -6
- package/libs/ui/elements/src/lib/ui-elements.module.d.ts.map +1 -1
- package/libs/ui/inputs/src/lib/image-input/image-input.component.d.ts +4 -2
- package/libs/ui/inputs/src/lib/image-input/image-input.component.d.ts.map +1 -1
- package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts +11 -0
- package/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.d.ts.map +1 -0
- package/libs/ui/search/src/lib/results-table/results-table.component.d.ts +4 -2
- package/libs/ui/search/src/lib/results-table/results-table.component.d.ts.map +1 -1
- package/libs/ui/widgets/src/index.d.ts +1 -0
- package/libs/ui/widgets/src/index.d.ts.map +1 -1
- package/libs/ui/widgets/src/lib/popover/popover.component.d.ts +19 -0
- package/libs/ui/widgets/src/lib/popover/popover.component.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/libs/api/metadata-converter/src/index.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +5 -1
- package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +37 -12
- package/src/libs/api/metadata-converter/src/lib/fixtures/metawal.records.ts +5 -1
- package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +4 -2
- package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +72 -2
- package/src/libs/api/metadata-converter/src/lib/iso19139/utils/geometry.ts +39 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +70 -1
- package/src/libs/api/metadata-converter/src/lib/xml-utils.ts +8 -0
- package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +20 -0
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +2 -1
- package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +12 -0
- package/src/libs/data-access/gn4/src/openapi/api/records.api.service.ts +1 -5
- package/src/libs/data-access/gn4/src/spec.yaml +0 -8
- package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.html +3 -1
- package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.ts +117 -21
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.css +0 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.html +5 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +22 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +6 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +13 -1
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +1 -0
- package/src/libs/feature/editor/src/lib/fields.config.ts +12 -1
- package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +2 -3
- package/src/libs/feature/search/src/lib/results-table/results-table-container.component.html +1 -0
- package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +5 -0
- package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.html +14 -20
- package/src/libs/ui/elements/src/lib/metadata-quality/metadata-quality.component.ts +0 -10
- package/src/libs/ui/elements/src/lib/metadata-quality-item/metadata-quality-item.component.html +1 -1
- package/src/libs/ui/elements/src/lib/ui-elements.module.ts +2 -1
- package/src/libs/ui/elements/src/lib/user-preview/user-preview.component.html +1 -1
- package/src/libs/ui/inputs/src/lib/image-input/image-input.component.html +1 -1
- package/src/libs/ui/inputs/src/lib/image-input/image-input.component.ts +7 -2
- package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.css +0 -0
- package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +17 -0
- package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +22 -0
- package/src/libs/ui/search/src/lib/results-table/results-table.component.html +9 -0
- package/src/libs/ui/search/src/lib/results-table/results-table.component.ts +26 -12
- package/src/libs/ui/widgets/src/index.ts +1 -0
- package/src/libs/ui/widgets/src/lib/popover/popover.component.css +0 -0
- package/src/libs/ui/widgets/src/lib/popover/popover.component.html +3 -0
- package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +85 -0
- package/tailwind.base.css +2 -1
- package/translations/de.json +11 -17
- package/translations/en.json +4 -10
- package/translations/es.json +3 -9
- package/translations/fr.json +4 -10
- package/translations/it.json +4 -10
- package/translations/nl.json +3 -9
- package/translations/pt.json +3 -9
- package/translations/sk.json +4 -10
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
XmlText,
|
|
7
7
|
} from '@rgrove/parse-xml'
|
|
8
8
|
import { ChainableFunction, fallback } from './function-utils'
|
|
9
|
+
|
|
9
10
|
export { XmlDocument, XmlElement } from '@rgrove/parse-xml'
|
|
10
11
|
|
|
11
12
|
export class XmlParseError extends Error {
|
|
@@ -115,6 +116,10 @@ export function allChildrenElement(element: XmlElement): Array<XmlElement> {
|
|
|
115
116
|
] as Array<XmlElement>
|
|
116
117
|
}
|
|
117
118
|
|
|
119
|
+
export function firstChildElement(element: XmlElement): XmlElement {
|
|
120
|
+
return allChildrenElement(element)[0] ?? null
|
|
121
|
+
}
|
|
122
|
+
|
|
118
123
|
/**
|
|
119
124
|
* Will return all matching elements nested according to the given
|
|
120
125
|
* names (similar to a path), starting form the input element;
|
|
@@ -228,6 +233,7 @@ export function xmlToString(
|
|
|
228
233
|
${padding}<${el.name}${attrs}/>
|
|
229
234
|
${parentPadding}`
|
|
230
235
|
}
|
|
236
|
+
|
|
231
237
|
return `
|
|
232
238
|
${padding}<${el.name}${attrs}>${children}</${el.name}>
|
|
233
239
|
${parentPadding}`
|
|
@@ -307,11 +313,13 @@ function getTreeRoot(element: XmlElement): XmlElement {
|
|
|
307
313
|
|
|
308
314
|
// stays on the parent element
|
|
309
315
|
// if the given elements are part of a subtree, will add the root of subtree
|
|
316
|
+
// will filter out falsy elements
|
|
310
317
|
export function appendChildren(
|
|
311
318
|
...childrenFns: Array<ChainableFunction<void, XmlElement>>
|
|
312
319
|
): ChainableFunction<XmlElement, XmlElement> {
|
|
313
320
|
return (element) => {
|
|
314
321
|
if (!element) return null
|
|
322
|
+
childrenFns = childrenFns.filter((fn) => fn)
|
|
315
323
|
element.children.push(...childrenFns.map((fn) => fn()).map(getTreeRoot))
|
|
316
324
|
element.children.forEach((el) => (el.parent = element))
|
|
317
325
|
return element
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
} from '../../../../../../libs/common/domain/src/lib/model/search'
|
|
25
25
|
import { catchError, map, tap } from 'rxjs/operators'
|
|
26
26
|
import {
|
|
27
|
+
BaseConverter,
|
|
27
28
|
findConverterForDocument,
|
|
28
29
|
Gn4Converter,
|
|
29
30
|
Gn4SearchResults,
|
|
@@ -230,6 +231,25 @@ export class Gn4Repository implements RecordsRepositoryInterface {
|
|
|
230
231
|
)
|
|
231
232
|
}
|
|
232
233
|
|
|
234
|
+
openRecordForDuplication(
|
|
235
|
+
uniqueIdentifier: string
|
|
236
|
+
): Observable<[CatalogRecord, string, false] | null> {
|
|
237
|
+
return this.loadRecordAsXml(uniqueIdentifier).pipe(
|
|
238
|
+
switchMap(async (recordAsXml) => {
|
|
239
|
+
const converter = findConverterForDocument(recordAsXml)
|
|
240
|
+
const record = await converter.readRecord(recordAsXml)
|
|
241
|
+
record.uniqueIdentifier = `TEMP-ID-${Date.now()}`
|
|
242
|
+
record.title = `${record.title} (Copy)`
|
|
243
|
+
const xml = await converter.writeRecord(record, recordAsXml)
|
|
244
|
+
window.localStorage.setItem(
|
|
245
|
+
this.getLocalStorageKeyForRecord(record.uniqueIdentifier),
|
|
246
|
+
xml
|
|
247
|
+
)
|
|
248
|
+
return [record, xml, false] as [CatalogRecord, string, false]
|
|
249
|
+
})
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
|
|
233
253
|
private serializeRecordToXml(
|
|
234
254
|
record: CatalogRecord,
|
|
235
255
|
referenceRecordSource?: string
|
|
@@ -30,6 +30,18 @@ export abstract class RecordsRepositoryInterface {
|
|
|
30
30
|
uniqueIdentifier: string
|
|
31
31
|
): Observable<[CatalogRecord, string, boolean] | null>
|
|
32
32
|
|
|
33
|
+
/**
|
|
34
|
+
* This emits once:
|
|
35
|
+
* - record object with a new unique identifier and suffixed title
|
|
36
|
+
* - serialized representation of the record as text
|
|
37
|
+
* - false, as the duplicated record is always a draft
|
|
38
|
+
* @param uniqueIdentifier
|
|
39
|
+
* @returns Observable<[CatalogRecord, string, false] | null>
|
|
40
|
+
*/
|
|
41
|
+
abstract openRecordForDuplication(
|
|
42
|
+
uniqueIdentifier: string
|
|
43
|
+
): Observable<[CatalogRecord, string, false] | null>
|
|
44
|
+
|
|
33
45
|
/**
|
|
34
46
|
* @param record
|
|
35
47
|
* @param referenceRecordSource
|
|
@@ -7201,11 +7201,7 @@ export class RecordsApiService {
|
|
|
7201
7201
|
}
|
|
7202
7202
|
|
|
7203
7203
|
// to determine the Content-Type header
|
|
7204
|
-
const consumes: string[] = [
|
|
7205
|
-
'application/xml',
|
|
7206
|
-
'application/json',
|
|
7207
|
-
'application/x-www-form-urlencoded',
|
|
7208
|
-
]
|
|
7204
|
+
const consumes: string[] = ['application/xml']
|
|
7209
7205
|
const httpContentTypeSelected: string | undefined =
|
|
7210
7206
|
this.configuration.selectHeaderContentType(consumes)
|
|
7211
7207
|
if (httpContentTypeSelected !== undefined) {
|
|
@@ -1832,14 +1832,6 @@ paths:
|
|
|
1832
1832
|
schema:
|
|
1833
1833
|
type: string
|
|
1834
1834
|
description: XML fragment.
|
|
1835
|
-
application/json:
|
|
1836
|
-
schema:
|
|
1837
|
-
type: string
|
|
1838
|
-
description: XML fragment.
|
|
1839
|
-
application/x-www-form-urlencoded:
|
|
1840
|
-
schema:
|
|
1841
|
-
type: string
|
|
1842
|
-
description: XML fragment.
|
|
1843
1835
|
responses:
|
|
1844
1836
|
default:
|
|
1845
1837
|
description: default response
|
package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.html
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<gn-ui-image-input
|
|
2
2
|
[maxSizeMB]="5"
|
|
3
3
|
[previewUrl]="resourceUrl"
|
|
4
|
-
[altText]="
|
|
4
|
+
[altText]="resourceAltText"
|
|
5
|
+
[formControl]="formControl"
|
|
5
6
|
(fileChange)="handleFileChange($event)"
|
|
6
7
|
(urlChange)="handleUrlChange($event)"
|
|
8
|
+
(altTextChange)="handleAltTextChange($event)"
|
|
7
9
|
(delete)="handleDelete()"
|
|
8
10
|
></gn-ui-image-input>
|
package/src/libs/feature/editor/src/lib/components/overview-upload/overview-upload.component.ts
CHANGED
|
@@ -2,12 +2,24 @@ import {
|
|
|
2
2
|
ChangeDetectionStrategy,
|
|
3
3
|
ChangeDetectorRef,
|
|
4
4
|
Component,
|
|
5
|
+
EventEmitter,
|
|
5
6
|
Input,
|
|
7
|
+
OnChanges,
|
|
6
8
|
OnInit,
|
|
9
|
+
Output,
|
|
10
|
+
SimpleChanges,
|
|
7
11
|
} from '@angular/core'
|
|
8
12
|
import { CommonModule } from '@angular/common'
|
|
9
13
|
import { RecordsApiService } from '../../../../../../../libs/data-access/gn4/src'
|
|
10
14
|
import { UiInputsModule } from '../../../../../../../libs/ui/inputs/src'
|
|
15
|
+
import { FormControl } from '@angular/forms'
|
|
16
|
+
import { GraphicOverview } from '../../../../../../../libs/common/domain/src/lib/model/record'
|
|
17
|
+
|
|
18
|
+
const extractFileNameFromUrl = (url: string): string => {
|
|
19
|
+
const pattern = new RegExp(`attachments/([^/?#]+)(?:[/?#]|$)`, 'i')
|
|
20
|
+
const match = url.match(pattern)
|
|
21
|
+
return match ? match[1] : ''
|
|
22
|
+
}
|
|
11
23
|
|
|
12
24
|
@Component({
|
|
13
25
|
selector: 'gn-ui-overview-upload',
|
|
@@ -17,11 +29,15 @@ import { UiInputsModule } from '../../../../../../../libs/ui/inputs/src'
|
|
|
17
29
|
styleUrls: ['./overview-upload.component.css'],
|
|
18
30
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
19
31
|
})
|
|
20
|
-
export class OverviewUploadComponent implements OnInit {
|
|
32
|
+
export class OverviewUploadComponent implements OnInit, OnChanges {
|
|
21
33
|
@Input() metadataUuid: string
|
|
34
|
+
@Input() formControl!: FormControl
|
|
35
|
+
@Output() overviewChange = new EventEmitter<GraphicOverview | null>()
|
|
36
|
+
@Output() altTextChange: EventEmitter<string> = new EventEmitter()
|
|
22
37
|
|
|
23
|
-
|
|
24
|
-
|
|
38
|
+
resourceAltText = '' // = ressourceFileName by default
|
|
39
|
+
resourceFileName = ''
|
|
40
|
+
resourceUrl: URL
|
|
25
41
|
|
|
26
42
|
constructor(
|
|
27
43
|
private recordsApiService: RecordsApiService,
|
|
@@ -29,42 +45,122 @@ export class OverviewUploadComponent implements OnInit {
|
|
|
29
45
|
) {}
|
|
30
46
|
|
|
31
47
|
ngOnInit(): void {
|
|
32
|
-
this.recordsApiService
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
48
|
+
this.recordsApiService.getAllResources(this.metadataUuid).subscribe({
|
|
49
|
+
next: (resources) => {
|
|
50
|
+
if (resources && resources.length > 0) {
|
|
51
|
+
this.resourceUrl = new URL(resources[0]?.url)
|
|
52
|
+
this.resourceAltText =
|
|
53
|
+
this.resourceAltText === ''
|
|
54
|
+
? resources[0].filename
|
|
55
|
+
: this.resourceAltText
|
|
56
|
+
this.resourceFileName = extractFileNameFromUrl(resources[0]?.url)
|
|
57
|
+
} else {
|
|
58
|
+
this.resourceUrl = null
|
|
59
|
+
this.resourceAltText = ''
|
|
60
|
+
this.resourceFileName = ''
|
|
61
|
+
}
|
|
62
|
+
|
|
37
63
|
this.cd.markForCheck()
|
|
38
|
-
}
|
|
64
|
+
},
|
|
65
|
+
error: this.errorHandle,
|
|
66
|
+
})
|
|
39
67
|
}
|
|
40
68
|
|
|
41
69
|
handleFileChange(file: File) {
|
|
42
70
|
this.recordsApiService
|
|
43
71
|
.putResource(this.metadataUuid, file, 'public')
|
|
44
|
-
.subscribe(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
72
|
+
.subscribe({
|
|
73
|
+
next: (resource) => {
|
|
74
|
+
this.resourceUrl = new URL(resource.url)
|
|
75
|
+
this.resourceAltText = resource.filename
|
|
76
|
+
|
|
77
|
+
this.overviewChange.emit({
|
|
78
|
+
url: new URL(resource.url),
|
|
79
|
+
description: resource.filename,
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
this.cd.markForCheck()
|
|
83
|
+
},
|
|
84
|
+
error: this.errorHandle,
|
|
48
85
|
})
|
|
49
86
|
}
|
|
50
87
|
|
|
51
88
|
handleUrlChange(url: string) {
|
|
52
89
|
this.recordsApiService
|
|
53
90
|
.putResourceFromURL(this.metadataUuid, url, 'public')
|
|
54
|
-
.subscribe(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
91
|
+
.subscribe({
|
|
92
|
+
next: (resource) => {
|
|
93
|
+
this.resourceUrl = new URL(resource.url)
|
|
94
|
+
this.resourceAltText = resource.filename
|
|
95
|
+
|
|
96
|
+
this.overviewChange.emit({
|
|
97
|
+
url: new URL(resource.url),
|
|
98
|
+
description: resource.filename,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
this.cd.markForCheck()
|
|
102
|
+
},
|
|
103
|
+
error: this.errorHandle,
|
|
58
104
|
})
|
|
59
105
|
}
|
|
60
106
|
|
|
107
|
+
handleAltTextChange(newAltText: string) {
|
|
108
|
+
this.resourceAltText = newAltText
|
|
109
|
+
|
|
110
|
+
this.overviewChange.emit({
|
|
111
|
+
url: this.resourceUrl,
|
|
112
|
+
description: this.resourceAltText,
|
|
113
|
+
})
|
|
114
|
+
this.cd.markForCheck()
|
|
115
|
+
}
|
|
116
|
+
|
|
61
117
|
handleDelete() {
|
|
62
118
|
this.recordsApiService
|
|
63
119
|
.delResource(this.metadataUuid, this.resourceFileName)
|
|
64
|
-
.subscribe(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
120
|
+
.subscribe({
|
|
121
|
+
next: () => {
|
|
122
|
+
this.resourceAltText = null
|
|
123
|
+
this.resourceUrl = null
|
|
124
|
+
|
|
125
|
+
this.overviewChange.emit(null)
|
|
126
|
+
|
|
127
|
+
this.cd.markForCheck()
|
|
128
|
+
},
|
|
129
|
+
error: this.errorHandle,
|
|
68
130
|
})
|
|
69
131
|
}
|
|
132
|
+
|
|
133
|
+
private errorHandle = (error: never) => {
|
|
134
|
+
console.error(error)
|
|
135
|
+
|
|
136
|
+
this.resourceUrl = null
|
|
137
|
+
this.resourceAltText = ''
|
|
138
|
+
this.resourceFileName = ''
|
|
139
|
+
|
|
140
|
+
this.overviewChange.emit(null)
|
|
141
|
+
|
|
142
|
+
this.cd.markForCheck()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
146
|
+
const overviewChanges = changes['formControl']
|
|
147
|
+
if (
|
|
148
|
+
overviewChanges &&
|
|
149
|
+
overviewChanges.currentValue !== overviewChanges.previousValue
|
|
150
|
+
) {
|
|
151
|
+
let overview: GraphicOverview
|
|
152
|
+
if (
|
|
153
|
+
overviewChanges.currentValue.value &&
|
|
154
|
+
overviewChanges.currentValue.value.length > 0
|
|
155
|
+
) {
|
|
156
|
+
overview = overviewChanges.currentValue.value[0] as GraphicOverview
|
|
157
|
+
} else {
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
if (overview.description && overview.description !== '') {
|
|
161
|
+
this.resourceAltText = overview.description
|
|
162
|
+
this.cd.markForCheck()
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
70
166
|
}
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CommonModule } from '@angular/common'
|
|
2
|
+
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
|
3
|
+
import { OverviewUploadComponent } from '../../../overview-upload/overview-upload.component'
|
|
4
|
+
import { FormControl } from '@angular/forms'
|
|
5
|
+
import { GraphicOverview } from '../../../../../../../../../libs/common/domain/src/lib/model/record'
|
|
6
|
+
|
|
7
|
+
@Component({
|
|
8
|
+
selector: 'gn-ui-form-field-overviews',
|
|
9
|
+
templateUrl: './form-field-overviews.component.html',
|
|
10
|
+
styleUrls: ['./form-field-overviews.component.css'],
|
|
11
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
12
|
+
standalone: true,
|
|
13
|
+
imports: [CommonModule, OverviewUploadComponent],
|
|
14
|
+
})
|
|
15
|
+
export class FormFieldOverviewsComponent {
|
|
16
|
+
@Input() metadataUuid: string
|
|
17
|
+
@Input() control!: FormControl
|
|
18
|
+
|
|
19
|
+
handleOverviewChange(overView: GraphicOverview | null) {
|
|
20
|
+
this.control.setValue(overView ? [overView] : [])
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html
CHANGED
|
@@ -76,6 +76,12 @@
|
|
|
76
76
|
<ng-container *ngIf="isSpatialExtentField">
|
|
77
77
|
<gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>
|
|
78
78
|
</ng-container>
|
|
79
|
+
<ng-container *ngIf="isGraphicOverview">
|
|
80
|
+
<gn-ui-form-field-overviews
|
|
81
|
+
[control]="formControl"
|
|
82
|
+
[metadataUuid]="metadataUuid$ | async"
|
|
83
|
+
></gn-ui-form-field-overviews>
|
|
84
|
+
</ng-container>
|
|
79
85
|
<ng-container *ngIf="isKeywords">
|
|
80
86
|
<gn-ui-form-field-keywords
|
|
81
87
|
[control]="formControl"
|
package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts
CHANGED
|
@@ -28,6 +28,9 @@ import { FormFieldSpatialExtentComponent } from './form-field-spatial-extent/for
|
|
|
28
28
|
import { FormFieldUpdateFrequencyComponent } from './form-field-update-frequency/form-field-update-frequency.component'
|
|
29
29
|
import { CatalogRecordKeys } from '../../../../../../../../libs/common/domain/src/lib/model/record'
|
|
30
30
|
import { FormFieldKeywordsComponent } from './form-field-keywords/form-field-keywords.component'
|
|
31
|
+
import { FormFieldOverviewsComponent } from './form-field-overviews/form-field-overviews.component'
|
|
32
|
+
import { map, take } from 'rxjs/operators'
|
|
33
|
+
import { EditorFacade } from '../../../+state/editor.facade'
|
|
31
34
|
import { FormFieldConfig } from '../../../models'
|
|
32
35
|
|
|
33
36
|
@Component({
|
|
@@ -55,6 +58,7 @@ import { FormFieldConfig } from '../../../models'
|
|
|
55
58
|
FormFieldArrayComponent,
|
|
56
59
|
FormFieldKeywordsComponent,
|
|
57
60
|
TranslateModule,
|
|
61
|
+
FormFieldOverviewsComponent,
|
|
58
62
|
],
|
|
59
63
|
})
|
|
60
64
|
export class FormFieldComponent {
|
|
@@ -70,9 +74,14 @@ export class FormFieldComponent {
|
|
|
70
74
|
|
|
71
75
|
@ViewChild('titleInput') titleInput: ElementRef
|
|
72
76
|
|
|
77
|
+
metadataUuid$ = this.facade.record$.pipe(
|
|
78
|
+
take(1),
|
|
79
|
+
map((record) => record.uniqueIdentifier)
|
|
80
|
+
)
|
|
81
|
+
|
|
73
82
|
formControl = new FormControl()
|
|
74
83
|
|
|
75
|
-
constructor() {
|
|
84
|
+
constructor(private facade: EditorFacade) {
|
|
76
85
|
this.valueChange = this.formControl.valueChanges
|
|
77
86
|
}
|
|
78
87
|
|
|
@@ -101,6 +110,9 @@ export class FormFieldComponent {
|
|
|
101
110
|
get isSpatialExtentField() {
|
|
102
111
|
return this.model === 'spatialExtents'
|
|
103
112
|
}
|
|
113
|
+
get isGraphicOverview() {
|
|
114
|
+
return this.model === 'overviews'
|
|
115
|
+
}
|
|
104
116
|
get isSimpleField() {
|
|
105
117
|
return this.model === 'uniqueIdentifier' || this.model === 'recordUpdated'
|
|
106
118
|
}
|
|
@@ -83,6 +83,13 @@ export const RECORD_ABSTRACT_FIELD: EditorField = {
|
|
|
83
83
|
},
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
export const RECORD_GRAPHICAL_OVERVIEW_FIELD: EditorField = {
|
|
87
|
+
model: 'overviews',
|
|
88
|
+
formFieldConfig: {
|
|
89
|
+
labelKey: marker('editor.record.form.field.overviews'),
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
|
|
86
93
|
/************************************************************
|
|
87
94
|
*************** SECTIONS *****************
|
|
88
95
|
************************************************************
|
|
@@ -90,7 +97,11 @@ export const RECORD_ABSTRACT_FIELD: EditorField = {
|
|
|
90
97
|
|
|
91
98
|
export const TITLE_SECTION: EditorSection = {
|
|
92
99
|
hidden: false,
|
|
93
|
-
fields: [
|
|
100
|
+
fields: [
|
|
101
|
+
RECORD_TITLE_FIELD,
|
|
102
|
+
RECORD_ABSTRACT_FIELD,
|
|
103
|
+
RECORD_GRAPHICAL_OVERVIEW_FIELD,
|
|
104
|
+
],
|
|
94
105
|
}
|
|
95
106
|
|
|
96
107
|
export const ABOUT_SECTION: EditorSection = {
|
|
@@ -220,11 +220,10 @@ export class MapUtilsService {
|
|
|
220
220
|
if (!('spatialExtents' in record) || record.spatialExtents.length === 0) {
|
|
221
221
|
return null
|
|
222
222
|
}
|
|
223
|
-
//
|
|
223
|
+
// extend all the spatial extents bbox into an including bbox
|
|
224
224
|
const totalExtent = record.spatialExtents.reduce(
|
|
225
225
|
(prev, curr) => {
|
|
226
|
-
|
|
227
|
-
return extend(prev, geom.getExtent())
|
|
226
|
+
return extend(prev, curr.bbox)
|
|
228
227
|
},
|
|
229
228
|
[Infinity, Infinity, -Infinity, -Infinity]
|
|
230
229
|
)
|
package/src/libs/feature/search/src/lib/results-table/results-table-container.component.html
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
[selectedRecordsIdentifiers]="selectedRecords$ | async"
|
|
5
5
|
[sortOrder]="sortBy$ | async"
|
|
6
6
|
(recordClick)="handleRecordClick($event)"
|
|
7
|
+
(duplicateRecord)="handleDuplicateRecord($event)"
|
|
7
8
|
(recordsSelectedChange)="handleRecordsSelectedChange($event[0], $event[1])"
|
|
8
9
|
(sortByChange)="handleSortByChange($event[0], $event[1])"
|
|
9
10
|
></gn-ui-results-table>
|
|
@@ -16,6 +16,7 @@ import { CommonModule } from '@angular/common'
|
|
|
16
16
|
})
|
|
17
17
|
export class ResultsTableContainerComponent {
|
|
18
18
|
@Output() recordClick = new EventEmitter<CatalogRecord>()
|
|
19
|
+
@Output() duplicateRecord = new EventEmitter<CatalogRecord>()
|
|
19
20
|
|
|
20
21
|
records$ = this.searchFacade.results$
|
|
21
22
|
selectedRecords$ = this.selectionService.selectedRecordsIdentifiers$
|
|
@@ -35,6 +36,10 @@ export class ResultsTableContainerComponent {
|
|
|
35
36
|
this.recordClick.emit(item as CatalogRecord)
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
handleDuplicateRecord(item: unknown) {
|
|
40
|
+
this.duplicateRecord.emit(item as CatalogRecord)
|
|
41
|
+
}
|
|
42
|
+
|
|
38
43
|
handleSortByChange(col: string, order: 'asc' | 'desc') {
|
|
39
44
|
this.searchService.setSortBy([order, col])
|
|
40
45
|
}
|
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
<div
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
></gn-ui-progress-bar>
|
|
15
|
-
</div>
|
|
16
|
-
<div
|
|
17
|
-
class="absolute z-10 bg-white border border-black border-opacity-35 rounded-lg shadow-lg p-5 whitespace-nowrap"
|
|
18
|
-
[class]="isMenuShown ? 'block' : 'hidden'"
|
|
19
|
-
>
|
|
1
|
+
<div *ngIf="metadataQualityDisplay" class="mb-6 metadata-quality">
|
|
2
|
+
<gn-ui-popover [content]="popoverItems" theme="light-border">
|
|
3
|
+
<div class="min-w-[200px]" [class]="smaller ? 'leading-[8px]' : ''">
|
|
4
|
+
<gn-ui-progress-bar
|
|
5
|
+
tabindex="0"
|
|
6
|
+
[value]="qualityScore"
|
|
7
|
+
type="primary"
|
|
8
|
+
></gn-ui-progress-bar>
|
|
9
|
+
</div>
|
|
10
|
+
</gn-ui-popover>
|
|
11
|
+
</div>
|
|
12
|
+
<ng-template #popoverItems>
|
|
13
|
+
<div class="p-2 py-4">
|
|
20
14
|
<div class="mb-4 font-bold" translate>record.metadata.quality.details</div>
|
|
21
15
|
<gn-ui-metadata-quality-item
|
|
22
16
|
*ngFor="let e of items"
|
|
@@ -24,4 +18,4 @@
|
|
|
24
18
|
[value]="e.value"
|
|
25
19
|
></gn-ui-metadata-quality-item>
|
|
26
20
|
</div>
|
|
27
|
-
</
|
|
21
|
+
</ng-template>
|
|
@@ -21,8 +21,6 @@ export class MetadataQualityComponent implements OnChanges {
|
|
|
21
21
|
|
|
22
22
|
items: MetadataQualityItem[] = []
|
|
23
23
|
|
|
24
|
-
isMenuShown = false
|
|
25
|
-
|
|
26
24
|
get qualityScore() {
|
|
27
25
|
const qualityScore = this.metadata?.extras?.qualityScore
|
|
28
26
|
return typeof qualityScore === 'number'
|
|
@@ -36,14 +34,6 @@ export class MetadataQualityComponent implements OnChanges {
|
|
|
36
34
|
)
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
showMenu() {
|
|
40
|
-
this.isMenuShown = true
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
hideMenu() {
|
|
44
|
-
this.isMenuShown = false
|
|
45
|
-
}
|
|
46
|
-
|
|
47
37
|
private add(name: string, value: boolean) {
|
|
48
38
|
if (this.metadataQualityDisplay?.[name] !== false) {
|
|
49
39
|
this.items.push({ name, value })
|
|
@@ -9,7 +9,7 @@ import { ContentGhostComponent } from './content-ghost/content-ghost.component'
|
|
|
9
9
|
import { DownloadItemComponent } from './download-item/download-item.component'
|
|
10
10
|
import { DownloadsListComponent } from './downloads-list/downloads-list.component'
|
|
11
11
|
import { ApiCardComponent } from './api-card/api-card.component'
|
|
12
|
-
import { UiWidgetsModule } from '../../../../../libs/ui/widgets/src'
|
|
12
|
+
import { PopoverComponent, UiWidgetsModule } from '../../../../../libs/ui/widgets/src'
|
|
13
13
|
import { MaxLinesComponent, UiLayoutModule } from '../../../../../libs/ui/layout/src'
|
|
14
14
|
import { TranslateModule } from '@ngx-translate/core'
|
|
15
15
|
import { RelatedRecordCardComponent } from './related-record-card/related-record-card.component'
|
|
@@ -45,6 +45,7 @@ import { TimeSincePipe } from './user-feedback-item/time-since.pipe'
|
|
|
45
45
|
UiInputsModule,
|
|
46
46
|
FormsModule,
|
|
47
47
|
NgOptimizedImage,
|
|
48
|
+
PopoverComponent,
|
|
48
49
|
MarkdownParserComponent,
|
|
49
50
|
ThumbnailComponent,
|
|
50
51
|
TimeSincePipe,
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
<div class="w-full h-full flex flex-col gap-2">
|
|
52
52
|
<label
|
|
53
53
|
gnUiFilesDrop
|
|
54
|
-
class="block flex-1 border-2 border-dashed border-gray-300 rounded-lg p-6 flex flex-col items-center justify-center gap-4"
|
|
54
|
+
class="block flex-1 border-2 border-dashed border-gray-300 rounded-lg p-6 flex flex-col items-center justify-center gap-4 hover:cursor-pointer"
|
|
55
55
|
(dragFilesOver)="handleDragFilesOver($event)"
|
|
56
56
|
(dropFiles)="handleDropFiles($event)"
|
|
57
57
|
>
|
|
@@ -16,6 +16,7 @@ import { ButtonComponent } from '../button/button.component'
|
|
|
16
16
|
import { FilesDropDirective } from '../files-drop/files-drop.directive'
|
|
17
17
|
import { TranslateModule } from '@ngx-translate/core'
|
|
18
18
|
import { marker } from '@biesbjerg/ngx-translate-extract-marker'
|
|
19
|
+
import { FormControl, ReactiveFormsModule } from '@angular/forms'
|
|
19
20
|
|
|
20
21
|
@Component({
|
|
21
22
|
selector: 'gn-ui-image-input',
|
|
@@ -30,11 +31,13 @@ import { marker } from '@biesbjerg/ngx-translate-extract-marker'
|
|
|
30
31
|
FilesDropDirective,
|
|
31
32
|
MatProgressSpinnerModule,
|
|
32
33
|
TranslateModule,
|
|
34
|
+
ReactiveFormsModule,
|
|
33
35
|
],
|
|
34
36
|
})
|
|
35
37
|
export class ImageInputComponent {
|
|
38
|
+
@Input() formControl!: FormControl
|
|
36
39
|
@Input() maxSizeMB: number
|
|
37
|
-
@Input() previewUrl?:
|
|
40
|
+
@Input() previewUrl?: URL
|
|
38
41
|
@Input() altText?: string
|
|
39
42
|
@Input() uploadProgress?: number
|
|
40
43
|
@Input() uploadError?: boolean
|
|
@@ -127,7 +130,8 @@ export class ImageInputComponent {
|
|
|
127
130
|
const file = new File([blob], name)
|
|
128
131
|
this.fileChange.emit(file)
|
|
129
132
|
},
|
|
130
|
-
error: () => {
|
|
133
|
+
error: (error) => {
|
|
134
|
+
console.error(error)
|
|
131
135
|
this.downloadError = true
|
|
132
136
|
this.cd.markForCheck()
|
|
133
137
|
this.urlChange.emit(this.urlInputValue)
|
|
@@ -165,6 +169,7 @@ export class ImageInputComponent {
|
|
|
165
169
|
}
|
|
166
170
|
|
|
167
171
|
handleDelete() {
|
|
172
|
+
this.formControl.markAsDirty()
|
|
168
173
|
this.delete.emit()
|
|
169
174
|
}
|
|
170
175
|
|
|
File without changes
|