@adaptabletools/adaptable-cjs 22.0.0-canary.5 → 22.0.0-canary.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 (122) hide show
  1. package/index.css +0 -3
  2. package/index.css.map +1 -1
  3. package/package.json +1 -1
  4. package/src/AdaptableOptions/CustomSortOptions.d.ts +1 -2
  5. package/src/AdaptableState/AlertState.d.ts +6 -3
  6. package/src/AdaptableState/ChartingState.d.ts +5 -5
  7. package/src/AdaptableState/Common/AdaptableObject.d.ts +4 -9
  8. package/src/AdaptableState/Common/BaseContext.d.ts +2 -0
  9. package/src/AdaptableState/Common/ColumnHighlightInfo.d.ts +18 -0
  10. package/src/AdaptableState/Common/ColumnHighlightInfo.js +2 -0
  11. package/src/AdaptableState/Common/NamedObject.d.ts +10 -0
  12. package/src/AdaptableState/Common/NamedObject.js +2 -0
  13. package/src/AdaptableState/Common/RowSummary.d.ts +1 -1
  14. package/src/AdaptableState/Common/Schedule.d.ts +7 -3
  15. package/src/AdaptableState/Common/SuspendableObject.d.ts +10 -0
  16. package/src/AdaptableState/Common/SuspendableObject.js +2 -0
  17. package/src/AdaptableState/CustomSortState.d.ts +6 -2
  18. package/src/AdaptableState/DashboardState.d.ts +3 -3
  19. package/src/AdaptableState/ExportState.d.ts +3 -3
  20. package/src/AdaptableState/FlashingCellState.d.ts +6 -2
  21. package/src/AdaptableState/FormatColumnState.d.ts +6 -2
  22. package/src/AdaptableState/InternalState.d.ts +2 -0
  23. package/src/AdaptableState/LayoutState.d.ts +3 -3
  24. package/src/AdaptableState/NamedQueryState.d.ts +3 -3
  25. package/src/AdaptableState/PlusMinusState.d.ts +6 -2
  26. package/src/AdaptableState/ShortcutState.d.ts +6 -2
  27. package/src/AdaptableState/StyledColumnState.d.ts +1 -1
  28. package/src/AdaptableState/ThemeState.d.ts +3 -3
  29. package/src/Api/AlertApi.d.ts +6 -0
  30. package/src/Api/CustomSortApi.d.ts +6 -0
  31. package/src/Api/FlashingCellApi.d.ts +6 -0
  32. package/src/Api/FormatColumnApi.d.ts +10 -4
  33. package/src/Api/GridApi.d.ts +18 -3
  34. package/src/Api/Implementation/AlertApiImpl.d.ts +1 -0
  35. package/src/Api/Implementation/AlertApiImpl.js +3 -0
  36. package/src/Api/Implementation/ChartingApiImpl.js +2 -2
  37. package/src/Api/Implementation/CustomSortApiImpl.d.ts +1 -0
  38. package/src/Api/Implementation/CustomSortApiImpl.js +3 -0
  39. package/src/Api/Implementation/FlashingCellApiImpl.d.ts +1 -0
  40. package/src/Api/Implementation/FlashingCellApiImpl.js +3 -0
  41. package/src/Api/Implementation/FormatColumnApiImpl.d.ts +6 -5
  42. package/src/Api/Implementation/FormatColumnApiImpl.js +6 -5
  43. package/src/Api/Implementation/GridApiImpl.d.ts +4 -0
  44. package/src/Api/Implementation/GridApiImpl.js +14 -0
  45. package/src/Api/Implementation/LayoutApiImpl.js +1 -1
  46. package/src/Api/Implementation/NamedQueryApiImpl.js +2 -2
  47. package/src/Api/Implementation/PlusMinusApiImpl.d.ts +1 -0
  48. package/src/Api/Implementation/PlusMinusApiImpl.js +3 -0
  49. package/src/Api/Implementation/ScheduleApiImpl.d.ts +1 -0
  50. package/src/Api/Implementation/ScheduleApiImpl.js +3 -0
  51. package/src/Api/Implementation/ShortcutApiImpl.d.ts +1 -0
  52. package/src/Api/Implementation/ShortcutApiImpl.js +3 -0
  53. package/src/Api/Implementation/SystemStatusApiImpl.js +4 -4
  54. package/src/Api/Internal/CalculatedColumnInternalApi.js +2 -2
  55. package/src/Api/Internal/FreeTextColumnInternalApi.js +2 -2
  56. package/src/Api/Internal/LayoutInternalApi.js +1 -1
  57. package/src/Api/Internal/NamedQueryInternalApi.js +4 -4
  58. package/src/Api/PlusMinusApi.d.ts +6 -0
  59. package/src/Api/ScheduleApi.d.ts +6 -0
  60. package/src/Api/ShortcutApi.d.ts +6 -0
  61. package/src/Redux/ActionsReducers/FormatColumnRedux.d.ts +8 -0
  62. package/src/Redux/ActionsReducers/FormatColumnRedux.js +17 -1
  63. package/src/Redux/ActionsReducers/InternalRedux.d.ts +15 -0
  64. package/src/Redux/ActionsReducers/InternalRedux.js +42 -3
  65. package/src/Redux/Store/AdaptableStore.js +39 -16
  66. package/src/Strategy/BulkUpdateModule.js +8 -8
  67. package/src/Strategy/PlusMinusModule.js +1 -1
  68. package/src/Strategy/QuickSearchModule.js +1 -1
  69. package/src/Strategy/SettingsPanelModule.js +11 -7
  70. package/src/Strategy/SmartEditModule.js +10 -10
  71. package/src/Utilities/Services/DataService.js +1 -1
  72. package/src/Utilities/Services/Fdc3Service.js +4 -4
  73. package/src/Utilities/Services/ModuleService.js +1 -3
  74. package/src/Utilities/Services/ThemeService.js +2 -6
  75. package/src/Utilities/Services/ValidationService.js +1 -1
  76. package/src/Utilities/logDeprecation.js +3 -4
  77. package/src/View/Alert/Utilities/getDefaultAlertDefinition.d.ts +2 -2
  78. package/src/View/Alert/Wizard/isValidAlertRules.js +1 -1
  79. package/src/View/CalculatedColumn/Wizard/CalculatedColumnDefinitionWizardSection.js +2 -2
  80. package/src/View/CalculatedColumn/Wizard/CalculatedColumnExpressionWizardSection.js +2 -2
  81. package/src/View/CalculatedColumn/Wizard/CalculatedColumnSettingsWizardSection.js +1 -1
  82. package/src/View/Charting/ChartingWizard/AgChargingWizard/SettingsSection.js +2 -2
  83. package/src/View/Charting/ChartingWizard/ExternalChartingWizard/SettingsSection.js +2 -2
  84. package/src/View/Components/CellPopup/index.js +1 -1
  85. package/src/View/Components/ColumnFilter/FloatingFilter.js +41 -3
  86. package/src/View/Components/ColumnFilter/components/ColumnFilterMenu.js +54 -2
  87. package/src/View/Components/EntityRulesEditor/Utilities.js +5 -5
  88. package/src/View/Components/NewScopeComponent.js +3 -3
  89. package/src/View/Components/Popups/AdaptablePopupConfirmation.js +1 -1
  90. package/src/View/CustomSort/Wizard/CustomSortColumnWizardSection.js +3 -3
  91. package/src/View/CustomSort/Wizard/CustomSortValuesWizardSection.js +1 -1
  92. package/src/View/FlashingCell/Wizard/isValidFlashingCellRules.js +1 -1
  93. package/src/View/FreeTextColumn/Wizard/FreeTextColumnSettingsWizardSection.d.ts +1 -1
  94. package/src/View/FreeTextColumn/Wizard/FreeTextColumnSettingsWizardSection.js +3 -3
  95. package/src/View/Layout/LayoutViewPanel.js +1 -1
  96. package/src/View/Layout/Wizard/sections/AggregationsSection.js +1 -1
  97. package/src/View/Layout/Wizard/sections/FilterSection.js +1 -1
  98. package/src/View/Layout/Wizard/sections/GridFilterSection.js +1 -1
  99. package/src/View/Layout/Wizard/sections/PivotAggregationsSection.js +3 -3
  100. package/src/View/Layout/Wizard/sections/RowSummarySection.js +1 -1
  101. package/src/View/NamedQuery/Wizard/NamedQueryExpressionWizardSection.js +2 -2
  102. package/src/View/PlusMinus/Wizard/PlusMinusSettingsWizardSection.js +5 -5
  103. package/src/View/Schedule/Wizard/ScheduleSettingsWizard/isSettingsValid.d.ts +1 -1
  104. package/src/View/Schedule/Wizard/ScheduleSettingsWizard/isSettingsValid.js +11 -11
  105. package/src/View/StateManagement/handleExportState.js +1 -1
  106. package/src/View/StyledColumn/Wizard/StyledColumnWizardColumnSection.js +1 -1
  107. package/src/agGrid/AdaptableAgGrid.js +47 -51
  108. package/src/agGrid/AgGridAdapter.js +8 -8
  109. package/src/agGrid/AgGridColumnAdapter.d.ts +1 -0
  110. package/src/agGrid/AgGridColumnAdapter.js +15 -4
  111. package/src/agGrid/AgGridExportAdapter.js +5 -5
  112. package/src/agGrid/AgGridThemeAdapter.js +2 -2
  113. package/src/components/OverlayTrigger/index.js +1 -1
  114. package/src/components/Select/Select.js +77 -14
  115. package/src/env.js +2 -2
  116. package/src/metamodel/adaptable.metamodel.d.ts +25 -18
  117. package/src/metamodel/adaptable.metamodel.js +1 -1
  118. package/src/migration/AdaptableUpgradeHelper.js +2 -2
  119. package/src/migration/VersionUpgrade17.js +4 -4
  120. package/src/migration/VersionUpgrade20.js +4 -4
  121. package/src/types.d.ts +2 -2
  122. package/tsconfig.cjs.tsbuildinfo +1 -1
