geonetwork-ui 2.11.0-dev.7f3cfba04 → 2.11.0-dev.840dcc932
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/fesm2022/geonetwork-ui.mjs +233 -18
- package/fesm2022/geonetwork-ui.mjs.map +1 -1
- package/index.d.ts +43 -16
- package/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/libs/api/metadata-converter/src/lib/fixtures/mel.records.dataset+featurecatalog.ts +83 -5
- package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +3 -3
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +15 -6
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +20 -8
- package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +131 -0
- package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +2 -0
- package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +78 -1
- package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +11 -0
- package/src/libs/common/domain/src/lib/model/record/flags.model.ts +1 -0
- package/src/libs/common/domain/src/lib/model/record/index.ts +1 -0
- package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +11 -8
- package/src/libs/common/domain/src/lib/platform.service.interface.ts +1 -0
- package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +19 -0
- package/src/libs/common/fixtures/src/lib/records.fixtures.ts +3 -3
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints/form-field-constraints.component.ts +3 -5
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.ts +2 -2
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-record-flags/form-field-record-flag-component.css +0 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-record-flags/form-field-record-flag-component.html +18 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-record-flags/form-field-record-flag-component.ts +86 -0
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +100 -88
- package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +11 -4
- package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +18 -4
- package/src/libs/feature/editor/src/lib/expressions.ts +67 -0
- package/src/libs/feature/editor/src/lib/fields.config.ts +13 -0
- package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +10 -4
- package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.html +1 -1
- package/translations/de.json +4 -0
- package/translations/en.json +4 -0
- package/translations/es.json +4 -0
- package/translations/fr.json +4 -0
- package/translations/it.json +4 -0
- package/translations/nl.json +4 -0
- package/translations/pt.json +4 -0
- package/translations/sk.json +4 -0
package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html
CHANGED
|
@@ -7,23 +7,22 @@
|
|
|
7
7
|
></gn-ui-form-field-open-data>
|
|
8
8
|
</ng-container> -->
|
|
9
9
|
<div class="flex flex-col h-full">
|
|
10
|
-
|
|
10
|
+
@if (withoutWrapper) {
|
|
11
11
|
<ng-container *ngTemplateOutlet="fieldContent"></ng-container>
|
|
12
|
-
|
|
13
|
-
<ng-template #withGenericWrapper>
|
|
12
|
+
} @else {
|
|
14
13
|
<gn-ui-form-field-wrapper
|
|
15
14
|
[label]="config.labelKey! | translate: { recordKind }"
|
|
16
15
|
[hint]="config.hintKey! | translate: { recordKind }"
|
|
17
16
|
>
|
|
18
17
|
<ng-container *ngTemplateOutlet="fieldContent"></ng-container>
|
|
19
18
|
</gn-ui-form-field-wrapper>
|
|
20
|
-
|
|
19
|
+
}
|
|
21
20
|
</div>
|
|
22
21
|
|
|
23
22
|
<ng-template #fieldContent>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<div class="flex flex-row flex-start items-center gap-3
|
|
23
|
+
@switch (model) {
|
|
24
|
+
@case ('title') {
|
|
25
|
+
<div class="flex flex-row flex-start items-center gap-3">
|
|
27
26
|
<textarea
|
|
28
27
|
#titleInput
|
|
29
28
|
cdkTextareaAutosize
|
|
@@ -45,158 +44,171 @@
|
|
|
45
44
|
class="m-2 cursor-pointer"
|
|
46
45
|
(click)="focusTitleInput()"
|
|
47
46
|
></ng-icon>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
@if (config.hintKey) {
|
|
48
|
+
<ng-icon
|
|
49
|
+
name="matHelpOutline"
|
|
50
|
+
size="16"
|
|
51
|
+
class="m-2"
|
|
52
|
+
[matTooltip]="config.hintKey! | translate: { recordKind }"
|
|
53
|
+
matTooltipPosition="above"
|
|
54
|
+
></ng-icon>
|
|
55
|
+
}
|
|
56
56
|
</div>
|
|
57
57
|
</div>
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
}
|
|
59
|
+
@case ('abstract') {
|
|
60
60
|
<gn-ui-form-field-rich
|
|
61
61
|
[label]="config.labelKey! | translate: { recordKind }"
|
|
62
62
|
[hint]="config.hintKey! | translate: { recordKind }"
|
|
63
63
|
[value]="valueAsString"
|
|
64
64
|
(valueChange)="valueChange.emit($event)"
|
|
65
65
|
></gn-ui-form-field-rich>
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
}
|
|
67
|
+
@case ('overviews') {
|
|
68
68
|
<gn-ui-form-field-overviews
|
|
69
69
|
[metadataUuid]="uniqueIdentifier"
|
|
70
70
|
[recordKind]="recordKind"
|
|
71
71
|
[value]="valueAsOverviews"
|
|
72
72
|
(valueChange)="valueChange.emit($event)"
|
|
73
73
|
></gn-ui-form-field-overviews>
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
}
|
|
75
|
+
@case ('resourceIdentifiers') {
|
|
76
76
|
<gn-ui-form-field-simple
|
|
77
77
|
[type]="'text'"
|
|
78
78
|
[value]="valueAsResourceIdentifierCode"
|
|
79
79
|
(valueChange)="handleResourceIdentifierChange($event)"
|
|
80
80
|
></gn-ui-form-field-simple>
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
}
|
|
82
|
+
@case ('resourceCreated') {
|
|
83
83
|
<gn-ui-form-field-date
|
|
84
84
|
[value]="valueAsDate"
|
|
85
85
|
(valueChange)="valueChange.emit($event)"
|
|
86
86
|
></gn-ui-form-field-date>
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
}
|
|
88
|
+
@case ('resourceUpdated') {
|
|
89
89
|
<gn-ui-form-field-date
|
|
90
90
|
[value]="valueAsDate"
|
|
91
91
|
(valueChange)="valueChange.emit($event)"
|
|
92
92
|
></gn-ui-form-field-date>
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
}
|
|
94
|
+
@case ('updateFrequency') {
|
|
95
95
|
<gn-ui-form-field-update-frequency
|
|
96
96
|
[value]="valueAsUpdateFrequency"
|
|
97
97
|
(valueChange)="valueChange.emit($event)"
|
|
98
98
|
[recordKind]="recordKind"
|
|
99
99
|
></gn-ui-form-field-update-frequency>
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
}
|
|
101
|
+
@case ('associatedRecords') {
|
|
102
102
|
<gn-ui-form-field-associated-records
|
|
103
103
|
[value]="valueAsAssociatedRecords"
|
|
104
104
|
(valueChange)="valueChange.emit($event)"
|
|
105
105
|
></gn-ui-form-field-associated-records>
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
}
|
|
107
|
+
@case ('temporalExtents') {
|
|
108
108
|
<gn-ui-form-field-temporal-extents
|
|
109
109
|
[value]="valueAsTemporalExtents"
|
|
110
110
|
(valueChange)="valueChange.emit($event)"
|
|
111
111
|
></gn-ui-form-field-temporal-extents>
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
}
|
|
113
|
+
@case ('spatialExtents') {
|
|
114
114
|
<gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
}
|
|
116
|
+
@case ('keywords') {
|
|
117
117
|
<gn-ui-form-field-keywords
|
|
118
118
|
[value]="valueAsKeywords"
|
|
119
119
|
(valueChange)="valueChange.emit($event)"
|
|
120
120
|
></gn-ui-form-field-keywords>
|
|
121
|
-
|
|
122
|
-
|
|
121
|
+
}
|
|
122
|
+
@case ('topics') {
|
|
123
123
|
<gn-ui-form-field-topics
|
|
124
124
|
[value]="valueAsTopics"
|
|
125
125
|
(valueChange)="valueChange.emit($event)"
|
|
126
126
|
></gn-ui-form-field-topics>
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
}
|
|
128
|
+
@case ('licenses') {
|
|
129
129
|
<gn-ui-form-field-license
|
|
130
130
|
[label]="config.labelKey! | translate: { recordKind }"
|
|
131
131
|
[recordLicences]="valueAsConstraints"
|
|
132
132
|
(recordLicencesChange)="valueChange.emit($event)"
|
|
133
133
|
></gn-ui-form-field-license>
|
|
134
|
-
|
|
134
|
+
}
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
136
|
+
<!-- TODO: merge these cases together when migrated to angular 21 -->
|
|
137
|
+
@case ('legalConstraints') {
|
|
138
|
+
<gn-ui-form-field-constraints
|
|
139
|
+
[label]="config.labelKey"
|
|
140
|
+
[value]="valueAsConstraints"
|
|
141
|
+
[constraintType]="model"
|
|
142
|
+
(valueChange)="valueChange.emit($event)"
|
|
143
|
+
></gn-ui-form-field-constraints>
|
|
144
|
+
}
|
|
145
|
+
@case ('securityConstraints') {
|
|
146
|
+
<gn-ui-form-field-constraints
|
|
147
|
+
[label]="config.labelKey"
|
|
148
|
+
[value]="valueAsConstraints"
|
|
149
|
+
[constraintType]="model"
|
|
150
|
+
(valueChange)="valueChange.emit($event)"
|
|
151
|
+
></gn-ui-form-field-constraints>
|
|
152
|
+
}
|
|
153
|
+
@case ('otherConstraints') {
|
|
146
154
|
<gn-ui-form-field-constraints
|
|
147
155
|
[label]="config.labelKey"
|
|
148
156
|
[value]="valueAsConstraints"
|
|
149
157
|
[constraintType]="model"
|
|
150
158
|
(valueChange)="valueChange.emit($event)"
|
|
151
|
-
></gn-ui-form-field-constraints
|
|
152
|
-
|
|
159
|
+
></gn-ui-form-field-constraints>
|
|
160
|
+
}
|
|
153
161
|
|
|
154
|
-
|
|
162
|
+
@case ('contactsForResource') {
|
|
155
163
|
<gn-ui-form-field-contacts-for-resource
|
|
156
164
|
[value]="valueAsIndividuals"
|
|
157
165
|
(valueChange)="valueChange.emit($event)"
|
|
158
166
|
></gn-ui-form-field-contacts-for-resource>
|
|
159
|
-
|
|
160
|
-
|
|
167
|
+
}
|
|
168
|
+
@case ('contacts') {
|
|
161
169
|
<gn-ui-form-field-contacts
|
|
162
170
|
[value]="valueAsIndividuals"
|
|
163
171
|
[modelSpecifier]="modelSpecifier"
|
|
164
172
|
(valueChange)="valueChange.emit($event)"
|
|
165
173
|
></gn-ui-form-field-contacts>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
174
|
+
}
|
|
175
|
+
@case ('onlineResources') {
|
|
176
|
+
@if (modelSpecifier === 'onlineResourceType:!link') {
|
|
177
|
+
<gn-ui-form-field-online-resources
|
|
178
|
+
[metadataUuid]="uniqueIdentifier"
|
|
179
|
+
[value]="valueAsOnlineResources"
|
|
180
|
+
(valueChange)="valueChange.emit($event)"
|
|
181
|
+
></gn-ui-form-field-online-resources>
|
|
182
|
+
} @else if (modelSpecifier === 'onlineResourceType:link') {
|
|
183
|
+
<gn-ui-form-field-online-link-resources
|
|
184
|
+
[metadataUuid]="uniqueIdentifier"
|
|
185
|
+
[value]="valueAsOnlineResources"
|
|
186
|
+
(valueChange)="valueChange.emit($event)"
|
|
187
|
+
></gn-ui-form-field-online-link-resources>
|
|
188
|
+
} @else if (modelSpecifier === 'onlineResourceType:singleLink') {
|
|
189
|
+
<gn-ui-form-field-online-single-link-resource
|
|
190
|
+
[value]="valueAsOnlineResources"
|
|
191
|
+
(valueChange)="valueChange.emit($event)"
|
|
192
|
+
></gn-ui-form-field-online-single-link-resource>
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
@case ('flags') {
|
|
196
|
+
<gn-ui-form-field-record-flag
|
|
197
|
+
[flagName]="recordFlag"
|
|
198
|
+
[labelKey]="config.labelKey"
|
|
199
|
+
[hintKey]="config.hintKey"
|
|
200
|
+
></gn-ui-form-field-record-flag>
|
|
201
|
+
}
|
|
202
|
+
}
|
|
191
203
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
204
|
+
@if (!model) {
|
|
205
|
+
@switch (componentName) {
|
|
206
|
+
@case ('form-field-constraints-shortcuts') {
|
|
195
207
|
<gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>
|
|
196
|
-
|
|
197
|
-
|
|
208
|
+
}
|
|
209
|
+
@case ('form-field-spatial-toggle') {
|
|
198
210
|
<gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
202
214
|
</ng-template>
|
package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts
CHANGED
|
@@ -12,13 +12,13 @@ import {
|
|
|
12
12
|
import { MatTooltipModule } from '@angular/material/tooltip'
|
|
13
13
|
import {
|
|
14
14
|
AssociatedRecord,
|
|
15
|
-
CatalogRecordKeys,
|
|
16
15
|
Constraint,
|
|
17
16
|
DatasetTemporalExtent,
|
|
18
17
|
GraphicOverview,
|
|
19
18
|
Individual,
|
|
20
19
|
Keyword,
|
|
21
20
|
OnlineResource,
|
|
21
|
+
RecordFlag,
|
|
22
22
|
RecordKind,
|
|
23
23
|
UpdateFrequency,
|
|
24
24
|
} from '../../../../../../../../libs/common/domain/src/lib/model/record'
|
|
@@ -36,9 +36,10 @@ import {
|
|
|
36
36
|
FormFieldTemporalExtentsComponent,
|
|
37
37
|
} from '.'
|
|
38
38
|
import {
|
|
39
|
-
FieldModelSpecifier,
|
|
40
39
|
FormFieldComponentName,
|
|
41
40
|
FormFieldConfig,
|
|
41
|
+
FormFieldModel,
|
|
42
|
+
FormFieldModelSpecifier,
|
|
42
43
|
} from '../../../models'
|
|
43
44
|
import { FormFieldAssociatedRecordsComponent } from './form-field-associated-records/form-field-associated-records.component'
|
|
44
45
|
import { FormFieldContactsForResourceComponent } from './form-field-contacts-for-resource/form-field-contacts-for-resource.component'
|
|
@@ -57,6 +58,7 @@ import { FormFieldConstraintsComponent } from './form-field-constraints/form-fie
|
|
|
57
58
|
import { TextFieldModule } from '@angular/cdk/text-field'
|
|
58
59
|
import { FormFieldSpatialToggleComponent } from './form-field-spatial-toggle/form-field-spatial-toggle.component'
|
|
59
60
|
import { FormFieldTopicsComponent } from './form-field-topics/form-field-topics.component'
|
|
61
|
+
import { FormFieldRecordFlagComponent } from './form-field-record-flags/form-field-record-flag-component'
|
|
60
62
|
|
|
61
63
|
@Component({
|
|
62
64
|
selector: 'gn-ui-form-field',
|
|
@@ -90,6 +92,7 @@ import { FormFieldTopicsComponent } from './form-field-topics/form-field-topics.
|
|
|
90
92
|
FormFieldTopicsComponent,
|
|
91
93
|
TextFieldModule,
|
|
92
94
|
NgIconComponent,
|
|
95
|
+
FormFieldRecordFlagComponent,
|
|
93
96
|
],
|
|
94
97
|
providers: [provideIcons({ matEditOutline, matHelpOutline })],
|
|
95
98
|
hostDirectives: [FieldFocusDirective],
|
|
@@ -97,8 +100,8 @@ import { FormFieldTopicsComponent } from './form-field-topics/form-field-topics.
|
|
|
97
100
|
export class FormFieldComponent {
|
|
98
101
|
@Input() uniqueIdentifier: string
|
|
99
102
|
@Input() recordKind: RecordKind
|
|
100
|
-
@Input() model:
|
|
101
|
-
@Input() modelSpecifier:
|
|
103
|
+
@Input() model: FormFieldModel
|
|
104
|
+
@Input() modelSpecifier: FormFieldModelSpecifier
|
|
102
105
|
@Input() componentName: FormFieldComponentName
|
|
103
106
|
|
|
104
107
|
@Input() config: FormFieldConfig
|
|
@@ -126,6 +129,7 @@ export class FormFieldComponent {
|
|
|
126
129
|
this.model === 'legalConstraints' ||
|
|
127
130
|
this.model === 'securityConstraints' ||
|
|
128
131
|
this.model === 'otherConstraints' ||
|
|
132
|
+
this.model === 'flags' ||
|
|
129
133
|
this.componentName === 'form-field-constraints-shortcuts'
|
|
130
134
|
)
|
|
131
135
|
}
|
|
@@ -172,6 +176,9 @@ export class FormFieldComponent {
|
|
|
172
176
|
}>
|
|
173
177
|
return identifiers?.[0]?.code || ''
|
|
174
178
|
}
|
|
179
|
+
get recordFlag() {
|
|
180
|
+
return this.modelSpecifier?.replace(/^flags:/, '') as RecordFlag
|
|
181
|
+
}
|
|
175
182
|
|
|
176
183
|
handleResourceIdentifierChange(code: string) {
|
|
177
184
|
const identifiers = this.value as Array<{
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
viewChildren,
|
|
12
12
|
} from '@angular/core'
|
|
13
13
|
import { EditorFacade } from '../../+state/editor.facade'
|
|
14
|
-
import { EditorFieldValue } from '../../models'
|
|
14
|
+
import { EditorFieldValue, FormFieldModel } from '../../models'
|
|
15
15
|
import { FieldFocusDirective, FormFieldComponent } from './form-field'
|
|
16
16
|
import { TranslateDirective } from '@ngx-translate/core'
|
|
17
17
|
import {
|
|
@@ -24,6 +24,7 @@ import { switchMap } from 'rxjs/operators'
|
|
|
24
24
|
import { toSignal } from '@angular/core/rxjs-interop'
|
|
25
25
|
import { evaluate, isExpression } from '../../expressions'
|
|
26
26
|
import { NotificationsService } from '../../../../../../../libs/feature/notifications/src'
|
|
27
|
+
import { PlatformServiceInterface } from '../../../../../../../libs/common/domain/src/lib/platform.service.interface'
|
|
27
28
|
|
|
28
29
|
@Component({
|
|
29
30
|
selector: 'gn-ui-record-form',
|
|
@@ -41,6 +42,7 @@ import { NotificationsService } from '../../../../../../../libs/feature/notifica
|
|
|
41
42
|
export class RecordFormComponent implements OnInit, OnDestroy {
|
|
42
43
|
facade = inject(EditorFacade)
|
|
43
44
|
notifications = inject(NotificationsService)
|
|
45
|
+
platform = inject(PlatformServiceInterface)
|
|
44
46
|
subscription = new Subscription()
|
|
45
47
|
|
|
46
48
|
recordUniqueIdentifier$ = this.facade.record$.pipe(
|
|
@@ -90,8 +92,8 @@ export class RecordFormComponent implements OnInit, OnDestroy {
|
|
|
90
92
|
this.subscription.unsubscribe()
|
|
91
93
|
}
|
|
92
94
|
|
|
93
|
-
handleFieldValueChange(model:
|
|
94
|
-
if (!model) {
|
|
95
|
+
handleFieldValueChange(model: FormFieldModel, newValue: EditorFieldValue) {
|
|
96
|
+
if (!model || model === 'flags') {
|
|
95
97
|
return
|
|
96
98
|
}
|
|
97
99
|
this.facade.updateRecordField(model, newValue)
|
|
@@ -122,6 +124,8 @@ export class RecordFormComponent implements OnInit, OnDestroy {
|
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
private recordSignal = toSignal(this.facade.record$, { requireSync: true })
|
|
127
|
+
private userSignal = toSignal(this.platform.getMe())
|
|
128
|
+
private isAdminSignal = toSignal(this.platform.isAdministrator())
|
|
125
129
|
private expressionCache = new Map<string, Signal<EditorFieldValue>>()
|
|
126
130
|
|
|
127
131
|
// only compiles the expression into an evaluator the first time;
|
|
@@ -149,7 +153,17 @@ ${errors.map((err) => `> ${err}`).join('\n')}`)
|
|
|
149
153
|
}
|
|
150
154
|
this.expressionCache.set(
|
|
151
155
|
expression,
|
|
152
|
-
computed(() =>
|
|
156
|
+
computed(() =>
|
|
157
|
+
evaluator({
|
|
158
|
+
globals: {
|
|
159
|
+
record: this.recordSignal(),
|
|
160
|
+
user: {
|
|
161
|
+
...this.userSignal(),
|
|
162
|
+
isAdmin: this.isAdminSignal(),
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
})
|
|
166
|
+
)
|
|
153
167
|
)
|
|
154
168
|
return this.expressionCache.get(expression)
|
|
155
169
|
}
|
|
@@ -17,10 +17,14 @@ const TOKEN_OPERATOR_LOGICAL = ['==', '!=']
|
|
|
17
17
|
const TOKEN_STRING_LITERAL = ["'", '"']
|
|
18
18
|
const TOKEN_GROUP_START = '('
|
|
19
19
|
const TOKEN_GROUP_END = ')'
|
|
20
|
+
const TOKEN_OPERATOR_BOOLEAN = ['&&', '||']
|
|
21
|
+
const TOKEN_OPERATOR_NOT = '!'
|
|
20
22
|
|
|
21
23
|
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence
|
|
22
24
|
const OPERATORS_BY_PRECEDENCE: string[][] = [
|
|
23
25
|
[TOKEN_OPERATOR_TERNARY_FIRST, TOKEN_OPERATOR_TERNARY_SECOND],
|
|
26
|
+
TOKEN_OPERATOR_BOOLEAN,
|
|
27
|
+
[TOKEN_OPERATOR_NOT],
|
|
24
28
|
TOKEN_OPERATOR_LOGICAL,
|
|
25
29
|
]
|
|
26
30
|
const ALL_OPERATORS = OPERATORS_BY_PRECEDENCE.flat()
|
|
@@ -161,6 +165,18 @@ function evaluateInternal(
|
|
|
161
165
|
continue
|
|
162
166
|
}
|
|
163
167
|
|
|
168
|
+
// BOOLEAN LITERAL
|
|
169
|
+
const isBooleanLiteral =
|
|
170
|
+
readNext(expression, pos, 4) === 'true' ||
|
|
171
|
+
readNext(expression, pos, 5) === 'false'
|
|
172
|
+
if (isBooleanLiteral) {
|
|
173
|
+
const literal = readNext(expression, pos, 4) === 'true' ? 'true' : 'false'
|
|
174
|
+
pos += literal.length
|
|
175
|
+
const booleanLiteral = literal === 'true'
|
|
176
|
+
currentEvaluator = () => booleanLiteral
|
|
177
|
+
continue
|
|
178
|
+
}
|
|
179
|
+
|
|
164
180
|
// SYMBOL (NAME)
|
|
165
181
|
const isSymbol = /[a-zA-Z]/.test(readNext(expression, pos))
|
|
166
182
|
if (isSymbol) {
|
|
@@ -291,6 +307,57 @@ function evaluateInternal(
|
|
|
291
307
|
continue
|
|
292
308
|
}
|
|
293
309
|
|
|
310
|
+
// BOOLEAN OPERATORS
|
|
311
|
+
const isBooleanOperator = TOKEN_OPERATOR_BOOLEAN.some(
|
|
312
|
+
(token) => readNext(expression, pos, token.length) === token
|
|
313
|
+
)
|
|
314
|
+
if (isBooleanOperator) {
|
|
315
|
+
const matchingOperator = TOKEN_OPERATOR_BOOLEAN.find(
|
|
316
|
+
(token) => readNext(expression, pos, token.length) === token
|
|
317
|
+
)
|
|
318
|
+
const isAnd = matchingOperator === '&&'
|
|
319
|
+
pos += matchingOperator.length
|
|
320
|
+
const leftEvaluator = currentEvaluator
|
|
321
|
+
const rightExpression = readUntilNextOperator(
|
|
322
|
+
expression,
|
|
323
|
+
pos,
|
|
324
|
+
matchingOperator
|
|
325
|
+
)
|
|
326
|
+
pos += rightExpression.length
|
|
327
|
+
const rightEvaluator = evaluateInternal(
|
|
328
|
+
rightExpression,
|
|
329
|
+
currentContext
|
|
330
|
+
).evaluator
|
|
331
|
+
|
|
332
|
+
currentEvaluator = (context) => {
|
|
333
|
+
return isAnd
|
|
334
|
+
? Boolean(leftEvaluator(context) && rightEvaluator(context))
|
|
335
|
+
: Boolean(leftEvaluator(context) || rightEvaluator(context))
|
|
336
|
+
}
|
|
337
|
+
continue
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// PREFIX OPERATORS
|
|
341
|
+
const isNotOperator = readNext(expression, pos) === TOKEN_OPERATOR_NOT
|
|
342
|
+
if (isNotOperator) {
|
|
343
|
+
pos++
|
|
344
|
+
const operandExpression = readUntilNextOperator(
|
|
345
|
+
expression,
|
|
346
|
+
pos,
|
|
347
|
+
TOKEN_OPERATOR_NOT
|
|
348
|
+
)
|
|
349
|
+
pos += operandExpression.length
|
|
350
|
+
const operandEvaluator = evaluateInternal(
|
|
351
|
+
operandExpression,
|
|
352
|
+
currentContext
|
|
353
|
+
).evaluator
|
|
354
|
+
|
|
355
|
+
currentEvaluator = (context) => {
|
|
356
|
+
return !operandEvaluator(context)
|
|
357
|
+
}
|
|
358
|
+
continue
|
|
359
|
+
}
|
|
360
|
+
|
|
294
361
|
// TERNARY OPERATOR
|
|
295
362
|
const isTernary = readNext(expression, pos) === TOKEN_OPERATOR_TERNARY_FIRST
|
|
296
363
|
if (isTernary) {
|
|
@@ -37,6 +37,19 @@ export const DEFAULT_CONFIGURATION: EditorConfig = {
|
|
|
37
37
|
labelKey: marker('editor.record.form.field.title'),
|
|
38
38
|
},
|
|
39
39
|
},
|
|
40
|
+
{
|
|
41
|
+
model: 'flags',
|
|
42
|
+
modelSpecifier: 'flags:IS_REFERENCE_DATASET',
|
|
43
|
+
formFieldConfig: {
|
|
44
|
+
labelKey: marker(
|
|
45
|
+
'editor.record.form.field.flags.IS_REFERENCE_DATASET'
|
|
46
|
+
),
|
|
47
|
+
hintKey: marker(
|
|
48
|
+
'editor.record.form.field.hint.flags.IS_REFERENCE_DATASET'
|
|
49
|
+
),
|
|
50
|
+
},
|
|
51
|
+
hidden: '${record.kind != "dataset" || !user.isAdmin}',
|
|
52
|
+
},
|
|
40
53
|
{
|
|
41
54
|
model: 'abstract',
|
|
42
55
|
formFieldConfig: {
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CatalogRecordKeys,
|
|
3
|
+
RecordFlag,
|
|
4
|
+
} from '../../../../../../libs/common/domain/src/lib/model/record'
|
|
2
5
|
|
|
3
6
|
// Expressions should be enclosed in `${}` to be recognized as such
|
|
4
7
|
// eg. ${dateNow()}
|
|
@@ -15,6 +18,8 @@ export interface FormFieldConfig {
|
|
|
15
18
|
invalidHintKey?: string
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
export type FormFieldModel = CatalogRecordKeys | 'flags'
|
|
22
|
+
|
|
18
23
|
// Specifiers let us use specific components
|
|
19
24
|
// This is used for instance to target only certain online resources in a field
|
|
20
25
|
type OnlineLinkResourceSpecifier = `onlineResourceType:link`
|
|
@@ -25,11 +30,12 @@ type OnlineSingleLinkResourceSpecifier = `onlineResourceType:singleLink`
|
|
|
25
30
|
// When set on the `contacts` field, contacts are rendered as editable detail
|
|
26
31
|
// fields (ContactDetailsFormComponent) instead of cards (ContactCardComponent)
|
|
27
32
|
type EditableContactDetailsSpecifier = `contact:editableDetails`
|
|
28
|
-
export type
|
|
33
|
+
export type FormFieldModelSpecifier =
|
|
29
34
|
| OnlineLinkResourceSpecifier
|
|
30
35
|
| DatasetDistributionsSpecifier
|
|
31
36
|
| OnlineSingleLinkResourceSpecifier
|
|
32
37
|
| EditableContactDetailsSpecifier
|
|
38
|
+
| `flags:${RecordFlag}`
|
|
33
39
|
|
|
34
40
|
export type FormFieldComponentName =
|
|
35
41
|
| 'form-field-constraints-shortcuts'
|
|
@@ -37,8 +43,8 @@ export type FormFieldComponentName =
|
|
|
37
43
|
|
|
38
44
|
export interface EditorFieldIdentification {
|
|
39
45
|
// name of the target field in the record; will not change the record directly if not defined
|
|
40
|
-
model?:
|
|
41
|
-
modelSpecifier?:
|
|
46
|
+
model?: FormFieldModel
|
|
47
|
+
modelSpecifier?: FormFieldModelSpecifier
|
|
42
48
|
|
|
43
49
|
// if no model is given, a component can be shown instead
|
|
44
50
|
componentName?: FormFieldComponentName
|
package/translations/de.json
CHANGED
|
@@ -166,6 +166,8 @@
|
|
|
166
166
|
"editor.record.error.back": "Zurück zum Katalog",
|
|
167
167
|
"editor.record.error.explanation": "Möglicherweise haben Sie keinen Zugriff auf diese Datei,<br>oder dieser Link ist ungültig.",
|
|
168
168
|
"editor.record.error.message": "Etwas ist nicht wie erwartet gelaufen.",
|
|
169
|
+
"editor.record.flag.saveError.body": "",
|
|
170
|
+
"editor.record.flag.saveError.title": "",
|
|
169
171
|
"editor.record.form.bottomButtons.comeBackLater": "Später wiederkommen",
|
|
170
172
|
"editor.record.form.bottomButtons.next": "Nächste",
|
|
171
173
|
"editor.record.form.bottomButtons.previous": "Vorherige",
|
|
@@ -198,6 +200,8 @@
|
|
|
198
200
|
"editor.record.form.field.contacts.placeholder": "Kontakt auswählen",
|
|
199
201
|
"editor.record.form.field.contactsForResource.noContact": "Bitte geben Sie mindestens einen Ansprechpartner an, der für die Daten verantwortlich ist.",
|
|
200
202
|
"editor.record.form.field.contactsForResource.placeholder": "Kontakt auswählen",
|
|
203
|
+
"editor.record.form.field.flags.IS_REFERENCE_DATASET": "",
|
|
204
|
+
"editor.record.form.field.hint.flags.IS_REFERENCE_DATASET": "",
|
|
201
205
|
"editor.record.form.field.keywords": "Schlagwörter",
|
|
202
206
|
"editor.record.form.field.legalConstraints": "Rechtliche Einschränkung",
|
|
203
207
|
"editor.record.form.field.license": "Lizenz",
|
package/translations/en.json
CHANGED
|
@@ -166,6 +166,8 @@
|
|
|
166
166
|
"editor.record.error.back": "Go back to the catalog",
|
|
167
167
|
"editor.record.error.explanation": "You might not have access to this record,<br> Or this link might not be valid.",
|
|
168
168
|
"editor.record.error.message": "Something went wrong",
|
|
169
|
+
"editor.record.flag.saveError.body": "The {recordKind, select, dataset{dataset} service{service} reuse{reuse} other{record}} could not be modified:",
|
|
170
|
+
"editor.record.flag.saveError.title": "Record modification failed",
|
|
169
171
|
"editor.record.form.bottomButtons.comeBackLater": "Come back later",
|
|
170
172
|
"editor.record.form.bottomButtons.next": "Next",
|
|
171
173
|
"editor.record.form.bottomButtons.previous": "Previous",
|
|
@@ -198,6 +200,8 @@
|
|
|
198
200
|
"editor.record.form.field.contacts.placeholder": "Choose a contact",
|
|
199
201
|
"editor.record.form.field.contactsForResource.noContact": "Please provide at least one point of contact responsible for the data.",
|
|
200
202
|
"editor.record.form.field.contactsForResource.placeholder": "Choose a contact",
|
|
203
|
+
"editor.record.form.field.flags.IS_REFERENCE_DATASET": "Reference dataset",
|
|
204
|
+
"editor.record.form.field.hint.flags.IS_REFERENCE_DATASET": "Enabling this toggle will turn this dataset into a \"reference dataset\". It will be put forward and advertised as such in the search results.",
|
|
201
205
|
"editor.record.form.field.keywords": "Keywords",
|
|
202
206
|
"editor.record.form.field.legalConstraints": "Legal constraint",
|
|
203
207
|
"editor.record.form.field.license": "License",
|
package/translations/es.json
CHANGED
|
@@ -166,6 +166,8 @@
|
|
|
166
166
|
"editor.record.error.back": "",
|
|
167
167
|
"editor.record.error.explanation": "",
|
|
168
168
|
"editor.record.error.message": "",
|
|
169
|
+
"editor.record.flag.saveError.body": "",
|
|
170
|
+
"editor.record.flag.saveError.title": "",
|
|
169
171
|
"editor.record.form.bottomButtons.comeBackLater": "",
|
|
170
172
|
"editor.record.form.bottomButtons.next": "",
|
|
171
173
|
"editor.record.form.bottomButtons.previous": "",
|
|
@@ -198,6 +200,8 @@
|
|
|
198
200
|
"editor.record.form.field.contacts.placeholder": "",
|
|
199
201
|
"editor.record.form.field.contactsForResource.noContact": "",
|
|
200
202
|
"editor.record.form.field.contactsForResource.placeholder": "",
|
|
203
|
+
"editor.record.form.field.flags.IS_REFERENCE_DATASET": "",
|
|
204
|
+
"editor.record.form.field.hint.flags.IS_REFERENCE_DATASET": "",
|
|
201
205
|
"editor.record.form.field.keywords": "",
|
|
202
206
|
"editor.record.form.field.legalConstraints": "",
|
|
203
207
|
"editor.record.form.field.license": "",
|
package/translations/fr.json
CHANGED
|
@@ -166,6 +166,8 @@
|
|
|
166
166
|
"editor.record.error.back": "Retour au catalogue",
|
|
167
167
|
"editor.record.error.explanation": "Vous n'avez peut être pas accès à cette fiche,<br>Ou ce lien n'est peut être pas valide.",
|
|
168
168
|
"editor.record.error.message": "Quelque chose ne s'est pas passé comme prévu",
|
|
169
|
+
"editor.record.flag.saveError.body": "{recordKind, select, dataset{Le jeu de données} service{Le service} reuse{La réutilisation} other{L'enregistrement}} n'a pas pu être modifié{recordKind, select, reuse{e} other{}} :",
|
|
170
|
+
"editor.record.flag.saveError.title": "Échec de la modification",
|
|
169
171
|
"editor.record.form.bottomButtons.comeBackLater": "Revenir plus tard",
|
|
170
172
|
"editor.record.form.bottomButtons.next": "Suivant",
|
|
171
173
|
"editor.record.form.bottomButtons.previous": "Précédent",
|
|
@@ -198,6 +200,8 @@
|
|
|
198
200
|
"editor.record.form.field.contacts.placeholder": "Choisissez un contact",
|
|
199
201
|
"editor.record.form.field.contactsForResource.noContact": "Veuillez renseigner au moins un point de contact responsable de la donnée.",
|
|
200
202
|
"editor.record.form.field.contactsForResource.placeholder": "Choisissez un contact",
|
|
203
|
+
"editor.record.form.field.flags.IS_REFERENCE_DATASET": "Donnée de référence",
|
|
204
|
+
"editor.record.form.field.hint.flags.IS_REFERENCE_DATASET": "Activer cette option fera de cette donnée une \"donnée de référence\". Elle sera mise en avant et présentée comme telle dans les résultats de recherche.",
|
|
201
205
|
"editor.record.form.field.keywords": "Mots-clés",
|
|
202
206
|
"editor.record.form.field.legalConstraints": "Contrainte légale",
|
|
203
207
|
"editor.record.form.field.license": "Licence",
|