@adaptabletools/adaptable 23.0.5 → 23.0.7

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 (43) hide show
  1. package/index.css +10 -1
  2. package/package.json +1 -1
  3. package/src/AdaptableOptions/AdaptableOptions.d.ts +9 -0
  4. package/src/AdaptableOptions/DataChangeHistoryOptions.d.ts +7 -0
  5. package/src/AdaptableOptions/DefaultAdaptableOptions.d.ts +17 -0
  6. package/src/AdaptableOptions/DefaultAdaptableOptions.js +8 -46
  7. package/src/AdaptableOptions/EditOptions.d.ts +10 -2
  8. package/src/AdaptableOptions/SettingsPanelOptions.d.ts +3 -28
  9. package/src/AdaptableOptions/WizardOptions.d.ts +25 -0
  10. package/src/AdaptableOptions/WizardOptions.js +1 -0
  11. package/src/AdaptableState/Common/CustomWindowConfig.d.ts +2 -14
  12. package/src/AdaptableState/Common/Window.d.ts +33 -0
  13. package/src/AdaptableState/Common/Window.js +1 -0
  14. package/src/AdaptableState/InitialState.d.ts +2 -1
  15. package/src/AdaptableState/PlusMinusState.d.ts +12 -2
  16. package/src/Api/Implementation/DataChangeHistoryApiImpl.js +10 -9
  17. package/src/Redux/ActionsReducers/InternalRedux.d.ts +2 -1
  18. package/src/Redux/ActionsReducers/InternalRedux.js +25 -27
  19. package/src/Strategy/DataChangeHistoryModule.js +1 -1
  20. package/src/Strategy/PlusMinusModule.js +5 -3
  21. package/src/Utilities/Extensions/ObjectExtensions.d.ts +16 -0
  22. package/src/Utilities/Extensions/ObjectExtensions.js +41 -0
  23. package/src/Utilities/Helpers/PlusMinusHelper.d.ts +62 -9
  24. package/src/Utilities/Helpers/PlusMinusHelper.js +180 -25
  25. package/src/View/Components/Popups/AdaptablePopup/AdaptablePopup.js +5 -1
  26. package/src/View/Components/Popups/AdaptablePopup/AdaptablePopupDialog.js +7 -3
  27. package/src/View/Components/Popups/Utilities.d.ts +11 -0
  28. package/src/View/Components/Popups/Utilities.js +8 -0
  29. package/src/View/DataChangeHistory/DataChangeHistoryViewPanel.js +3 -4
  30. package/src/View/DataChangeHistory/dataChangeHistoryHelpers.js +1 -1
  31. package/src/View/PlusMinus/Wizard/KeyComboCaptureInput.d.ts +30 -0
  32. package/src/View/PlusMinus/Wizard/KeyComboCaptureInput.js +161 -0
  33. package/src/View/PlusMinus/Wizard/PlusMinusSettingsWizardSection.js +30 -60
  34. package/src/View/Wizard/OnePageWizards.js +27 -2
  35. package/src/agGrid/AdaptableAgGrid.js +2 -0
  36. package/src/components/ui/input-group.js +0 -1
  37. package/src/env.js +2 -2
  38. package/src/migration/DeprecatedStateKeys.d.ts +37 -0
  39. package/src/migration/DeprecatedStateKeys.js +42 -0
  40. package/src/migration/VersionUpgrade23.d.ts +9 -0
  41. package/src/migration/VersionUpgrade23.js +1 -2
  42. package/src/types.d.ts +4 -2
  43. package/tsconfig.esm.tsbuildinfo +1 -1
