@adaptabletools/adaptable-cjs 22.0.0-canary.7 → 22.0.0-canary.9

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 (69) hide show
  1. package/agGrid.d.ts +9 -9
  2. package/agGrid.js +1 -0
  3. package/index.css +63 -71
  4. package/index.css.map +1 -1
  5. package/index.d.ts +66 -0
  6. package/index.js +85 -0
  7. package/package.json +3 -3
  8. package/src/AdaptableInterfaces/IAdaptable.d.ts +6 -6
  9. package/src/AdaptableOptions/ColumnOptions.d.ts +2 -2
  10. package/src/AdaptableOptions/ContainerOptions.d.ts +55 -15
  11. package/src/AdaptableState/AdaptableState.d.ts +2 -0
  12. package/src/AdaptableState/Common/AdaptableColumn.d.ts +10 -10
  13. package/src/AdaptableState/Common/AdaptableColumnContext.d.ts +9 -0
  14. package/src/AdaptableState/Common/AdaptableRowContext.d.ts +11 -0
  15. package/src/AdaptableState/Common/AdaptableRowContext.js +2 -0
  16. package/src/AdaptableState/Common/DataUpdateConfig.d.ts +7 -0
  17. package/src/AdaptableState/Common/TransposeConfig.d.ts +11 -9
  18. package/src/AdaptableState/InitialState.d.ts +9 -0
  19. package/src/AdaptableState/LayoutState.d.ts +1 -2
  20. package/src/AdaptableState/UserInterfaceState.d.ts +14 -0
  21. package/src/AdaptableState/UserInterfaceState.js +2 -0
  22. package/src/Api/GridApi.d.ts +5 -9
  23. package/src/Api/Implementation/AlertApiImpl.js +2 -6
  24. package/src/Api/Implementation/ColumnApiImpl.d.ts +1 -1
  25. package/src/Api/Implementation/GridApiImpl.d.ts +2 -6
  26. package/src/Api/Implementation/GridApiImpl.js +9 -9
  27. package/src/Api/Implementation/LayoutApiImpl.d.ts +1 -0
  28. package/src/Api/Implementation/LayoutApiImpl.js +3 -0
  29. package/src/Api/Implementation/SystemStatusApiImpl.js +2 -5
  30. package/src/Api/Implementation/UserInterfaceApiImpl.d.ts +5 -0
  31. package/src/Api/Implementation/UserInterfaceApiImpl.js +13 -0
  32. package/src/Api/LayoutApi.d.ts +6 -0
  33. package/src/Api/UserInterfaceApi.d.ts +17 -0
  34. package/src/Redux/ActionsReducers/UserInterfaceRedux.d.ts +11 -0
  35. package/src/Redux/ActionsReducers/UserInterfaceRedux.js +26 -0
  36. package/src/Redux/Store/AdaptableStore.js +27 -0
  37. package/src/Utilities/resolveContainerElement.d.ts +23 -0
  38. package/src/Utilities/resolveContainerElement.js +47 -0
  39. package/src/View/Components/ColumnFilter/components/ColumnFilterInput.js +1 -1
  40. package/src/View/Components/Popups/AdaptablePopup/AdaptablePopup.js +2 -1
  41. package/src/View/Components/Popups/AdaptablePopup/AdaptablePopupBody.js +1 -1
  42. package/src/View/Components/Popups/AdaptablePopup/AdaptablePopupDialog.d.ts +1 -1
  43. package/src/View/Components/Popups/AdaptablePopup/AdaptablePopupDialog.js +1 -8
  44. package/src/View/Components/Popups/WindowPopups/WindowPopups.js +35 -0
  45. package/src/View/Components/WizardSummaryPage.js +1 -1
  46. package/src/View/Dashboard/CustomToolbar.js +1 -1
  47. package/src/View/DataChangeHistory/DataChangeHistoryViewPanel.js +1 -1
  48. package/src/View/Layout/TransposedPopup.js +144 -138
  49. package/src/View/Schedule/Wizard/ScheduleSettingsWizard/ScheduleSettingsReminder.js +1 -1
  50. package/src/View/UIHelper.d.ts +2 -1
  51. package/src/View/UIHelper.js +8 -14
  52. package/src/agGrid/Adaptable.js +11 -11
  53. package/src/agGrid/AdaptableAgGrid.d.ts +12 -8
  54. package/src/agGrid/AdaptableAgGrid.js +112 -31
  55. package/src/agGrid/AgGridFloatingFilterAdapter.js +1 -1
  56. package/src/agGrid/AgGridMenuAdapter.js +9 -1
  57. package/src/components/CheckBox/index.js +1 -1
  58. package/src/components/Dropdown/Arrows.js +1 -1
  59. package/src/components/ExpressionEditor/DataTableEditor.js +3 -3
  60. package/src/components/FormLayout/index.js +1 -1
  61. package/src/components/Select/Select.js +1 -1
  62. package/src/components/Tree/TreeDropdown/index.js +1 -1
  63. package/src/env.js +2 -2
  64. package/src/metamodel/adaptable.metamodel.d.ts +62 -0
  65. package/src/metamodel/adaptable.metamodel.js +1 -1
  66. package/src/types.d.ts +6 -3
  67. package/themes/dark.css +30 -29
  68. package/themes/light.css +4 -2
  69. package/tsconfig.cjs.tsbuildinfo +1 -1
