@adaptabletools/adaptable 22.0.11 → 22.1.0-canary.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.
Files changed (75) hide show
  1. package/index.css +19 -1
  2. package/index.css.map +1 -1
  3. package/package.json +3 -4
  4. package/src/AdaptableOptions/DashboardOptions.d.ts +2 -2
  5. package/src/AdaptableState/Common/AdaptablePredicate.js +1 -1
  6. package/src/AdaptableState/InitialState.d.ts +2 -2
  7. package/src/AdaptableState/LayoutState.d.ts +44 -0
  8. package/src/Api/CalendarApi.d.ts +15 -0
  9. package/src/Api/ColumnScopeApi.d.ts +5 -0
  10. package/src/Api/Implementation/CalendarApiImpl.d.ts +3 -0
  11. package/src/Api/Implementation/CalendarApiImpl.js +10 -0
  12. package/src/Api/Implementation/ColumnApiImpl.d.ts +1 -0
  13. package/src/Api/Implementation/ColumnApiImpl.js +14 -0
  14. package/src/Api/Implementation/ColumnScopeApiImpl.d.ts +1 -0
  15. package/src/Api/Implementation/ColumnScopeApiImpl.js +12 -0
  16. package/src/Api/Implementation/LayoutHelpers.js +12 -0
  17. package/src/Api/Internal/AlertInternalApi.js +4 -1
  18. package/src/Api/Internal/FormatColumnInternalApi.js +3 -3
  19. package/src/Strategy/FlashingCellModule.js +1 -0
  20. package/src/Strategy/PlusMinusModule.js +3 -3
  21. package/src/Strategy/SmartEditModule.js +1 -1
  22. package/src/Utilities/Constants/GeneralConstants.js +2 -1
  23. package/src/Utilities/ExpressionFunctions/booleanExpressionFunctions.d.ts +1 -1
  24. package/src/Utilities/ExpressionFunctions/booleanExpressionFunctions.js +41 -2
  25. package/src/Utilities/ExpressionFunctions/scalarExpressionFunctions.d.ts +1 -1
  26. package/src/Utilities/ExpressionFunctions/scalarExpressionFunctions.js +31 -2
  27. package/src/Utilities/Helpers/AdaptableHelper.js +30 -4
  28. package/src/Utilities/Services/Interface/IQueryLanguageService.d.ts +1 -0
  29. package/src/Utilities/Services/MetamodelService.js +18 -18
  30. package/src/Utilities/Services/QueryLanguageService.d.ts +2 -0
  31. package/src/Utilities/Services/QueryLanguageService.js +20 -8
  32. package/src/Utilities/Services/ValidationService.js +3 -1
  33. package/src/View/Components/EntityRulesEditor/index.js +1 -1
  34. package/src/View/Components/ModuleValueSelector/index.js +9 -1
  35. package/src/View/Components/ReorderDraggable/index.js +22 -36
  36. package/src/View/Components/ValueSelector/index.js +46 -50
  37. package/src/View/Dashboard/PinnedToolbarsSelector.js +1 -1
  38. package/src/View/Layout/Wizard/LayoutWizard.js +16 -1
  39. package/src/View/Layout/Wizard/sections/ColumnsSection.js +31 -19
  40. package/src/View/Layout/Wizard/sections/RowGroupingSection.js +1 -1
  41. package/src/View/Layout/Wizard/sections/RowSelectionSection.d.ts +8 -0
  42. package/src/View/Layout/Wizard/sections/RowSelectionSection.js +140 -0
  43. package/src/View/NamedQuery/Wizard/NamedQuerySettingsWizardSection.js +0 -1
  44. package/src/agGrid/AdaptableAgGrid.js +10 -0
  45. package/src/components/Dashboard/Dashboard.js +1 -1
  46. package/src/components/DragAndDropContext/ModuleManager.d.ts +1 -0
  47. package/src/components/DragAndDropContext/ModuleManager.js +12 -37
  48. package/src/components/DragAndDropContext/TabList.d.ts +11 -6
  49. package/src/components/DragAndDropContext/TabList.js +78 -36
  50. package/src/components/DragAndDropContext/UnusedPanel.js +10 -21
  51. package/src/components/ExpressionEditor/BaseEditorInput.d.ts +2 -0
  52. package/src/components/ExpressionEditor/BaseEditorInput.js +4 -0
  53. package/src/components/ExpressionEditor/EditorInput.d.ts +3 -1
  54. package/src/components/ExpressionEditor/EditorInput.js +20 -9
  55. package/src/components/ExpressionEditor/QueryBuilder/QueryBuilder.d.ts +2 -1
  56. package/src/components/ExpressionEditor/QueryBuilder/QueryBuilder.js +3 -12
  57. package/src/components/ExpressionEditor/QueryBuilder/QueryPredicateBuilder.js +17 -19
  58. package/src/components/ExpressionEditor/index.d.ts +2 -1
  59. package/src/components/ExpressionEditor/index.js +1 -1
  60. package/src/components/Tree/TreeDropdown/index.js +38 -27
  61. package/src/components/dnd/index.d.ts +3 -13
  62. package/src/components/dnd/index.js +4 -55
  63. package/src/env.js +2 -2
  64. package/src/layout-manager/src/LayoutManagerModel.d.ts +2 -1
  65. package/src/layout-manager/src/index.d.ts +10 -0
  66. package/src/layout-manager/src/index.js +156 -4
  67. package/src/layout-manager/src/normalizeLayoutModel.js +8 -0
  68. package/src/layout-manager/src/simplifyLayoutModel.js +6 -0
  69. package/src/metamodel/adaptable-metamodel-model.d.ts +22 -13
  70. package/src/metamodel/adaptable.metamodel.d.ts +3792 -5143
  71. package/src/metamodel/adaptable.metamodel.js +1 -1
  72. package/src/parser/src/parser.js +55 -1218
  73. package/src/parser/src/types.d.ts +5 -0
  74. package/src/types.d.ts +1 -1
  75. package/tsconfig.esm.tsbuildinfo +1 -1
@@ -1,43 +1,29 @@
1
1
  import * as React from 'react';
2
- import { DragDropContext, Draggable, Droppable } from '../../../components/dnd';
2
+ import { defaultDragProxyMove, DragDropProvider, DragList } from '../../../components/dnd';
3
3
  import { Icon } from '../../../components/icons';
