@luomus/laji-form 15.1.90 → 15.1.92

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.
@@ -146,6 +146,7 @@ const fields = importLocalComponents("fields", [
146
146
  "MultiActiveArrayField",
147
147
  "PrefixArrayField",
148
148
  "FillDateRangeField",
149
+ "TaxonSetPopulatorField",
149
150
  "ScientificNameTaxonAutosuggestField",
150
151
  { "InputTransformerField": "ConditionalOnChangeField" }, // Alias for backward compatibility.
151
152
  { "ConditionalField": "ConditionalUiSchemaField" }, // Alias for backward compatibility.
@@ -22,6 +22,12 @@ export default class MultiAnyToBooleanField extends React.Component<any, any, an
22
22
  getInitialState(props: any): {
23
23
  groupsFormData: any[];
24
24
  };
25
+ getStateFromProps(props: any): {
26
+ groupsFormData: any[];
27
+ };
28
+ initializeGroups: (props: any) => {
29
+ groupsFormData: any[];
30
+ };
25
31
  onChange: (index: any) => (value: any) => void;
26
32
  render(): JSX.Element;
27
33
  }
@@ -62,6 +62,31 @@ const utils_2 = require("@rjsf/utils");
62
62
  let MultiAnyToBooleanField = class MultiAnyToBooleanField extends React.Component {
63
63
  constructor(props) {
64
64
  super(props);
65
+ this.initializeGroups = (props) => {
66
+ let { groups } = (0, utils_1.getUiOptions)(props.uiSchema) || [];
67
+ const { formData } = props;
68
+ const trueValues = groups.map(group => group.trueValue);
69
+ const falseValues = groups.map(group => group.falseValue);
70
+ const groupsFormData = [];
71
+ if (formData) {
72
+ formData.forEach(value => {
73
+ if (value === undefined) {
74
+ return;
75
+ }
76
+ const trueIndex = trueValues.findIndex(trueValue => props.formContext.utils.formDataEquals(value, trueValue, props.idSchema.$id));
77
+ if (trueIndex !== -1) {
78
+ groupsFormData[trueIndex] = value;
79
+ }
80
+ else {
81
+ const falseIndex = falseValues.findIndex(falseValue => props.formContext.utils.formDataEquals(value, falseValue, props.idSchema.$id));
82
+ if (falseIndex !== -1) {
83
+ groupsFormData[falseIndex] = value;
84
+ }
85
+ }
86
+ });
87
+ }
88
+ return { groupsFormData: groupsFormData };
89
+ };
65
90
  this.onChange = (index) => (value) => {
66
91
  const groupsFormData = this.state.groupsFormData;
67
92
  groupsFormData[index] = value;
@@ -77,29 +102,10 @@ let MultiAnyToBooleanField = class MultiAnyToBooleanField extends React.Componen
77
102
  this.state = this.getInitialState(props);
78
103
  }
79
104
  getInitialState(props) {
80
- let { groups } = (0, utils_1.getUiOptions)(props.uiSchema) || [];
81
- const { formData } = props;
82
- const trueValues = groups.map(group => group.trueValue);
83
- const falseValues = groups.map(group => group.falseValue);
84
- const groupsFormData = [];
85
- if (formData) {
86
- formData.forEach(value => {
87
- if (value === undefined) {
88
- return;
89
- }
90
- const trueIndex = trueValues.findIndex(trueValue => props.formContext.utils.formDataEquals(value, trueValue, props.idSchema.$id));
91
- if (trueIndex !== -1) {
92
- groupsFormData[trueIndex] = value;
93
- }
94
- else {
95
- const falseIndex = falseValues.findIndex(falseValue => props.formContext.utils.formDataEquals(value, falseValue, props.idSchema.$id));
96
- if (falseIndex !== -1) {
97
- groupsFormData[falseIndex] = value;
98
- }
99
- }
100
- });
101
- }
102
- return { groupsFormData: groupsFormData };
105
+ return this.initializeGroups(props);
106
+ }
107
+ getStateFromProps(props) {
108
+ return this.initializeGroups(props);
103
109
  }
104
110
  render() {
105
111
  const TitleFieldTemplate = (0, utils_2.getTemplate)("TitleFieldTemplate", this.props.registry, (0, utils_1.getUiOptions)(this.props.uiSchema));
@@ -0,0 +1,50 @@
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 taxon set IDs.
6
+ *
7
+ * When taxon set IDs are added, it fetches the taxa in those sets from the API and adds them to the units in formData.
8
+ *
9
+ * When taxon set IDs are removed, it removes any taxa belonging to those sets from the units in formData.
10
+ *
11
+ * uiSchema = {
12
+ * "ui:field": "TaxonSetPopulatorField",
13
+ * "ui:options": {
14
+ * "props": {
15
+ * "from": "taxonCensus", // Source object containing taxon set IDs
16
+ * "fromArrayKey": "censusTaxonSetID", // Field within source object containing the taxon set IDs
17
+ * "joinArray": true, // Join array of IDs into comma-separated string
18
+ * }
19
+ * }
20
+ * }
21
+ */
22
+ export default class TaxonSetPopulatorField extends React.Component<FieldProps> {
23
+ static propTypes: {
24
+ uiSchema: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
25
+ "ui:options": PropTypes.Requireable<PropTypes.InferProps<{
26
+ props: PropTypes.Requireable<NonNullable<PropTypes.InferProps<{
27
+ from: PropTypes.Validator<string>;
28
+ fromArrayKey: PropTypes.Requireable<string>;
29
+ joinArray: PropTypes.Requireable<boolean>;
30
+ }> | (PropTypes.InferProps<{
31
+ from: PropTypes.Validator<string>;
32
+ fromArrayKey: PropTypes.Requireable<string>;
33
+ joinArray: PropTypes.Requireable<boolean>;
34
+ }> | null | undefined)[] | null | undefined>>;
35
+ }>>;
36
+ uiSchema: PropTypes.Requireable<object>;
37
+ }>>>;
38
+ schema: PropTypes.Validator<NonNullable<PropTypes.InferProps<{
39
+ type: PropTypes.Requireable<string>;
40
+ }>>>;
41
+ formData: PropTypes.Validator<object>;
42
+ };
43
+ static getName(): string;
44
+ taxonSets: any[];
45
+ getStateFromProps(): {
46
+ onChange: (formData: any) => Promise<void>;
47
+ };
48
+ onChange: (formData: any) => Promise<void>;
49
+ private fetchTaxaFromSet;
50
+ }
@@ -0,0 +1,206 @@
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 propsPropType = PropTypes.shape({
58
+ from: PropTypes.string.isRequired,
59
+ fromArrayKey: PropTypes.string,
60
+ joinArray: PropTypes.bool,
61
+ });
62
+ /**
63
+ * Watches a specified field which contains taxon set IDs.
64
+ *
65
+ * When taxon set IDs are added, it fetches the taxa in those sets from the API and adds them to the units in formData.
66
+ *
67
+ * When taxon set IDs are removed, it removes any taxa belonging to those sets from the units in formData.
68
+ *
69
+ * uiSchema = {
70
+ * "ui:field": "TaxonSetPopulatorField",
71
+ * "ui:options": {
72
+ * "props": {
73
+ * "from": "taxonCensus", // Source object containing taxon set IDs
74
+ * "fromArrayKey": "censusTaxonSetID", // Field within source object containing the taxon set IDs
75
+ * "joinArray": true, // Join array of IDs into comma-separated string
76
+ * }
77
+ * }
78
+ * }
79
+ */
80
+ let TaxonSetPopulatorField = class TaxonSetPopulatorField extends React.Component {
81
+ constructor() {
82
+ super(...arguments);
83
+ this.taxonSets = [];
84
+ this.onChange = (formData) => __awaiter(this, void 0, void 0, function* () {
85
+ var _a, _b, _c;
86
+ const previousTaxonSets = this.taxonSets;
87
+ const currentTaxonSets = ((_a = formData === null || formData === void 0 ? void 0 : formData.taxonCensus) === null || _a === void 0 ? void 0 : _a.map((item) => item.censusTaxonSetID)) || [];
88
+ const deletedTaxonSets = previousTaxonSets.filter((item) => !currentTaxonSets.includes(item));
89
+ const addedTaxonSets = currentTaxonSets.filter((item) => !previousTaxonSets.includes(item));
90
+ this.taxonSets = ((_b = formData === null || formData === void 0 ? void 0 : formData.taxonCensus) === null || _b === void 0 ? void 0 : _b.map((item) => item.censusTaxonSetID)) || [];
91
+ if (deletedTaxonSets.length > 0) {
92
+ deletedTaxonSets.map((deletedTaxonSetId) => {
93
+ var _a;
94
+ const currentUnits = Array.isArray((_a = this.props.formData) === null || _a === void 0 ? void 0 : _a.units) ? this.props.formData.units : [];
95
+ let observationsExist = false;
96
+ const deletedTaxonSetUnits = currentUnits.filter((unit) => {
97
+ return unit.taxonSets && unit.taxonSets.includes(deletedTaxonSetId);
98
+ });
99
+ deletedTaxonSetUnits.map((unit) => {
100
+ var _a, _b, _c, _d;
101
+ if (unit.maleIndividualCount ||
102
+ unit.femaleIndividualCount ||
103
+ unit.nestCount ||
104
+ ((_a = unit.unitFact) === null || _a === void 0 ? void 0 : _a.destroyedNestCount) ||
105
+ ((_b = unit.unitFact) === null || _b === void 0 ? void 0 : _b.broodCount) ||
106
+ ((_c = unit.unitFact) === null || _c === void 0 ? void 0 : _c.femalesWithBroodsCount) ||
107
+ ((_d = unit.unitFact) === null || _d === void 0 ? void 0 : _d.juvenileCount)) {
108
+ window.alert(`Warning: Can't delete taxon set "${deletedTaxonSetId}" because it has observations.`);
109
+ observationsExist = true;
110
+ const updatedFormData = Object.assign(Object.assign({}, formData), { taxonCensus: [
111
+ ...formData.taxonCensus,
112
+ {
113
+ censusTaxonSetID: deletedTaxonSetId,
114
+ taxonCensusType: "MY.taxonCensusTypeCounted"
115
+ }
116
+ ] });
117
+ this.taxonSets = [...this.taxonSets, deletedTaxonSetId];
118
+ this.props.onChange(updatedFormData);
119
+ return;
120
+ }
121
+ });
122
+ if (observationsExist) {
123
+ return;
124
+ }
125
+ const updatedUnits = currentUnits.filter((unit) => {
126
+ return !unit.taxonSets || !unit.taxonSets.includes(deletedTaxonSetId);
127
+ });
128
+ const updatedFormData = Object.assign(Object.assign({}, formData), { units: updatedUnits });
129
+ this.props.onChange(updatedFormData);
130
+ });
131
+ }
132
+ if (addedTaxonSets.length > 0) {
133
+ const currentUnits = Array.isArray((_c = this.props.formData) === null || _c === void 0 ? void 0 : _c.units) ? this.props.formData.units : [];
134
+ // if current units include any units with taxon sets that are being added, return to avoid duplicates
135
+ const duplicateUnits = currentUnits.filter((unit) => {
136
+ return unit.taxonSets && unit.taxonSets.some((taxonSetId) => addedTaxonSets.includes(taxonSetId));
137
+ });
138
+ if (duplicateUnits.length > 0) {
139
+ return;
140
+ }
141
+ const results = yield this.fetchTaxaFromSet(this.props, addedTaxonSets);
142
+ const newUnits = results.map((result) => {
143
+ return {
144
+ identifications: [{
145
+ taxon: result.scientificName,
146
+ taxonID: result.id,
147
+ taxonVerbatim: result.vernacularName
148
+ }],
149
+ informalTaxonGroups: result.informalTaxonGroups || [],
150
+ taxonSets: result.taxonSets || []
151
+ };
152
+ });
153
+ const updatedFormData = Object.assign(Object.assign({}, formData), { units: [...currentUnits, ...newUnits] });
154
+ this.props.onChange(updatedFormData);
155
+ }
156
+ });
157
+ }
158
+ static getName() {
159
+ return "TaxonSetPopulatorField";
160
+ }
161
+ getStateFromProps() {
162
+ return { onChange: this.onChange };
163
+ }
164
+ fetchTaxaFromSet(props, taxonSets) {
165
+ return __awaiter(this, void 0, void 0, function* () {
166
+ var _a;
167
+ const apiClient = (_a = props.formContext) === null || _a === void 0 ? void 0 : _a.apiClient;
168
+ if (!apiClient) {
169
+ return [];
170
+ }
171
+ try {
172
+ const response = yield apiClient.post("/taxa", {
173
+ query: {
174
+ pageSize: 1000,
175
+ selectedFields: ["id", "scientificName", "vernacularName", "informalTaxonGroups", "taxonSets"]
176
+ }
177
+ }, {
178
+ taxonSets
179
+ });
180
+ if (!response.results || !Array.isArray(response.results)) {
181
+ return [];
182
+ }
183
+ return response.results;
184
+ }
185
+ catch (error) {
186
+ return [];
187
+ }
188
+ });
189
+ }
190
+ };
191
+ TaxonSetPopulatorField.propTypes = {
192
+ uiSchema: PropTypes.shape({
193
+ "ui:options": PropTypes.shape({
194
+ props: PropTypes.oneOfType([PropTypes.arrayOf(propsPropType), propsPropType])
195
+ }),
196
+ uiSchema: PropTypes.object
197
+ }).isRequired,
198
+ schema: PropTypes.shape({
199
+ type: PropTypes.oneOf(["array", "object"])
200
+ }).isRequired,
201
+ formData: PropTypes.oneOfType([PropTypes.array, PropTypes.object]).isRequired
202
+ };
203
+ TaxonSetPopulatorField = __decorate([
204
+ VirtualSchemaField_1.default
205
+ ], TaxonSetPopulatorField);
206
+ exports.default = TaxonSetPopulatorField;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luomus/laji-form",
3
- "version": "15.1.90",
3
+ "version": "15.1.92",
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",