@teselagen/ui 0.7.32 → 0.7.33-beta.1
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/DataTable/utils/filterLocalEntitiesToHasura.d.ts +5 -0
- package/DataTable/utils/initializeHasuraWhereAndFilter.d.ts +2 -0
- package/DataTable/utils/queryParams.d.ts +8 -12
- package/DataTable/utils/simplifyHasuraWhere.d.ts +1 -0
- package/DataTable/utils/tableQueryParamsToHasuraClauses.d.ts +14 -0
- package/{src/DataTable/FilterAndSortMenu.js → FilterAndSortMenu.js} +27 -30
- package/filterLocalEntitiesToHasura.js +216 -0
- package/index.cjs.js +695 -967
- package/index.d.ts +1 -0
- package/index.es.js +695 -967
- package/initializeHasuraWhereAndFilter.js +27 -0
- package/{src/utils/isBeingCalledExcessively.js → isBeingCalledExcessively.js} +0 -1
- package/package.json +1 -1
- package/queryParams.js +336 -0
- package/simplifyHasuraWhere.js +80 -0
- package/tableQueryParamsToHasuraClauses.js +113 -0
- package/{src/DataTable/utils/withTableParams.js → withTableParams.js} +1 -14
- package/src/AdvancedOptions.spec.js +0 -26
- package/src/AsyncValidateFieldSpinner/index.js +0 -12
- package/src/BlueprintError/index.js +0 -14
- package/src/BounceLoader/index.js +0 -16
- package/src/BounceLoader/style.css +0 -45
- package/src/CollapsibleCard/index.js +0 -68
- package/src/CollapsibleCard/style.css +0 -23
- package/src/DNALoader/index.js +0 -20
- package/src/DNALoader/style.css +0 -251
- package/src/DataTable/index.js +0 -3213
- package/src/DataTable/style.css +0 -608
- package/src/DataTable/utils/index.js +0 -55
- package/src/DataTable/utils/queryParams.js +0 -1058
- package/src/DialogFooter/index.js +0 -86
- package/src/DialogFooter/style.css +0 -9
- package/src/FormComponents/index.js +0 -1266
- package/src/FormComponents/style.css +0 -275
- package/src/FormComponents/utils.js +0 -6
- package/src/HotkeysDialog/index.js +0 -79
- package/src/HotkeysDialog/style.css +0 -54
- package/src/InfoHelper/index.js +0 -78
- package/src/InfoHelper/style.css +0 -7
- package/src/IntentText/index.js +0 -18
- package/src/Loading/index.js +0 -70
- package/src/Loading/style.css +0 -4
- package/src/MenuBar/index.js +0 -423
- package/src/MenuBar/style.css +0 -45
- package/src/PromptUnsavedChanges/index.js +0 -38
- package/src/ResizableDraggableDialog/index.js +0 -141
- package/src/ResizableDraggableDialog/style.css +0 -42
- package/src/ScrollToTop/index.js +0 -72
- package/src/TagSelect/index.js +0 -69
- package/src/TagSelect/style.css +0 -13
- package/src/TgHtmlSelect/index.js +0 -20
- package/src/TgSelect/index.js +0 -537
- package/src/TgSelect/style.css +0 -61
- package/src/TgSuggest/index.js +0 -124
- package/src/Timeline/index.js +0 -15
- package/src/enhancers/withDialog/index.js +0 -196
- package/src/index.js +0 -87
- package/src/showConfirmationDialog/index.js +0 -148
- package/src/style.css +0 -265
- /package/{src/AdvancedOptions.js → AdvancedOptions.js} +0 -0
- /package/{src/AssignDefaultsModeContext.js → AssignDefaultsModeContext.js} +0 -0
- /package/{src/DataTable/CellDragHandle.js → CellDragHandle.js} +0 -0
- /package/{src/DataTable/ColumnFilterMenu.js → ColumnFilterMenu.js} +0 -0
- /package/{src/DataTable/Columns.js → Columns.js} +0 -0
- /package/{src/DataTable/DisabledLoadingComponent.js → DisabledLoadingComponent.js} +0 -0
- /package/{src/DataTable/DisplayOptions.js → DisplayOptions.js} +0 -0
- /package/{src/DropdownButton.js → DropdownButton.js} +0 -0
- /package/{src/DataTable/DropdownCell.js → DropdownCell.js} +0 -0
- /package/{src/DataTable/EditableCell.js → EditableCell.js} +0 -0
- /package/{src/FillWindow.css → FillWindow.css} +0 -0
- /package/{src/FillWindow.js → FillWindow.js} +0 -0
- /package/{src/FormComponents/FormSeparator.js → FormSeparator.js} +0 -0
- /package/{src/FormComponents/LoadingDots.js → LoadingDots.js} +0 -0
- /package/{src/MatchHeaders.js → MatchHeaders.js} +0 -0
- /package/{src/DataTable/PagingTool.js → PagingTool.js} +0 -0
- /package/{src/DataTable/RenderCell.js → RenderCell.js} +0 -0
- /package/{src/DataTable/SearchBar.js → SearchBar.js} +0 -0
- /package/{src/SimpleStepViz.js → SimpleStepViz.js} +0 -0
- /package/{src/DataTable/SortableColumns.js → SortableColumns.js} +0 -0
- /package/{src/DataTable/TableFormTrackerContext.js → TableFormTrackerContext.js} +0 -0
- /package/{src/Tag.js → Tag.js} +0 -0
- /package/{src/DataTable/ThComponent.js → ThComponent.js} +0 -0
- /package/{src/Timeline/TimelineEvent.js → TimelineEvent.js} +0 -0
- /package/{src/UploadCsvWizard.css → UploadCsvWizard.css} +0 -0
- /package/{src/UploadCsvWizard.js → UploadCsvWizard.js} +0 -0
- /package/{src/FormComponents/Uploader.js → Uploader.js} +0 -0
- /package/{src/utils/adHoc.js → adHoc.js} +0 -0
- /package/{src/autoTooltip.js → autoTooltip.js} +0 -0
- /package/{src/utils/basicHandleActionsWithFullState.js → basicHandleActionsWithFullState.js} +0 -0
- /package/{src/utils/browserUtils.js → browserUtils.js} +0 -0
- /package/{src/utils/combineReducersWithFullState.js → combineReducersWithFullState.js} +0 -0
- /package/{src/utils/commandControls.js → commandControls.js} +0 -0
- /package/{src/utils/commandUtils.js → commandUtils.js} +0 -0
- /package/{src/constants.js → constants.js} +0 -0
- /package/{src/DataTable/utils/convertSchema.js → convertSchema.js} +0 -0
- /package/{src/customIcons.js → customIcons.js} +0 -0
- /package/{src/DataTable/dataTableEnhancer.js → dataTableEnhancer.js} +0 -0
- /package/{src/DataTable/defaultFormatters.js → defaultFormatters.js} +0 -0
- /package/{src/DataTable/defaultValidators.js → defaultValidators.js} +0 -0
- /package/{src/utils/determineBlackOrWhiteTextColor.js → determineBlackOrWhiteTextColor.js} +0 -0
- /package/{src/DataTable/editCellHelper.js → editCellHelper.js} +0 -0
- /package/{src/DataTable/utils/formatPasteData.js → formatPasteData.js} +0 -0
- /package/{src/DataTable/utils/getAllRows.js → getAllRows.js} +0 -0
- /package/{src/DataTable/utils/getCellCopyText.js → getCellCopyText.js} +0 -0
- /package/{src/DataTable/utils/getCellInfo.js → getCellInfo.js} +0 -0
- /package/{src/DataTable/getCellVal.js → getCellVal.js} +0 -0
- /package/{src/utils/getDayjsFormatter.js → getDayjsFormatter.js} +0 -0
- /package/{src/DataTable/utils/getFieldPathToField.js → getFieldPathToField.js} +0 -0
- /package/{src/DataTable/utils/getIdOrCodeOrIndex.js → getIdOrCodeOrIndex.js} +0 -0
- /package/{src/DataTable/utils/getLastSelectedEntity.js → getLastSelectedEntity.js} +0 -0
- /package/{src/DataTable/utils/getNewEntToSelect.js → getNewEntToSelect.js} +0 -0
- /package/{src/FormComponents/getNewName.js → getNewName.js} +0 -0
- /package/{src/DataTable/utils/getRowCopyText.js → getRowCopyText.js} +0 -0
- /package/{src/DataTable/utils/getTableConfigFromStorage.js → getTableConfigFromStorage.js} +0 -0
- /package/{src/utils/getTextFromEl.js → getTextFromEl.js} +0 -0
- /package/{src/DataTable/getVals.js → getVals.js} +0 -0
- /package/{src/DataTable/utils/handleCopyColumn.js → handleCopyColumn.js} +0 -0
- /package/{src/DataTable/utils/handleCopyHelper.js → handleCopyHelper.js} +0 -0
- /package/{src/DataTable/utils/handleCopyRows.js → handleCopyRows.js} +0 -0
- /package/{src/DataTable/utils/handleCopyTable.js → handleCopyTable.js} +0 -0
- /package/{src/utils/handlerHelpers.js → handlerHelpers.js} +0 -0
- /package/{src/utils/hotkeyUtils.js → hotkeyUtils.js} +0 -0
- /package/{src/utils/hooks/index.js → index.js} +0 -0
- /package/{src/DataTable/utils/isBottomRightCornerOfRectangle.js → isBottomRightCornerOfRectangle.js} +0 -0
- /package/{src/DataTable/utils/isEntityClean.js → isEntityClean.js} +0 -0
- /package/{src/DataTable/isTruthy.js → isTruthy.js} +0 -0
- /package/{src/DataTable/isValueEmpty.js → isValueEmpty.js} +0 -0
- /package/{src/FormComponents/itemUpload.js → itemUpload.js} +0 -0
- /package/{src/utils/menuUtils.js → menuUtils.js} +0 -0
- /package/{src/utils/popoverOverflowModifiers.js → popoverOverflowModifiers.js} +0 -0
- /package/{src/DataTable/utils/primarySelectedValue.js → primarySelectedValue.js} +0 -0
- /package/{src/utils/pureNoFunc.js → pureNoFunc.js} +0 -0
- /package/{src/DataTable/utils/removeCleanRows.js → removeCleanRows.js} +0 -0
- /package/{src/utils/renderOnDoc.js → renderOnDoc.js} +0 -0
- /package/{src/rerenderOnWindowResize.js → rerenderOnWindowResize.js} +0 -0
- /package/{src/DataTable/utils/rowClick.js → rowClick.js} +0 -0
- /package/{src/DataTable/utils/selection.js → selection.js} +0 -0
- /package/{src/showAppSpinner.js → showAppSpinner.js} +0 -0
- /package/{src/showDialogOnDocBody.js → showDialogOnDocBody.js} +0 -0
- /package/{src/utils/showProgressToast.js → showProgressToast.js} +0 -0
- /package/{src/FormComponents/sortify.js → sortify.js} +0 -0
- /package/{src/Timeline/style.css → style.css} +0 -0
- /package/{src/utils/tagUtils.js → tagUtils.js} +0 -0
- /package/{src/utils/tgFormValues.js → tgFormValues.js} +0 -0
- /package/{src/enhancers/withDialog/tg_modalState.js → tg_modalState.js} +0 -0
- /package/{src/throwFormError.js → throwFormError.js} +0 -0
- /package/{src/toastr.js → toastr.js} +0 -0
- /package/{src/FormComponents/tryToMatchSchemas.js → tryToMatchSchemas.js} +0 -0
- /package/{src/typeToCommonType.js → typeToCommonType.js} +0 -0
- /package/{src/utils/hooks/useDeepEqualMemo.js → useDeepEqualMemo.js} +0 -0
- /package/{src/useDialog.js → useDialog.js} +0 -0
- /package/{src/utils/hooks/useStableReference.js → useStableReference.js} +0 -0
- /package/{src/DataTable/utils/useTableEntities.js → useTableEntities.js} +0 -0
- /package/{src/utils/useTraceUpdate.js → useTraceUpdate.js} +0 -0
- /package/{src/DataTable/utils/utils.js → utils.js} +0 -0
- /package/{src/DataTable/validateTableWideErrors.js → validateTableWideErrors.js} +0 -0
- /package/{src/DataTable/viewColumn.js → viewColumn.js} +0 -0
- /package/{src/enhancers/withField.js → withField.js} +0 -0
- /package/{src/enhancers/withFields.js → withFields.js} +0 -0
- /package/{src/enhancers/withLocalStorage.js → withLocalStorage.js} +0 -0
- /package/{src/utils/withSelectTableRecords.js → withSelectTableRecords.js} +0 -0
- /package/{src/DataTable/utils/withSelectedEntities.js → withSelectedEntities.js} +0 -0
- /package/{src/utils/withStore.js → withStore.js} +0 -0
- /package/{src/wrapDialog.js → wrapDialog.js} +0 -0
package/src/DataTable/index.js
DELETED
|
@@ -1,3213 +0,0 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
useEffect,
|
|
3
|
-
useRef,
|
|
4
|
-
useMemo,
|
|
5
|
-
useState,
|
|
6
|
-
useCallback,
|
|
7
|
-
useContext
|
|
8
|
-
} from "react";
|
|
9
|
-
import {
|
|
10
|
-
invert,
|
|
11
|
-
toNumber,
|
|
12
|
-
isEmpty,
|
|
13
|
-
min,
|
|
14
|
-
max,
|
|
15
|
-
camelCase,
|
|
16
|
-
startCase,
|
|
17
|
-
noop,
|
|
18
|
-
cloneDeep,
|
|
19
|
-
keyBy,
|
|
20
|
-
omit,
|
|
21
|
-
forEach,
|
|
22
|
-
lowerCase,
|
|
23
|
-
get,
|
|
24
|
-
omitBy,
|
|
25
|
-
times,
|
|
26
|
-
toArray,
|
|
27
|
-
isFunction,
|
|
28
|
-
isEqual,
|
|
29
|
-
every,
|
|
30
|
-
some
|
|
31
|
-
} from "lodash-es";
|
|
32
|
-
import {
|
|
33
|
-
Button,
|
|
34
|
-
Menu,
|
|
35
|
-
MenuItem,
|
|
36
|
-
ContextMenu,
|
|
37
|
-
Icon,
|
|
38
|
-
Intent,
|
|
39
|
-
Callout,
|
|
40
|
-
Tooltip,
|
|
41
|
-
useHotkeys
|
|
42
|
-
} from "@blueprintjs/core";
|
|
43
|
-
import { arrayMove } from "@dnd-kit/sortable";
|
|
44
|
-
import classNames from "classnames";
|
|
45
|
-
import scrollIntoView from "dom-scroll-into-view";
|
|
46
|
-
import ReactTable from "@teselagen/react-table";
|
|
47
|
-
import immer, { produceWithPatches, enablePatches, applyPatches } from "immer";
|
|
48
|
-
import papaparse from "papaparse";
|
|
49
|
-
import { useDispatch, useSelector } from "react-redux";
|
|
50
|
-
import { ThComponent } from "./ThComponent";
|
|
51
|
-
import {
|
|
52
|
-
defaultParsePaste,
|
|
53
|
-
formatPasteData,
|
|
54
|
-
getAllRows,
|
|
55
|
-
getCellCopyText,
|
|
56
|
-
getCellInfo,
|
|
57
|
-
getEntityIdToEntity,
|
|
58
|
-
getFieldPathToIndex,
|
|
59
|
-
getIdOrCodeOrIndex,
|
|
60
|
-
getLastSelectedEntity,
|
|
61
|
-
getNewEntToSelect,
|
|
62
|
-
getRecordsFromIdMap,
|
|
63
|
-
getRowCopyText,
|
|
64
|
-
handleCopyColumn,
|
|
65
|
-
handleCopyHelper,
|
|
66
|
-
handleCopyRows,
|
|
67
|
-
handleCopyTable,
|
|
68
|
-
isEntityClean,
|
|
69
|
-
PRIMARY_SELECTED_VAL,
|
|
70
|
-
removeCleanRows
|
|
71
|
-
} from "./utils";
|
|
72
|
-
import { useDeepEqualMemo } from "../utils/hooks";
|
|
73
|
-
import rowClick, {
|
|
74
|
-
changeSelectedEntities,
|
|
75
|
-
finalizeSelection
|
|
76
|
-
} from "./utils/rowClick";
|
|
77
|
-
import PagingTool from "./PagingTool";
|
|
78
|
-
import SearchBar from "./SearchBar";
|
|
79
|
-
import DisplayOptions from "./DisplayOptions";
|
|
80
|
-
import DisabledLoadingComponent from "./DisabledLoadingComponent";
|
|
81
|
-
import SortableColumns from "./SortableColumns";
|
|
82
|
-
import dataTableEnhancer from "./dataTableEnhancer";
|
|
83
|
-
import "../toastr";
|
|
84
|
-
import "@teselagen/react-table/react-table.css";
|
|
85
|
-
import "./style.css";
|
|
86
|
-
import { nanoid } from "nanoid";
|
|
87
|
-
import { SwitchField } from "../FormComponents";
|
|
88
|
-
import { validateTableWideErrors } from "./validateTableWideErrors";
|
|
89
|
-
import { editCellHelper } from "./editCellHelper";
|
|
90
|
-
import getTableConfigFromStorage from "./utils/getTableConfigFromStorage";
|
|
91
|
-
import { viewColumn, openColumn, multiViewColumn } from "./viewColumn";
|
|
92
|
-
import convertSchema from "./utils/convertSchema";
|
|
93
|
-
import TableFormTrackerContext from "./TableFormTrackerContext";
|
|
94
|
-
import {
|
|
95
|
-
getCCDisplayName,
|
|
96
|
-
getCurrentParamsFromUrl,
|
|
97
|
-
getQueryParams,
|
|
98
|
-
makeDataTableHandlers,
|
|
99
|
-
setCurrentParamsOnUrl
|
|
100
|
-
} from "./utils/queryParams";
|
|
101
|
-
import { useColumns } from "./Columns";
|
|
102
|
-
import { formValueSelector, change as _change } from "redux-form";
|
|
103
|
-
import { throwFormError } from "../throwFormError";
|
|
104
|
-
import { isObservableArray, toJS } from "mobx";
|
|
105
|
-
import { isBeingCalledExcessively } from "../utils/isBeingCalledExcessively";
|
|
106
|
-
|
|
107
|
-
enablePatches();
|
|
108
|
-
const IS_LINUX = window.navigator.platform.toLowerCase().search("linux") > -1;
|
|
109
|
-
|
|
110
|
-
const itemSizeEstimators = {
|
|
111
|
-
compact: () => 25.34,
|
|
112
|
-
normal: () => 33.34,
|
|
113
|
-
comfortable: () => 41.34
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const DataTable = ({
|
|
117
|
-
controlled_pageSize,
|
|
118
|
-
formName = "tgDataTable",
|
|
119
|
-
history,
|
|
120
|
-
isSimple,
|
|
121
|
-
isLocalCall = true,
|
|
122
|
-
isTableParamsConnected,
|
|
123
|
-
noForm,
|
|
124
|
-
orderByFirstColumn,
|
|
125
|
-
schema: _schema,
|
|
126
|
-
showEmptyColumnsByDefault,
|
|
127
|
-
tableParams: _tableParams,
|
|
128
|
-
anyTouched,
|
|
129
|
-
blur,
|
|
130
|
-
...ownProps
|
|
131
|
-
}) => {
|
|
132
|
-
if (isTableParamsConnected && _tableParams && !_tableParams.entities) {
|
|
133
|
-
throw new Error(
|
|
134
|
-
`No entities array detected in tableParams object (<DataTable {...tableParams}/>). You need to call withQuery() after withTableParams() like: compose(withTableParams(), withQuery(something)).`
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
const dispatch = useDispatch();
|
|
138
|
-
const change = useCallback(
|
|
139
|
-
(...args) => dispatch(_change(formName, ...args)),
|
|
140
|
-
[dispatch, formName]
|
|
141
|
-
);
|
|
142
|
-
const tableRef = useRef();
|
|
143
|
-
const alreadySelected = useRef(false);
|
|
144
|
-
const [onlyShowRowsWErrors, setOnlyShowRowsWErrors] = useState(false);
|
|
145
|
-
const [entitiesUndoRedoStack, setEntitiesUndoRedoStack] = useState({
|
|
146
|
-
currentVersion: 0
|
|
147
|
-
});
|
|
148
|
-
const [selectedCells, setSelectedCells] = useState({});
|
|
149
|
-
const _tableConfig = getTableConfigFromStorage(formName);
|
|
150
|
-
// make user set page size persist
|
|
151
|
-
const userSetPageSize =
|
|
152
|
-
_tableConfig?.userSetPageSize && parseInt(_tableConfig.userSetPageSize, 10);
|
|
153
|
-
|
|
154
|
-
const formTracker = useContext(TableFormTrackerContext);
|
|
155
|
-
useEffect(() => {
|
|
156
|
-
if (formTracker.isActive && !formTracker.formNames.includes(formName)) {
|
|
157
|
-
formTracker.pushFormName(formName);
|
|
158
|
-
}
|
|
159
|
-
}, [formTracker, formName]);
|
|
160
|
-
|
|
161
|
-
const [showForcedHiddenColumns, setShowForcedHidden] = useState(() => {
|
|
162
|
-
if (showEmptyColumnsByDefault) {
|
|
163
|
-
return true;
|
|
164
|
-
}
|
|
165
|
-
return false;
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
const {
|
|
169
|
-
reduxFormCellValidation: _reduxFormCellValidation,
|
|
170
|
-
reduxFormEditingCell,
|
|
171
|
-
reduxFormEntities,
|
|
172
|
-
reduxFormQueryParams: _reduxFormQueryParams = {},
|
|
173
|
-
reduxFormSelectedEntityIdMap: _reduxFormSelectedEntityIdMap = {}
|
|
174
|
-
} = useSelector(state =>
|
|
175
|
-
formValueSelector(formName)(
|
|
176
|
-
state,
|
|
177
|
-
"reduxFormCellValidation",
|
|
178
|
-
"reduxFormEntities",
|
|
179
|
-
"reduxFormQueryParams",
|
|
180
|
-
"reduxFormSelectedEntityIdMap"
|
|
181
|
-
)
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
// We want to make sure we don't rerender everything unnecessary
|
|
185
|
-
// with redux-forms we tend to do unnecessary renders
|
|
186
|
-
const reduxFormCellValidation = useDeepEqualMemo(_reduxFormCellValidation);
|
|
187
|
-
const reduxFormQueryParams = useDeepEqualMemo(_reduxFormQueryParams);
|
|
188
|
-
const reduxFormSelectedEntityIdMap = useDeepEqualMemo(
|
|
189
|
-
_reduxFormSelectedEntityIdMap
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
let props = ownProps;
|
|
193
|
-
if (!isTableParamsConnected) {
|
|
194
|
-
// When using mobx values we need to transform it to a js array instead of a proxy so the next hooks get the right values
|
|
195
|
-
const normalizedEntities = isObservableArray(ownProps.entities)
|
|
196
|
-
? toJS(ownProps.entities)
|
|
197
|
-
: ownProps.entities;
|
|
198
|
-
//this is the case where we're hooking up to withTableParams locally, so we need to take the tableParams off the props
|
|
199
|
-
props = {
|
|
200
|
-
...ownProps,
|
|
201
|
-
..._tableParams,
|
|
202
|
-
entities: normalizedEntities
|
|
203
|
-
};
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const convertedSchema = useMemo(() => convertSchema(_schema), [_schema]);
|
|
207
|
-
|
|
208
|
-
if (isLocalCall) {
|
|
209
|
-
if (!noForm && (!formName || formName === "tgDataTable")) {
|
|
210
|
-
throw new Error(
|
|
211
|
-
"Please pass a unique 'formName' prop to the locally connected <DataTable/> component with schema: ",
|
|
212
|
-
_schema
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
} else {
|
|
216
|
-
//in user instantiated withTableParams() call
|
|
217
|
-
if (!formName || formName === "tgDataTable") {
|
|
218
|
-
throw new Error(
|
|
219
|
-
"Please pass a unique 'formName' prop to the withTableParams() with schema: ",
|
|
220
|
-
_schema
|
|
221
|
-
);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const { withPaging = !isSimple } = props;
|
|
226
|
-
const {
|
|
227
|
-
doNotCoercePageSize,
|
|
228
|
-
isInfinite = isSimple && !withPaging,
|
|
229
|
-
syncDisplayOptionsToDb,
|
|
230
|
-
urlConnected,
|
|
231
|
-
withSelectedEntities
|
|
232
|
-
} = props;
|
|
233
|
-
|
|
234
|
-
const defaults = useMemo(() => {
|
|
235
|
-
const _defaults = {
|
|
236
|
-
pageSize: controlled_pageSize || 25,
|
|
237
|
-
order: [], // ["-name", "statusCode"] //an array of camelCase display names with - sign to denote reverse
|
|
238
|
-
searchTerm: "",
|
|
239
|
-
page: 1,
|
|
240
|
-
filters: [
|
|
241
|
-
// filters look like this:
|
|
242
|
-
// {
|
|
243
|
-
// selectedFilter: 'textContains', //camel case
|
|
244
|
-
// filterOn: ccDisplayName, //camel case display name
|
|
245
|
-
// filterValue: 'thomas',
|
|
246
|
-
// }
|
|
247
|
-
],
|
|
248
|
-
...(props.defaults || {})
|
|
249
|
-
};
|
|
250
|
-
if (isLocalCall && orderByFirstColumn && !_defaults?.order?.length) {
|
|
251
|
-
const r = [getCCDisplayName(convertedSchema.fields[0])];
|
|
252
|
-
_defaults.order = r;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (!syncDisplayOptionsToDb && userSetPageSize) {
|
|
256
|
-
_defaults.pageSize = userSetPageSize;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return _defaults;
|
|
260
|
-
}, [
|
|
261
|
-
controlled_pageSize,
|
|
262
|
-
convertedSchema.fields,
|
|
263
|
-
isLocalCall,
|
|
264
|
-
orderByFirstColumn,
|
|
265
|
-
props.defaults,
|
|
266
|
-
syncDisplayOptionsToDb,
|
|
267
|
-
userSetPageSize
|
|
268
|
-
]);
|
|
269
|
-
|
|
270
|
-
const selectedEntities = withSelectedEntities
|
|
271
|
-
? getRecordsFromIdMap(reduxFormSelectedEntityIdMap)
|
|
272
|
-
: undefined;
|
|
273
|
-
|
|
274
|
-
props = {
|
|
275
|
-
...props,
|
|
276
|
-
...(withSelectedEntities &&
|
|
277
|
-
typeof withSelectedEntities === "string" && {
|
|
278
|
-
[withSelectedEntities]: selectedEntities
|
|
279
|
-
})
|
|
280
|
-
};
|
|
281
|
-
|
|
282
|
-
const _currentParams = useMemo(() => {
|
|
283
|
-
const tmp =
|
|
284
|
-
(urlConnected
|
|
285
|
-
? getCurrentParamsFromUrl(history.location) //important to use history location and not ownProps.location because for some reason the location path lags one render behind!!
|
|
286
|
-
: reduxFormQueryParams) || {};
|
|
287
|
-
return tmp;
|
|
288
|
-
}, [history, reduxFormQueryParams, urlConnected]);
|
|
289
|
-
|
|
290
|
-
const currentParams = useDeepEqualMemo(_currentParams);
|
|
291
|
-
|
|
292
|
-
const tableParams = useMemo(() => {
|
|
293
|
-
if (!isTableParamsConnected) {
|
|
294
|
-
const setNewParams = newParams => {
|
|
295
|
-
// we always will update the redux params as a workaround for withRouter not always working
|
|
296
|
-
// if inside a redux-connected container https://github.com/ReactTraining/react-router/issues/5037
|
|
297
|
-
change("reduxFormQueryParams", prev => {
|
|
298
|
-
let tmp = newParams;
|
|
299
|
-
if (typeof tmp === "function") tmp = newParams(prev);
|
|
300
|
-
urlConnected && setCurrentParamsOnUrl(tmp, history?.replace);
|
|
301
|
-
return tmp;
|
|
302
|
-
});
|
|
303
|
-
};
|
|
304
|
-
|
|
305
|
-
const dispatchProps = makeDataTableHandlers({
|
|
306
|
-
setNewParams,
|
|
307
|
-
defaults,
|
|
308
|
-
onlyOneFilter: props.onlyOneFilter
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
const changeFormValue = (...args) => change(...args);
|
|
312
|
-
|
|
313
|
-
return {
|
|
314
|
-
changeFormValue,
|
|
315
|
-
selectedEntities,
|
|
316
|
-
..._tableParams,
|
|
317
|
-
...dispatchProps,
|
|
318
|
-
isTableParamsConnected: true //let the table know not to do local sorting/filtering etc.
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
return _tableParams;
|
|
322
|
-
}, [
|
|
323
|
-
_tableParams,
|
|
324
|
-
change,
|
|
325
|
-
defaults,
|
|
326
|
-
history?.replace,
|
|
327
|
-
isTableParamsConnected,
|
|
328
|
-
props.onlyOneFilter,
|
|
329
|
-
selectedEntities,
|
|
330
|
-
urlConnected
|
|
331
|
-
]);
|
|
332
|
-
|
|
333
|
-
props = {
|
|
334
|
-
...props,
|
|
335
|
-
...tableParams
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
const queryParams = useMemo(() => {
|
|
339
|
-
if (!isTableParamsConnected) {
|
|
340
|
-
const additionalFilterToUse =
|
|
341
|
-
typeof props.additionalFilter === "function"
|
|
342
|
-
? props.additionalFilter
|
|
343
|
-
: () => props.additionalFilter;
|
|
344
|
-
|
|
345
|
-
const additionalOrFilterToUse =
|
|
346
|
-
typeof props.additionalOrFilter === "function"
|
|
347
|
-
? props.additionalOrFilter
|
|
348
|
-
: () => props.additionalOrFilter;
|
|
349
|
-
|
|
350
|
-
return getQueryParams({
|
|
351
|
-
doNotCoercePageSize,
|
|
352
|
-
currentParams,
|
|
353
|
-
entities: props.entities, // for local table
|
|
354
|
-
urlConnected,
|
|
355
|
-
defaults,
|
|
356
|
-
schema: convertedSchema,
|
|
357
|
-
isInfinite,
|
|
358
|
-
isLocalCall,
|
|
359
|
-
additionalFilter: additionalFilterToUse,
|
|
360
|
-
additionalOrFilter: additionalOrFilterToUse,
|
|
361
|
-
noOrderError: props.noOrderError,
|
|
362
|
-
isCodeModel: props.isCodeModel,
|
|
363
|
-
ownProps: props
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
return {};
|
|
367
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
368
|
-
}, [
|
|
369
|
-
props.entities,
|
|
370
|
-
props.noOrderError,
|
|
371
|
-
props.isCodeModel,
|
|
372
|
-
convertedSchema,
|
|
373
|
-
currentParams,
|
|
374
|
-
doNotCoercePageSize,
|
|
375
|
-
isInfinite,
|
|
376
|
-
isLocalCall,
|
|
377
|
-
isTableParamsConnected,
|
|
378
|
-
urlConnected
|
|
379
|
-
]);
|
|
380
|
-
|
|
381
|
-
props = {
|
|
382
|
-
...props,
|
|
383
|
-
...queryParams
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
const {
|
|
387
|
-
addFilters = noop,
|
|
388
|
-
additionalFilters,
|
|
389
|
-
additionalFooterButtons,
|
|
390
|
-
autoFocusSearch,
|
|
391
|
-
cellRenderer,
|
|
392
|
-
children,
|
|
393
|
-
className = "",
|
|
394
|
-
clearFilters = noop,
|
|
395
|
-
compact: _compact = true,
|
|
396
|
-
compactPaging,
|
|
397
|
-
contextMenu = noop,
|
|
398
|
-
controlled_hasNextPage,
|
|
399
|
-
controlled_onRefresh,
|
|
400
|
-
controlled_page,
|
|
401
|
-
controlled_setPage,
|
|
402
|
-
controlled_setPageSize,
|
|
403
|
-
controlled_total,
|
|
404
|
-
currentUser,
|
|
405
|
-
deleteTableConfiguration,
|
|
406
|
-
disabled = false,
|
|
407
|
-
disableSetPageSize,
|
|
408
|
-
doNotShowEmptyRows,
|
|
409
|
-
doNotValidateUntouchedRows,
|
|
410
|
-
editingCellSelectAll,
|
|
411
|
-
entities: _origEntities = [],
|
|
412
|
-
entitiesAcrossPages: _entitiesAcrossPages,
|
|
413
|
-
entityCount,
|
|
414
|
-
errorParsingUrlString,
|
|
415
|
-
expandAllByDefault,
|
|
416
|
-
extraClasses = "",
|
|
417
|
-
extraCompact: _extraCompact,
|
|
418
|
-
filters = [],
|
|
419
|
-
fragment,
|
|
420
|
-
getCellHoverText,
|
|
421
|
-
getRowClassName,
|
|
422
|
-
helperProp,
|
|
423
|
-
hideColumnHeader,
|
|
424
|
-
hideDisplayOptionsIcon,
|
|
425
|
-
hidePageSizeWhenPossible = isSimple ? !withPaging : false,
|
|
426
|
-
hideSelectedCount = isSimple,
|
|
427
|
-
hideSetPageSize,
|
|
428
|
-
hideTotalPages,
|
|
429
|
-
selectedIds,
|
|
430
|
-
isCellEditable,
|
|
431
|
-
isCopyable = true,
|
|
432
|
-
isEntityDisabled = noop,
|
|
433
|
-
isLoading = false,
|
|
434
|
-
isOpenable,
|
|
435
|
-
isSingleSelect = false,
|
|
436
|
-
isViewable,
|
|
437
|
-
recordIdToIsVisibleMap,
|
|
438
|
-
setRecordIdToIsVisibleMap,
|
|
439
|
-
keepSelectionOnPageChange,
|
|
440
|
-
leftOfSearchBarItems,
|
|
441
|
-
maxHeight = 600,
|
|
442
|
-
minimalStyle,
|
|
443
|
-
mustClickCheckboxToSelect,
|
|
444
|
-
noDeselectAll,
|
|
445
|
-
noFooter = isSimple ? !withPaging : false,
|
|
446
|
-
noFullscreenButton = isSimple,
|
|
447
|
-
noHeader = false,
|
|
448
|
-
noPadding = isSimple,
|
|
449
|
-
noRowsFoundMessage,
|
|
450
|
-
noSelect = false,
|
|
451
|
-
noUserSelect,
|
|
452
|
-
onDeselect = noop,
|
|
453
|
-
onDoubleClick,
|
|
454
|
-
onMultiRowSelect = noop,
|
|
455
|
-
onRefresh,
|
|
456
|
-
onRowClick = noop,
|
|
457
|
-
onRowSelect = noop,
|
|
458
|
-
onSingleRowSelect = noop,
|
|
459
|
-
order,
|
|
460
|
-
page = 1,
|
|
461
|
-
pageSize: _pageSize = 10,
|
|
462
|
-
pagingDisabled,
|
|
463
|
-
removeSingleFilter,
|
|
464
|
-
ReactTableProps = {},
|
|
465
|
-
safeQuery,
|
|
466
|
-
searchMenuButton,
|
|
467
|
-
searchTerm,
|
|
468
|
-
selectAllByDefault,
|
|
469
|
-
setNewParams,
|
|
470
|
-
setOrder,
|
|
471
|
-
setPage = noop,
|
|
472
|
-
setPageSize = noop,
|
|
473
|
-
setSearchTerm = noop,
|
|
474
|
-
shouldShowSubComponent,
|
|
475
|
-
showCount = false,
|
|
476
|
-
style = {},
|
|
477
|
-
SubComponent,
|
|
478
|
-
subHeader,
|
|
479
|
-
tableConfigurations,
|
|
480
|
-
tableName,
|
|
481
|
-
topLeftItems,
|
|
482
|
-
upsertFieldOption,
|
|
483
|
-
upsertTableConfiguration,
|
|
484
|
-
variables,
|
|
485
|
-
withCheckboxes = false,
|
|
486
|
-
withDisplayOptions,
|
|
487
|
-
withExpandAndCollapseAllButton,
|
|
488
|
-
withFilter,
|
|
489
|
-
withSearch = !isSimple,
|
|
490
|
-
withSelectAll,
|
|
491
|
-
withSort,
|
|
492
|
-
withTitle = !isSimple,
|
|
493
|
-
noExcessiveCheck
|
|
494
|
-
} = props;
|
|
495
|
-
|
|
496
|
-
const _entities = useMemo(
|
|
497
|
-
() => (reduxFormEntities?.length ? reduxFormEntities : _origEntities) || [],
|
|
498
|
-
[_origEntities, reduxFormEntities]
|
|
499
|
-
);
|
|
500
|
-
|
|
501
|
-
const entities = useDeepEqualMemo(_entities);
|
|
502
|
-
|
|
503
|
-
const entitiesAcrossPages = useDeepEqualMemo(_entitiesAcrossPages);
|
|
504
|
-
|
|
505
|
-
// This is because we need to maintain the reduxFormSelectedEntityIdMap and
|
|
506
|
-
// allOrderedEntities updated
|
|
507
|
-
useEffect(() => {
|
|
508
|
-
!noExcessiveCheck && isBeingCalledExcessively({ uniqName: `dt_entities_${formName}` });
|
|
509
|
-
change("allOrderedEntities", entitiesAcrossPages);
|
|
510
|
-
if (entities.length === 0 || isEmpty(reduxFormSelectedEntityIdMap)) return;
|
|
511
|
-
changeSelectedEntities({
|
|
512
|
-
idMap: reduxFormSelectedEntityIdMap,
|
|
513
|
-
entities,
|
|
514
|
-
change
|
|
515
|
-
});
|
|
516
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
517
|
-
}, [entitiesAcrossPages, reduxFormSelectedEntityIdMap, change, noExcessiveCheck]);
|
|
518
|
-
|
|
519
|
-
const [tableConfig, setTableConfig] = useState({ fieldOptions: [] });
|
|
520
|
-
|
|
521
|
-
useEffect(() => {
|
|
522
|
-
if (withDisplayOptions) {
|
|
523
|
-
let newTableConfig = {};
|
|
524
|
-
if (syncDisplayOptionsToDb) {
|
|
525
|
-
newTableConfig = tableConfigurations && tableConfigurations[0];
|
|
526
|
-
} else {
|
|
527
|
-
newTableConfig = getTableConfigFromStorage(formName);
|
|
528
|
-
}
|
|
529
|
-
!noExcessiveCheck && isBeingCalledExcessively({ uniqName: `dt_setTableConfig_${formName}` });
|
|
530
|
-
// if the tableConfig is the same as the newTableConfig, don't update
|
|
531
|
-
setTableConfig(prev => {
|
|
532
|
-
if (!newTableConfig) {
|
|
533
|
-
newTableConfig = {
|
|
534
|
-
fieldOptions: []
|
|
535
|
-
};
|
|
536
|
-
if (isEqual(prev, newTableConfig)) {
|
|
537
|
-
return prev;
|
|
538
|
-
} else {
|
|
539
|
-
return newTableConfig;
|
|
540
|
-
}
|
|
541
|
-
} else {
|
|
542
|
-
return newTableConfig;
|
|
543
|
-
}
|
|
544
|
-
});
|
|
545
|
-
}
|
|
546
|
-
}, [
|
|
547
|
-
convertedSchema, // If the schema changes we want to take into account the synced tableConfig again
|
|
548
|
-
formName,
|
|
549
|
-
syncDisplayOptionsToDb,
|
|
550
|
-
tableConfigurations,
|
|
551
|
-
withDisplayOptions,
|
|
552
|
-
noExcessiveCheck
|
|
553
|
-
]);
|
|
554
|
-
|
|
555
|
-
const schema = useMemo(() => {
|
|
556
|
-
const schema = { ...convertedSchema };
|
|
557
|
-
if (isViewable) {
|
|
558
|
-
schema.fields = [viewColumn, ...schema.fields];
|
|
559
|
-
}
|
|
560
|
-
if (recordIdToIsVisibleMap) {
|
|
561
|
-
schema.fields = [multiViewColumn, ...schema.fields];
|
|
562
|
-
}
|
|
563
|
-
if (isOpenable) {
|
|
564
|
-
schema.fields = [
|
|
565
|
-
openColumn({ onDoubleClick, history }),
|
|
566
|
-
...schema.fields
|
|
567
|
-
];
|
|
568
|
-
}
|
|
569
|
-
// this must come before handling orderings.
|
|
570
|
-
schema.fields = schema.fields.map(field => {
|
|
571
|
-
if (field.placementPath) {
|
|
572
|
-
return {
|
|
573
|
-
...field,
|
|
574
|
-
sortDisabled:
|
|
575
|
-
field.sortDisabled ||
|
|
576
|
-
(typeof field.path === "string" && field.path.includes(".")),
|
|
577
|
-
path: field.placementPath
|
|
578
|
-
};
|
|
579
|
-
} else {
|
|
580
|
-
return field;
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
if (withDisplayOptions) {
|
|
585
|
-
const fieldOptsByPath = keyBy(tableConfig.fieldOptions, "path");
|
|
586
|
-
schema.fields = schema.fields.map(field => {
|
|
587
|
-
const fieldOpt = fieldOptsByPath[field.path];
|
|
588
|
-
let noValsForField = false;
|
|
589
|
-
// only add this hidden column ability if no paging
|
|
590
|
-
if (
|
|
591
|
-
!showForcedHiddenColumns &&
|
|
592
|
-
withDisplayOptions &&
|
|
593
|
-
(isSimple || isInfinite)
|
|
594
|
-
) {
|
|
595
|
-
noValsForField = entities.every(e => {
|
|
596
|
-
const val = get(e, field.path);
|
|
597
|
-
return field.render
|
|
598
|
-
? !field.render(val, e, undefined, {
|
|
599
|
-
currentParams,
|
|
600
|
-
setNewParams
|
|
601
|
-
})
|
|
602
|
-
: cellRenderer?.[field.path]
|
|
603
|
-
? !cellRenderer[field.path](val, e, undefined, {
|
|
604
|
-
currentParams,
|
|
605
|
-
setNewParams
|
|
606
|
-
})
|
|
607
|
-
: !val;
|
|
608
|
-
});
|
|
609
|
-
}
|
|
610
|
-
if (noValsForField) {
|
|
611
|
-
return {
|
|
612
|
-
...field,
|
|
613
|
-
isHidden: true,
|
|
614
|
-
isForcedHidden: true
|
|
615
|
-
};
|
|
616
|
-
} else if (fieldOpt) {
|
|
617
|
-
return {
|
|
618
|
-
...field,
|
|
619
|
-
isHidden: fieldOpt.isHidden
|
|
620
|
-
};
|
|
621
|
-
} else {
|
|
622
|
-
return field;
|
|
623
|
-
}
|
|
624
|
-
});
|
|
625
|
-
|
|
626
|
-
const columnOrderings = tableConfig.columnOrderings;
|
|
627
|
-
if (columnOrderings) {
|
|
628
|
-
const fieldsWithOrders = [];
|
|
629
|
-
const fieldsWithoutOrder = [];
|
|
630
|
-
// if a new field has been added since the orderings were set then we want
|
|
631
|
-
// it to be at the end instead of the beginning
|
|
632
|
-
schema.fields.forEach(field => {
|
|
633
|
-
if (columnOrderings.indexOf(field.path) > -1) {
|
|
634
|
-
fieldsWithOrders.push(field);
|
|
635
|
-
} else {
|
|
636
|
-
fieldsWithoutOrder.push(field);
|
|
637
|
-
}
|
|
638
|
-
});
|
|
639
|
-
schema.fields = fieldsWithOrders
|
|
640
|
-
.sort(({ path: path1 }, { path: path2 }) => {
|
|
641
|
-
return (
|
|
642
|
-
columnOrderings.indexOf(path1) - columnOrderings.indexOf(path2)
|
|
643
|
-
);
|
|
644
|
-
})
|
|
645
|
-
.concat(fieldsWithoutOrder);
|
|
646
|
-
// We shouldn't need to update the columnOrderings here, this could lead
|
|
647
|
-
// to unnecessary updates. TableConfig and schema have circular
|
|
648
|
-
// dependencies, which is bad at the moment of updating.
|
|
649
|
-
if (
|
|
650
|
-
!isEqual(
|
|
651
|
-
schema.fields.map(f => f.path),
|
|
652
|
-
columnOrderings
|
|
653
|
-
)
|
|
654
|
-
) {
|
|
655
|
-
setTableConfig(prev => ({
|
|
656
|
-
...prev,
|
|
657
|
-
columnOrderings: schema.fields.map(f => f.path)
|
|
658
|
-
}));
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
return schema;
|
|
663
|
-
}, [
|
|
664
|
-
cellRenderer,
|
|
665
|
-
convertedSchema,
|
|
666
|
-
currentParams,
|
|
667
|
-
entities,
|
|
668
|
-
history,
|
|
669
|
-
isInfinite,
|
|
670
|
-
isOpenable,
|
|
671
|
-
isSimple,
|
|
672
|
-
isViewable,
|
|
673
|
-
onDoubleClick,
|
|
674
|
-
setNewParams,
|
|
675
|
-
showForcedHiddenColumns,
|
|
676
|
-
tableConfig.columnOrderings,
|
|
677
|
-
tableConfig.fieldOptions,
|
|
678
|
-
withDisplayOptions,
|
|
679
|
-
recordIdToIsVisibleMap
|
|
680
|
-
]);
|
|
681
|
-
|
|
682
|
-
const {
|
|
683
|
-
moveColumnPersist,
|
|
684
|
-
persistPageSize,
|
|
685
|
-
resetDefaultVisibility,
|
|
686
|
-
resizePersist,
|
|
687
|
-
updateColumnVisibility,
|
|
688
|
-
updateTableDisplayDensity
|
|
689
|
-
} = useMemo(() => {
|
|
690
|
-
let resetDefaultVisibility;
|
|
691
|
-
let updateColumnVisibility;
|
|
692
|
-
let updateTableDisplayDensity;
|
|
693
|
-
let persistPageSize;
|
|
694
|
-
let moveColumnPersist;
|
|
695
|
-
let resizePersist = noop;
|
|
696
|
-
|
|
697
|
-
if (withDisplayOptions) {
|
|
698
|
-
const fieldOptsByPath = keyBy(tableConfig.fieldOptions, "path");
|
|
699
|
-
if (syncDisplayOptionsToDb) {
|
|
700
|
-
// sync up to db
|
|
701
|
-
// There must be a better way to set this variable...
|
|
702
|
-
let tableConfigurationId;
|
|
703
|
-
resetDefaultVisibility = function () {
|
|
704
|
-
tableConfigurationId = tableConfig.id;
|
|
705
|
-
if (tableConfigurationId) {
|
|
706
|
-
deleteTableConfiguration(tableConfigurationId);
|
|
707
|
-
}
|
|
708
|
-
};
|
|
709
|
-
updateColumnVisibility = function ({ shouldShow, path }) {
|
|
710
|
-
if (tableConfigurationId) {
|
|
711
|
-
const existingFieldOpt = fieldOptsByPath[path] || {};
|
|
712
|
-
upsertFieldOption({
|
|
713
|
-
id: existingFieldOpt.id,
|
|
714
|
-
path,
|
|
715
|
-
isHidden: !shouldShow,
|
|
716
|
-
tableConfigurationId
|
|
717
|
-
});
|
|
718
|
-
} else {
|
|
719
|
-
upsertTableConfiguration({
|
|
720
|
-
userId: currentUser.user.id,
|
|
721
|
-
formName,
|
|
722
|
-
fieldOptions: [
|
|
723
|
-
{
|
|
724
|
-
path,
|
|
725
|
-
isHidden: !shouldShow
|
|
726
|
-
}
|
|
727
|
-
]
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
};
|
|
731
|
-
} else {
|
|
732
|
-
const syncStorage = newTableConfig => {
|
|
733
|
-
setTableConfig(newTableConfig);
|
|
734
|
-
window.localStorage.setItem(formName, JSON.stringify(newTableConfig));
|
|
735
|
-
};
|
|
736
|
-
|
|
737
|
-
//sync display options with localstorage
|
|
738
|
-
resetDefaultVisibility = function () {
|
|
739
|
-
setTableConfig({ fieldOptions: [] });
|
|
740
|
-
window.localStorage.removeItem(formName);
|
|
741
|
-
};
|
|
742
|
-
updateColumnVisibility = function ({ path, paths, shouldShow }) {
|
|
743
|
-
const newFieldOpts = {
|
|
744
|
-
...fieldOptsByPath
|
|
745
|
-
};
|
|
746
|
-
const pathsToUse = paths ? paths : [path];
|
|
747
|
-
pathsToUse.forEach(path => {
|
|
748
|
-
newFieldOpts[path] = { path, isHidden: !shouldShow };
|
|
749
|
-
});
|
|
750
|
-
syncStorage({ ...tableConfig, fieldOptions: toArray(newFieldOpts) });
|
|
751
|
-
};
|
|
752
|
-
updateTableDisplayDensity = function (density) {
|
|
753
|
-
syncStorage({ ...tableConfig, density: density });
|
|
754
|
-
};
|
|
755
|
-
persistPageSize = function (pageSize) {
|
|
756
|
-
syncStorage({ ...tableConfig, userSetPageSize: pageSize });
|
|
757
|
-
};
|
|
758
|
-
moveColumnPersist = function ({ oldIndex, newIndex }) {
|
|
759
|
-
// we might already have an array of the fields [path1, path2, ..etc]
|
|
760
|
-
const columnOrderings =
|
|
761
|
-
tableConfig.columnOrderings ||
|
|
762
|
-
schema.fields.map(({ path }) => path); // columnOrderings is [path1, path2, ..etc]
|
|
763
|
-
syncStorage({
|
|
764
|
-
...tableConfig,
|
|
765
|
-
columnOrderings: arrayMove(columnOrderings, oldIndex, newIndex)
|
|
766
|
-
});
|
|
767
|
-
};
|
|
768
|
-
resizePersist = function (newResized) {
|
|
769
|
-
syncStorage({ ...tableConfig, resized: newResized });
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
return {
|
|
774
|
-
moveColumnPersist,
|
|
775
|
-
persistPageSize,
|
|
776
|
-
resetDefaultVisibility,
|
|
777
|
-
resizePersist,
|
|
778
|
-
updateColumnVisibility,
|
|
779
|
-
updateTableDisplayDensity
|
|
780
|
-
};
|
|
781
|
-
}, [
|
|
782
|
-
currentUser?.user?.id,
|
|
783
|
-
deleteTableConfiguration,
|
|
784
|
-
formName,
|
|
785
|
-
schema.fields,
|
|
786
|
-
syncDisplayOptionsToDb,
|
|
787
|
-
tableConfig,
|
|
788
|
-
upsertFieldOption,
|
|
789
|
-
upsertTableConfiguration,
|
|
790
|
-
withDisplayOptions
|
|
791
|
-
]);
|
|
792
|
-
|
|
793
|
-
let compact = _compact;
|
|
794
|
-
let extraCompact = _extraCompact;
|
|
795
|
-
|
|
796
|
-
if (withDisplayOptions && tableConfig.density) {
|
|
797
|
-
compact = tableConfig.density === "compact";
|
|
798
|
-
extraCompact = tableConfig.density === "extraCompact";
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
const resized = useMemo(
|
|
802
|
-
() => tableConfig.resized || [],
|
|
803
|
-
[tableConfig?.resized]
|
|
804
|
-
);
|
|
805
|
-
|
|
806
|
-
const pageSize = controlled_pageSize || _pageSize;
|
|
807
|
-
|
|
808
|
-
const [expandedEntityIdMap, setExpandedEntityIdMap] = useState(() => {
|
|
809
|
-
const initialExpandedEntityIdMap = {};
|
|
810
|
-
if (expandAllByDefault) {
|
|
811
|
-
entities.forEach(entity => {
|
|
812
|
-
initialExpandedEntityIdMap[entity.id || entity.code] = true;
|
|
813
|
-
});
|
|
814
|
-
}
|
|
815
|
-
return initialExpandedEntityIdMap;
|
|
816
|
-
});
|
|
817
|
-
|
|
818
|
-
const updateValidation = useCallback(
|
|
819
|
-
(entities, newCellValidate) => {
|
|
820
|
-
const tableWideErr = validateTableWideErrors({
|
|
821
|
-
entities,
|
|
822
|
-
schema,
|
|
823
|
-
newCellValidate
|
|
824
|
-
});
|
|
825
|
-
change("reduxFormCellValidation", tableWideErr);
|
|
826
|
-
},
|
|
827
|
-
[schema, change]
|
|
828
|
-
);
|
|
829
|
-
|
|
830
|
-
const updateEntitiesHelper = useCallback(
|
|
831
|
-
(ents, fn) => {
|
|
832
|
-
const [nextState, patches, inversePatches] = produceWithPatches(ents, fn);
|
|
833
|
-
if (!inversePatches.length) return;
|
|
834
|
-
const thatNewNew = [...nextState];
|
|
835
|
-
thatNewNew.isDirty = true;
|
|
836
|
-
change("reduxFormEntities", thatNewNew);
|
|
837
|
-
setEntitiesUndoRedoStack(prev => ({
|
|
838
|
-
...omitBy(prev, (v, k) => {
|
|
839
|
-
return toNumber(k) > prev.currentVersion + 1;
|
|
840
|
-
}),
|
|
841
|
-
currentVersion: prev.currentVersion + 1,
|
|
842
|
-
[prev.currentVersion + 1]: {
|
|
843
|
-
inversePatches,
|
|
844
|
-
patches
|
|
845
|
-
}
|
|
846
|
-
}));
|
|
847
|
-
},
|
|
848
|
-
[change]
|
|
849
|
-
);
|
|
850
|
-
|
|
851
|
-
const formatAndValidateEntities = useCallback(
|
|
852
|
-
(entities, { useDefaultValues, indexToStartAt } = {}) => {
|
|
853
|
-
const editableFields = schema.fields.filter(f => !f.isNotEditable);
|
|
854
|
-
const validationErrors = {};
|
|
855
|
-
|
|
856
|
-
const newEnts = immer(entities, entities => {
|
|
857
|
-
entities.forEach((e, index) => {
|
|
858
|
-
editableFields.forEach(columnSchema => {
|
|
859
|
-
if (useDefaultValues) {
|
|
860
|
-
if (e[columnSchema.path] === undefined) {
|
|
861
|
-
if (isFunction(columnSchema.defaultValue)) {
|
|
862
|
-
e[columnSchema.path] = columnSchema.defaultValue(
|
|
863
|
-
index + indexToStartAt,
|
|
864
|
-
e
|
|
865
|
-
);
|
|
866
|
-
} else e[columnSchema.path] = columnSchema.defaultValue;
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
//mutative
|
|
870
|
-
const { error } = editCellHelper({
|
|
871
|
-
entity: e,
|
|
872
|
-
columnSchema,
|
|
873
|
-
newVal: e[columnSchema.path]
|
|
874
|
-
});
|
|
875
|
-
if (error) {
|
|
876
|
-
const rowId = getIdOrCodeOrIndex(e, index);
|
|
877
|
-
validationErrors[`${rowId}:${columnSchema.path}`] = error;
|
|
878
|
-
}
|
|
879
|
-
});
|
|
880
|
-
});
|
|
881
|
-
});
|
|
882
|
-
return {
|
|
883
|
-
newEnts,
|
|
884
|
-
validationErrors
|
|
885
|
-
};
|
|
886
|
-
},
|
|
887
|
-
[schema.fields]
|
|
888
|
-
);
|
|
889
|
-
|
|
890
|
-
const updateValidationHelper = useCallback(() => {
|
|
891
|
-
updateValidation(entities, reduxFormCellValidation);
|
|
892
|
-
}, [entities, reduxFormCellValidation, updateValidation]);
|
|
893
|
-
|
|
894
|
-
const addEditableTableEntities = useCallback(
|
|
895
|
-
incomingEnts => {
|
|
896
|
-
updateEntitiesHelper(entities, entities => {
|
|
897
|
-
const newEntities = incomingEnts.map(e => ({
|
|
898
|
-
...e,
|
|
899
|
-
id: e.id || nanoid(),
|
|
900
|
-
_isClean: false
|
|
901
|
-
}));
|
|
902
|
-
|
|
903
|
-
const { newEnts, validationErrors } = formatAndValidateEntities(
|
|
904
|
-
newEntities,
|
|
905
|
-
{
|
|
906
|
-
useDefaultValues: true,
|
|
907
|
-
indexToStartAt: entities.length
|
|
908
|
-
}
|
|
909
|
-
);
|
|
910
|
-
if (every(entities, "_isClean")) {
|
|
911
|
-
forEach(newEnts, (e, i) => {
|
|
912
|
-
entities[i] = e;
|
|
913
|
-
});
|
|
914
|
-
} else {
|
|
915
|
-
entities.splice(entities.length, 0, ...newEnts);
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
updateValidation(entities, {
|
|
919
|
-
...reduxFormCellValidation,
|
|
920
|
-
...validationErrors
|
|
921
|
-
});
|
|
922
|
-
});
|
|
923
|
-
},
|
|
924
|
-
[
|
|
925
|
-
entities,
|
|
926
|
-
formatAndValidateEntities,
|
|
927
|
-
reduxFormCellValidation,
|
|
928
|
-
updateEntitiesHelper,
|
|
929
|
-
updateValidation
|
|
930
|
-
]
|
|
931
|
-
);
|
|
932
|
-
|
|
933
|
-
const getEditableTableInfoAndThrowFormError = useCallback(() => {
|
|
934
|
-
const { entsToUse, validationToUse } = removeCleanRows(
|
|
935
|
-
reduxFormEntities,
|
|
936
|
-
reduxFormCellValidation
|
|
937
|
-
);
|
|
938
|
-
const validationWTableErrs = validateTableWideErrors({
|
|
939
|
-
entities: entsToUse,
|
|
940
|
-
schema,
|
|
941
|
-
newCellValidate: validationToUse
|
|
942
|
-
});
|
|
943
|
-
|
|
944
|
-
if (!entsToUse?.length) {
|
|
945
|
-
throwFormError(
|
|
946
|
-
"Please add at least one row to the table before submitting."
|
|
947
|
-
);
|
|
948
|
-
}
|
|
949
|
-
const invalid =
|
|
950
|
-
isEmpty(validationWTableErrs) || !some(validationWTableErrs, v => v)
|
|
951
|
-
? undefined
|
|
952
|
-
: validationWTableErrs;
|
|
953
|
-
|
|
954
|
-
if (invalid) {
|
|
955
|
-
throwFormError("Please fix the errors in the table before submitting.");
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
return entsToUse;
|
|
959
|
-
}, [reduxFormCellValidation, reduxFormEntities, schema]);
|
|
960
|
-
|
|
961
|
-
useEffect(() => {
|
|
962
|
-
// This is bad practice, we shouldn't be assigning value to an
|
|
963
|
-
// external variable
|
|
964
|
-
if (helperProp) {
|
|
965
|
-
helperProp.updateValidationHelper = updateValidationHelper;
|
|
966
|
-
helperProp.addEditableTableEntities = addEditableTableEntities;
|
|
967
|
-
helperProp.getEditableTableInfoAndThrowFormError =
|
|
968
|
-
getEditableTableInfoAndThrowFormError;
|
|
969
|
-
}
|
|
970
|
-
}, [
|
|
971
|
-
addEditableTableEntities,
|
|
972
|
-
getEditableTableInfoAndThrowFormError,
|
|
973
|
-
helperProp,
|
|
974
|
-
updateValidationHelper
|
|
975
|
-
]);
|
|
976
|
-
|
|
977
|
-
const handleRowMove = useCallback(
|
|
978
|
-
(type, shiftHeld) => e => {
|
|
979
|
-
e.preventDefault();
|
|
980
|
-
e.stopPropagation();
|
|
981
|
-
let newIdMap = {};
|
|
982
|
-
const lastSelectedEnt = getLastSelectedEntity(
|
|
983
|
-
reduxFormSelectedEntityIdMap
|
|
984
|
-
);
|
|
985
|
-
|
|
986
|
-
if (noSelect) return;
|
|
987
|
-
if (lastSelectedEnt) {
|
|
988
|
-
let lastSelectedIndex = entities.findIndex(
|
|
989
|
-
ent => ent === lastSelectedEnt
|
|
990
|
-
);
|
|
991
|
-
if (lastSelectedIndex === -1) {
|
|
992
|
-
if (lastSelectedEnt.id !== undefined) {
|
|
993
|
-
lastSelectedIndex = entities.findIndex(
|
|
994
|
-
ent => ent.id === lastSelectedEnt.id
|
|
995
|
-
);
|
|
996
|
-
} else if (lastSelectedEnt.code !== undefined) {
|
|
997
|
-
lastSelectedIndex = entities.findIndex(
|
|
998
|
-
ent => ent.code === lastSelectedEnt.code
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
if (lastSelectedIndex === -1) {
|
|
1003
|
-
return;
|
|
1004
|
-
}
|
|
1005
|
-
const newEntToSelect = getNewEntToSelect({
|
|
1006
|
-
type,
|
|
1007
|
-
lastSelectedIndex,
|
|
1008
|
-
entities,
|
|
1009
|
-
isEntityDisabled
|
|
1010
|
-
});
|
|
1011
|
-
|
|
1012
|
-
if (!newEntToSelect) return;
|
|
1013
|
-
if (shiftHeld && !isSingleSelect) {
|
|
1014
|
-
if (
|
|
1015
|
-
reduxFormSelectedEntityIdMap[
|
|
1016
|
-
newEntToSelect.id || newEntToSelect.code
|
|
1017
|
-
]
|
|
1018
|
-
) {
|
|
1019
|
-
//the entity being moved to has already been selected
|
|
1020
|
-
newIdMap = omit(reduxFormSelectedEntityIdMap, [
|
|
1021
|
-
lastSelectedEnt.id || lastSelectedEnt.code
|
|
1022
|
-
]);
|
|
1023
|
-
newIdMap[newEntToSelect.id || newEntToSelect.code].time =
|
|
1024
|
-
Date.now() + 1;
|
|
1025
|
-
} else {
|
|
1026
|
-
//the entity being moved to has NOT been selected yet
|
|
1027
|
-
newIdMap = {
|
|
1028
|
-
...reduxFormSelectedEntityIdMap,
|
|
1029
|
-
[newEntToSelect.id || newEntToSelect.code]: {
|
|
1030
|
-
entity: newEntToSelect,
|
|
1031
|
-
time: Date.now()
|
|
1032
|
-
}
|
|
1033
|
-
};
|
|
1034
|
-
}
|
|
1035
|
-
} else {
|
|
1036
|
-
//no shiftHeld
|
|
1037
|
-
newIdMap[newEntToSelect.id || newEntToSelect.code] = {
|
|
1038
|
-
entity: newEntToSelect,
|
|
1039
|
-
time: Date.now()
|
|
1040
|
-
};
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
finalizeSelection({
|
|
1045
|
-
idMap: newIdMap,
|
|
1046
|
-
entities,
|
|
1047
|
-
props: {
|
|
1048
|
-
onDeselect,
|
|
1049
|
-
onSingleRowSelect,
|
|
1050
|
-
onMultiRowSelect,
|
|
1051
|
-
noDeselectAll,
|
|
1052
|
-
onRowSelect,
|
|
1053
|
-
noSelect,
|
|
1054
|
-
change
|
|
1055
|
-
}
|
|
1056
|
-
});
|
|
1057
|
-
},
|
|
1058
|
-
[
|
|
1059
|
-
change,
|
|
1060
|
-
entities,
|
|
1061
|
-
isEntityDisabled,
|
|
1062
|
-
isSingleSelect,
|
|
1063
|
-
noDeselectAll,
|
|
1064
|
-
noSelect,
|
|
1065
|
-
onDeselect,
|
|
1066
|
-
onMultiRowSelect,
|
|
1067
|
-
onRowSelect,
|
|
1068
|
-
onSingleRowSelect,
|
|
1069
|
-
reduxFormSelectedEntityIdMap
|
|
1070
|
-
]
|
|
1071
|
-
);
|
|
1072
|
-
|
|
1073
|
-
const primarySelectedCellId = useMemo(() => {
|
|
1074
|
-
for (const k of Object.keys(selectedCells)) {
|
|
1075
|
-
if (selectedCells[k] === PRIMARY_SELECTED_VAL) {
|
|
1076
|
-
return k;
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
}, [selectedCells]);
|
|
1080
|
-
|
|
1081
|
-
const startCellEdit = useCallback(
|
|
1082
|
-
(cellId, initialValue) => {
|
|
1083
|
-
// This initial value is not needed if the event is propagated accordingly.
|
|
1084
|
-
// This is directly connected to the RenderCell component, which does set
|
|
1085
|
-
// the initial value.
|
|
1086
|
-
change("reduxFormInitialValue", initialValue);
|
|
1087
|
-
change("reduxFormEditingCell", prev => {
|
|
1088
|
-
//check if the cell is already selected and editing and if so, don't change it
|
|
1089
|
-
if (prev === cellId) return cellId;
|
|
1090
|
-
setSelectedCells(prev => {
|
|
1091
|
-
if (prev[cellId] === PRIMARY_SELECTED_VAL) {
|
|
1092
|
-
return prev;
|
|
1093
|
-
}
|
|
1094
|
-
return { ...prev, [cellId]: PRIMARY_SELECTED_VAL };
|
|
1095
|
-
});
|
|
1096
|
-
return cellId;
|
|
1097
|
-
});
|
|
1098
|
-
},
|
|
1099
|
-
[change]
|
|
1100
|
-
);
|
|
1101
|
-
|
|
1102
|
-
const handleEnterStartCellEdit = useCallback(
|
|
1103
|
-
e => {
|
|
1104
|
-
e.stopPropagation();
|
|
1105
|
-
startCellEdit(primarySelectedCellId);
|
|
1106
|
-
},
|
|
1107
|
-
[primarySelectedCellId, startCellEdit]
|
|
1108
|
-
);
|
|
1109
|
-
|
|
1110
|
-
const handleDeleteCell = useCallback(() => {
|
|
1111
|
-
const newCellValidate = {
|
|
1112
|
-
...reduxFormCellValidation
|
|
1113
|
-
};
|
|
1114
|
-
if (isEmpty(selectedCells)) return;
|
|
1115
|
-
const rowIds = [];
|
|
1116
|
-
updateEntitiesHelper(entities, entities => {
|
|
1117
|
-
const entityIdToEntity = getEntityIdToEntity(entities);
|
|
1118
|
-
Object.keys(selectedCells).forEach(cellId => {
|
|
1119
|
-
const [rowId, path] = cellId.split(":");
|
|
1120
|
-
rowIds.push(rowId);
|
|
1121
|
-
const entity = entityIdToEntity[rowId].e;
|
|
1122
|
-
delete entity._isClean;
|
|
1123
|
-
const { error } = editCellHelper({
|
|
1124
|
-
entity,
|
|
1125
|
-
path,
|
|
1126
|
-
schema,
|
|
1127
|
-
newVal: ""
|
|
1128
|
-
});
|
|
1129
|
-
if (error) {
|
|
1130
|
-
newCellValidate[cellId] = error;
|
|
1131
|
-
} else {
|
|
1132
|
-
delete newCellValidate[cellId];
|
|
1133
|
-
}
|
|
1134
|
-
});
|
|
1135
|
-
updateValidation(entities, newCellValidate);
|
|
1136
|
-
});
|
|
1137
|
-
}, [
|
|
1138
|
-
entities,
|
|
1139
|
-
reduxFormCellValidation,
|
|
1140
|
-
schema,
|
|
1141
|
-
selectedCells,
|
|
1142
|
-
updateEntitiesHelper,
|
|
1143
|
-
updateValidation
|
|
1144
|
-
]);
|
|
1145
|
-
|
|
1146
|
-
const handleCopySelectedCells = useCallback(
|
|
1147
|
-
e => {
|
|
1148
|
-
// if the current selection is consecutive cells then copy with
|
|
1149
|
-
// tabs between. if not then just select primary selected cell
|
|
1150
|
-
if (isEmpty(selectedCells)) return;
|
|
1151
|
-
const pathToIndex = getFieldPathToIndex(schema);
|
|
1152
|
-
const entityIdToEntity = getEntityIdToEntity(entities);
|
|
1153
|
-
const selectionGrid = [];
|
|
1154
|
-
let firstRowIndex;
|
|
1155
|
-
let firstCellIndex;
|
|
1156
|
-
Object.keys(selectedCells).forEach(key => {
|
|
1157
|
-
const [rowId, path] = key.split(":");
|
|
1158
|
-
const eInfo = entityIdToEntity[rowId];
|
|
1159
|
-
if (eInfo) {
|
|
1160
|
-
if (firstRowIndex === undefined || eInfo.i < firstRowIndex) {
|
|
1161
|
-
firstRowIndex = eInfo.i;
|
|
1162
|
-
}
|
|
1163
|
-
if (!selectionGrid[eInfo.i]) {
|
|
1164
|
-
selectionGrid[eInfo.i] = [];
|
|
1165
|
-
}
|
|
1166
|
-
const cellIndex = pathToIndex[path];
|
|
1167
|
-
if (firstCellIndex === undefined || cellIndex < firstCellIndex) {
|
|
1168
|
-
firstCellIndex = cellIndex;
|
|
1169
|
-
}
|
|
1170
|
-
selectionGrid[eInfo.i][cellIndex] = true;
|
|
1171
|
-
}
|
|
1172
|
-
});
|
|
1173
|
-
if (firstRowIndex === undefined) return;
|
|
1174
|
-
const allRows = getAllRows(e);
|
|
1175
|
-
let fullCellText = "";
|
|
1176
|
-
const fullJson = [];
|
|
1177
|
-
times(selectionGrid.length, i => {
|
|
1178
|
-
const row = selectionGrid[i];
|
|
1179
|
-
if (fullCellText) {
|
|
1180
|
-
fullCellText += "\n";
|
|
1181
|
-
}
|
|
1182
|
-
if (!row) {
|
|
1183
|
-
return;
|
|
1184
|
-
} else {
|
|
1185
|
-
const jsonRow = [];
|
|
1186
|
-
// ignore header
|
|
1187
|
-
let [rowCopyText, json] = getRowCopyText(allRows[i + 1]);
|
|
1188
|
-
rowCopyText = rowCopyText.split("\t");
|
|
1189
|
-
times(row.length, i => {
|
|
1190
|
-
const cell = row[i];
|
|
1191
|
-
if (cell) {
|
|
1192
|
-
fullCellText += rowCopyText[i];
|
|
1193
|
-
jsonRow.push(json[i]);
|
|
1194
|
-
}
|
|
1195
|
-
if (i !== row.length - 1 && i >= firstCellIndex)
|
|
1196
|
-
fullCellText += "\t";
|
|
1197
|
-
});
|
|
1198
|
-
fullJson.push(jsonRow);
|
|
1199
|
-
}
|
|
1200
|
-
});
|
|
1201
|
-
if (!fullCellText) return window.toastr.warning("No text to copy");
|
|
1202
|
-
|
|
1203
|
-
handleCopyHelper(fullCellText, fullJson, "Selected cells copied");
|
|
1204
|
-
},
|
|
1205
|
-
[entities, selectedCells, schema]
|
|
1206
|
-
);
|
|
1207
|
-
|
|
1208
|
-
const handleCopySelectedRows = useCallback(
|
|
1209
|
-
(selectedRecords, e) => {
|
|
1210
|
-
const idToIndex = entities.reduce((acc, e, i) => {
|
|
1211
|
-
acc[e.id || e.code] = i;
|
|
1212
|
-
return acc;
|
|
1213
|
-
}, {});
|
|
1214
|
-
|
|
1215
|
-
//index 0 of the table is the column titles
|
|
1216
|
-
//must add 1 to rowNum
|
|
1217
|
-
const rowNumbersToCopy = selectedRecords
|
|
1218
|
-
.map(rec => idToIndex[rec.id || rec.code] + 1)
|
|
1219
|
-
.sort();
|
|
1220
|
-
|
|
1221
|
-
if (!rowNumbersToCopy.length) return;
|
|
1222
|
-
rowNumbersToCopy.unshift(0); //add in the header row
|
|
1223
|
-
try {
|
|
1224
|
-
const allRowEls = getAllRows(e);
|
|
1225
|
-
if (!allRowEls) return;
|
|
1226
|
-
const rowEls = rowNumbersToCopy.map(i => allRowEls[i]);
|
|
1227
|
-
|
|
1228
|
-
handleCopyRows(rowEls, {
|
|
1229
|
-
onFinishMsg: "Selected rows copied"
|
|
1230
|
-
});
|
|
1231
|
-
} catch (error) {
|
|
1232
|
-
console.error(`error:`, error);
|
|
1233
|
-
window.toastr.error("Error copying rows.");
|
|
1234
|
-
}
|
|
1235
|
-
},
|
|
1236
|
-
[entities]
|
|
1237
|
-
);
|
|
1238
|
-
|
|
1239
|
-
const handleCopyHotkey = useCallback(
|
|
1240
|
-
e => {
|
|
1241
|
-
if (isCellEditable) {
|
|
1242
|
-
handleCopySelectedCells(e);
|
|
1243
|
-
} else {
|
|
1244
|
-
handleCopySelectedRows(
|
|
1245
|
-
getRecordsFromIdMap(reduxFormSelectedEntityIdMap),
|
|
1246
|
-
e
|
|
1247
|
-
);
|
|
1248
|
-
}
|
|
1249
|
-
},
|
|
1250
|
-
[
|
|
1251
|
-
handleCopySelectedCells,
|
|
1252
|
-
handleCopySelectedRows,
|
|
1253
|
-
isCellEditable,
|
|
1254
|
-
reduxFormSelectedEntityIdMap
|
|
1255
|
-
]
|
|
1256
|
-
);
|
|
1257
|
-
|
|
1258
|
-
const handleCut = useCallback(
|
|
1259
|
-
e => {
|
|
1260
|
-
handleDeleteCell();
|
|
1261
|
-
handleCopyHotkey(e);
|
|
1262
|
-
},
|
|
1263
|
-
[handleCopyHotkey, handleDeleteCell]
|
|
1264
|
-
);
|
|
1265
|
-
|
|
1266
|
-
const flashTableBorder = () => {
|
|
1267
|
-
try {
|
|
1268
|
-
const table = tableRef.current.tableRef;
|
|
1269
|
-
table.classList.add("tgBorderBlue");
|
|
1270
|
-
setTimeout(() => {
|
|
1271
|
-
table.classList.remove("tgBorderBlue");
|
|
1272
|
-
}, 300);
|
|
1273
|
-
} catch (e) {
|
|
1274
|
-
console.error(`err when flashing table border:`, e);
|
|
1275
|
-
}
|
|
1276
|
-
};
|
|
1277
|
-
|
|
1278
|
-
const handleUndo = useCallback(() => {
|
|
1279
|
-
if (entitiesUndoRedoStack.currentVersion > 0) {
|
|
1280
|
-
flashTableBorder();
|
|
1281
|
-
const nextState = applyPatches(
|
|
1282
|
-
entities,
|
|
1283
|
-
entitiesUndoRedoStack[entitiesUndoRedoStack.currentVersion]
|
|
1284
|
-
.inversePatches
|
|
1285
|
-
);
|
|
1286
|
-
const { newEnts, validationErrors } =
|
|
1287
|
-
formatAndValidateEntities(nextState);
|
|
1288
|
-
setEntitiesUndoRedoStack(prev => ({
|
|
1289
|
-
...prev,
|
|
1290
|
-
currentVersion: prev.currentVersion - 1
|
|
1291
|
-
}));
|
|
1292
|
-
updateValidation(newEnts, validationErrors);
|
|
1293
|
-
change("reduxFormEntities", newEnts);
|
|
1294
|
-
}
|
|
1295
|
-
}, [
|
|
1296
|
-
change,
|
|
1297
|
-
entities,
|
|
1298
|
-
formatAndValidateEntities,
|
|
1299
|
-
entitiesUndoRedoStack,
|
|
1300
|
-
updateValidation
|
|
1301
|
-
]);
|
|
1302
|
-
|
|
1303
|
-
const handleRedo = useCallback(() => {
|
|
1304
|
-
const nextV = entitiesUndoRedoStack.currentVersion + 1;
|
|
1305
|
-
if (entitiesUndoRedoStack[nextV]) {
|
|
1306
|
-
flashTableBorder();
|
|
1307
|
-
const nextState = applyPatches(
|
|
1308
|
-
entities,
|
|
1309
|
-
entitiesUndoRedoStack[nextV].patches
|
|
1310
|
-
);
|
|
1311
|
-
const { newEnts, validationErrors } =
|
|
1312
|
-
formatAndValidateEntities(nextState);
|
|
1313
|
-
change("reduxFormEntities", newEnts);
|
|
1314
|
-
updateValidation(newEnts, validationErrors);
|
|
1315
|
-
setEntitiesUndoRedoStack(prev => ({
|
|
1316
|
-
...prev,
|
|
1317
|
-
currentVersion: nextV
|
|
1318
|
-
}));
|
|
1319
|
-
}
|
|
1320
|
-
}, [
|
|
1321
|
-
change,
|
|
1322
|
-
entities,
|
|
1323
|
-
formatAndValidateEntities,
|
|
1324
|
-
entitiesUndoRedoStack,
|
|
1325
|
-
updateValidation
|
|
1326
|
-
]);
|
|
1327
|
-
|
|
1328
|
-
const handleSelectAllRows = useCallback(
|
|
1329
|
-
e => {
|
|
1330
|
-
if (isSingleSelect) return;
|
|
1331
|
-
e.preventDefault();
|
|
1332
|
-
|
|
1333
|
-
if (isCellEditable) {
|
|
1334
|
-
const schemaPaths = schema.fields.map(f => f.path);
|
|
1335
|
-
const newSelectedCells = {};
|
|
1336
|
-
entities.forEach((entity, i) => {
|
|
1337
|
-
if (isEntityDisabled(entity)) return;
|
|
1338
|
-
const entityId = getIdOrCodeOrIndex(entity, i);
|
|
1339
|
-
schemaPaths.forEach(p => {
|
|
1340
|
-
newSelectedCells[`${entityId}:${p}`] = true;
|
|
1341
|
-
});
|
|
1342
|
-
});
|
|
1343
|
-
setSelectedCells(newSelectedCells);
|
|
1344
|
-
} else {
|
|
1345
|
-
const newIdMap = {};
|
|
1346
|
-
|
|
1347
|
-
entities.forEach((entity, i) => {
|
|
1348
|
-
if (isEntityDisabled(entity)) return;
|
|
1349
|
-
const entityId = getIdOrCodeOrIndex(entity, i);
|
|
1350
|
-
newIdMap[entityId] = { entity };
|
|
1351
|
-
});
|
|
1352
|
-
finalizeSelection({
|
|
1353
|
-
idMap: newIdMap,
|
|
1354
|
-
entities,
|
|
1355
|
-
props: {
|
|
1356
|
-
onDeselect,
|
|
1357
|
-
onSingleRowSelect,
|
|
1358
|
-
onMultiRowSelect,
|
|
1359
|
-
noDeselectAll,
|
|
1360
|
-
onRowSelect,
|
|
1361
|
-
noSelect,
|
|
1362
|
-
change
|
|
1363
|
-
}
|
|
1364
|
-
});
|
|
1365
|
-
}
|
|
1366
|
-
},
|
|
1367
|
-
[
|
|
1368
|
-
change,
|
|
1369
|
-
entities,
|
|
1370
|
-
isCellEditable,
|
|
1371
|
-
isEntityDisabled,
|
|
1372
|
-
isSingleSelect,
|
|
1373
|
-
noDeselectAll,
|
|
1374
|
-
noSelect,
|
|
1375
|
-
onDeselect,
|
|
1376
|
-
onMultiRowSelect,
|
|
1377
|
-
onRowSelect,
|
|
1378
|
-
onSingleRowSelect,
|
|
1379
|
-
schema.fields
|
|
1380
|
-
]
|
|
1381
|
-
);
|
|
1382
|
-
|
|
1383
|
-
const hotKeys = useMemo(
|
|
1384
|
-
() => [
|
|
1385
|
-
{
|
|
1386
|
-
global: false,
|
|
1387
|
-
combo: "up",
|
|
1388
|
-
label: "Move Up a Row",
|
|
1389
|
-
onKeyDown: handleRowMove("up")
|
|
1390
|
-
},
|
|
1391
|
-
{
|
|
1392
|
-
global: false,
|
|
1393
|
-
combo: "down",
|
|
1394
|
-
label: "Move Down a Row",
|
|
1395
|
-
onKeyDown: handleRowMove("down")
|
|
1396
|
-
},
|
|
1397
|
-
{
|
|
1398
|
-
global: false,
|
|
1399
|
-
combo: "up+shift",
|
|
1400
|
-
label: "Move Up a Row",
|
|
1401
|
-
onKeyDown: handleRowMove("up", true)
|
|
1402
|
-
},
|
|
1403
|
-
...(isCellEditable
|
|
1404
|
-
? [
|
|
1405
|
-
{
|
|
1406
|
-
global: false,
|
|
1407
|
-
combo: "enter",
|
|
1408
|
-
label: "Enter -> Start Cell Edit",
|
|
1409
|
-
onKeyDown: handleEnterStartCellEdit
|
|
1410
|
-
},
|
|
1411
|
-
{
|
|
1412
|
-
global: false,
|
|
1413
|
-
combo: "mod+x",
|
|
1414
|
-
label: "Cut",
|
|
1415
|
-
onKeyDown: handleCut
|
|
1416
|
-
},
|
|
1417
|
-
{
|
|
1418
|
-
global: false,
|
|
1419
|
-
combo: IS_LINUX ? "alt+z" : "mod+z",
|
|
1420
|
-
label: "Undo",
|
|
1421
|
-
onKeyDown: handleUndo
|
|
1422
|
-
},
|
|
1423
|
-
{
|
|
1424
|
-
global: false,
|
|
1425
|
-
combo: IS_LINUX ? "alt+shift+z" : "mod+shift+z",
|
|
1426
|
-
label: "Redo",
|
|
1427
|
-
onKeyDown: handleRedo
|
|
1428
|
-
},
|
|
1429
|
-
{
|
|
1430
|
-
global: false,
|
|
1431
|
-
combo: "backspace",
|
|
1432
|
-
label: "Delete Cell",
|
|
1433
|
-
onKeyDown: handleDeleteCell
|
|
1434
|
-
}
|
|
1435
|
-
]
|
|
1436
|
-
: []),
|
|
1437
|
-
{
|
|
1438
|
-
global: false,
|
|
1439
|
-
combo: "down+shift",
|
|
1440
|
-
label: "Move Down a Row",
|
|
1441
|
-
onKeyDown: handleRowMove("down", true)
|
|
1442
|
-
},
|
|
1443
|
-
{
|
|
1444
|
-
global: false,
|
|
1445
|
-
combo: "mod + c",
|
|
1446
|
-
label: "Copy rows",
|
|
1447
|
-
onKeyDown: handleCopyHotkey
|
|
1448
|
-
},
|
|
1449
|
-
{
|
|
1450
|
-
global: false,
|
|
1451
|
-
combo: "mod + a",
|
|
1452
|
-
label: "Select rows",
|
|
1453
|
-
onKeyDown: handleSelectAllRows
|
|
1454
|
-
}
|
|
1455
|
-
],
|
|
1456
|
-
[
|
|
1457
|
-
handleCopyHotkey,
|
|
1458
|
-
handleCut,
|
|
1459
|
-
handleDeleteCell,
|
|
1460
|
-
handleEnterStartCellEdit,
|
|
1461
|
-
handleRedo,
|
|
1462
|
-
handleRowMove,
|
|
1463
|
-
handleSelectAllRows,
|
|
1464
|
-
handleUndo,
|
|
1465
|
-
isCellEditable
|
|
1466
|
-
]
|
|
1467
|
-
);
|
|
1468
|
-
|
|
1469
|
-
const { handleKeyDown, handleKeyUp } = useHotkeys(hotKeys);
|
|
1470
|
-
const [columns, setColumns] = useState([]);
|
|
1471
|
-
const [fullscreen, setFullscreen] = useState(false);
|
|
1472
|
-
const [selectingAll, setSelectingAll] = useState(false);
|
|
1473
|
-
|
|
1474
|
-
// format in the schema shouldn't be something that changes the value
|
|
1475
|
-
// everytime, it produces weird behavior since it keeps rerendering,
|
|
1476
|
-
// we should make enforce the user set the format as something that
|
|
1477
|
-
// "formats", not "changes".
|
|
1478
|
-
useEffect(() => {
|
|
1479
|
-
const formatAndValidateTableInitial = () => {
|
|
1480
|
-
const { newEnts, validationErrors } = formatAndValidateEntities(entities);
|
|
1481
|
-
const toKeep = {};
|
|
1482
|
-
//on the initial load we want to keep any async table wide errors
|
|
1483
|
-
forEach(reduxFormCellValidation, (v, k) => {
|
|
1484
|
-
if (v && v._isTableAsyncWideError) {
|
|
1485
|
-
toKeep[k] = v;
|
|
1486
|
-
}
|
|
1487
|
-
});
|
|
1488
|
-
change("reduxFormEntities", prev => {
|
|
1489
|
-
if (!isEqual(prev, newEnts)) {
|
|
1490
|
-
return newEnts;
|
|
1491
|
-
}
|
|
1492
|
-
return prev;
|
|
1493
|
-
});
|
|
1494
|
-
updateValidation(newEnts, {
|
|
1495
|
-
...toKeep,
|
|
1496
|
-
...validationErrors
|
|
1497
|
-
});
|
|
1498
|
-
};
|
|
1499
|
-
isCellEditable && formatAndValidateTableInitial();
|
|
1500
|
-
}, [
|
|
1501
|
-
change,
|
|
1502
|
-
entities,
|
|
1503
|
-
formatAndValidateEntities,
|
|
1504
|
-
isCellEditable,
|
|
1505
|
-
reduxFormCellValidation,
|
|
1506
|
-
updateValidation
|
|
1507
|
-
]);
|
|
1508
|
-
|
|
1509
|
-
const handlePaste = useCallback(
|
|
1510
|
-
e => {
|
|
1511
|
-
if (isCellEditable) {
|
|
1512
|
-
if (isEmpty(selectedCells)) return;
|
|
1513
|
-
try {
|
|
1514
|
-
let pasteData = [];
|
|
1515
|
-
let toPaste;
|
|
1516
|
-
if (window.clipboardData && window.clipboardData.getData) {
|
|
1517
|
-
// IE
|
|
1518
|
-
toPaste = window.clipboardData.getData("Text");
|
|
1519
|
-
} else if (e.clipboardData && e.clipboardData.getData) {
|
|
1520
|
-
toPaste = e.clipboardData.getData("text/plain");
|
|
1521
|
-
}
|
|
1522
|
-
const jsonToPaste = e.clipboardData.getData("application/json");
|
|
1523
|
-
try {
|
|
1524
|
-
const pastedJson = [];
|
|
1525
|
-
JSON.parse(jsonToPaste).forEach(row => {
|
|
1526
|
-
const newRow = [];
|
|
1527
|
-
Object.values(row).forEach(cell => {
|
|
1528
|
-
const cellVal = JSON.parse(cell);
|
|
1529
|
-
newRow.push(cellVal);
|
|
1530
|
-
});
|
|
1531
|
-
pastedJson.push(newRow);
|
|
1532
|
-
});
|
|
1533
|
-
pasteData = pastedJson;
|
|
1534
|
-
// try to remove the header row if it exists
|
|
1535
|
-
if (
|
|
1536
|
-
pasteData[0] &&
|
|
1537
|
-
pasteData[0][0] &&
|
|
1538
|
-
pasteData[0][0].__isHeaderCell
|
|
1539
|
-
) {
|
|
1540
|
-
pasteData = pasteData.slice(1);
|
|
1541
|
-
}
|
|
1542
|
-
} catch (e) {
|
|
1543
|
-
if (toPaste.includes(",")) {
|
|
1544
|
-
//try papaparsing it out as a csv if it contains commas
|
|
1545
|
-
try {
|
|
1546
|
-
const { data, errors } = papaparse.parse(toPaste, {
|
|
1547
|
-
header: false
|
|
1548
|
-
});
|
|
1549
|
-
if (data?.length && !errors?.length) {
|
|
1550
|
-
pasteData = data;
|
|
1551
|
-
}
|
|
1552
|
-
} catch (error) {
|
|
1553
|
-
console.error(`error p982qhgpf9qh`, error);
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
pasteData = pasteData.length ? pasteData : defaultParsePaste(toPaste);
|
|
1558
|
-
|
|
1559
|
-
if (!pasteData || !pasteData.length) return;
|
|
1560
|
-
|
|
1561
|
-
if (pasteData.length === 1 && pasteData[0].length === 1) {
|
|
1562
|
-
const newCellValidate = {
|
|
1563
|
-
...reduxFormCellValidation
|
|
1564
|
-
};
|
|
1565
|
-
// single paste value, fill all cells with value
|
|
1566
|
-
const newVal = pasteData[0][0];
|
|
1567
|
-
updateEntitiesHelper(entities, entities => {
|
|
1568
|
-
const entityIdToEntity = getEntityIdToEntity(entities);
|
|
1569
|
-
Object.keys(selectedCells).forEach(cellId => {
|
|
1570
|
-
const [rowId, path] = cellId.split(":");
|
|
1571
|
-
|
|
1572
|
-
const entity = entityIdToEntity[rowId].e;
|
|
1573
|
-
delete entity._isClean;
|
|
1574
|
-
const { error } = editCellHelper({
|
|
1575
|
-
entity,
|
|
1576
|
-
path,
|
|
1577
|
-
schema,
|
|
1578
|
-
newVal: formatPasteData({ newVal, path, schema })
|
|
1579
|
-
});
|
|
1580
|
-
if (error) {
|
|
1581
|
-
newCellValidate[cellId] = error;
|
|
1582
|
-
} else {
|
|
1583
|
-
delete newCellValidate[cellId];
|
|
1584
|
-
}
|
|
1585
|
-
});
|
|
1586
|
-
updateValidation(entities, newCellValidate);
|
|
1587
|
-
});
|
|
1588
|
-
} else {
|
|
1589
|
-
// handle paste in same format
|
|
1590
|
-
if (primarySelectedCellId) {
|
|
1591
|
-
const newCellValidate = {
|
|
1592
|
-
...reduxFormCellValidation
|
|
1593
|
-
};
|
|
1594
|
-
|
|
1595
|
-
const newSelectedCells = { ...selectedCells };
|
|
1596
|
-
updateEntitiesHelper(entities, entities => {
|
|
1597
|
-
const entityIdToEntity = getEntityIdToEntity(entities);
|
|
1598
|
-
const [rowId, primaryCellPath] =
|
|
1599
|
-
primarySelectedCellId.split(":");
|
|
1600
|
-
const primaryEntityInfo = entityIdToEntity[rowId];
|
|
1601
|
-
const startIndex = primaryEntityInfo.i;
|
|
1602
|
-
const endIndex = primaryEntityInfo.i + pasteData.length;
|
|
1603
|
-
for (let i = startIndex; i < endIndex; i++) {
|
|
1604
|
-
if (!entities[i]) {
|
|
1605
|
-
entities[i] = { id: nanoid() };
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
const entitiesToManipulate = entities.slice(
|
|
1609
|
-
startIndex,
|
|
1610
|
-
endIndex
|
|
1611
|
-
);
|
|
1612
|
-
const pathToIndex = getFieldPathToIndex(schema);
|
|
1613
|
-
const indexToPath = invert(pathToIndex);
|
|
1614
|
-
const startCellIndex = pathToIndex[primaryCellPath];
|
|
1615
|
-
pasteData.forEach((row, i) => {
|
|
1616
|
-
row.forEach((newVal, j) => {
|
|
1617
|
-
if (newVal) {
|
|
1618
|
-
const cellIndexToChange = startCellIndex + j;
|
|
1619
|
-
const entity = entitiesToManipulate[i];
|
|
1620
|
-
if (entity) {
|
|
1621
|
-
delete entity._isClean;
|
|
1622
|
-
const path = indexToPath[cellIndexToChange];
|
|
1623
|
-
if (path) {
|
|
1624
|
-
const { error } = editCellHelper({
|
|
1625
|
-
entity,
|
|
1626
|
-
path,
|
|
1627
|
-
schema,
|
|
1628
|
-
newVal: formatPasteData({
|
|
1629
|
-
newVal,
|
|
1630
|
-
path,
|
|
1631
|
-
schema
|
|
1632
|
-
})
|
|
1633
|
-
});
|
|
1634
|
-
const cellId = `${getIdOrCodeOrIndex(entity)}:${path}`;
|
|
1635
|
-
if (!newSelectedCells[cellId]) {
|
|
1636
|
-
newSelectedCells[cellId] = true;
|
|
1637
|
-
}
|
|
1638
|
-
if (error) {
|
|
1639
|
-
newCellValidate[cellId] = error;
|
|
1640
|
-
} else {
|
|
1641
|
-
delete newCellValidate[cellId];
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
});
|
|
1647
|
-
});
|
|
1648
|
-
updateValidation(entities, newCellValidate);
|
|
1649
|
-
});
|
|
1650
|
-
setSelectedCells(newSelectedCells);
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
} catch (error) {
|
|
1654
|
-
console.error(`error:`, error);
|
|
1655
|
-
}
|
|
1656
|
-
}
|
|
1657
|
-
},
|
|
1658
|
-
[
|
|
1659
|
-
entities,
|
|
1660
|
-
isCellEditable,
|
|
1661
|
-
primarySelectedCellId,
|
|
1662
|
-
reduxFormCellValidation,
|
|
1663
|
-
schema,
|
|
1664
|
-
selectedCells,
|
|
1665
|
-
updateEntitiesHelper,
|
|
1666
|
-
updateValidation
|
|
1667
|
-
]
|
|
1668
|
-
);
|
|
1669
|
-
|
|
1670
|
-
useEffect(() => {
|
|
1671
|
-
document.addEventListener("paste", handlePaste);
|
|
1672
|
-
return () => {
|
|
1673
|
-
document.removeEventListener("paste", handlePaste);
|
|
1674
|
-
};
|
|
1675
|
-
}, [handlePaste]);
|
|
1676
|
-
|
|
1677
|
-
useEffect(() => {
|
|
1678
|
-
addFilters(additionalFilters);
|
|
1679
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1680
|
-
}, [additionalFilters]);
|
|
1681
|
-
|
|
1682
|
-
useEffect(() => {
|
|
1683
|
-
setColumns(
|
|
1684
|
-
schema.fields
|
|
1685
|
-
? schema.fields.reduce((col, field, i) => {
|
|
1686
|
-
if (field.isHidden) {
|
|
1687
|
-
return col;
|
|
1688
|
-
}
|
|
1689
|
-
return col.concat({
|
|
1690
|
-
...field,
|
|
1691
|
-
columnIndex: i
|
|
1692
|
-
});
|
|
1693
|
-
}, [])
|
|
1694
|
-
: []
|
|
1695
|
-
);
|
|
1696
|
-
}, [schema?.fields]);
|
|
1697
|
-
|
|
1698
|
-
const setSelectedIds = useCallback(
|
|
1699
|
-
(selectedIds, scrollToFirst) => {
|
|
1700
|
-
const idArray = Array.isArray(selectedIds) ? selectedIds : [selectedIds];
|
|
1701
|
-
const selectedEntities = entities.filter(
|
|
1702
|
-
e => idArray.indexOf(getIdOrCodeOrIndex(e)) > -1 && !isEntityDisabled(e)
|
|
1703
|
-
);
|
|
1704
|
-
const newIdMap = selectedEntities.reduce((acc, entity) => {
|
|
1705
|
-
acc[getIdOrCodeOrIndex(entity)] = { entity };
|
|
1706
|
-
return acc;
|
|
1707
|
-
}, {});
|
|
1708
|
-
setExpandedEntityIdMap(newIdMap);
|
|
1709
|
-
finalizeSelection({
|
|
1710
|
-
idMap: newIdMap,
|
|
1711
|
-
entities,
|
|
1712
|
-
props: {
|
|
1713
|
-
onDeselect,
|
|
1714
|
-
onSingleRowSelect,
|
|
1715
|
-
onMultiRowSelect,
|
|
1716
|
-
noDeselectAll,
|
|
1717
|
-
onRowSelect,
|
|
1718
|
-
noSelect,
|
|
1719
|
-
change
|
|
1720
|
-
}
|
|
1721
|
-
});
|
|
1722
|
-
// This option could be eliminated, keeping it because it was prior in the
|
|
1723
|
-
// code, but it is a fuctionality not needed
|
|
1724
|
-
if (scrollToFirst) {
|
|
1725
|
-
const idToScrollTo = idArray[0];
|
|
1726
|
-
if (!idToScrollTo && idToScrollTo !== 0) return;
|
|
1727
|
-
const entityIndexToScrollTo = entities.findIndex(
|
|
1728
|
-
e => e.id === idToScrollTo || e.code === idToScrollTo
|
|
1729
|
-
);
|
|
1730
|
-
if (entityIndexToScrollTo === -1 || !tableRef.current) return;
|
|
1731
|
-
const tableBody = tableRef.current.tableRef.querySelector(".rt-tbody");
|
|
1732
|
-
if (!tableBody) return;
|
|
1733
|
-
const rowEl =
|
|
1734
|
-
tableBody.getElementsByClassName("rt-tr-group")[
|
|
1735
|
-
entityIndexToScrollTo
|
|
1736
|
-
];
|
|
1737
|
-
if (!rowEl) return;
|
|
1738
|
-
setTimeout(() => {
|
|
1739
|
-
//we need to delay for a teeny bit to make sure the table has drawn
|
|
1740
|
-
rowEl &&
|
|
1741
|
-
tableBody &&
|
|
1742
|
-
scrollIntoView(rowEl, tableBody, {
|
|
1743
|
-
alignWithTop: true
|
|
1744
|
-
});
|
|
1745
|
-
}, 0);
|
|
1746
|
-
}
|
|
1747
|
-
},
|
|
1748
|
-
[
|
|
1749
|
-
change,
|
|
1750
|
-
entities,
|
|
1751
|
-
isEntityDisabled,
|
|
1752
|
-
noDeselectAll,
|
|
1753
|
-
noSelect,
|
|
1754
|
-
onDeselect,
|
|
1755
|
-
onMultiRowSelect,
|
|
1756
|
-
onRowSelect,
|
|
1757
|
-
onSingleRowSelect
|
|
1758
|
-
]
|
|
1759
|
-
);
|
|
1760
|
-
|
|
1761
|
-
// We need to make sure this only runs at the beggining
|
|
1762
|
-
useEffect(() => {
|
|
1763
|
-
if (selectedIds) {
|
|
1764
|
-
setSelectedIds(selectedIds);
|
|
1765
|
-
}
|
|
1766
|
-
if (selectAllByDefault && entities && entities.length) {
|
|
1767
|
-
if (alreadySelected.current) return;
|
|
1768
|
-
setSelectedIds(entities.map(getIdOrCodeOrIndex));
|
|
1769
|
-
alreadySelected.current = true;
|
|
1770
|
-
}
|
|
1771
|
-
}, [entities, selectedIds, selectAllByDefault, setSelectedIds]);
|
|
1772
|
-
|
|
1773
|
-
const TheadComponent = useCallback(
|
|
1774
|
-
({ className, style, children }) => {
|
|
1775
|
-
const moveColumn = ({ oldIndex, newIndex }) => {
|
|
1776
|
-
let oldStateColumnIndex, newStateColumnIndex;
|
|
1777
|
-
columns.forEach((column, i) => {
|
|
1778
|
-
if (oldIndex === column.columnIndex) oldStateColumnIndex = i;
|
|
1779
|
-
if (newIndex === column.columnIndex) newStateColumnIndex = i;
|
|
1780
|
-
});
|
|
1781
|
-
// because it is all handled in state we need
|
|
1782
|
-
// to perform the move and update the columnIndices
|
|
1783
|
-
// because they are used for the sortable columns
|
|
1784
|
-
const newColumns = arrayMove(
|
|
1785
|
-
columns,
|
|
1786
|
-
oldStateColumnIndex,
|
|
1787
|
-
newStateColumnIndex
|
|
1788
|
-
).map((column, i) => {
|
|
1789
|
-
return {
|
|
1790
|
-
...column,
|
|
1791
|
-
columnIndex: i
|
|
1792
|
-
};
|
|
1793
|
-
});
|
|
1794
|
-
setColumns(newColumns);
|
|
1795
|
-
};
|
|
1796
|
-
return (
|
|
1797
|
-
<SortableColumns
|
|
1798
|
-
className={className}
|
|
1799
|
-
style={style}
|
|
1800
|
-
moveColumn={moveColumnPersist || moveColumn}
|
|
1801
|
-
>
|
|
1802
|
-
{children}
|
|
1803
|
-
</SortableColumns>
|
|
1804
|
-
);
|
|
1805
|
-
},
|
|
1806
|
-
[columns, moveColumnPersist]
|
|
1807
|
-
);
|
|
1808
|
-
|
|
1809
|
-
const addEntitiesToSelection = entities => {
|
|
1810
|
-
const idMap = reduxFormSelectedEntityIdMap || {};
|
|
1811
|
-
const newIdMap = cloneDeep(idMap) || {};
|
|
1812
|
-
entities.forEach((entity, i) => {
|
|
1813
|
-
if (isEntityDisabled(entity)) return;
|
|
1814
|
-
const entityId = getIdOrCodeOrIndex(entity, i);
|
|
1815
|
-
newIdMap[entityId] = { entity };
|
|
1816
|
-
});
|
|
1817
|
-
finalizeSelection({
|
|
1818
|
-
idMap: newIdMap,
|
|
1819
|
-
entities,
|
|
1820
|
-
props: {
|
|
1821
|
-
onDeselect,
|
|
1822
|
-
onSingleRowSelect,
|
|
1823
|
-
onMultiRowSelect,
|
|
1824
|
-
noDeselectAll,
|
|
1825
|
-
onRowSelect,
|
|
1826
|
-
noSelect,
|
|
1827
|
-
change
|
|
1828
|
-
}
|
|
1829
|
-
});
|
|
1830
|
-
};
|
|
1831
|
-
|
|
1832
|
-
const refocusTable = useCallback(() => {
|
|
1833
|
-
const table = tableRef.current?.tableRef?.closest(
|
|
1834
|
-
".data-table-container>div"
|
|
1835
|
-
);
|
|
1836
|
-
table?.focus();
|
|
1837
|
-
}, []);
|
|
1838
|
-
|
|
1839
|
-
const isSelectionARectangle = useCallback(() => {
|
|
1840
|
-
if (selectedCells && Object.keys(selectedCells).length > 1) {
|
|
1841
|
-
const pathToIndex = getFieldPathToIndex(schema);
|
|
1842
|
-
const entityMap = getEntityIdToEntity(entities);
|
|
1843
|
-
let selectionGrid = [];
|
|
1844
|
-
let firstCellIndex;
|
|
1845
|
-
let lastCellIndex;
|
|
1846
|
-
let lastRowIndex;
|
|
1847
|
-
let firstRowIndex;
|
|
1848
|
-
const selectedPaths = [];
|
|
1849
|
-
Object.keys(selectedCells).forEach(key => {
|
|
1850
|
-
// if (reduxFormSelectedCells[key] === PRIMARY_SELECTED_VAL) {
|
|
1851
|
-
// primaryCellId = key;
|
|
1852
|
-
// }
|
|
1853
|
-
const [rowId, cellPath] = key.split(":");
|
|
1854
|
-
if (!selectedPaths.includes(cellPath)) selectedPaths.push(cellPath);
|
|
1855
|
-
const cellIndex = pathToIndex[cellPath];
|
|
1856
|
-
const ent = entityMap[rowId];
|
|
1857
|
-
if (!ent) return;
|
|
1858
|
-
const { i } = ent;
|
|
1859
|
-
if (firstRowIndex === undefined || i < firstRowIndex) {
|
|
1860
|
-
firstRowIndex = i;
|
|
1861
|
-
}
|
|
1862
|
-
if (lastRowIndex === undefined || i > lastRowIndex) {
|
|
1863
|
-
lastRowIndex = i;
|
|
1864
|
-
}
|
|
1865
|
-
if (!selectionGrid[i]) selectionGrid[i] = [];
|
|
1866
|
-
selectionGrid[i][cellIndex] = { cellId: key, rowIndex: i, cellIndex };
|
|
1867
|
-
if (firstCellIndex === undefined || cellIndex < firstCellIndex) {
|
|
1868
|
-
firstCellIndex = cellIndex;
|
|
1869
|
-
}
|
|
1870
|
-
if (lastCellIndex === undefined || cellIndex > lastCellIndex) {
|
|
1871
|
-
lastCellIndex = cellIndex;
|
|
1872
|
-
}
|
|
1873
|
-
});
|
|
1874
|
-
selectionGrid = selectionGrid.slice(firstRowIndex);
|
|
1875
|
-
let isRectangle = true;
|
|
1876
|
-
for (let i = 0; i < selectionGrid.length; i++) {
|
|
1877
|
-
const row = selectionGrid[i];
|
|
1878
|
-
if (!row) {
|
|
1879
|
-
isRectangle = false;
|
|
1880
|
-
break;
|
|
1881
|
-
} else {
|
|
1882
|
-
for (let j = firstCellIndex; j < row.length; j++) {
|
|
1883
|
-
if (!row[j]) {
|
|
1884
|
-
isRectangle = false;
|
|
1885
|
-
break;
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1890
|
-
if (isRectangle) {
|
|
1891
|
-
return {
|
|
1892
|
-
entityMap,
|
|
1893
|
-
firstCellIndex,
|
|
1894
|
-
firstRowIndex,
|
|
1895
|
-
isRect: true,
|
|
1896
|
-
lastCellIndex,
|
|
1897
|
-
lastRowIndex,
|
|
1898
|
-
selectedPaths,
|
|
1899
|
-
selectionGrid,
|
|
1900
|
-
pathToIndex
|
|
1901
|
-
};
|
|
1902
|
-
} else {
|
|
1903
|
-
return {};
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
|
-
return {};
|
|
1907
|
-
}, [entities, schema, selectedCells]);
|
|
1908
|
-
|
|
1909
|
-
const handleCellClick = useCallback(
|
|
1910
|
-
({ event, cellId }) => {
|
|
1911
|
-
if (!cellId) return;
|
|
1912
|
-
const [rowId, cellPath] = cellId.split(":");
|
|
1913
|
-
const entityMap = getEntityIdToEntity(entities);
|
|
1914
|
-
const { e: entity, i: rowIndex } = entityMap[rowId];
|
|
1915
|
-
const pathToIndex = getFieldPathToIndex(schema);
|
|
1916
|
-
const columnIndex = pathToIndex[cellPath];
|
|
1917
|
-
const rowDisabled = isEntityDisabled(entity);
|
|
1918
|
-
|
|
1919
|
-
if (rowDisabled) return;
|
|
1920
|
-
let newSelectedCells = {
|
|
1921
|
-
...selectedCells
|
|
1922
|
-
};
|
|
1923
|
-
if (newSelectedCells[cellId] && !event.shiftKey) {
|
|
1924
|
-
// don't deselect if editing
|
|
1925
|
-
if (reduxFormEditingCell === cellId) return;
|
|
1926
|
-
if (event.metaKey) {
|
|
1927
|
-
delete newSelectedCells[cellId];
|
|
1928
|
-
} else {
|
|
1929
|
-
newSelectedCells = {};
|
|
1930
|
-
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
1931
|
-
}
|
|
1932
|
-
} else {
|
|
1933
|
-
if (event.metaKey) {
|
|
1934
|
-
if (isEmpty(newSelectedCells)) {
|
|
1935
|
-
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
1936
|
-
} else {
|
|
1937
|
-
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
1938
|
-
if (primarySelectedCellId)
|
|
1939
|
-
newSelectedCells[primarySelectedCellId] = true;
|
|
1940
|
-
}
|
|
1941
|
-
} else if (event.shiftKey) {
|
|
1942
|
-
if (primarySelectedCellId) {
|
|
1943
|
-
const [rowId, colPath] = primarySelectedCellId.split(":");
|
|
1944
|
-
const primaryRowIndex = entities.findIndex((e, i) => {
|
|
1945
|
-
return getIdOrCodeOrIndex(e, i) === rowId;
|
|
1946
|
-
});
|
|
1947
|
-
const fieldToIndex = getFieldPathToIndex(schema);
|
|
1948
|
-
const primaryColIndex = fieldToIndex[colPath];
|
|
1949
|
-
|
|
1950
|
-
if (primaryRowIndex === -1 || primaryColIndex === -1) {
|
|
1951
|
-
newSelectedCells = {};
|
|
1952
|
-
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
1953
|
-
} else {
|
|
1954
|
-
const minRowIndex = min([primaryRowIndex, rowIndex]);
|
|
1955
|
-
const minColIndex = min([primaryColIndex, columnIndex]);
|
|
1956
|
-
const maxRowIndex = max([primaryRowIndex, rowIndex]);
|
|
1957
|
-
const maxColIndex = max([primaryColIndex, columnIndex]);
|
|
1958
|
-
const entitiesBetweenRows = entities.slice(
|
|
1959
|
-
minRowIndex,
|
|
1960
|
-
maxRowIndex + 1
|
|
1961
|
-
);
|
|
1962
|
-
const fieldsBetweenCols = schema.fields.slice(
|
|
1963
|
-
minColIndex,
|
|
1964
|
-
maxColIndex + 1
|
|
1965
|
-
);
|
|
1966
|
-
newSelectedCells = {
|
|
1967
|
-
[primarySelectedCellId]: PRIMARY_SELECTED_VAL
|
|
1968
|
-
};
|
|
1969
|
-
entitiesBetweenRows.forEach(e => {
|
|
1970
|
-
const rowId = getIdOrCodeOrIndex(e, entities.indexOf(e));
|
|
1971
|
-
fieldsBetweenCols.forEach(f => {
|
|
1972
|
-
const cellId = `${rowId}:${f.path}`;
|
|
1973
|
-
if (!newSelectedCells[cellId])
|
|
1974
|
-
newSelectedCells[cellId] = true;
|
|
1975
|
-
});
|
|
1976
|
-
});
|
|
1977
|
-
// newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
1978
|
-
// newSelectedCells[primarySelectedCellId] = true;
|
|
1979
|
-
}
|
|
1980
|
-
} else {
|
|
1981
|
-
newSelectedCells = {};
|
|
1982
|
-
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
1983
|
-
}
|
|
1984
|
-
} else {
|
|
1985
|
-
newSelectedCells = {};
|
|
1986
|
-
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
1987
|
-
}
|
|
1988
|
-
}
|
|
1989
|
-
|
|
1990
|
-
setSelectedCells(newSelectedCells);
|
|
1991
|
-
},
|
|
1992
|
-
[
|
|
1993
|
-
entities,
|
|
1994
|
-
isEntityDisabled,
|
|
1995
|
-
primarySelectedCellId,
|
|
1996
|
-
reduxFormEditingCell,
|
|
1997
|
-
schema,
|
|
1998
|
-
selectedCells
|
|
1999
|
-
]
|
|
2000
|
-
);
|
|
2001
|
-
|
|
2002
|
-
const insertRows = useCallback(
|
|
2003
|
-
({ above, numRows = 1, appendToBottom } = {}) => {
|
|
2004
|
-
const [rowId] = primarySelectedCellId?.split(":") || [];
|
|
2005
|
-
updateEntitiesHelper(entities, entities => {
|
|
2006
|
-
const newEntities = times(numRows).map(() => ({ id: nanoid() }));
|
|
2007
|
-
|
|
2008
|
-
const indexToInsert = entities.findIndex((e, i) => {
|
|
2009
|
-
return getIdOrCodeOrIndex(e, i) === rowId;
|
|
2010
|
-
});
|
|
2011
|
-
const insertIndex = above ? indexToInsert : indexToInsert + 1;
|
|
2012
|
-
const insertIndexToUse = appendToBottom ? entities.length : insertIndex;
|
|
2013
|
-
let { newEnts, validationErrors } = formatAndValidateEntities(
|
|
2014
|
-
newEntities,
|
|
2015
|
-
{
|
|
2016
|
-
useDefaultValues: true,
|
|
2017
|
-
indexToStartAt: insertIndexToUse
|
|
2018
|
-
}
|
|
2019
|
-
);
|
|
2020
|
-
|
|
2021
|
-
newEnts = newEnts.map(e => ({
|
|
2022
|
-
...e,
|
|
2023
|
-
_isClean: true
|
|
2024
|
-
}));
|
|
2025
|
-
updateValidation(entities, {
|
|
2026
|
-
...reduxFormCellValidation,
|
|
2027
|
-
...validationErrors
|
|
2028
|
-
});
|
|
2029
|
-
|
|
2030
|
-
entities.splice(insertIndexToUse, 0, ...newEnts);
|
|
2031
|
-
});
|
|
2032
|
-
refocusTable();
|
|
2033
|
-
},
|
|
2034
|
-
[
|
|
2035
|
-
entities,
|
|
2036
|
-
formatAndValidateEntities,
|
|
2037
|
-
primarySelectedCellId,
|
|
2038
|
-
reduxFormCellValidation,
|
|
2039
|
-
refocusTable,
|
|
2040
|
-
updateEntitiesHelper,
|
|
2041
|
-
updateValidation
|
|
2042
|
-
]
|
|
2043
|
-
);
|
|
2044
|
-
|
|
2045
|
-
const showContextMenu = useCallback(
|
|
2046
|
-
(e, { idMap, selectedCells } = {}) => {
|
|
2047
|
-
let selectedRecords;
|
|
2048
|
-
if (isCellEditable) {
|
|
2049
|
-
const rowIds = {};
|
|
2050
|
-
Object.keys(selectedCells).forEach(cellKey => {
|
|
2051
|
-
const [rowId] = cellKey.split(":");
|
|
2052
|
-
rowIds[rowId] = true;
|
|
2053
|
-
});
|
|
2054
|
-
selectedRecords = entities.filter(
|
|
2055
|
-
ent => rowIds[getIdOrCodeOrIndex(ent)]
|
|
2056
|
-
);
|
|
2057
|
-
} else {
|
|
2058
|
-
selectedRecords = getRecordsFromIdMap(idMap);
|
|
2059
|
-
}
|
|
2060
|
-
|
|
2061
|
-
const itemsToRender = contextMenu({
|
|
2062
|
-
selectedRecords,
|
|
2063
|
-
history
|
|
2064
|
-
});
|
|
2065
|
-
if (!itemsToRender && !isCopyable) return null;
|
|
2066
|
-
const copyMenuItems = [];
|
|
2067
|
-
|
|
2068
|
-
e.persist();
|
|
2069
|
-
if (isCopyable) {
|
|
2070
|
-
//compute the cellWrapper here so we don't lose access to it
|
|
2071
|
-
const cellWrapper =
|
|
2072
|
-
e.target.querySelector(".tg-cell-wrapper") ||
|
|
2073
|
-
e.target.closest(".tg-cell-wrapper");
|
|
2074
|
-
if (cellWrapper) {
|
|
2075
|
-
copyMenuItems.push(
|
|
2076
|
-
<MenuItem
|
|
2077
|
-
key="copyCell"
|
|
2078
|
-
onClick={() => {
|
|
2079
|
-
//TODOCOPY: we need to make sure that the cell copy is being used by the row copy.. right now we have 2 different things going on
|
|
2080
|
-
//do we need to be able to copy hidden cells? It seems like it should just copy what's on the page..?
|
|
2081
|
-
const specificColumn = cellWrapper.getAttribute("data-test");
|
|
2082
|
-
handleCopyRows([cellWrapper.closest(".rt-tr")], {
|
|
2083
|
-
specificColumn,
|
|
2084
|
-
onFinishMsg: "Cell copied"
|
|
2085
|
-
});
|
|
2086
|
-
const [text, jsonText] = getCellCopyText(cellWrapper);
|
|
2087
|
-
handleCopyHelper(text, jsonText);
|
|
2088
|
-
}}
|
|
2089
|
-
text="Cell"
|
|
2090
|
-
/>
|
|
2091
|
-
);
|
|
2092
|
-
|
|
2093
|
-
copyMenuItems.push(
|
|
2094
|
-
<MenuItem
|
|
2095
|
-
key="copyColumn"
|
|
2096
|
-
onClick={() => {
|
|
2097
|
-
handleCopyColumn(e, cellWrapper);
|
|
2098
|
-
}}
|
|
2099
|
-
text="Column"
|
|
2100
|
-
/>
|
|
2101
|
-
);
|
|
2102
|
-
if (selectedRecords.length > 1) {
|
|
2103
|
-
copyMenuItems.push(
|
|
2104
|
-
<MenuItem
|
|
2105
|
-
key="copyColumnSelected"
|
|
2106
|
-
onClick={() => {
|
|
2107
|
-
handleCopyColumn(e, cellWrapper, selectedRecords);
|
|
2108
|
-
}}
|
|
2109
|
-
text="Column (Selected)"
|
|
2110
|
-
/>
|
|
2111
|
-
);
|
|
2112
|
-
}
|
|
2113
|
-
}
|
|
2114
|
-
if (selectedRecords.length === 0 || selectedRecords.length === 1) {
|
|
2115
|
-
//compute the row here so we don't lose access to it
|
|
2116
|
-
const cell =
|
|
2117
|
-
e.target.querySelector(".tg-cell-wrapper") ||
|
|
2118
|
-
e.target.closest(".tg-cell-wrapper") ||
|
|
2119
|
-
e.target.closest(".rt-td");
|
|
2120
|
-
const row = cell.closest(".rt-tr");
|
|
2121
|
-
copyMenuItems.push(
|
|
2122
|
-
<MenuItem
|
|
2123
|
-
key="copySelectedRows"
|
|
2124
|
-
onClick={() => {
|
|
2125
|
-
handleCopyRows([row]);
|
|
2126
|
-
// loop through each cell in the row
|
|
2127
|
-
}}
|
|
2128
|
-
text="Row"
|
|
2129
|
-
/>
|
|
2130
|
-
);
|
|
2131
|
-
} else if (selectedRecords.length > 1) {
|
|
2132
|
-
copyMenuItems.push(
|
|
2133
|
-
<MenuItem
|
|
2134
|
-
key="copySelectedRows"
|
|
2135
|
-
onClick={() => {
|
|
2136
|
-
handleCopySelectedRows(selectedRecords, e);
|
|
2137
|
-
// loop through each cell in the row
|
|
2138
|
-
}}
|
|
2139
|
-
text="Rows"
|
|
2140
|
-
/>
|
|
2141
|
-
);
|
|
2142
|
-
}
|
|
2143
|
-
copyMenuItems.push(
|
|
2144
|
-
<MenuItem
|
|
2145
|
-
key="copyFullTableRows"
|
|
2146
|
-
onClick={() => {
|
|
2147
|
-
handleCopyTable(e);
|
|
2148
|
-
// loop through each cell in the row
|
|
2149
|
-
}}
|
|
2150
|
-
text="Table"
|
|
2151
|
-
/>
|
|
2152
|
-
);
|
|
2153
|
-
}
|
|
2154
|
-
const selectedRowIds = Object.keys(selectedCells).map(cellId => {
|
|
2155
|
-
const [rowId] = cellId.split(":");
|
|
2156
|
-
return rowId;
|
|
2157
|
-
});
|
|
2158
|
-
|
|
2159
|
-
const menu = (
|
|
2160
|
-
<Menu>
|
|
2161
|
-
{itemsToRender}
|
|
2162
|
-
{copyMenuItems.length && (
|
|
2163
|
-
<MenuItem icon="clipboard" key="copyOpts" text="Copy">
|
|
2164
|
-
{copyMenuItems}
|
|
2165
|
-
</MenuItem>
|
|
2166
|
-
)}
|
|
2167
|
-
{isCellEditable && (
|
|
2168
|
-
<>
|
|
2169
|
-
<MenuItem
|
|
2170
|
-
icon="add-row-top"
|
|
2171
|
-
text="Add Row Above"
|
|
2172
|
-
key="addRowAbove"
|
|
2173
|
-
onClick={() => {
|
|
2174
|
-
insertRows({ above: true });
|
|
2175
|
-
}}
|
|
2176
|
-
/>
|
|
2177
|
-
<MenuItem
|
|
2178
|
-
icon="add-row-top"
|
|
2179
|
-
text="Add Row Below"
|
|
2180
|
-
key="addRowBelow"
|
|
2181
|
-
onClick={() => {
|
|
2182
|
-
insertRows({});
|
|
2183
|
-
}}
|
|
2184
|
-
/>
|
|
2185
|
-
<MenuItem
|
|
2186
|
-
icon="remove"
|
|
2187
|
-
text={`Remove Row${selectedRowIds.length > 1 ? "s" : ""}`}
|
|
2188
|
-
key="removeRow"
|
|
2189
|
-
onClick={() => {
|
|
2190
|
-
const selectedRowIds = Object.keys(selectedCells).map(
|
|
2191
|
-
cellId => {
|
|
2192
|
-
const [rowId] = cellId.split(":");
|
|
2193
|
-
return rowId;
|
|
2194
|
-
}
|
|
2195
|
-
);
|
|
2196
|
-
updateEntitiesHelper(entities, entities => {
|
|
2197
|
-
const ents = entities.filter(
|
|
2198
|
-
(e, i) =>
|
|
2199
|
-
!selectedRowIds.includes(getIdOrCodeOrIndex(e, i))
|
|
2200
|
-
);
|
|
2201
|
-
updateValidation(
|
|
2202
|
-
ents,
|
|
2203
|
-
omitBy(reduxFormCellValidation, (v, cellId) =>
|
|
2204
|
-
selectedRowIds.includes(cellId.split(":")[0])
|
|
2205
|
-
)
|
|
2206
|
-
);
|
|
2207
|
-
return ents;
|
|
2208
|
-
});
|
|
2209
|
-
refocusTable();
|
|
2210
|
-
}}
|
|
2211
|
-
/>
|
|
2212
|
-
</>
|
|
2213
|
-
)}
|
|
2214
|
-
</Menu>
|
|
2215
|
-
);
|
|
2216
|
-
ContextMenu.show(menu, { left: e.clientX, top: e.clientY });
|
|
2217
|
-
},
|
|
2218
|
-
[
|
|
2219
|
-
contextMenu,
|
|
2220
|
-
entities,
|
|
2221
|
-
handleCopySelectedRows,
|
|
2222
|
-
history,
|
|
2223
|
-
insertRows,
|
|
2224
|
-
isCellEditable,
|
|
2225
|
-
isCopyable,
|
|
2226
|
-
reduxFormCellValidation,
|
|
2227
|
-
refocusTable,
|
|
2228
|
-
updateEntitiesHelper,
|
|
2229
|
-
updateValidation
|
|
2230
|
-
]
|
|
2231
|
-
);
|
|
2232
|
-
|
|
2233
|
-
const getTableRowProps = useCallback(
|
|
2234
|
-
(state, rowInfo) => {
|
|
2235
|
-
if (!rowInfo) {
|
|
2236
|
-
return {
|
|
2237
|
-
className: "no-row-data"
|
|
2238
|
-
};
|
|
2239
|
-
}
|
|
2240
|
-
const entity = rowInfo.original;
|
|
2241
|
-
const rowId = getIdOrCodeOrIndex(entity, rowInfo.index);
|
|
2242
|
-
const rowSelected = reduxFormSelectedEntityIdMap[rowId];
|
|
2243
|
-
const isExpanded = expandedEntityIdMap[rowId];
|
|
2244
|
-
const rowDisabled = isEntityDisabled(entity);
|
|
2245
|
-
const dataId = entity.id || entity.code;
|
|
2246
|
-
return {
|
|
2247
|
-
onClick: e => {
|
|
2248
|
-
if (isCellEditable) return;
|
|
2249
|
-
// if checkboxes are activated or row expander is clicked don't select row
|
|
2250
|
-
if (e.target.matches(".tg-expander, .tg-expander *")) {
|
|
2251
|
-
setExpandedEntityIdMap(prev => ({ ...prev, [rowId]: !isExpanded }));
|
|
2252
|
-
return;
|
|
2253
|
-
} else if (
|
|
2254
|
-
e.target.closest(".tg-react-table-checkbox-cell-container")
|
|
2255
|
-
) {
|
|
2256
|
-
return;
|
|
2257
|
-
} else if (mustClickCheckboxToSelect) {
|
|
2258
|
-
return;
|
|
2259
|
-
}
|
|
2260
|
-
if (e.detail > 1) {
|
|
2261
|
-
return; //cancel multiple quick clicks
|
|
2262
|
-
}
|
|
2263
|
-
rowClick(e, rowInfo, entities, {
|
|
2264
|
-
reduxFormSelectedEntityIdMap,
|
|
2265
|
-
isSingleSelect,
|
|
2266
|
-
noSelect,
|
|
2267
|
-
onRowClick,
|
|
2268
|
-
isEntityDisabled,
|
|
2269
|
-
withCheckboxes,
|
|
2270
|
-
onDeselect,
|
|
2271
|
-
onSingleRowSelect,
|
|
2272
|
-
onMultiRowSelect,
|
|
2273
|
-
noDeselectAll,
|
|
2274
|
-
onRowSelect,
|
|
2275
|
-
change
|
|
2276
|
-
});
|
|
2277
|
-
},
|
|
2278
|
-
//row right click
|
|
2279
|
-
onContextMenu: e => {
|
|
2280
|
-
e.preventDefault();
|
|
2281
|
-
if (rowId === undefined || rowDisabled || isCellEditable) return;
|
|
2282
|
-
const oldIdMap = cloneDeep(reduxFormSelectedEntityIdMap) || {};
|
|
2283
|
-
let newIdMap;
|
|
2284
|
-
if (withCheckboxes) {
|
|
2285
|
-
newIdMap = oldIdMap;
|
|
2286
|
-
} else {
|
|
2287
|
-
// if we are not using checkboxes we need to make sure
|
|
2288
|
-
// that the id of the record gets added to the id map
|
|
2289
|
-
newIdMap = oldIdMap[rowId] ? oldIdMap : { [rowId]: { entity } };
|
|
2290
|
-
|
|
2291
|
-
// tgreen: this will refresh the selection with fresh data. The entities in redux might not be up to date
|
|
2292
|
-
const keyedEntities = keyBy(entities, getIdOrCodeOrIndex);
|
|
2293
|
-
forEach(newIdMap, (val, key) => {
|
|
2294
|
-
const freshEntity = keyedEntities[key];
|
|
2295
|
-
if (freshEntity) {
|
|
2296
|
-
newIdMap[key] = { ...newIdMap[key], entity: freshEntity };
|
|
2297
|
-
}
|
|
2298
|
-
});
|
|
2299
|
-
finalizeSelection({
|
|
2300
|
-
idMap: newIdMap,
|
|
2301
|
-
entities,
|
|
2302
|
-
props: {
|
|
2303
|
-
onDeselect,
|
|
2304
|
-
onSingleRowSelect,
|
|
2305
|
-
onMultiRowSelect,
|
|
2306
|
-
noDeselectAll,
|
|
2307
|
-
onRowSelect,
|
|
2308
|
-
noSelect,
|
|
2309
|
-
change
|
|
2310
|
-
}
|
|
2311
|
-
});
|
|
2312
|
-
}
|
|
2313
|
-
showContextMenu(e, { idMap: newIdMap, selectedCells });
|
|
2314
|
-
},
|
|
2315
|
-
className: classNames(
|
|
2316
|
-
"with-row-data",
|
|
2317
|
-
getRowClassName && getRowClassName(rowInfo, state),
|
|
2318
|
-
{
|
|
2319
|
-
disabled: rowDisabled,
|
|
2320
|
-
selected: rowSelected && !withCheckboxes,
|
|
2321
|
-
"rt-tr-last-row": rowInfo.index === entities.length - 1
|
|
2322
|
-
}
|
|
2323
|
-
),
|
|
2324
|
-
"data-test-id": dataId === undefined ? rowInfo.index : dataId,
|
|
2325
|
-
"data-index": rowInfo.index,
|
|
2326
|
-
"data-tip": typeof rowDisabled === "string" ? rowDisabled : undefined,
|
|
2327
|
-
onDoubleClick: e => {
|
|
2328
|
-
if (rowDisabled) return;
|
|
2329
|
-
onDoubleClick &&
|
|
2330
|
-
onDoubleClick(rowInfo.original, rowInfo.index, history, e);
|
|
2331
|
-
}
|
|
2332
|
-
};
|
|
2333
|
-
},
|
|
2334
|
-
[
|
|
2335
|
-
change,
|
|
2336
|
-
entities,
|
|
2337
|
-
expandedEntityIdMap,
|
|
2338
|
-
getRowClassName,
|
|
2339
|
-
history,
|
|
2340
|
-
isCellEditable,
|
|
2341
|
-
isEntityDisabled,
|
|
2342
|
-
isSingleSelect,
|
|
2343
|
-
mustClickCheckboxToSelect,
|
|
2344
|
-
noDeselectAll,
|
|
2345
|
-
noSelect,
|
|
2346
|
-
onDeselect,
|
|
2347
|
-
onDoubleClick,
|
|
2348
|
-
onMultiRowSelect,
|
|
2349
|
-
onRowClick,
|
|
2350
|
-
onRowSelect,
|
|
2351
|
-
onSingleRowSelect,
|
|
2352
|
-
reduxFormSelectedEntityIdMap,
|
|
2353
|
-
selectedCells,
|
|
2354
|
-
showContextMenu,
|
|
2355
|
-
withCheckboxes
|
|
2356
|
-
]
|
|
2357
|
-
);
|
|
2358
|
-
|
|
2359
|
-
const getTableCellProps = useCallback(
|
|
2360
|
-
(state, rowInfo, column) => {
|
|
2361
|
-
if (!isCellEditable) return {}; //only allow cell selection to do stuff here
|
|
2362
|
-
if (!rowInfo) return {};
|
|
2363
|
-
if (!reduxFormCellValidation) return {};
|
|
2364
|
-
const entity = rowInfo.original;
|
|
2365
|
-
const rowIndex = rowInfo.index;
|
|
2366
|
-
const rowId = getIdOrCodeOrIndex(entity, rowIndex);
|
|
2367
|
-
const {
|
|
2368
|
-
cellId,
|
|
2369
|
-
cellIdAbove,
|
|
2370
|
-
cellIdToRight,
|
|
2371
|
-
cellIdBelow,
|
|
2372
|
-
cellIdToLeft,
|
|
2373
|
-
rowDisabled,
|
|
2374
|
-
columnIndex
|
|
2375
|
-
} = getCellInfo({
|
|
2376
|
-
columnIndex: column.index,
|
|
2377
|
-
columnPath: column.path,
|
|
2378
|
-
rowId,
|
|
2379
|
-
schema,
|
|
2380
|
-
entities,
|
|
2381
|
-
rowIndex,
|
|
2382
|
-
isEntityDisabled,
|
|
2383
|
-
entity
|
|
2384
|
-
});
|
|
2385
|
-
|
|
2386
|
-
const _isClean =
|
|
2387
|
-
(entity._isClean && doNotValidateUntouchedRows) ||
|
|
2388
|
-
isEntityClean(entity);
|
|
2389
|
-
|
|
2390
|
-
const err = !_isClean && reduxFormCellValidation[cellId];
|
|
2391
|
-
let selectedTopBorder,
|
|
2392
|
-
selectedRightBorder,
|
|
2393
|
-
selectedBottomBorder,
|
|
2394
|
-
selectedLeftBorder;
|
|
2395
|
-
if (selectedCells[cellId]) {
|
|
2396
|
-
selectedTopBorder = !selectedCells[cellIdAbove];
|
|
2397
|
-
selectedRightBorder = !selectedCells[cellIdToRight];
|
|
2398
|
-
selectedBottomBorder = !selectedCells[cellIdBelow];
|
|
2399
|
-
selectedLeftBorder = !selectedCells[cellIdToLeft];
|
|
2400
|
-
}
|
|
2401
|
-
const isPrimarySelected = selectedCells[cellId] === PRIMARY_SELECTED_VAL;
|
|
2402
|
-
const className = classNames({
|
|
2403
|
-
isSelectedCell: selectedCells[cellId],
|
|
2404
|
-
isPrimarySelected,
|
|
2405
|
-
isSecondarySelected: selectedCells[cellId] === true,
|
|
2406
|
-
noSelectedTopBorder: !selectedTopBorder,
|
|
2407
|
-
isCleanRow: _isClean,
|
|
2408
|
-
noSelectedRightBorder: !selectedRightBorder,
|
|
2409
|
-
noSelectedBottomBorder: !selectedBottomBorder,
|
|
2410
|
-
noSelectedLeftBorder: !selectedLeftBorder,
|
|
2411
|
-
isDropdownCell: column.type === "dropdown",
|
|
2412
|
-
isEditingCell: reduxFormEditingCell === cellId,
|
|
2413
|
-
hasCellError: !!err,
|
|
2414
|
-
"no-data-tip": selectedCells[cellId]
|
|
2415
|
-
});
|
|
2416
|
-
return {
|
|
2417
|
-
onDoubleClick: () => {
|
|
2418
|
-
// cell double click
|
|
2419
|
-
if (rowDisabled) return;
|
|
2420
|
-
startCellEdit(cellId);
|
|
2421
|
-
},
|
|
2422
|
-
...(err && {
|
|
2423
|
-
"data-tip": err?.message || err,
|
|
2424
|
-
"data-no-child-data-tip": true
|
|
2425
|
-
}),
|
|
2426
|
-
onContextMenu: e => {
|
|
2427
|
-
const newSelectedCells = { ...selectedCells };
|
|
2428
|
-
if (!isPrimarySelected) {
|
|
2429
|
-
if (primarySelectedCellId) {
|
|
2430
|
-
newSelectedCells[primarySelectedCellId] = true;
|
|
2431
|
-
}
|
|
2432
|
-
newSelectedCells[cellId] = PRIMARY_SELECTED_VAL;
|
|
2433
|
-
setSelectedCells(newSelectedCells);
|
|
2434
|
-
}
|
|
2435
|
-
showContextMenu(e, { selectedCells: newSelectedCells });
|
|
2436
|
-
},
|
|
2437
|
-
onClick: event => {
|
|
2438
|
-
handleCellClick({
|
|
2439
|
-
event,
|
|
2440
|
-
cellId,
|
|
2441
|
-
rowDisabled,
|
|
2442
|
-
rowIndex,
|
|
2443
|
-
columnIndex
|
|
2444
|
-
});
|
|
2445
|
-
},
|
|
2446
|
-
className
|
|
2447
|
-
};
|
|
2448
|
-
},
|
|
2449
|
-
[
|
|
2450
|
-
doNotValidateUntouchedRows,
|
|
2451
|
-
entities,
|
|
2452
|
-
handleCellClick,
|
|
2453
|
-
isCellEditable,
|
|
2454
|
-
isEntityDisabled,
|
|
2455
|
-
primarySelectedCellId,
|
|
2456
|
-
reduxFormCellValidation,
|
|
2457
|
-
reduxFormEditingCell,
|
|
2458
|
-
schema,
|
|
2459
|
-
selectedCells,
|
|
2460
|
-
showContextMenu,
|
|
2461
|
-
startCellEdit
|
|
2462
|
-
]
|
|
2463
|
-
);
|
|
2464
|
-
|
|
2465
|
-
if (withSelectAll && !safeQuery) {
|
|
2466
|
-
throw new Error("safeQuery is needed for selecting all table records");
|
|
2467
|
-
}
|
|
2468
|
-
|
|
2469
|
-
let compactClassName = "";
|
|
2470
|
-
if (compactPaging) {
|
|
2471
|
-
compactClassName += " tg-compact-paging";
|
|
2472
|
-
}
|
|
2473
|
-
compactClassName += extraCompact
|
|
2474
|
-
? " tg-extra-compact-table"
|
|
2475
|
-
: compact
|
|
2476
|
-
? " tg-compact-table"
|
|
2477
|
-
: "";
|
|
2478
|
-
|
|
2479
|
-
const hasFilters =
|
|
2480
|
-
filters.length ||
|
|
2481
|
-
searchTerm ||
|
|
2482
|
-
schema.fields.some(
|
|
2483
|
-
field => field.filterIsActive && field.filterIsActive(currentParams)
|
|
2484
|
-
);
|
|
2485
|
-
|
|
2486
|
-
const additionalFilterKeys = schema.fields.reduce((acc, field) => {
|
|
2487
|
-
if (field.filterKey) acc.push(field.filterKey);
|
|
2488
|
-
return acc;
|
|
2489
|
-
}, []);
|
|
2490
|
-
|
|
2491
|
-
const filtersOnNonDisplayedFields = useMemo(() => {
|
|
2492
|
-
const _filtersOnNonDisplayedFields = [];
|
|
2493
|
-
if (filters && filters.length) {
|
|
2494
|
-
schema.fields.forEach(field => {
|
|
2495
|
-
const ccDisplayName = getCCDisplayName(field);
|
|
2496
|
-
if (field.isHidden) {
|
|
2497
|
-
filters.forEach(filter => {
|
|
2498
|
-
if (filter.filterOn === ccDisplayName) {
|
|
2499
|
-
_filtersOnNonDisplayedFields.push({
|
|
2500
|
-
...filter,
|
|
2501
|
-
displayName: field.displayName
|
|
2502
|
-
});
|
|
2503
|
-
}
|
|
2504
|
-
});
|
|
2505
|
-
}
|
|
2506
|
-
});
|
|
2507
|
-
}
|
|
2508
|
-
return _filtersOnNonDisplayedFields;
|
|
2509
|
-
}, [filters, schema.fields]);
|
|
2510
|
-
|
|
2511
|
-
const numRows = isInfinite ? entities.length : pageSize;
|
|
2512
|
-
const idMap = useMemo(
|
|
2513
|
-
() => reduxFormSelectedEntityIdMap || {},
|
|
2514
|
-
[reduxFormSelectedEntityIdMap]
|
|
2515
|
-
);
|
|
2516
|
-
const selectedRowCount = Object.keys(idMap).filter(key => idMap[key]).length;
|
|
2517
|
-
|
|
2518
|
-
let rowsToShow = doNotShowEmptyRows
|
|
2519
|
-
? Math.min(numRows, entities.length)
|
|
2520
|
-
: numRows;
|
|
2521
|
-
// if there are no entities then provide enough space to show
|
|
2522
|
-
// no rows found message
|
|
2523
|
-
if (entities.length === 0 && rowsToShow < 3) rowsToShow = 3;
|
|
2524
|
-
const expandedRows = entities.reduce((acc, row, index) => {
|
|
2525
|
-
const rowId = getIdOrCodeOrIndex(row, index);
|
|
2526
|
-
acc[index] = expandedEntityIdMap[rowId];
|
|
2527
|
-
return acc;
|
|
2528
|
-
}, {});
|
|
2529
|
-
|
|
2530
|
-
const showHeader = (withTitle || withSearch || children) && !noHeader;
|
|
2531
|
-
const toggleFullscreenButton = (
|
|
2532
|
-
<Button
|
|
2533
|
-
icon="fullscreen"
|
|
2534
|
-
active={fullscreen}
|
|
2535
|
-
minimal
|
|
2536
|
-
onClick={() => setFullscreen(prev => !prev)}
|
|
2537
|
-
/>
|
|
2538
|
-
);
|
|
2539
|
-
|
|
2540
|
-
const { showSelectAll, showClearAll } = useMemo(() => {
|
|
2541
|
-
let _showSelectAll = false;
|
|
2542
|
-
let _showClearAll = false;
|
|
2543
|
-
// we want to show select all if every row on the current page is selected
|
|
2544
|
-
// and not every row across all pages are already selected.
|
|
2545
|
-
if (!isInfinite) {
|
|
2546
|
-
const canShowSelectAll =
|
|
2547
|
-
withSelectAll ||
|
|
2548
|
-
(entitiesAcrossPages && numRows < entitiesAcrossPages.length);
|
|
2549
|
-
if (canShowSelectAll) {
|
|
2550
|
-
// could all be disabled
|
|
2551
|
-
let atLeastOneRowOnCurrentPageSelected = false;
|
|
2552
|
-
const allRowsOnCurrentPageSelected = entities.every(e => {
|
|
2553
|
-
const rowId = getIdOrCodeOrIndex(e);
|
|
2554
|
-
const selected = idMap[rowId] || isEntityDisabled(e);
|
|
2555
|
-
if (selected) atLeastOneRowOnCurrentPageSelected = true;
|
|
2556
|
-
return selected;
|
|
2557
|
-
});
|
|
2558
|
-
if (
|
|
2559
|
-
atLeastOneRowOnCurrentPageSelected &&
|
|
2560
|
-
allRowsOnCurrentPageSelected
|
|
2561
|
-
) {
|
|
2562
|
-
let everyEntitySelected;
|
|
2563
|
-
if (isLocalCall) {
|
|
2564
|
-
everyEntitySelected = entitiesAcrossPages.every(e => {
|
|
2565
|
-
const rowId = getIdOrCodeOrIndex(e);
|
|
2566
|
-
return idMap[rowId] || isEntityDisabled(e);
|
|
2567
|
-
});
|
|
2568
|
-
} else {
|
|
2569
|
-
everyEntitySelected = entityCount <= selectedRowCount;
|
|
2570
|
-
}
|
|
2571
|
-
if (everyEntitySelected) {
|
|
2572
|
-
_showClearAll = selectedRowCount;
|
|
2573
|
-
}
|
|
2574
|
-
// only show if not all selected
|
|
2575
|
-
_showSelectAll = !everyEntitySelected;
|
|
2576
|
-
}
|
|
2577
|
-
}
|
|
2578
|
-
}
|
|
2579
|
-
return { showSelectAll: _showSelectAll, showClearAll: _showClearAll };
|
|
2580
|
-
}, [
|
|
2581
|
-
entities,
|
|
2582
|
-
entitiesAcrossPages,
|
|
2583
|
-
entityCount,
|
|
2584
|
-
idMap,
|
|
2585
|
-
isEntityDisabled,
|
|
2586
|
-
isInfinite,
|
|
2587
|
-
isLocalCall,
|
|
2588
|
-
numRows,
|
|
2589
|
-
selectedRowCount,
|
|
2590
|
-
withSelectAll
|
|
2591
|
-
]);
|
|
2592
|
-
|
|
2593
|
-
const showNumSelected = !noSelect && !isSingleSelect && !hideSelectedCount;
|
|
2594
|
-
const selectedAndTotalMessage = useMemo(() => {
|
|
2595
|
-
let _selectedAndTotalMessage = "";
|
|
2596
|
-
if (showNumSelected) {
|
|
2597
|
-
_selectedAndTotalMessage += `${selectedRowCount} Selected `;
|
|
2598
|
-
}
|
|
2599
|
-
if (showCount && showNumSelected) {
|
|
2600
|
-
_selectedAndTotalMessage += `/ `;
|
|
2601
|
-
}
|
|
2602
|
-
if (showCount) {
|
|
2603
|
-
_selectedAndTotalMessage += `${entityCount || 0} Total`;
|
|
2604
|
-
}
|
|
2605
|
-
if (_selectedAndTotalMessage) {
|
|
2606
|
-
_selectedAndTotalMessage = <div>{_selectedAndTotalMessage}</div>;
|
|
2607
|
-
}
|
|
2608
|
-
return _selectedAndTotalMessage;
|
|
2609
|
-
}, [entityCount, selectedRowCount, showCount, showNumSelected]);
|
|
2610
|
-
|
|
2611
|
-
const shouldShowPaging =
|
|
2612
|
-
!isInfinite &&
|
|
2613
|
-
withPaging &&
|
|
2614
|
-
(hidePageSizeWhenPossible ? entityCount > pageSize : true);
|
|
2615
|
-
|
|
2616
|
-
const SubComponentToUse = useMemo(() => {
|
|
2617
|
-
if (SubComponent) {
|
|
2618
|
-
return row => {
|
|
2619
|
-
let shouldShow = true;
|
|
2620
|
-
if (shouldShowSubComponent) {
|
|
2621
|
-
shouldShow = shouldShowSubComponent(row.original);
|
|
2622
|
-
}
|
|
2623
|
-
if (shouldShow) {
|
|
2624
|
-
return SubComponent(row);
|
|
2625
|
-
}
|
|
2626
|
-
};
|
|
2627
|
-
}
|
|
2628
|
-
return;
|
|
2629
|
-
}, [SubComponent, shouldShowSubComponent]);
|
|
2630
|
-
|
|
2631
|
-
const nonDisplayedFilterComp = useMemo(() => {
|
|
2632
|
-
if (filtersOnNonDisplayedFields.length) {
|
|
2633
|
-
const content = filtersOnNonDisplayedFields.map(
|
|
2634
|
-
({ displayName, path, selectedFilter, filterValue }) => {
|
|
2635
|
-
let filterValToDisplay = filterValue;
|
|
2636
|
-
if (selectedFilter === "inList") {
|
|
2637
|
-
filterValToDisplay = Array.isArray(filterValToDisplay)
|
|
2638
|
-
? filterValToDisplay
|
|
2639
|
-
: filterValToDisplay && filterValToDisplay.split(";");
|
|
2640
|
-
}
|
|
2641
|
-
if (Array.isArray(filterValToDisplay)) {
|
|
2642
|
-
filterValToDisplay = filterValToDisplay.join(", ");
|
|
2643
|
-
}
|
|
2644
|
-
return (
|
|
2645
|
-
<div
|
|
2646
|
-
key={displayName || startCase(camelCase(path))}
|
|
2647
|
-
className="tg-filter-on-non-displayed-field"
|
|
2648
|
-
>
|
|
2649
|
-
{displayName || startCase(camelCase(path))}{" "}
|
|
2650
|
-
{lowerCase(selectedFilter)} {filterValToDisplay}
|
|
2651
|
-
</div>
|
|
2652
|
-
);
|
|
2653
|
-
}
|
|
2654
|
-
);
|
|
2655
|
-
return (
|
|
2656
|
-
<div style={{ marginRight: 5, marginLeft: "auto" }}>
|
|
2657
|
-
<Tooltip
|
|
2658
|
-
content={
|
|
2659
|
-
<div>
|
|
2660
|
-
Active filters on hidden columns:
|
|
2661
|
-
<br />
|
|
2662
|
-
<br />
|
|
2663
|
-
{content}
|
|
2664
|
-
</div>
|
|
2665
|
-
}
|
|
2666
|
-
>
|
|
2667
|
-
<Icon icon="filter-list" />
|
|
2668
|
-
</Tooltip>
|
|
2669
|
-
</div>
|
|
2670
|
-
);
|
|
2671
|
-
}
|
|
2672
|
-
return null;
|
|
2673
|
-
}, [filtersOnNonDisplayedFields]);
|
|
2674
|
-
|
|
2675
|
-
const filteredEnts = useMemo(() => {
|
|
2676
|
-
if (onlyShowRowsWErrors) {
|
|
2677
|
-
const rowToErrorMap = {};
|
|
2678
|
-
forEach(reduxFormCellValidation, (err, cellId) => {
|
|
2679
|
-
if (err) {
|
|
2680
|
-
const [rowId] = cellId.split(":");
|
|
2681
|
-
rowToErrorMap[rowId] = true;
|
|
2682
|
-
}
|
|
2683
|
-
});
|
|
2684
|
-
return entities.filter(e => {
|
|
2685
|
-
return rowToErrorMap[e.id];
|
|
2686
|
-
});
|
|
2687
|
-
}
|
|
2688
|
-
return entities;
|
|
2689
|
-
}, [entities, onlyShowRowsWErrors, reduxFormCellValidation]);
|
|
2690
|
-
|
|
2691
|
-
const renderColumns = useColumns({
|
|
2692
|
-
addFilters,
|
|
2693
|
-
cellRenderer,
|
|
2694
|
-
columns,
|
|
2695
|
-
currentParams,
|
|
2696
|
-
compact,
|
|
2697
|
-
editingCellSelectAll,
|
|
2698
|
-
entities,
|
|
2699
|
-
expandedEntityIdMap,
|
|
2700
|
-
extraCompact,
|
|
2701
|
-
filters,
|
|
2702
|
-
formName,
|
|
2703
|
-
getCellHoverText,
|
|
2704
|
-
isCellEditable,
|
|
2705
|
-
isEntityDisabled,
|
|
2706
|
-
isLocalCall,
|
|
2707
|
-
isSimple,
|
|
2708
|
-
isSingleSelect,
|
|
2709
|
-
isSelectionARectangle,
|
|
2710
|
-
noDeselectAll,
|
|
2711
|
-
noSelect,
|
|
2712
|
-
noUserSelect,
|
|
2713
|
-
onDeselect,
|
|
2714
|
-
onMultiRowSelect,
|
|
2715
|
-
onRowClick,
|
|
2716
|
-
onRowSelect,
|
|
2717
|
-
onSingleRowSelect,
|
|
2718
|
-
order,
|
|
2719
|
-
primarySelectedCellId,
|
|
2720
|
-
reduxFormCellValidation,
|
|
2721
|
-
reduxFormSelectedEntityIdMap,
|
|
2722
|
-
refocusTable,
|
|
2723
|
-
removeSingleFilter,
|
|
2724
|
-
schema,
|
|
2725
|
-
selectedCells,
|
|
2726
|
-
setExpandedEntityIdMap,
|
|
2727
|
-
setNewParams,
|
|
2728
|
-
setOrder,
|
|
2729
|
-
setSelectedCells,
|
|
2730
|
-
shouldShowSubComponent,
|
|
2731
|
-
startCellEdit,
|
|
2732
|
-
SubComponent,
|
|
2733
|
-
tableRef,
|
|
2734
|
-
updateEntitiesHelper,
|
|
2735
|
-
updateValidation,
|
|
2736
|
-
withCheckboxes,
|
|
2737
|
-
withExpandAndCollapseAllButton,
|
|
2738
|
-
withFilter,
|
|
2739
|
-
withSort,
|
|
2740
|
-
recordIdToIsVisibleMap,
|
|
2741
|
-
setRecordIdToIsVisibleMap
|
|
2742
|
-
});
|
|
2743
|
-
|
|
2744
|
-
const scrollToTop = useCallback(
|
|
2745
|
-
() =>
|
|
2746
|
-
tableRef.current?.tableRef?.children?.[0]?.children?.[0]?.scrollIntoView(),
|
|
2747
|
-
[]
|
|
2748
|
-
);
|
|
2749
|
-
|
|
2750
|
-
const reactTable = useMemo(
|
|
2751
|
-
() => (
|
|
2752
|
-
<ReactTable
|
|
2753
|
-
data={filteredEnts}
|
|
2754
|
-
ref={tableRef}
|
|
2755
|
-
className={classNames({
|
|
2756
|
-
isCellEditable,
|
|
2757
|
-
"tg-table-loading": isLoading,
|
|
2758
|
-
"tg-table-disabled": disabled
|
|
2759
|
-
})}
|
|
2760
|
-
itemSizeEstimator={
|
|
2761
|
-
extraCompact
|
|
2762
|
-
? itemSizeEstimators.compact
|
|
2763
|
-
: compact
|
|
2764
|
-
? itemSizeEstimators.normal
|
|
2765
|
-
: itemSizeEstimators.comfortable
|
|
2766
|
-
}
|
|
2767
|
-
TfootComponent={() => {
|
|
2768
|
-
return <button>hasdfasdf</button>;
|
|
2769
|
-
}}
|
|
2770
|
-
// We should try to not give all the props to the render column
|
|
2771
|
-
columns={renderColumns}
|
|
2772
|
-
pageSize={rowsToShow}
|
|
2773
|
-
expanded={expandedRows}
|
|
2774
|
-
showPagination={false}
|
|
2775
|
-
sortable={false}
|
|
2776
|
-
loading={isLoading || disabled}
|
|
2777
|
-
defaultResized={resized}
|
|
2778
|
-
onResizedChange={(newResized = []) => {
|
|
2779
|
-
const resizedToUse = newResized.map(column => {
|
|
2780
|
-
// have a min width of 50 so that columns don't disappear
|
|
2781
|
-
if (column.value < 50) {
|
|
2782
|
-
return {
|
|
2783
|
-
...column,
|
|
2784
|
-
value: 50
|
|
2785
|
-
};
|
|
2786
|
-
} else {
|
|
2787
|
-
return column;
|
|
2788
|
-
}
|
|
2789
|
-
});
|
|
2790
|
-
resizePersist(resizedToUse);
|
|
2791
|
-
}}
|
|
2792
|
-
TheadComponent={TheadComponent}
|
|
2793
|
-
ThComponent={ThComponent}
|
|
2794
|
-
getTrGroupProps={getTableRowProps}
|
|
2795
|
-
getTdProps={getTableCellProps}
|
|
2796
|
-
NoDataComponent={({ children }) =>
|
|
2797
|
-
isLoading ? null : (
|
|
2798
|
-
<div className="rt-noData">{noRowsFoundMessage || children}</div>
|
|
2799
|
-
)
|
|
2800
|
-
}
|
|
2801
|
-
LoadingComponent={({ loadingText, loading }) => (
|
|
2802
|
-
<DisabledLoadingComponent
|
|
2803
|
-
loading={loading}
|
|
2804
|
-
loadingText={loadingText}
|
|
2805
|
-
disabled={disabled}
|
|
2806
|
-
/>
|
|
2807
|
-
)}
|
|
2808
|
-
style={{
|
|
2809
|
-
maxHeight,
|
|
2810
|
-
minHeight: 150,
|
|
2811
|
-
...style
|
|
2812
|
-
}}
|
|
2813
|
-
SubComponent={SubComponentToUse}
|
|
2814
|
-
{...ReactTableProps}
|
|
2815
|
-
/>
|
|
2816
|
-
),
|
|
2817
|
-
[
|
|
2818
|
-
ReactTableProps,
|
|
2819
|
-
SubComponentToUse,
|
|
2820
|
-
TheadComponent,
|
|
2821
|
-
compact,
|
|
2822
|
-
disabled,
|
|
2823
|
-
expandedRows,
|
|
2824
|
-
extraCompact,
|
|
2825
|
-
filteredEnts,
|
|
2826
|
-
getTableCellProps,
|
|
2827
|
-
getTableRowProps,
|
|
2828
|
-
isCellEditable,
|
|
2829
|
-
isLoading,
|
|
2830
|
-
maxHeight,
|
|
2831
|
-
noRowsFoundMessage,
|
|
2832
|
-
renderColumns,
|
|
2833
|
-
resizePersist,
|
|
2834
|
-
resized,
|
|
2835
|
-
rowsToShow,
|
|
2836
|
-
style
|
|
2837
|
-
]
|
|
2838
|
-
);
|
|
2839
|
-
|
|
2840
|
-
return (
|
|
2841
|
-
<div tabIndex="1" onKeyDown={handleKeyDown} onKeyUp={handleKeyUp}>
|
|
2842
|
-
<div
|
|
2843
|
-
className={classNames(
|
|
2844
|
-
"data-table-container",
|
|
2845
|
-
extraClasses,
|
|
2846
|
-
className,
|
|
2847
|
-
compactClassName,
|
|
2848
|
-
{
|
|
2849
|
-
fullscreen,
|
|
2850
|
-
in_cypress_test: window.Cypress, //tnr: this is a hack to make cypress be able to correctly click the table without the sticky header getting in the way. remove me once https://github.com/cypress-io/cypress/issues/871 is fixed
|
|
2851
|
-
"dt-isViewable": isViewable,
|
|
2852
|
-
"dt-minimalStyle": minimalStyle,
|
|
2853
|
-
"no-padding": noPadding,
|
|
2854
|
-
"hide-column-header": hideColumnHeader
|
|
2855
|
-
}
|
|
2856
|
-
)}
|
|
2857
|
-
>
|
|
2858
|
-
<div
|
|
2859
|
-
className="data-table-container-inner"
|
|
2860
|
-
{...(isCellEditable && {
|
|
2861
|
-
tabIndex: -1,
|
|
2862
|
-
onKeyDown: e => {
|
|
2863
|
-
const isTabKey = e.key === "Tab";
|
|
2864
|
-
const isArrowKey = e.key.startsWith("Arrow");
|
|
2865
|
-
if ((isArrowKey && e.target?.tagName !== "INPUT") || isTabKey) {
|
|
2866
|
-
const left = e.key === "ArrowLeft";
|
|
2867
|
-
const up = e.key === "ArrowUp";
|
|
2868
|
-
const down = e.key === "ArrowDown" || e.key === "Enter";
|
|
2869
|
-
let cellIdToUse = primarySelectedCellId;
|
|
2870
|
-
const pathToIndex = getFieldPathToIndex(schema);
|
|
2871
|
-
const entityMap = getEntityIdToEntity(entities);
|
|
2872
|
-
if (!cellIdToUse) return;
|
|
2873
|
-
const {
|
|
2874
|
-
isRect,
|
|
2875
|
-
firstCellIndex,
|
|
2876
|
-
lastCellIndex,
|
|
2877
|
-
lastRowIndex,
|
|
2878
|
-
firstRowIndex
|
|
2879
|
-
} = isSelectionARectangle();
|
|
2880
|
-
|
|
2881
|
-
if (isRect) {
|
|
2882
|
-
const [rowId, columnPath] = cellIdToUse.split(":");
|
|
2883
|
-
|
|
2884
|
-
const columnIndex = pathToIndex[columnPath];
|
|
2885
|
-
const indexToPath = invert(pathToIndex);
|
|
2886
|
-
// we want to grab the cell opposite to the primary selected cell
|
|
2887
|
-
if (
|
|
2888
|
-
firstCellIndex === columnIndex &&
|
|
2889
|
-
firstRowIndex === entityMap[rowId]?.i
|
|
2890
|
-
) {
|
|
2891
|
-
cellIdToUse = `${entities[lastRowIndex].id}:${indexToPath[lastCellIndex]}`;
|
|
2892
|
-
} else if (
|
|
2893
|
-
firstCellIndex === columnIndex &&
|
|
2894
|
-
lastRowIndex === entityMap[rowId]?.i
|
|
2895
|
-
) {
|
|
2896
|
-
cellIdToUse = `${entities[firstRowIndex].id}:${indexToPath[lastCellIndex]}`;
|
|
2897
|
-
} else if (
|
|
2898
|
-
lastCellIndex === columnIndex &&
|
|
2899
|
-
firstRowIndex === entityMap[rowId]?.i
|
|
2900
|
-
) {
|
|
2901
|
-
cellIdToUse = `${entities[lastRowIndex].id}:${indexToPath[firstCellIndex]}`;
|
|
2902
|
-
} else {
|
|
2903
|
-
cellIdToUse = `${entities[firstRowIndex].id}:${indexToPath[firstCellIndex]}`;
|
|
2904
|
-
}
|
|
2905
|
-
}
|
|
2906
|
-
if (!cellIdToUse) return;
|
|
2907
|
-
const [rowId, columnPath] = cellIdToUse.split(":");
|
|
2908
|
-
const columnIndex = pathToIndex[columnPath];
|
|
2909
|
-
|
|
2910
|
-
const { i: rowIndex } = entityMap[rowId];
|
|
2911
|
-
|
|
2912
|
-
const {
|
|
2913
|
-
cellIdAbove,
|
|
2914
|
-
cellIdToRight,
|
|
2915
|
-
cellIdBelow,
|
|
2916
|
-
cellIdToLeft
|
|
2917
|
-
} = getCellInfo({
|
|
2918
|
-
columnIndex,
|
|
2919
|
-
columnPath,
|
|
2920
|
-
rowId,
|
|
2921
|
-
schema,
|
|
2922
|
-
entities,
|
|
2923
|
-
rowIndex,
|
|
2924
|
-
isEntityDisabled,
|
|
2925
|
-
entity: entityMap[rowId].e
|
|
2926
|
-
});
|
|
2927
|
-
const nextCellId = up
|
|
2928
|
-
? cellIdAbove
|
|
2929
|
-
: down
|
|
2930
|
-
? cellIdBelow
|
|
2931
|
-
: left
|
|
2932
|
-
? cellIdToLeft
|
|
2933
|
-
: cellIdToRight;
|
|
2934
|
-
|
|
2935
|
-
e.stopPropagation();
|
|
2936
|
-
e.preventDefault();
|
|
2937
|
-
if (!nextCellId) return;
|
|
2938
|
-
// this.handleCellBlur();
|
|
2939
|
-
// this.finishCellEdit
|
|
2940
|
-
if (
|
|
2941
|
-
document.activeElement?.parentElement?.classList.contains(
|
|
2942
|
-
"rt-td"
|
|
2943
|
-
)
|
|
2944
|
-
) {
|
|
2945
|
-
document.activeElement.blur();
|
|
2946
|
-
}
|
|
2947
|
-
handleCellClick({
|
|
2948
|
-
event: e,
|
|
2949
|
-
cellId: nextCellId
|
|
2950
|
-
});
|
|
2951
|
-
}
|
|
2952
|
-
if (e.metaKey || e.ctrlKey || e.altKey) return;
|
|
2953
|
-
if (!primarySelectedCellId) return;
|
|
2954
|
-
const entityIdToEntity = getEntityIdToEntity(entities);
|
|
2955
|
-
const [rowId] = primarySelectedCellId.split(":");
|
|
2956
|
-
if (!rowId) return;
|
|
2957
|
-
const entity = entityIdToEntity[rowId].e;
|
|
2958
|
-
if (!entity) return;
|
|
2959
|
-
const rowDisabled = isEntityDisabled(entity);
|
|
2960
|
-
const isNum = e.code?.startsWith("Digit");
|
|
2961
|
-
const isLetter = e.code?.startsWith("Key");
|
|
2962
|
-
if (!isNum && !isLetter) {
|
|
2963
|
-
return;
|
|
2964
|
-
}
|
|
2965
|
-
if (rowDisabled) return;
|
|
2966
|
-
e.stopPropagation();
|
|
2967
|
-
startCellEdit(primarySelectedCellId, e.key);
|
|
2968
|
-
}
|
|
2969
|
-
})}
|
|
2970
|
-
>
|
|
2971
|
-
{isCellEditable && entities.length > 50 && (
|
|
2972
|
-
// test for this!!
|
|
2973
|
-
<SwitchField
|
|
2974
|
-
name="onlyShowRowsWErrors"
|
|
2975
|
-
inlineLabel={true}
|
|
2976
|
-
label="Only Show Rows With Errors"
|
|
2977
|
-
onChange={e => {
|
|
2978
|
-
setOnlyShowRowsWErrors(e.target.value);
|
|
2979
|
-
}}
|
|
2980
|
-
/>
|
|
2981
|
-
)}
|
|
2982
|
-
{showHeader && (
|
|
2983
|
-
<div className="data-table-header">
|
|
2984
|
-
<div className="data-table-title-and-buttons">
|
|
2985
|
-
{tableName && withTitle && (
|
|
2986
|
-
<span className="data-table-title">{tableName}</span>
|
|
2987
|
-
)}
|
|
2988
|
-
{children}
|
|
2989
|
-
{topLeftItems}
|
|
2990
|
-
</div>
|
|
2991
|
-
{errorParsingUrlString && (
|
|
2992
|
-
<Callout
|
|
2993
|
-
icon="error"
|
|
2994
|
-
style={{
|
|
2995
|
-
width: "unset"
|
|
2996
|
-
}}
|
|
2997
|
-
intent={Intent.WARNING}
|
|
2998
|
-
>
|
|
2999
|
-
Error parsing URL
|
|
3000
|
-
</Callout>
|
|
3001
|
-
)}
|
|
3002
|
-
{nonDisplayedFilterComp}
|
|
3003
|
-
{withSearch && (
|
|
3004
|
-
<div className="data-table-search-and-clear-filter-container">
|
|
3005
|
-
{leftOfSearchBarItems}
|
|
3006
|
-
{hasFilters ? (
|
|
3007
|
-
<Tooltip content="Clear Filters">
|
|
3008
|
-
<Button
|
|
3009
|
-
minimal
|
|
3010
|
-
intent="danger"
|
|
3011
|
-
icon="filter-remove"
|
|
3012
|
-
disabled={disabled}
|
|
3013
|
-
className="data-table-clear-filters"
|
|
3014
|
-
onClick={() => {
|
|
3015
|
-
clearFilters(additionalFilterKeys);
|
|
3016
|
-
}}
|
|
3017
|
-
/>
|
|
3018
|
-
</Tooltip>
|
|
3019
|
-
) : (
|
|
3020
|
-
""
|
|
3021
|
-
)}
|
|
3022
|
-
<SearchBar
|
|
3023
|
-
noForm={noForm}
|
|
3024
|
-
searchInput={currentParams.searchTerm}
|
|
3025
|
-
setSearchTerm={setSearchTerm}
|
|
3026
|
-
loading={isLoading}
|
|
3027
|
-
searchMenuButton={searchMenuButton}
|
|
3028
|
-
disabled={disabled}
|
|
3029
|
-
autoFocusSearch={autoFocusSearch}
|
|
3030
|
-
/>
|
|
3031
|
-
</div>
|
|
3032
|
-
)}
|
|
3033
|
-
</div>
|
|
3034
|
-
)}
|
|
3035
|
-
{subHeader}
|
|
3036
|
-
{showSelectAll && !isSingleSelect && (
|
|
3037
|
-
<div
|
|
3038
|
-
style={{
|
|
3039
|
-
marginTop: 5,
|
|
3040
|
-
marginBottom: 5,
|
|
3041
|
-
display: "flex",
|
|
3042
|
-
alignItems: "center"
|
|
3043
|
-
}}
|
|
3044
|
-
>
|
|
3045
|
-
All items on this page are selected.{" "}
|
|
3046
|
-
<Button
|
|
3047
|
-
small
|
|
3048
|
-
minimal
|
|
3049
|
-
intent="primary"
|
|
3050
|
-
text={`Select all ${
|
|
3051
|
-
entityCount || entitiesAcrossPages.length
|
|
3052
|
-
} items`}
|
|
3053
|
-
loading={selectingAll}
|
|
3054
|
-
onClick={async () => {
|
|
3055
|
-
if (withSelectAll) {
|
|
3056
|
-
// this will be by querying for everything
|
|
3057
|
-
setSelectingAll(true);
|
|
3058
|
-
try {
|
|
3059
|
-
const allEntities = await safeQuery(fragment, {
|
|
3060
|
-
variables: {
|
|
3061
|
-
filter: variables.filter,
|
|
3062
|
-
sort: variables.sort
|
|
3063
|
-
},
|
|
3064
|
-
canCancel: true
|
|
3065
|
-
});
|
|
3066
|
-
addEntitiesToSelection(allEntities);
|
|
3067
|
-
} catch (error) {
|
|
3068
|
-
console.error(`error:`, error);
|
|
3069
|
-
window.toastr.error("Error selecting all constructs");
|
|
3070
|
-
}
|
|
3071
|
-
setSelectingAll(false);
|
|
3072
|
-
} else {
|
|
3073
|
-
addEntitiesToSelection(entitiesAcrossPages);
|
|
3074
|
-
}
|
|
3075
|
-
}}
|
|
3076
|
-
/>
|
|
3077
|
-
</div>
|
|
3078
|
-
)}
|
|
3079
|
-
{showClearAll > 0 && (
|
|
3080
|
-
<div
|
|
3081
|
-
style={{
|
|
3082
|
-
marginTop: 5,
|
|
3083
|
-
marginBottom: 5,
|
|
3084
|
-
display: "flex",
|
|
3085
|
-
alignItems: "center"
|
|
3086
|
-
}}
|
|
3087
|
-
>
|
|
3088
|
-
All {showClearAll} items are selected.
|
|
3089
|
-
<Button
|
|
3090
|
-
small
|
|
3091
|
-
minimal
|
|
3092
|
-
intent="primary"
|
|
3093
|
-
text="Clear Selection"
|
|
3094
|
-
onClick={() => {
|
|
3095
|
-
finalizeSelection({
|
|
3096
|
-
idMap: {},
|
|
3097
|
-
entities,
|
|
3098
|
-
props: {
|
|
3099
|
-
onDeselect,
|
|
3100
|
-
onSingleRowSelect,
|
|
3101
|
-
onMultiRowSelect,
|
|
3102
|
-
noDeselectAll,
|
|
3103
|
-
onRowSelect,
|
|
3104
|
-
noSelect,
|
|
3105
|
-
change
|
|
3106
|
-
}
|
|
3107
|
-
});
|
|
3108
|
-
}}
|
|
3109
|
-
/>
|
|
3110
|
-
</div>
|
|
3111
|
-
)}
|
|
3112
|
-
{reactTable}
|
|
3113
|
-
{isCellEditable && (
|
|
3114
|
-
<div style={{ display: "flex" }}>
|
|
3115
|
-
<div
|
|
3116
|
-
style={{
|
|
3117
|
-
width: "100%",
|
|
3118
|
-
display: "flex",
|
|
3119
|
-
justifyContent: "center"
|
|
3120
|
-
}}
|
|
3121
|
-
>
|
|
3122
|
-
{!onlyShowRowsWErrors && (
|
|
3123
|
-
<Button
|
|
3124
|
-
icon="add"
|
|
3125
|
-
onClick={() => {
|
|
3126
|
-
insertRows({ numRows: 10, appendToBottom: true });
|
|
3127
|
-
}}
|
|
3128
|
-
minimal
|
|
3129
|
-
>
|
|
3130
|
-
Add 10 Rows
|
|
3131
|
-
</Button>
|
|
3132
|
-
)}
|
|
3133
|
-
</div>
|
|
3134
|
-
<Button
|
|
3135
|
-
onClick={e => {
|
|
3136
|
-
handleCopyTable(e, { isDownload: true });
|
|
3137
|
-
}}
|
|
3138
|
-
data-tip="Download Table as CSV"
|
|
3139
|
-
minimal
|
|
3140
|
-
icon="download"
|
|
3141
|
-
/>
|
|
3142
|
-
</div>
|
|
3143
|
-
)}
|
|
3144
|
-
{!noFooter && (
|
|
3145
|
-
<div
|
|
3146
|
-
className="data-table-footer"
|
|
3147
|
-
style={{
|
|
3148
|
-
justifyContent:
|
|
3149
|
-
!showNumSelected && !showCount ? "flex-end" : "space-between"
|
|
3150
|
-
}}
|
|
3151
|
-
>
|
|
3152
|
-
{selectedAndTotalMessage}
|
|
3153
|
-
<div style={{ display: "flex", flexWrap: "wrap" }}>
|
|
3154
|
-
{additionalFooterButtons}
|
|
3155
|
-
{!noFullscreenButton && toggleFullscreenButton}
|
|
3156
|
-
{withDisplayOptions && (
|
|
3157
|
-
<DisplayOptions
|
|
3158
|
-
compact={compact}
|
|
3159
|
-
extraCompact={extraCompact}
|
|
3160
|
-
disabled={disabled}
|
|
3161
|
-
hideDisplayOptionsIcon={hideDisplayOptionsIcon}
|
|
3162
|
-
resetDefaultVisibility={resetDefaultVisibility}
|
|
3163
|
-
updateColumnVisibility={updateColumnVisibility}
|
|
3164
|
-
updateTableDisplayDensity={updateTableDisplayDensity}
|
|
3165
|
-
showForcedHiddenColumns={showForcedHiddenColumns}
|
|
3166
|
-
setShowForcedHidden={setShowForcedHidden}
|
|
3167
|
-
hasOptionForForcedHidden={
|
|
3168
|
-
withDisplayOptions && (isSimple || isInfinite)
|
|
3169
|
-
}
|
|
3170
|
-
schema={schema}
|
|
3171
|
-
/>
|
|
3172
|
-
)}
|
|
3173
|
-
{shouldShowPaging && (
|
|
3174
|
-
<PagingTool
|
|
3175
|
-
controlled_hasNextPage={controlled_hasNextPage}
|
|
3176
|
-
controlled_onRefresh={controlled_onRefresh}
|
|
3177
|
-
controlled_page={controlled_page}
|
|
3178
|
-
controlled_setPage={controlled_setPage}
|
|
3179
|
-
controlled_setPageSize={controlled_setPageSize}
|
|
3180
|
-
controlled_total={controlled_total}
|
|
3181
|
-
disabled={disabled}
|
|
3182
|
-
disableSetPageSize={disableSetPageSize}
|
|
3183
|
-
entities={entities}
|
|
3184
|
-
entityCount={entityCount}
|
|
3185
|
-
hideSetPageSize={hideSetPageSize}
|
|
3186
|
-
hideTotalPages={hideTotalPages}
|
|
3187
|
-
keepSelectionOnPageChange={keepSelectionOnPageChange}
|
|
3188
|
-
onRefresh={onRefresh}
|
|
3189
|
-
page={page}
|
|
3190
|
-
pageSize={pageSize}
|
|
3191
|
-
pagingDisabled={pagingDisabled}
|
|
3192
|
-
persistPageSize={persistPageSize}
|
|
3193
|
-
setPage={setPage}
|
|
3194
|
-
setPageSize={setPageSize}
|
|
3195
|
-
setSelectedEntityIdMap={newIdMap => {
|
|
3196
|
-
change("reduxFormSelectedEntityIdMap", newIdMap);
|
|
3197
|
-
}}
|
|
3198
|
-
scrollToTop={scrollToTop}
|
|
3199
|
-
/>
|
|
3200
|
-
)}
|
|
3201
|
-
</div>
|
|
3202
|
-
</div>
|
|
3203
|
-
)}
|
|
3204
|
-
</div>
|
|
3205
|
-
</div>
|
|
3206
|
-
</div>
|
|
3207
|
-
);
|
|
3208
|
-
};
|
|
3209
|
-
|
|
3210
|
-
const WrappedDT = dataTableEnhancer(DataTable);
|
|
3211
|
-
export default WrappedDT;
|
|
3212
|
-
const ConnectedPagingTool = dataTableEnhancer(PagingTool);
|
|
3213
|
-
export { ConnectedPagingTool };
|