@@ -73,15 +73,11 @@ class ThemeService {
73
73
  return val;
74
74
  });
75
75
  if (abLoaded !== '777') {
76
- logger.consoleError('Please import Adaptable styles from "@adaptabletools/adaptable/index.css"');
76
+ logger.consoleError('Adaptable styles not detected. Please import "@adaptabletools/adaptable/index.css".');
77
77
  }
78
78
  const isCustomUserTheme = !this.api.themeApi.internalApi.isSystemTheme(themeName);
79
79
  if (!isCustomUserTheme && abThemeLoaded !== themeName) {
80
- logger.consoleWarn(`Theme "${themeName}" doesn't seem to be loaded! Make sure you import the css file for the "${themeName}" theme!
81
-
82
- If it's an AdapTable system theme, try
83
-
84
- import "@adaptabletools/adaptable/themes/${themeName}.css"`);
80
+ logger.consoleWarn(`Theme "${themeName}" does not appear to be loaded. Ensure the CSS file is imported, e.g.: import "@adaptabletools/adaptable/themes/${themeName}.css".`);
85
81
  }
86
82
  }
87
83
  // prefers-color-scheme
@@ -57,7 +57,7 @@ class ValidationService {
57
57
  let alert = {
58
58
  alertType: 'cellChanged',
59
59
  header: 'Alert',
60
- message: 'Perform Edit Alert Fired',
60
+ message: 'A validation rule was triggered for this edit.',
61
61
  alertDefinition: failedRules[0],
62
62
  cellDataChangedInfo: cellDataChangedInfo,
63
63
  };
@@ -14,16 +14,15 @@ const doOnce = (func, key) => {
14
14
  };
15
15
  const logDeprecation = (logger, typeName, oldProp, newProp, message) => {
16
16
  const newPropMsg = newProp ? `Please use '${typeName}.${newProp}()' instead. ` : '';
17
- doOnce(() => logger.consoleWarn(`'${typeName}.${oldProp}()' is deprecated. ${newPropMsg}${message ?? ''}`), `Deprecated_${oldProp}`);
17
+ doOnce(() => logger.consoleWarn(`${typeName}.${oldProp}() is deprecated. ${newPropMsg}${message ?? ''}`), `Deprecated_${oldProp}`);
18
18
  };
19
19
  exports.logDeprecation = logDeprecation;
20
20
  const logDeprecationExternal = (logger, oldTypeName, oldProp, newTypeName, newProp, message) => {
21
21
  const newPropMsg = newProp ? `Please use '${newTypeName}.${newProp}()' instead. ` : '';
22
- doOnce(() => logger.consoleWarn(`'${oldTypeName}.${oldProp}()' is deprecated. ${newPropMsg}${message ?? ''}`), `Deprecated_${oldProp}`);
22
+ doOnce(() => logger.consoleWarn(`${oldTypeName}.${oldProp}() is deprecated. ${newPropMsg}${message ?? ''}`), `Deprecated_${oldProp}`);
23
23
  };
24
24
  exports.logDeprecationExternal = logDeprecationExternal;
25
25
  const logDeprecationInternal = (logger, typeName, oldProp) => {
26
- doOnce(() => logger.consoleWarn(`'${typeName}.${oldProp}()' is deprecated. The method will be removed in the next major release.
27
- Please contact support if you need the missing functionality.`), `Deprecated_${oldProp}`);
26
+ doOnce(() => logger.consoleWarn(`${typeName}.${oldProp}() is deprecated and will be removed in the next major release. Contact support if you need this functionality.`), `Deprecated_${oldProp}`);
28
27
  };
29
28
  exports.logDeprecationInternal = logDeprecationInternal;
@@ -6,6 +6,7 @@ import { AlertType } from './getAlertType';
6
6
  */
7
7
  export declare const getDefaultAlertDefinition: (alertDefinition: AlertDefinition, type: AlertType) => {
8
8
  Uuid: string;
9
+ Name: string;
9
10
  Scope: import("../../../types").ColumnScope;
10
11
  Rule: import("../../../types").AlertRule;
11
12
  MessageType: import("../../../types").AdaptableMessageType;
@@ -13,11 +14,10 @@ export declare const getDefaultAlertDefinition: (alertDefinition: AlertDefinitio
13
14
  MessageText?: string;
14
15
  AlertProperties?: import("../../../types").AlertProperties;
15
16
  AlertForm?: string | import("../../../types").AlertButtonForm;
16
- Name: string;
17
+ IsSuspended?: boolean;
17
18
  Source?: "InitialState" | "User";
18
19
  AdaptableVersion?: import("../../../types").AdaptableVersion;
19
20
  IsReadOnly?: boolean;
20
21
  Tags?: import("../../../types").AdaptableObjectTag[];
21
22
  Metadata?: any;
22
- IsSuspended?: boolean;
23
23
  };
@@ -7,7 +7,7 @@ const isValidAlertRules = (alert, api, context) => {
7
7
  !alert.Rule.BooleanExpression &&
8
8
  !alert.Rule.ObservableExpression &&
9
9
  !alert.Rule.AggregatedBooleanExpression) {
10
- return 'No Rule defined for Alert';
10
+ return 'A rule is required for the Alert.';
11
11
  }
12
12
  const isRuleValid = (0, Utilities_1.isAdaptableRuleValid)(alert, api, context);
13
13
  if (typeof isRuleValid === 'string') {
@@ -26,11 +26,11 @@ exports.renderCalculatedColumnDefinitionSummary = renderCalculatedColumnDefiniti
26
26
  const isValidCalculatedColumnDefinition = (data, api) => {
27
27
  const columns = api.columnApi.getColumns();
28
28
  if (!data.ColumnId) {
29
- return 'Column Id cannot be empty';
29
+ return 'A Column ID is required.';
30
30
  }
31
31
  const columnsWithSameIdCount = columns.filter((c) => c.columnId === data.ColumnId).length;
32
32
  const hasAlreadyExistingId = data.Uuid ? columnsWithSameIdCount > 1 : columnsWithSameIdCount > 0;
33
- return hasAlreadyExistingId ? 'A Column already exists with that id' : true;
33
+ return hasAlreadyExistingId ? 'A column with this ID already exists.' : true;
34
34
  };
35
35
  exports.isValidCalculatedColumnDefinition = isValidCalculatedColumnDefinition;
36
36
  const CalculatedColumnDefinitionWizardSection = (props) => {
@@ -22,11 +22,11 @@ const isValidCalculatedColumnExpression = (data, api) => {
22
22
  const calculatedColumnExpressionService = api.internalApi.getCalculatedColumnExpressionService();
23
23
  const expression = api.expressionApi.getAdaptableQueryExpression(data.Query)?.trim();
24
24
  if (!expression) {
25
- return 'Calculated Column Expression cannot be empty';
25
+ return 'An expression is required for the Calculated Column.';
26
26
  }
27
27
  const isValid = calculatedColumnExpressionService.isCalculatedColumnQueryValid(data.Query);
28
28
  if (!isValid) {
29
- return 'Calculated Column Expression is not valid';
29
+ return 'The Calculated Column expression is not valid.';
30
30
  }
31
31
  return true;
32
32
  };
@@ -21,7 +21,7 @@ const renderCalculatedColumnSettingsSummary = (data) => {
21
21
  exports.renderCalculatedColumnSettingsSummary = renderCalculatedColumnSettingsSummary;
22
22
  const isValidCalculatedColumnSettings = (data) => {
23
23
  if (!data.CalculatedColumnSettings?.DataType) {
24
- return 'No data type is specified and it could not be inferred from the defined expression';
24
+ return 'A data type is required. It could not be inferred from the expression.';
25
25
  }
26
26
  return true;
27
27
  };
@@ -9,12 +9,12 @@ const FormLayout_1 = tslib_1.__importStar(require("../../../../components/FormLa
9
9
  const AdaptableInput_1 = tslib_1.__importDefault(require("../../../Components/AdaptableInput"));
10
10
  const isSettingsValid = (chartDefinition, api) => {
11
11
  if (!chartDefinition.Name) {
12
- return 'Name is mandatory';
12
+ return 'A name is required.';
13
13
  }
14
14
  const allChartDefinitions = api.chartingApi.getChartDefinitions();
15
15
  if (allChartDefinitions.some((chartDefinitionLoopItem) => chartDefinitionLoopItem.Uuid !== chartDefinition.Uuid &&
16
16
  chartDefinitionLoopItem.Name === chartDefinition.Name)) {
17
- return 'There is already a chart with this name';
17
+ return 'A Chart with this name already exists.';
18
18
  }
19
19
  return true;
20
20
  };
@@ -7,12 +7,12 @@ const FormLayout_1 = tslib_1.__importStar(require("../../../../components/FormLa
7
7
  const AdaptableInput_1 = tslib_1.__importDefault(require("../../../Components/AdaptableInput"));
8
8
  const isSettingsValid = (chartDefinition, api) => {
9
9
  if (!chartDefinition.Name) {
10
- return 'Name is mandatory';
10
+ return 'A name is required.';
11
11
  }
12
12
  const allChartDefinitions = api.chartingApi.getExternalChartDefinitions();
13
13
  if (allChartDefinitions.some((chartDefinitionLoopItem) => chartDefinitionLoopItem.Uuid !== chartDefinition.Uuid &&
14
14
  chartDefinitionLoopItem.Name === chartDefinition.Name)) {
15
- return 'There is already a chart with this name';
15
+ return 'A Chart with this name already exists.';
16
16
  }
17
17
  return true;
18
18
  };
@@ -36,7 +36,7 @@ exports.CellPopup = React.forwardRef((props, ref) => {
36
36
  const cellSelector = `[row-id="${props.primaryKeyValue}"] [col-id="${props.columnId}"]`;
37
37
  const alignTo = document.querySelector(cellSelector);
38
38
  if (!alignTo) {
39
- adaptable.logger.consoleError(`Could not find cell with selector ${cellSelector} to show popup`);
39
+ adaptable.logger.consoleError(`Cell not found for selector "${cellSelector}". Unable to display popup.`);
40
40
  return;
41
41
  }
42
42
  const showOverlayOptions = {
@@ -41,11 +41,19 @@ const FloatingFilter = (props) => {
41
41
  const handleClear = () => props.onClear?.();
42
42
  const showEvent = 'click';
43
43
  const hideEvent = 'blur';
44
+ const [overlayVisible, setOverlayVisible] = React.useState(false);
44
45
  let filterDropdown = null;
45
- let filterDropdownButton = (React.createElement(SimpleButton_1.default, { variant: "text", "data-name": "floating-filter-button", "data-value": props.predicate?.args[0]?.operator, onClick: () => {
46
+ const filterDropdownButton = (React.createElement(SimpleButton_1.default, { variant: "text", "data-name": "floating-filter-button", onBlur: () => {
47
+ if (isInlineEditable) {
48
+ setOverlayVisible(false);
49
+ }
50
+ }, "data-value": props.predicate?.args[0]?.operator, onClick: () => {
46
51
  if (!isInlineEditable) {
47
52
  adaptable.api.filterApi.columnFilterApi.internalApi.openColumnFilterPopup(props.columnId);
48
53
  }
54
+ else {
55
+ setOverlayVisible(true);
56
+ }
49
57
  }, style: {
50
58
  textAlign: 'left',
51
59
  marginRight: 1, // just so that the focus outline is not cut off
@@ -59,9 +67,10 @@ const FloatingFilter = (props) => {
59
67
  React.createElement(Flex_1.Box, null, !isManualApply && singleFilterPredicateDef?.icon ? (singleFilterPredicateDef?.icon) : (React.createElement(AdaptableIconComponent_1.AdaptableIconComponent, { icon: { name: 'filter' } }))),
60
68
  showLabel && (React.createElement(Flex_1.Box, { className: "ab-FloatingFilter-label twa:ml-2 twa:flex-1", title: label }, label))));
61
69
  if (isInlineEditable) {
62
- filterDropdown = showQuickFilterDropdown && (React.createElement(OverlayTrigger_1.default, { className: "ab-FloatingFilter-overlay", showEvent: showEvent, hideEvent: hideEvent, preventPortalEventPropagation: showEvent === 'click', targetOffset: 10, hideDelay: 50, "data-name": "floating-filter-overlay", render: () => {
70
+ filterDropdown = showQuickFilterDropdown && (React.createElement(OverlayTrigger_1.default, { className: "ab-FloatingFilter-overlay", showEvent: showEvent, hideEvent: hideEvent, visible: overlayVisible, onVisibleChange: setOverlayVisible, preventPortalEventPropagation: showEvent === 'click', targetOffset: 10, hideDelay: 50, "data-name": "floating-filter-overlay", render: () => {
63
71
  // we render this only for single filter
64
72
  return (React.createElement(ColumnFilterMenu_1.ColumnFilterMenu, { columnId: props.columnId, disabled: props.disabled, predicate: props.predicate.args[0], predicateDefs: props.predicateDefs, onPredicateChange: (predicate) => {
73
+ setOverlayVisible(false);
65
74
  props.onPredicateChange({
66
75
  operator: props.predicate.operator,
67
76
  args: [predicate],
@@ -72,7 +81,36 @@ const FloatingFilter = (props) => {
72
81
  else {
73
82
  filterDropdown = filterDropdownButton;
74
83
  }
75
- return (React.createElement(Flex_1.Flex, { className: "ab-FloatingFilter twa:w-full" },
84
+ return (React.createElement(Flex_1.Flex, { className: "ab-FloatingFilter twa:w-full", onKeyDownCapture: (e) => {
85
+ // AG Grid's header keyboard navigation intercepts Tab and calls preventDefault(),
86
+ // which prevents focus from moving between elements inside the floating filter.
87
+ // We handle Tab manually in the capture phase (before AG Grid's handlers).
88
+ if (e.key === 'Tab') {
89
+ const target = e.target;
90
+ const wrapper = e.currentTarget;
91
+ if (!e.shiftKey) {
92
+ // Tab forward: from filter button → select input
93
+ if (target.getAttribute('data-name') === 'floating-filter-button') {
94
+ const selectInput = wrapper.querySelector('[data-name="Select Values"] input');
95
+ if (selectInput) {
96
+ e.preventDefault();
97
+ e.nativeEvent.stopImmediatePropagation();
98
+ selectInput.focus();
99
+ // When the DummyInput gets focus, react-select sets isFocused=true,
100
+ // triggering a React re-render. During this re-render, unstable component
101
+ // references in selectComponents can cause the DummyInput to be removed
102
+ // from DOM and recreated, losing focus. We restore focus after the re-render.
103
+ requestAnimationFrame(() => {
104
+ if (document.activeElement === document.body || document.activeElement === null) {
105
+ const newInput = wrapper.querySelector('[data-name="Select Values"] input');
106
+ newInput?.focus();
107
+ }
108
+ });
109
+ }
110
+ }
111
+ }
112
+ }
113
+ } },
76
114
  filterDropdown,
77
115
  isInlineEditable && (React.createElement(Flex_1.Flex, { className: "twa:flex-1 twa:min-w-0" },
78
116
  React.createElement(FloatingFilterInputList_1.FloatingFilterInputList, { onKeyDown: props.onKeydown, columnId: props.columnId, disabled: props.disabled,
@@ -6,17 +6,69 @@ const React = tslib_1.__importStar(require("react"));
6
6
  const Panel_1 = tslib_1.__importDefault(require("../../../../components/Panel"));
7
7
  const SimpleButton_1 = tslib_1.__importDefault(require("../../../../components/SimpleButton"));
8
8
  const Flex_1 = require("../../../../components/Flex");
9
+ const clsx_1 = tslib_1.__importDefault(require("clsx"));
10
+ const react_1 = require("react");
9
11
  const ColumnFilterMenuItem = ({ active, onClick, icon, label, }) => {
10
12
  return (React.createElement(SimpleButton_1.default, { className: "twa:p-1 twa:w-full", variant: "text", tone: active ? 'info' : 'none', onClick: onClick },
11
13
  React.createElement(Flex_1.Box, { className: "twa:mr-2" }, icon),
12
14
  React.createElement(Flex_1.Box, { className: "twa:text-2" }, label)));
13
15
  };
14
16
  const ColumnFilterMenu = (props) => {
17
+ const [activeIndex, setActiveIndex] = React.useState(() => {
18
+ const index = props.predicateDefs.findIndex((predicateDef) => predicateDef.operator === props.predicate.operator);
19
+ return index === -1 ? 0 : index;
20
+ });
21
+ const activeIndexRef = React.useRef(activeIndex);
22
+ const onPredicateChangeRef = React.useRef(props.onPredicateChange);
23
+ const predicateDefsRef = React.useRef(props.predicateDefs);
24
+ (0, react_1.useLayoutEffect)(() => {
25
+ activeIndexRef.current = activeIndex;
26
+ onPredicateChangeRef.current = props.onPredicateChange;
27
+ predicateDefsRef.current = props.predicateDefs;
28
+ });
29
+ const confirm = React.useCallback((predicateDef) => {
30
+ onPredicateChangeRef.current({ operator: predicateDef.operator, args: [] });
31
+ }, []);
32
+ (0, react_1.useEffect)(() => {
33
+ const onKeyDown = (e) => {
34
+ // Only handle arrow keys and Enter - let other keys (like Tab) pass through
35
+ if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'Enter') {
36
+ return;
37
+ }
38
+ const activeIndex = activeIndexRef.current;
39
+ const predicateDefs = predicateDefsRef.current;
40
+ if (e.key === 'Enter') {
41
+ const predicateDef = predicateDefs[activeIndex];
42
+ if (predicateDef) {
43
+ confirm(predicateDef);
44
+ }
45
+ }
46
+ e.stopPropagation();
47
+ e.preventDefault();
48
+ const dir = e.key === 'ArrowDown' ? 1 : e.key === 'ArrowUp' ? -1 : 0;
49
+ if (dir) {
50
+ let nextIndex = activeIndex + dir;
51
+ if (nextIndex < 0) {
52
+ nextIndex = predicateDefs.length - 1;
53
+ }
54
+ else if (nextIndex >= predicateDefs.length) {
55
+ nextIndex = 0;
56
+ }
57
+ setActiveIndex(nextIndex);
58
+ }
59
+ };
60
+ document.addEventListener('keydown', onKeyDown);
61
+ return () => {
62
+ document.removeEventListener('keydown', onKeyDown);
63
+ };
64
+ }, [confirm]);
15
65
  return (React.createElement(Panel_1.default, { className: "twa:min-w-max" }, props.predicateDefs?.map((predicateDef, index) => {
16
- return (React.createElement(Flex_1.Flex, { className: "twa:mb-1", key: index, onMouseDownCapture: (e) => {
66
+ const active = activeIndex === index;
67
+ return (React.createElement(Flex_1.Flex, { className: (0, clsx_1.default)("twa:mb-1", active && "twa:bg-primarylight"), key: index, onMouseDownCapture: (e) => {
17
68
  e.stopPropagation();
69
+ e.preventDefault();
18
70
  } },
19
- React.createElement(ColumnFilterMenuItem, { onClick: () => props.onPredicateChange({ operator: predicateDef.operator, args: [] }), icon: predicateDef.icon, label: predicateDef.label, active: props.predicate.operator === predicateDef.operator })));
71
+ React.createElement(ColumnFilterMenuItem, { onClick: () => confirm(predicateDef), icon: predicateDef.icon, label: predicateDef.label, active: active })));
20
72
  })));
21
73
  };
22
74
  exports.ColumnFilterMenu = ColumnFilterMenu;
@@ -4,28 +4,28 @@ exports.isAdaptableRuleValid = void 0;
4
4
  const isAdaptableRuleValid = (abObject, api, context) => {
5
5
  if (abObject?.Rule?.Predicates?.length) {
6
6
  if (!api.predicateApi.isEveryPredicateValid(abObject?.Rule?.Predicates)) {
7
- return `The Predicate${abObject?.Rule?.Predicates?.length === 1 ? ' is' : 's are'} not valid`;
7
+ return `The predicate${abObject?.Rule?.Predicates?.length === 1 ? ' is' : 's are'} not valid.`;
8
8
  }
9
9
  }
10
10
  if (abObject?.Rule?.BooleanExpression) {
11
11
  if (!api.expressionApi.isValidBooleanExpression(abObject?.Rule?.BooleanExpression, context.moduleInfo.ModuleName)) {
12
- return 'The Expression is not a valid Boolean Expression';
12
+ return 'The Boolean expression is not valid.';
13
13
  }
14
14
  }
15
15
  if (abObject?.Rule?.ObservableExpression) {
16
16
  if (!api.expressionApi.isValidObservableExpression(abObject?.Rule?.ObservableExpression, context.moduleInfo.ModuleName)) {
17
- return 'The Expression is not a valid Observable Expression';
17
+ return 'The Observable expression is not valid.';
18
18
  }
19
19
  }
20
20
  if (abObject?.Rule?.AggregatedBooleanExpression) {
21
21
  if (!api.expressionApi.isValidAggregatedBooleanExpression(abObject?.Rule?.AggregatedBooleanExpression, context.moduleInfo.ModuleName)) {
22
- return 'The Expression is not a valid Aggregated Boolean Expression';
22
+ return 'The Aggregated Boolean expression is not valid.';
23
23
  }
24
24
  }
25
25
  if (abObject?.Rule?.Predicates?.length) {
26
26
  const isAPredicateWithInvalidColumnId = abObject?.Rule?.Predicates?.some((predicate) => predicate.ColumnId !== undefined && predicate.ColumnId === '');
27
27
  if (isAPredicateWithInvalidColumnId) {
28
- return 'Predicates with custom scope need a valid column';
28
+ return 'Predicates with a custom scope require a valid column.';
29
29
  }
30
30
  }
31
31
  return true;
@@ -18,13 +18,13 @@ const Tag_1 = require("../../components/Tag/Tag");
18
18
  const isScopeValid = ({ Scope }) => {
19
19
  const result = [];
20
20
  if (!Scope) {
21
- return 'No scope specified or scope is empty';
21
+ return 'A scope is required.';
22
22
  }
23
23
  if (Scope && 'ColumnIds' in Scope && Scope.ColumnIds.length === 0) {
24
- result.push('No Columns selected in Scope');
24
+ result.push('Please select at least one column for the scope.');
25
25
  }
26
26
  if (Scope && 'DataTypes' in Scope && Scope.DataTypes.length === 0) {
27
- result.push('No Data Types selected in Scope');
27
+ result.push('Please select at least one data type for the scope.');
28
28
  }
29
29
  return result.length ? result.join(', ') : true;
30
30
  };
@@ -55,7 +55,7 @@ const AdaptablePopupConfirmation = (props) => {
55
55
  setDisableDeleteConfirmation(!disableDeleteConfirmation);
56
56
  } }, "Do not show this again")),
57
57
  props.showInputBox && (React.createElement(Flex_1.Box, { className: "twa:p-2", "data-name": "body" },
58
- React.createElement("p", null, "Please enter a comment to confirm"),
58
+ React.createElement("p", null, "Please enter a comment to confirm."),
59
59
  React.createElement(Input_1.default, { className: "twa:mt-2 twa:w-full", value: promptText, type: "string", placeholder: "Enter text", onChange: (e) => changeContent(e) }))),
60
60
  React.createElement(Flex_1.Flex, { className: "twa:mt-3 twa:p-2", "data-name": "footer", justifyContent: "space-between" },
61
61
  props.cancelButtonText != null ? (React.createElement(SimpleButton_1.default, { "data-name": "cancel", tone: "neutral", variant: "raised", onClick: () => onCancelForm() }, props.cancelButtonText)) : (React.createElement("div", null)),
@@ -23,13 +23,13 @@ const renderCustomSortColumn = (data) => {
23
23
  exports.renderCustomSortColumn = renderCustomSortColumn;
24
24
  const isValidCustomSortColumn = (data, allCustomSorts) => {
25
25
  if (!data.Name) {
26
- return 'Custom Sort Name cannot be blank';
26
+ return 'A name is required.';
27
27
  }
28
28
  if (allCustomSorts.some((customSort) => customSort.Name === data.Name && customSort.Uuid !== data.Uuid)) {
29
- return 'A Custom Sort already exists with that name';
29
+ return 'A Custom Sort with this name already exists.';
30
30
  }
31
31
  if (!data.ColumnId) {
32
- return 'You have to select a Column for Custom Sort';
32
+ return 'Please select a column for the Custom Sort.';
33
33
  }
34
34
  return true;
35
35
  };
@@ -15,7 +15,7 @@ const DateHelper_1 = require("../../../Utilities/Helpers/DateHelper");
15
15
  const Tag_1 = require("../../../components/Tag");
16
16
  const isValidCustomSortOrder = (data) => {
17
17
  if (!data.SortedValues || !data.SortedValues.length) {
18
- return 'You have to specify at least one value for Custom Sort order';
18
+ return 'At least one value is required for the Custom Sort order.';
19
19
  }
20
20
  return true;
21
21
  };
@@ -4,7 +4,7 @@ exports.isValidFlashingCellRules = void 0;
4
4
  const Utilities_1 = require("../../Components/EntityRulesEditor/Utilities");
5
5
  const isValidFlashingCellRules = (flashingCell, api, context) => {
6
6
  if (!flashingCell.Rule?.Predicates?.length && !flashingCell.Rule.BooleanExpression) {
7
- return 'No Rule defined for Flashing Cell';
7
+ return 'A rule is required for the Flashing Cell.';
8
8
  }
9
9
  const isRuleValid = (0, Utilities_1.isAdaptableRuleValid)(flashingCell, api, context);
10
10
  if (typeof isRuleValid === 'string') {
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import { FreeTextColumn } from '../../../AdaptableState/FreeTextColumnState';
3
3
  import { AdaptableApi } from '../../../Api/AdaptableApi';
4
4
  export declare const renderFreeTextColumnSummary: (data: FreeTextColumn) => React.JSX.Element;
5
- export declare const isValidFreeTextColumn: (data: FreeTextColumn, api: AdaptableApi) => true | "Column Id cannot be empty" | "A Column already exists with that id" | "No data type specified for column";
5
+ export declare const isValidFreeTextColumn: (data: FreeTextColumn, api: AdaptableApi) => true | "A Column ID is required." | "A column with this ID already exists." | "A data type is required for the column.";
6
6
  export type FreeTextColumnSettingsWizardSectionProps = {
7
7
  onChange: (data: FreeTextColumn) => void;
8
8
  isEdit: boolean;
@@ -45,15 +45,15 @@ exports.renderFreeTextColumnSummary = renderFreeTextColumnSummary;
45
45
  const isValidFreeTextColumn = (data, api) => {
46
46
  const columns = api.columnApi.getUIAvailableColumns();
47
47
  if (!data.ColumnId) {
48
- return 'Column Id cannot be empty';
48
+ return 'A Column ID is required.';
49
49
  }
50
50
  const columnsWithSameIdCount = columns.filter((c) => c.columnId === data.ColumnId).length;
51
51
  const hasAlreadyExistingId = data.Uuid ? columnsWithSameIdCount > 1 : columnsWithSameIdCount > 0;
52
52
  if (hasAlreadyExistingId) {
53
- return 'A Column already exists with that id';
53
+ return 'A column with this ID already exists.';
54
54
  }
55
55
  if (!data.FreeTextColumnSettings.DataType) {
56
- return 'No data type specified for column';
56
+ return 'A data type is required for the column.';
57
57
  }
58
58
  return true;
59
59
  };
@@ -83,7 +83,7 @@ function mapDispatchToProps(dispatch) {
83
83
  showMissingLayoutsError: () => {
84
84
  dispatch(PopupRedux.PopupShowConfirmation({
85
85
  Header: 'Missing Layouts',
86
- Msg: 'You have not defined any Layout! See the console for more details.',
86
+ Msg: 'No Layouts have been defined. Please check the console for details.',
87
87
  ConfirmAction: null,
88
88
  ConfirmButtonText: 'OK',
89
89
  CancelButtonText: null,
@@ -23,7 +23,7 @@ const isAggregationsSectionValid = (data) => {
23
23
  AggFunc.type === 'weightedAverage')?.AggFunc
24
24
  : null;
25
25
  if (weightedAvg && !weightedAvg.weightedColumnId) {
26
- return 'The Weighted Average Aggregation requires a Weighted Column';
26
+ return 'Weighted Average requires a weight column to be selected.';
27
27
  }
28
28
  return true;
29
29
  };
@@ -17,7 +17,7 @@ const Flex_1 = require("../../../../components/Flex");
17
17
  const isColumnFiltersValid = (layout) => {
18
18
  const invalidColumnFilters = (layout.ColumnFilters ?? [])?.filter((columnFilter) => !columnFilter?.Predicates[0]?.PredicateId);
19
19
  if (invalidColumnFilters.length > 0) {
20
- return 'Please select a Predicate for each Column Filter';
20
+ return 'Please select a predicate for each column filter.';
21
21
  }
22
22
  return true;
23
23
  };
@@ -17,7 +17,7 @@ const isGridFiltersValid = (layout, api) => {
17
17
  return true;
18
18
  }
19
19
  return (api.internalApi.getQueryLanguageService().validateBoolean(expression, ModuleConstants_1.GridFilterModuleId)
20
- .isValid || 'Invalid Expression');
20
+ .isValid || 'The expression is not valid.');
21
21
  };
22
22
  exports.isGridFiltersValid = isGridFiltersValid;
23
23
  const GridFilterSectionSummary = () => {
@@ -220,7 +220,7 @@ const isPivotAggregationsSectionValid = (data) => {
220
220
  .find((agg) => typeof agg === 'object' && agg.type === 'weightedAverage')
221
221
  : null;
222
222
  if (weightedAvg && !weightedAvg.weightedColumnId) {
223
- return 'The Weighted Average Aggregation requires a Weighted Column';
223
+ return 'Weighted Average requires a weight column to be selected.';
224
224
  }
225
225
  return true;
226
226
  };
@@ -309,12 +309,12 @@ const PivotAggregationsSection = (props) => {
309
309
  }
310
310
  const firstAggFuncName = (0, AggregationColumns_1.getAggFuncName)(aggregationColumns[0].AggFunc);
311
311
  if (layout.PivotAggregationColumns?.some((aggCol) => (0, AggregationColumns_1.getAggFuncName)(aggCol.AggFunc) !== firstAggFuncName)) {
312
- return 'Requires identical aggregation on all columns';
312
+ return 'All columns must use the same aggregation function.';
313
313
  }
314
314
  // check that no Aggregation Total Column is enabled
315
315
  const hasAggregationTotalColumn = aggregationColumns.some((aggCol) => aggCol.Total !== false && aggCol.Total != null);
316
316
  if (hasAggregationTotalColumn) {
317
- return 'Can only be enabled when no Aggregation Total Column is present';
317
+ return 'This option is not available when an Aggregation Total Column is present.';
318
318
  }
319
319
  return true;
320
320
  };
@@ -28,7 +28,7 @@ const areSummaryRowsValid = (layout) => {
28
28
  layout.RowSummaries?.find((rowSummary) => {
29
29
  for (const [_, fn] of Object.entries(rowSummary.ColumnsMap ?? {})) {
30
30
  if (!fn) {
31
- valid = 'All row summary columns must have an aggregation function.';
31
+ valid = 'Each row summary column requires an aggregation function.';
32
32
  return true;
33
33
  }
34
34
  }
@@ -11,11 +11,11 @@ const OnePageAdaptableWizard_1 = require("../../Wizard/OnePageAdaptableWizard");
11
11
  const Flex_1 = require("../../../components/Flex");
12
12
  const isValidNamedQueryExpression = (data, api) => {
13
13
  if (!data.BooleanExpression) {
14
- return 'Expression is empty';
14
+ return 'An expression is required.';
15
15
  }
16
16
  const valid = api.expressionApi.isValidBooleanExpression(data.BooleanExpression, ModuleConstants_1.NamedQueryModuleId);
17
17
  if (!valid) {
18
- return 'Query is not a valid Boolean Query';
18
+ return 'The query is not a valid Boolean expression.';
19
19
  }
20
20
  return valid;
21
21
  };
@@ -29,16 +29,16 @@ const PlusMinusSettingsSummary = (props) => {
29
29
  exports.PlusMinusSettingsSummary = PlusMinusSettingsSummary;
30
30
  const isSettingsValid = (hasCondition) => (data, api, context) => {
31
31
  if (!data.Name?.trim()) {
32
- return 'Name is required';
32
+ return 'A name is required.';
33
33
  }
34
34
  const allPlusMinusNudges = api.plusMinusApi.getAllPlusMinus();
35
35
  const isDuplicateName = allPlusMinusNudges.some((nudge) => nudge.Name === data.Name && nudge.Uuid !== data.Uuid);
36
36
  if (isDuplicateName) {
37
- return 'A Plus Minus Nudge already exists with that name';
37
+ return 'A Plus/Minus Nudge with this name already exists.';
38
38
  }
39
39
  if (hasCondition) {
40
40
  if (!data?.Rule?.BooleanExpression) {
41
- return 'No valid Rule is specified';
41
+ return 'A valid rule is required.';
42
42
  }
43
43
  const ruleValidation = (0, Utilities_1.isAdaptableRuleValid)(data, api, context);
44
44
  if (typeof ruleValidation === 'string') {
@@ -46,10 +46,10 @@ const isSettingsValid = (hasCondition) => (data, api, context) => {
46
46
  }
47
47
  }
48
48
  if (typeof data.NudgeValue !== 'number') {
49
- return 'Nudge value is not specified';
49
+ return 'A nudge value is required.';
50
50
  }
51
51
  if (data.NudgeValue === 0) {
52
- return 'Nudge value must be different than 0';
52
+ return 'Nudge value must not be zero.';
53
53
  }
54
54
  return true;
55
55
  };
@@ -1,3 +1,3 @@
1
1
  import { AdaptableApi } from '../../../../Api/AdaptableApi';
2
2
  import { BaseSchedule } from '../../../../AdaptableState/Common/Schedule';
3
- export declare const isSettingsValid: (schedule: BaseSchedule, api: AdaptableApi) => true | "Name is required" | "A Schedule with this name already exists" | "Message type not selected" | "Reminder header not specified" | "Reminder message not specified" | "Report source not specified" | "Report format not selected" | "Report not selected" | "Report folder not selected" | "Report page not selected";
3
+ export declare const isSettingsValid: (schedule: BaseSchedule, api: AdaptableApi) => true | "A name is required." | "A Schedule with this name already exists." | "Please select a message type." | "A reminder header is required." | "A reminder message is required." | "Please select a report." | "Please select a report format." | "Please select a report folder." | "Please select a report page.";