@@ -0,0 +1,161 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as React from 'react';
3
+ import { cn } from '../../../lib/utils';
4
+ import { Box, Flex } from '../../../components/Flex';
5
+ import SimpleButton from '../../../components/SimpleButton';
6
+ import { capturePlusMinusTriggerFromEvent, plusMinusKeyLabel, plusMinusTriggerDisplayParts, } from '../../../Utilities/Helpers/PlusMinusHelper';
7
+ import { targetOwn } from '../../../components/twUtils';
8
+ const Kbd = ({ children }) => (_jsx(Box, { as: "kbd", className: "twa:px-2 twa:py-[2px] twa:rounded-standard twa:bg-primary twa:text-2 twa:leading-none twa:font-medium twa:whitespace-nowrap", children: children }));
9
+ const renderTokens = (tokens) => tokens.map((token, index) => (_jsxs(React.Fragment, { children: [index > 0 ? _jsx(Box, { className: "twa:opacity-50 twa:text-2", children: "+" }) : null, _jsx(Kbd, { children: token })] }, `${token}-${index}`)));
10
+ export const KeyComboCaptureInput = (props) => {
11
+ const { value, isUsingDefault, placeholder, disabled, onCapture, onReset, validateCapture } = props;
12
+ const ref = React.useRef(null);
13
+ const [focused, setFocused] = React.useState(false);
14
+ const [editing, setEditing] = React.useState(false);
15
+ const [pendingModifiers, setPendingModifiers] = React.useState([]);
16
+ const [staged, setStaged] = React.useState(undefined);
17
+ const [error, setError] = React.useState(undefined);
18
+ const stopEditing = React.useCallback(() => {
19
+ setEditing(false);
20
+ setPendingModifiers([]);
21
+ setStaged(undefined);
22
+ }, []);
23
+ const handleKeyDown = (event) => {
24
+ if (disabled) {
25
+ return;
26
+ }
27
+ if (!editing) {
28
+ if (event.key === 'Enter') {
29
+ event.preventDefault();
30
+ event.stopPropagation();
31
+ setError(undefined);
32
+ setPendingModifiers([]);
33
+ setStaged(undefined);
34
+ setEditing(true);
35
+ }
36
+ return;
37
+ }
38
+ if (event.key === 'Escape') {
39
+ event.preventDefault();
40
+ event.stopPropagation();
41
+ setError(undefined);
42
+ stopEditing();
43
+ return;
44
+ }
45
+ if (event.key === 'Tab') {
46
+ if (staged && !validateCapture?.(staged)) {
47
+ onCapture(staged);
48
+ }
49
+ stopEditing();
50
+ setError(undefined);
51
+ return;
52
+ }
53
+ event.preventDefault();
54
+ event.stopPropagation();
55
+ const noModifiers = !event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey;
56
+ if (event.key === 'Enter' && noModifiers) {
57
+ if (!staged) {
58
+ return;
59
+ }
60
+ const validationError = validateCapture?.(staged);
61
+ if (validationError) {
62
+ setError(validationError);
63
+ return;
64
+ }
65
+ const confirmed = staged;
66
+ setError(undefined);
67
+ stopEditing();
68
+ onCapture(confirmed);
69
+ return;
70
+ }
71
+ const result = capturePlusMinusTriggerFromEvent({
72
+ key: event.key,
73
+ ctrlKey: event.ctrlKey,
74
+ altKey: event.altKey,
75
+ metaKey: event.metaKey,
76
+ shiftKey: event.shiftKey,
77
+ });
78
+ if (result.kind === 'pending') {
79
+ setPendingModifiers(result.modifiers);
80
+ setError(undefined);
81
+ return;
82
+ }
83
+ if (result.kind === 'invalid') {
84
+ setPendingModifiers([]);
85
+ setStaged(undefined);
86
+ setError(result.reason);
87
+ return;
88
+ }
89
+ const validationError = validateCapture?.(result.trigger);
90
+ if (validationError) {
91
+ setPendingModifiers([]);
92
+ setStaged(undefined);
93
+ setError(validationError);
94
+ return;
95
+ }
96
+ setPendingModifiers([]);
97
+ setError(undefined);
98
+ setStaged(result.trigger);
99
+ };
100
+ const handleReset = (event) => {
101
+ event.preventDefault();
102
+ event.stopPropagation();
103
+ setError(undefined);
104
+ stopEditing();
105
+ onReset?.();
106
+ };
107
+ const handleEnterEdit = (event) => {
108
+ event.preventDefault();
109
+ event.stopPropagation();
110
+ setError(undefined);
111
+ setPendingModifiers([]);
112
+ setStaged(undefined);
113
+ setEditing(true);
114
+ ref.current?.focus();
115
+ };
116
+ const valueParts = plusMinusTriggerDisplayParts(value);
117
+ let content;
118
+ if (editing) {
119
+ if (staged) {
120
+ content = (_jsx(Flex, { className: "twa:items-center twa:gap-1", children: renderTokens(plusMinusTriggerDisplayParts(staged)) }));
121
+ }
122
+ else if (pendingModifiers.length) {
123
+ content = (_jsxs(Flex, { className: "twa:items-center twa:gap-1", children: [renderTokens(pendingModifiers.map(plusMinusKeyLabel)), _jsx(Box, { className: "twa:opacity-50 twa:text-2", children: "+ \u2026" })] }));
124
+ }
125
+ else {
126
+ content = _jsx(Box, { className: "twa:opacity-60 twa:text-2", children: "Press a key combination\u2026" });
127
+ }
128
+ }
129
+ else if (valueParts.length) {
130
+ content = (_jsxs(Flex, { className: "twa:items-center twa:gap-1", children: [renderTokens(valueParts), isUsingDefault ? (_jsx(Box, { className: "twa:opacity-60 twa:text-2 twa:ml-1", children: "(default)" })) : null] }));
131
+ }
132
+ else {
133
+ content = _jsx(Box, { className: "twa:opacity-60 twa:text-2", children: placeholder ?? 'Hit Enter to edit' });
134
+ }
135
+ return (_jsxs(Flex, { flexDirection: "column", className: "twa:gap-1 twa:max-w-[300px] twa:w-full", children: [_jsxs(Flex, { ref: ref, role: "button", tabIndex: disabled ? -1 : 0, "data-name": props['data-name'], "aria-label": "Record keyboard shortcut", onFocus: () => {
136
+ if (!disabled) {
137
+ setFocused(true);
138
+ }
139
+ }, onBlur: (event) => {
140
+ if (ref.current && event.relatedTarget && ref.current.contains(event.relatedTarget)) {
141
+ return;
142
+ }
143
+ if (editing && staged && !validateCapture?.(staged)) {
144
+ onCapture(staged);
145
+ }
146
+ setFocused(false);
147
+ stopEditing();
148
+ setError(undefined);
149
+ }, onClick: () => ref.current?.focus(), onKeyDown: handleKeyDown, className: cn('twa:min-h-input twa:rounded-input twa:px-2 twa:items-center twa:gap-2 twa:w-full', 'twa:border-input twa:border', targetOwn.focusWithinOutline, disabled
150
+ ? 'twa:opacity-60 twa:cursor-not-allowed'
151
+ : 'twa:cursor-pointer twa:bg-input-background', editing ? 'twa:border-accent' : '', error ? 'twa:border-destructive' : ''), children: [_jsx(Flex, { className: "twa:flex-1 twa:flex-wrap twa:items-center twa:gap-1 twa:py-1", children: content }), !disabled && !editing ? (onReset && !isUsingDefault ? (_jsx(SimpleButton, { variant: "text", icon: "undo", tooltip: "Revert to default", "data-name": "plus-minus-reset-key", tabIndex: -1, onMouseDown: handleReset, onKeyDown: (event) => {
152
+ if (event.key === 'Enter') {
153
+ handleReset(event);
154
+ ref.current?.focus();
155
+ }
156
+ } })) : (_jsx(SimpleButton, { variant: "text", icon: "edit", tooltip: "Edit keyboard shortcut", "data-name": "plus-minus-edit-key", tabIndex: -1, onMouseDown: handleEnterEdit, onKeyDown: (event) => {
157
+ if (event.key === 'Enter') {
158
+ handleEnterEdit(event);
159
+ }
160
+ } }))) : null] }), _jsx(Box, { "data-name": error ? 'key-capture-error' : 'key-capture-hint', className: cn('twa:text-2', error ? 'twa:text-destructive' : 'twa:opacity-60', !focused && !error ? 'twa:invisible' : ''), children: error ? error : editing ? 'ENTER to confirm, ESCAPE to cancel' : 'Hit Enter to edit' })] }));
161
+ };
@@ -5,7 +5,8 @@ import { SummaryText, useOnePageAdaptableWizardContext, } from '../../Wizard/One
5
5
  import { Tag } from '../../../components/Tag';
