@lblod/ember-rdfa-editor-lblod-plugins 33.0.0 → 33.1.0-dev.367f7322beb7deee231dd44356f445bd1d6515fd
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/.changeset/eleven-jeans-yell.md +5 -0
- package/CHANGELOG.md +10 -0
- package/addon/components/besluit-topic-plugin/besluit-topic-toolbar-dropdown.ts +1 -1
- package/addon/components/besluit-type-plugin/toolbar-dropdown.gts +1 -1
- package/addon/components/decision-plugin/decision-plugin-card.gts +3 -2
- package/addon/components/decision-plugin/insert-article.gts +1 -1
- package/addon/components/document-validation-plugin/card.gts +130 -33
- package/addon/components/lpdc-plugin/lpdc-insert.ts +1 -1
- package/addon/components/roadsign-regulation-plugin/roadsign-regulation-card.gts +1 -1
- package/addon/components/roadsign-regulation-plugin/roadsigns-modal.gts +1 -1
- package/addon/plugins/besluit-type-plugin/utils/besluit-type-instances.ts +1 -1
- package/addon/plugins/besluit-type-plugin/utils/set-besluit-type.ts +1 -1
- package/addon/plugins/decision-plugin/commands/insert-article-container.ts +14 -1
- package/addon/plugins/decision-plugin/commands/insert-description.ts +9 -1
- package/addon/plugins/decision-plugin/commands/insert-motivation.ts +9 -1
- package/addon/plugins/decision-plugin/commands/insert-title.ts +9 -1
- package/addon/plugins/document-validation-plugin/common-fixes.ts +125 -0
- package/addon/plugins/document-validation-plugin/index.ts +61 -32
- package/addon/plugins/roadsign-regulation-plugin/actions/insert-measure.ts +69 -18
- package/addon/plugins/roadsign-regulation-plugin/queries/mobility-measure-concept.ts +9 -1
- package/addon/plugins/roadsign-regulation-plugin/schemas/mobility-measure-preview.ts +22 -0
- package/addon/plugins/roadsign-regulation-plugin/schemas/traffic-signal.ts +18 -0
- package/addon/plugins/roadsign-regulation-plugin/schemas/variable-instance.ts +55 -0
- package/addon/plugins/roadsign-regulation-plugin/schemas/variable.ts +6 -6
- package/addon/{plugins/besluit-topic-plugin/utils/helpers.ts → utils/decision-utils.ts} +33 -9
- package/declarations/addon/components/document-validation-plugin/card.d.ts +51 -1
- package/declarations/addon/plugins/decision-plugin/commands/insert-article-container.d.ts +3 -1
- package/declarations/addon/plugins/document-validation-plugin/common-fixes.d.ts +6 -0
- package/declarations/addon/plugins/document-validation-plugin/index.d.ts +30 -6
- package/declarations/addon/plugins/roadsign-regulation-plugin/actions/insert-measure.d.ts +10 -5
- package/declarations/addon/plugins/roadsign-regulation-plugin/schemas/mobility-measure-preview.d.ts +279 -0
- package/declarations/addon/plugins/roadsign-regulation-plugin/schemas/traffic-signal.d.ts +90 -0
- package/declarations/addon/plugins/roadsign-regulation-plugin/schemas/variable-instance.d.ts +246 -0
- package/declarations/addon/plugins/roadsign-regulation-plugin/schemas/variable.d.ts +120 -0
- package/declarations/addon/{plugins/besluit-topic-plugin/utils/helpers.d.ts → utils/decision-utils.d.ts} +5 -1
- package/package.json +2 -2
- package/pnpm-lock.yaml +5 -5
- package/translations/en-US.yaml +1 -0
- package/translations/nl-BE.yaml +1 -0
|
@@ -2,14 +2,17 @@ import factory from '@rdfjs/dataset';
|
|
|
2
2
|
import SHACLValidator from 'rdf-validate-shacl';
|
|
3
3
|
import { Parser as ParserN3 } from 'n3';
|
|
4
4
|
import { RdfaParser } from 'rdfa-streaming-parser';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
ProsePlugin,
|
|
7
|
+
PluginKey,
|
|
8
|
+
EditorView,
|
|
9
|
+
SayController,
|
|
10
|
+
} from '@lblod/ember-rdfa-editor';
|
|
6
11
|
import removeQuotes from '@lblod/ember-rdfa-editor-lblod-plugins/utils/remove-quotes';
|
|
7
12
|
import {
|
|
8
|
-
BlankNode,
|
|
9
13
|
DataFactory,
|
|
10
14
|
DatasetCore,
|
|
11
15
|
DatasetCoreFactory,
|
|
12
|
-
NamedNode,
|
|
13
16
|
Quad,
|
|
14
17
|
} from '@rdfjs/types';
|
|
15
18
|
import ValidationReport from 'rdf-validate-shacl/src/validation-report';
|
|
@@ -18,8 +21,34 @@ import { SayDataFactory } from '@lblod/ember-rdfa-editor/core/say-data-factory';
|
|
|
18
21
|
export const documentValidationPluginKey =
|
|
19
22
|
new PluginKey<DocumentValidationPluginState>('DOCUMENT_VALIDATION');
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
type Violation =
|
|
25
|
+
| {
|
|
26
|
+
action: (controller: SayController, report: ValidationReport) => void;
|
|
27
|
+
buttonTitle: string;
|
|
28
|
+
}
|
|
29
|
+
| {
|
|
30
|
+
helpText: string;
|
|
31
|
+
};
|
|
32
|
+
type Rule =
|
|
33
|
+
| {
|
|
34
|
+
shaclRule: string;
|
|
35
|
+
violations: {
|
|
36
|
+
[key: string]: Violation;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
| {
|
|
40
|
+
shaclRule: string;
|
|
41
|
+
action: (controller: SayController, report: ValidationReport) => void;
|
|
42
|
+
buttonTitle: string;
|
|
43
|
+
}
|
|
44
|
+
| {
|
|
45
|
+
shaclRule: string;
|
|
46
|
+
helpText: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export interface DocumentValidationPluginArgs {
|
|
22
50
|
documentShape: string;
|
|
51
|
+
rules: Rule[];
|
|
23
52
|
}
|
|
24
53
|
|
|
25
54
|
export type ShaclValidationReport = ValidationReport.ValidationReport<
|
|
@@ -27,17 +56,16 @@ export type ShaclValidationReport = ValidationReport.ValidationReport<
|
|
|
27
56
|
DatasetCoreFactory<Quad, Quad, DatasetCore<Quad, Quad>>
|
|
28
57
|
>;
|
|
29
58
|
|
|
59
|
+
type PropertyWithError = {
|
|
60
|
+
message: string;
|
|
61
|
+
subject: string | undefined;
|
|
62
|
+
shape: string;
|
|
63
|
+
constraint: string;
|
|
64
|
+
};
|
|
30
65
|
interface DocumentValidationResult {
|
|
31
66
|
report?: ValidationReport;
|
|
32
67
|
propertiesWithoutErrors: { message: string }[];
|
|
33
|
-
propertiesWithErrors:
|
|
34
|
-
| {
|
|
35
|
-
message: string;
|
|
36
|
-
subject: string | undefined;
|
|
37
|
-
}
|
|
38
|
-
// TODO get rid of this?
|
|
39
|
-
| undefined
|
|
40
|
-
)[];
|
|
68
|
+
propertiesWithErrors: PropertyWithError[];
|
|
41
69
|
}
|
|
42
70
|
export interface DocumentValidationTransactionMeta
|
|
43
71
|
extends DocumentValidationResult {
|
|
@@ -47,6 +75,7 @@ export interface DocumentValidationPluginState
|
|
|
47
75
|
extends DocumentValidationResult {
|
|
48
76
|
documentShape: string;
|
|
49
77
|
validationCallback: typeof validationCallback;
|
|
78
|
+
rules: Rule[];
|
|
50
79
|
}
|
|
51
80
|
|
|
52
81
|
export const documentValidationPlugin = (
|
|
@@ -61,6 +90,7 @@ export const documentValidationPlugin = (
|
|
|
61
90
|
documentShape: options.documentShape,
|
|
62
91
|
propertiesWithoutErrors: [],
|
|
63
92
|
propertiesWithErrors: [],
|
|
93
|
+
rules: options.rules,
|
|
64
94
|
};
|
|
65
95
|
},
|
|
66
96
|
apply(tr, state) {
|
|
@@ -107,31 +137,30 @@ async function validationCallback(view: EditorView, documentHtml: string) {
|
|
|
107
137
|
...shacl.match(undefined, propertyPred, undefined),
|
|
108
138
|
].map((quad: Quad) => quad.object);
|
|
109
139
|
|
|
110
|
-
const propertiesWithErrors: {
|
|
111
|
-
sourceShape: BlankNode | NamedNode<string>;
|
|
112
|
-
focusNode: BlankNode | NamedNode<string> | null;
|
|
113
|
-
}[] = [];
|
|
114
|
-
for (const r of report.results) {
|
|
115
|
-
const sourceShape = r.sourceShape;
|
|
116
|
-
if (sourceShape)
|
|
117
|
-
propertiesWithErrors.push({ sourceShape, focusNode: r.focusNode });
|
|
118
|
-
}
|
|
119
140
|
const errorMessagePred = sayFactory.namedNode(
|
|
120
141
|
'http://www.w3.org/ns/shacl#resultMessage',
|
|
121
142
|
);
|
|
122
|
-
const
|
|
123
|
-
|
|
143
|
+
const propertiesWithErrors: PropertyWithError[] = [];
|
|
144
|
+
for (const r of report.results) {
|
|
145
|
+
const sourceShape = r.sourceShape;
|
|
146
|
+
if (sourceShape) {
|
|
124
147
|
const match = shacl.match(sourceShape, errorMessagePred, undefined);
|
|
125
148
|
const message = [...match][0]?.object.value;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
149
|
+
if (message) {
|
|
150
|
+
propertiesWithErrors.push({
|
|
151
|
+
message: removeQuotes(message),
|
|
152
|
+
subject: r.focusNode?.value,
|
|
153
|
+
shape: sourceShape.value,
|
|
154
|
+
constraint: r.sourceConstraintComponent?.value as string,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
131
160
|
const propertiesWithoutErrorsArray = propertyNodes.filter((propertyNode) =>
|
|
132
|
-
propertiesWithErrors.
|
|
133
|
-
|
|
134
|
-
|
|
161
|
+
propertiesWithErrors.every(
|
|
162
|
+
(propertyWithError) => propertyWithError.shape !== propertyNode.value,
|
|
163
|
+
),
|
|
135
164
|
);
|
|
136
165
|
|
|
137
166
|
const successMessagePred = sayFactory.namedNode(
|
|
@@ -149,7 +178,7 @@ async function validationCallback(view: EditorView, documentHtml: string) {
|
|
|
149
178
|
type: 'setNewReport',
|
|
150
179
|
report,
|
|
151
180
|
propertiesWithoutErrors,
|
|
152
|
-
propertiesWithErrors:
|
|
181
|
+
propertiesWithErrors: propertiesWithErrors,
|
|
153
182
|
});
|
|
154
183
|
transaction.setMeta('addToHistory', false);
|
|
155
184
|
view.dispatch(transaction);
|
|
@@ -38,30 +38,50 @@ import { createNumberVariable } from '../../variable-plugin/actions/create-numbe
|
|
|
38
38
|
import { createDateVariable } from '../../variable-plugin/actions/create-date-variable';
|
|
39
39
|
import { createCodelistVariable } from '../../variable-plugin/actions/create-codelist-variable';
|
|
40
40
|
import { createClassicLocationVariable } from '../../variable-plugin/actions/create-classic-location-variable';
|
|
41
|
+
import { isTrafficSignal, TrafficSignal } from '../schemas/traffic-signal';
|
|
42
|
+
import { MobilityMeasurePreview } from '../schemas/mobility-measure-preview';
|
|
43
|
+
import {
|
|
44
|
+
isVariableInstance,
|
|
45
|
+
VariableInstance,
|
|
46
|
+
} from '../schemas/variable-instance';
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
measureConcept: MobilityMeasureConcept;
|
|
48
|
+
type InsertMeasureArgs = {
|
|
44
49
|
zonality: ZonalOrNot;
|
|
45
50
|
temporal: boolean;
|
|
46
|
-
variables: Record<
|
|
51
|
+
variables: Record<
|
|
52
|
+
string,
|
|
53
|
+
Exclude<Variable, { type: 'instruction' }> | VariableInstance
|
|
54
|
+
>;
|
|
47
55
|
templateString: string;
|
|
48
56
|
decisionUri: string;
|
|
49
57
|
articleUriGenerator?: () => string;
|
|
50
|
-
}
|
|
58
|
+
} & (
|
|
59
|
+
| {
|
|
60
|
+
measureConcept: MobilityMeasureConcept;
|
|
61
|
+
}
|
|
62
|
+
| {
|
|
63
|
+
measurePreview: MobilityMeasurePreview;
|
|
64
|
+
}
|
|
65
|
+
);
|
|
51
66
|
|
|
52
67
|
export default function insertMeasure({
|
|
53
|
-
measureConcept,
|
|
54
68
|
zonality,
|
|
55
69
|
temporal,
|
|
56
70
|
variables,
|
|
57
71
|
templateString,
|
|
58
72
|
articleUriGenerator,
|
|
59
73
|
decisionUri,
|
|
74
|
+
...args
|
|
60
75
|
}: InsertMeasureArgs): TransactionMonad<boolean> {
|
|
61
76
|
return function (state: EditorState) {
|
|
77
|
+
const measureConcept =
|
|
78
|
+
'measureConcept' in args
|
|
79
|
+
? args.measureConcept
|
|
80
|
+
: args.measurePreview.measureConcept;
|
|
81
|
+
const measurePreview = 'measurePreview' in args && args.measurePreview;
|
|
62
82
|
const { schema } = state;
|
|
63
83
|
const signNodes = measureConcept.trafficSignalConcepts.map((signConcept) =>
|
|
64
|
-
|
|
84
|
+
constructSignalNode(signConcept, schema, zonality),
|
|
65
85
|
);
|
|
66
86
|
let signSection: PNode[] = [];
|
|
67
87
|
if (signNodes.length) {
|
|
@@ -117,6 +137,14 @@ export default function insertMeasure({
|
|
|
117
137
|
predicate: DCT('description').full,
|
|
118
138
|
object: sayDataFactory.contentLiteral('nl-BE'),
|
|
119
139
|
},
|
|
140
|
+
...(measurePreview
|
|
141
|
+
? [
|
|
142
|
+
{
|
|
143
|
+
predicate: MOBILITEIT('isGebaseerdOpMaatregelOntwerp'),
|
|
144
|
+
object: sayDataFactory.namedNode(measurePreview.uri),
|
|
145
|
+
},
|
|
146
|
+
]
|
|
147
|
+
: []),
|
|
120
148
|
// TODO there are some properties that are missing from the measure that we should define if we can:
|
|
121
149
|
// locn:address, mobiliteit:contactorganisatie, mobiliteit:doelgroep, adms:identifier,
|
|
122
150
|
// mobiliteit:periode, mobiliteit:plaatsbepaling, schema:eventSchedule, mobiliteit:type,
|
|
@@ -172,7 +200,10 @@ export default function insertMeasure({
|
|
|
172
200
|
|
|
173
201
|
function constructMeasureBody(
|
|
174
202
|
templateString: string,
|
|
175
|
-
variables: Record<
|
|
203
|
+
variables: Record<
|
|
204
|
+
string,
|
|
205
|
+
Exclude<Variable, { type: 'instruction' }> | VariableInstance
|
|
206
|
+
>,
|
|
176
207
|
schema: Schema,
|
|
177
208
|
) {
|
|
178
209
|
const parts = templateString.split(/(\$\{[^{}$]+\})/);
|
|
@@ -216,13 +247,18 @@ function determineSignLabel(signConcept: TrafficSignalConcept) {
|
|
|
216
247
|
}
|
|
217
248
|
}
|
|
218
249
|
|
|
219
|
-
function
|
|
220
|
-
|
|
250
|
+
function constructSignalNode(
|
|
251
|
+
signalOrSignalConcept: TrafficSignal | TrafficSignalConcept,
|
|
221
252
|
schema: Schema,
|
|
222
253
|
zonality?: ZonalOrNot,
|
|
223
254
|
) {
|
|
224
|
-
const
|
|
225
|
-
|
|
255
|
+
const signalConcept = isTrafficSignal(signalOrSignalConcept)
|
|
256
|
+
? signalOrSignalConcept.trafficSignalConcept
|
|
257
|
+
: signalOrSignalConcept;
|
|
258
|
+
const signalUri = isTrafficSignal(signalOrSignalConcept)
|
|
259
|
+
? signalOrSignalConcept.uri
|
|
260
|
+
: `http://data.lblod.info/verkeerstekens/${uuid()}`;
|
|
261
|
+
const prefix = determineSignLabel(signalConcept);
|
|
226
262
|
const zonalityText =
|
|
227
263
|
!zonality || zonality !== ZONALITY_OPTIONS.ZONAL
|
|
228
264
|
? ''
|
|
@@ -232,7 +268,7 @@ function constructSignNode(
|
|
|
232
268
|
const node = schema.nodes.inline_rdfa.create(
|
|
233
269
|
{
|
|
234
270
|
rdfaNodeType: 'resource',
|
|
235
|
-
subject:
|
|
271
|
+
subject: signalUri,
|
|
236
272
|
__rdfaId: uuid(),
|
|
237
273
|
properties: [
|
|
238
274
|
{
|
|
@@ -242,33 +278,48 @@ function constructSignNode(
|
|
|
242
278
|
{
|
|
243
279
|
predicate: RDF('type').full,
|
|
244
280
|
object: sayDataFactory.namedNode(
|
|
245
|
-
TRAFFIC_SIGNAL_TYPE_MAPPING[
|
|
281
|
+
TRAFFIC_SIGNAL_TYPE_MAPPING[signalConcept.type],
|
|
246
282
|
),
|
|
247
283
|
},
|
|
248
284
|
{
|
|
249
285
|
predicate: PROV('wasDerivedFrom').full,
|
|
250
|
-
object: sayDataFactory.namedNode(
|
|
286
|
+
object: sayDataFactory.namedNode(signalOrSignalConcept.uri),
|
|
251
287
|
},
|
|
252
288
|
// TODO should include extra Verkeersteken properties? mobiliteit:heeftOnderbord,
|
|
253
289
|
// mobiliteit:isBeginZone, mobiliteit:isEindeZone?
|
|
254
290
|
],
|
|
255
291
|
},
|
|
256
292
|
schema.text(
|
|
257
|
-
`${prefix} ${
|
|
293
|
+
`${prefix} ${signalConcept.regulatoryNotation || signalConcept.code}${zonalityText}`,
|
|
258
294
|
),
|
|
259
295
|
);
|
|
260
296
|
return node;
|
|
261
297
|
}
|
|
262
298
|
|
|
263
299
|
function constructVariableNode(
|
|
264
|
-
|
|
300
|
+
variableOrVariableInstance:
|
|
301
|
+
| Exclude<Variable, { type: 'instruction' }>
|
|
302
|
+
| VariableInstance,
|
|
265
303
|
schema: Schema,
|
|
266
304
|
) {
|
|
267
|
-
const
|
|
305
|
+
const variable = isVariableInstance(variableOrVariableInstance)
|
|
306
|
+
? variableOrVariableInstance.variable
|
|
307
|
+
: variableOrVariableInstance;
|
|
308
|
+
const variableInstance = isVariableInstance(variableOrVariableInstance)
|
|
309
|
+
? variableOrVariableInstance
|
|
310
|
+
: {
|
|
311
|
+
uri: generateVariableInstanceUri(),
|
|
312
|
+
value: undefined,
|
|
313
|
+
};
|
|
314
|
+
const valueStr =
|
|
315
|
+
variableInstance.value instanceof Date
|
|
316
|
+
? variableInstance.value.toISOString()
|
|
317
|
+
: variableInstance.value?.toString();
|
|
268
318
|
const args = {
|
|
269
319
|
schema,
|
|
270
320
|
variable: variable.uri,
|
|
271
|
-
variableInstance,
|
|
321
|
+
variableInstance: variableInstance.uri,
|
|
322
|
+
value: valueStr,
|
|
272
323
|
label: variable.label,
|
|
273
324
|
};
|
|
274
325
|
switch (variable.type) {
|
|
@@ -92,8 +92,15 @@ async function _queryMobilityMeasures<Count extends boolean>(
|
|
|
92
92
|
: /* sparql */ `SELECT DISTINCT ?uri ?label ?preview ?zonality ?variableSignage`;
|
|
93
93
|
|
|
94
94
|
const filterStatement = _buildFilters(options).join('\n');
|
|
95
|
+
const orderBindings = !count
|
|
96
|
+
? `
|
|
97
|
+
BIND(REPLACE(?label, "^(\\\\D+).*", "$1", "i") AS ?firstLetters)
|
|
98
|
+
BIND(xsd:decimal(REPLACE(?label, "^\\\\D+(\\\\d*\\\\.?\\\\d*).*", "$1", "i")) AS ?number)
|
|
99
|
+
BIND(REPLACE(?label, "^\\\\D+\\\\d*\\\\.?\\\\d*(.*)", "$1", "i") AS ?secondLetters)
|
|
100
|
+
`
|
|
101
|
+
: '';
|
|
95
102
|
const orderByStatement = !count
|
|
96
|
-
? /* sparql */ `ORDER BY ASC(
|
|
103
|
+
? /* sparql */ `ORDER BY ASC(UCASE(?firstLetters)) ASC(?number) ASC(LCASE(?secondLetters))`
|
|
97
104
|
: '';
|
|
98
105
|
const paginationStatement = !count
|
|
99
106
|
? /* sparql */ `LIMIT ${pageSize} OFFSET ${page * pageSize}`
|
|
@@ -126,6 +133,7 @@ async function _queryMobilityMeasures<Count extends boolean>(
|
|
|
126
133
|
?signUri dct:type ?signClassification.
|
|
127
134
|
}
|
|
128
135
|
${filterStatement}
|
|
136
|
+
${orderBindings}
|
|
129
137
|
}
|
|
130
138
|
${orderByStatement}
|
|
131
139
|
${paginationStatement}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TrafficSignalSchema } from './traffic-signal';
|
|
3
|
+
import {
|
|
4
|
+
type MobilityMeasureConcept,
|
|
5
|
+
MobilityMeasureConceptSchema,
|
|
6
|
+
} from './mobility-measure-concept';
|
|
7
|
+
|
|
8
|
+
export const MobilityMeasurePreviewSchema = z.object({
|
|
9
|
+
uri: z.string(),
|
|
10
|
+
trafficSignals: z.array(TrafficSignalSchema),
|
|
11
|
+
measureConcept: MobilityMeasureConceptSchema,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type MobilityMeasurePreview = z.infer<
|
|
15
|
+
typeof MobilityMeasurePreviewSchema
|
|
16
|
+
>;
|
|
17
|
+
|
|
18
|
+
export function isMobilityMeasurePreview(
|
|
19
|
+
conceptOrPreview: MobilityMeasureConcept | MobilityMeasurePreview,
|
|
20
|
+
): conceptOrPreview is MobilityMeasurePreview {
|
|
21
|
+
return 'measureConcept' in conceptOrPreview;
|
|
22
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
TrafficSignalConcept,
|
|
4
|
+
TrafficSignalConceptSchema,
|
|
5
|
+
} from './traffic-signal-concept';
|
|
6
|
+
|
|
7
|
+
export const TrafficSignalSchema = z.object({
|
|
8
|
+
uri: z.string(),
|
|
9
|
+
trafficSignalConcept: TrafficSignalConceptSchema,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type TrafficSignal = z.infer<typeof TrafficSignalSchema>;
|
|
13
|
+
|
|
14
|
+
export function isTrafficSignal(
|
|
15
|
+
signalOrSignalConcept: TrafficSignal | TrafficSignalConcept,
|
|
16
|
+
): signalOrSignalConcept is TrafficSignal {
|
|
17
|
+
return 'trafficSignalConcept' in signalOrSignalConcept;
|
|
18
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import {
|
|
3
|
+
CodelistVariableSchema,
|
|
4
|
+
DateVariableSchema,
|
|
5
|
+
LocationVariableSchema,
|
|
6
|
+
NumberVariableSchema,
|
|
7
|
+
TextVariableSchema,
|
|
8
|
+
Variable,
|
|
9
|
+
} from './variable';
|
|
10
|
+
|
|
11
|
+
const BaseVariableInstanceSchema = z.object({
|
|
12
|
+
uri: z.string(),
|
|
13
|
+
id: z.string(),
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const TextVariableInstanceSchema = BaseVariableInstanceSchema.extend({
|
|
17
|
+
value: z.string().optional(),
|
|
18
|
+
variable: TextVariableSchema,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const NumberVariableInstanceSchema = BaseVariableInstanceSchema.extend({
|
|
22
|
+
value: z.number({ coerce: true }).optional(),
|
|
23
|
+
variable: NumberVariableSchema,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const DateVariableInstanceSchema = BaseVariableInstanceSchema.extend({
|
|
27
|
+
value: z.date({ coerce: true }).optional(),
|
|
28
|
+
variable: DateVariableSchema,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const LocationVariableInstanceSchema = BaseVariableInstanceSchema.extend({
|
|
32
|
+
value: z.string().optional(),
|
|
33
|
+
variable: LocationVariableSchema,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const CodelistVariableInstanceSchema = BaseVariableInstanceSchema.extend({
|
|
37
|
+
value: z.string().optional(),
|
|
38
|
+
variable: CodelistVariableSchema,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const VariableInstanceSchema = z.union([
|
|
42
|
+
TextVariableInstanceSchema,
|
|
43
|
+
NumberVariableInstanceSchema,
|
|
44
|
+
DateVariableInstanceSchema,
|
|
45
|
+
LocationVariableInstanceSchema,
|
|
46
|
+
CodelistVariableInstanceSchema,
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
export type VariableInstance = z.infer<typeof VariableInstanceSchema>;
|
|
50
|
+
|
|
51
|
+
export function isVariableInstance(
|
|
52
|
+
variableOrVariableInstance: Variable | VariableInstance,
|
|
53
|
+
): variableOrVariableInstance is VariableInstance {
|
|
54
|
+
return 'variable' in variableOrVariableInstance;
|
|
55
|
+
}
|
|
@@ -5,33 +5,33 @@ const BaseVariableSchema = z.object({
|
|
|
5
5
|
label: z.string(),
|
|
6
6
|
source: z.string().optional(),
|
|
7
7
|
});
|
|
8
|
-
const TextVariableSchema = BaseVariableSchema.extend({
|
|
8
|
+
export const TextVariableSchema = BaseVariableSchema.extend({
|
|
9
9
|
type: z.literal('text'),
|
|
10
10
|
defaultValue: z.string().optional(),
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
const NumberVariableSchema = BaseVariableSchema.extend({
|
|
13
|
+
export const NumberVariableSchema = BaseVariableSchema.extend({
|
|
14
14
|
type: z.literal('number'),
|
|
15
15
|
defaultValue: z.number({ coerce: true }).optional(),
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
const DateVariableSchema = BaseVariableSchema.extend({
|
|
18
|
+
export const DateVariableSchema = BaseVariableSchema.extend({
|
|
19
19
|
type: z.literal('date'),
|
|
20
20
|
defaultValue: z.date({ coerce: true }).optional(),
|
|
21
21
|
});
|
|
22
22
|
|
|
23
|
-
const CodelistVariableSchema = BaseVariableSchema.extend({
|
|
23
|
+
export const CodelistVariableSchema = BaseVariableSchema.extend({
|
|
24
24
|
type: z.literal('codelist'),
|
|
25
25
|
defaultValue: z.string().optional(),
|
|
26
26
|
codelistUri: z.string(),
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
const LocationVariableSchema = BaseVariableSchema.extend({
|
|
29
|
+
export const LocationVariableSchema = BaseVariableSchema.extend({
|
|
30
30
|
type: z.literal('location'),
|
|
31
31
|
defaultValue: z.string().optional(),
|
|
32
32
|
});
|
|
33
33
|
|
|
34
|
-
const InstructionVariableSchema = BaseVariableSchema.extend({
|
|
34
|
+
export const InstructionVariableSchema = BaseVariableSchema.extend({
|
|
35
35
|
type: z.literal('instruction'),
|
|
36
36
|
});
|
|
37
37
|
|
|
@@ -7,6 +7,16 @@ import { hasOutgoingNamedNodeTriple } from '@lblod/ember-rdfa-editor-lblod-plugi
|
|
|
7
7
|
import { ElementPNode } from '@lblod/ember-rdfa-editor/plugins/datastore';
|
|
8
8
|
import { findAncestors } from '@lblod/ember-rdfa-editor/utils/position-utils';
|
|
9
9
|
|
|
10
|
+
export function getDecisionNodeLocation(controller: SayController) {
|
|
11
|
+
const besluitRange = getCurrentBesluitRange(controller);
|
|
12
|
+
if (!besluitRange) return;
|
|
13
|
+
const decisionNodeLocation = {
|
|
14
|
+
pos: besluitRange.from,
|
|
15
|
+
node: besluitRange.node,
|
|
16
|
+
};
|
|
17
|
+
return decisionNodeLocation;
|
|
18
|
+
}
|
|
19
|
+
|
|
10
20
|
export const getCurrentBesluitRange = (
|
|
11
21
|
controllerOrState: SayController | EditorState,
|
|
12
22
|
): ElementPNode | undefined => {
|
|
@@ -15,15 +25,29 @@ export const getCurrentBesluitRange = (
|
|
|
15
25
|
? controllerOrState.mainEditorState
|
|
16
26
|
: controllerOrState;
|
|
17
27
|
const selection = state.selection;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
let besluit;
|
|
29
|
+
if (
|
|
30
|
+
selection.$from.nodeAfter &&
|
|
31
|
+
hasOutgoingNamedNodeTriple(
|
|
32
|
+
selection.$from.nodeAfter.attrs,
|
|
33
|
+
RDF('type'),
|
|
34
|
+
BESLUIT('Besluit'),
|
|
35
|
+
)
|
|
36
|
+
) {
|
|
37
|
+
besluit = {
|
|
38
|
+
node: selection.$from.nodeAfter,
|
|
39
|
+
pos: selection.$from.pos,
|
|
40
|
+
};
|
|
41
|
+
} else {
|
|
42
|
+
besluit =
|
|
43
|
+
findAncestors(selection.$from, (node: PNode) => {
|
|
44
|
+
return hasOutgoingNamedNodeTriple(
|
|
45
|
+
node.attrs,
|
|
46
|
+
RDF('type'),
|
|
47
|
+
BESLUIT('Besluit'),
|
|
48
|
+
);
|
|
49
|
+
})[0] ?? null;
|
|
50
|
+
}
|
|
27
51
|
if (!besluit) {
|
|
28
52
|
return undefined;
|
|
29
53
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Component from '@glimmer/component';
|
|
2
2
|
import { SayController } from '@lblod/ember-rdfa-editor';
|
|
3
|
+
import ValidationReport from 'rdf-validate-shacl/src/validation-report';
|
|
3
4
|
interface Sig {
|
|
4
5
|
Args: {
|
|
5
6
|
controller: SayController;
|
|
@@ -9,14 +10,63 @@ export default class DocumentValidationPluginCard extends Component<Sig> {
|
|
|
9
10
|
get controller(): SayController;
|
|
10
11
|
get validationState(): import("@lblod/ember-rdfa-editor-lblod-plugins/plugins/document-validation-plugin").DocumentValidationPluginState | undefined;
|
|
11
12
|
get documentValidationErrors(): ({
|
|
13
|
+
rule: {
|
|
14
|
+
action: (controller: SayController, report: ValidationReport) => void;
|
|
15
|
+
buttonTitle: string;
|
|
16
|
+
} | {
|
|
17
|
+
helpText: string;
|
|
18
|
+
};
|
|
12
19
|
message: string;
|
|
13
20
|
subject: string | undefined;
|
|
14
|
-
|
|
21
|
+
shape: string;
|
|
22
|
+
constraint: string;
|
|
23
|
+
} | {
|
|
24
|
+
rule: {
|
|
25
|
+
shaclRule: string;
|
|
26
|
+
action: (controller: SayController, report: ValidationReport) => void;
|
|
27
|
+
buttonTitle: string;
|
|
28
|
+
} | {
|
|
29
|
+
shaclRule: string;
|
|
30
|
+
helpText: string;
|
|
31
|
+
} | undefined;
|
|
32
|
+
message: string;
|
|
33
|
+
subject: string | undefined;
|
|
34
|
+
shape: string;
|
|
35
|
+
constraint: string;
|
|
36
|
+
})[] | undefined;
|
|
15
37
|
get propertiesWithoutErrors(): {
|
|
16
38
|
message: string;
|
|
17
39
|
}[];
|
|
18
40
|
goToSubject: (subject: string) => void;
|
|
19
41
|
get status(): "not-run" | "no-matches" | "valid" | "invalid";
|
|
20
42
|
get isSuccesslike(): boolean;
|
|
43
|
+
doActionAndTriggerValidation: (action: (controller: SayController, report: ValidationReport) => void) => Promise<void>;
|
|
44
|
+
oldVal: typeof this.documentValidationErrors;
|
|
45
|
+
dedupeDocumentValidationErrors: (val: typeof this.documentValidationErrors) => ({
|
|
46
|
+
rule: {
|
|
47
|
+
action: (controller: SayController, report: ValidationReport) => void;
|
|
48
|
+
buttonTitle: string;
|
|
49
|
+
} | {
|
|
50
|
+
helpText: string;
|
|
51
|
+
};
|
|
52
|
+
message: string;
|
|
53
|
+
subject: string | undefined;
|
|
54
|
+
shape: string;
|
|
55
|
+
constraint: string;
|
|
56
|
+
} | {
|
|
57
|
+
rule: {
|
|
58
|
+
shaclRule: string;
|
|
59
|
+
action: (controller: SayController, report: ValidationReport) => void;
|
|
60
|
+
buttonTitle: string;
|
|
61
|
+
} | {
|
|
62
|
+
shaclRule: string;
|
|
63
|
+
helpText: string;
|
|
64
|
+
} | undefined;
|
|
65
|
+
message: string;
|
|
66
|
+
subject: string | undefined;
|
|
67
|
+
shape: string;
|
|
68
|
+
constraint: string;
|
|
69
|
+
})[] | undefined;
|
|
70
|
+
compareDocumentValidationErrors: (val1: typeof this.documentValidationErrors, val2: typeof this.documentValidationErrors) => boolean;
|
|
21
71
|
}
|
|
22
72
|
export {};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Command } from '@lblod/ember-rdfa-editor';
|
|
2
2
|
import IntlService from 'ember-intl/services/intl';
|
|
3
|
+
import { NodeWithPos } from '@curvenote/prosemirror-utils';
|
|
3
4
|
interface InsertArticleContainerArgs {
|
|
4
5
|
intl: IntlService;
|
|
5
6
|
decisionUri: string;
|
|
6
7
|
articleUriGenerator?: () => string;
|
|
8
|
+
decisionLocation: NodeWithPos;
|
|
7
9
|
}
|
|
8
|
-
export default function insertArticleContainer({ decisionUri, articleUriGenerator, }: InsertArticleContainerArgs): Command;
|
|
10
|
+
export default function insertArticleContainer({ decisionUri, articleUriGenerator, decisionLocation, }: InsertArticleContainerArgs): Command;
|
|
9
11
|
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SayController } from '@lblod/ember-rdfa-editor';
|
|
2
|
+
import IntlService from 'ember-intl/services/intl';
|
|
3
|
+
export declare function insertTitleAtCursor(controller: SayController, intl: IntlService): void;
|
|
4
|
+
export declare function insertDescriptionAtCursor(controller: SayController, intl: IntlService): void;
|
|
5
|
+
export declare function insertMotivationAtCursor(controller: SayController, intl: IntlService): void;
|
|
6
|
+
export declare function insertArticleContainerAtCursor(controller: SayController, intl: IntlService, articleUriGenerator?: () => string): void;
|