geonetwork-ui 2.2.0-dev.6f0f0ee9 → 2.2.0-dev.70a9dc16
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 +16 -4
- package/esm2022/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.mjs +3 -1
- package/esm2022/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.mjs +1 -1
- package/esm2022/libs/api/metadata-converter/src/lib/iso19139/converter.mjs +7 -2
- package/esm2022/libs/api/metadata-converter/src/lib/iso19139/read-parts.mjs +4 -1
- package/esm2022/libs/api/metadata-converter/src/lib/iso19139/write-parts.mjs +1 -1
- package/esm2022/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.mjs +2 -2
- package/esm2022/libs/common/domain/src/lib/model/record/metadata.model.mjs +1 -1
- package/esm2022/libs/feature/editor/src/index.mjs +6 -1
- package/esm2022/libs/feature/editor/src/lib/+state/editor.actions.mjs +8 -0
- package/esm2022/libs/feature/editor/src/lib/+state/editor.effects.mjs +26 -0
- package/esm2022/libs/feature/editor/src/lib/+state/editor.facade.mjs +30 -0
- package/esm2022/libs/feature/editor/src/lib/+state/editor.models.mjs +2 -0
- package/esm2022/libs/feature/editor/src/lib/+state/editor.reducer.mjs +42 -0
- package/esm2022/libs/feature/editor/src/lib/+state/editor.selectors.mjs +13 -0
- package/esm2022/libs/feature/editor/src/lib/expressions.mjs +13 -0
- package/esm2022/libs/feature/editor/src/lib/feature-editor.module.mjs +16 -4
- package/esm2022/libs/feature/editor/src/lib/fields.config.mjs +34 -0
- package/esm2022/libs/feature/editor/src/lib/models/fields.model.mjs +2 -0
- package/esm2022/libs/feature/editor/src/lib/record-form/record-form.component.mjs +15 -11
- package/esm2022/libs/feature/editor/src/lib/services/editor.service.mjs +22 -44
- package/esm2022/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.mjs +13 -13
- package/esm2022/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/max-lines/max-lines.component.mjs +5 -3
- package/esm2022/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.mjs +3 -3
- package/esm2022/libs/ui/elements/src/lib/metadata-info/metadata-info.component.mjs +17 -5
- package/esm2022/libs/ui/inputs/src/lib/button/button.component.mjs +9 -9
- package/esm2022/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.mjs +3 -3
- package/esm2022/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.mjs +3 -3
- package/esm2022/libs/ui/inputs/src/lib/form-field/form-field.component.mjs +4 -2
- package/esm2022/libs/ui/inputs/src/lib/form-field/form-field.model.mjs +1 -1
- package/esm2022/libs/ui/layout/src/lib/carousel/carousel.component.mjs +3 -3
- package/esm2022/libs/util/i18n/src/lib/i18n.constants.mjs +18 -1
- package/esm2022/libs/util/shared/src/lib/utils/index.mjs +2 -1
- package/esm2022/libs/util/shared/src/lib/utils/temporal-extent-union.mjs +32 -0
- package/esm2022/translations/de.json +35 -26
- package/esm2022/translations/en.json +27 -18
- package/esm2022/translations/es.json +24 -15
- package/esm2022/translations/fr.json +45 -36
- package/esm2022/translations/it.json +39 -30
- package/esm2022/translations/nl.json +25 -16
- package/esm2022/translations/pt.json +24 -15
- package/fesm2022/geonetwork-ui.mjs +575 -294
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts +1 -0
- package/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/iso19139/converter.d.ts.map +1 -1
- package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts +1 -0
- package/libs/api/metadata-converter/src/lib/iso19139/read-parts.d.ts.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/elasticsearch/elasticsearch.service.d.ts.map +1 -1
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts +3 -0
- package/libs/common/domain/src/lib/model/record/metadata.model.d.ts.map +1 -1
- package/libs/feature/editor/src/index.d.ts +5 -0
- package/libs/feature/editor/src/index.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/+state/editor.actions.d.ts +23 -0
- package/libs/feature/editor/src/lib/+state/editor.actions.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/+state/editor.effects.d.ts +15 -0
- package/libs/feature/editor/src/lib/+state/editor.effects.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/+state/editor.facade.d.ts +19 -0
- package/libs/feature/editor/src/lib/+state/editor.facade.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/+state/editor.models.d.ts +2 -0
- package/libs/feature/editor/src/lib/+state/editor.models.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/+state/editor.reducer.d.ts +18 -0
- package/libs/feature/editor/src/lib/+state/editor.reducer.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/+state/editor.selectors.d.ts +15 -0
- package/libs/feature/editor/src/lib/+state/editor.selectors.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/expressions.d.ts +4 -0
- package/libs/feature/editor/src/lib/expressions.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/feature-editor.module.d.ts +3 -1
- package/libs/feature/editor/src/lib/feature-editor.module.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/fields.config.d.ts +3 -0
- package/libs/feature/editor/src/lib/fields.config.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/models/fields.model.d.ts +15 -0
- package/libs/feature/editor/src/lib/models/fields.model.d.ts.map +1 -0
- package/libs/feature/editor/src/lib/record-form/record-form.component.d.ts +10 -5
- package/libs/feature/editor/src/lib/record-form/record-form.component.d.ts.map +1 -1
- package/libs/feature/editor/src/lib/services/editor.service.d.ts +3 -13
- package/libs/feature/editor/src/lib/services/editor.service.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/max-lines/max-lines.component.d.ts.map +1 -1
- package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts +6 -0
- package/libs/ui/elements/src/lib/metadata-info/metadata-info.component.d.ts.map +1 -1
- package/libs/ui/inputs/src/lib/button/button.component.d.ts.map +1 -1
- package/libs/ui/inputs/src/lib/form-field/form-field.component.d.ts.map +1 -1
- package/libs/ui/inputs/src/lib/form-field/form-field.model.d.ts +0 -1
- package/libs/ui/inputs/src/lib/form-field/form-field.model.d.ts.map +1 -1
- package/libs/util/i18n/src/lib/i18n.constants.d.ts +17 -0
- package/libs/util/i18n/src/lib/i18n.constants.d.ts.map +1 -1
- package/libs/util/shared/src/lib/utils/index.d.ts +1 -0
- package/libs/util/shared/src/lib/utils/index.d.ts.map +1 -1
- package/libs/util/shared/src/lib/utils/temporal-extent-union.d.ts +5 -0
- package/libs/util/shared/src/lib/utils/temporal-extent-union.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/libs/api/metadata-converter/src/lib/fixtures/generic.records.ts +2 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geo2france.records.ts +2 -0
- package/src/libs/api/metadata-converter/src/lib/fixtures/geocat-ch.records.ts +4 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +19 -3
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.metadata.mapper.ts +2 -0
- package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/converter.ts +6 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +5 -1
- package/src/libs/api/metadata-converter/src/lib/iso19139/write-parts.ts +8 -2
- package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +1 -1
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +4 -0
- package/src/libs/common/fixtures/src/lib/elasticsearch/full-response.ts +1 -1
- package/src/libs/common/fixtures/src/lib/records.fixtures.ts +2 -0
- package/src/libs/feature/editor/src/index.ts +5 -0
- package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +24 -0
- package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +49 -0
- package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +30 -0
- package/src/libs/feature/editor/src/lib/+state/editor.models.ts +1 -0
- package/src/libs/feature/editor/src/lib/+state/editor.reducer.ts +68 -0
- package/src/libs/feature/editor/src/lib/+state/editor.selectors.ts +39 -0
- package/src/libs/feature/editor/src/lib/expressions.ts +16 -0
- package/src/libs/feature/editor/src/lib/feature-editor.module.ts +11 -0
- package/src/libs/feature/editor/src/lib/fields.config.ts +35 -0
- package/src/libs/feature/editor/src/lib/models/fields.model.ts +29 -0
- package/src/libs/feature/editor/src/lib/record-form/record-form.component.html +9 -7
- package/src/libs/feature/editor/src/lib/record-form/record-form.component.ts +11 -5
- package/src/libs/feature/editor/src/lib/services/editor.service.ts +34 -73
- package/src/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.ts +12 -12
- package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.html +1 -1
- package/src/libs/ui/elements/src/lib/max-lines/max-lines.component.html +5 -1
- package/src/libs/ui/elements/src/lib/max-lines/max-lines.component.ts +1 -0
- package/src/libs/ui/elements/src/lib/metadata-contact/metadata-contact.component.html +1 -1
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +107 -19
- package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +14 -0
- package/src/libs/ui/inputs/src/lib/button/button.component.css +0 -5
- package/src/libs/ui/inputs/src/lib/button/button.component.html +0 -1
- package/src/libs/ui/inputs/src/lib/button/button.component.ts +6 -6
- package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
- package/src/libs/ui/inputs/src/lib/dropdown-selector/dropdown-selector.component.html +3 -1
- package/src/libs/ui/inputs/src/lib/form-field/form-field.component.ts +3 -1
- package/src/libs/ui/inputs/src/lib/form-field/form-field.model.ts +0 -1
- package/src/libs/ui/layout/src/lib/carousel/carousel.component.html +1 -0
- package/src/libs/util/i18n/src/lib/i18n.constants.ts +18 -0
- package/src/libs/util/shared/src/lib/utils/index.ts +1 -0
- package/src/libs/util/shared/src/lib/utils/temporal-extent-union.ts +32 -0
- package/tailwind.base.config.js +0 -3
- package/tailwind.base.css +43 -14
- package/translations/de.json +35 -26
- package/translations/en.json +27 -18
- package/translations/es.json +24 -15
- package/translations/fr.json +45 -36
- package/translations/it.json +39 -30
- package/translations/nl.json +25 -16
- package/translations/pt.json +24 -15
- package/translations/sk.json +117 -108
|
@@ -1,59 +1,27 @@
|
|
|
1
1
|
import { Inject, Injectable, Optional } from '@angular/core'
|
|
2
2
|
import { toModel, toXml } from '../../../../../../libs/api/metadata-converter/src'
|
|
3
3
|
import { Configuration } from '../../../../../../libs/data-access/gn4/src'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { Observable } from 'rxjs'
|
|
5
|
+
import { map } from 'rxjs/operators'
|
|
6
6
|
import { HttpClient } from '@angular/common/http'
|
|
7
|
-
import { FormFieldConfig } from '../../../../../../libs/ui/inputs/src'
|
|
8
7
|
import { CatalogRecord } from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
config: FormFieldConfig
|
|
12
|
-
value: string | number | boolean | unknown
|
|
13
|
-
}
|
|
8
|
+
import { EditorFieldsConfig } from '../models/fields.model'
|
|
9
|
+
import { evaluate } from '../expressions'
|
|
14
10
|
|
|
15
11
|
@Injectable({
|
|
16
12
|
providedIn: 'root',
|
|
17
13
|
})
|
|
18
14
|
export class EditorService {
|
|
19
|
-
private record$ = new BehaviorSubject<CatalogRecord | null>(null)
|
|
20
|
-
private fieldsConfig: FormFieldConfig[] = [
|
|
21
|
-
{
|
|
22
|
-
model: 'title',
|
|
23
|
-
labelKey: 'Metadata title',
|
|
24
|
-
type: 'text',
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
model: 'abstract',
|
|
28
|
-
labelKey: 'Abstract',
|
|
29
|
-
type: 'rich',
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
model: 'uniqueIdentifier',
|
|
33
|
-
labelKey: 'Unique identifier',
|
|
34
|
-
type: 'text',
|
|
35
|
-
locked: true,
|
|
36
|
-
},
|
|
37
|
-
]
|
|
38
|
-
|
|
39
15
|
private apiUrl = `${this.apiConfiguration?.basePath || '/geonetwork/srv/api'}`
|
|
40
16
|
|
|
41
|
-
fields$: Observable<FormField[]> = this.record$.pipe(
|
|
42
|
-
map((record) =>
|
|
43
|
-
this.fieldsConfig.map((fieldConfig) => ({
|
|
44
|
-
config: fieldConfig,
|
|
45
|
-
value: record?.[fieldConfig.model] || null,
|
|
46
|
-
}))
|
|
47
|
-
)
|
|
48
|
-
)
|
|
49
|
-
saving$ = new BehaviorSubject(false)
|
|
50
|
-
|
|
51
17
|
constructor(
|
|
52
18
|
private http: HttpClient,
|
|
53
19
|
@Optional()
|
|
54
20
|
@Inject(Configuration)
|
|
55
21
|
private apiConfiguration: Configuration
|
|
56
22
|
) {}
|
|
23
|
+
|
|
24
|
+
// TODO: use the catalog repository instead
|
|
57
25
|
loadRecordByUuid(uuid: string): Observable<CatalogRecord> {
|
|
58
26
|
return this.http
|
|
59
27
|
.get(`${this.apiUrl}/records/${uuid}/formatters/xml`, {
|
|
@@ -65,43 +33,36 @@ export class EditorService {
|
|
|
65
33
|
.pipe(map((response) => toModel(response.toString())))
|
|
66
34
|
}
|
|
67
35
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
this.saving$.next(true)
|
|
75
|
-
}),
|
|
76
|
-
switchMap((record) =>
|
|
77
|
-
this.http.put(
|
|
78
|
-
`${this.apiUrl}/records?metadataType=METADATA&uuidProcessing=OVERWRITE&transformWith=_none_&publishToAll=on`,
|
|
79
|
-
toXml(record),
|
|
80
|
-
{
|
|
81
|
-
headers: {
|
|
82
|
-
'Content-Type': 'application/xml',
|
|
83
|
-
},
|
|
84
|
-
withCredentials: true,
|
|
85
|
-
}
|
|
86
|
-
)
|
|
87
|
-
),
|
|
88
|
-
map(() => undefined),
|
|
89
|
-
finalize(() => {
|
|
90
|
-
this.saving$.next(false)
|
|
91
|
-
})
|
|
92
|
-
)
|
|
93
|
-
}
|
|
36
|
+
// returns the record as it was when saved
|
|
37
|
+
saveRecord(
|
|
38
|
+
record: CatalogRecord,
|
|
39
|
+
fieldsConfig: EditorFieldsConfig
|
|
40
|
+
): Observable<CatalogRecord> {
|
|
41
|
+
const savedRecord = { ...record }
|
|
94
42
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
43
|
+
// run onSave processes
|
|
44
|
+
for (const field of fieldsConfig) {
|
|
45
|
+
if (field.onSaveProcess && field.model) {
|
|
46
|
+
const evaluator = evaluate(field.onSaveProcess)
|
|
47
|
+
savedRecord[field.model] = evaluator({
|
|
48
|
+
config: field,
|
|
49
|
+
value: record[field.model],
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
98
53
|
|
|
99
|
-
|
|
100
|
-
this.
|
|
101
|
-
.
|
|
102
|
-
|
|
103
|
-
|
|
54
|
+
// TODO: use the catalog repository instead
|
|
55
|
+
return this.http
|
|
56
|
+
.put(
|
|
57
|
+
`${this.apiUrl}/records?metadataType=METADATA&uuidProcessing=OVERWRITE&transformWith=_none_&publishToAll=on`,
|
|
58
|
+
toXml(savedRecord),
|
|
59
|
+
{
|
|
60
|
+
headers: {
|
|
61
|
+
'Content-Type': 'application/xml',
|
|
62
|
+
},
|
|
63
|
+
withCredentials: true,
|
|
64
|
+
}
|
|
104
65
|
)
|
|
105
|
-
.
|
|
66
|
+
.pipe(map(() => savedRecord))
|
|
106
67
|
}
|
|
107
68
|
}
|
package/src/libs/feature/record/src/lib/data-view-permalink/data-view-permalink.component.ts
CHANGED
|
@@ -29,18 +29,18 @@ export class DataViewPermalinkComponent {
|
|
|
29
29
|
if (config) {
|
|
30
30
|
const { aggregation, xProperty, yProperty, chartType } = config
|
|
31
31
|
const url = new URL(`${this.wcEmbedderBaseUrl}`, window.location.origin)
|
|
32
|
-
url.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
url.searchParams.set('v', `${this.version}`)
|
|
33
|
+
url.searchParams.append('e', `gn-dataset-view-chart`)
|
|
34
|
+
url.searchParams.append('a', `api-url=${this.config.basePath}`)
|
|
35
|
+
url.searchParams.append('a', `dataset-id=${metadata.uniqueIdentifier}`)
|
|
36
|
+
url.searchParams.append('a', `primary-color=#0f4395`)
|
|
37
|
+
url.searchParams.append('a', `secondary-color=#8bc832`)
|
|
38
|
+
url.searchParams.append('a', `main-color=#555`)
|
|
39
|
+
url.searchParams.append('a', `background-color=#fdfbff`)
|
|
40
|
+
url.searchParams.append('a', `aggregation=${aggregation}`)
|
|
41
|
+
url.searchParams.append('a', `x-property=${xProperty}`)
|
|
42
|
+
url.searchParams.append('a', `y-property=${yProperty}`)
|
|
43
|
+
url.searchParams.append('a', `chart-type=${chartType}`)
|
|
44
44
|
return url.toString()
|
|
45
45
|
}
|
|
46
46
|
return ''
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
<div
|
|
2
2
|
#container
|
|
3
|
-
class="max-lines overflow-hidden transition-[max-height] duration-300"
|
|
3
|
+
class="max-lines overflow-hidden transition-[max-height] duration-300 relative"
|
|
4
4
|
[ngClass]="isExpanded ? 'ease-in' : 'ease-out'"
|
|
5
5
|
[style.maxHeight]="maxHeight"
|
|
6
6
|
>
|
|
7
7
|
<ng-content></ng-content>
|
|
8
|
+
<div
|
|
9
|
+
*ngIf="showToggleButton && !isExpanded"
|
|
10
|
+
class="absolute inset-x-0 bottom-0 bg-gradient-to-b from-transparent to-white h-3"
|
|
11
|
+
></div>
|
|
8
12
|
</div>
|
|
9
13
|
<div
|
|
10
14
|
*ngIf="showToggleButton"
|
|
@@ -55,29 +55,82 @@
|
|
|
55
55
|
</div>
|
|
56
56
|
</gn-ui-expandable-panel>
|
|
57
57
|
<gn-ui-expandable-panel
|
|
58
|
-
class="metadata-origin"
|
|
59
58
|
*ngIf="
|
|
60
59
|
metadata.lineage ||
|
|
61
60
|
metadata.recordUpdated ||
|
|
62
61
|
metadata.updateFrequency ||
|
|
63
62
|
metadata.status
|
|
64
63
|
"
|
|
65
|
-
[title]="'record.metadata.
|
|
64
|
+
[title]="'record.metadata.details' | translate"
|
|
66
65
|
>
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
>
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
<div *ngIf="metadata.lineage" class="text-gray-900 flex flex-col mt-4 gap-2">
|
|
67
|
+
<p class="whitespace-pre-line break-words text-gray-900" gnUiLinkify>
|
|
68
|
+
{{ metadata.lineage }}
|
|
69
|
+
</p>
|
|
70
|
+
</div>
|
|
71
|
+
<div class="flex flex-row gap-6 mt-5 mb-8" *ngIf="resourceContact">
|
|
72
|
+
<div
|
|
73
|
+
*ngIf="resourceContact.organization?.logoUrl?.href"
|
|
74
|
+
class="flex items-center justify-center border-solid border border-gray-300 rounded-md bg-white h-32 overflow-hidden"
|
|
75
|
+
>
|
|
76
|
+
<gn-ui-thumbnail
|
|
77
|
+
class="relative h-full w-full"
|
|
78
|
+
[thumbnailUrl]="resourceContact.organization.logoUrl.href"
|
|
79
|
+
fit="contain"
|
|
80
|
+
></gn-ui-thumbnail>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="flex flex-col gap-1">
|
|
83
|
+
<p class="text-sm font-medium" translate>record.metadata.producer</p>
|
|
84
|
+
<div
|
|
85
|
+
class="text-primary font-title text-21 mr-2 cursor-pointer hover:underline"
|
|
86
|
+
data-cy="organization-name"
|
|
87
|
+
>
|
|
88
|
+
{{ resourceContact.organization?.name }}
|
|
89
|
+
</div>
|
|
90
|
+
<div *ngIf="resourceContact.organization?.website">
|
|
91
|
+
<a
|
|
92
|
+
[href]="resourceContact.organization.website"
|
|
93
|
+
target="_blank"
|
|
94
|
+
class="contact-website text-primary text-sm cursor-pointer hover:underline transition-all"
|
|
95
|
+
>{{ resourceContact.organization.website }}
|
|
96
|
+
<mat-icon
|
|
97
|
+
class="material-symbols-outlined !w-[12px] !h-[12px] !text-[12px] opacity-75 shrink-0"
|
|
98
|
+
>open_in_new</mat-icon
|
|
99
|
+
>
|
|
100
|
+
</a>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="mt-4" *ngIf="resourceContact.email">
|
|
103
|
+
<div class="flex">
|
|
104
|
+
<mat-icon
|
|
105
|
+
class="material-symbols-outlined !w-5 !h-5 !text-[20px] opacity-75 shrink-0"
|
|
106
|
+
>
|
|
107
|
+
mail_outline</mat-icon
|
|
108
|
+
>
|
|
109
|
+
<a
|
|
110
|
+
*ngIf="resourceContact.email"
|
|
111
|
+
[href]="'mailto:' + resourceContact.email"
|
|
112
|
+
class="text-sm hover:underline ml-2"
|
|
113
|
+
target="_blank"
|
|
114
|
+
data-cy="contact-email"
|
|
115
|
+
>{{ resourceContact?.email }}</a
|
|
116
|
+
>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
74
121
|
<div
|
|
75
|
-
class="py-
|
|
122
|
+
class="py-6 px-6 rounded bg-gray-100 grid grid-cols-2 gap-y-6 gap-x-[20px] text-gray-700"
|
|
76
123
|
>
|
|
77
|
-
<div *ngIf="metadata.
|
|
78
|
-
<p class="text-sm" translate>record.metadata.
|
|
124
|
+
<div *ngIf="metadata.recordCreated">
|
|
125
|
+
<p class="text-sm" translate>record.metadata.creation</p>
|
|
79
126
|
<p class="text-primary font-medium mt-1">
|
|
80
|
-
{{ metadata.
|
|
127
|
+
{{ metadata.recordCreated.toLocaleDateString() }}
|
|
128
|
+
</p>
|
|
129
|
+
</div>
|
|
130
|
+
<div *ngIf="metadata.recordPublished">
|
|
131
|
+
<p class="text-sm" translate>record.metadata.publication</p>
|
|
132
|
+
<p class="text-primary font-medium mt-1">
|
|
133
|
+
{{ metadata.recordPublished.toLocaleDateString() }}
|
|
81
134
|
</p>
|
|
82
135
|
</div>
|
|
83
136
|
<div *ngIf="updateFrequency">
|
|
@@ -90,17 +143,52 @@
|
|
|
90
143
|
{{ updateFrequency }}
|
|
91
144
|
</p>
|
|
92
145
|
</div>
|
|
93
|
-
<div *ngIf="metadata.
|
|
94
|
-
<p class="text-sm" translate>record.metadata.
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
146
|
+
<div *ngIf="metadata.languages">
|
|
147
|
+
<p class="text-sm mb-1" translate>record.metadata.languages</p>
|
|
148
|
+
<div class="flex flex-row gap-1 flex-wrap">
|
|
149
|
+
<p
|
|
150
|
+
class="text-primary font-medium"
|
|
151
|
+
translate
|
|
152
|
+
*ngFor="let language of metadata.languages"
|
|
153
|
+
>
|
|
154
|
+
language.{{ language }}
|
|
155
|
+
</p>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
<div *ngIf="temporalExtent">
|
|
159
|
+
<p class="text-sm" translate>record.metadata.temporalExtent</p>
|
|
160
|
+
<div class="flex flex-row gap-1 mb-1 text-primary font-medium">
|
|
161
|
+
<p
|
|
162
|
+
*ngIf="temporalExtent.start && temporalExtent.end"
|
|
163
|
+
translate
|
|
164
|
+
[translateParams]="{
|
|
165
|
+
start: temporalExtent.start,
|
|
166
|
+
end: temporalExtent.end
|
|
167
|
+
}"
|
|
168
|
+
>
|
|
169
|
+
record.metadata.temporalExtent.fromDateToDate
|
|
170
|
+
</p>
|
|
171
|
+
<p
|
|
172
|
+
*ngIf="temporalExtent.start && !temporalExtent.end"
|
|
173
|
+
translate
|
|
174
|
+
[translateParams]="{ start: temporalExtent.start }"
|
|
175
|
+
>
|
|
176
|
+
record.metadata.temporalExtent.sinceDate
|
|
177
|
+
</p>
|
|
178
|
+
<p
|
|
179
|
+
*ngIf="!temporalExtent.start && temporalExtent.end"
|
|
180
|
+
translate
|
|
181
|
+
[translateParams]="{ end: temporalExtent.end }"
|
|
182
|
+
>
|
|
183
|
+
record.metadata.temporalExtent.untilDate
|
|
184
|
+
</p>
|
|
185
|
+
</div>
|
|
98
186
|
</div>
|
|
99
187
|
</div>
|
|
100
188
|
</gn-ui-expandable-panel>
|
|
101
189
|
<gn-ui-expandable-panel
|
|
102
190
|
*ngIf="metadata.landingPage"
|
|
103
|
-
[title]="'record.metadata.
|
|
191
|
+
[title]="'record.metadata.technical' | translate"
|
|
104
192
|
>
|
|
105
193
|
<div class="flex flex-col gap-4 mr-4 py-5 rounded text-gray-700">
|
|
106
194
|
<div *ngIf="metadata.recordUpdated">
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
DatasetRecord,
|
|
10
10
|
Keyword,
|
|
11
11
|
} from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
12
|
+
import { getTemporalRangeUnion } from '../../../../../../libs/util/shared/src'
|
|
12
13
|
|
|
13
14
|
@Component({
|
|
14
15
|
selector: 'gn-ui-metadata-info',
|
|
@@ -76,6 +77,19 @@ export class MetadataInfoComponent {
|
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
get temporalExtent(): { start: string; end: string } {
|
|
81
|
+
const temporalExtents = this.metadata.temporalExtents
|
|
82
|
+
return getTemporalRangeUnion(temporalExtents)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get shownOrganization() {
|
|
86
|
+
return this.metadata.ownerOrganization
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get resourceContact() {
|
|
90
|
+
return this.metadata.contactsForResource?.[0]
|
|
91
|
+
}
|
|
92
|
+
|
|
79
93
|
fieldReady(propName: string) {
|
|
80
94
|
return !this.incomplete || propName in this.metadata
|
|
81
95
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<button
|
|
2
2
|
type="button"
|
|
3
|
-
class="flex flex-row items-center text-[1em] leading-none p-[1em] rounded-[0.25em] transition-all duration-100 focus:outline-none disabled:opacity-50 disabled:pointer-events-none"
|
|
4
3
|
[class]="classList"
|
|
5
4
|
[disabled]="disabled"
|
|
6
5
|
(click)="handleClick($event)"
|
|
@@ -17,25 +17,25 @@ import { propagateToDocumentOnly } from '../../../../../../libs/util/shared/src'
|
|
|
17
17
|
export class ButtonComponent {
|
|
18
18
|
private btnClass: string
|
|
19
19
|
|
|
20
|
-
// btn-classes are explicited to allow tailwind recognize them and add it in css.
|
|
21
20
|
@Input() set type(
|
|
22
21
|
value: 'primary' | 'secondary' | 'default' | 'outline' | 'light'
|
|
23
22
|
) {
|
|
23
|
+
// btn-classes are written in full to be picked up by tailwind
|
|
24
24
|
switch (value) {
|
|
25
25
|
case 'primary':
|
|
26
|
-
this.btnClass = 'btn-primary'
|
|
26
|
+
this.btnClass = 'gn-ui-btn-primary'
|
|
27
27
|
break
|
|
28
28
|
case 'secondary':
|
|
29
|
-
this.btnClass = 'btn-secondary'
|
|
29
|
+
this.btnClass = 'gn-ui-btn-secondary'
|
|
30
30
|
break
|
|
31
31
|
case 'outline':
|
|
32
|
-
this.btnClass = 'btn-outline'
|
|
32
|
+
this.btnClass = 'gn-ui-btn-outline'
|
|
33
33
|
break
|
|
34
34
|
case 'light':
|
|
35
|
-
this.btnClass = 'btn-light'
|
|
35
|
+
this.btnClass = 'gn-ui-btn-light'
|
|
36
36
|
break
|
|
37
37
|
default:
|
|
38
|
-
this.btnClass = 'btn-default'
|
|
38
|
+
this.btnClass = 'gn-ui-btn-default'
|
|
39
39
|
break
|
|
40
40
|
}
|
|
41
41
|
}
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
<gn-ui-button
|
|
10
10
|
type="outline"
|
|
11
11
|
class="grow min-w-0"
|
|
12
|
-
extraClass="!p-[8px] !pl-[16px] flex flex-row w-full {{
|
|
12
|
+
extraClass="bg-background !p-[8px] !pl-[16px] flex flex-row w-full {{
|
|
13
|
+
extraBtnClass
|
|
14
|
+
}}"
|
|
13
15
|
[title]="title"
|
|
14
16
|
[attr.aria-owns]="id"
|
|
15
17
|
(buttonClick)="openOverlay()"
|
|
@@ -17,7 +17,9 @@ import { Observable } from 'rxjs'
|
|
|
17
17
|
export class FormFieldComponent {
|
|
18
18
|
@Input() config: FormFieldConfig
|
|
19
19
|
@Input() set value(v: unknown) {
|
|
20
|
-
this.formControl.setValue(v
|
|
20
|
+
this.formControl.setValue(v, {
|
|
21
|
+
emitEvent: false,
|
|
22
|
+
})
|
|
21
23
|
}
|
|
22
24
|
@Output() valueChange: Observable<unknown>
|
|
23
25
|
|
|
@@ -40,6 +40,24 @@ export const LANG_3_TO_2_MAPPER = {
|
|
|
40
40
|
slo: 'sk',
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export const LANGUAGE_NAMES = {
|
|
44
|
+
en: 'English',
|
|
45
|
+
nl: 'Nederlands',
|
|
46
|
+
fr: 'Français',
|
|
47
|
+
de: 'Deutsch',
|
|
48
|
+
ko: '한국어',
|
|
49
|
+
es: 'Español',
|
|
50
|
+
cs: 'Čeština',
|
|
51
|
+
ca: 'Català',
|
|
52
|
+
fi: 'Suomi',
|
|
53
|
+
is: 'Íslenska',
|
|
54
|
+
it: 'Italiano',
|
|
55
|
+
pt: 'Português',
|
|
56
|
+
ru: 'Русский',
|
|
57
|
+
zh: '中文',
|
|
58
|
+
sk: 'Slovenčina',
|
|
59
|
+
}
|
|
60
|
+
|
|
43
61
|
// Caution: changing this can break language selection from third parties!
|
|
44
62
|
export const LANGUAGE_STORAGE_KEY = 'geonetwork-ui-language'
|
|
45
63
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function getTemporalRangeUnion(ranges) {
|
|
2
|
+
let earliestStartDate = Infinity
|
|
3
|
+
let latestEndDate = -Infinity
|
|
4
|
+
if (ranges.length) {
|
|
5
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
6
|
+
const rangeStart = ranges[i].start
|
|
7
|
+
? new Date(ranges[i].start).getTime()
|
|
8
|
+
: -Infinity
|
|
9
|
+
const rangeEnd = ranges[i].end
|
|
10
|
+
? new Date(ranges[i].end).getTime()
|
|
11
|
+
: Infinity
|
|
12
|
+
if (rangeStart < earliestStartDate) {
|
|
13
|
+
earliestStartDate = rangeStart
|
|
14
|
+
}
|
|
15
|
+
if (rangeEnd > latestEndDate) {
|
|
16
|
+
latestEndDate = rangeEnd
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
start:
|
|
21
|
+
earliestStartDate !== -Infinity
|
|
22
|
+
? new Date(earliestStartDate).toLocaleDateString()
|
|
23
|
+
: undefined,
|
|
24
|
+
end:
|
|
25
|
+
latestEndDate !== Infinity
|
|
26
|
+
? new Date(latestEndDate).toLocaleDateString()
|
|
27
|
+
: undefined,
|
|
28
|
+
}
|
|
29
|
+
} else {
|
|
30
|
+
return undefined
|
|
31
|
+
}
|
|
32
|
+
}
|
package/tailwind.base.config.js
CHANGED
|
@@ -52,9 +52,6 @@ module.exports = {
|
|
|
52
52
|
'var(--font-family-title, ui-serif, Georgia, Cambria, "Times New Roman", Times, serif)', // alias for serif
|
|
53
53
|
mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace',
|
|
54
54
|
},
|
|
55
|
-
fontWeight: {
|
|
56
|
-
title: '600',
|
|
57
|
-
},
|
|
58
55
|
fontSize: {
|
|
59
56
|
13: '13px',
|
|
60
57
|
21: [
|
package/tailwind.base.css
CHANGED
|
@@ -2,49 +2,78 @@
|
|
|
2
2
|
@tailwind components;
|
|
3
3
|
@tailwind utilities;
|
|
4
4
|
|
|
5
|
+
/* PLEASE NOTE: all Tailwind components should be prefixed by `gn-ui` */
|
|
5
6
|
@layer components {
|
|
7
|
+
/* TODO: add prefix */
|
|
6
8
|
.card-shadow {
|
|
7
9
|
@apply shadow-xl hover:shadow-xl-hover transition-shadow;
|
|
8
10
|
}
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
/* BUTTON CLASSES */
|
|
13
|
+
/* these are used behind the scenes by the `gn-ui-button` component */
|
|
14
|
+
|
|
15
|
+
/* this is a base class, do not use it directly */
|
|
16
|
+
.gn-ui-btn {
|
|
17
|
+
--rounded: var(--gn-ui-button-rounded, 0.25em);
|
|
18
|
+
--padding: var(--gn-ui-button-padding, 1em);
|
|
19
|
+
--width: var(--gn-ui-button-width, auto);
|
|
20
|
+
--height: var(--gn-ui-button-height, auto);
|
|
21
|
+
--background: var(--gn-ui-button-background, --color-background);
|
|
22
|
+
--font-size: var(--gn-ui-button-font-size, 1em);
|
|
23
|
+
@apply flex flex-row items-center justify-center
|
|
24
|
+
text-[length:--font-size] leading-none
|
|
25
|
+
p-[--padding] rounded-[--rounded] w-[--width] h-[--height] overflow-hidden
|
|
26
|
+
bg-[--background] transition-all duration-100
|
|
27
|
+
focus:outline-none
|
|
28
|
+
disabled:opacity-50 disabled:pointer-events-none;
|
|
29
|
+
}
|
|
30
|
+
/* makes sure icons will not make the buttons grow vertically */
|
|
31
|
+
.gn-ui-btn mat-icon.mat-icon {
|
|
32
|
+
margin-top: -0.325em;
|
|
33
|
+
margin-bottom: -0.325em;
|
|
34
|
+
flex-shrink: 0;
|
|
35
|
+
}
|
|
36
|
+
/* makes spinners appear in the right color */
|
|
37
|
+
.gn-ui-btn mat-spinner circle {
|
|
38
|
+
stroke: currentColor !important;
|
|
12
39
|
}
|
|
13
40
|
|
|
14
|
-
.btn-default {
|
|
15
|
-
@apply btn text-white
|
|
41
|
+
.gn-ui-btn-default {
|
|
42
|
+
@apply gn-ui-btn text-white
|
|
16
43
|
bg-gray-700 hover:bg-gray-800 active:bg-gray-900
|
|
17
44
|
border border-gray-700 focus:ring-4 focus:ring-gray-200;
|
|
18
45
|
}
|
|
19
46
|
|
|
20
|
-
.btn-primary {
|
|
21
|
-
@apply btn text-white
|
|
47
|
+
.gn-ui-btn-primary {
|
|
48
|
+
@apply gn-ui-btn text-white
|
|
22
49
|
bg-primary hover:bg-primary-darker focus:bg-primary-darker active:bg-primary-darkest
|
|
23
50
|
border border-primary focus:ring-4 focus:ring-primary-lightest;
|
|
24
51
|
}
|
|
25
52
|
|
|
26
|
-
.btn-secondary {
|
|
27
|
-
@apply btn text-white
|
|
53
|
+
.gn-ui-btn-secondary {
|
|
54
|
+
@apply gn-ui-btn text-white
|
|
28
55
|
bg-secondary hover:bg-secondary-darker focus:bg-secondary-darker active:bg-secondary-darkest
|
|
29
56
|
border border-secondary focus:ring-4 focus:ring-secondary-lightest;
|
|
30
57
|
}
|
|
31
58
|
|
|
32
|
-
.btn-outline {
|
|
33
|
-
@apply btn text-main
|
|
34
|
-
|
|
59
|
+
.gn-ui-btn-outline {
|
|
60
|
+
@apply gn-ui-btn text-main
|
|
61
|
+
hover:text-primary-darker focus:text-primary-darker active:text-primary-black
|
|
35
62
|
border border-gray-300 hover:border-primary-lighter focus:border-primary-lighter focus:ring-4 focus:ring-primary-lightest active:border-primary-darker;
|
|
36
63
|
}
|
|
37
64
|
|
|
38
|
-
.btn-light {
|
|
39
|
-
@apply btn text-main
|
|
40
|
-
|
|
65
|
+
.gn-ui-btn-light {
|
|
66
|
+
@apply gn-ui-btn text-main
|
|
67
|
+
hover:bg-gray-50 focus:bg-gray-50 active:bg-gray-100
|
|
41
68
|
border border-white focus:ring-4 focus:ring-gray-300;
|
|
42
69
|
}
|
|
43
70
|
|
|
71
|
+
/* TODO: add prefix */
|
|
44
72
|
.badge-btn {
|
|
45
73
|
@apply flex items-center justify-center px-4 py-1 text-white rounded backdrop-blur;
|
|
46
74
|
}
|
|
47
75
|
|
|
76
|
+
/* TODO: add prefix */
|
|
48
77
|
.card-icon {
|
|
49
78
|
@apply text-primary opacity-50 group-hover:text-secondary group-hover:opacity-100 transition-colors transition-opacity;
|
|
50
79
|
}
|