6
6
  import { Box, Flex } from '../../../components/Flex';
7
7
  import { Card } from '../../../components/Card';
8
- import { plusMinusDecrementKeyFromOptionsOnly, plusMinusIncrementKeyFromOptionsOnly, plusMinusResolvedKeysConflict, plusMinusTriggerSameAsBaseline, resolvePlusMinusTriggerKeysForNudge, } from '../../../Utilities/Helpers/PlusMinusHelper';
8
+ import { normalizePlusMinusTrigger, plusMinusDecrementKeyFromOptionsOnly, plusMinusIncrementKeyFromOptionsOnly, plusMinusResolvedKeysConflict, plusMinusTriggerSameAsBaseline, resolvePlusMinusTriggerKeysForNudge, } from '../../../Utilities/Helpers/PlusMinusHelper';
9
+ import { KeyComboCaptureInput } from './KeyComboCaptureInput';
9
10
  export const PlusMinusSettingsSummary = () => {
10
11
  const { data, api } = useOnePageAdaptableWizardContext();
11
12
  const { incrementKey, decrementKey } = resolvePlusMinusTriggerKeysForNudge(data, api.optionsApi.getEditOptions().plusMinusOptions ?? {});
@@ -36,42 +37,35 @@ export const PlusMinusSettingsWizardSection = (props) => {
36
37
  const pmOpts = api.optionsApi.getEditOptions().plusMinusOptions ?? {};
37
38
  const incrementBaseline = plusMinusIncrementKeyFromOptionsOnly(pmOpts);
38
39
  const decrementBaseline = plusMinusDecrementKeyFromOptionsOnly(pmOpts);
39
- const [incrementEdit, setIncrementEdit] = React.useState(undefined);
40
- const [decrementEdit, setDecrementEdit] = React.useState(undefined);
41
- React.useEffect(() => {
42
- setIncrementEdit(undefined);
43
- setDecrementEdit(undefined);
44
- }, [data.Uuid]);
45
- const incrementDisplayValue = incrementEdit !== undefined
46
- ? incrementEdit
47
- : data.IncrementKey?.trim()
48
- ? (data.IncrementKey ?? '').trim()
49
- : incrementBaseline;
50
- const decrementDisplayValue = decrementEdit !== undefined
51
- ? decrementEdit
52
- : data.DecrementKey?.trim()
53
- ? (data.DecrementKey ?? '').trim()
54
- : decrementBaseline;
55
- const commitIncrementKey = React.useCallback((raw) => {
56
- const trimmed = raw.trim();
57
- const next = trimmed === '' || plusMinusTriggerSameAsBaseline(trimmed, incrementBaseline)
58
- ? undefined
59
- : trimmed;
60
- const prev = data.IncrementKey?.trim() || undefined;
61
- if (next !== prev) {
62
- props.onChange({ ...data, IncrementKey: next });
63
- }
40
+ const incrementUsingDefault = !data.IncrementKey?.trim();
41
+ const decrementUsingDefault = !data.DecrementKey?.trim();
42
+ const incrementDisplayValue = incrementUsingDefault
43
+ ? incrementBaseline
44
+ : (data.IncrementKey ?? '').trim();
45
+ const decrementDisplayValue = decrementUsingDefault
46
+ ? decrementBaseline
47
+ : (data.DecrementKey ?? '').trim();
48
+ const commitIncrementKey = React.useCallback((trigger) => {
49
+ const next = plusMinusTriggerSameAsBaseline(trigger, incrementBaseline) ? undefined : trigger;
50
+ props.onChange({ ...data, IncrementKey: next });
64
51
  }, [data, incrementBaseline, props.onChange]);
65
- const commitDecrementKey = React.useCallback((raw) => {
66
- const trimmed = raw.trim();
67
- const next = trimmed === '' || plusMinusTriggerSameAsBaseline(trimmed, decrementBaseline)
68
- ? undefined
69
- : trimmed;
70
- const prev = data.DecrementKey?.trim() || undefined;
71
- if (next !== prev) {
72
- props.onChange({ ...data, DecrementKey: next });
73
- }
52
+ const commitDecrementKey = React.useCallback((trigger) => {
53
+ const next = plusMinusTriggerSameAsBaseline(trigger, decrementBaseline) ? undefined : trigger;
54
+ props.onChange({ ...data, DecrementKey: next });
74
55
  }, [data, decrementBaseline, props.onChange]);
56
+ const resetIncrementKey = React.useCallback(() => {
57
+ props.onChange({ ...data, IncrementKey: undefined });
58
+ }, [data, props.onChange]);
59
+ const resetDecrementKey = React.useCallback(() => {
60
+ props.onChange({ ...data, DecrementKey: undefined });
61
+ }, [data, props.onChange]);
62
+ const SAME_KEYS_MESSAGE = 'Increment and decrement keys cannot be the same.';
63
+ const validateIncrementCapture = React.useCallback((trigger) => normalizePlusMinusTrigger(trigger) === normalizePlusMinusTrigger(decrementDisplayValue)
64
+ ? SAME_KEYS_MESSAGE
65
+ : undefined, [decrementDisplayValue]);
66
+ const validateDecrementCapture = React.useCallback((trigger) => normalizePlusMinusTrigger(trigger) === normalizePlusMinusTrigger(incrementDisplayValue)
67
+ ? SAME_KEYS_MESSAGE
68
+ : undefined, [incrementDisplayValue]);
75
69
  const handleNameChange = (event) => {
76
70
  props.onChange({
77
71
  ...data,
@@ -85,29 +79,5 @@ export const PlusMinusSettingsWizardSection = (props) => {
85
79
  NudgeValue: isNaN(newValue) ? '' : newValue,
86
80
  });
87
81
  };
88
- const handleIncrementKeyFocus = () => {
89
- setIncrementEdit(data.IncrementKey?.trim() ? (data.IncrementKey ?? '').trim() : incrementBaseline);
90
- };
91
- const handleIncrementKeyChange = (event) => {
92
- const raw = event.target.value;
93
- setIncrementEdit(raw);
94
- commitIncrementKey(raw);
95
- };
96
- const handleIncrementKeyBlur = (event) => {
97
- commitIncrementKey(event.target.value);
98
- setIncrementEdit(undefined);
99
- };
100
- const handleDecrementKeyFocus = () => {
101
- setDecrementEdit(data.DecrementKey?.trim() ? (data.DecrementKey ?? '').trim() : decrementBaseline);
102
- };
103
- const handleDecrementKeyChange = (event) => {
104
- const raw = event.target.value;
105
- setDecrementEdit(raw);
106
- commitDecrementKey(raw);
107
- };
108
- const handleDecrementKeyBlur = (event) => {
109
- commitDecrementKey(event.target.value);
110
- setDecrementEdit(undefined);
111
- };
112
- return (_jsx(Box, { "data-name": "plus-minus-column-settings", children: _jsxs(Flex, { flexDirection: "column", className: "twa:gap-3 twa:p-3", children: [_jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Name" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Provide a unique name for the Plus/Minus Nudge" })] }), _jsx(Card.Body, { className: "twa:p-1", children: _jsx(Input, { "data-name": "plus-minus-name", className: "twa:max-w-[300px] twa:w-full", onChange: handleNameChange, placeholder: "Enter Name", value: data.Name ?? '' }) })] }), _jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Nudge Value" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Amount added to or subtracted from the cell value when Plus/Minus is used" })] }), _jsx(Card.Body, { className: "twa:p-1", children: _jsx(Input, { "data-name": "nudge-value", className: "twa:max-w-[300px] twa:w-full", onChange: handleNudgeValueChange, placeholder: "Enter Number", type: "number", value: data.NudgeValue ?? '' }) })] }), _jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Trigger Keys" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Keyboard keys that trigger increment and decrement" })] }), _jsx(Card.Body, { className: "twa:p-1", children: _jsxs(Flex, { flexDirection: "column", className: "twa:gap-3", children: [_jsxs(Box, { children: [_jsx(Box, { className: "twa:text-2 twa:mb-1 twa:opacity-80", children: "Increment key" }), _jsx(Input, { "data-name": "plus-minus-increment-key", className: "twa:max-w-[300px] twa:w-full", onBlur: handleIncrementKeyBlur, onChange: handleIncrementKeyChange, onFocus: handleIncrementKeyFocus, value: incrementDisplayValue })] }), _jsxs(Box, { children: [_jsx(Box, { className: "twa:text-2 twa:mb-1 twa:opacity-80", children: "Decrement key" }), _jsx(Input, { "data-name": "plus-minus-decrement-key", className: "twa:max-w-[300px] twa:w-full", onBlur: handleDecrementKeyBlur, onChange: handleDecrementKeyChange, onFocus: handleDecrementKeyFocus, value: decrementDisplayValue })] })] }) })] })] }) }));
82
+ return (_jsx(Box, { "data-name": "plus-minus-column-settings", children: _jsxs(Flex, { flexDirection: "column", className: "twa:gap-3 twa:p-3", children: [_jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Name" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Provide a unique name for the Plus / Minus Nudge" })] }), _jsx(Card.Body, { className: "twa:p-1", children: _jsx(Input, { "data-name": "plus-minus-name", className: "twa:max-w-[300px] twa:w-full", onChange: handleNameChange, placeholder: "Enter Name", value: data.Name ?? '' }) })] }), _jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Nudge Value" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Amount added to or subtracted from the cell value when Plus / Minus is used" })] }), _jsx(Card.Body, { className: "twa:p-1", children: _jsx(Input, { "data-name": "nudge-value", className: "twa:max-w-[300px] twa:w-full", onChange: handleNudgeValueChange, placeholder: "Enter Number", type: "number", value: data.NudgeValue ?? '' }) })] }), _jsxs(Card, { shadow: false, children: [_jsxs(Card.Title, { children: [_jsx(Box, { className: "twa:font-medium", children: "Trigger Keys" }), _jsx(Box, { className: "twa:text-xs twa:opacity-70 twa:font-normal twa:max-w-[520px]", children: "Click a field and press the keys that should trigger increment / decrement." })] }), _jsx(Card.Body, { className: "twa:p-1", children: _jsxs(Flex, { flexDirection: "column", className: "twa:gap-3", children: [_jsxs(Box, { children: [_jsx(Box, { className: "twa:text-2 twa:mb-1 twa:opacity-80", children: "Increment key" }), _jsx(KeyComboCaptureInput, { "data-name": "plus-minus-increment-key", value: incrementDisplayValue, isUsingDefault: incrementUsingDefault, onCapture: commitIncrementKey, onReset: resetIncrementKey, validateCapture: validateIncrementCapture })] }), _jsxs(Box, { children: [_jsx(Box, { className: "twa:text-2 twa:mb-1 twa:opacity-80", children: "Decrement key" }), _jsx(KeyComboCaptureInput, { "data-name": "plus-minus-decrement-key", value: decrementDisplayValue, isUsingDefault: decrementUsingDefault, onCapture: commitDecrementKey, onReset: resetDecrementKey, validateCapture: validateDecrementCapture })] })] }) })] })] }) }));
113
83
  };
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import * as React from 'react';
3
3
  import { useState, useRef } from 'react';