4
- import ArrayExtensions from '../../../Utilities/Extensions/ArrayExtensions';
5
4
  import { Box, Flex } from '../../../components/Flex';
6
5
  import clsx from 'clsx';
7
- import { twMerge } from '../../../twMerge';
8
6
  export function ReorderDraggable(props) {
9
- const { onChange, order, toIdentifier, isOptionDraggable, disabled, } = props;
7
+ const { onChange, order, toIdentifier, isOptionDraggable, disabled } = props;
10
8
  const baseClassName = 'ab-ReorderDraggable';
11
- const renderOption = (option, index) => {
12
- const identifier = toIdentifier(option);
13
- const renderNode = (flexProps, dragHandleProps) => {
14
- const reorderable = isOptionDraggable ? isOptionDraggable(option) : true;
15
- return (React.createElement(Flex, { alignItems: "center", key: identifier ?? index, "data-index": index, "data-id": identifier, "data-name": "option", ...flexProps, className: clsx(`${baseClassName}__option ${index ? 'twa:mt-1' : 'twa:mt-0'} twa:bg-primary twa:p-2 ${flexProps?.className || ''}`, props.optionClassName?.(option)), onClick: (e) => props.onOptionClick?.(option, e) },
16
- React.createElement(Flex, { className: "twa:flex-1", flexDirection: "row", alignItems: "center" },
17
- reorderable ? (React.createElement(Box, { ...dragHandleProps, className: `twa:mr-3 ${dragHandleProps?.className || ''}` },
18
- React.createElement(Icon, { name: "drag", style: { cursor: 'grab' } }))) : (React.createElement(Box, { className: "twa:mr-3" },
19
- React.createElement(Icon, { name: "drag", style: { cursor: 'not-allowed', opacity: 0.3 } }))),
20
- props.renderOption(option, index))));
21
- };
22
- const reorderable = isOptionDraggable ? isOptionDraggable(option) : true;
23
- return (React.createElement(Draggable, { key: identifier, index: index, draggableId: `${identifier}`, isDragDisabled: !reorderable || disabled }, (draggableProvided) => {
24
- return renderNode({
25
- ref: draggableProvided.innerRef,
26
- ...draggableProvided.draggableProps,
27
- style: draggableProvided.draggableProps.style,
28
- }, draggableProvided.dragHandleProps);
29
- }));
30
- };
31
- return (React.createElement(Flex, { style: props.style, className: twMerge(`${baseClassName} twa:flex-1`, props.className), flexDirection: "column" },
32
- React.createElement(DragDropContext, { onDragEnd: (result) => {
33
- const { source, destination } = result;
34
- const newOrder = ArrayExtensions.reorderArray(props.order, source.index, destination.index);
35
- onChange(newOrder);
36
- } },
37
- React.createElement(Flex, { className: `${baseClassName}__body twa:flex-1 twa:overflow-auto`, flexDirection: "column" },
38
- React.createElement(Droppable, { droppableId: "droppable" }, (droppableProvided) => {
39
- return (React.createElement("div", { ref: droppableProvided.innerRef, ...droppableProvided.droppableProps },
40
- order.map(renderOption),
41
- droppableProvided.placeholder));
42
- })))));
9
+ return (React.createElement(Flex, { style: props.style, className: `${baseClassName} twa:flex-1`, flexDirection: "column" },
10
+ React.createElement(DragDropProvider, null,
11
+ React.createElement(Flex, { className: `${baseClassName}__body twa:flex-1 twa:overflow-y-auto twa:overflow-x-hidden`, flexDirection: "column" },
12
+ React.createElement(DragList, { dragListId: "reorder-draggable", orientation: "vertical", dragStrategy: "proxy", preserveDragSpace: true, onDragProxyMove: defaultDragProxyMove, onDragProxySetup: ({ proxyElement }) => {
13
+ proxyElement.classList.add('twa:shadow-md');
14
+ }, onDrop: (sortedIndexes) => {
15
+ onChange(sortedIndexes.map((i) => order[i]));
16
+ } }, (listDomProps) => (React.createElement("div", { ...listDomProps }, order.map((option, index) => {
17
+ const identifier = toIdentifier(option);
18
+ const reorderable = isOptionDraggable ? isOptionDraggable(option) : true;
19
+ return (React.createElement(DragList.DraggableItem, { key: identifier, id: `${identifier}` }, (itemDomProps, itemContext) => {
20
+ const { onPointerDown, ...restDomProps } = itemDomProps;
21
+ return (React.createElement(Flex, { alignItems: "center", "data-index": index, "data-id": identifier, "data-name": "option", ...restDomProps, className: clsx(`${baseClassName}__option`, index ? 'twa:mt-1' : 'twa:mt-0', 'twa:bg-primary twa:p-2', itemContext.active ? 'twa:shadow-md' : '', restDomProps.className, props.optionClassName?.(option)), onClick: (e) => props.onOptionClick?.(option, e) },
22
+ React.createElement(Flex, { className: "twa:flex-1", flexDirection: "row", alignItems: "center" },
23
+ reorderable && !disabled ? (React.createElement(Box, { onPointerDown: onPointerDown, className: "twa:mr-3" },
24
+ React.createElement(Icon, { name: "drag", style: { cursor: 'grab' } }))) : (React.createElement(Box, { className: "twa:mr-3" },
25
+ React.createElement(Icon, { name: "drag", style: { cursor: 'not-allowed', opacity: 0.3 } }))),
26
+ props.renderOption(option, index))));
27
+ }));
28
+ }))))))));
43
29
  }
@@ -1,11 +1,10 @@
1
1
  import * as React from 'react';
2
2
  import { useState, useMemo, useCallback } from 'react';
3
- import { DragDropContext, Draggable, Droppable } from '../../../components/dnd';
3
+ import { defaultDragProxyMove, DragDropProvider, DragList } from '../../../components/dnd';
4
4
  import { CheckBox } from '../../../components/CheckBox';
5
5
  import { Icon } from '../../../components/icons';
6
6
  import Radio from '../../../components/Radio';
7
7
  import { AdaptableFormControlTextClear } from '../Forms/AdaptableFormControlTextClear';
