@luomus/laji-form 15.1.66 → 15.1.68

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 +2 -9
  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 +79 -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
@@ -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)
@@ -162,7 +171,7 @@ function MediaArrayField(ComposedComponent) {
162
171
  const item = this.props.formData[i];
163
172
  this.setState({ metadataModalOpen: i });
164
173
  this.fetching = item;
165
- this.apiClient.fetch(`/${this.ENDPOINT}/${item}`).then((response) => {
174
+ this.apiClient.get(`/${this.ENDPOINT}/{id}`, { path: { id: item } }).then((response) => {
166
175
  if (response.id !== this.fetching)
167
176
  return;
168
177
  this._context.metadatas[item] = response;
@@ -172,10 +181,11 @@ function MediaArrayField(ComposedComponent) {
172
181
  this.onMediaRmClick = (i) => () => {
173
182
  const id = this.props.formData[i];
174
183
  this.props.onChange((0, immutability_helper_1.default)(this.props.formData, { $splice: [[i, 1]] }));
175
- this.apiClient.fetch(`/${this.ENDPOINT}/${id}`, undefined, {
176
- method: "DELETE",
177
- failSilently: true
178
- });
184
+ try {
185
+ this.apiClient.delete(`/${this.ENDPOINT}/{id}`, { path: { id } });
186
+ }
187
+ catch (e) {
188
+ }
179
189
  };
180
190
  this.hideMetadataModal = () => this.setState({ metadataModalOpen: false, metadataSaveSuccess: undefined });
181
191
  this.onMetadataFormChange = (formData) => this.setState({ modalMetadata: formData });
@@ -185,7 +195,7 @@ function MediaArrayField(ComposedComponent) {
185
195
  const metadataForm = this.state.metadataForm || {};
186
196
  if (typeof metadataModalOpen === "number" && !this.state.metadataForm) {
187
197
  const { metadataFormId = this.METADATA_FORM_ID } = (0, utils_1.getUiOptions)(this.props.uiSchema);
188
- this.apiClient.fetchCached(`/forms/${metadataFormId}`, { lang, format: "schema" })
198
+ this.apiClient.get("/forms/{id}", { path: { id: metadataFormId }, query: { lang, format: "schema" } })
189
199
  .then(metadataForm => {
190
200
  if (this.mounted) {
191
201
  this.setState({ metadataForm });
@@ -422,16 +432,10 @@ function MediaArrayField(ComposedComponent) {
422
432
  reader.readAsDataURL(file);
423
433
  });
424
434
  };
425
- this.onMediaMetadataUpdate = ({ formData }) => {
435
+ this.onMediaMetadataUpdate = (_a) => __awaiter(this, [_a], void 0, function* ({ formData }) {
426
436
  this.props.formContext.services.blocker.push();
427
- this.apiClient.fetch(`/${this.ENDPOINT}/${formData.id}`, undefined, {
428
- method: "PUT",
429
- headers: {
430
- "accept": "application/json",
431
- "content-type": "application/json"
432
- },
433
- body: JSON.stringify(formData)
434
- }).then(() => {
437
+ try {
438
+ yield this.apiClient.put(`/${this.ENDPOINT}/{id}`, { path: { id: formData.id } }, formData);
435
439
  this.props.formContext.services.blocker.pop();
436
440
  const notify = () => this.props.formContext.notifier.success(this.props.formContext.translations.SaveSuccess);
437
441
  if (this.mounted) {
@@ -440,11 +444,12 @@ function MediaArrayField(ComposedComponent) {
440
444
  else {
441
445
  notify();
442
446
  }
443
- }).catch(() => {
447
+ }
448
+ catch (e) {
444
449
  this.props.formContext.services.blocker.pop();
445
450
  this.mounted && this.setState({ metadataSaveSuccess: false });
446
- });
447
- };
451
+ }
452
+ });
448
453
  this.getMetadataPromise = () => {
449
454
  let mediaMetadata = this.props.formContext.mediaMetadata
450
455
  || { intellectualRights: "MZ.intellectualRightsARR" };
@@ -452,7 +457,7 @@ function MediaArrayField(ComposedComponent) {
452
457
  return ("capturerVerbatim" in mediaMetadata)
453
458
  ? Promise.resolve(Object.assign(Object.assign({}, mediaMetadata), { capturerVerbatim: [mediaMetadata.capturerVerbatim] }))
454
459
  : MACode
455
- ? this.apiClient.fetchCached(`/person/by-id/${MACode}`).then(({ fullName = MACode }) => (Object.assign(Object.assign({ capturerVerbatim: Array.isArray(fullName) ? fullName : [fullName] }, mediaMetadata), { intellectualOwner: fullName }))).catch(() => Promise.resolve(mediaMetadata))
460
+ ? this.apiClient.get("/person/by-id/{personId}", { path: { personId: MACode } }).then(({ fullName = MACode }) => (Object.assign(Object.assign({ capturerVerbatim: Array.isArray(fullName) ? fullName : [fullName] }, mediaMetadata), { intellectualOwner: fullName }))).catch(() => Promise.resolve(mediaMetadata))
456
461
  : mediaMetadata;
457
462
  };
458
463
  this.getMaxFileSizeAsString = () => {
@@ -567,105 +572,67 @@ function MediaArrayField(ComposedComponent) {
567
572
  this.renderMediaAddModal()))));
568
573
  }
569
574
  saveMedias(files) {
570
- const containerId = this.getContainerId();
571
- let tmpMedias;
572
- const fail = (translationKey, additionalInfo = "") => {
573
- const translation = (Array.isArray(translationKey) ? translationKey : [translationKey])
574
- .map((key) => this.props.formContext.translations[key])
575
- .join(". ");
576
- throw `${translation} ${additionalInfo}`;
577
- };
578
- return this.processFiles(files).then(processedFiles => {
579
- let invalidFile = (files.length <= 0);
580
- let fileTooLarge = false;
581
- let noValidData = true;
582
- if (!this._context.tmpMedias[containerId]) {
583
- this._context.tmpMedias[containerId] = {};
584
- }
585
- tmpMedias = processedFiles.map(f => {
586
- mediaUuid++;
587
- this._context.tmpMedias[containerId][mediaUuid] = f.dataURL;
588
- return mediaUuid;
589
- });
590
- this.mounted && this.setState({ tmpMedias: [...(this.state.tmpMedias || []), ...tmpMedias] });
591
- const formDataBody = files.reduce((body, file) => {
592
- if (!this.ALLOWED_FILE_TYPES.includes(file.type)) {
593
- invalidFile = true;
575
+ return __awaiter(this, void 0, void 0, function* () {
576
+ const containerId = this.getContainerId();
577
+ let tmpMedias = [];
578
+ const fail = (translationKey, additionalInfo = "") => {
579
+ const translation = (Array.isArray(translationKey) ? translationKey : [translationKey])
580
+ .map((key) => this.props.formContext.translations[key])
581
+ .join(". ");
582
+ throw `${translation} ${additionalInfo}`;
583
+ };
584
+ try {
585
+ const processedFiles = yield this.processFiles(files);
586
+ let invalidFile = (files.length <= 0);
587
+ let fileTooLarge = false;
588
+ let noValidData = true;
589
+ if (!this._context.tmpMedias[containerId]) {
590
+ this._context.tmpMedias[containerId] = {};
594
591
  }
595
- else if (file.size > this.MAX_FILE_SIZE) {
596
- fileTooLarge = true;
592
+ tmpMedias = processedFiles.map(f => {
593
+ mediaUuid++;
594
+ this._context.tmpMedias[containerId][mediaUuid] = f.dataURL;
595
+ return mediaUuid;
596
+ });
597
+ this.mounted && this.setState({ tmpMedias: [...(this.state.tmpMedias || []), ...tmpMedias] });
598
+ const formData = files.reduce((body, file) => {
599
+ if (!this.ALLOWED_FILE_TYPES.includes(file.type)) {
600
+ invalidFile = true;
601
+ }
602
+ else if (file.size > this.MAX_FILE_SIZE) {
603
+ fileTooLarge = true;
604
+ }
605
+ else {
606
+ body.append("data", file);
607
+ noValidData = false;
608
+ }
609
+ return body;
610
+ }, new FormData());
611
+ if (noValidData && invalidFile) {
612
+ fail(this.getAllowedMediaFormatsTranslationKey(), this.getAllowedMediaFormatsAsString() + ".");
613
+ return;
597
614
  }
598
- else {
599
- body.append("data", file);
600
- noValidData = false;
615
+ else if (noValidData && fileTooLarge) {
616
+ fail("AllowedFileSize", this.getMaxFileSizeAsString() + ".");
617
+ return;
601
618
  }
602
- return body;
603
- }, new FormData());
604
- if (noValidData && invalidFile) {
605
- fail(this.getAllowedMediaFormatsTranslationKey(), this.getAllowedMediaFormatsAsString() + ".");
606
- return;
607
- }
608
- else if (noValidData && fileTooLarge) {
609
- fail("AllowedFileSize", this.getMaxFileSizeAsString() + ".");
610
- return;
611
- }
612
- else {
613
- return this.apiClient.fetchRaw(`/${this.ENDPOINT}`, undefined, {
614
- method: "POST",
615
- body: formDataBody
619
+ const tmpMediaEntities = yield this.apiClient.post(`/${this.ENDPOINT}`, undefined, formData);
620
+ const mediaMetadata = yield this.getMetadataPromise();
621
+ const mediaEntities = yield Promise.all(tmpMediaEntities.map((item) => this.apiClient.post(`/${this.ENDPOINT}/{id}`, { path: { id: item.id } }, mediaMetadata)));
622
+ const ids = mediaEntities.map((item) => item ? item.id : undefined).filter(item => item !== undefined);
623
+ tmpMedias.forEach(id => {
624
+ delete this._context.tmpMedias[containerId][id];
616
625
  });
626
+ this.mounted && this.setState({ tmpMedias: this.state.tmpMedias.filter(id => !tmpMedias.includes(id)) });
627
+ return ids;
617
628
  }
618
- }).then(response => {
619
- if (!response)
620
- return;
621
- if (response.status < 400) {
622
- return response.json();
623
- }
624
- else if (response.status === 400) {
625
- fail("InvalidFile");
626
- }
627
- else if (response.status === 503) {
628
- fail("InsufficientSpace");
629
- }
630
- else {
631
- fail(["SomethingWentWrong", "TryAgainLater"]);
632
- }
633
- }).then(response => {
634
- if (!response)
635
- return;
636
- return this.getMetadataPromise().then(mediaMetadata => {
637
- return Promise.all(response.map((item) => {
638
- return this.apiClient.fetchRaw(`/${this.ENDPOINT}/${item.id}`, undefined, {
639
- method: "POST",
640
- headers: {
641
- "accept": "application/json",
642
- "content-type": "application/json"
643
- },
644
- body: JSON.stringify(mediaMetadata)
645
- }).then(response => {
646
- if (response.status < 400) {
647
- return response.json();
648
- }
649
- });
650
- }));
651
- });
652
- }).then(response => {
653
- if (!response)
654
- return;
655
- const ids = response.map((item) => item ? item.id : undefined).filter(item => item !== undefined);
656
- tmpMedias.forEach(id => {
657
- delete this._context.tmpMedias[containerId][id];
658
- });
659
- this.mounted && this.setState({ tmpMedias: this.state.tmpMedias.filter(id => !tmpMedias.includes(id)) });
660
- return ids;
661
- }).catch((e) => {
662
- if (tmpMedias) {
629
+ catch (e) {
663
630
  tmpMedias.forEach(id => {
664
631
  delete this._context.tmpMedias[containerId][id];
665
632
  });
666
633
  this.mounted && this.setState({ tmpMedias: this.state.tmpMedias.filter(id => !tmpMedias.includes(id)) });
634
+ throw e;
667
635
  }
668
- throw e;
669
636
  });
670
637
  }
671
638
  };
@@ -706,15 +673,18 @@ function MediaArrayField(ComposedComponent) {
706
673
  class Thumbnail extends React.PureComponent {
707
674
  constructor(props) {
708
675
  super(props);
709
- this.updateURL = ({ id, apiClient, apiEndpoint = "images" }) => {
676
+ this.updateURL = (_a) => __awaiter(this, [_a], void 0, function* ({ id, apiClient, apiEndpoint = "images" }) {
710
677
  if (!id)
711
678
  return;
712
- apiClient.fetchCached(`/${apiEndpoint}/${id}`, undefined, { failSilently: true }).then((response) => {
679
+ try {
680
+ const response = yield apiClient.get(`/${apiEndpoint}/{id}`, { path: { id } });
713
681
  if (!this.mounted)
714
682
  return;
715
683
  this.setState({ url: response.squareThumbnailURL, linkUrl: response.originalURL });
716
- });
717
- };
684
+ }
685
+ catch (e) {
686
+ }
687
+ });
718
688
  this.state = {};
719
689
  this.updateURL(props);
720
690
  }
@@ -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)
@@ -1053,7 +1062,7 @@ function _MapArrayField(ComposedComponent) {
1053
1062
  constructor(props) {
1054
1063
  super(props);
1055
1064
  this.stretchContainerRef = React.createRef();
1056
- this.geocode = () => {
1065
+ this.geocode = () => __awaiter(this, void 0, void 0, function* () {
1057
1066
  // Zoom map to area. Area ID is accessed from schema field defined in options.areaField
1058
1067
  const item = (this.props.formData || [])[this.state.activeIdx];
1059
1068
  const { areaField } = (0, utils_2.getUiOptions)(this.props.uiSchema);
@@ -1066,11 +1075,10 @@ function _MapArrayField(ComposedComponent) {
1066
1075
  }
1067
1076
  const geometries = this.getGeometries();
1068
1077
  if (geometries.length === 0 && area && area.length > 0) {
1069
- this.props.formContext.apiClient.fetch(`/areas/${area}`, undefined, undefined).then((result) => {
1070
- this.map.geocode(result.name, undefined, 8);
1071
- });
1078
+ const { name } = yield this.props.formContext.apiClient.get(`/areas/${area}`);
1079
+ this.map.geocode(name, undefined, 8);
1072
1080
  }
1073
- };
1081
+ });
1074
1082
  this.computeArea = () => {
1075
1083
  const { activeIdx } = this.state;
1076
1084
  if (activeIdx === undefined)
@@ -36,7 +36,7 @@ export default class MapField extends React.Component<any, any, any> {
36
36
  componentDidUpdate(prevProps: any): void;
37
37
  _lastFormData: any;
38
38
  _zoomToDataOnNextTick: boolean | undefined;
39
- geocode: (prevProps: any) => void;
39
+ geocode: (prevProps: any) => Promise<void>;
40
40
  zoomIfExternalEdit: (props: any) => void;
41
41
  setMapRef: (mapComponent: any) => void;
42
42
  map: any;
@@ -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 __rest = (this && this.__rest) || function (s, e) {
36
45
  var t = {};
37
46
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
@@ -107,7 +116,7 @@ class MapField extends React.Component {
107
116
  this.setState({ locateOn: true });
108
117
  }
109
118
  };
110
- this.geocode = (prevProps) => {
119
+ this.geocode = (prevProps) => __awaiter(this, void 0, void 0, function* () {
111
120
  let { area } = (0, utils_1.getUiOptions)(this.props.uiSchema);
112
121
  if (area instanceof Array) {
113
122
  area = area[0];
@@ -120,11 +129,10 @@ class MapField extends React.Component {
120
129
  || (geoData.type === "FeatureCollection" && geoData.features.length === 0);
121
130
  });
122
131
  if (isEmptyAndWasEmpty && area && area.length > 0) {
123
- this.props.formContext.apiClient.fetch(`/areas/${area}`, undefined, undefined).then((result) => {
124
- this.map.geocode(result.name, undefined, 8);
125
- });
132
+ const { name } = yield this.props.formContext.apiClient.get(`/areas/${area}`);
133
+ this.map.geocode(name, undefined, 8);
126
134
  }
127
- };
135
+ });
128
136
  this.zoomIfExternalEdit = (props) => {
129
137
  if (!equals(this._lastFormData, props.formData)) {
130
138
  this.map.zoomToData();
@@ -1,7 +1,8 @@
1
1
  import * as React from "react";
2
2
  import { ByLang, FormContext } from "../../LajiForm";
3
- import { NamedPlace } from "@luomus/laji-schema";
4
3
  import memoize from "memoizee";
4
+ import type { components } from "generated/api.d";
5
+ type NamedPlace = components["schemas"]["namedPlace"];
5
6
  type Props = {
6
7
  places: NamedPlace[];
7
8
  failed?: boolean;
@@ -1,6 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { FieldProps, JSONSchemaArray, JSONSchemaObject } from "../../../types";
3
- import { NamedPlace } from "@luomus/laji-schema";
3
+ import type { components } from "generated/api.d";
4
+ type NamedPlace = components["schemas"]["namedPlace"];
4
5
  type Props = FieldProps<NamedPlace, JSONSchemaObject | JSONSchemaArray<JSONSchemaObject>>;
5
6
  type State = {
6
7
  show?: boolean;
@@ -11,7 +12,6 @@ type State = {
11
12
  /** Compatible only with gatherings array and gathering object */
12
13
  export default class NamedPlaceChooserField extends React.Component<Props, State> {
13
14
  static contextType: React.Context<import("../../../ReactContext").ContextProps>;
14
- removeIds: Record<string, boolean>;
15
15
  mounted: boolean;
16
16
  state: State;
17
17
  getUiSchema: (props: Props, buttonDefinition: any) => import("../../../types").UiSchema<any> | {
@@ -60,9 +60,14 @@ export default class NamedPlaceChooserField extends React.Component<Props, State
60
60
  };
61
61
  isGatheringsArray: (schema: JSONSchemaObject | JSONSchemaArray<JSONSchemaObject>) => schema is JSONSchemaArray<JSONSchemaObject>;
62
62
  onPlaceSelected: (place: NamedPlace) => void;
63
- onPlaceDeleted: (place: NamedPlace, success: () => void) => void;
63
+ onPlaceDeleted: (place: NamedPlace & {
64
+ id: string;
65
+ }, end: () => void) => Promise<void>;
64
66
  onButtonClick: () => () => void;
65
- updatePlaces: () => void;
67
+ updatePlaces: (response: {
68
+ results: NamedPlace[];
69
+ }) => void;
70
+ getNamedPlacesUnsubscribe: () => void;
66
71
  componentDidMount(): void;
67
72
  componentWillUnmount(): void;
68
73
  onHide: () => void;
@@ -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 "";