@teselagen/ui 0.3.76 → 0.3.77
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/index.cjs.js +51658 -5841
- package/index.es.js +51655 -5838
- package/package.json +2 -8
- package/src/DataTable/dataTableEnhancer.js +4 -2
- package/src/DataTable/editCellHelper.js +306 -10
- package/src/DataTable/getCellVal.js +4 -1
- package/src/DataTable/index.js +622 -192
- package/src/ExcelCell.js +38 -0
- package/src/FormComponents/tryToMatchSchemas.js +9 -3
- package/src/MatchHeaders.js +1 -1
- package/src/ResizableDraggableDialog/index.js +6 -3
- package/src/showConfirmationDialog/index.js +6 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teselagen/ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.77",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"buffer": "5.7.1",
|
|
22
22
|
"color": "^3.2.1",
|
|
23
23
|
"copy-to-clipboard": "^3.3.1",
|
|
24
|
-
"dayjs": "^1.10.4",
|
|
25
24
|
"dom-scroll-into-view": "^2.0.1",
|
|
26
25
|
"downloadjs": "^1.4.7",
|
|
27
26
|
"fuse.js": "^6.6.2",
|
|
@@ -30,19 +29,15 @@
|
|
|
30
29
|
"is-mobile": "^3.0.0",
|
|
31
30
|
"jszip": "^3.10.1",
|
|
32
31
|
"math-expression-evaluator": "^1.3.7",
|
|
33
|
-
"mobx": "^6.10.2",
|
|
34
|
-
"mobx-react": "^9.0.1",
|
|
35
32
|
"mock-fs": "5.2.0",
|
|
36
33
|
"nanoid": "^4.0.0",
|
|
37
34
|
"papaparse": "^5.3.2",
|
|
38
35
|
"prop-types": "^15.6.2",
|
|
39
|
-
"qs": "^6.9.6",
|
|
40
36
|
"react": "18.2.0",
|
|
41
37
|
"react-color": "^2.19.3",
|
|
42
38
|
"react-dom": "18.2.0",
|
|
43
39
|
"react-dropzone": "^11.4.2",
|
|
44
40
|
"react-markdown": "8.0.7",
|
|
45
|
-
"react-redux": "^8.0.5",
|
|
46
41
|
"react-rnd": "^10.2.4",
|
|
47
42
|
"react-router-dom": "^4.3.1",
|
|
48
43
|
"react-sortable-hoc": "^0.6.8",
|
|
@@ -54,8 +49,7 @@
|
|
|
54
49
|
"remark-gfm": "^3.0.1",
|
|
55
50
|
"tippy.js": "^6.3.7",
|
|
56
51
|
"url-join": "^4.0.1",
|
|
57
|
-
"use-deep-compare-effect": "^1.6.1"
|
|
58
|
-
"write-excel-file": "^1.4.25"
|
|
52
|
+
"use-deep-compare-effect": "^1.6.1"
|
|
59
53
|
},
|
|
60
54
|
"license": "MIT"
|
|
61
55
|
}
|
|
@@ -15,6 +15,7 @@ import { viewColumn, openColumn } from "../DataTable/viewColumn";
|
|
|
15
15
|
import pureNoFunc from "../utils/pureNoFunc";
|
|
16
16
|
import tgFormValues from "../utils/tgFormValues";
|
|
17
17
|
import getTableConfigFromStorage from "./utils/getTableConfigFromStorage";
|
|
18
|
+
import computePresets from "./utils/computePresets";
|
|
18
19
|
|
|
19
20
|
export default compose(
|
|
20
21
|
// maybe we need this in some cases?
|
|
@@ -40,6 +41,7 @@ export default compose(
|
|
|
40
41
|
...ownProps.tableParams
|
|
41
42
|
};
|
|
42
43
|
}
|
|
44
|
+
propsToUse = computePresets(propsToUse);
|
|
43
45
|
|
|
44
46
|
const {
|
|
45
47
|
schema,
|
|
@@ -126,8 +128,8 @@ export default compose(
|
|
|
126
128
|
return field.render
|
|
127
129
|
? !field.render(val, e)
|
|
128
130
|
: cellRenderer[field.path]
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
? !cellRenderer[field.path](val, e)
|
|
132
|
+
: !val;
|
|
131
133
|
});
|
|
132
134
|
}
|
|
133
135
|
if (noValsForField) {
|
|
@@ -1,25 +1,166 @@
|
|
|
1
|
-
import { set } from "lodash";
|
|
1
|
+
import { isString, set, toNumber } from "lodash";
|
|
2
2
|
import { defaultValidators } from "./defaultValidators";
|
|
3
3
|
import { defaultFormatters } from "./defaultFormatters";
|
|
4
|
+
import { evaluate } from "mathjs";
|
|
5
|
+
import getIdOrCodeOrIndex from "./utils/getIdOrCodeOrIndex";
|
|
4
6
|
|
|
5
7
|
//(mutative) responsible for formatting and then validating the
|
|
8
|
+
// const depGraph = {
|
|
9
|
+
// a1: ["a3"],
|
|
10
|
+
// a2: ["a1"],
|
|
11
|
+
// a3: [],
|
|
12
|
+
// b1: ["a1", "a2"],
|
|
13
|
+
// b2: ["a2"],
|
|
14
|
+
// b3: ["a3"]
|
|
15
|
+
// };
|
|
6
16
|
|
|
7
17
|
export const editCellHelper = ({
|
|
18
|
+
_cellAlphaNum,
|
|
19
|
+
updateGroup,
|
|
20
|
+
depGraph,
|
|
8
21
|
entity,
|
|
9
22
|
path,
|
|
10
23
|
schema,
|
|
11
24
|
columnSchema,
|
|
12
|
-
newVal
|
|
25
|
+
newVal,
|
|
26
|
+
entities,
|
|
27
|
+
nestLevel = 0,
|
|
28
|
+
depLevel = 0,
|
|
29
|
+
allowFormulas
|
|
13
30
|
}) => {
|
|
14
31
|
let nv = newVal;
|
|
32
|
+
if (nv?.formula) {
|
|
33
|
+
nv = nv.formula;
|
|
34
|
+
}
|
|
15
35
|
|
|
16
36
|
const colSchema =
|
|
17
37
|
columnSchema || schema?.fields?.find(({ path: p }) => p === path) || {};
|
|
18
38
|
path = path || colSchema.path;
|
|
39
|
+
const cellAlphaNum =
|
|
40
|
+
_cellAlphaNum ||
|
|
41
|
+
getCellAlphaNum({
|
|
42
|
+
entities,
|
|
43
|
+
entity,
|
|
44
|
+
colSchema,
|
|
45
|
+
schema
|
|
46
|
+
});
|
|
47
|
+
if (
|
|
48
|
+
updateGroup[cellAlphaNum] !== undefined &&
|
|
49
|
+
updateGroup[cellAlphaNum] !== "__Currently&&Updating__"
|
|
50
|
+
) {
|
|
51
|
+
// if the cell is already being updated, return the value
|
|
52
|
+
return { value: updateGroup[cellAlphaNum], errors: {} };
|
|
53
|
+
} else {
|
|
54
|
+
updateGroup[cellAlphaNum] = "__Currently&&Updating__";
|
|
55
|
+
}
|
|
56
|
+
const cellId = `${getIdOrCodeOrIndex(entity)}:${colSchema.path}`;
|
|
57
|
+
const oldVal = entity[path];
|
|
19
58
|
const { format, validate, type } = colSchema;
|
|
20
|
-
let
|
|
21
|
-
|
|
59
|
+
let errors = {
|
|
60
|
+
__hasErrors: false
|
|
61
|
+
};
|
|
62
|
+
if (nv === undefined && colSchema.defaultValue !== undefined) {
|
|
22
63
|
nv = colSchema.defaultValue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let hasFormula = false;
|
|
67
|
+
if (colSchema.allowFormulas && typeof nv === "string" && nv[0] === "=") {
|
|
68
|
+
const ogFormula = nv;
|
|
69
|
+
// if the nv is missing a closing paren, add it
|
|
70
|
+
// count the number of open parens
|
|
71
|
+
// count the number of close parens
|
|
72
|
+
// if the number of open parens is greater than the number of close parens, add a close paren
|
|
73
|
+
const openParens = (nv.match(/\(/g) || []).length;
|
|
74
|
+
const closeParens = (nv.match(/\)/g) || []).length;
|
|
75
|
+
if (openParens > closeParens) {
|
|
76
|
+
nv = nv + ")";
|
|
77
|
+
}
|
|
78
|
+
// if the nv is a valid formula, evaluate it and evaluate any nested formulas
|
|
79
|
+
// if the nv is not a valid formula, return the error
|
|
80
|
+
// fill in any variables with their values
|
|
81
|
+
let error;
|
|
82
|
+
// if nv contains : then it is a range
|
|
83
|
+
// if (nv.includes(":")) {
|
|
84
|
+
// replace the range with the the values of the range
|
|
85
|
+
// get the start and end of the range
|
|
86
|
+
const { rangeErr, replacedFormula } = replaceFormulaRanges({
|
|
87
|
+
formula: nv,
|
|
88
|
+
schema,
|
|
89
|
+
entities
|
|
90
|
+
});
|
|
91
|
+
error = rangeErr;
|
|
92
|
+
nv = replacedFormula;
|
|
93
|
+
nv = nv.replace(/([A-Z]+[0-9]+)/gi, _match => {
|
|
94
|
+
const match = _match.toUpperCase();
|
|
95
|
+
if (updateGroup[match] === "__Currently&&Updating__") {
|
|
96
|
+
error = `Circular Loop Detected between ${cellAlphaNum} and ${match}`;
|
|
97
|
+
return "circular_loop_detected";
|
|
98
|
+
}
|
|
99
|
+
// match will equal E12 or B4 for example
|
|
100
|
+
const [letter, rowIndex] = match.split(/(\d+)/);
|
|
101
|
+
const entity = entities.find((e, i) => {
|
|
102
|
+
return i === rowIndex - 1;
|
|
103
|
+
});
|
|
104
|
+
const columns = schema.fields;
|
|
105
|
+
const letterIndex = lettersToNumber(letter);
|
|
106
|
+
const col = columns[letterIndex];
|
|
107
|
+
if (!col) {
|
|
108
|
+
return match;
|
|
109
|
+
}
|
|
110
|
+
const { path } = col;
|
|
111
|
+
if (!entity) return match;
|
|
112
|
+
let val = entity[path];
|
|
113
|
+
if (val === undefined || val === "") return 0;
|
|
114
|
+
if (val?.formula) {
|
|
115
|
+
val = val.formula;
|
|
116
|
+
}
|
|
117
|
+
if (isString(val) && val[0] === "=") {
|
|
118
|
+
// if the value is a formula, evaluate it
|
|
119
|
+
const { value, errors: _errors } = editCellHelper({
|
|
120
|
+
_cellAlphaNum: match,
|
|
121
|
+
updateGroup,
|
|
122
|
+
depGraph,
|
|
123
|
+
entity,
|
|
124
|
+
path,
|
|
125
|
+
schema,
|
|
126
|
+
columnSchema: col,
|
|
127
|
+
newVal: val,
|
|
128
|
+
entities,
|
|
129
|
+
nestLevel: nestLevel + 1
|
|
130
|
+
});
|
|
131
|
+
errors = mergeErrors(errors, _errors);
|
|
132
|
+
val = value?.formula ? value.value : value;
|
|
133
|
+
} else if (!isNaN(toNumber(val))) {
|
|
134
|
+
return val;
|
|
135
|
+
} else if (isString(val)) {
|
|
136
|
+
return 0;
|
|
137
|
+
}
|
|
138
|
+
return val;
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const toEval = nv.slice(1);
|
|
142
|
+
try {
|
|
143
|
+
if (!error) {
|
|
144
|
+
nv = evaluate(toEval);
|
|
145
|
+
nv = {
|
|
146
|
+
formula: ogFormula,
|
|
147
|
+
value: `${nv}`
|
|
148
|
+
};
|
|
149
|
+
} else {
|
|
150
|
+
throw new Error(error);
|
|
151
|
+
}
|
|
152
|
+
} catch (e) {
|
|
153
|
+
nv = {
|
|
154
|
+
formula: ogFormula,
|
|
155
|
+
value: `#ERROR`,
|
|
156
|
+
error: e.message
|
|
157
|
+
};
|
|
158
|
+
errors[cellId] = e.message;
|
|
159
|
+
errors.__hasErrors = true;
|
|
160
|
+
}
|
|
161
|
+
hasFormula = nv;
|
|
162
|
+
nv = nv.value;
|
|
163
|
+
}
|
|
23
164
|
|
|
24
165
|
if (format) {
|
|
25
166
|
nv = format(nv, colSchema);
|
|
@@ -27,18 +168,173 @@ export const editCellHelper = ({
|
|
|
27
168
|
if (defaultFormatters[type]) {
|
|
28
169
|
nv = defaultFormatters[type](nv, colSchema);
|
|
29
170
|
}
|
|
30
|
-
if (validate) {
|
|
31
|
-
error = validate(nv, colSchema, entity);
|
|
171
|
+
if (validate && !hasErrors(errors)) {
|
|
172
|
+
const error = validate(nv, colSchema, entity);
|
|
173
|
+
if (error) {
|
|
174
|
+
errors.__hasErrors = true;
|
|
175
|
+
}
|
|
176
|
+
errors[cellId] = error;
|
|
32
177
|
}
|
|
33
|
-
if (!
|
|
178
|
+
if (!hasErrors(errors)) {
|
|
34
179
|
const validator =
|
|
35
180
|
defaultValidators[type] ||
|
|
36
181
|
type === "string" ||
|
|
37
182
|
(type === undefined && defaultValidators.string);
|
|
38
183
|
if (validator) {
|
|
39
|
-
error = validator(nv, colSchema);
|
|
184
|
+
const error = validator(nv, colSchema);
|
|
185
|
+
if (error) {
|
|
186
|
+
errors.__hasErrors = true;
|
|
187
|
+
}
|
|
188
|
+
errors[cellId] = error;
|
|
40
189
|
}
|
|
41
190
|
}
|
|
42
|
-
|
|
43
|
-
|
|
191
|
+
const value = hasFormula || nv;
|
|
192
|
+
if (
|
|
193
|
+
// if the formula and its value is the same as it was, don't set it again otherwise it will be added to the undo/redo stack
|
|
194
|
+
!(
|
|
195
|
+
hasFormula &&
|
|
196
|
+
value.value === oldVal?.value &&
|
|
197
|
+
value.formula === oldVal?.formula
|
|
198
|
+
)
|
|
199
|
+
) {
|
|
200
|
+
set(entity, path, value);
|
|
201
|
+
}
|
|
202
|
+
updateGroup[cellAlphaNum] = value;
|
|
203
|
+
if (allowFormulas && entities && entities.length) {
|
|
204
|
+
// go through the depGraph and update any cells that depend on this cell
|
|
205
|
+
const cellDepGraph = depGraph[cellAlphaNum];
|
|
206
|
+
if (cellDepGraph && cellDepGraph.length) {
|
|
207
|
+
cellDepGraph.forEach(depCellAlphaNum => {
|
|
208
|
+
if (depCellAlphaNum === cellAlphaNum) return;
|
|
209
|
+
if (updateGroup[depCellAlphaNum] === "__Currently&&Updating__") {
|
|
210
|
+
// if the cell is already being updated, return the value
|
|
211
|
+
return updateGroup[depCellAlphaNum];
|
|
212
|
+
}
|
|
213
|
+
const [depColLetter, depRowIndex] = depCellAlphaNum.split(/(\d+)/);
|
|
214
|
+
const depEntity = entities[depRowIndex - 1];
|
|
215
|
+
// if (!depEntity) debugger
|
|
216
|
+
// if (!depEntity) return
|
|
217
|
+
const depColIndex = depColLetter.charCodeAt(0) - 65;
|
|
218
|
+
const depColSchema = schema.fields[depColIndex];
|
|
219
|
+
const depPath = depColSchema.path;
|
|
220
|
+
const depNewVal = depEntity[depPath];
|
|
221
|
+
|
|
222
|
+
const { errors: _errors } = editCellHelper({
|
|
223
|
+
_cellAlphaNum: depCellAlphaNum,
|
|
224
|
+
allowFormulas,
|
|
225
|
+
updateGroup,
|
|
226
|
+
depGraph,
|
|
227
|
+
entity: depEntity,
|
|
228
|
+
path: depPath,
|
|
229
|
+
schema,
|
|
230
|
+
columnSchema: depColSchema,
|
|
231
|
+
newVal: depNewVal,
|
|
232
|
+
entities,
|
|
233
|
+
depLevel: depLevel + 1,
|
|
234
|
+
nestLevel: nestLevel
|
|
235
|
+
});
|
|
236
|
+
errors = mergeErrors(errors, _errors);
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
updateGroup[cellAlphaNum] = value?.formula ? value.value : value;
|
|
241
|
+
if (!hasErrors(errors)) {
|
|
242
|
+
errors[cellId] = undefined;
|
|
243
|
+
}
|
|
244
|
+
return { entity, errors, value };
|
|
44
245
|
};
|
|
246
|
+
|
|
247
|
+
function getCellAlphaNum({ entities, entity, colSchema, schema }) {
|
|
248
|
+
const rowIndex = entities.indexOf(entity);
|
|
249
|
+
const colIndex = schema.fields.indexOf(colSchema);
|
|
250
|
+
return getCellAlphaNumHelper(colIndex, rowIndex);
|
|
251
|
+
}
|
|
252
|
+
export function getCellAlphaNumHelper(colIndex, rowIndex) {
|
|
253
|
+
const colLetter = getColLetFromIndex(colIndex);
|
|
254
|
+
const cellAlphaNum = `${colLetter}${rowIndex + 1}`;
|
|
255
|
+
return cellAlphaNum;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const hasErrors = errors => {
|
|
259
|
+
return errors.__hasErrors;
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
export const getColLetFromIndex = index => {
|
|
263
|
+
if (index > 25)
|
|
264
|
+
return (
|
|
265
|
+
getColLetFromIndexHelper(index / 26 - 1) +
|
|
266
|
+
getColLetFromIndexHelper(index % 26)
|
|
267
|
+
);
|
|
268
|
+
return getColLetFromIndexHelper(index);
|
|
269
|
+
};
|
|
270
|
+
const getColLetFromIndexHelper = index => {
|
|
271
|
+
return String.fromCharCode(65 + index);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const lettersToNumber = letters => {
|
|
275
|
+
let n = 0;
|
|
276
|
+
for (let p = 0; p < letters.length; p++) {
|
|
277
|
+
n = letters[p].charCodeAt() - 64 + n * 26;
|
|
278
|
+
}
|
|
279
|
+
return n - 1;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
export const replaceFormulaRanges = ({ formula, schema, entities }) => {
|
|
283
|
+
let error;
|
|
284
|
+
const replaced = formula
|
|
285
|
+
.toLowerCase()
|
|
286
|
+
.replaceAll("$", "")
|
|
287
|
+
.replace(/([A-Z]*[0-9]*:[A-Z]*[0-9]*)/gi, _match => {
|
|
288
|
+
// if (_match.includes(":")) {
|
|
289
|
+
// }
|
|
290
|
+
const match = _match.toUpperCase();
|
|
291
|
+
const [start, end] = match.split(":");
|
|
292
|
+
const [startLetter, _startRowIndex] = start.split(/(\d+)/);
|
|
293
|
+
const [endLetter, _endRowIndex] = end.split(/(\d+)/);
|
|
294
|
+
let startRowIndex = parseInt(_startRowIndex);
|
|
295
|
+
let endRowIndex = parseInt(_endRowIndex);
|
|
296
|
+
let toRet = "";
|
|
297
|
+
|
|
298
|
+
if (startLetter !== endLetter) {
|
|
299
|
+
error = `Ranges must be in the same column`;
|
|
300
|
+
return "range_in_different_columns";
|
|
301
|
+
}
|
|
302
|
+
if (!startLetter && !endLetter && _startRowIndex === _endRowIndex) {
|
|
303
|
+
// we have a range like 1:1
|
|
304
|
+
const rowIndex = startRowIndex;
|
|
305
|
+
const startColIndex = 1;
|
|
306
|
+
const endColIndex = schema.fields.length;
|
|
307
|
+
for (let i = startColIndex; i <= endColIndex; i++) {
|
|
308
|
+
const colLet = getColLetFromIndex(i - 1);
|
|
309
|
+
toRet += `${colLet}${rowIndex}${i === endColIndex ? "" : ","}`;
|
|
310
|
+
}
|
|
311
|
+
return toRet;
|
|
312
|
+
}
|
|
313
|
+
if (_startRowIndex === undefined && _endRowIndex === undefined) {
|
|
314
|
+
// we have a range like A:A
|
|
315
|
+
startRowIndex = 1;
|
|
316
|
+
endRowIndex = entities.length;
|
|
317
|
+
}
|
|
318
|
+
for (let j = startRowIndex; j <= endRowIndex; j++) {
|
|
319
|
+
toRet += `${startLetter}${j}${j === endRowIndex ? "" : ","}`;
|
|
320
|
+
}
|
|
321
|
+
return toRet;
|
|
322
|
+
});
|
|
323
|
+
return {
|
|
324
|
+
replacedFormula: replaced,
|
|
325
|
+
error
|
|
326
|
+
};
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
function mergeErrors(errors, _errors) {
|
|
330
|
+
let hasErrors = false;
|
|
331
|
+
if (_errors.__hasErrors || errors.__hasErrors) {
|
|
332
|
+
hasErrors = true;
|
|
333
|
+
}
|
|
334
|
+
errors = {
|
|
335
|
+
...errors,
|
|
336
|
+
..._errors,
|
|
337
|
+
__hasErrors: hasErrors
|
|
338
|
+
};
|
|
339
|
+
return errors;
|
|
340
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { get } from "lodash";
|
|
1
|
+
import { get, has } from "lodash";
|
|
2
2
|
import { isString } from "lodash";
|
|
3
3
|
import { isTruthy } from "./isTruthy";
|
|
4
4
|
|
|
@@ -16,5 +16,8 @@ export const getCellVal = (ent, path, col) => {
|
|
|
16
16
|
selectedCellVal === "yes";
|
|
17
17
|
selectedCellVal = isTruthy(selectedCellVal);
|
|
18
18
|
}
|
|
19
|
+
if (has(selectedCellVal, "value")) {
|
|
20
|
+
return selectedCellVal.value;
|
|
21
|
+
}
|
|
19
22
|
return selectedCellVal;
|
|
20
23
|
};
|