@luomus/laji-form 15.1.69 → 15.1.70

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.
Files changed (31) hide show
  1. package/dist/laji-form.js +1 -1
  2. package/lib/ApiClient.d.ts +66 -21
  3. package/lib/ApiClient.js +174 -68
  4. package/lib/components/LajiForm.js +1 -1
  5. package/lib/components/fields/AnnotationField.js +26 -22
  6. package/lib/components/fields/AudioArrayField.js +18 -5
  7. package/lib/components/fields/AutosuggestField.d.ts +2 -2
  8. package/lib/components/fields/AutosuggestField.js +4 -4
  9. package/lib/components/fields/EnumRangeArrayField.js +1 -1
  10. package/lib/components/fields/GeocoderField.js +67 -79
  11. package/lib/components/fields/ImageArrayField.d.ts +2 -2
  12. package/lib/components/fields/ImageArrayField.js +82 -112
  13. package/lib/components/fields/MapArrayField.js +13 -5
  14. package/lib/components/fields/MapField.d.ts +1 -1
  15. package/lib/components/fields/MapField.js +13 -5
  16. package/lib/components/fields/NamedPlaceChooserField/NamedPlaceChooser.d.ts +2 -1
  17. package/lib/components/fields/NamedPlaceChooserField/NamedPlaceChooserField.d.ts +9 -4
  18. package/lib/components/fields/NamedPlaceChooserField/NamedPlaceChooserField.js +51 -51
  19. package/lib/components/fields/NamedPlaceChooserField/Popup.d.ts +2 -1
  20. package/lib/components/fields/NamedPlaceSaverField.js +22 -18
  21. package/lib/components/fields/ScopeField.js +1 -1
  22. package/lib/components/fields/SingleActiveArrayField.js +2 -2
  23. package/lib/components/fields/SortArrayField.js +1 -1
  24. package/lib/components/fields/UnitCountShorthandField.js +1 -1
  25. package/lib/components/fields/UnitListShorthandArrayField.js +2 -2
  26. package/lib/components/fields/UnitShorthandField.js +14 -18
  27. package/lib/components/widgets/AutosuggestWidget.js +77 -66
  28. package/lib/components/widgets/InformalTaxonGroupChooserWidget.js +1 -1
  29. package/lib/components/widgets/InputWithDefaultValueButtonWidget.js +1 -2
  30. package/lib/validation.js +1 -1
  31. package/package.json +5 -3
@@ -32,6 +32,15 @@ var __importStar = (this && this.__importStar) || (function () {
32
32
  return result;
33
33
  };
34
34
  })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
35
44
  var __importDefault = (this && this.__importDefault) || function (mod) {
36
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
46
  };