4
+ import { useDispatch, useSelector } from 'react-redux';
4
5
  import { cn } from '../../lib/utils';
5
6
  import Dialog from '../../components/Dialog';
6
7
  import SimpleButton from '../../components/SimpleButton';
@@ -15,6 +16,9 @@ import { useKeyboardNavigation } from './useKeyboardNavigation';
15
16
  import { Box, Flex } from '../../components/Flex';
16
17
  import { twMerge } from '../../twMerge';
17
18
  import { targetOwn } from '../../components/twUtils';
19
+ import { useAdaptable } from '../AdaptableContext';
20
+ import { getMiddlePosition, getWizardSize } from '../Components/Popups/Utilities';
21
+ import { SettingsPanelSet } from '../../Redux/ActionsReducers/InternalRedux';
18
22
  const ONE_PAGE_WIZARD_SECTION_GRID = 'twa:grid twa:grid-cols-[minmax(160px,14rem)_minmax(0,1fr)]';
19
23
  export const SummaryTag = (props) => (_jsx(Box, { ...props }));
20
24
  export const SummaryText = (props) => (_jsx(Box, { ...props, className: twMerge('twa:text-2 twa:mb-3', props.className) }));
@@ -113,7 +117,28 @@ export const OnePageWizard = (props) => {
113
117
  const canFinish = !invalidCount;
114
118
  const activeSection = visibleSections[currentSection];
115
119
  const activeSectionDetails = activeSection !== '-' ? activeSection?.details : undefined;
116
- return (_jsx(NamedQueryContext.Provider, { value: { namedQuery, setNamedQuery }, children: _jsx(OnePageWizardContext.Provider, { value: contextValue, children: _jsx(Dialog, { modal: props.modal ?? true, isOpen: true, showCloseButton: false, focusOnBrowserVisible: true, className: "twa:rounded-standard twa:overflow-hidden twa:h-[90vh]", ref: dialogRef, onDismiss: () => props.onHide?.(), onKeyDown: (event) => {
120
+ const adaptable = useAdaptable();
121
+ const wizardOptions = adaptable.adaptableOptions.wizardOptions;
122
+ const isWindowMode = wizardOptions?.popupType === 'window' && props.modal !== false;
123
+ const wizardSettingsKey = `wizard-${props.name || 'unnamed'}`;
124
+ const dispatch = useDispatch();
125
+ const persistedWizardSettings = useSelector((state) => state?.Internal?.SettingsPanel?.[wizardSettingsKey]);
126
+ let windowModalProps;
127
+ if (isWindowMode) {
128
+ const size = persistedWizardSettings?.size ?? wizardOptions?.size ?? getWizardSize();
129
+ const position = persistedWizardSettings?.position ?? wizardOptions?.position ?? getMiddlePosition(size);
130
+ windowModalProps = {
131
+ handleSelector: '.ab-OnePageWizard__header',
132
+ minHeight: 460,
133
+ minWidth: 400,
134
+ size,
135
+ position,
136
+ onChange: (settings) => {
137
+ dispatch(SettingsPanelSet(wizardSettingsKey, settings));
138
+ },
139
+ };
140
+ }
141
+ return (_jsx(NamedQueryContext.Provider, { value: { namedQuery, setNamedQuery }, children: _jsx(OnePageWizardContext.Provider, { value: contextValue, children: _jsx(Dialog, { modal: isWindowMode ? false : props.modal ?? true, windowModal: isWindowMode, windowModalProps: windowModalProps, fixed: !isWindowMode, isOpen: true, showCloseButton: false, focusOnBrowserVisible: true, className: cn('twa:rounded-standard twa:overflow-hidden', isWindowMode ? 'twa:h-full' : 'twa:h-[90vh]'), ref: dialogRef, onDismiss: () => props.onHide?.(), onKeyDown: (event) => {
117
142
  if (event.metaKey || event.ctrlKey) {
118
143
  const { key } = event;
119
144
  if (!isNaN(Number(key))) {
@@ -129,7 +154,7 @@ export const OnePageWizard = (props) => {
129
154
  }
130
155
  }
131
156
  }
132
- }, children: _jsxs(Box, { className: cn('ab-OnePageWizard twa:flex twa:flex-col twa:h-full twa:w-[90vw] twa:max-w-[1200px]', 'twa:bg-primarylight twa:text-primary-foreground'), "data-name": props.name, style: props.style, children: [(props.moduleName || activeSectionDetails) && (_jsxs(Box, { className: cn('ab-OnePageWizard__header', ONE_PAGE_WIZARD_SECTION_GRID, 'twa:items-start twa:my-3 twa:px-2'), children: [_jsx(Box, { className: "ab-OnePageWizard__module-name twa:min-w-0 twa:pl-3 twa:font-bold", children: props.moduleName }), _jsx(Box, { className: "ab-OnePageWizard__details twa:min-w-0 twa:pr-2 twa:text-4", children: activeSectionDetails })] })), _jsx(Box, { as: "hr", className: "ab-OnePageWizard__module-separator twa:w-full twa:border-0 twa:border-t twa:border-t-input-border twa:mb-2" }), _jsxs(Box, { className: cn(ONE_PAGE_WIZARD_SECTION_GRID, 'twa:flex-1 twa:min-h-0 twa:overflow-auto twa:items-stretch'), children: [_jsxs(Flex, { flexDirection: "column", className: "ab-OnePageWizard__section-title-container twa:min-h-0 twa:min-w-0 twa:overflow-auto twa:p-3 twa:relative", ref: sizeOwnerRef, style: props.titleContainerStyle, children: [visibleSections.map((section, index) => {
157
+ }, children: _jsxs(Box, { className: cn('ab-OnePageWizard twa:flex twa:flex-col twa:h-full', isWindowMode ? 'twa:w-full' : 'twa:w-[90vw] twa:max-w-[1200px]', 'twa:bg-primarylight twa:text-primary-foreground'), "data-name": props.name, style: props.style, children: [(props.moduleName || activeSectionDetails) && (_jsxs(Box, { className: cn('ab-OnePageWizard__header', ONE_PAGE_WIZARD_SECTION_GRID, 'twa:items-start twa:my-3 twa:px-2'), children: [_jsx(Box, { className: "ab-OnePageWizard__module-name twa:min-w-0 twa:pl-3 twa:font-bold", children: props.moduleName }), _jsx(Box, { className: "ab-OnePageWizard__details twa:min-w-0 twa:pr-2 twa:text-4", children: activeSectionDetails })] })), _jsx(Box, { as: "hr", className: "ab-OnePageWizard__module-separator twa:w-full twa:border-0 twa:border-t twa:border-t-input-border twa:mb-2" }), _jsxs(Box, { className: cn(ONE_PAGE_WIZARD_SECTION_GRID, 'twa:flex-1 twa:min-h-0 twa:overflow-auto twa:items-stretch'), children: [_jsxs(Flex, { flexDirection: "column", className: "ab-OnePageWizard__section-title-container twa:min-h-0 twa:min-w-0 twa:overflow-auto twa:p-3 twa:relative", ref: sizeOwnerRef, style: props.titleContainerStyle, children: [visibleSections.map((section, index) => {
133
158
  if (section === '-') {
134
159
  return (_jsx(Box, { as: "hr", className: "ab-OnePageWizard__section-separator twa:mt-2 twa:w-full twa:border-t twa:border-t-input-border" }, `${index}-`));
135
160
  }
@@ -81,6 +81,7 @@ import { ONLY_AGG_FN_NAME, WEIGHTED_AVERAGE_AGG_FN_NAME, } from '../AdaptableSta
81
81
  import { RowFormService } from '../Utilities/Services/RowFormService';
82
82
  import { ADAPTABLE_PUBLISH_TIMESTAMP } from '../EnvVars';
83
83
  import { AdaptableUpgradeHelper } from '../migration/AdaptableUpgradeHelper';
84
+ import { stripDeprecatedStateKeys } from '../migration/DeprecatedStateKeys';
84
85
  import { ensureLoadingScreenPortalElement } from '../components/Modal';
85
86
  import { AdaptableLoadingScreen } from '../View/Components/Popups/AdaptableLoadingScreen';
86
87
  import { createElement } from 'react';
@@ -521,6 +522,7 @@ export class AdaptableAgGrid {
521
522
  });
522
523
  }
523
524
  normalizeAdaptableState(state, agGridOptions) {
525
+ state = stripDeprecatedStateKeys(state, this.logger);
524
526
  state = this.normaliseLayoutState(state, agGridOptions);
525
527
  state = this.normaliseToolPanelState(state);
526
528
  return state;
@@ -1,4 +1,3 @@
1
- 'use client';
2
1
  import { jsx as _jsx } from "react/jsx-runtime";
3
2
  import * as React from 'react';
4
3
  import { cva } from 'class-variance-authority';
package/src/env.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export default {
2
2
  NEXT_PUBLIC_INFINITE_TABLE_LICENSE_KEY: "StartDate=2021-06-29|EndDate=2030-01-01|Owner=Adaptable|Type=distribution|TS=1624971462479|C=137829811,1004007071,2756196225,1839832928,3994409405,636616862" || '',
3
- PUBLISH_TIMESTAMP: 1782478280705 || Date.now(),
4
- VERSION: "23.0.5" || '--current-version--',
3
+ PUBLISH_TIMESTAMP: 1782993623253 || Date.now(),
4
+ VERSION: "23.0.7" || '--current-version--',
5
5
  };
@@ -0,0 +1,37 @@
1
+ import { AdaptableLogger } from '../agGrid/AdaptableLogger';
2
+ export interface DeprecatedStateKeyInfo {
3
+ /** AdapTable major version in which the key was removed from `AdaptableState`. */
4
+ removedInVersion: number;
5
+ /**
6
+ * Optional short pointer to the replacement feature(s). Only appended to the
7
+ * info message when the deprecated slice actually had content (i.e. the
8
+ * value is a non-empty object). Empty slices — e.g. someone leaving
9
+ * `Schedule: {}` in their `initialState` — get the base message only, since
10
+ * they have nothing to migrate.
11
+ */
12
+ replacement?: string;
13
+ }
14
+ /**
15
+ * Top-level `AdaptableState` keys that used to exist but have since been
16
+ * removed from AdapTable's state shape.
17
+ *
18
+ * On load, `stripDeprecatedStateKeys` quietly removes any of these keys from
19
+ * the incoming state and logs a single friendly `info` line per key — instead
20
+ * of letting Redux's `combineReducers` surface its more alarming
21
+ * `Unexpected key "…" found in previous state received by the reducer` warning.
22
+ *
23
+ * When you drop a top-level state slice, add it here so upgrading users with
24
+ * either an older persisted state or a stale `initialState` block in their
25
+ * `AdaptableOptions` see a soft, actionable message rather than a raw Redux
26
+ * dev-tools warning.
27
+ */
28
+ export declare const DEPRECATED_TOP_LEVEL_STATE_KEYS: Readonly<Record<string, DeprecatedStateKeyInfo>>;
29
+ /**
30
+ * Remove any known-deprecated top-level keys from an incoming state object and
31
+ * log a friendly `info` message per stripped key. Unknown keys are left alone
32
+ * so Redux still surfaces genuinely unexpected state entries.
33
+ *
34
+ * Returns a shallow-cloned state with the deprecated keys removed, or the
35
+ * original state reference when nothing needed stripping.
36
+ */
37
+ export declare function stripDeprecatedStateKeys<T extends Record<string, any>>(state: T, logger?: Pick<AdaptableLogger, 'consoleInfo'>): T;
@@ -0,0 +1,42 @@
1
+ export const DEPRECATED_TOP_LEVEL_STATE_KEYS = {
2
+ Schedule: {
3
+ removedInVersion: 23,
4
+ replacement: 'Use Scheduled Alerts for time-based triggers, or move Report schedules onto Export state.',
5
+ },
6
+ };
7
+ const INTERNAL_STATE_METADATA_KEYS = new Set([
8
+ 'Uuid',
9
+ 'AdaptableVersion',
10
+ 'Source',
11
+ 'Revision',
12
+ ]);
13
+ export function stripDeprecatedStateKeys(state, logger) {
14
+ if (!state || typeof state !== 'object') {
15
+ return state;
16
+ }
17
+ let cleanedState = state;
18
+ let didStrip = false;
19
+ for (const [key, info] of Object.entries(DEPRECATED_TOP_LEVEL_STATE_KEYS)) {
20
+ const value = state[key];
21
+ if (value === undefined) {
22
+ continue;
23
+ }
24
+ if (!didStrip) {
25
+ cleanedState = { ...state };
26
+ didStrip = true;
27
+ }
28
+ delete cleanedState[key];
29
+ const hasContent = value !== null &&
30
+ typeof value === 'object' &&
31
+ Object.keys(value).some((k) => !INTERNAL_STATE_METADATA_KEYS.has(k));
32
+ const message = `Deprecated state key "${key}" was removed in AdapTable v${info.removedInVersion} and will be ignored.` +
33
+ (hasContent && info.replacement ? ` ${info.replacement}` : '');
34
+ if (logger?.consoleInfo) {
35
+ logger.consoleInfo(message);
36
+ }
37
+ else {
38
+ console.info(message);
39
+ }
40
+ }
41
+ return cleanedState;
42
+ }
@@ -2,6 +2,15 @@ import { VersionUpgrade } from './VersionUpgrade';
2
2
  import { AdaptableState } from '../AdaptableState/AdaptableState';
3
3
  export declare class VersionUpgrade23 extends VersionUpgrade {
4
4
  migrateState(state: AdaptableState): AdaptableState;
5
+ /**
6
+ * Logs a one-line summary of each populated sub-collection on the legacy
7
+ * `Schedule` slice so users can see exactly what they had before v23 removed
8
+ * the slice. The actual key removal is done later by
9
+ * `stripDeprecatedStateKeys` (in `normalizeAdaptableState`) so that the
10
+ * friendly "Schedule was removed…" info line always fires whenever `Schedule`
11
+ * is present — even when the slice is empty (e.g. someone left
12
+ * `Schedule: {}` in their `initialState`) or when `autoMigrateState` is off.
13
+ */
5
14
  private migrateSchedulingState;
6
15
  /**
7
16
  * v22 Percent Bar stored cell-text overlay settings as flat
@@ -43,8 +43,7 @@ export class VersionUpgrade23 extends VersionUpgrade {
43
43
  if (removedReminderCount > 0) {
44
44
  this.logger.info(`Removed ${removedReminderCount} legacy Reminders from Schedule state.`);
45
45
  }
46
- const { Schedule: _removed, ...stateWithoutSchedule } = state;
47
- return stateWithoutSchedule;
46
+ return state;
48
47
  }
49
48
  migratePercentBarCellText(state) {
50
49
  const columns = state.StyledColumn?.StyledColumns;
package/src/types.d.ts CHANGED
@@ -51,7 +51,8 @@ export type { ToolPanelOptions, CustomToolPanel, ToolPanelButtonContext, CustomT
51
51
  export type { UserInterfaceOptions, LoadingScreenOptions, ObjectTagsContext, CustomIcon, } from './AdaptableOptions/UserInterfaceOptions';
52
52
  export type { ContextMenuOptions, AdaptableSystemContextMenuItem, CustomContextMenuContext, CustomContextMenuItem, UserContextMenuItem, AgGridContextMenuItemType, DefaultAdaptableMenuStructure, DefaultAgGridMenuStructure, CustomGroupContextMenuItem, } from './AdaptableOptions/ContextMenuOptions';
53
53
  export type { ColumnMenuOptions, CustomColumnMenuContext, CustomColumnMenuItem, UserColumnMenuItem, AdaptableSystemColumnMenuItem, AgGridColumnMenuItemType, CustomGroupColumnMenuItem, } from './AdaptableOptions/ColumnMenuOptions';
54
- export type { CustomSettingsPanel, SettingsPanelOptions, SettingsPanelNavigation, SettingsPanelNavigationGroup, SettingsPanelNavigationContext, SettingsPanelNavigationConfigurer, LegacyFlatSettingsPanelNavigation, SettingsPanelPosition, SettingsPanelSize, PopupType, } from './AdaptableOptions/SettingsPanelOptions';
54
+ export type { CustomSettingsPanel, SettingsPanelOptions, SettingsPanelNavigation, SettingsPanelNavigationGroup, SettingsPanelNavigationContext, SettingsPanelNavigationConfigurer, LegacyFlatSettingsPanelNavigation, PopupType, } from './AdaptableOptions/SettingsPanelOptions';
55
+ export type { WizardOptions } from './AdaptableOptions/WizardOptions';
55
56
  export type { EntitlementOptions, EntitlementContext, DefaultAccessLevelContext, } from './AdaptableOptions/EntitlementOptions';
56
57
  export type { EvaluateExpressionExternallyContext, ExpressionOptions, ModuleExpressionFunctions, ModuleExpressionFunctionsMap, GlobalExpressionFunctionsContext, ModuleExpressionFunctionsContext, CustomQueryVariableContext, QueryableColumnContext, AdaptableFieldContext, } from './AdaptableOptions/ExpressionOptions';
57
58
  export type { PredicateOptions, SystemPredicatesContext, } from './AdaptableOptions/PredicateOptions';
@@ -231,5 +232,6 @@ export type { Fdc3Options, GridDataContextMapping, ActionColumnDefaultConfigurat
231
232
  export type { CommentState, CommentThread, AdaptableComment } from './AdaptableState/CommentState';
232
233
  export type { UpgradeConfig } from '../agGrid';
233
234
  export type { ProgressIndicatorConfig } from './AdaptableState/Common/ProgressIndicatorConfig';
234
- export type { CustomWindowConfig, WindowPosition, WindowSize, } from './AdaptableState/Common/CustomWindowConfig';
235
+ export type { CustomWindowConfig } from './AdaptableState/Common/CustomWindowConfig';
236
+ export type { WindowPosition, WindowSize } from './AdaptableState/Common/Window';
235
237
  export type { TransposeConfig } from './AdaptableState/Common/TransposeConfig';