@luomus/laji-form 15.1.119 → 15.1.121

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.
@@ -313,6 +313,7 @@ export default class LajiForm extends React.Component<LajiFormProps, LajiFormSta
313
313
  MultiActiveArrayField: typeof fields.MultiActiveArrayField;
314
314
  PrefixArrayField: typeof fields.PrefixArrayField;
315
315
  FillDateRangeField: typeof fields.FillDateRangeField;
316
+ TaxaByYearPopulatorField: typeof fields.TaxaByYearPopulatorField;
316
317
  TaxonSetPopulatorField: typeof fields.TaxonSetPopulatorField;
317
318
  ScientificNameTaxonAutosuggestField: typeof fields.ScientificNameTaxonAutosuggestField;
318
319
  ArraySchemaField: typeof fields.SchemaField;
@@ -487,7 +488,7 @@ export default class LajiForm extends React.Component<LajiFormProps, LajiFormSta
487
488
  addEventListener: (target: typeof document | typeof window, name: string, fn: (e: Event) => void) => void;
488
489
  setTimeout: (fn: () => void, time?: number) => number;
489
490
  destroy: () => void;
490
- getSchemaValidationErrors: (formData: any) => any;
491
+ getSchemaValidationErrors: (formData: any) => ErrorSchema;
491
492
  getFormDataReadyForSubmit: (formData: any, schema: JSONSchema) => {
492
493
  formData: any;
493
494
  removedArrayItemsAndObjects: string[];
@@ -377,7 +377,7 @@ class LajiForm extends React.Component {
377
377
  ignoreErrorPaths.forEach(path => {
378
378
  schemaErrors = (0, utils_1.immutableDelete)(schemaErrors, path);
379
379
  });
380
- return schemaErrors;
380
+ return removeEmptyErrorObjects(schemaErrors);
381
381
  };
382
382
  this.getFormDataReadyForSubmit = (formData, schema) => {
383
383
  formData = this.memoizedFormContext.services.ids.removeLajiFormIds(formData);
@@ -597,6 +597,21 @@ const removeEmptyValuesAndTrim = (formData, schema) => {
597
597
  return formData;
598
598
  }
599
599
  };
600
+ const removeEmptyErrorObjects = (errors) => {
601
+ const result = {};
602
+ for (const key of Object.keys(errors)) {
603
+ if (key === "__errors") {
604
+ result[key] = errors[key];
605
+ }
606
+ else if (errors[key]) {
607
+ const cleanedValue = removeEmptyErrorObjects(errors[key]);
608
+ if (Object.keys(cleanedValue).length > 0) {
609
+ result[key] = cleanedValue;
610
+ }
611
+ }
612
+ }
613
+ return Object.keys(result).length === 0 ? {} : result;
614
+ };
600
615
  const getShortcuts = (uiSchema) => {
601
616
  var _a, _b;
602
617
  if ((_b = (_a = window.navigator) === null || _a === void 0 ? void 0 : _a.platform) === null || _b === void 0 ? void 0 : _b.includes("Mac")) {
@@ -0,0 +1,45 @@
1
+ import * as React from "react";
2
+ import * as PropTypes from "prop-types";
3
+ import { FieldProps } from "../../types";
4
+ /**
5
+ * Watches a specified field which contains a year.
6
+ *
7
+ * Fetches taxa observed in the specified year and adds them to the units in formData.
8
+ *
9
+ * uiSchema = {
10
+ * "ui:field": "TaxaByYearPopulatorField",
11
+ * "ui:options": {
12
+ * "collectionID": "HR.6920", // Collection ID to fetch documents from
13
+ * "unitFilter": { // Filter for units from fetched documents
14
+ * "field": "observationStatus", // Field to filter on
15
+ * "valueIn": ["MY.observationStatusObservedNoCount", ...] // Allowed values
16
+ * }
17
+ * }
18
+ * }
19
+ */
20
+ export default class TaxaByYearPopulatorField extends React.Component<FieldProps> {
21
+ static propTypes: {
22
+ uiSchema: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
23
+ "ui:options": PropTypes.Requireable<PropTypes.InferProps<{
24
+ collectionID: PropTypes.Requireable<string>;
25
+ unitFilter: PropTypes.Requireable<PropTypes.InferProps<{
26
+ field: PropTypes.Validator<string>;
27
+ valueIn: PropTypes.Validator<(string | null | undefined)[]>;
28
+ }>>;
29
+ }>>;
30
+ uiSchema: PropTypes.Requireable<object>;
31
+ }>>>;
32
+ schema: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
33
+ type: PropTypes.Requireable<string>;
34
+ }>>>;
35
+ formData: PropTypes.Validator<object>;
36
+ };
37
+ static getName(): string;
38
+ getStateFromProps(): {
39
+ onChange: (formData: any) => Promise<void>;
40
+ };
41
+ componentDidMount(): Promise<void>;
42
+ onChange: (formData: any) => Promise<void>;
43
+ private populateTaxa;
44
+ private fetchTaxaFromNamedPlace;
45
+ }
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
51
+ return (mod && mod.__esModule) ? mod : { "default": mod };
52
+ };
53
+ Object.defineProperty(exports, "__esModule", { value: true });
54
+ const React = __importStar(require("react"));
55
+ const PropTypes = __importStar(require("prop-types"));
56
+ const VirtualSchemaField_1 = __importDefault(require("../VirtualSchemaField"));
57
+ const utils_1 = require("../../utils");
58
+ const unitFilterPropType = PropTypes.shape({
59
+ field: PropTypes.string.isRequired,
60
+ valueIn: PropTypes.arrayOf(PropTypes.string).isRequired
61
+ });
62
+ /**
63
+ * Watches a specified field which contains a year.
64
+ *
65
+ * Fetches taxa observed in the specified year and adds them to the units in formData.
66
+ *
67
+ * uiSchema = {
68
+ * "ui:field": "TaxaByYearPopulatorField",
69
+ * "ui:options": {
70
+ * "collectionID": "HR.6920", // Collection ID to fetch documents from
71
+ * "unitFilter": { // Filter for units from fetched documents
72
+ * "field": "observationStatus", // Field to filter on
73
+ * "valueIn": ["MY.observationStatusObservedNoCount", ...] // Allowed values
74
+ * }
75
+ * }
76
+ * }
77
+ */
78
+ let TaxaByYearPopulatorField = class TaxaByYearPopulatorField extends React.Component {
79
+ constructor() {
80
+ super(...arguments);
81
+ this.onChange = (formData) => __awaiter(this, void 0, void 0, function* () {
82
+ yield this.populateTaxa(formData);
83
+ });
84
+ }
85
+ static getName() {
86
+ return "TaxaByYearPopulatorField";
87
+ }
88
+ getStateFromProps() {
89
+ return { onChange: this.onChange };
90
+ }
91
+ componentDidMount() {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ yield this.populateTaxa(this.props.formData);
94
+ });
95
+ }
96
+ populateTaxa(formData) {
97
+ return __awaiter(this, void 0, void 0, function* () {
98
+ var _a, _b, _c, _d, _e, _f, _g;
99
+ if (!((_a = formData === null || formData === void 0 ? void 0 : formData.gatheringEvent) === null || _a === void 0 ? void 0 : _a.dateBegin)) {
100
+ this.props.onChange(formData);
101
+ return;
102
+ }
103
+ const { collectionID, unitFilter } = (0, utils_1.getUiOptions)(this.props.uiSchema);
104
+ const namedPlace = formData === null || formData === void 0 ? void 0 : formData.namedPlaceID;
105
+ const observationYear = Number((_c = (_b = formData === null || formData === void 0 ? void 0 : formData.gatheringEvent) === null || _b === void 0 ? void 0 : _b.dateBegin) === null || _c === void 0 ? void 0 : _c.split("-")[0]) || undefined;
106
+ const res = yield this.fetchTaxaFromNamedPlace(this.props, collectionID, namedPlace, observationYear);
107
+ let fetchedUnits = res.flatMap(doc => doc.gatherings.flatMap(g => g.units));
108
+ if ((unitFilter === null || unitFilter === void 0 ? void 0 : unitFilter.field) && (unitFilter === null || unitFilter === void 0 ? void 0 : unitFilter.valueIn)) {
109
+ fetchedUnits = fetchedUnits.filter((u) => u[unitFilter.field] && unitFilter.valueIn.includes(u[unitFilter.field]));
110
+ }
111
+ if (fetchedUnits.length === 0) {
112
+ this.props.onChange(formData);
113
+ return;
114
+ }
115
+ const seen = new Set();
116
+ const identifications = fetchedUnits.flatMap(u => u.identifications).filter(id => {
117
+ if (!id.taxonID || seen.has(id.taxonID))
118
+ return false;
119
+ seen.add(id.taxonID);
120
+ return true;
121
+ });
122
+ const tmpIdTree = this.props.formContext.services.ids.getRelativeTmpIdTree(this.props.idSchema.$id + "_units");
123
+ const formUnits = ((_e = (_d = formData.gatherings) === null || _d === void 0 ? void 0 : _d[0]) === null || _e === void 0 ? void 0 : _e.units)
124
+ ? [...formData.gatherings[0].units].filter((unit) => { var _a; return (_a = unit.unitFact) === null || _a === void 0 ? void 0 : _a.autocompleteSelectedTaxonID; })
125
+ : [];
126
+ identifications.forEach((identification) => {
127
+ if (!formUnits.some((u) => { var _a; return ((_a = u.unitFact) === null || _a === void 0 ? void 0 : _a.autocompleteSelectedTaxonID) === identification.taxonID; })) {
128
+ formUnits.push((0, utils_1.addLajiFormIds)({
129
+ identifications: [{
130
+ taxon: identification.taxonVerbatim
131
+ }],
132
+ unitFact: {
133
+ autocompleteSelectedTaxonID: identification.taxonID
134
+ }
135
+ }, tmpIdTree, false)[0]);
136
+ }
137
+ });
138
+ this.props.onChange(Object.assign(Object.assign({}, formData), { gatherings: [
139
+ Object.assign(Object.assign({}, (((_f = formData.gatherings) === null || _f === void 0 ? void 0 : _f[0]) || {})), { units: formUnits }),
140
+ ...(((_g = formData.gatherings) === null || _g === void 0 ? void 0 : _g.slice(1)) || [])
141
+ ] }));
142
+ return;
143
+ });
144
+ }
145
+ fetchTaxaFromNamedPlace(props, collectionID, namedPlace, observationYear) {
146
+ return __awaiter(this, void 0, void 0, function* () {
147
+ var _a;
148
+ const apiClient = (_a = props.formContext) === null || _a === void 0 ? void 0 : _a.apiClient;
149
+ if (!apiClient) {
150
+ return [];
151
+ }
152
+ try {
153
+ const response = yield apiClient.get("/documents", {
154
+ query: {
155
+ collectionID,
156
+ namedPlace,
157
+ observationYear,
158
+ selfAsEditorOrCreator: true,
159
+ pageSize: 1000,
160
+ page: 1
161
+ }
162
+ });
163
+ if (!response.results || !Array.isArray(response.results)) {
164
+ return [];
165
+ }
166
+ return response.results;
167
+ }
168
+ catch (error) {
169
+ return [];
170
+ }
171
+ });
172
+ }
173
+ };
174
+ TaxaByYearPopulatorField.propTypes = {
175
+ uiSchema: PropTypes.shape({
176
+ "ui:options": PropTypes.shape({
177
+ collectionID: PropTypes.string,
178
+ unitFilter: unitFilterPropType
179
+ }),
180
+ uiSchema: PropTypes.object
181
+ }).isRequired,
182
+ schema: PropTypes.shape({
183
+ type: PropTypes.oneOf(["array", "object"])
184
+ }).isRequired,
185
+ formData: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired
186
+ };
187
+ TaxaByYearPopulatorField = __decorate([
188
+ VirtualSchemaField_1.default
189
+ ], TaxaByYearPopulatorField);
190
+ exports.default = TaxaByYearPopulatorField;
@@ -54,7 +54,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
54
54
  const React = __importStar(require("react"));