@@ -59,7 +68,6 @@ const PLACE_DELETE_FAIL = "PLACE_DELETE_FAIL";
59
68
  class NamedPlaceChooserField extends React.Component {
60
69
  constructor() {
61
70
  super(...arguments);
62
- this.removeIds = {};
63
71
  this.mounted = false;
64
72
  this.state = {};
65
73
  this.getUiSchema = (props, buttonDefinition) => {
@@ -122,69 +130,61 @@ class NamedPlaceChooserField extends React.Component {
122
130
  this.setState({ failed: PLACE_USE_FAIL });
123
131
  }
124
132
  };
125
- this.onPlaceDeleted = (place, success) => {
126
- this.props.formContext.apiClient.fetchRaw(`/named-places/${place.id}`, undefined, { method: "DELETE" }).then(response => {
127
- if (response.status < 400) {
128
- // It takes a while for API to remove the place, so we remove it locally and then invalidate again after some time.
129
- this.removeIds[place.id] = true;
130
- this.props.formContext.apiClient.invalidateCachePath("/named-places");
131
- setTimeout(() => this.props.formContext.apiClient.invalidateCachePath("/named-places"), 2000);
132
- success();
133
- }
134
- }).catch(() => {
133
+ this.onPlaceDeleted = (place, end) => __awaiter(this, void 0, void 0, function* () {
134
+ try {
135
+ yield this.props.formContext.apiClient.delete("/named-places/{id}", { path: { id: place.id } });
136
+ end();
137
+ }
138
+ catch (e) {
135
139
  this.setState({ failed: PLACE_DELETE_FAIL });
136
140
  this.props.formContext.notifier.error(this.props.formContext.translations.PlaceRemovalFailed);
137
- });
138
- };
141
+ end();
142
+ }
143
+ });
139
144
  this.onButtonClick = () => () => {
140
145
  this.setState({ show: true });
141
146
  };
142
- this.updatePlaces = () => {
143
- this.props.formContext.apiClient.fetchCached("/named-places", { includePublic: false, pageSize: 100000 }).then(response => {
144
- var _a;
145
- if (!this.mounted)
146
- return;
147
- const state = { places: response.results.filter(p => !this.removeIds[p.id]).sort((a, b) => {
148
- if (a.name < b.name)
149
- return -1;
150
- if (a.name > b.name)
151
- return 1;
152
- return 0;
153
- }) };
154
- if (!((_a = response.results) === null || _a === void 0 ? void 0 : _a.length)) {
155
- return;
156
- }
157
- const buttonDefinition = {
158
- fn: this.onButtonClick,
159
- fnName: "addNamedPlace",
160
- glyph: "map-marker",
161
- label: this.props.formContext.translations.ChooseFromNamedPlace,
162
- id: this.props.idSchema.$id,
163
- changesFormData: true,
164
- variant: "primary"
165
- };
166
- if (this.isGatheringsArray(this.props.schema)) {
167
- buttonDefinition.rules = { canAdd: true };
168
- }
169
- else {
170
- buttonDefinition.position = "top";
171
- }
172
- state.buttonDefinition = buttonDefinition;
173
- this.setState(state);
174
- }).catch(() => {
175
- this.setState({ failed: PLACES_FETCH_FAIL });
176
- });
147
+ this.updatePlaces = (response) => {
148
+ var _a;
149
+ if (!this.mounted)
150
+ return;
151
+ const state = { places: response.results.sort((a, b) => {
152
+ if (a.name < b.name)
153
+ return -1;
154
+ if (a.name > b.name)
155
+ return 1;
156
+ return 0;
157
+ }) };
158
+ if (!((_a = response.results) === null || _a === void 0 ? void 0 : _a.length)) {
159
+ return;
160
+ }
161
+ const buttonDefinition = {
162
+ fn: this.onButtonClick,
163
+ fnName: "addNamedPlace",
164
+ glyph: "map-marker",
165
+ label: this.props.formContext.translations.ChooseFromNamedPlace,
166
+ id: this.props.idSchema.$id,
167
+ changesFormData: true,
168
+ variant: "primary"
169
+ };
170
+ if (this.isGatheringsArray(this.props.schema)) {
171
+ buttonDefinition.rules = { canAdd: true };
172
+ }
173
+ else {
174
+ buttonDefinition.position = "top";
175
+ }
176
+ state.buttonDefinition = buttonDefinition;
177
+ this.setState(state);
177
178
  };
178
179
  this.onHide = () => this.setState({ show: false });
179
180
  }
180
181
  componentDidMount() {
181
182
  this.mounted = true;
182
- this.updatePlaces();
183
- this.props.formContext.apiClient.onCachePathInvalidation("/named-places", this.updatePlaces);
183
+ this.getNamedPlacesUnsubscribe = this.props.formContext.apiClient.subscribe("/named-places", { query: { includePublic: false, pageSize: 100000 } }, this.updatePlaces, () => this.setState({ failed: PLACES_FETCH_FAIL }), 1000);
184
184
  }
185
185
  componentWillUnmount() {
186
186
  this.mounted = false;
187
- this.props.formContext.apiClient.removeOnCachePathInvalidation("/named-places", this.updatePlaces);
187
+ this.getNamedPlacesUnsubscribe();
188
188
  }
189
189
  render() {
190
190
  const { registry: { fields: { SchemaField } }, formContext } = this.props;
@@ -1,6 +1,7 @@
1
1
  import * as React from "react";
2
- import { NamedPlace } from "@luomus/laji-schema";
3
2
  import { FormContext } from "src/components/LajiForm";
3
+ import type { components } from "generated/api.d";
4
+ type NamedPlace = components["schemas"]["namedPlace"];
4
5
  type Props = {
5
6
  onPlaceSelected: (place: NamedPlace) => void;
6
7
  onPlaceDeleted: (place: NamedPlace) => void;
@@ -38,6 +38,15 @@ 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
+ };
41
50
  var __rest = (this && this.__rest) || function (s, e) {
42
51
  var t = {};
43
52
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -182,7 +191,7 @@ class PlaceSaverDialog extends React.Component {
182
191
  }
183
192
  componentDidMount() {
184
193
  this.mounted = true;
185
- this.apiClient.fetchCached("/named-places", { includePublic: false, pageSize: 1000 }).then(response => {
194
+ this.apiClient.get("/named-places", { query: { includePublic: false, pageSize: 100000 } }).then(response => {
186
195
  if (!this.mounted)
187
196
  return;
188
197
  const state = {
@@ -213,23 +222,18 @@ class PlaceSaverDialog extends React.Component {
213
222
  });
214
223
  }
215
224
  onSave(place) {
216
- place = Object.assign(Object.assign({}, place), { geometry: place.prepopulatedDocument.gatherings[0].geometry });
217
- this.props.formContext.services.blocker.push();
218
- this.apiClient.fetchRaw(`/named-places${place.id ? `/${place.id}` : ""}`, undefined, {
219
- method: place.id ? "PUT" : "POST",
220
- headers: {
221
- "accept": "application/json",
222
- "content-type": "application/json"
223
- },
224
- body: JSON.stringify(place)
225
- }).then(response => {
226
- this.props.formContext.services.blocker.pop();
227
- this.apiClient.invalidateCachePath("/named-places");
228
- return response.json();
229
- }).then(this.props.onSave)
230
- .catch(() => {
231
- this.props.formContext.services.blocker.pop();
232
- this.setState({ failed: SAVE });
225
+ return __awaiter(this, void 0, void 0, function* () {
226
+ place = Object.assign(Object.assign({}, place), { geometry: place.prepopulatedDocument.gatherings[0].geometry });
227
+ this.props.formContext.services.blocker.push();
228
+ try {
229
+ const savedPlace = yield this.apiClient[place.id ? "put" : "post"](`/named-places${place.id ? "/{id}" : ""}`, place.id ? { path: { id: place.id } } : undefined, place);
230
+ this.props.formContext.services.blocker.pop();
231
+ yield this.props.onSave(savedPlace);
232
+ }
233
+ catch (e) {
234
+ this.props.formContext.services.blocker.pop();
235
+ this.setState({ failed: SAVE });
236
+ }
233
237
  });
234
238
  }
235
239
  render() {
@@ -50,7 +50,7 @@ const utils_2 = require("@rjsf/utils");
50
50
  const scopeFieldSettings = {
51
51
  taxonGroups: {
52
52
  translate: (props, taxonGroup) => {
53
- return props.formContext.apiClient.fetchCached("/informal-taxon-groups/" + taxonGroup).then((response) => {
53
+ return props.formContext.apiClient.get("/informal-taxon-groups/" + taxonGroup).then((response) => {
54
54
  return response.name;
55
55
  }).catch(() => {
56
56
  return "";
@@ -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.fetchCached(`/named-places/${namedPlaceID}`, undefined, { failSilently: true }).then(response => {
914
+ props.that.props.formContext.apiClient.get("/named-places/{id}", { path: { id: namedPlaceID } }).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
+ }).catch(() => { });
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.fetchCached("/taxa", Object.assign(Object.assign({}, this.options.query), { pageSize: 10000, selectedFields: "id" })))
72
+ this.idToIdx = (yield this.formContext.apiClient.get("/taxa", { query: 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.fetchCached("/autocomplete/pairCount", { q: value, taxonID: taxonId }).then(suggestion => {
85
+ apiClient.get("/shorthand/unit/water-bird-pair-count", { query: { query: 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.fetch("/autocomplete/unit", { q: value, list: true, includePayload: true }).then(({ payload: { units, nonMatchingCount } }) => {
73
- units = units.map(unit => {
72
+ apiClient.get("/shorthand/unit/list", { query: { query: value } }).then(({ results, nonMatchingCount }) => {
73
+ const units = results.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,7 +51,6 @@ 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"];
55
54
  let UnitShorthandField = class UnitShorthandField extends React.Component {
56
55
  constructor(props) {
57
56
  super(props);
@@ -125,13 +124,13 @@ let UnitShorthandField = class UnitShorthandField extends React.Component {
125
124
  render() {
126
125
  const { uiSchema, formContext, disabled, readonly } = this.props;
127
126
  const { SchemaField } = this.props.registry.fields;
128
- const shorthandFieldName = (0, utils_1.getUiOptions)(this.props.uiSchema).shorthandField;
127
+ const { shorthandField, lineTransect } = (0, utils_1.getUiOptions)(this.props.uiSchema);
129
128
  const toggleButton = this.getToggleButton();
130
129
  const tailUiSchema = (0, utils_1.getNestedTailUiSchema)(uiSchema);
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 :
130
+ let help = tailUiSchema && tailUiSchema[shorthandField] && tailUiSchema[shorthandField]["ui:belowHelp"];
131
+ const uiSchemaWithoutHelp = (0, utils_1.isEmptyString)(help) ? uiSchema : (0, utils_1.updateTailUiSchema)(uiSchema, { [shorthandField]: { "ui:belowHelp": { $set: undefined } } });
132
+ const id = (shorthandField && this.props.idSchema[shorthandField]) ?
133
+ this.props.idSchema[shorthandField].$id :
135
134
  `${this.props.idSchema.$id}_shortHandField`;
136
135
  let innerUiSchema = undefined;
137
136
  if (this.state.showSchema) {
@@ -140,7 +139,7 @@ let UnitShorthandField = class UnitShorthandField extends React.Component {
140
139
  innerUiSchema = Object.assign(Object.assign({}, innerUiSchema), { "ui:options": Object.assign(Object.assign({}, innerOptions), { buttons: [...(innerOptions.buttons || []), toggleButton] }) });
141
140
  }
142
141
  return !this.state.showSchema ? (React.createElement("div", { className: "laji-form-field-template-item", id: `_laji-form_${id}` },
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" }),
142
+ React.createElement(CodeReader, { translations: this.props.formContext.translations, onChange: this.onCodeChange, value: this.props.formData[shorthandField], formID: (0, utils_1.getUiOptions)(this.props.uiSchema).formID || formContext.formID || formContext.uiSchemaContext.formID, help: help, id: id, formContext: formContext, disabled: disabled, readonly: readonly, lineTransect: lineTransect, className: "laji-form-field-template-schema" }),
144
143
  React.createElement("div", { className: "laji-form-field-template-buttons" }, (0, ArrayFieldTemplate_1.getButton)(toggleButton)))) : (React.createElement(SchemaField, Object.assign({}, this.props, { uiSchema: innerUiSchema })));
145
144
  }
146
145
  };
@@ -185,14 +184,14 @@ let CodeReader = class CodeReader extends React.Component {
185
184
  this.onAutosuggestChange = (formData) => {
186
185
  this.props.onChange(formData);
187
186
  };
188
- this.onSuggestionSelected = ({ payload: { unit } }) => {
187
+ this.onSuggestionSelected = ({ unit }) => {
189
188
  const { formContext } = this.props;
190
189
  unit = (0, utils_1.bringRemoteFormData)(unit, formContext);
191
190
  this.props.onChange(unit);
192
191
  };
193
192
  this.renderSuggestion = (suggestion) => {
194
193
  const { translations } = this.props;
195
- return suggestion.payload.isNonMatching
194
+ return suggestion.isNonMatching
196
195
  ? React.createElement("span", { className: "text-muted" },
197
196
  suggestion.value,
198
197
  " ",
@@ -212,8 +211,8 @@ let CodeReader = class CodeReader extends React.Component {
212
211
  }
213
212
  else if (value.length >= 3) {
214
213
  this.mounted && this.setState({ loading: true });
215
- this.apiClient.fetchCached("/autocomplete/unit", { q: value, formID: this.props.formID, includePayload: true }).then(response => {
216
- this.props.onChange(response.payload.unit);
214
+ this.apiClient.get("/shorthand/unit/line-transect", { query: { query: value } }).then(response => {
215
+ this.props.onChange(response.unit);
217
216
  }).catch(() => {
218
217
  this.mounted && this.setState({ failed: true, loading: false });
219
218
  });
@@ -230,18 +229,15 @@ let CodeReader = class CodeReader extends React.Component {
230
229
  this.mounted = false;
231
230
  }
232
231
  render() {
233
- const { translations, readonly, disabled } = this.props;
232
+ const { translations, readonly, disabled, lineTransect } = this.props;
234
233
  let validationState = null;
235
234
  if (this.state.failed === true)
236
235
  validationState = "warning";
237
236
  else if (!(0, utils_1.isEmptyString)(this.props.value) && this.props.value === this.state.value)
238
237
  validationState = "success";
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 })));
238
+ const { formContext } = this.props;
239
+ const inputElem = lineTransect ? (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" },
240
+ React.createElement(AutosuggestWidget_1.Autosuggest, { autosuggestField: "unit", onSuggestionSelected: this.onSuggestionSelected, renderSuggestion: this.renderSuggestion, onChange: this.onAutosuggestChange, formContext: formContext, allowNonsuggestedValue: false })));
245
241
  const { FormGroup, HelpBlock } = this.context.theme;
246
242
  return (React.createElement(FormGroup, { validationState: this.state.failed ? "error" : undefined },
247
243
  inputElem,