@@ -0,0 +1,23 @@
1
+ import type { AdaptableContainerValue, ContainerContext, InitContainerContext } from '../AdaptableOptions/ContainerOptions';
2
+ /**
3
+ * The union type representing any container option value (static or function).
4
+ */
5
+ type AnyContainerOption = AdaptableContainerValue | ((context: any) => AdaptableContainerValue);
6
+ /**
7
+ * Resolves a container option value to an `HTMLElement`.
8
+ *
9
+ * Resolution order:
10
+ * 1. If `container` is `null`/`undefined`, returns `null`.
11
+ * 2. If `container` is a function, it is called with the provided `context` and the result is resolved.
12
+ * 3. If the value is an `HTMLElement`, it is returned directly.
13
+ * 4. If the value is an `AdaptableCSSSelector` (`{ selector: string }`), `document.querySelectorAll` is used.
14
+ * If multiple elements match, the first is returned and a console warning is logged.
15
+ * 5. If the value is a `string`, it is treated as an element ID and `document.getElementById` is used.
16
+ *
17
+ * @param container - The container reference to resolve.
18
+ * @param context - Optional context passed to the function form of the container.
19
+ * @param doc - The document to query against (defaults to `globalThis.document`).
20
+ * @returns The resolved `HTMLElement`, or `null` if not found.
21
+ */
22
+ export declare function resolveContainerElement(container: AnyContainerOption | undefined | null, context?: ContainerContext | InitContainerContext, doc?: Document): HTMLElement | null;
23
+ export {};
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveContainerElement = resolveContainerElement;
4
+ /**
5
+ * Resolves a container option value to an `HTMLElement`.
6
+ *
7
+ * Resolution order:
8
+ * 1. If `container` is `null`/`undefined`, returns `null`.
9
+ * 2. If `container` is a function, it is called with the provided `context` and the result is resolved.
10
+ * 3. If the value is an `HTMLElement`, it is returned directly.
11
+ * 4. If the value is an `AdaptableCSSSelector` (`{ selector: string }`), `document.querySelectorAll` is used.
12
+ * If multiple elements match, the first is returned and a console warning is logged.
13
+ * 5. If the value is a `string`, it is treated as an element ID and `document.getElementById` is used.
14
+ *
15
+ * @param container - The container reference to resolve.
16
+ * @param context - Optional context passed to the function form of the container.
17
+ * @param doc - The document to query against (defaults to `globalThis.document`).
18
+ * @returns The resolved `HTMLElement`, or `null` if not found.
19
+ */
20
+ function resolveContainerElement(container, context, doc = globalThis.document) {
21
+ if (container == null) {
22
+ return null;
23
+ }
24
+ // Unwrap function form — pass context if the container is a function
25
+ const value = typeof container === 'function' ? container(context) : container;
26
+ // Guard against null/undefined returned by a callback (e.g. document.getElementById(...))
27
+ if (value == null) {
28
+ return null;
29
+ }
30
+ // Direct HTMLElement reference
31
+ if (value instanceof HTMLElement) {
32
+ return value;
33
+ }
34
+ // CSS Selector object
35
+ if (typeof value === 'object' && 'selector' in value) {
36
+ const matches = doc.querySelectorAll(value.selector);
37
+ if (matches.length > 1) {
38
+ console.warn(`[AdapTable] CSS selector "${value.selector}" matched ${matches.length} elements. Using the first match. Consider using a more specific selector.`);
39
+ }
40
+ return matches[0] ?? null;
41
+ }
42
+ // String element ID
43
+ if (typeof value === 'string') {
44
+ return doc.getElementById(value);
45
+ }
46
+ return null;
47
+ }
@@ -97,7 +97,7 @@ const ColumnFilterInput = (props) => {
97
97
  return (React.createElement(AdaptableInput_1.default, { style: filterType === 'floating'
98
98
  ? {
99
99
  width: '100%',
100
- padding: 'var(--ab-space-1)',
100
+ padding: 'var(--ab-base-space)',
101
101
  borderRadius: 0,
102
102
  border: 'none',
103
103
  }
@@ -13,6 +13,7 @@ const AdaptablePopupBody_1 = require("./AdaptablePopupBody");
13
13
  const AdaptableContext_1 = require("../../../AdaptableContext");
14
14
  const CustomSettingsPanelView_1 = require("./CustomSettingsPanelView");
15
15
  const useMenuItems_1 = require("./useMenuItems");
16
+ const resolveContainerElement_1 = require("../../../../Utilities/resolveContainerElement");
16
17
  const AdaptablePopupDialog_1 = require("./AdaptablePopupDialog");
17
18
  const Flex_1 = require("../../../../components/Flex");
18
19
  const AdaptablePopup = (props) => {
@@ -21,7 +22,7 @@ const AdaptablePopup = (props) => {
21
22
  const settingsPanelTitle = adaptable.ModuleService.getModuleFriendlyName('SettingsPanel');
22
23
  const menuItems = (0, useMenuItems_1.useMenuItems)();
23
24
  const isWindowModal = settingsPanelOptions.popupType === 'window';
24
- const modalContainer = adaptable.adaptableOptions?.containerOptions?.modalContainer;
25
+ const modalContainer = (0, resolveContainerElement_1.resolveContainerElement)(adaptable.adaptableOptions?.containerOptions?.modalContainer, props.api.internalApi.buildBaseContext());
25
26
  let friendlyName = null;
26
27
  /**
27
28
  * This means that it is not rendered in the context of Settings Panel
@@ -7,7 +7,7 @@ const UIHelper_1 = require("../../../UIHelper");
7
7
  const AdaptableViewFactory_1 = require("../../../AdaptableViewFactory");
8
8
  const AdaptablePopupModuleView_1 = require("./AdaptablePopupModuleView");
9
9
  const AdaptablePopupBody = (props) => {
10
- const modalContainer = UIHelper_1.UIHelper.getModalContainer(props.api.optionsApi.getAdaptableOptions(), document);
10
+ const modalContainer = UIHelper_1.UIHelper.getModalContainer(props.api.optionsApi.getAdaptableOptions(), document, props.api.internalApi.buildBaseContext());
11
11
  const moduleName = props.module.moduleInfo.ModuleName;
12
12
  const accessLevel = props.api.entitlementApi.getEntitlementAccessLevelForModule(moduleName);
13
13
  const moduleInfo = props.api.internalApi.getModuleService().getModuleInfoByModule(moduleName);
@@ -7,6 +7,6 @@ export declare const AdaptablePopupDialog: React.FunctionComponent<React.PropsWi
7
7
  isWindowModal: boolean;
8
8
  onHide: () => void;
9
9
  style?: React.CSSProperties;
10
- modalContainer?: string | HTMLElement;
10
+ modalContainer?: HTMLElement;
11
11
  dataName?: string;
12
12
  }>>;
@@ -47,14 +47,7 @@ const PopupDialog = (props) => {
47
47
  const AdaptablePopupDialog = (props) => {
48
48
  const { isActionModule, style, friendlyName, baseClassName, className, children, onHide, isWindowModal, modalContainer, } = props;
49
49
  if (modalContainer) {
50
- let ref = null;
51
- if (typeof modalContainer === 'string') {
52
- ref = globalThis.document.querySelector(modalContainer);
53
- }
54
- else {
55
- ref = modalContainer;
56
- }
57
- return (0, react_dom_1.createPortal)(React.createElement(Dialog_1.default, { "data-name": props.dataName, modal: false, fixed: false, onDismiss: onHide, className: className }, children), ref);
50
+ return (0, react_dom_1.createPortal)(React.createElement(Dialog_1.default, { "data-name": props.dataName, modal: false, fixed: false, onDismiss: onHide, className: className }, children), modalContainer);
58
51
  }
59
52
  if (isWindowModal) {
60
53
  const settingsPanelOptionsKey = isActionModule ? `action-${friendlyName}` : 'settings';
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WindowPopups = exports.CUSTOM_WINDOW_FACTORY_ID = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const React = tslib_1.__importStar(require("react"));
6
+ const react_dom_1 = require("react-dom");
6
7
  const react_redux_1 = require("react-redux");
7
8
  const Dialog_1 = tslib_1.__importDefault(require("../../../../components/Dialog"));
8
9
  const PopupRedux_1 = require("../../../../Redux/ActionsReducers/PopupRedux");
10
+ const resolveContainerElement_1 = require("../../../../Utilities/resolveContainerElement");
9
11
  const AdaptableContext_1 = require("../../../AdaptableContext");
10
12
  const ExternalRenderer_1 = require("../../ExternalRenderer");
11
13
  const PanelWithImage_1 = require("../../Panels/PanelWithImage");
@@ -15,6 +17,32 @@ const NoopComponent = () => {
15
17
  return React.createElement(React.Fragment, null);
16
18
  };
17
19
  exports.CUSTOM_WINDOW_FACTORY_ID = 'CUSTOM_WINDOW_FACTORY_ID';
20
+ /**
21
+ * Portals children into a target container element.
22
+ * Monitors the container with a MutationObserver — if the container is removed
23
+ * from the DOM, `onContainerRemoved` is called so callers can clean up React/Redux state.
24
+ */
25
+ const ContainerPortal = ({ container, onContainerRemoved, children }) => {
26
+ React.useEffect(() => {
27
+ // If the container is already detached, clean up immediately
28
+ if (!document.contains(container)) {
29
+ onContainerRemoved();
30
+ return;
31
+ }
32
+ const observer = new MutationObserver(() => {
33
+ if (!document.contains(container)) {
34
+ onContainerRemoved();
35
+ observer.disconnect();
36
+ }
37
+ });
38
+ // Observe the entire document body for subtree removals
39
+ observer.observe(document.body, { childList: true, subtree: true });
40
+ return () => {
41
+ observer.disconnect();
42
+ };
43
+ }, [container, onContainerRemoved]);
44
+ return (0, react_dom_1.createPortal)(children, container);
45
+ };
18
46
  const WindowPopups = () => {
19
47
  const [windowModalSettings, setWindowModalSettings] = React.useState({});
20
48
  const adaptable = (0, AdaptableContext_1.useAdaptable)();
@@ -41,6 +69,13 @@ const WindowPopups = () => {
41
69
  Component = Component ?? NoopComponent;
42
70
  componentNode = (React.createElement(Component, { api: adaptable.api, onDismiss: handleDismiss, popupProps: restPopupProps }));
43
71
  }
72
+ // Transposed View: portal into custom container if configured
73
+ if (windowItem.FactoryId === windowFactory_1.WINDOW_SHOW_TRANSPOSED_VIEW) {
74
+ const transposedContainer = (0, resolveContainerElement_1.resolveContainerElement)(adaptable.adaptableOptions?.containerOptions?.transposedViewContainer, adaptable.api.internalApi.buildBaseContext());
75
+ if (transposedContainer) {
76
+ return (React.createElement(ContainerPortal, { key: windowItem.Id, container: transposedContainer, onContainerRemoved: handleDismiss }, componentNode));
77
+ }
78
+ }
44
79
  return (React.createElement(Dialog_1.default, { "data-name": windowItem.Id, className: "ab-Window-Modal twa:h-full twa:p-0", key: windowItem.Id, windowModal: true, windowModalProps: {
45
80
  ...windowModalProps,
46
81
  onChange: (settings) => {
@@ -13,7 +13,7 @@ const tableDOMProps = {
13
13
  className: 'ab-WizardSummary__list',
14
14
  style: {
15
15
  height: '100%',
16
- margin: 'var(--ab-space-2)',
16
+ margin: 'calc(var(--ab-base-space) * 2)',
17
17
  },
18
18
  };
19
19
  const WizardSummaryPage = (props) => {
@@ -79,7 +79,7 @@ const CustomToolbarCmp = (props) => {
79
79
  const disabled = button.disabled && button.disabled(button, dashboardContext);
80
80
  let buttonVariant = buttonStyle && buttonStyle.variant ? buttonStyle.variant : 'outlined';
81
81
  let buttonTone = buttonStyle && buttonStyle.tone ? buttonStyle.tone : 'neutral';
82
- return (React.createElement(AdaptableButton_1.AdaptableButtonComponent, { style: { marginLeft: index ? 'var(--ab-space-1)' : 0 }, key: index, disabled: disabled, tooltip: buttonTooltip, icon: buttonIcon, variant: buttonVariant, tone: buttonTone, className: buttonStyle?.className || '', onClick: () => {
82
+ return (React.createElement(AdaptableButton_1.AdaptableButtonComponent, { style: { marginLeft: index ? 'var(--ab-base-space)' : 0 }, key: index, disabled: disabled, tooltip: buttonTooltip, icon: buttonIcon, variant: buttonVariant, tone: buttonTone, className: buttonStyle?.className || '', onClick: () => {
83
83
  button.onClick ? button.onClick(button, dashboardContext) : null;
84
84
  setTimeout(() => {
85
85
  // mutate state to force a re-rendering
@@ -31,7 +31,7 @@ const DataChangeHistoryViewPanelControl = (props) => {
31
31
  const enabled = changeHistoryMode === 'ACTIVE';
32
32
  const disabled = changeHistoryMode === 'INACTIVE';
33
33
  const suspended = changeHistoryMode === 'SUSPENDED';
34
- const gap = props.gap ?? 'var(--ab-space-1)';
34
+ const gap = props.gap ?? 'var(--ab-base-space)';
35
35
  const buttonsPaddingY = props.buttonsPaddingY ?? 2;
36
36
  const buttonPanel = (React.createElement(Flex_1.Flex, { className: "ab-DataChangeHistoryPanel--button-panel", style: { gap: gap, paddingBlock: buttonsPaddingY } },
37
37
  disabled && (React.createElement(ButtonPlay_1.ButtonPlay, { "aria-label": "Enable Data Change History", className: "ab-DataChangeHistoryPanel--button-activate", "data-name": 'data-change-history--button-activate', tooltip: '', onClick: () => onChangeHistoryEnable() })),
@@ -9,72 +9,153 @@ const AdaptableContext_1 = require("../AdaptableContext");
9
9
  const ColumnSelector_1 = require("../Components/Selectors/ColumnSelector");
10
10
  const AdaptableAgGrid_1 = require("../../agGrid/AdaptableAgGrid");
11
11
  const Flex_1 = require("../../components/Flex");
12
- const adaptableContainerId = `transposed-adaptable-container`;
13
- const agGridContainerId = `transposed-adaptable-ag-grid-container`;
12
+ const ModuleConstants_1 = require("../../Utilities/Constants/ModuleConstants");
13
+ const StringExtensions_1 = tslib_1.__importDefault(require("../../Utilities/Extensions/StringExtensions"));
14
+ const ADAPTABLE_CONTAINER_ID = 'transposed-adaptable-container';
15
+ const AG_GRID_CONTAINER_ID = 'transposed-adaptable-ag-grid-container';
16
+ /** Field used for the first column in transposed grid (hidden, holds column id). */
17
+ const TRANSPOSED_FIRST_COLUMN_FIELD = '_transposed_column_value';
18
+ /** Header used for the first visible column in transposed grid (shows friendly name). */
19
+ const TRANSPOSED_FIRST_COLUMN_HEADER = '_transposed_column_header';
20
+ function buildTransposedAdaptableOptions({ hostOptions, transposedRowsAndColumns, currentTheme, }) {
21
+ return {
22
+ primaryKey: TRANSPOSED_FIRST_COLUMN_FIELD,
23
+ licenseKey: hostOptions.licenseKey,
24
+ userName: `${hostOptions.userName}`,
25
+ adaptableId: `${hostOptions.adaptableId}::TransposedView`,
26
+ containerOptions: {
27
+ adaptableContainer: ADAPTABLE_CONTAINER_ID,
28
+ agGridContainer: AG_GRID_CONTAINER_ID,
29
+ },
30
+ entitlementOptions: { defaultAccessLevel: 'Hidden' },
31
+ initialState: {
32
+ Layout: {
33
+ Revision: Date.now(),
34
+ CurrentLayout: 'TransposedView',
35
+ Layouts: [
36
+ {
37
+ Name: 'TransposedView',
38
+ TableColumns: [
39
+ TRANSPOSED_FIRST_COLUMN_HEADER,
40
+ ...transposedRowsAndColumns.transposedColumns.map((c) => c.colId),
41
+ ],
42
+ ColumnPinning: { [TRANSPOSED_FIRST_COLUMN_HEADER]: 'left' },
43
+ AutoSizeColumns: true,
44
+ },
45
+ ],
46
+ },
47
+ Theme: { CurrentTheme: currentTheme },
48
+ },
49
+ };
50
+ }
51
+ function buildTransposedGridOptions({ transposedRowsAndColumns, elevatedColumnId, adaptableApi, }) {
52
+ const firstColumn = {
53
+ field: TRANSPOSED_FIRST_COLUMN_HEADER,
54
+ headerName: adaptableApi.columnApi.getFriendlyNameForColumnId(elevatedColumnId),
55
+ };
56
+ return {
57
+ loading: false,
58
+ defaultColDef: {
59
+ floatingFilter: false,
60
+ filter: false,
61
+ sortable: true,
62
+ resizable: true,
63
+ enableRowGroup: false,
64
+ editable: false,
65
+ enablePivot: false,
66
+ enableValue: false,
67
+ lockPinned: true,
68
+ menuTabs: [],
69
+ width: 120,
70
+ },
71
+ columnDefs: [
72
+ { field: TRANSPOSED_FIRST_COLUMN_FIELD, hide: true },
73
+ firstColumn,
74
+ ...transposedRowsAndColumns.transposedColumns.map((col) => ({ field: col.colId, headerName: col.header })),
75
+ ],
76
+ rowData: transposedRowsAndColumns.transposedRows,
77
+ sideBar: false,
78
+ };
79
+ }
14
80
  const TransposedPopup = (props) => {
15
81
  const adaptable = (0, AdaptableContext_1.useAdaptable)();
16
- const { transposedColumnId, hideTransposedColumn, visibleColumns, visibleRows, autosize } = props.popupProps;
17
- const rowNodes = React.useMemo(() => {
18
- return props.popupProps.visibleRows
19
- ? adaptable.api.gridApi.getVisibleRowNodes()
20
- : adaptable.api.gridApi.getAllRowNodes();
21
- }, [
22
- // can be later triggered by tickng data
23
- ]);
24
82
  const primaryKey = adaptable.api.optionsApi.getPrimaryKey();
25
- const [syntheticTransposedByColumnId, doSetSyntheticTransposedByColumnId] = React.useState(transposedColumnId);
26
- const setSyntheticTransposedByColumnId = (syntheticTransposedByColumnId) => {
83
+ const rawConfig = (props.popupProps ?? {});
84
+ const transposeConfig = {
85
+ transposedColumnId: rawConfig.transposedColumnId ?? primaryKey,
86
+ hideTransposedColumn: rawConfig.hideTransposedColumn ?? true,
87
+ autosize: rawConfig.autosize ?? true,
88
+ columnsToTranspose: rawConfig.columnsToTranspose,
89
+ rowsToTranspose: rawConfig.rowsToTranspose,
90
+ };
91
+ const rowNodes = React.useMemo(() => {
92
+ let transposableRowNodes = [];
93
+ const rowsToTranspose = transposeConfig.rowsToTranspose;
94
+ if (rowsToTranspose === 'VisibleOnly') {
95
+ return adaptable.api.gridApi.getVisibleRowNodes();
96
+ }
97
+ if (rowsToTranspose === 'All') {
98
+ return adaptable.api.gridApi.getAllRowNodes();
99
+ }
100
+ if (StringExtensions_1.default.IsNotNullOrEmpty(rowsToTranspose)) {
101
+ adaptable.api.gridApi.getAllRowNodes().forEach((rn) => {
102
+ const shouldTransposeRow = adaptable.api.internalApi
103
+ .getQueryLanguageService()
104
+ .evaluateBooleanExpression(rowsToTranspose, ModuleConstants_1.ExportModuleId, rn);
105
+ if (shouldTransposeRow) {
106
+ transposableRowNodes.push(rn);
107
+ }
108
+ });
109
+ return transposableRowNodes;
110
+ }
111
+ return adaptable.api.gridApi.getAllRowNodes();
112
+ }, [transposeConfig.rowsToTranspose, adaptable.api]);
113
+ const [elevatedColumnId, setElevatedColumnIdState] = React.useState(() => transposeConfig.transposedColumnId ?? primaryKey);
114
+ const setElevatedColumnId = (newElevatedColumnId) => {
27
115
  transposedAdaptableApiRef.current?.destroy({ unmount: true, destroyAgGrid: true });
28
- doSetSyntheticTransposedByColumnId(syntheticTransposedByColumnId);
116
+ setElevatedColumnIdState(newElevatedColumnId);
29
117
  };
30
118
  const transposedAdaptableApiRef = React.useRef(null);
31
119
  const columns = React.useMemo(() => {
32
- // customisable
33
- return visibleColumns
34
- ? adaptable.api.columnApi.getVisibleColumns()
35
- : adaptable.api.columnApi.getUIAvailableColumns();
36
- }, []);
120
+ const allUIColumns = adaptable.api.columnApi.getUIAvailableColumns();
121
+ const columnsToTranspose = transposeConfig.columnsToTranspose;
122
+ if (!columnsToTranspose) {
123
+ return allUIColumns;
124
+ }
125
+ const columnIds = typeof columnsToTranspose === 'function'
126
+ ? columnsToTranspose({
127
+ ...adaptable.api.internalApi.buildBaseContext(),
128
+ columns: allUIColumns,
129
+ })
130
+ : columnsToTranspose;
131
+ return columnIds
132
+ .map((c) => adaptable.api.columnApi.getColumnWithColumnId(c))
133
+ .filter((col) => col != null);
134
+ }, [transposeConfig.columnsToTranspose, adaptable.api]);
37
135
  /**
38
- * This is used as first field
136
+ * Build transposed structure: original rows become columns (colId = primaryKey value),
137
+ * original columns become rows. Each transposed row has the column id/header plus
138
+ * one cell per original row keyed by primaryKey value.
39
139
  */
40
- const transposedFirstColumnField = '_transposed_column_value';
41
- const transposedFirstColumnHeader = '_transposed_column_header';
42
140
  const transposedRowsAndColumns = React.useMemo(() => {
43
- /**
44
- * transposed column values become primaryKey of the new tarnsposed rows
45
- * we build row by row, might be easer
46
- */
47
141
  const transposedColumns = [];
48
142
  const transposedRows = [];
49
143
  for (const row of rowNodes) {
50
- // we force the col-ids to be strings, easer to work with
51
- //row[transposeByColumnId] + '';
52
144
  const colId = adaptable.api.gridApi.getNormalisedValueFromRowNode(row, primaryKey) + '';
53
- //row[synteticTransposedByColumnId] + '';
54
- const header = adaptable.api.gridApi.getNormalisedValueFromRowNode(row, syntheticTransposedByColumnId) +
55
- '';
56
- transposedColumns.push({
57
- colId,
58
- header,
59
- });
145
+ const header = adaptable.api.gridApi.getNormalisedValueFromRowNode(row, elevatedColumnId) + '';
146
+ transposedColumns.push({ colId, header });
60
147
  }
61
148
  for (const column of columns) {
62
- /**
63
- * We can hide the transposed column, if we want
64
- */
65
- if (hideTransposedColumn && column.columnId === syntheticTransposedByColumnId) {
149
+ if (transposeConfig.hideTransposedColumn &&
150
+ column.columnId === elevatedColumnId) {
66
151
  continue;
67
152
  }
68
153
  const transposedRow = {
69
- // [transposed-by-column-id]: [other column id],
70
- // the value can be set to friendlyname
71
- [transposedFirstColumnField]: column.columnId,
72
- [transposedFirstColumnHeader]: column.friendlyName,
154
+ [TRANSPOSED_FIRST_COLUMN_FIELD]: column.columnId,
155
+ [TRANSPOSED_FIRST_COLUMN_HEADER]: column.friendlyName,
73
156
  };
74
- for (let row of rowNodes) {
75
- // [transposed-by-column-value[n]]: [other column value[n]]
157
+ for (const row of rowNodes) {
76
158
  const key = adaptable.api.gridApi.getNormalisedValueFromRowNode(row, primaryKey);
77
- // row[column.field]
78
159
  let value = adaptable.api.gridApi.getDisplayValueFromRowNode(row, column.columnId);
79
160
  if (value instanceof Date) {
80
161
  value = value.toLocaleString();
@@ -83,90 +164,25 @@ const TransposedPopup = (props) => {
83
164
  }
84
165
  transposedRows.push(transposedRow);
85
166
  }
86
- return {
87
- transposedColumns,
88
- transposedRows,
89
- };
90
- }, [rowNodes, primaryKey, syntheticTransposedByColumnId]);
167
+ return { transposedColumns, transposedRows };
168
+ }, [rowNodes, primaryKey, elevatedColumnId, columns, transposeConfig.hideTransposedColumn, adaptable.api]);
91
169
  React.useEffect(() => {
92
- // Mounting in an effect, so the nodes are rendered/available
93
- const hostAdaptableOptions = adaptable.adaptableOptions;
94
- const adaptableOptions = {
95
- primaryKey: transposedFirstColumnField,
96
- licenseKey: hostAdaptableOptions.licenseKey,
97
- userName: `${hostAdaptableOptions.userName}`,
98
- adaptableId: `${hostAdaptableOptions.adaptableId}::TransposedView`,
99
- containerOptions: {
100
- adaptableContainer: adaptableContainerId,
101
- agGridContainer: agGridContainerId,
102
- },
103
- entitlementOptions: {
104
- defaultAccessLevel: 'Hidden',
105
- },
106
- initialState: {
107
- Layout: {
108
- Revision: Date.now(),
109
- CurrentLayout: 'TransposedView',
110
- Layouts: [
111
- {
112
- Name: 'TransposedView',
113
- TableColumns: [
114
- transposedFirstColumnHeader,
115
- ...transposedRowsAndColumns.transposedColumns.map((c) => c.colId),
116
- ],
117
- ColumnPinning: {
118
- [transposedFirstColumnHeader]: 'left',
119
- },
120
- AutoSizeColumns: true,
121
- },
122
- ],
123
- },
124
- Theme: {
125
- CurrentTheme: adaptable.api.themeApi.getCurrentTheme(),
126
- },
127
- },
128
- };
129
- const firstColumn = {
130
- field: transposedFirstColumnHeader, // use the column friendly name
131
- headerName: adaptable.api.columnApi.getFriendlyNameForColumnId(syntheticTransposedByColumnId),
132
- };
133
- const agGridOptions = {
134
- loading: false,
135
- defaultColDef: {
136
- floatingFilter: false,
137
- filter: false,
138
- sortable: true,
139
- resizable: true,
140
- enableRowGroup: false,
141
- editable: false,
142
- enablePivot: false,
143
- enableValue: false,
144
- lockPinned: true,
145
- menuTabs: [],
146
- width: 120,
147
- },
148
- columnDefs: [
149
- {
150
- field: transposedFirstColumnField,
151
- hide: true,
152
- },
153
- firstColumn,
154
- ...transposedRowsAndColumns.transposedColumns.map((col) => {
155
- return {
156
- field: col.colId,
157
- type: null,
158
- headerName: col.header,
159
- };
160
- }),
161
- ],
162
- rowData: transposedRowsAndColumns.transposedRows,
163
- sideBar: false,
164
- };
170
+ const hostOptions = adaptable.adaptableOptions;
171
+ const adaptableOptions = buildTransposedAdaptableOptions({
172
+ hostOptions,
173
+ transposedRowsAndColumns,
174
+ currentTheme: adaptable.api.themeApi.getCurrentTheme(),
175
+ });
176
+ const gridOptions = buildTransposedGridOptions({
177
+ transposedRowsAndColumns,
178
+ elevatedColumnId,
179
+ adaptableApi: adaptable.api,
180
+ });
165
181
  const modules = adaptable.agGridModulesAdapter.getAgGridRegisteredModules();
166
182
  AdaptableAgGrid_1.AdaptableAgGrid._initInternal({
167
183
  variant: 'vanilla',
168
184
  adaptableOptions,
169
- gridOptions: agGridOptions,
185
+ gridOptions,
170
186
  modules,
171
187
  }).then((adaptableApi) => {
172
188
  transposedAdaptableApiRef.current = adaptableApi;
@@ -174,31 +190,21 @@ const TransposedPopup = (props) => {
174
190
  transposedAdaptableApiRef.current?.themeApi.loadTheme(typeof event.theme === 'object' ? event.theme.Name : event.theme);
175
191
  });
176
192
  });
177
- }, [syntheticTransposedByColumnId]);
193
+ }, [elevatedColumnId, adaptable]);
178
194
  React.useEffect(() => {
179
- // destroy when closing the popup
180
195
  return () => {
181
196
  requestAnimationFrame(() => {
182
197
  transposedAdaptableApiRef.current?.destroy({ unmount: true, destroyAgGrid: true });
183
198
  });
184
199
  };
185
200
  }, []);
186
- /**
187
- * Need to get all data, manualy pivot the grid using the primary key.
188
- *
189
- * 1. get the data, and pivot using the primary key
190
- * 2. create the col definitios, a col definition for each row
191
- * 3. create the grid
192
- */
193
201
  return (React.createElement(Flex_1.Flex, { flexDirection: "column", className: "twa:w-full twa:h-full" },
194
202
  React.createElement(Panel_1.default, null,
195
203
  React.createElement(FormLayout_1.default, null,
196
204
  React.createElement(FormLayout_1.FormRow, { label: "Elevated Column" },
197
- React.createElement(ColumnSelector_1.ColumnSelector, { value: syntheticTransposedByColumnId, onChange: (colId) => {
198
- setSyntheticTransposedByColumnId(colId);
199
- } })))),
205
+ React.createElement(ColumnSelector_1.ColumnSelector, { value: elevatedColumnId, onChange: setElevatedColumnId })))),
200
206
  React.createElement(Flex_1.Flex, { className: "twa:h-full" },
201
- React.createElement(Flex_1.Box, { id: adaptableContainerId }),
202
- React.createElement(Flex_1.Box, { className: "twa:h-full twa:w-full", id: agGridContainerId }))));
207
+ React.createElement(Flex_1.Box, { id: ADAPTABLE_CONTAINER_ID }),
208
+ React.createElement(Flex_1.Box, { className: "twa:h-full twa:w-full", id: AG_GRID_CONTAINER_ID }))));
203
209
  };
204
210
  exports.TransposedPopup = TransposedPopup;
@@ -57,7 +57,7 @@ const ScheduleSettingsReminder = (props) => {
57
57
  React.createElement(Tabs_1.Tabs.Content, null,
58
58
  React.createElement(FormLayout_1.default, null,
59
59
  React.createElement(FormLayout_1.FormRow, { label: "Name" },
60
- React.createElement(Input_1.default, { "data-name": "schedule-name", className: "twa:w-[300px]", onChange: handleNameChange, placeholder: "Enter Schedule Name", type: "string", value: props.reminderSchedule?.Name ?? '' })),
60
+ React.createElement(Input_1.default, { "data-name": "schedule-name", className: "twa:w-[300px]", onChange: handleNameChange, placeholder: "Enter Reminder Name", type: "string", value: props.reminderSchedule?.Name ?? '' })),
61
61
  React.createElement(FormLayout_1.FormRow, { label: "" },
62
62
  React.createElement(Flex_1.Box, { className: "twa:h-2" })),
63
63
  React.createElement(FormLayout_1.FormRow, { label: "Header" },
@@ -6,6 +6,7 @@ import { Schedule, Weekday } from '../AdaptableState/Common/Schedule';
6
6
  import { AdaptableColumnDataType, AdaptableSystemIconName, AdaptableOptions } from '../types';
7
7
  import { AdaptableAlert } from '../AdaptableState/Common/AdaptableAlert';
8
8
  import { AdaptableMessageType } from '../AdaptableState/Common/AdaptableMessageType';
9
+ import type { ContainerContext } from '../AdaptableOptions/ContainerOptions';
9
10
  export declare const BLACK: string;
10
11
  export declare const WHITE: string;
11
12
  export declare const LIGHT_GRAY: string;
@@ -31,7 +32,7 @@ export declare function getDefaultColors(): string[];
31
32
  export declare function getEmptyConfigState(): EditableConfigEntityState;
32
33
  export declare function getDescriptionForDataType(dataType: AdaptableColumnDataType): "text" | "number" | "date";
33
34
  export declare function getPlaceholderForDataType(dataType: AdaptableColumnDataType): "Enter Value" | "Enter Number" | "Enter Date";
34
- export declare function getModalContainer(adaptableOptions: AdaptableOptions, document: Document): HTMLElement;
35
+ export declare function getModalContainer(adaptableOptions: AdaptableOptions, document: Document, context?: ContainerContext): HTMLElement;
35
36
  export declare function IsEmptyStyle(style: AdaptableStyle): boolean;
36
37
  export declare function IsNotEmptyStyle(style: AdaptableStyle): boolean;
37
38
  export declare function getMessageTypeByStatusColour(statusColour: StatusColour): AdaptableMessageType;
@@ -35,6 +35,7 @@ const EditableConfigEntityState_1 = require("./Components/SharedProps/EditableCo
35
35
  const Enums_1 = require("../AdaptableState/Common/Enums");
36
36
  const StringExtensions_1 = require("../Utilities/Extensions/StringExtensions");
37
37
  const ArrayExtensions_1 = tslib_1.__importDefault(require("../Utilities/Extensions/ArrayExtensions"));
38
+ const resolveContainerElement_1 = require("../Utilities/resolveContainerElement");
38
39
  exports.BLACK = 'Black';
39
40
  exports.WHITE = 'White';
40
41
  exports.LIGHT_GRAY = 'LightGray';
@@ -153,19 +154,12 @@ function getPlaceholderForDataType(dataType) {
153
154
  return 'Enter Date';
154
155
  }
155
156
  }
156
- function getModalContainer(adaptableOptions, document) {
157
- let modalContainer;
158
- if (adaptableOptions.containerOptions.modalContainer) {
159
- // this has been set, so we use the property
160
- modalContainer =
161
- typeof adaptableOptions.containerOptions.modalContainer === 'string'
162
- ? document.getElementById(adaptableOptions.containerOptions.modalContainer)
163
- : adaptableOptions.containerOptions.modalContainer;
164
- if (modalContainer) {
165
- const modalContainerClassName = ' modal-container';
166
- if (!modalContainer.className.includes(modalContainerClassName)) {
167
- modalContainer.className += modalContainerClassName;
168
- }
157
+ function getModalContainer(adaptableOptions, document, context) {
158
+ let modalContainer = (0, resolveContainerElement_1.resolveContainerElement)(adaptableOptions.containerOptions.modalContainer, context, document);
159
+ if (modalContainer) {
160
+ const modalContainerClassName = ' modal-container';
161
+ if (!modalContainer.className.includes(modalContainerClassName)) {
162
+ modalContainer.className += modalContainerClassName;
169
163
  }
170
164
  }
171
165
  if (!modalContainer) {
@@ -456,7 +450,7 @@ function getAdaptableToolPanelWidth() {
456
450
  return getNumericCSSVariableValue(getCSSVariableValue('--ab-cmp-toolpanel__width'), 200);
457
451
  }
458
452
  function getSimpleButtonPaddingWidth() {
459
- return getNumericCSSVariableValue(getCSSVariableValue('--ab-space-1'), 4);
453
+ return getNumericCSSVariableValue(getCSSVariableValue('--ab-base-space'), 4);
460
454
  }
461
455
  function getCSSVariableValue(cssVariable) {
462
456
  if (!isBrowserDocumentAvailable()) {