8
- import ArrayExtensions from '../../../Utilities/Extensions/ArrayExtensions';
9
8
  import { Box, Flex } from '../../../components/Flex';
10
9
  import clsx from 'clsx';
11
10
  function useValuesMap({ options, value, toIdentifier, selectedMap, }) {
@@ -57,13 +56,14 @@ export function ValueSelector(props) {
57
56
  const identifier = toIdentifier(option);
58
57
  const label = !allowReorder ? preparedToLabel(option) : null;
59
58
  const reorderable = typeof allowReorder === 'function' ? allowReorder(option) : allowReorder;
60
- const renderNode = (props, dragHandleProps) => {
61
- return (React.createElement(Flex, { alignItems: "center", key: identifier ?? index, "data-index": index, "data-id": identifier, "data-name": "option", ...props, className: clsx(`twa:bg-primary twa:text-text-on-primary twa:rounded-standard twa:p-2`, {
59
+ return (React.createElement(DragList.DraggableItem, { key: identifier, id: `${identifier}` }, (itemDomProps) => {
60
+ const { onPointerDown, ...restDomProps } = itemDomProps;
61
+ return (React.createElement(Flex, { alignItems: "center", "data-index": index, "data-id": identifier, "data-name": "option", ...restDomProps, className: clsx('twa:bg-primary twa:text-text-on-primary twa:rounded-standard twa:p-2', {
62
62
  'twa:mt-1': index,
63
63
  'twa:mt-0': !index,
64
- }, props.className, `${baseClassName}__option`) },
64
+ }, restDomProps.className, `${baseClassName}__option`) },
65
65
  React.createElement(Flex, { flexDirection: "row", alignItems: "center", className: "twa:flex-1" },
66
- reorderable ? (React.createElement(Box, { ...dragHandleProps, className: clsx('twa:mr-3', dragHandleProps?.className) },
66
+ reorderable ? (React.createElement(Box, { onPointerDown: onPointerDown, className: "twa:mr-3" },
67
67
  React.createElement(Icon, { name: "drag", style: { cursor: 'grab' } }))) : null,
68
68
  singleSelect ? (React.createElement(Radio, { checked: selectedMap.has(identifier), "data-name": identifier, onChange: (checked) => {
69
69
  if (checked) {
@@ -84,13 +84,6 @@ export function ValueSelector(props) {
84
84
  notifyChange();
85
85
  }, checked: selectedMap.has(identifier) }, label)),
86
86
  React.createElement(Box, { className: "twa:ml-2 twa:flex-1" }, allowReorder ? preparedToLabel(option) : null))));
87
- };
88
- return (React.createElement(Draggable, { key: identifier, index: index, draggableId: `${identifier}`, isDragDisabled: !reorderable }, (draggableProvided) => {
89
- return renderNode({
90
- ref: draggableProvided.innerRef,
91
- ...draggableProvided.draggableProps,
92
- style: draggableProvided.draggableProps.style,
93
- }, draggableProvided.dragHandleProps);
94
87
  }));
95
88
  };
96
89
  const showOnlySelectedCheckbox = (React.createElement(CheckBox, { disabled: !value.length, checked: selectedOnly, onChange: setSelectedOnly }, showSelectedOnlyLabel ?? 'Show Selected Only'));
@@ -115,45 +108,48 @@ export function ValueSelector(props) {
115
108
  return (React.createElement(Flex, { style: props.style, className: clsx('twa:flex-1', baseClassName), flexDirection: "column" },
116
109
  React.createElement(Flex, { className: "twa:mb-1" }, showFilterInput && filter ? (React.createElement(AdaptableFormControlTextClear, { value: searchInputValue, OnTextChange: setSearchInputValue, placeholder: "Type to search", className: "twa:flex-1 twa:border-0 twa:m-[3px]" })) : (React.createElement(Box, { className: "twa:flex-1" }))),
117
110
  renderSelectionSection(selectionSectionProps),
118
- React.createElement(DragDropContext, { onDragEnd: (result) => {
119
- const { source, destination } = result;
120
- const selection = [];
121
- const extraKeys = [];
122
- for (let [key, value] of selectedMap) {
123
- if (value != null) {
124
- selection.push(key);
125
- }
126
- else {
127
- // null/non-existent keys have to be stored separately
128
- extraKeys.push(key);
129
- }
130
- }
131
- const clone = new Map(selectedMap);
132
- const newSelection = ArrayExtensions.reorderArray(selection, source.index, destination.index);
133
- // and then pushed back in the new order, at the end
134
- newSelection.push(...extraKeys);
135
- selectedMap.clear();
136
- newSelection.forEach((key) => {
137
- selectedMap.set(key, clone.get(key));
138
- });
139
- notifyChange();
140
- } },
111
+ React.createElement(DragDropProvider, null,
141
112
  React.createElement(Flex, { className: `${baseClassName}__body twa:flex-1 twa:overflow-auto`, flexDirection: "column" },
142
- React.createElement(Droppable, { droppableId: "droppable" }, (droppableProvided) => {
143
- return (React.createElement("div", { ref: droppableProvided.innerRef, ...droppableProvided.droppableProps },
144
- options
145
- .filter((option) => {
146
- let result = true;
147
- if (filter) {
148
- result = filter(option, searchInputValue);
113
+ React.createElement(DragList, { dragListId: "value-selector", orientation: "vertical", onDragProxyMove: defaultDragProxyMove, onDragProxySetup: ({ proxyElement }) => {
114
+ proxyElement.classList.add('twa:shadow-md');
115
+ }, onDrop: (_sortedIndexes) => {
116
+ const selection = [];
117
+ const extraKeys = [];
118
+ for (const [key, value] of selectedMap) {
119
+ if (value != null) {
120
+ selection.push(key);
149
121
  }
150
- result =
151
- result && (selectedOnly ? selectedMap.has(toIdentifier(option)) : true);
152
- return result;
153
- })
154
- .map(renderOption),
155
- droppableProvided.placeholder));
156
- })))));
122
+ else {
123
+ // null/non-existent keys have to be stored separately
124
+ extraKeys.push(key);
125
+ }
126
+ }
127
+ const clone = new Map(selectedMap);
128
+ // const newSelection: ID_TYPE[] = ArrayExtensions.reorderArray(
129
+ // selection,
130
+ // dragIndex,
131
+ // dropIndex
132
+ // );
133
+ const newSelection = _sortedIndexes
134
+ .map((index) => selection[index])
135
+ .filter((x) => x != null);
136
+ newSelection.push(...extraKeys);
137
+ selectedMap.clear();
138
+ newSelection.forEach((key) => {
139
+ selectedMap.set(key, clone.get(key));
140
+ });
141
+ notifyChange();
142
+ } }, (listDomProps) => (React.createElement("div", { ...listDomProps }, options
143
+ .filter((option) => {
144
+ let result = true;
145
+ if (filter) {
146
+ result = filter(option, searchInputValue);
147
+ }
148
+ result =
149
+ result && (selectedOnly ? selectedMap.has(toIdentifier(option)) : true);
150
+ return result;
151
+ })
152
+ .map(renderOption))))))));
157
153
  }
158
154
  export const renderSelectionSection = (props) => {
159
155
  const { value, options, disabled, singleSelect, toLabel, toIdentifier, } = props;
@@ -37,5 +37,5 @@ export const PinnedToolbarsSelector = (props) => {
37
37
  editTabName: false,
38
38
  }, onTabsChange: (tabs) => {
39
39
  dispatch(DashboardSetPinnedToolbars(tabs[0].Items));
40
- }, disabled: isDashboardDisabled, tabs: tabs, availableItems: toolbars, tabsTitle: 'Pinned Toolbars', unusedPanelTitle: "Available Pinned Toolbars", dragItemText: "Drag into the Panel below" }));
40
+ }, disabled: isDashboardDisabled, tabs: tabs, availableItems: toolbars, filterOutSelectedItems: true, tabsTitle: 'Pinned Toolbars', unusedPanelTitle: "Available Pinned Toolbars", dragItemText: "Drag into the Panel below" }));
41
41
  };
@@ -13,6 +13,7 @@ import { SortSection, SortSectionSummary } from './sections/SortSection';
13
13
  import { FilterSection, FilterSectionSummary, isColumnFiltersValid, } from './sections/FilterSection';
14
14
  import { GridFilterSection, GridFilterSectionSummary, isGridFiltersValid, } from './sections/GridFilterSection';
15
15
  import { areSummaryRowsValid, RowSummarySection, RowSummarySectionSummary, } from './sections/RowSummarySection';
16
+ import { RowSelectionSection, RowSelectionSectionSummary } from './sections/RowSelectionSection';
16
17
  import { WEIGHTED_AVERAGE_AGGREGATED_FUNCTION } from '../../../AdaptableState/Common/RowSummary';
17
18
  import { isPivotLayout } from '../../../Utilities/isPivotLayout';
18
19
  import { PivotRowGroupingSection, PivotRowGroupingSectionSummary, } from './sections/PivotRowGroupingSection';
@@ -114,7 +115,7 @@ export const LayoutWizard = (props) => {
114
115
  isValid: (data) => isPivotAggregationsSectionValid(data),
115
116
  render: () => (React.createElement(Box, { className: "twa:p-2 twa:h-full" },
116
117
  React.createElement(PivotAggregationsSection, { onChange: (layout) => {
117
- let newLayout = cloneObject(layout);
118
+ const newLayout = cloneObject(layout);
118
119
  setLayout(newLayout);
119
120
  } }))),
120
121
  },
@@ -144,6 +145,13 @@ export const LayoutWizard = (props) => {
144
145
  render: () => (React.createElement(Box, { className: "twa:p-2 twa:h-full" },
145
146
  React.createElement(GridFilterSection, { onChange: (newLayout) => setLayout(newLayout) }))),
146
147
  },
148
+ {
149
+ title: 'Row Selection',
150
+ details: 'Configure Row Selection',
151
+ renderSummary: () => React.createElement(RowSelectionSectionSummary, null),
152
+ render: () => (React.createElement(Box, { className: "twa:p-2" },
153
+ React.createElement(RowSelectionSection, { onChange: (newLayout) => setLayout(newLayout) }))),
154
+ },
147
155
  '-',
148
156
  {
149
157
  details: 'Review your Pivot Layout',
@@ -257,6 +265,13 @@ export const LayoutWizard = (props) => {
257
265
  render: () => (React.createElement(Box, { className: "twa:p-2 twa:h-full" },
258
266
  React.createElement(GridFilterSection, { onChange: (newLayout) => setLayout(newLayout) }))),
259
267
  },
268
+ {
269
+ title: 'Row Selection',
270
+ details: 'Configure Row Selection',
271
+ renderSummary: () => React.createElement(RowSelectionSectionSummary, null),
272
+ render: () => (React.createElement(Box, { className: "twa:p-2" },
273
+ React.createElement(RowSelectionSection, { onChange: (newLayout) => setLayout(newLayout) }))),
274
+ },
260
275
  '-',
261
276
  {
262
277
  details: 'Review your Table Layout',
@@ -10,7 +10,7 @@ import { Icon, NaturallySizedIcon } from '../../../../components/icons';
10
10
  import { CheckBox } from '../../../../components/CheckBox';
11
11
  import { clamp } from '../../../../Utilities/Helpers/Helper';
12
12
  import ArrayExtensions from '../../../../Utilities/Extensions/ArrayExtensions';
13
- import { generateAutoRowGroupColumnForColumn, generateAutoRowGroupSingleColumn, generateAutoTreeSingleColumn, isAutoRowGroupColumn, } from '../../../../Api/Implementation/ColumnApiImpl';
13
+ import { generateAutoRowGroupColumnForColumn, generateAutoRowGroupSingleColumn, generateAutoTreeSingleColumn, generateSelectionColumn, isAutoRowGroupColumn, } from '../../../../Api/Implementation/ColumnApiImpl';
14
14
  import { ReorderDraggable } from '../../../Components/ReorderDraggable';
15
15
  import { AdaptableFormControlTextClear } from '../../../Components/Forms/AdaptableFormControlTextClear';
16
16
  import { sortColumnIdsByOrder } from '../../../../layout-manager/src/sortColumnIdsByOrder';
@@ -132,26 +132,29 @@ export const ColumnsSectionSummary = () => {
132
132
  return (React.createElement(DataSource, { data: data, primaryKey: "columnId" },
133
133
  React.createElement(InfiniteTableGrid, { columnTypes: columnTypes, rowHeight: rowHeight, columnHeaderHeight: headerHeight, domProps: tableDOMProps, columns: columns })));
134
134
  };
135
+ const isSelectionColumn = (columnId) => columnId === AG_GRID_SELECTION_COLUMN;
135
136
  const isColumnVisible = (options) => {
136
137
  const { columnId, layout } = options;
137
138
  const isRowGroupColumn = isAutoRowGroupColumn(columnId);
138
139
  const visible = (!isPivotLayout(layout) &&
139
140
  layout.TableColumns.includes(columnId) &&
140
141
  layout.ColumnVisibility?.[columnId] !== false) ||
141
- isRowGroupColumn;
142
+ isRowGroupColumn ||
143
+ isSelectionColumn(columnId);
142
144
  return visible;
143
145
  };
144
146
  const ColumnRow = (props) => {
145
147
  const adaptable = useAdaptable();
146
148
  const initialHeader = adaptable.api.columnApi.getFriendlyNameForColumnId(props.column.columnId, props.layout);
147
149
  const isRowGroupColumn = isAutoRowGroupColumn(props.column.columnId);
150
+ const isSelectionCol = isSelectionColumn(props.column.columnId);
148
151
  const { column } = props;
149
152
  const visible = isColumnVisible({ columnId: column.columnId, layout: props.layout });
150
153
  return (React.createElement(Box, { "data-name": props.column.columnId, className: "twa:flex-1" },
151
154
  React.createElement(Flex, { className: "ab-Layout-Wizard__ColumnRow__Header twa:my-1" },
152
155
  React.createElement(CheckBox, { "data-name": column.columnId, onChange: (checked) => {
153
156
  props.onColumnVisibilityChange(column.columnId, checked);
154
- }, disabled: column.hideable === false || isRowGroupColumn, onClick: (event) => {
157
+ }, disabled: column.hideable === false || isRowGroupColumn || isSelectionCol, onClick: (event) => {
155
158
  event.stopPropagation();
156
159
  }, checked: visible }),
157
160
  React.createElement(Flex, { className: "twa:mx-2", alignItems: "center", "data-name": "column-label" }, initialHeader),
@@ -164,7 +167,12 @@ export const ColumnsSection = (props) => {
164
167
  const { data: layout } = useOnePageAdaptableWizardContext();
165
168
  const [searchInputValue, setSearchInputValue] = React.useState('');
166
169
  const [selectedColumnId, setSelectedColumnId] = React.useState(null);
167
- let hasSelectionColumn = false;
170
+ // the selection column is a special column managed by AG Grid - it is not
171
+ // returned by `getUIAvailableColumns`, but we still want to expose it in the
172
+ // column list (similar to auto row group columns) so users can reorder/pin it
173
+ const hasSelectionColumn = adaptable.api.columnApi
174
+ .getColumns()
175
+ .some((col) => col.isGeneratedSelectionColumn);
168
176
  const allColumns = adaptable.api.columnApi
169
177
  .getUIAvailableColumns()
170
178
  .filter((col) => {
@@ -175,14 +183,9 @@ export const ColumnsSection = (props) => {
175
183
  })
176
184
  // if the current Layout is a PivotLayout, then we also filter out current Pivot Result Columns
177
185
  .filter((col) => !col.isGeneratedPivotResultColumn)
178
- // also we need to filter out selection column
179
- .filter((col) => {
180
- const result = !col.isGeneratedSelectionColumn;
181
- if (!result) {
182
- hasSelectionColumn = true;
183
- }
184
- return result;
185
- });
186
+ // selection columns are not returned by `getUIAvailableColumns` but guard
187
+ // against any future change
188
+ .filter((col) => !col.isGeneratedSelectionColumn);
186
189
  const onChange = (data) => {
187
190
  if (hasSelectionColumn &&
188
191
  Array.isArray(data.TableColumns) &&
@@ -209,13 +212,22 @@ export const ColumnsSection = (props) => {
209
212
  !allColumns.find((col) => col.columnId === AG_GRID_GROUPED_COLUMN)) {
210
213
  allColumns.unshift(generateAutoTreeSingleColumn());
211
214
  }
215
+ if (hasSelectionColumn) {
216
+ allColumns.unshift(generateSelectionColumn());
217
+ }
212
218
  const colIdToCol = allColumns.reduce((acc, col) => {
213
219
  if (col) {
214
220
  acc[col.columnId] = col;
215
221
  }
216
222
  return acc;
217
223
  }, {});
218
- const TableColumns = layout.TableColumns;
224
+ let TableColumns = layout.TableColumns;
225
+ // when the selection column exists but is not explicitly listed in
226
+ // TableColumns, `sortArrayWithOrder` would push it to the end - instead we
227
+ // want it at the start (consistent with AG Grid's default position for it)
228
+ if (hasSelectionColumn && !TableColumns.includes(AG_GRID_SELECTION_COLUMN)) {
229
+ TableColumns = [AG_GRID_SELECTION_COLUMN, ...TableColumns];
230
+ }
219
231
  const ColumnOrderAllColumns = ArrayExtensions.sortArrayWithOrder(allColumns.map((col) => col.columnId), TableColumns, { sortUnorderedItems: false }).map((colId) => colIdToCol[colId]);
220
232
  const currentOrder = searchInputValue
221
233
  ? ColumnOrderAllColumns.filter((col) => {
@@ -259,7 +271,7 @@ export const ColumnsSection = (props) => {
259
271
  const columnIdArray = Array.isArray(columnId) ? columnId : [columnId];
260
272
  const columnIdSet = new Set(columnIdArray);
261
273
  const ColumnVisibility = { ...layout.ColumnVisibility };
262
- let TableColumns = [...layout.TableColumns];
274
+ let newTableColumns = [...TableColumns];
263
275
  if (visible) {
264
276
  columnIdArray.forEach((colId) => {
265
277
  delete ColumnVisibility[colId];
@@ -272,11 +284,11 @@ export const ColumnsSection = (props) => {
272
284
  }
273
285
  const columnIds = ColumnOrderAllColumns.map((col) => col.columnId);
274
286
  const idsToIndexes = new Map(columnIds.map((colId, index) => [colId, index]));
275
- const columnOrderSet = new Set(TableColumns);
287
+ const columnOrderSet = new Set(newTableColumns);
276
288
  const currentColumnIdsAreIncluded = columnIdArray.every((colId) => columnOrderSet.has(colId));
277
289
  if (!currentColumnIdsAreIncluded) {
278
290
  const biggestIndex = Math.max(...columnIdArray.map((colId) => idsToIndexes.get(colId)));
279
- TableColumns = columnIds.filter((colId) => {
291
+ newTableColumns = columnIds.filter((colId) => {
280
292
  const isCurrent = columnOrderSet.has(colId);
281
293
  if (isCurrent) {
282
294
  return true;
@@ -298,7 +310,7 @@ export const ColumnsSection = (props) => {
298
310
  }
299
311
  onChange({
300
312
  ...layout,
301
- TableColumns: TableColumns,
313
+ TableColumns: newTableColumns,
302
314
  ColumnVisibility,
303
315
  });
304
316
  };
@@ -452,7 +464,7 @@ export const ColumnsSection = (props) => {
452
464
  return (React.createElement(ColumnRow, { onColumnNameChange: handleColumnNameChange, onColumnWidthChange: handleColumnWidthChange, onColumnFlexChange: handleColumnFlexChange, onColumnMinWidthChange: handleColumnMinWidthChange, onColumnMaxWidthChange: handleColumnMaxWidthChange, onColumnVisibilityChange: handleColumnVisibilityChange, onPinChange: handlePinChange, layout: layout, column: option }));
453
465
  }, onChange: handleColumnsChange }))),
454
466
  currentOrderIds.length ? (React.createElement(ColumnPropertiesEditor, { column: selectedColumnId && currentOrderIds.includes(selectedColumnId)
455
- ? (colIdToCol[selectedColumnId] ?? null)
467
+ ? colIdToCol[selectedColumnId] ?? null
456
468
  : null, layout: layout, onPinChange: handlePinChange, onColumnNameChange: handleColumnNameChange, onColumnWidthChange: handleColumnWidthChange, onColumnFlexChange: handleColumnFlexChange, onColumnMinWidthChange: handleColumnMinWidthChange, onColumnMaxWidthChange: handleColumnMaxWidthChange, onColumnVisibilityChange: handleColumnVisibilityChange })) : null))));
457
469
  };
458
470
  const hr = (React.createElement("hr", { className: "twa:my-3 twa:mb-0 twa:w-full twa:h-[0.5px] twa:bg-inputborder/50 twa:border-none" }));
@@ -494,7 +506,7 @@ const ColumnPropertiesEditor = (props) => {
494
506
  React.createElement(Flex, { flexDirection: "column", className: "twa:gap-3 twa:mt-3" },
495
507
  React.createElement(Flex, { flexDirection: "column", className: "twa:gap-1" },
496
508
  "Header",
497
- React.createElement(Input, { "data-name": "column-header", className: "ab-Layout-Wizard__ColumnPropertiesEditor__Input twa:w-full", placeholder: "Custom name (optional)", onChange: () => {
509
+ React.createElement(Input, { "data-name": "column-header", className: "ab-Layout-Wizard__ColumnPropertiesEditor__Input twa:w-full", placeholder: "Custom name (optional)", disabled: props.column.isGeneratedSelectionColumn, onChange: () => {
498
510
  props.onColumnNameChange(props.column.columnId, event.target.value);
499
511
  }, value: customHeader })),
500
512
  React.createElement(Box, { className: "twa:grid twa:grid-cols-[1fr_1fr] twa:gap-2" },
@@ -91,7 +91,7 @@ export const RowGroupingSection = (props) => {
91
91
  onChange(newLayout);
92
92
  } },
93
93
  React.createElement(TypeRadio, { value: "single", text: "Single Column", description: "All Row Grouped Columns display in one hierarchical Column" }),
94
- React.createElement(TypeRadio, { value: "multi", text: "Multiple Columns", description: "Each Row Grouped Columns displays in its own, separate, Column" }))))),
94
+ React.createElement(TypeRadio, { value: "multi", text: "Multiple Columns", description: "Each Row Grouped Column displays in its own, separate, Column" }))))),
95
95
  React.createElement(Tabs, { className: "twa:mt-2" },
96
96
  React.createElement(Tabs.Tab, null, "Row Grouped Columns"),
97
97
  React.createElement(Tabs.Tab, null, rowGroupsText),
@@ -0,0 +1,8 @@
1
+ import * as React from 'react';
2
+ import { Layout } from '../../../../../types';
3
+ export declare const RowSelectionSectionSummary: React.FunctionComponent;
4
+ interface RowSelectionSectionProps {
5
+ onChange: (data: Layout) => void;
6
+ }
7
+ export declare const RowSelectionSection: React.FunctionComponent<RowSelectionSectionProps>;
8
+ export {};
@@ -0,0 +1,140 @@
1
+ import * as React from 'react';
2
+ import { CheckBox } from '../../../../components/CheckBox';
3
+ import Radio, { radioGroupStyling } from '../../../../components/Radio';
4
+ import { RadioGroup } from '../../../../components/Radio';
5
+ import { Tabs } from '../../../../components/Tabs';
6
+ import { Tag } from '../../../../components/Tag';
7
+ import { useOnePageAdaptableWizardContext } from '../../../Wizard/OnePageAdaptableWizard';
8
+ import { Box, Flex } from '../../../../components/Flex';
9
+ import { twMerge } from '../../../../twMerge';
10
+ import HelpBlock from '../../../../components/HelpBlock';
11
+ import { isPivotLayout } from '../../../../Utilities/isPivotLayout';
12
+ import { AG_GRID_SELECTION_COLUMN } from '../../../../Utilities/Constants/GeneralConstants';
13
+ export const RowSelectionSectionSummary = () => {
14
+ const { data: layout } = useOnePageAdaptableWizardContext();
15
+ if (layout.RowSelection === false) {
16
+ return (React.createElement(Box, null,
17
+ React.createElement(Tag, null, "Row Selection Disabled")));
18
+ }
19
+ if (!layout.RowSelection) {
20
+ return (React.createElement(Box, null,
21
+ React.createElement(Tag, null, "Default (from Grid Options)")));
22
+ }
23
+ const rs = layout.RowSelection;
24
+ return (React.createElement(Box, null,
25
+ React.createElement(Tag, { className: "twa:mr-2" },
26
+ "Mode: ",
27
+ rs.Mode === 'multiRow' ? 'Multi Row' : 'Single Row'),
28
+ rs.Checkboxes != null && (React.createElement(Tag, { className: "twa:mr-2" },
29
+ "Checkboxes: ",
30
+ rs.Checkboxes ? 'Yes' : 'No')),
31
+ rs.HeaderCheckbox != null && (React.createElement(Tag, { className: "twa:mr-2" },
32
+ "Header Checkbox: ",
33
+ rs.HeaderCheckbox ? 'Yes' : 'No')),
34
+ rs.EnableClickSelection != null && (React.createElement(Tag, { className: "twa:mr-2" },
35
+ "Click Selection: ",
36
+ String(rs.EnableClickSelection))),
37
+ rs.CheckboxInGroupColumn != null && (React.createElement(Tag, { className: "twa:mr-2" },
38
+ "Checkbox Location: ",
39
+ rs.CheckboxInGroupColumn ? 'Group Column' : 'Selection Column')),
40
+ rs.GroupSelectMode != null && (React.createElement(Tag, { className: "twa:mr-2" },
41
+ "Group Select Mode: ",
42
+ rs.GroupSelectMode)),
43
+ rs.SelectAllMode != null && (React.createElement(Tag, { className: "twa:mr-2" },
44
+ "Select All Mode: ",
45
+ rs.SelectAllMode))));
46
+ };
47
+ function getMode(layout) {
48
+ if (!layout.RowSelection) {
49
+ return false;
50
+ }
51
+ return layout.RowSelection.Mode;
52
+ }
53
+ export const RowSelectionSection = (props) => {
54
+ const { data: layout } = useOnePageAdaptableWizardContext();
55
+ const mode = getMode(layout);
56
+ const isPivot = isPivotLayout(layout);
57
+ const rowSelection = layout.RowSelection ?? false;
58
+ const handleModeChange = (newMode) => {
59
+ if (newMode === false) {
60
+ props.onChange({ ...layout, RowSelection: false });
61
+ return;
62
+ }
63
+ const base = rowSelection
64
+ ? { ...rowSelection, Mode: newMode }
65
+ : { Mode: newMode };
66
+ if (newMode === 'singleRow') {
67
+ delete base.HeaderCheckbox;
68
+ delete base.GroupSelectMode;
69
+ delete base.SelectAllMode;
70
+ }
71
+ props.onChange({ ...layout, RowSelection: base });
72
+ };
73
+ const updateRowSelection = (patch) => {
74
+ if (!rowSelection) {
75
+ return;
76
+ }
77
+ const newLayout = {
78
+ ...layout,
79
+ RowSelection: { ...rowSelection, ...patch },
80
+ };
81
+ if (newLayout.RowSelection && !newLayout.RowSelection.CheckboxInGroupColumn) {
82
+ if (newLayout.TableColumns) {
83
+ if (!newLayout.TableColumns.includes(AG_GRID_SELECTION_COLUMN)) {
84
+ newLayout.TableColumns = [AG_GRID_SELECTION_COLUMN, ...(newLayout.TableColumns ?? [])];
85
+ }
86
+ }
87
+ else if (newLayout.PivotColumns) {
88
+ if (!newLayout.PivotColumns.includes(AG_GRID_SELECTION_COLUMN)) {
89
+ newLayout.PivotColumns = [AG_GRID_SELECTION_COLUMN, ...(newLayout.PivotColumns ?? [])];
90
+ }
91
+ }
92
+ }
93
+ props.onChange(newLayout);
94
+ };
95
+ return (React.createElement(React.Fragment, null,
96
+ React.createElement(Tabs, null,
97
+ React.createElement(Tabs.Tab, null, "Row Selection Mode"),
98
+ React.createElement(Tabs.Content, null,
99
+ React.createElement(Flex, { flexDirection: "column" },
100
+ React.createElement(RadioGroup, { orientation: "horizontal", variant: "text-only", className: twMerge(radioGroupStyling.horizontalTextOnly, 'twa:gap-2 twa:max-w-[500px] twa:bg-defaultbackground twa:p-2'), value: mode, name: "rowSelectionMode", onRadioChange: handleModeChange },
101
+ React.createElement(Radio, { value: false }, "Disabled"),
102
+ React.createElement(Radio, { value: "singleRow" }, "Single Row"),
103
+ React.createElement(Radio, { value: "multiRow" }, "Multi Row"))))),
104
+ !rowSelection && React.createElement(HelpBlock, null, "There is no Row Selection configured for this Layout"),
105
+ rowSelection && (React.createElement(React.Fragment, null,
106
+ React.createElement(Tabs, { className: "twa:mt-2" },
107
+ React.createElement(Tabs.Tab, null, "Row Selection Column"),
108
+ React.createElement(Tabs.Content, null,
109
+ React.createElement(Flex, { flexDirection: "row", className: "twa:gap-6" },
110
+ React.createElement(CheckBox, { className: "twa:flex-1", checked: rowSelection.Checkboxes ?? true, onChange: (checked) => updateRowSelection({ Checkboxes: checked }) }, "Show Row Selection Checkboxes"),
111
+ mode === 'multiRow' && (React.createElement(CheckBox, { className: "twa:flex-1", checked: rowSelection.HeaderCheckbox ?? true, onChange: (checked) => updateRowSelection({ HeaderCheckbox: checked }) }, "Show Header Checkbox (to enable Select All)"))))),
112
+ (rowSelection.Checkboxes ?? true) && (React.createElement(Tabs, { className: "twa:mt-2" },
113
+ React.createElement(Tabs.Tab, null, "Row Grouping"),
114
+ React.createElement(Tabs.Content, null,
115
+ React.createElement(RadioGroup, { orientation: "vertical", value: rowSelection.CheckboxInGroupColumn ?? false, name: "checkboxLocation", onRadioChange: (value) => updateRowSelection({ CheckboxInGroupColumn: value }) },
116
+ React.createElement(Radio, { value: false }, "Show Row Selection Checkbox in dedicated Selection Column"),
117
+ React.createElement(Radio, { value: true }, "Show Row Selection Checkbox in Row Grouped Column"))))),
118
+ React.createElement(Tabs, { className: "twa:mt-2" },
119
+ React.createElement(Tabs.Tab, null, "Row Click Selection (when user clicks on Row outside of Selection Checkbox)"),
120
+ React.createElement(Tabs.Content, null,
121
+ React.createElement(RadioGroup, { orientation: "vertical", value: rowSelection.EnableClickSelection ?? false, name: "clickSelection", onRadioChange: (value) => updateRowSelection({ EnableClickSelection: value }) },
122
+ React.createElement(Radio, { value: false }, "Disabled (Cannot select or deselect by clicking in Row)"),
123
+ React.createElement(Radio, { value: true }, "Full (Enable selection by clicking in Row and deselection by Ctrl+clicking in Row)"),
124
+ React.createElement(Radio, { value: 'enableSelection' }, "Selection Only (Enable selection by clicking in Row)"),
125
+ React.createElement(Radio, { value: 'enableDeselection' }, "Deselection Only (Enable deselection by Ctrl+clicking in Row)")))),
126
+ mode === 'multiRow' && !isPivot && (React.createElement(Tabs, { className: "twa:mt-2" },
127
+ React.createElement(Tabs.Tab, null, "Grouped Row Selection Behaviour"),
128
+ React.createElement(Tabs.Content, null,
129
+ React.createElement(RadioGroup, { orientation: "vertical", value: rowSelection.GroupSelectMode ?? 'self', name: "groupSelectMode", onRadioChange: (value) => updateRowSelection({ GroupSelectMode: value }) },
130
+ React.createElement(Radio, { value: 'self' }, "Select Grouped Row Only (no cascade)"),
131
+ React.createElement(Radio, { value: 'descendants' }, "Select Grouped Row and all descendants"),
132
+ React.createElement(Radio, { value: 'filteredDescendants' }, "Select Grouped Row and only filtered descendants"))))),
133
+ mode === 'multiRow' && (React.createElement(Tabs, { className: "twa:mt-2" },
134
+ React.createElement(Tabs.Tab, null, "Select All (in Header) Behaviour"),
135
+ React.createElement(Tabs.Content, null,
136
+ React.createElement(RadioGroup, { orientation: "vertical", value: rowSelection.SelectAllMode ?? 'all', name: "selectAllMode", onRadioChange: (value) => updateRowSelection({ SelectAllMode: value }) },
137
+ React.createElement(Radio, { value: 'all' }, "All rows"),
138
+ React.createElement(Radio, { value: 'filtered' }, "Filtered rows only"),
139
+ React.createElement(Radio, { value: 'currentPage' }, "Current page only")))))))));
140
+ };
@@ -1,4 +1,3 @@
1
- // TODO: move to named query
2
1
  import * as React from 'react';
3
2
  import WizardPanel from '../../../components/WizardPanel';
4
3
  import FormLayout, { FormRow } from '../../../components/FormLayout';
@@ -452,6 +452,7 @@ export class AdaptableAgGrid {
452
452
  columnDefs = LayoutManager.getColumnDefsChangesForLayout(layoutModel, columnDefs) ?? columnDefs;
453
453
  gridOptions.columnDefs = columnDefs;
454
454
  gridOptions.initialState = initialGridState;
455
+ const initialRowSelection = gridOptions.rowSelection;
455
456
  if (layoutModel) {
456
457
  if (isPivotLayoutModel(layoutModel)) {
457
458
  gridOptions.pivotDefaultExpanded = layoutModel.PivotExpandLevel;
@@ -460,6 +461,14 @@ export class AdaptableAgGrid {
460
461
  layoutModel.RowGroupDisplayType === 'multi' ? 'multipleColumns' : 'singleColumn';
461
462
  // fixes issue #3053
462
463
  gridOptions.suppressAggFuncInHeader = !!layoutModel.SuppressAggFuncInHeader;
464
+ if (!isPivotLayoutModel(layoutModel) &&
465
+ LayoutManager.shouldUnlockSelectionColumnPosition(layoutModel)) {
466
+ gridOptions.selectionColumnDef = {
467
+ ...gridOptions.selectionColumnDef,
468
+ lockPosition: false,
469
+ };
470
+ }
471
+ gridOptions.rowSelection = LayoutManager.getGridOptionForRowSelectionFromLayout(layoutModel.RowSelection, gridOptions.rowSelection);
463
472
  }
464
473
  this.lifecycleState = 'initAgGrid';
465
474
  this.agGridAdapter.initialGridOptions = gridOptions;
@@ -475,6 +484,7 @@ export class AdaptableAgGrid {
475
484
  this.layoutManager = new LayoutManager({
476
485
  gridApi: agGridApi,
477
486
  debugId: this.adaptableOptions.adaptableId,
487
+ initialRowSelection,
478
488
  });
479
489
  this.silentUpdateCurrentLayoutModel(layoutModel);
480
490
  // this shouldn't be needed
@@ -27,7 +27,7 @@ export function Dashboard(props) {
27
27
  left: position.x,
28
28
  top: position.y,
29
29
  };
30
- const renderTabs = () => (React.createElement("div", { className: "ab-Dashboard__tabs" }, children &&
30
+ const renderTabs = () => (React.createElement("div", { className: "ab-Dashboard__tabs twa:whitespace-nowrap" }, children &&
31
31
  React.Children.map(children, (child, index) => (React.createElement("button", { type: "button", className: join('ab-Dashboard__tab', !collapsed && activeTabIndex === index ? 'ab-Dashboard__tab--active' : ''), key: index, onClick: () => {
32
32
  if (activeTabIndex === index) {
33
33
  setCollapsed(!collapsed);
@@ -2,6 +2,7 @@ import * as React from 'react';
2
2
  import { BaseModuleTab, ModuleDraggableItem } from './types';
3
3
  export interface ModuleManagerProps {
4
4
  availableItems: ModuleDraggableItem[];
5
+ filterOutSelectedItems?: boolean;
5
6
  className?: string;
6
7
  disabled: boolean;
7
8
  onTabsChange: (tabs: BaseModuleTab[]) => void;