@luomus/laji-form 15.1.67 → 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 -64
- package/lib/ApiClient.js +68 -172
- 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 -52
- 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 +5 -5
- 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
|
@@ -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)
|
|
@@ -171,7 +162,7 @@ function MediaArrayField(ComposedComponent) {
|
|
|
171
162
|
const item = this.props.formData[i];
|
|
172
163
|
this.setState({ metadataModalOpen: i });
|
|
173
164
|
this.fetching = item;
|
|
174
|
-
this.apiClient.
|
|
165
|
+
this.apiClient.fetch(`/${this.ENDPOINT}/${item}`).then((response) => {
|
|
175
166
|
if (response.id !== this.fetching)
|
|
176
167
|
return;
|
|
177
168
|
this._context.metadatas[item] = response;
|
|
@@ -181,11 +172,10 @@ function MediaArrayField(ComposedComponent) {
|
|
|
181
172
|
this.onMediaRmClick = (i) => () => {
|
|
182
173
|
const id = this.props.formData[i];
|
|
183
174
|
this.props.onChange((0, immutability_helper_1.default)(this.props.formData, { $splice: [[i, 1]] }));
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
175
|
+
this.apiClient.fetch(`/${this.ENDPOINT}/${id}`, undefined, {
|
|
176
|
+
method: "DELETE",
|
|
177
|
+
failSilently: true
|
|
178
|
+
});
|
|
189
179
|
};
|
|
190
180
|
this.hideMetadataModal = () => this.setState({ metadataModalOpen: false, metadataSaveSuccess: undefined });
|
|
191
181
|
this.onMetadataFormChange = (formData) => this.setState({ modalMetadata: formData });
|
|
@@ -195,7 +185,7 @@ function MediaArrayField(ComposedComponent) {
|
|
|
195
185
|
const metadataForm = this.state.metadataForm || {};
|
|
196
186
|
if (typeof metadataModalOpen === "number" && !this.state.metadataForm) {
|
|
197
187
|
const { metadataFormId = this.METADATA_FORM_ID } = (0, utils_1.getUiOptions)(this.props.uiSchema);
|
|
198
|
-
this.apiClient.
|
|
188
|
+
this.apiClient.fetchCached(`/forms/${metadataFormId}`, { lang, format: "schema" })
|
|
199
189
|
.then(metadataForm => {
|
|
200
190
|
if (this.mounted) {
|
|
201
191
|
this.setState({ metadataForm });
|
|
@@ -432,10 +422,16 @@ function MediaArrayField(ComposedComponent) {
|
|
|
432
422
|
reader.readAsDataURL(file);
|
|
433
423
|
});
|
|
434
424
|
};
|
|
435
|
-
this.onMediaMetadataUpdate = (
|
|
425
|
+
this.onMediaMetadataUpdate = ({ formData }) => {
|
|
436
426
|
this.props.formContext.services.blocker.push();
|
|
437
|
-
|
|
438
|
-
|
|
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(() => {
|
|
439
435
|
this.props.formContext.services.blocker.pop();
|
|
440
436
|
const notify = () => this.props.formContext.notifier.success(this.props.formContext.translations.SaveSuccess);
|
|
441
437
|
if (this.mounted) {
|
|
@@ -444,12 +440,11 @@ function MediaArrayField(ComposedComponent) {
|
|
|
444
440
|
else {
|
|
445
441
|
notify();
|
|
446
442
|
}
|
|
447
|
-
}
|
|
448
|
-
catch (e) {
|
|
443
|
+
}).catch(() => {
|
|
449
444
|
this.props.formContext.services.blocker.pop();
|
|
450
445
|
this.mounted && this.setState({ metadataSaveSuccess: false });
|
|
451
|
-
}
|
|
452
|
-
}
|
|
446
|
+
});
|
|
447
|
+
};
|
|
453
448
|
this.getMetadataPromise = () => {
|
|
454
449
|
let mediaMetadata = this.props.formContext.mediaMetadata
|
|
455
450
|
|| { intellectualRights: "MZ.intellectualRightsARR" };
|
|
@@ -457,7 +452,7 @@ function MediaArrayField(ComposedComponent) {
|
|
|
457
452
|
return ("capturerVerbatim" in mediaMetadata)
|
|
458
453
|
? Promise.resolve(Object.assign(Object.assign({}, mediaMetadata), { capturerVerbatim: [mediaMetadata.capturerVerbatim] }))
|
|
459
454
|
: MACode
|
|
460
|
-
? this.apiClient.
|
|
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))
|
|
461
456
|
: mediaMetadata;
|
|
462
457
|
};
|
|
463
458
|
this.getMaxFileSizeAsString = () => {
|
|
@@ -572,67 +567,105 @@ function MediaArrayField(ComposedComponent) {
|
|
|
572
567
|
this.renderMediaAddModal()))));
|
|
573
568
|
}
|
|
574
569
|
saveMedias(files) {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
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;
|
|
591
594
|
}
|
|
592
|
-
|
|
593
|
-
|
|
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;
|
|
595
|
+
else if (file.size > this.MAX_FILE_SIZE) {
|
|
596
|
+
fileTooLarge = true;
|
|
614
597
|
}
|
|
615
|
-
else
|
|
616
|
-
|
|
617
|
-
|
|
598
|
+
else {
|
|
599
|
+
body.append("data", file);
|
|
600
|
+
noValidData = false;
|
|
618
601
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
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
|
|
625
616
|
});
|
|
626
|
-
this.mounted && this.setState({ tmpMedias: this.state.tmpMedias.filter(id => !tmpMedias.includes(id)) });
|
|
627
|
-
return ids;
|
|
628
617
|
}
|
|
629
|
-
|
|
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) {
|
|
630
663
|
tmpMedias.forEach(id => {
|
|
631
664
|
delete this._context.tmpMedias[containerId][id];
|
|
632
665
|
});
|
|
633
666
|
this.mounted && this.setState({ tmpMedias: this.state.tmpMedias.filter(id => !tmpMedias.includes(id)) });
|
|
634
|
-
throw e;
|
|
635
667
|
}
|
|
668
|
+
throw e;
|
|
636
669
|
});
|
|
637
670
|
}
|
|
638
671
|
};
|
|
@@ -673,18 +706,15 @@ function MediaArrayField(ComposedComponent) {
|
|
|
673
706
|
class Thumbnail extends React.PureComponent {
|
|
674
707
|
constructor(props) {
|
|
675
708
|
super(props);
|
|
676
|
-
this.updateURL = (
|
|
709
|
+
this.updateURL = ({ id, apiClient, apiEndpoint = "images" }) => {
|
|
677
710
|
if (!id)
|
|
678
711
|
return;
|
|
679
|
-
|
|
680
|
-
const response = yield apiClient.get(`/${apiEndpoint}/{id}`, { path: { id } });
|
|
712
|
+
apiClient.fetchCached(`/${apiEndpoint}/${id}`, undefined, { failSilently: true }).then((response) => {
|
|
681
713
|
if (!this.mounted)
|
|
682
714
|
return;
|
|
683
715
|
this.setState({ url: response.squareThumbnailURL, linkUrl: response.originalURL });
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
}
|
|
687
|
-
});
|
|
716
|
+
});
|
|
717
|
+
};
|
|
688
718
|
this.state = {};
|
|
689
719
|
this.updateURL(props);
|
|
690
720
|
}
|
|
@@ -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)
|
|
@@ -1062,7 +1053,7 @@ function _MapArrayField(ComposedComponent) {
|
|
|
1062
1053
|
constructor(props) {
|
|
1063
1054
|
super(props);
|
|
1064
1055
|
this.stretchContainerRef = React.createRef();
|
|
1065
|
-
this.geocode = () =>
|
|
1056
|
+
this.geocode = () => {
|
|
1066
1057
|
// Zoom map to area. Area ID is accessed from schema field defined in options.areaField
|
|
1067
1058
|
const item = (this.props.formData || [])[this.state.activeIdx];
|
|
1068
1059
|
const { areaField } = (0, utils_2.getUiOptions)(this.props.uiSchema);
|
|
@@ -1075,10 +1066,11 @@ function _MapArrayField(ComposedComponent) {
|
|
|
1075
1066
|
}
|
|
1076
1067
|
const geometries = this.getGeometries();
|
|
1077
1068
|
if (geometries.length === 0 && area && area.length > 0) {
|
|
1078
|
-
|
|
1079
|
-
|
|
1069
|
+
this.props.formContext.apiClient.fetch(`/areas/${area}`, undefined, undefined).then((result) => {
|
|
1070
|
+
this.map.geocode(result.name, undefined, 8);
|
|
1071
|
+
});
|
|
1080
1072
|
}
|
|
1081
|
-
}
|
|
1073
|
+
};
|
|
1082
1074
|
this.computeArea = () => {
|
|
1083
1075
|
const { activeIdx } = this.state;
|
|
1084
1076
|
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) =>
|
|
39
|
+
geocode: (prevProps: any) => void;
|
|
40
40
|
zoomIfExternalEdit: (props: any) => void;
|
|
41
41
|
setMapRef: (mapComponent: any) => void;
|
|
42
42
|
map: any;
|
|
@@ -32,15 +32,6 @@ 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
|
-
};
|
|
44
35
|
var __rest = (this && this.__rest) || function (s, e) {
|
|
45
36
|
var t = {};
|
|
46
37
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
@@ -116,7 +107,7 @@ class MapField extends React.Component {
|
|
|
116
107
|
this.setState({ locateOn: true });
|
|
117
108
|
}
|
|
118
109
|
};
|
|
119
|
-
this.geocode = (prevProps) =>
|
|
110
|
+
this.geocode = (prevProps) => {
|
|
120
111
|
let { area } = (0, utils_1.getUiOptions)(this.props.uiSchema);
|
|
121
112
|
if (area instanceof Array) {
|
|
122
113
|
area = area[0];
|
|
@@ -129,10 +120,11 @@ class MapField extends React.Component {
|
|
|
129
120
|
|| (geoData.type === "FeatureCollection" && geoData.features.length === 0);
|
|
130
121
|
});
|
|
131
122
|
if (isEmptyAndWasEmpty && area && area.length > 0) {
|
|
132
|
-
|
|
133
|
-
|
|
123
|
+
this.props.formContext.apiClient.fetch(`/areas/${area}`, undefined, undefined).then((result) => {
|
|
124
|
+
this.map.geocode(result.name, undefined, 8);
|
|
125
|
+
});
|
|
134
126
|
}
|
|
135
|
-
}
|
|
127
|
+
};
|
|
136
128
|
this.zoomIfExternalEdit = (props) => {
|
|
137
129
|
if (!equals(this._lastFormData, props.formData)) {
|
|
138
130
|
this.map.zoomToData();
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { ByLang, FormContext } from "../../LajiForm";
|
|
3
|
+
import { NamedPlace } from "@luomus/laji-schema";
|
|
3
4
|
import memoize from "memoizee";
|
|
4
|
-
import type { components } from "generated/api.d";
|
|
5
|
-
type NamedPlace = components["schemas"]["namedPlace"];
|
|
6
5
|
type Props = {
|
|
7
6
|
places: NamedPlace[];
|
|
8
7
|
failed?: boolean;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { FieldProps, JSONSchemaArray, JSONSchemaObject } from "../../../types";
|
|
3
|
-
import
|
|
4
|
-
type NamedPlace = components["schemas"]["namedPlace"];
|
|
3
|
+
import { NamedPlace } from "@luomus/laji-schema";
|
|
5
4
|
type Props = FieldProps<NamedPlace, JSONSchemaObject | JSONSchemaArray<JSONSchemaObject>>;
|
|
6
5
|
type State = {
|
|
7
6
|
show?: boolean;
|
|
@@ -12,6 +11,7 @@ type State = {
|
|
|
12
11
|
/** Compatible only with gatherings array and gathering object */
|
|
13
12
|
export default class NamedPlaceChooserField extends React.Component<Props, State> {
|
|
14
13
|
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,14 +60,9 @@ 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
|
|
64
|
-
id: string;
|
|
65
|
-
}, end: () => void) => Promise<void>;
|
|
63
|
+
onPlaceDeleted: (place: NamedPlace, success: () => void) => void;
|
|
66
64
|
onButtonClick: () => () => void;
|
|
67
|
-
updatePlaces: (
|
|
68
|
-
results: NamedPlace[];
|
|
69
|
-
}) => void;
|
|
70
|
-
getNamedPlacesUnsubscribe: () => void;
|
|
65
|
+
updatePlaces: () => void;
|
|
71
66
|
componentDidMount(): void;
|
|
72
67
|
componentWillUnmount(): void;
|
|
73
68
|
onHide: () => void;
|
|
@@ -32,15 +32,6 @@ 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
|
-
};
|
|
44
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
45
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
37
|
};
|
|
@@ -48,7 +39,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
48
39
|
const React = __importStar(require("react"));
|
|
49
40
|
const ReactContext_1 = __importDefault(require("../../../ReactContext"));
|
|
50
41
|
const utils_1 = require("../../../utils");
|
|
51
|
-
// import { NamedPlace } from "@luomus/laji-schema";
|
|
52
42
|
const Context_1 = __importDefault(require("../../../Context"));
|
|
53
43
|
const NamedPlaceChooser_1 = require("./NamedPlaceChooser");
|
|
54
44
|
const PLACE_WHITELIST = [
|
|
@@ -69,6 +59,7 @@ const PLACE_DELETE_FAIL = "PLACE_DELETE_FAIL";
|
|
|
69
59
|
class NamedPlaceChooserField extends React.Component {
|
|
70
60
|
constructor() {
|
|
71
61
|
super(...arguments);
|
|
62
|
+
this.removeIds = {};
|
|
72
63
|
this.mounted = false;
|
|
73
64
|
this.state = {};
|
|
74
65
|
this.getUiSchema = (props, buttonDefinition) => {
|
|
@@ -131,61 +122,69 @@ class NamedPlaceChooserField extends React.Component {
|
|
|
131
122
|
this.setState({ failed: PLACE_USE_FAIL });
|
|
132
123
|
}
|
|
133
124
|
};
|
|
134
|
-
this.onPlaceDeleted = (place,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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(() => {
|
|
140
135
|
this.setState({ failed: PLACE_DELETE_FAIL });
|
|
141
136
|
this.props.formContext.notifier.error(this.props.formContext.translations.PlaceRemovalFailed);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
});
|
|
137
|
+
});
|
|
138
|
+
};
|
|
145
139
|
this.onButtonClick = () => () => {
|
|
146
140
|
this.setState({ show: true });
|
|
147
141
|
};
|
|
148
|
-
this.updatePlaces = (
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
+
});
|
|
179
177
|
};
|
|
180
178
|
this.onHide = () => this.setState({ show: false });
|
|
181
179
|
}
|
|
182
180
|
componentDidMount() {
|
|
183
181
|
this.mounted = true;
|
|
184
|
-
this.
|
|
182
|
+
this.updatePlaces();
|
|
183
|
+
this.props.formContext.apiClient.onCachePathInvalidation("/named-places", this.updatePlaces);
|
|
185
184
|
}
|
|
186
185
|
componentWillUnmount() {
|
|
187
186
|
this.mounted = false;
|
|
188
|
-
this.
|
|
187
|
+
this.props.formContext.apiClient.removeOnCachePathInvalidation("/named-places", this.updatePlaces);
|
|
189
188
|
}
|
|
190
189
|
render() {
|
|
191
190
|
const { registry: { fields: { SchemaField } }, formContext } = this.props;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { NamedPlace } from "@luomus/laji-schema";
|
|
2
3
|
import { FormContext } from "src/components/LajiForm";
|
|
3
|
-
import type { components } from "generated/api.d";
|
|
4
|
-
type NamedPlace = components["schemas"]["namedPlace"];
|
|
5
4
|
type Props = {
|
|
6
5
|
onPlaceSelected: (place: NamedPlace) => void;
|
|
7
6
|
onPlaceDeleted: (place: NamedPlace) => void;
|
|
@@ -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)
|
|
@@ -191,7 +182,7 @@ class PlaceSaverDialog extends React.Component {
|
|
|
191
182
|
}
|
|
192
183
|
componentDidMount() {
|
|
193
184
|
this.mounted = true;
|
|
194
|
-
this.apiClient.
|
|
185
|
+
this.apiClient.fetchCached("/named-places", { includePublic: false, pageSize: 1000 }).then(response => {
|
|
195
186
|
if (!this.mounted)
|
|
196
187
|
return;
|
|
197
188
|
const state = {
|
|
@@ -222,18 +213,23 @@ class PlaceSaverDialog extends React.Component {
|
|
|
222
213
|
});
|
|
223
214
|
}
|
|
224
215
|
onSave(place) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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 });
|
|
237
233
|
});
|
|
238
234
|
}
|
|
239
235
|
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.
|
|
53
|
+
return props.formContext.apiClient.fetchCached("/informal-taxon-groups/" + taxonGroup).then((response) => {
|
|
54
54
|
return response.name;
|
|
55
55
|
}).catch(() => {
|
|
56
56
|
return "";
|