@teselagen/ui 0.7.23 → 0.7.25

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.
@@ -1,44 +0,0 @@
1
- import React, { useEffect, useRef, useState } from "react";
2
-
3
- export const EditableCell = ({
4
- cancelEdit,
5
- dataTest,
6
- finishEdit,
7
- isNumeric,
8
- initialValue
9
- }) => {
10
- const [value, setValue] = useState(initialValue);
11
- const inputRef = useRef(null);
12
-
13
- useEffect(() => {
14
- if (inputRef.current) {
15
- inputRef.current.focus();
16
- }
17
- }, [isNumeric]);
18
-
19
- return (
20
- <input
21
- style={{
22
- border: 0,
23
- width: "95%",
24
- fontSize: 12,
25
- background: "none"
26
- }}
27
- ref={inputRef}
28
- {...dataTest}
29
- autoFocus
30
- onKeyDown={e => {
31
- e.stopPropagation();
32
- if (e.key === "Enter") {
33
- e.target.blur();
34
- } else if (e.key === "Escape") {
35
- cancelEdit();
36
- }
37
- }}
38
- onBlur={() => finishEdit(value)}
39
- onChange={e => setValue(e.target.value)}
40
- type={isNumeric ? "number" : undefined}
41
- value={value}
42
- />
43
- );
44
- };
@@ -1,191 +0,0 @@
1
- import React from "react";
2
- import { useSelector } from "react-redux";
3
- import { Checkbox, Icon } from "@blueprintjs/core";
4
- import {
5
- getIdOrCodeOrIndex,
6
- isBottomRightCornerOfRectangle,
7
- PRIMARY_SELECTED_VAL
8
- } from "./utils";
9
- import { DropdownCell } from "./DropdownCell";
10
- import { EditableCell } from "./EditabelCell";
11
- import { getVals } from "./getVals";
12
- import { CellDragHandle } from "./CellDragHandle";
13
-
14
- export const RenderCell = ({
15
- oldFunc,
16
- getCopyTextForCell,
17
- column,
18
- isCellEditable,
19
- isEntityDisabled,
20
- finishCellEdit,
21
- formName,
22
- noEllipsis,
23
- cancelCellEdit,
24
- getCellHoverText,
25
- selectedCells,
26
- isSelectionARectangle,
27
- startCellEdit,
28
- tableRef,
29
- onDragEnd,
30
- args
31
- }) => {
32
- const editingCell = useSelector(
33
- state => state.form?.[formName]?.values?.reduxFormEditingCell
34
- );
35
- const initialValue = useSelector(
36
- state => state.form?.[formName]?.values?.reduxFormInitialValue
37
- );
38
-
39
- const [row] = args;
40
- const rowId = getIdOrCodeOrIndex(row.original, row.index);
41
- const cellId = `${rowId}:${row.column.path}`;
42
- const isEditingCell = editingCell === cellId;
43
- let val = oldFunc(...args);
44
- const oldVal = val;
45
- const text = getCopyTextForCell(val, row, column);
46
- const dataTest = {
47
- "data-test": "tgCell_" + column.path
48
- };
49
- const fullValue = row.original?.[row.column.path];
50
-
51
- if (isEditingCell) {
52
- if (column.type === "genericSelect") {
53
- const GenericSelectComp = column.GenericSelectComp;
54
-
55
- return (
56
- <GenericSelectComp
57
- rowId={rowId}
58
- fullValue={fullValue}
59
- initialValue={text}
60
- {...dataTest}
61
- finishEdit={(newVal, doNotStopEditing) => {
62
- finishCellEdit(cellId, newVal, doNotStopEditing);
63
- }}
64
- dataTest={dataTest}
65
- cancelEdit={cancelCellEdit}
66
- />
67
- );
68
- }
69
- if (column.type === "dropdown" || column.type === "dropdownMulti") {
70
- return (
71
- <DropdownCell
72
- isMulti={dataTest.isMulti || column.type === "dropdownMulti"}
73
- initialValue={dataTest.initialValue || text}
74
- options={getVals(column.values)}
75
- finishEdit={(newVal, doNotStopEditing) => {
76
- finishCellEdit(cellId, newVal, doNotStopEditing);
77
- }}
78
- dataTest={dataTest}
79
- cancelEdit={cancelCellEdit}
80
- />
81
- );
82
- } else {
83
- return (
84
- <EditableCell
85
- dataTest={dataTest}
86
- cancelEdit={cancelCellEdit}
87
- isNumeric={column.type === "number"}
88
- initialValue={initialValue || text}
89
- finishEdit={newVal => {
90
- finishCellEdit(cellId, newVal);
91
- }}
92
- />
93
- );
94
- }
95
- }
96
-
97
- const isBool = column.type === "boolean";
98
- if (isCellEditable && isBool) {
99
- val = (
100
- <Checkbox
101
- disabled={isEntityDisabled(row.original)}
102
- className="tg-cell-edit-boolean-checkbox"
103
- checked={oldVal === "True"}
104
- onChange={e => {
105
- const checked = e.target.checked;
106
- finishCellEdit(cellId, checked);
107
- }}
108
- />
109
- );
110
- noEllipsis = true;
111
- }
112
-
113
- //wrap the original tableColumn.Cell function in another div in order to add a title attribute
114
- let title = text;
115
- if (getCellHoverText) title = getCellHoverText(...args);
116
- else if (column.getTitleAttr) title = column.getTitleAttr(...args);
117
- const isSelectedCell = selectedCells?.[cellId];
118
- const {
119
- isRect,
120
- selectionGrid,
121
- lastRowIndex,
122
- lastCellIndex,
123
- entityMap,
124
- pathToIndex
125
- } = isSelectionARectangle();
126
-
127
- return (
128
- <>
129
- <div
130
- style={{
131
- ...(!noEllipsis && {
132
- textOverflow: "ellipsis",
133
- overflow: "hidden"
134
- })
135
- }}
136
- {...dataTest}
137
- className="tg-cell-wrapper"
138
- data-copy-text={text}
139
- data-copy-json={JSON.stringify(
140
- //tnw: eventually we'll parse these back out and use either the fullValue (for the generic selects) or the regular text vals for everything else
141
- column.type === "genericSelect"
142
- ? {
143
- __strVal: fullValue,
144
- __genSelCol: column.path
145
- }
146
- : { __strVal: text }
147
- )}
148
- title={title || undefined}
149
- >
150
- {val}
151
- </div>
152
- {isCellEditable &&
153
- (column.type === "dropdown" ||
154
- column.type === "dropdownMulti" ||
155
- column.type === "genericSelect") && (
156
- <Icon
157
- icon="caret-down"
158
- style={{
159
- position: "absolute",
160
- right: 5,
161
- opacity: 0.3
162
- }}
163
- className="cell-edit-dropdown"
164
- onClick={() => {
165
- startCellEdit(cellId);
166
- }}
167
- />
168
- )}
169
-
170
- {isSelectedCell &&
171
- (isRect
172
- ? isBottomRightCornerOfRectangle({
173
- cellId,
174
- selectionGrid,
175
- lastRowIndex,
176
- lastCellIndex,
177
- entityMap,
178
- pathToIndex
179
- })
180
- : isSelectedCell === PRIMARY_SELECTED_VAL) && (
181
- <CellDragHandle
182
- key={cellId}
183
- thisTable={tableRef.current.tableRef}
184
- cellId={cellId}
185
- isSelectionARectangle={isSelectionARectangle}
186
- onDragEnd={onDragEnd}
187
- />
188
- )}
189
- </>
190
- );
191
- };
@@ -1,10 +0,0 @@
1
- import { isEqual } from "lodash-es";
2
- import { useRef } from "react";
3
-
4
- export const useDeepEqualMemo = value => {
5
- const ref = useRef();
6
- if (!isEqual(value, ref.current)) {
7
- ref.current = value;
8
- }
9
- return ref.current;
10
- };
@@ -1,361 +0,0 @@
1
- import { useContext, useEffect, useMemo, useState } from "react";
2
- import { change } from "redux-form";
3
- import { useDispatch, useSelector } from "react-redux";
4
- import { isFunction, keyBy, get } from "lodash-es";
5
- import TableFormTrackerContext from "../TableFormTrackerContext";
6
- import { viewColumn, openColumn } from "./viewColumn";
7
- import convertSchema from "./convertSchema";
8
- import { getRecordsFromIdMap } from "./withSelectedEntities";
9
- import {
10
- makeDataTableHandlers,
11
- getQueryParams,
12
- setCurrentParamsOnUrl,
13
- getCurrentParamsFromUrl,
14
- getCCDisplayName
15
- } from "./queryParams";
16
- import getTableConfigFromStorage from "./getTableConfigFromStorage";
17
-
18
- /*
19
- NOTE:
20
- This haven't been tested yet. It is the first version of what we should replace withTableParams
21
- and also the first bit of the DataTable.
22
- */
23
-
24
- /**
25
- * Note all these options can be passed at Design Time or at Runtime (like reduxForm())
26
- *
27
- * @export
28
- *
29
- * @param {compOrOpts} compOrOpts
30
- * @typedef {object} compOrOpts
31
- * @property {*string} formName - required unique identifier for the table
32
- * @property {Object | Function} schema - The data table schema or a function returning it. The function wll be called with props as the argument.
33
- * @property {boolean} urlConnected - whether the table should connect to/update the URL
34
- * @property {boolean} withSelectedEntities - whether or not to pass the selected entities
35
- * @property {boolean} isCodeModel - whether the model is keyed by code instead of id in the db
36
- * @property {object} defaults - tableParam defaults such as pageSize, filter, etc
37
- * @property {boolean} noOrderError - won't console an error if an order is not found on schema
38
- */
39
- export default function useTableParams(
40
- props // This should be the same as the spread above
41
- ) {
42
- const {
43
- formName,
44
- isTableParamsConnected,
45
- urlConnected,
46
- onlyOneFilter,
47
- defaults = {},
48
- // WE NEED THIS HOOK TO BE WRAPPED IN A WITHROUTER OR MOVE TO REACT-ROUTER-DOM 5
49
- // BEST SOLUTION IS TO ASSUME IT IS GOING TO BE RECEIVED
50
- history,
51
- withSelectedEntities,
52
- tableParams: _tableParams,
53
- schema: __schema,
54
- noForm,
55
- orderByFirstColumn,
56
- withDisplayOptions,
57
- syncDisplayOptionsToDb,
58
- tableConfigurations,
59
- isViewable,
60
- isOpenable,
61
- showEmptyColumnsByDefault,
62
- isSimple,
63
- entities: _origEntities = [],
64
- cellRenderer,
65
- additionalFilter,
66
- additionalOrFilter,
67
- doNotCoercePageSize,
68
- isLocalCall
69
- } = props;
70
- const isInfinite = props.isInfinite || isSimple || !props.withPaging;
71
- const additionalFilterToUse =
72
- typeof additionalFilter === "function"
73
- ? additionalFilter.bind(this, props)
74
- : () => additionalFilter;
75
-
76
- const additionalOrFilterToUse =
77
- typeof additionalOrFilter === "function"
78
- ? additionalOrFilter.bind(this, props)
79
- : () => additionalOrFilter;
80
-
81
- let _schema;
82
- if (isFunction(__schema)) _schema = __schema(props);
83
- else _schema = __schema;
84
- const convertedSchema = convertSchema(_schema);
85
-
86
- if (isLocalCall) {
87
- if (!noForm && (!formName || formName === "tgDataTable")) {
88
- throw new Error(
89
- "Please pass a unique 'formName' prop to the locally connected <DataTable/> component with schema: ",
90
- _schema
91
- );
92
- }
93
- if (orderByFirstColumn && !defaults?.order?.length) {
94
- const r = [getCCDisplayName(convertedSchema.fields[0])];
95
- defaults.order = r;
96
- }
97
- } else {
98
- //in user instantiated withTableParams() call
99
- if (!formName || formName === "tgDataTable") {
100
- throw new Error(
101
- "Please pass a unique 'formName' prop to the withTableParams() with schema: ",
102
- _schema
103
- );
104
- }
105
- }
106
-
107
- const [showForcedHiddenColumns, setShowForcedHidden] = useState(() => {
108
- if (showEmptyColumnsByDefault) {
109
- return true;
110
- }
111
- return false;
112
- });
113
-
114
- const [tableConfig, setTableConfig] = useState({ fieldOptions: [] });
115
-
116
- useEffect(() => {
117
- let newTableConfig = {};
118
- if (withDisplayOptions) {
119
- if (syncDisplayOptionsToDb) {
120
- newTableConfig = tableConfigurations && tableConfigurations[0];
121
- } else {
122
- newTableConfig = getTableConfigFromStorage(formName);
123
- }
124
- if (!newTableConfig) {
125
- newTableConfig = {
126
- fieldOptions: []
127
- };
128
- }
129
- }
130
- setTableConfig(newTableConfig);
131
- }, [
132
- formName,
133
- syncDisplayOptionsToDb,
134
- tableConfigurations,
135
- withDisplayOptions
136
- ]);
137
-
138
- // make user set page size persist
139
- const userSetPageSize =
140
- tableConfig?.userSetPageSize && parseInt(tableConfig.userSetPageSize, 10);
141
- if (!syncDisplayOptionsToDb && userSetPageSize) {
142
- defaults.pageSize = userSetPageSize;
143
- }
144
-
145
- const {
146
- reduxFormSearchInput = "",
147
- onlyShowRowsWErrors,
148
- reduxFormCellValidation,
149
- reduxFormEntities,
150
- reduxFormSelectedCells = {},
151
- reduxFormSelectedEntityIdMap = {},
152
- reduxFormQueryParams = {}
153
- } = useSelector(state => {
154
- if (!state.form[formName]) return {};
155
- return state.form[formName].values || {};
156
- });
157
-
158
- const entities = reduxFormEntities || _origEntities;
159
-
160
- const { schema } = useMemo(() => {
161
- const schema = convertSchema(_schema);
162
- if (isViewable) {
163
- schema.fields = [viewColumn, ...schema.fields];
164
- }
165
- if (isOpenable) {
166
- schema.fields = [openColumn, ...schema.fields];
167
- }
168
- // this must come before handling orderings.
169
- schema.fields = schema.fields.map(field => {
170
- if (field.placementPath) {
171
- return {
172
- ...field,
173
- sortDisabled:
174
- field.sortDisabled ||
175
- (typeof field.path === "string" && field.path.includes(".")),
176
- path: field.placementPath
177
- };
178
- } else {
179
- return field;
180
- }
181
- });
182
-
183
- if (withDisplayOptions) {
184
- const fieldOptsByPath = keyBy(tableConfig.fieldOptions, "path");
185
- schema.fields = schema.fields.map(field => {
186
- const fieldOpt = fieldOptsByPath[field.path];
187
- let noValsForField = false;
188
- // only add this hidden column ability if no paging
189
- if (
190
- !showForcedHiddenColumns &&
191
- withDisplayOptions &&
192
- (isSimple || isInfinite)
193
- ) {
194
- noValsForField = entities.every(e => {
195
- const val = get(e, field.path);
196
- return field.render
197
- ? !field.render(val, e)
198
- : cellRenderer[field.path]
199
- ? !cellRenderer[field.path](val, e)
200
- : !val;
201
- });
202
- }
203
- if (noValsForField) {
204
- return {
205
- ...field,
206
- isHidden: true,
207
- isForcedHidden: true
208
- };
209
- } else if (fieldOpt) {
210
- return {
211
- ...field,
212
- isHidden: fieldOpt.isHidden
213
- };
214
- } else {
215
- return field;
216
- }
217
- });
218
-
219
- const columnOrderings = tableConfig.columnOrderings;
220
- if (columnOrderings) {
221
- const fieldsWithOrders = [];
222
- const fieldsWithoutOrder = [];
223
- // if a new field has been added since the orderings were set then we want
224
- // it to be at the end instead of the beginning
225
- schema.fields.forEach(field => {
226
- if (columnOrderings.indexOf(field.path) > -1) {
227
- fieldsWithOrders.push(field);
228
- } else {
229
- fieldsWithoutOrder.push(field);
230
- }
231
- });
232
- schema.fields = fieldsWithOrders
233
- .sort(({ path: path1 }, { path: path2 }) => {
234
- return (
235
- columnOrderings.indexOf(path1) - columnOrderings.indexOf(path2)
236
- );
237
- })
238
- .concat(fieldsWithoutOrder);
239
- setTableConfig(prev => ({
240
- ...prev,
241
- columnOrderings: schema.fields.map(f => f.path)
242
- }));
243
- }
244
- }
245
- return { schema };
246
- }, [
247
- _schema,
248
- cellRenderer,
249
- entities,
250
- isInfinite,
251
- isOpenable,
252
- isSimple,
253
- isViewable,
254
- showForcedHiddenColumns,
255
- tableConfig,
256
- withDisplayOptions
257
- ]);
258
-
259
- const selectedEntities = withSelectedEntities
260
- ? getRecordsFromIdMap(reduxFormSelectedEntityIdMap)
261
- : undefined;
262
-
263
- const currentParams = urlConnected
264
- ? getCurrentParamsFromUrl(history.location) //important to use history location and not ownProps.location because for some reason the location path lags one render behind!!
265
- : reduxFormQueryParams;
266
-
267
- currentParams.searchTerm = reduxFormSearchInput;
268
-
269
- props = {
270
- ...props,
271
- ...getQueryParams({
272
- doNotCoercePageSize,
273
- currentParams,
274
- entities: props.entities, // for local table
275
- urlConnected,
276
- defaults: props.defaults,
277
- schema: convertedSchema,
278
- isInfinite,
279
- isLocalCall,
280
- additionalFilter: additionalFilterToUse,
281
- additionalOrFilter: additionalOrFilterToUse,
282
- noOrderError: props.noOrderError,
283
- isCodeModel: props.isCodeModel,
284
- ownProps: props
285
- })
286
- };
287
-
288
- const dispatch = useDispatch();
289
- let tableParams;
290
- if (!isTableParamsConnected) {
291
- const updateSearch = val => {
292
- setTimeout(() => {
293
- dispatch(change(formName, "reduxFormSearchInput", val || ""));
294
- });
295
- };
296
-
297
- let setNewParams;
298
- if (urlConnected) {
299
- setNewParams = newParams => {
300
- setCurrentParamsOnUrl(newParams, history.replace);
301
- dispatch(change(formName, "reduxFormQueryParams", newParams)); //we always will update the redux params as a workaround for withRouter not always working if inside a redux-connected container https://github.com/ReactTraining/react-router/issues/5037
302
- };
303
- } else {
304
- setNewParams = function (newParams) {
305
- dispatch(change(formName, "reduxFormQueryParams", newParams));
306
- };
307
- }
308
-
309
- const bindThese = makeDataTableHandlers({
310
- setNewParams,
311
- updateSearch,
312
- defaults,
313
- onlyOneFilter
314
- });
315
-
316
- const boundDispatchProps = {};
317
- //bind currentParams to actions
318
- Object.keys(bindThese).forEach(function (key) {
319
- const action = bindThese[key];
320
- boundDispatchProps[key] = function (...args) {
321
- action(...args, currentParams);
322
- };
323
- });
324
-
325
- const changeFormValue = (...args) => dispatch(change(formName, ...args));
326
-
327
- tableParams = {
328
- changeFormValue,
329
- selectedEntities,
330
- ..._tableParams,
331
- ...props,
332
- ...boundDispatchProps,
333
- form: formName, //this will override the default redux form name
334
- isTableParamsConnected: true //let the table know not to do local sorting/filtering etc.
335
- };
336
- }
337
-
338
- const formTracker = useContext(TableFormTrackerContext);
339
- useEffect(() => {
340
- if (formTracker.isActive && !formTracker.formNames.includes(formName)) {
341
- formTracker.pushFormName(formName);
342
- }
343
- }, [formTracker, formName]);
344
-
345
- return {
346
- ...props,
347
- selectedEntities,
348
- tableParams,
349
- currentParams,
350
- schema,
351
- entities,
352
- reduxFormSearchInput,
353
- onlyShowRowsWErrors,
354
- reduxFormCellValidation,
355
- reduxFormSelectedCells,
356
- reduxFormSelectedEntityIdMap,
357
- reduxFormQueryParams,
358
- showForcedHiddenColumns,
359
- setShowForcedHidden
360
- };
361
- }