@luomus/laji-form 15.1.68 → 15.1.69
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/dist/laji-form.js +1 -1
- package/lib/ApiClient.d.ts +21 -66
- package/lib/ApiClient.js +68 -174
- package/lib/components/LajiForm.js +1 -1
- package/lib/components/fields/AnnotationField.js +22 -26
- package/lib/components/fields/AudioArrayField.js +5 -18
- package/lib/components/fields/AutosuggestField.d.ts +2 -2
- package/lib/components/fields/AutosuggestField.js +4 -4
- package/lib/components/fields/EnumRangeArrayField.js +1 -1
- package/lib/components/fields/GeocoderField.js +9 -2
- package/lib/components/fields/ImageArrayField.d.ts +2 -2
- package/lib/components/fields/ImageArrayField.js +112 -82
- package/lib/components/fields/MapArrayField.js +5 -13
- package/lib/components/fields/MapField.d.ts +1 -1
- package/lib/components/fields/MapField.js +5 -13
- package/lib/components/fields/NamedPlaceChooserField/NamedPlaceChooser.d.ts +1 -2
- package/lib/components/fields/NamedPlaceChooserField/NamedPlaceChooserField.d.ts +4 -9
- package/lib/components/fields/NamedPlaceChooserField/NamedPlaceChooserField.js +51 -51
- package/lib/components/fields/NamedPlaceChooserField/Popup.d.ts +1 -2
- package/lib/components/fields/NamedPlaceSaverField.js +18 -22
- package/lib/components/fields/ScopeField.js +1 -1
- package/lib/components/fields/SingleActiveArrayField.js +2 -2
- package/lib/components/fields/SortArrayField.js +1 -1
- package/lib/components/fields/UnitCountShorthandField.js +1 -1
- package/lib/components/fields/UnitListShorthandArrayField.js +2 -2
- package/lib/components/fields/UnitShorthandField.js +18 -14
- package/lib/components/widgets/AutosuggestWidget.js +66 -79
- package/lib/components/widgets/InformalTaxonGroupChooserWidget.js +1 -1
- package/lib/components/widgets/InputWithDefaultValueButtonWidget.js +2 -1
- package/lib/validation.js +1 -1
- package/package.json +3 -5
|
@@ -911,13 +911,13 @@ const headerFormatters = {
|
|
|
911
911
|
this.fetch = (props) => {
|
|
912
912
|
const { namedPlaceID } = (props.that.props.formData || {})[props.idx] || {};
|
|
913
913
|
if (namedPlaceID)
|
|
914
|
-
props.that.props.formContext.apiClient.
|
|
914
|
+
props.that.props.formContext.apiClient.fetchCached(`/named-places/${namedPlaceID}`, undefined, { failSilently: true }).then(response => {
|
|
915
915
|
if (this.mounted && response.name !== this.state.name)
|
|
916
916
|
this.setState({
|
|
917
917
|
namedPlaceID,
|
|
918
918
|
name: response.name
|
|
919
919
|
});
|
|
920
|
-
})
|
|
920
|
+
});
|
|
921
921
|
};
|
|
922
922
|
this.state = {};
|
|
923
923
|
}
|
|
@@ -69,7 +69,7 @@ class TaxonomicComparer extends Comparer {
|
|
|
69
69
|
}
|
|
70
70
|
initialize() {
|
|
71
71
|
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
-
this.idToIdx = (yield this.formContext.apiClient.
|
|
72
|
+
this.idToIdx = (yield this.formContext.apiClient.fetchCached("/taxa", Object.assign(Object.assign({}, this.options.query), { pageSize: 10000, selectedFields: "id" })))
|
|
73
73
|
.results.reduce((idToIdx, { id }, idx) => {
|
|
74
74
|
idToIdx[id] = idx;
|
|
75
75
|
return idToIdx;
|
|
@@ -82,7 +82,7 @@ let UnitCountShorthandField = class UnitCountShorthandField extends React.Compon
|
|
|
82
82
|
resolve({ success: undefined });
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
|
-
apiClient.
|
|
85
|
+
apiClient.fetchCached("/autocomplete/pairCount", { q: value, taxonID: taxonId }).then(suggestion => {
|
|
86
86
|
if (timestamp !== this.promiseTimestamp) {
|
|
87
87
|
reject();
|
|
88
88
|
return;
|
|
@@ -69,8 +69,8 @@ let UnitListShorthandArrayField = class UnitListShorthandArrayField extends Reac
|
|
|
69
69
|
this.onHide();
|
|
70
70
|
const { translations, notifier, apiClient } = this.props.formContext;
|
|
71
71
|
this.props.formContext.services.blocker.push();
|
|
72
|
-
apiClient.
|
|
73
|
-
|
|
72
|
+
apiClient.fetch("/autocomplete/unit", { q: value, list: true, includePayload: true }).then(({ payload: { units, nonMatchingCount } }) => {
|
|
73
|
+
units = units.map(unit => {
|
|
74
74
|
unit = (0, utils_1.getDefaultFormState)(this.props.schema.items, unit);
|
|
75
75
|
unit = (0, utils_1.bringRemoteFormData)(unit, this.props.formContext);
|
|
76
76
|
unit = (0, utils_1.assignUUID)(unit);
|
|
@@ -51,6 +51,7 @@ const ReactContext_1 = __importDefault(require("../../ReactContext"));
|
|
|
51
51
|
const components_1 = require("../components");
|
|
52
52
|
const AutosuggestWidget_1 = require("../widgets/AutosuggestWidget");
|
|
53
53
|
const ArrayFieldTemplate_1 = require("../templates/ArrayFieldTemplate");
|
|
54
|
+
const LINE_TRANSECT_IDS = ["MHL.1162", "MHL.27", "MHL.28"];
|
|
54
55
|
let UnitShorthandField = class UnitShorthandField extends React.Component {
|
|
55
56
|
constructor(props) {
|
|
56
57
|
super(props);
|
|
@@ -124,13 +125,13 @@ let UnitShorthandField = class UnitShorthandField extends React.Component {
|
|
|
124
125
|
render() {
|
|
125
126
|
const { uiSchema, formContext, disabled, readonly } = this.props;
|
|
126
127
|
const { SchemaField } = this.props.registry.fields;
|
|
127
|
-
const
|
|
128
|
+
const shorthandFieldName = (0, utils_1.getUiOptions)(this.props.uiSchema).shorthandField;
|
|
128
129
|
const toggleButton = this.getToggleButton();
|
|
129
130
|
const tailUiSchema = (0, utils_1.getNestedTailUiSchema)(uiSchema);
|
|
130
|
-
let help = tailUiSchema && tailUiSchema[
|
|
131
|
-
const uiSchemaWithoutHelp = (0, utils_1.isEmptyString)(help) ? uiSchema : (0, utils_1.updateTailUiSchema)(uiSchema, { [
|
|
132
|
-
const id = (
|
|
133
|
-
this.props.idSchema[
|
|
131
|
+
let help = tailUiSchema && tailUiSchema[shorthandFieldName] && tailUiSchema[shorthandFieldName]["ui:belowHelp"];
|
|
132
|
+
const uiSchemaWithoutHelp = (0, utils_1.isEmptyString)(help) ? uiSchema : (0, utils_1.updateTailUiSchema)(uiSchema, { [shorthandFieldName]: { "ui:belowHelp": { $set: undefined } } });
|
|
133
|
+
const id = (shorthandFieldName && this.props.idSchema[shorthandFieldName]) ?
|
|
134
|
+
this.props.idSchema[shorthandFieldName].$id :
|
|
134
135
|
`${this.props.idSchema.$id}_shortHandField`;
|
|
135
136
|
let innerUiSchema = undefined;
|
|
136
137
|
if (this.state.showSchema) {
|
|
@@ -139,7 +140,7 @@ let UnitShorthandField = class UnitShorthandField extends React.Component {
|
|
|
139
140
|
innerUiSchema = Object.assign(Object.assign({}, innerUiSchema), { "ui:options": Object.assign(Object.assign({}, innerOptions), { buttons: [...(innerOptions.buttons || []), toggleButton] }) });
|
|
140
141
|
}
|
|
141
142
|
return !this.state.showSchema ? (React.createElement("div", { className: "laji-form-field-template-item", id: `_laji-form_${id}` },
|
|
142
|
-
React.createElement(CodeReader, { translations: this.props.formContext.translations, onChange: this.onCodeChange, value: this.props.formData[
|
|
143
|
+
React.createElement(CodeReader, { translations: this.props.formContext.translations, onChange: this.onCodeChange, value: this.props.formData[shorthandFieldName], formID: (0, utils_1.getUiOptions)(this.props.uiSchema).formID || formContext.formID || formContext.uiSchemaContext.formID, help: help, id: id, formContext: formContext, disabled: disabled, readonly: readonly, className: "laji-form-field-template-schema" }),
|
|
143
144
|
React.createElement("div", { className: "laji-form-field-template-buttons" }, (0, ArrayFieldTemplate_1.getButton)(toggleButton)))) : (React.createElement(SchemaField, Object.assign({}, this.props, { uiSchema: innerUiSchema })));
|
|
144
145
|
}
|
|
145
146
|
};
|
|
@@ -184,14 +185,14 @@ let CodeReader = class CodeReader extends React.Component {
|
|
|
184
185
|
this.onAutosuggestChange = (formData) => {
|
|
185
186
|
this.props.onChange(formData);
|
|
186
187
|
};
|
|
187
|
-
this.onSuggestionSelected = ({ unit }) => {
|
|
188
|
+
this.onSuggestionSelected = ({ payload: { unit } }) => {
|
|
188
189
|
const { formContext } = this.props;
|
|
189
190
|
unit = (0, utils_1.bringRemoteFormData)(unit, formContext);
|
|
190
191
|
this.props.onChange(unit);
|
|
191
192
|
};
|
|
192
193
|
this.renderSuggestion = (suggestion) => {
|
|
193
194
|
const { translations } = this.props;
|
|
194
|
-
return suggestion.isNonMatching
|
|
195
|
+
return suggestion.payload.isNonMatching
|
|
195
196
|
? React.createElement("span", { className: "text-muted" },
|
|
196
197
|
suggestion.value,
|
|
197
198
|
" ",
|
|
@@ -211,8 +212,8 @@ let CodeReader = class CodeReader extends React.Component {
|
|
|
211
212
|
}
|
|
212
213
|
else if (value.length >= 3) {
|
|
213
214
|
this.mounted && this.setState({ loading: true });
|
|
214
|
-
this.apiClient.
|
|
215
|
-
this.props.onChange(response.unit);
|
|
215
|
+
this.apiClient.fetchCached("/autocomplete/unit", { q: value, formID: this.props.formID, includePayload: true }).then(response => {
|
|
216
|
+
this.props.onChange(response.payload.unit);
|
|
216
217
|
}).catch(() => {
|
|
217
218
|
this.mounted && this.setState({ failed: true, loading: false });
|
|
218
219
|
});
|
|
@@ -229,15 +230,18 @@ let CodeReader = class CodeReader extends React.Component {
|
|
|
229
230
|
this.mounted = false;
|
|
230
231
|
}
|
|
231
232
|
render() {
|
|
232
|
-
const { translations, readonly, disabled
|
|
233
|
+
const { translations, readonly, disabled } = this.props;
|
|
233
234
|
let validationState = null;
|
|
234
235
|
if (this.state.failed === true)
|
|
235
236
|
validationState = "warning";
|
|
236
237
|
else if (!(0, utils_1.isEmptyString)(this.props.value) && this.props.value === this.state.value)
|
|
237
238
|
validationState = "success";
|
|
238
|
-
const { formContext } = this.props;
|
|
239
|
-
const inputElem =
|
|
240
|
-
React.createElement(AutosuggestWidget_1.Autosuggest, { autosuggestField: "unit",
|
|
239
|
+
const { formID, formContext } = this.props;
|
|
240
|
+
const inputElem = LINE_TRANSECT_IDS.includes(formID) ? (React.createElement(components_1.FetcherInput, { id: this.props.id, loading: this.state.loading, value: this.state.value, validationState: validationState, onChange: this.onFetcherInputChange, onBlur: this.getCode, onKeyDown: this.onKeyDown, readonly: readonly, disabled: disabled })) : (React.createElement("div", { className: "unit-shorthand" },
|
|
241
|
+
React.createElement(AutosuggestWidget_1.Autosuggest, { autosuggestField: "unit", query: {
|
|
242
|
+
formID,
|
|
243
|
+
includeNonMatching: true
|
|
244
|
+
}, onSuggestionSelected: this.onSuggestionSelected, renderSuggestion: this.renderSuggestion, onChange: this.onAutosuggestChange, formContext: formContext, allowNonsuggestedValue: false })));
|
|
241
245
|
const { FormGroup, HelpBlock } = this.context.theme;
|
|
242
246
|
return (React.createElement(FormGroup, { validationState: this.state.failed ? "error" : undefined },
|
|
243
247
|
inputElem,
|
|
@@ -38,15 +38,6 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
return result;
|
|
39
39
|
};
|
|
40
40
|
})();
|
|
41
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
42
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
43
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
44
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
45
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
46
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
47
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
48
|
-
});
|
|
49
|
-
};
|
|
50
41
|
var __rest = (this && this.__rest) || function (s, e) {
|
|
51
42
|
var t = {};
|
|
52
43
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
@@ -72,7 +63,7 @@ const components_1 = require("../components");
|
|
|
72
63
|
const ReactContext_1 = __importDefault(require("../../ReactContext"));
|
|
73
64
|
const InformalTaxonGroupChooserWidget_1 = require("./InformalTaxonGroupChooserWidget");
|
|
74
65
|
function renderFlag(suggestion, prepend) {
|
|
75
|
-
return (suggestion || {}).finnish
|
|
66
|
+
return (suggestion && suggestion.payload || {}).finnish
|
|
76
67
|
? React.createElement(React.Fragment, null,
|
|
77
68
|
prepend || null,
|
|
78
69
|
React.createElement("img", { src: "https://cdn.laji.fi/images/icons/flag_fi_small.png", width: "16" }))
|
|
@@ -82,11 +73,10 @@ class _AutosuggestWidget extends React.Component {
|
|
|
82
73
|
render() {
|
|
83
74
|
if (this.props.options) {
|
|
84
75
|
switch (this.props.options.autosuggestField) {
|
|
85
|
-
case "taxa":
|
|
86
76
|
case "taxon":
|
|
87
|
-
return React.createElement(TaxonAutosuggestWidget, Object.assign({}, this.props
|
|
77
|
+
return React.createElement(TaxonAutosuggestWidget, Object.assign({}, this.props));
|
|
88
78
|
case "unit":
|
|
89
|
-
return React.createElement(UnitAutosuggestWidget, Object.assign({}, this.props
|
|
79
|
+
return React.createElement(UnitAutosuggestWidget, Object.assign({}, this.props));
|
|
90
80
|
case "friends":
|
|
91
81
|
case "person":
|
|
92
82
|
return React.createElement(FriendsAutosuggestWidget, Object.assign({}, this.props));
|
|
@@ -107,7 +97,6 @@ class _AutosuggestWidget extends React.Component {
|
|
|
107
97
|
let component = undefined;
|
|
108
98
|
switch (options.autosuggestField) {
|
|
109
99
|
case "taxon":
|
|
110
|
-
case "taxa":
|
|
111
100
|
component = TaxonAutosuggestWidget;
|
|
112
101
|
break;
|
|
113
102
|
case "unit":
|
|
@@ -187,7 +176,11 @@ function TaxonAutosuggest(ComposedComponent) {
|
|
|
187
176
|
orWriteSpeciesNameLabel || this.props.formContext.translations.orWriteSpeciesName))));
|
|
188
177
|
};
|
|
189
178
|
this.onTaxonImgSelected = (taxonID, taxon) => {
|
|
190
|
-
this.autosuggestRef.selectSuggestion(
|
|
179
|
+
this.autosuggestRef.selectSuggestion({
|
|
180
|
+
key: taxonID,
|
|
181
|
+
value: taxon.vernacularName,
|
|
182
|
+
payload: taxon
|
|
183
|
+
});
|
|
191
184
|
};
|
|
192
185
|
this.setAutosuggestRef = (elem) => {
|
|
193
186
|
this.autosuggestRef = elem;
|
|
@@ -219,20 +212,19 @@ function TaxonAutosuggest(ComposedComponent) {
|
|
|
219
212
|
}
|
|
220
213
|
}
|
|
221
214
|
getSuggestionFromValue(value) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const { vernacularName, scientificName } = yield this.props.formContext.apiClient.get(`/taxa/${id}`);
|
|
215
|
+
if (this.isValueSuggested(value)) {
|
|
216
|
+
return this.props.formContext.apiClient.fetchCached(`/taxa/${value}`).then(({ vernacularName, scientificName }) => {
|
|
225
217
|
if (vernacularName !== undefined) {
|
|
226
218
|
return { value: vernacularName, key: value };
|
|
227
219
|
}
|
|
228
220
|
if (scientificName !== undefined) {
|
|
229
221
|
return { value: scientificName, key: value };
|
|
230
222
|
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
return Promise.reject();
|
|
227
|
+
}
|
|
236
228
|
}
|
|
237
229
|
isValueSuggested(value) {
|
|
238
230
|
return !(0, utils_1.isEmptyString)(value) && !!value.match(/MX\.\d+/);
|
|
@@ -280,10 +272,10 @@ let UnitAutosuggestWidget = class UnitAutosuggestWidget extends React.Component
|
|
|
280
272
|
this.renderSuggestion = this.renderSuggestion.bind(this);
|
|
281
273
|
}
|
|
282
274
|
renderSuggestion(suggestion) {
|
|
283
|
-
const { count, maleIndividualCount, femaleIndividualCount } = suggestion.interpretedFrom;
|
|
275
|
+
const { count, maleIndividualCount, femaleIndividualCount } = suggestion.payload.interpretedFrom;
|
|
284
276
|
const [countElem, maleElem, femaleElem] = [count, maleIndividualCount, femaleIndividualCount].map(val => val && React.createElement("span", { className: "text-muted" }, val));
|
|
285
|
-
const taxonName = suggestion.unit.identifications[0].taxon;
|
|
286
|
-
const name = suggestion.isNonMatching
|
|
277
|
+
const taxonName = suggestion.payload.unit.identifications[0].taxon;
|
|
278
|
+
const name = suggestion.payload.isNonMatching
|
|
287
279
|
? React.createElement("span", { className: "text-muted" },
|
|
288
280
|
taxonName,
|
|
289
281
|
" ",
|
|
@@ -326,11 +318,10 @@ class FriendsAutosuggestWidget extends React.Component {
|
|
|
326
318
|
this.isValueSuggested = this.isValueSuggested.bind(this);
|
|
327
319
|
}
|
|
328
320
|
getSuggestionFromValue(value) {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const { fullName, group, id } = yield this.props.formContext.apiClient.get(`/person/by-id/${value}`);
|
|
321
|
+
const { showID } = (0, utils_1.getUiOptions)(this.props);
|
|
322
|
+
const { isAdmin } = this.props.formContext.uiSchemaContext;
|
|
323
|
+
if (this.isValueSuggested(value)) {
|
|
324
|
+
return this.props.formContext.apiClient.fetchCached(`/person/by-id/${value}`).then(({ fullName, group, id }) => {
|
|
334
325
|
if (fullName) {
|
|
335
326
|
const addGroup = str => group ? `${str} (${group})` : str;
|
|
336
327
|
const addID = str => isAdmin && showID ? `${str} (${id})` : str;
|
|
@@ -339,11 +330,11 @@ class FriendsAutosuggestWidget extends React.Component {
|
|
|
339
330
|
key: value
|
|
340
331
|
};
|
|
341
332
|
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
return Promise.reject();
|
|
337
|
+
}
|
|
347
338
|
}
|
|
348
339
|
isValueSuggested(value) {
|
|
349
340
|
return !(0, utils_1.isEmptyString)(value) && value.match(/MA\.\d+/);
|
|
@@ -391,21 +382,22 @@ class BasicAutosuggestWidget extends React.Component {
|
|
|
391
382
|
this.isValueSuggested = this.isValueSuggested.bind(this);
|
|
392
383
|
}
|
|
393
384
|
getSuggestionFromValue(value) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
385
|
+
const { autosuggestField, nameField } = this.props;
|
|
386
|
+
if (this.isValueSuggested(value)) {
|
|
387
|
+
const apiClient = this.props.formContext.apiClient;
|
|
388
|
+
const fetch = (this.props.cache ? apiClient.fetchCached : apiClient.fetch).bind(apiClient);
|
|
389
|
+
return fetch(`/${autosuggestField}/by-id/${value}`).then(result => {
|
|
398
390
|
if (result[nameField]) {
|
|
399
391
|
return {
|
|
400
392
|
value: result[nameField],
|
|
401
393
|
key: value
|
|
402
394
|
};
|
|
403
395
|
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
return Promise.reject();
|
|
400
|
+
}
|
|
409
401
|
}
|
|
410
402
|
isValueSuggested(value) {
|
|
411
403
|
const regexp = new RegExp(this.props.validValueRegexp);
|
|
@@ -544,12 +536,12 @@ class Autosuggest extends React.Component {
|
|
|
544
536
|
const { findExactMatch } = this.props;
|
|
545
537
|
return findExactMatch
|
|
546
538
|
? findExactMatch(suggestions, inputValue)
|
|
547
|
-
: suggestions.find(suggestion => (suggestion && suggestion.value.toLowerCase() === inputValue.trim().toLowerCase() && !suggestion.isNonMatching));
|
|
539
|
+
: suggestions.find(suggestion => (suggestion && suggestion.value.toLowerCase() === inputValue.trim().toLowerCase() && (!suggestion.payload || !suggestion.payload.isNonMatching)));
|
|
548
540
|
};
|
|
549
541
|
this.findTheOnlyOneMatch = (suggestions) => {
|
|
550
542
|
if (!Array.isArray(suggestions))
|
|
551
543
|
suggestions = [suggestions];
|
|
552
|
-
const filtered = suggestions.filter(suggestion => !suggestion || !suggestion.isNonMatching);
|
|
544
|
+
const filtered = suggestions.filter(suggestion => !suggestion || !suggestion.payload || !suggestion.payload.isNonMatching);
|
|
553
545
|
if (filtered.length === 1) {
|
|
554
546
|
return filtered[0];
|
|
555
547
|
}
|
|
@@ -557,7 +549,7 @@ class Autosuggest extends React.Component {
|
|
|
557
549
|
this.findNonMatching = (suggestions) => {
|
|
558
550
|
if (!Array.isArray(suggestions))
|
|
559
551
|
suggestions = [suggestions];
|
|
560
|
-
const filtered = suggestions.filter(suggestion => suggestion && suggestion.isNonMatching);
|
|
552
|
+
const filtered = suggestions.filter(suggestion => suggestion && suggestion.payload && suggestion.payload.isNonMatching);
|
|
561
553
|
if (filtered.length === 1) {
|
|
562
554
|
return filtered[0];
|
|
563
555
|
}
|
|
@@ -580,15 +572,11 @@ class Autosuggest extends React.Component {
|
|
|
580
572
|
}
|
|
581
573
|
const { autosuggestField, query = {} } = this.props;
|
|
582
574
|
this.setState({ isLoading: true });
|
|
583
|
-
const request = () =>
|
|
575
|
+
const request = () => {
|
|
584
576
|
let timestamp = Date.now();
|
|
585
577
|
this.promiseTimestamp = timestamp;
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
// Hack for laji-form in Kotka, since it uses API that isn't laji-api and q was renamed to query in laji-api
|
|
589
|
-
q: value, query: value, matchType: "exact,partial", includeHidden: false }, query) }, this.props.cache);
|
|
590
|
-
// Hack for laji-form in Kotka, since it uses API that isn't laji-api and might have different response signature.
|
|
591
|
-
let suggestions = Array.isArray(suggestionsResponse) ? suggestionsResponse : suggestionsResponse.results;
|
|
578
|
+
const fetch = (this.props.cache ? this.apiClient.fetchCached : this.apiClient.fetch).bind(this.apiClient);
|
|
579
|
+
fetch("/autocomplete/" + autosuggestField, Object.assign({ q: value, includePayload: true, matchType: "exact,partial", includeHidden: false }, query)).then(suggestions => {
|
|
592
580
|
if (this.props.prepareSuggestion) {
|
|
593
581
|
suggestions = suggestions.map(s => this.props.prepareSuggestion(s));
|
|
594
582
|
}
|
|
@@ -598,13 +586,12 @@ class Autosuggest extends React.Component {
|
|
|
598
586
|
this.mounted
|
|
599
587
|
? this.setState({ isLoading: false, suggestions }, () => this.afterBlurAndFetch(suggestions))
|
|
600
588
|
: this.afterBlurAndFetch(suggestions);
|
|
601
|
-
}
|
|
602
|
-
catch (e) {
|
|
589
|
+
}).catch(() => {
|
|
603
590
|
this.mounted
|
|
604
591
|
? this.setState({ isLoading: false }, this.afterBlurAndFetch)
|
|
605
592
|
: this.afterBlurAndFetch();
|
|
606
|
-
}
|
|
607
|
-
}
|
|
593
|
+
});
|
|
594
|
+
};
|
|
608
595
|
if (this.timeout) {
|
|
609
596
|
clearTimeout(this.timeout);
|
|
610
597
|
}
|
|
@@ -815,10 +802,10 @@ class Autosuggest extends React.Component {
|
|
|
815
802
|
? this.props.highlightFirstSuggestion
|
|
816
803
|
: !this.props.allowNonsuggestedValue;
|
|
817
804
|
const { renderExtra } = props;
|
|
818
|
-
return React.createElement(React.Fragment, null,
|
|
805
|
+
return (React.createElement(React.Fragment, null,
|
|
819
806
|
renderExtra && renderExtra(),
|
|
820
807
|
React.createElement("div", { className: (0, utils_1.classNames)("autosuggest-wrapper", props.wrapperClassName) },
|
|
821
|
-
React.createElement(ReactAutosuggest, { id: `${this.props.id}-autosuggest`, inputProps: inputProps, renderInputComponent: this.renderInput, suggestions: suggestions, renderSuggestion: this.renderSuggestion, onSuggestionsFetchRequested: this.onSuggestionsFetchRequested, onSuggestionsClearRequested: this.onSuggestionsClearRequested, onSuggestionSelected: this.onSuggestionSelected, onUnsuggestedSelected: this.onUnsuggestedSelected, highlightFirstSuggestion: highlightFirstSuggestion, suggestionsOpenOnFocus: !this.isSuggested(), theme: cssClasses, formContext: this.props.formContext, ref: this.setRef })));
|
|
808
|
+
React.createElement(ReactAutosuggest, { id: `${this.props.id}-autosuggest`, inputProps: inputProps, renderInputComponent: this.renderInput, suggestions: suggestions, renderSuggestion: this.renderSuggestion, onSuggestionsFetchRequested: this.onSuggestionsFetchRequested, onSuggestionsClearRequested: this.onSuggestionsClearRequested, onSuggestionSelected: this.onSuggestionSelected, onUnsuggestedSelected: this.onUnsuggestedSelected, highlightFirstSuggestion: highlightFirstSuggestion, suggestionsOpenOnFocus: !this.isSuggested(), theme: cssClasses, formContext: this.props.formContext, ref: this.setRef }))));
|
|
822
809
|
}
|
|
823
810
|
}
|
|
824
811
|
exports.Autosuggest = Autosuggest;
|
|
@@ -855,22 +842,21 @@ class _TaxonWrapper extends React.Component {
|
|
|
855
842
|
this.fetch(value);
|
|
856
843
|
}
|
|
857
844
|
fetch(value) {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
this.
|
|
845
|
+
if (!value) {
|
|
846
|
+
this.setState({ scientificName: "", cursiveName: false });
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
this.props.formContext.apiClient.fetchCached(`/taxa/${value}`).then(({ scientificName, cursiveName, vernacularName, taxonRank, informalTaxonGroups, finnish }) => {
|
|
850
|
+
if (!this.mounted)
|
|
851
|
+
return;
|
|
852
|
+
this.setState({ value, taxonRank, informalTaxonGroups, taxon: { scientificName, vernacularName, cursiveName, finnish } });
|
|
853
|
+
(0, InformalTaxonGroupChooserWidget_1.getInformalGroups)(this.props.formContext.apiClient).then(({ informalTaxonGroupsById }) => {
|
|
864
854
|
if (!this.mounted)
|
|
865
855
|
return;
|
|
866
|
-
this.setState({
|
|
867
|
-
(0, InformalTaxonGroupChooserWidget_1.getInformalGroups)(this.props.formContext.apiClient).then(({ informalTaxonGroupsById }) => {
|
|
868
|
-
if (!this.mounted)
|
|
869
|
-
return;
|
|
870
|
-
this.setState({ informalTaxonGroupsById });
|
|
871
|
-
});
|
|
856
|
+
this.setState({ informalTaxonGroupsById });
|
|
872
857
|
});
|
|
873
|
-
|
|
858
|
+
});
|
|
859
|
+
this.props.formContext.apiClient.fetchCached(`/taxa/${value}/parents`).then(parents => {
|
|
874
860
|
if (!this.mounted)
|
|
875
861
|
return;
|
|
876
862
|
const state = { order: undefined, family: undefined };
|
|
@@ -888,12 +874,13 @@ class _TaxonWrapper extends React.Component {
|
|
|
888
874
|
}
|
|
889
875
|
}
|
|
890
876
|
this.setState(Object.assign(Object.assign({}, state), { higherThanOrder: !state.order && !state.family }));
|
|
891
|
-
|
|
877
|
+
});
|
|
878
|
+
this.props.formContext.apiClient.fetchCached("/metadata/ranges/MX.taxonRankEnum").then(taxonRanks => {
|
|
892
879
|
if (!this.mounted)
|
|
893
880
|
return;
|
|
894
881
|
this.setState({ taxonRanks: (0, utils_1.dictionarify)(taxonRanks, function getKey(rank) { return rank.id; }, function getValue(rank) { return rank.value; }) });
|
|
895
|
-
}
|
|
896
|
-
}
|
|
882
|
+
});
|
|
883
|
+
}
|
|
897
884
|
}
|
|
898
885
|
render() {
|
|
899
886
|
const { id, formContext, value, children, placement, inputValue, isSuggested } = this.props;
|
|
@@ -1008,7 +995,7 @@ class TaxonImgChooser extends React.Component {
|
|
|
1008
995
|
}
|
|
1009
996
|
componentDidMount() {
|
|
1010
997
|
this.mounted = true;
|
|
1011
|
-
this.props.formContext.apiClient.
|
|
998
|
+
this.props.formContext.apiClient.fetchCached(`/taxa/${this.props.id}`, { includeMedia: true }).then(taxon => {
|
|
1012
999
|
if (!this.mounted)
|
|
1013
1000
|
return;
|
|
1014
1001
|
if (taxon.multimedia && taxon.multimedia.length) {
|
|
@@ -1055,7 +1042,7 @@ const TaxonName = ({ scientificName, vernacularName = "", cursiveName, finnish }
|
|
|
1055
1042
|
return (React.createElement(React.Fragment, null,
|
|
1056
1043
|
`${vernacularName}${vernacularName ? " " : ""}`,
|
|
1057
1044
|
cursiveName ? React.createElement("i", null, _scientificName) : _scientificName,
|
|
1058
|
-
renderFlag({ finnish }, " ")));
|
|
1045
|
+
renderFlag({ payload: { finnish } }, " ")));
|
|
1059
1046
|
};
|
|
1060
1047
|
class ReactAutosuggest extends React.Component {
|
|
1061
1048
|
constructor(props) {
|
|
@@ -161,7 +161,7 @@ function getInformalGroups(apiClient) {
|
|
|
161
161
|
if (informalTaxonGroups) {
|
|
162
162
|
return Promise.resolve({ informalTaxonGroups, informalTaxonGroupsById });
|
|
163
163
|
}
|
|
164
|
-
return apiClient.
|
|
164
|
+
return apiClient.fetchCached("/informal-taxon-groups/tree").then(response => {
|
|
165
165
|
// Contains the current taxon group.
|
|
166
166
|
const informalTaxonGroups = mapGroupsById(response.results);
|
|
167
167
|
// Contains all groups in flat object.
|
|
@@ -54,8 +54,9 @@ class InputWithDefaultValueButtonWidget extends React.Component {
|
|
|
54
54
|
else if (apiQueryForDefaultValue) {
|
|
55
55
|
const { path, query = {}, resultKey, cache = false } = apiQueryForDefaultValue;
|
|
56
56
|
const apiClient = this.props.formContext.apiClient;
|
|
57
|
+
const fetch = (cache ? apiClient.fetchCached : apiClient.fetch).bind(apiClient);
|
|
57
58
|
this.setState({ fetching: true });
|
|
58
|
-
return
|
|
59
|
+
return fetch(path, query).then(result => {
|
|
59
60
|
if (result[resultKey]) {
|
|
60
61
|
this.props.onChange(result[resultKey]);
|
|
61
62
|
}
|
package/lib/validation.js
CHANGED
|
@@ -39,7 +39,7 @@ exports.toErrorSchema = toErrorSchema;
|
|
|
39
39
|
const lajiValidate = __importStar(require("@luomus/laji-validate"));
|
|
40
40
|
function initializeValidation(apiClient) {
|
|
41
41
|
lajiValidate.extend(lajiValidate.validators.remote, {
|
|
42
|
-
fetch: (...params) => apiClient.
|
|
42
|
+
fetch: (...params) => apiClient.fetchRaw(...params)
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
exports.default = ({ errors: error, warnings: warning }, data) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luomus/laji-form",
|
|
3
|
-
"version": "15.1.
|
|
3
|
+
"version": "15.1.69",
|
|
4
4
|
"description": "React module capable of building dynamic forms from Laji form json schemas",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -28,8 +28,7 @@
|
|
|
28
28
|
"test:docker": "npm run test:docker:build && npm run test:docker:run --",
|
|
29
29
|
"test:lightweight": "npx playwright test --project chromium",
|
|
30
30
|
"test:docker:build": "docker build -t laji-form-test -f test.Dockerfile .",
|
|
31
|
-
"test:docker:run": "docker run laji-form-test"
|
|
32
|
-
"generate:api-client": "openapi-typescript https://apitest.laji.fi/explorer-json -o ./generated/api.d.ts --properties-required-by-default"
|
|
31
|
+
"test:docker:run": "docker run laji-form-test"
|
|
33
32
|
},
|
|
34
33
|
"keywords": [
|
|
35
34
|
"react-jsonschema-form",
|
|
@@ -72,7 +71,7 @@
|
|
|
72
71
|
"@playwright/test": "^1.40.1",
|
|
73
72
|
"@stylistic/eslint-plugin": "^5.4.0",
|
|
74
73
|
"@types/jasmine": "^3.7.7",
|
|
75
|
-
"@types/node": "^
|
|
74
|
+
"@types/node": "^20.17.0",
|
|
76
75
|
"@typescript-eslint/eslint-plugin": "^8.44.1",
|
|
77
76
|
"@typescript-eslint/parser": "^8.44.1",
|
|
78
77
|
"copy-webpack-plugin": "^9.0.1",
|
|
@@ -83,7 +82,6 @@
|
|
|
83
82
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
84
83
|
"mini-css-extract-plugin": "^2.1.0",
|
|
85
84
|
"notus": "^0.3.2",
|
|
86
|
-
"openapi-typescript": "^7.9.1",
|
|
87
85
|
"querystring": "^0.2.1",
|
|
88
86
|
"rimraf": "^2.5.4",
|
|
89
87
|
"style-loader": "^3.0.0",
|