55
55
  const PropTypes = __importStar(require("prop-types"));
56
56
  const VirtualSchemaField_1 = __importDefault(require("../VirtualSchemaField"));
57
- const utils_1 = require("../..//utils");
57
+ const utils_1 = require("../../utils");
58
58
  const propsPropType = PropTypes.shape({
59
59
  from: PropTypes.string.isRequired,
60
60
  fromArrayKey: PropTypes.string,
@@ -67,6 +67,7 @@ export { default as CondensedObjectField } from "./CondensedObjectField";
67
67
  export { default as MultiActiveArrayField } from "./MultiActiveArrayField";
68
68
  export { default as PrefixArrayField } from "./PrefixArrayField";
69
69
  export { default as FillDateRangeField } from "./FillDateRangeField";
70
+ export { default as TaxaByYearPopulatorField } from "./TaxaByYearPopulatorField";
70
71
  export { default as TaxonSetPopulatorField } from "./TaxonSetPopulatorField";
71
72
  export { default as ScientificNameTaxonAutosuggestField } from "./ScientificNameTaxonAutosuggestField";
72
73
  export { default as ArraySchemaField } from "./SchemaField";
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.FakePropertyField = exports.ImageDisplayField = exports.LocalityField = exports.DataLeakerField = exports.LocationChooserField = exports.UnitListShorthandArrayField = exports.EnumRangeArrayField = exports.AnyToBooleanField = exports.PrefillingArrayField = exports.AnnotationField = exports.ConditionalUiSchemaField = exports.ConditionalOnChangeField = exports.StringToArrayField = exports.TagArrayField = exports.GeocoderField = exports.MapField = exports.NamedPlaceSaverField = exports.NamedPlaceChooserField = exports.SumField = exports.ExtraLabelRowField = exports.UiFieldMapperArrayField = exports.CombinedValueDisplayField = exports.UnitShorthandField = exports.SingleItemArrayField = exports.SingleActiveArrayField = exports.FlatField = exports.SplitField = exports.ImageArrayField = exports.ContextInjectionField = exports.InitiallyHiddenField = exports.HiddenWithTextField = exports.HiddenField = exports.AutosuggestField = exports.AutoArrayField = exports.MapArrayField = exports.DependentDisableField = exports.DependentBooleanField = exports.ArrayCombinerField = exports.InjectDefaultValueField = exports.InjectField = exports.TableField = exports.GridLayoutField = exports.SelectTreeField = exports.ScopeField = exports.ArrayPropertyCountField = exports.ArrayPropertySumField = exports.NestField = exports.ObjectField = exports.ArrayField = exports.SchemaField = void 0;
7
- exports.AccordionArrayField = exports.UnitRapidField = exports.ConditionalField = exports.InputTransformerField = exports.ArraySchemaField = exports.ScientificNameTaxonAutosuggestField = exports.TaxonSetPopulatorField = exports.FillDateRangeField = exports.PrefixArrayField = exports.MultiActiveArrayField = exports.CondensedObjectField = exports.AsArrayField = exports.PdfArrayField = exports.MultiTagArrayField = exports.InputWithDefaultValueButtonField = exports.SortArrayField = exports.MultiLanguageField = exports.UiFieldApplierField = exports.DefaultValueArrayField = exports.ToggleAdditionalArrayFieldsField = exports.UnitCountShorthandField = exports.MultiAnyToBooleanField = exports.FilterArrayField = exports.AudioArrayField = exports.MultiArrayField = exports.SectionArrayField = void 0;
7
+ exports.AccordionArrayField = exports.UnitRapidField = exports.ConditionalField = exports.InputTransformerField = exports.ArraySchemaField = exports.ScientificNameTaxonAutosuggestField = exports.TaxonSetPopulatorField = exports.TaxaByYearPopulatorField = exports.FillDateRangeField = exports.PrefixArrayField = exports.MultiActiveArrayField = exports.CondensedObjectField = exports.AsArrayField = exports.PdfArrayField = exports.MultiTagArrayField = exports.InputWithDefaultValueButtonField = exports.SortArrayField = exports.MultiLanguageField = exports.UiFieldApplierField = exports.DefaultValueArrayField = exports.ToggleAdditionalArrayFieldsField = exports.UnitCountShorthandField = exports.MultiAnyToBooleanField = exports.FilterArrayField = exports.AudioArrayField = exports.MultiArrayField = exports.SectionArrayField = void 0;
8
8
  var SchemaField_1 = require("./SchemaField");
9
9
  Object.defineProperty(exports, "SchemaField", { enumerable: true, get: function () { return __importDefault(SchemaField_1).default; } });
10
10
  var ArrayField_1 = require("./ArrayField");
@@ -143,6 +143,8 @@ var PrefixArrayField_1 = require("./PrefixArrayField");
143
143
  Object.defineProperty(exports, "PrefixArrayField", { enumerable: true, get: function () { return __importDefault(PrefixArrayField_1).default; } });
144
144
  var FillDateRangeField_1 = require("./FillDateRangeField");
145
145
  Object.defineProperty(exports, "FillDateRangeField", { enumerable: true, get: function () { return __importDefault(FillDateRangeField_1).default; } });
146
+ var TaxaByYearPopulatorField_1 = require("./TaxaByYearPopulatorField");
147
+ Object.defineProperty(exports, "TaxaByYearPopulatorField", { enumerable: true, get: function () { return __importDefault(TaxaByYearPopulatorField_1).default; } });
146
148
  var TaxonSetPopulatorField_1 = require("./TaxonSetPopulatorField");
147
149
  Object.defineProperty(exports, "TaxonSetPopulatorField", { enumerable: true, get: function () { return __importDefault(TaxonSetPopulatorField_1).default; } });
148
150
  var ScientificNameTaxonAutosuggestField_1 = require("./ScientificNameTaxonAutosuggestField");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luomus/laji-form",
3
- "version": "15.1.119",
3
+ "version": "15.1.121",
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",
@@ -268,4 +268,5 @@ export declare const maybeJSONPointerToLocator: (pointer: string) => string;
268
268
  /** Fills value into given input and presses tab to unfocus it. Useful for inputs with debounce */
269
269
  export declare const updateValue: ($input: Locator, value: string) => Promise<void>;
270
270
  export declare const getRemoveUnit: (page: Page) => (gatheringIdx: number, unitIdx: number) => Promise<void>;
271
+ export declare const getRemoveIdentification: (page: Page) => (gatheringIdx: number, unitIdx: number, identificationIdx: number) => Promise<void>;
271
272
  export {};
@@ -53,7 +53,7 @@ var __rest = (this && this.__rest) || function (s, e) {
53
53
  return t;
54
54
  };
55
55
  Object.defineProperty(exports, "__esModule", { value: true });
56
- exports.getRemoveUnit = exports.updateValue = exports.maybeJSONPointerToLocator = exports.filterUUIDs = exports.mockImageMetadata = exports.DemoPageForm = exports.Form = exports.getFocusedId = exports.getFocusedElement = exports.lajiFormLocate = exports.lajiFormLocator = exports.navigateToForm = exports.emptyForm = void 0;
56
+ exports.getRemoveIdentification = exports.getRemoveUnit = exports.updateValue = exports.maybeJSONPointerToLocator = exports.filterUUIDs = exports.mockImageMetadata = exports.DemoPageForm = exports.Form = exports.getFocusedId = exports.getFocusedElement = exports.lajiFormLocate = exports.lajiFormLocator = exports.navigateToForm = exports.emptyForm = void 0;
57
57
  exports.createForm = createForm;
58
58
  const path = __importStar(require("path"));
59
59
  const test_utils_1 = require("@luomus/laji-map/test-export/test-utils");
@@ -415,3 +415,8 @@ const getRemoveUnit = (page) => (gatheringIdx, unitIdx) => __awaiter(void 0, voi
415
415
  return page.locator(`#root_gatherings_${gatheringIdx}_units_${unitIdx}-delete-confirm-yes`).click();
416
416
  });
417
417
  exports.getRemoveUnit = getRemoveUnit;
418
+ const getRemoveIdentification = (page) => (gatheringIdx, unitIdx, identificationIdx) => __awaiter(void 0, void 0, void 0, function* () {
419
+ yield page.locator(`#root_gatherings_${gatheringIdx}_units_${unitIdx}_identifications_${identificationIdx}-delete`).click();
420
+ return page.locator(`#root_gatherings_${gatheringIdx}_units_${unitIdx}_identifications_${identificationIdx}-delete-confirm-yes`).click();
421
+ });
422
+ exports.getRemoveIdentification = getRemoveIdentification;