@adaptabletools/adaptable 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.
- package/index.css +0 -3
- package/index.css.map +1 -1
- package/package.json +1 -1
- package/src/AdaptableOptions/CustomSortOptions.d.ts +1 -2
- package/src/AdaptableState/AlertState.d.ts +6 -3
- package/src/AdaptableState/ChartingState.d.ts +5 -5
- package/src/AdaptableState/Common/AdaptableObject.d.ts +4 -9
- package/src/AdaptableState/Common/BaseContext.d.ts +2 -0
- package/src/AdaptableState/Common/ColumnHighlightInfo.d.ts +18 -0
- package/src/AdaptableState/Common/ColumnHighlightInfo.js +1 -0
- package/src/AdaptableState/Common/NamedObject.d.ts +10 -0
- package/src/AdaptableState/Common/NamedObject.js +1 -0
- package/src/AdaptableState/Common/RowSummary.d.ts +1 -1
- package/src/AdaptableState/Common/Schedule.d.ts +7 -3
- package/src/AdaptableState/Common/SuspendableObject.d.ts +10 -0
- package/src/AdaptableState/Common/SuspendableObject.js +1 -0
- package/src/AdaptableState/CustomSortState.d.ts +6 -2
- package/src/AdaptableState/DashboardState.d.ts +3 -3
- package/src/AdaptableState/ExportState.d.ts +3 -3
- package/src/AdaptableState/FlashingCellState.d.ts +6 -2
- package/src/AdaptableState/FormatColumnState.d.ts +6 -2
- package/src/AdaptableState/InternalState.d.ts +2 -0
- package/src/AdaptableState/LayoutState.d.ts +3 -3
- package/src/AdaptableState/NamedQueryState.d.ts +3 -3
- package/src/AdaptableState/PlusMinusState.d.ts +6 -2
- package/src/AdaptableState/ShortcutState.d.ts +6 -2
- package/src/AdaptableState/StyledColumnState.d.ts +1 -1
- package/src/AdaptableState/ThemeState.d.ts +3 -3
- package/src/Api/AlertApi.d.ts +6 -0
- package/src/Api/CustomSortApi.d.ts +6 -0
- package/src/Api/FlashingCellApi.d.ts +6 -0
- package/src/Api/FormatColumnApi.d.ts +10 -4
- package/src/Api/GridApi.d.ts +18 -3
- package/src/Api/Implementation/AlertApiImpl.d.ts +1 -0
- package/src/Api/Implementation/AlertApiImpl.js +3 -0
- package/src/Api/Implementation/ChartingApiImpl.js +2 -2
- package/src/Api/Implementation/CustomSortApiImpl.d.ts +1 -0
- package/src/Api/Implementation/CustomSortApiImpl.js +3 -0
- package/src/Api/Implementation/FlashingCellApiImpl.d.ts +1 -0
- package/src/Api/Implementation/FlashingCellApiImpl.js +3 -0
- package/src/Api/Implementation/FormatColumnApiImpl.d.ts +6 -5
- package/src/Api/Implementation/FormatColumnApiImpl.js +6 -5
- package/src/Api/Implementation/GridApiImpl.d.ts +4 -0
- package/src/Api/Implementation/GridApiImpl.js +15 -1
- package/src/Api/Implementation/LayoutApiImpl.js +1 -1
- package/src/Api/Implementation/NamedQueryApiImpl.js +2 -2
- package/src/Api/Implementation/PlusMinusApiImpl.d.ts +1 -0
- package/src/Api/Implementation/PlusMinusApiImpl.js +3 -0
- package/src/Api/Implementation/ScheduleApiImpl.d.ts +1 -0
- package/src/Api/Implementation/ScheduleApiImpl.js +3 -0
- package/src/Api/Implementation/ShortcutApiImpl.d.ts +1 -0
- package/src/Api/Implementation/ShortcutApiImpl.js +3 -0
- package/src/Api/Implementation/SystemStatusApiImpl.js +4 -4
- package/src/Api/Internal/CalculatedColumnInternalApi.js +2 -2
- package/src/Api/Internal/FreeTextColumnInternalApi.js +2 -2
- package/src/Api/Internal/LayoutInternalApi.js +1 -1
- package/src/Api/Internal/NamedQueryInternalApi.js +4 -4
- package/src/Api/PlusMinusApi.d.ts +6 -0
- package/src/Api/ScheduleApi.d.ts +6 -0
- package/src/Api/ShortcutApi.d.ts +6 -0
- package/src/Redux/ActionsReducers/FormatColumnRedux.d.ts +8 -0
- package/src/Redux/ActionsReducers/FormatColumnRedux.js +15 -0
- package/src/Redux/ActionsReducers/InternalRedux.d.ts +15 -0
- package/src/Redux/ActionsReducers/InternalRedux.js +36 -0
- package/src/Redux/Store/AdaptableStore.js +39 -16
- package/src/Strategy/BulkUpdateModule.js +8 -8
- package/src/Strategy/PlusMinusModule.js +1 -1
- package/src/Strategy/QuickSearchModule.js +1 -1
- package/src/Strategy/SettingsPanelModule.js +11 -7
- package/src/Strategy/SmartEditModule.js +10 -10
- package/src/Utilities/Services/DataService.js +1 -1
- package/src/Utilities/Services/Fdc3Service.js +4 -4
- package/src/Utilities/Services/ModuleService.js +1 -3
- package/src/Utilities/Services/ThemeService.js +2 -6
- package/src/Utilities/Services/ValidationService.js +1 -1
- package/src/Utilities/logDeprecation.js +3 -4
- package/src/View/Alert/Utilities/getDefaultAlertDefinition.d.ts +2 -2
- package/src/View/Alert/Wizard/isValidAlertRules.js +1 -1
- package/src/View/CalculatedColumn/Wizard/CalculatedColumnDefinitionWizardSection.js +2 -2
- package/src/View/CalculatedColumn/Wizard/CalculatedColumnExpressionWizardSection.js +2 -2
- package/src/View/CalculatedColumn/Wizard/CalculatedColumnSettingsWizardSection.js +1 -1
- package/src/View/Charting/ChartingWizard/AgChargingWizard/SettingsSection.js +2 -2
- package/src/View/Charting/ChartingWizard/ExternalChartingWizard/SettingsSection.js +2 -2
- package/src/View/Components/CellPopup/index.js +1 -1
- package/src/View/Components/ColumnFilter/FloatingFilter.js +41 -3
- package/src/View/Components/ColumnFilter/components/ColumnFilterMenu.js +54 -2
- package/src/View/Components/EntityRulesEditor/Utilities.js +5 -5
- package/src/View/Components/NewScopeComponent.js +3 -3
- package/src/View/Components/Popups/AdaptablePopupConfirmation.js +1 -1
- package/src/View/CustomSort/Wizard/CustomSortColumnWizardSection.js +3 -3
- package/src/View/CustomSort/Wizard/CustomSortValuesWizardSection.js +1 -1
- package/src/View/FlashingCell/Wizard/isValidFlashingCellRules.js +1 -1
- package/src/View/FreeTextColumn/Wizard/FreeTextColumnSettingsWizardSection.d.ts +1 -1
- package/src/View/FreeTextColumn/Wizard/FreeTextColumnSettingsWizardSection.js +3 -3
- package/src/View/Layout/LayoutViewPanel.js +1 -1
- package/src/View/Layout/Wizard/sections/AggregationsSection.js +1 -1
- package/src/View/Layout/Wizard/sections/FilterSection.js +1 -1
- package/src/View/Layout/Wizard/sections/GridFilterSection.js +1 -1
- package/src/View/Layout/Wizard/sections/PivotAggregationsSection.js +3 -3
- package/src/View/Layout/Wizard/sections/RowSummarySection.js +1 -1
- package/src/View/NamedQuery/Wizard/NamedQueryExpressionWizardSection.js +2 -2
- package/src/View/PlusMinus/Wizard/PlusMinusSettingsWizardSection.js +5 -5
- package/src/View/Schedule/Wizard/ScheduleSettingsWizard/isSettingsValid.d.ts +1 -1
- package/src/View/Schedule/Wizard/ScheduleSettingsWizard/isSettingsValid.js +11 -11
- package/src/View/StateManagement/handleExportState.js +1 -1
- package/src/View/StyledColumn/Wizard/StyledColumnWizardColumnSection.js +1 -1
- package/src/agGrid/AdaptableAgGrid.js +47 -51
- package/src/agGrid/AgGridAdapter.js +8 -8
- package/src/agGrid/AgGridColumnAdapter.d.ts +1 -0
- package/src/agGrid/AgGridColumnAdapter.js +15 -4
- package/src/agGrid/AgGridExportAdapter.js +5 -5
- package/src/agGrid/AgGridThemeAdapter.js +2 -2
- package/src/components/OverlayTrigger/index.js +1 -1
- package/src/components/Select/Select.js +78 -15
- package/src/env.js +2 -2
- package/src/metamodel/adaptable.metamodel.d.ts +25 -18
- package/src/metamodel/adaptable.metamodel.js +1 -1
- package/src/migration/AdaptableUpgradeHelper.js +2 -2
- package/src/migration/VersionUpgrade17.js +4 -4
- package/src/migration/VersionUpgrade20.js +4 -4
- package/src/types.d.ts +2 -2
- package/tsconfig.esm.tsbuildinfo +1 -1
|
@@ -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
|
-
|
|
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
|
};
|
|
@@ -4,7 +4,7 @@ export const isValidAlertRules = (alert, api, context) => {
|
|
|
4
4
|
!alert.Rule.BooleanExpression &&
|
|
5
5
|
!alert.Rule.ObservableExpression &&
|
|
6
6
|
!alert.Rule.AggregatedBooleanExpression) {
|
|
7
|
-
return '
|
|
7
|
+
return 'A rule is required for the Alert.';
|
|
8
8
|
}
|
|
9
9
|
const isRuleValid = isAdaptableRuleValid(alert, api, context);
|
|
10
10
|
if (typeof isRuleValid === 'string') {
|
|
@@ -21,11 +21,11 @@ export const renderCalculatedColumnDefinitionSummary = (data) => {
|
|
|
21
21
|
export const isValidCalculatedColumnDefinition = (data, api) => {
|
|
22
22
|
const columns = api.columnApi.getColumns();
|
|
23
23
|
if (!data.ColumnId) {
|
|
24
|
-
return 'Column
|
|
24
|
+
return 'A Column ID is required.';
|
|
25
25
|
}
|
|
26
26
|
const columnsWithSameIdCount = columns.filter((c) => c.columnId === data.ColumnId).length;
|
|
27
27
|
const hasAlreadyExistingId = data.Uuid ? columnsWithSameIdCount > 1 : columnsWithSameIdCount > 0;
|
|
28
|
-
return hasAlreadyExistingId ? 'A
|
|
28
|
+
return hasAlreadyExistingId ? 'A column with this ID already exists.' : true;
|
|
29
29
|
};
|
|
30
30
|
export const CalculatedColumnDefinitionWizardSection = (props) => {
|
|
31
31
|
const { data, api } = useOnePageAdaptableWizardContext();
|
|
@@ -17,11 +17,11 @@ export const isValidCalculatedColumnExpression = (data, api) => {
|
|
|
17
17
|
const calculatedColumnExpressionService = api.internalApi.getCalculatedColumnExpressionService();
|
|
18
18
|
const expression = api.expressionApi.getAdaptableQueryExpression(data.Query)?.trim();
|
|
19
19
|
if (!expression) {
|
|
20
|
-
return '
|
|
20
|
+
return 'An expression is required for the Calculated Column.';
|
|
21
21
|
}
|
|
22
22
|
const isValid = calculatedColumnExpressionService.isCalculatedColumnQueryValid(data.Query);
|
|
23
23
|
if (!isValid) {
|
|
24
|
-
return 'Calculated Column
|
|
24
|
+
return 'The Calculated Column expression is not valid.';
|
|
25
25
|
}
|
|
26
26
|
return true;
|
|
27
27
|
};
|
|
@@ -16,7 +16,7 @@ export const renderCalculatedColumnSettingsSummary = (data) => {
|
|
|
16
16
|
};
|
|
17
17
|
export const isValidCalculatedColumnSettings = (data) => {
|
|
18
18
|
if (!data.CalculatedColumnSettings?.DataType) {
|
|
19
|
-
return '
|
|
19
|
+
return 'A data type is required. It could not be inferred from the expression.';
|
|
20
20
|
}
|
|
21
21
|
return true;
|
|
22
22
|
};
|
|
@@ -5,12 +5,12 @@ import FormLayout, { FormRow } from '../../../../components/FormLayout';
|
|
|
5
5
|
import AdaptableInput from '../../../Components/AdaptableInput';
|
|
6
6
|
export const isSettingsValid = (chartDefinition, api) => {
|
|
7
7
|
if (!chartDefinition.Name) {
|
|
8
|
-
return '
|
|
8
|
+
return 'A name is required.';
|
|
9
9
|
}
|
|
10
10
|
const allChartDefinitions = api.chartingApi.getChartDefinitions();
|
|
11
11
|
if (allChartDefinitions.some((chartDefinitionLoopItem) => chartDefinitionLoopItem.Uuid !== chartDefinition.Uuid &&
|
|
12
12
|
chartDefinitionLoopItem.Name === chartDefinition.Name)) {
|
|
13
|
-
return '
|
|
13
|
+
return 'A Chart with this name already exists.';
|
|
14
14
|
}
|
|
15
15
|
return true;
|
|
16
16
|
};
|
|
@@ -3,12 +3,12 @@ import FormLayout, { FormRow } from '../../../../components/FormLayout';
|
|
|
3
3
|
import AdaptableInput from '../../../Components/AdaptableInput';
|
|
4
4
|
export const isSettingsValid = (chartDefinition, api) => {
|
|
5
5
|
if (!chartDefinition.Name) {
|
|
6
|
-
return '
|
|
6
|
+
return 'A name is required.';
|
|
7
7
|
}
|
|
8
8
|
const allChartDefinitions = api.chartingApi.getExternalChartDefinitions();
|
|
9
9
|
if (allChartDefinitions.some((chartDefinitionLoopItem) => chartDefinitionLoopItem.Uuid !== chartDefinition.Uuid &&
|
|
10
10
|
chartDefinitionLoopItem.Name === chartDefinition.Name)) {
|
|
11
|
-
return '
|
|
11
|
+
return 'A Chart with this name already exists.';
|
|
12
12
|
}
|
|
13
13
|
return true;
|
|
14
14
|
};
|
|
@@ -32,7 +32,7 @@ export const CellPopup = React.forwardRef((props, ref) => {
|
|
|
32
32
|
const cellSelector = `[row-id="${props.primaryKeyValue}"] [col-id="${props.columnId}"]`;
|
|
33
33
|
const alignTo = document.querySelector(cellSelector);
|
|
34
34
|
if (!alignTo) {
|
|
35
|
-
adaptable.logger.consoleError(`
|
|
35
|
+
adaptable.logger.consoleError(`Cell not found for selector "${cellSelector}". Unable to display popup.`);
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
const showOverlayOptions = {
|
|
@@ -37,11 +37,19 @@ export const FloatingFilter = (props) => {
|
|
|
37
37
|
const handleClear = () => props.onClear?.();
|
|
38
38
|
const showEvent = 'click';
|
|
39
39
|
const hideEvent = 'blur';
|
|
40
|
+
const [overlayVisible, setOverlayVisible] = React.useState(false);
|
|
40
41
|
let filterDropdown = null;
|
|
41
|
-
|
|
42
|
+
const filterDropdownButton = (React.createElement(SimpleButton, { variant: "text", "data-name": "floating-filter-button", onBlur: () => {
|
|
43
|
+
if (isInlineEditable) {
|
|
44
|
+
setOverlayVisible(false);
|
|
45
|
+
}
|
|
46
|
+
}, "data-value": props.predicate?.args[0]?.operator, onClick: () => {
|
|
42
47
|
if (!isInlineEditable) {
|
|
43
48
|
adaptable.api.filterApi.columnFilterApi.internalApi.openColumnFilterPopup(props.columnId);
|
|
44
49
|
}
|
|
50
|
+
else {
|
|
51
|
+
setOverlayVisible(true);
|
|
52
|
+
}
|
|
45
53
|
}, style: {
|
|
46
54
|
textAlign: 'left',
|
|
47
55
|
marginRight: 1, // just so that the focus outline is not cut off
|
|
@@ -55,9 +63,10 @@ export const FloatingFilter = (props) => {
|
|
|
55
63
|
React.createElement(Box, null, !isManualApply && singleFilterPredicateDef?.icon ? (singleFilterPredicateDef?.icon) : (React.createElement(AdaptableIconComponent, { icon: { name: 'filter' } }))),
|
|
56
64
|
showLabel && (React.createElement(Box, { className: "ab-FloatingFilter-label twa:ml-2 twa:flex-1", title: label }, label))));
|
|
57
65
|
if (isInlineEditable) {
|
|
58
|
-
filterDropdown = showQuickFilterDropdown && (React.createElement(OverlayTrigger, { className: "ab-FloatingFilter-overlay", showEvent: showEvent, hideEvent: hideEvent, preventPortalEventPropagation: showEvent === 'click', targetOffset: 10, hideDelay: 50, "data-name": "floating-filter-overlay", render: () => {
|
|
66
|
+
filterDropdown = showQuickFilterDropdown && (React.createElement(OverlayTrigger, { 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: () => {
|
|
59
67
|
// we render this only for single filter
|
|
60
68
|
return (React.createElement(ColumnFilterMenu, { columnId: props.columnId, disabled: props.disabled, predicate: props.predicate.args[0], predicateDefs: props.predicateDefs, onPredicateChange: (predicate) => {
|
|
69
|
+
setOverlayVisible(false);
|
|
61
70
|
props.onPredicateChange({
|
|
62
71
|
operator: props.predicate.operator,
|
|
63
72
|
args: [predicate],
|
|
@@ -68,7 +77,36 @@ export const FloatingFilter = (props) => {
|
|
|
68
77
|
else {
|
|
69
78
|
filterDropdown = filterDropdownButton;
|
|
70
79
|
}
|
|
71
|
-
return (React.createElement(Flex, { className: "ab-FloatingFilter twa:w-full"
|
|
80
|
+
return (React.createElement(Flex, { className: "ab-FloatingFilter twa:w-full", onKeyDownCapture: (e) => {
|
|
81
|
+
// AG Grid's header keyboard navigation intercepts Tab and calls preventDefault(),
|
|
82
|
+
// which prevents focus from moving between elements inside the floating filter.
|
|
83
|
+
// We handle Tab manually in the capture phase (before AG Grid's handlers).
|
|
84
|
+
if (e.key === 'Tab') {
|
|
85
|
+
const target = e.target;
|
|
86
|
+
const wrapper = e.currentTarget;
|
|
87
|
+
if (!e.shiftKey) {
|
|
88
|
+
// Tab forward: from filter button → select input
|
|
89
|
+
if (target.getAttribute('data-name') === 'floating-filter-button') {
|
|
90
|
+
const selectInput = wrapper.querySelector('[data-name="Select Values"] input');
|
|
91
|
+
if (selectInput) {
|
|
92
|
+
e.preventDefault();
|
|
93
|
+
e.nativeEvent.stopImmediatePropagation();
|
|
94
|
+
selectInput.focus();
|
|
95
|
+
// When the DummyInput gets focus, react-select sets isFocused=true,
|
|
96
|
+
// triggering a React re-render. During this re-render, unstable component
|
|
97
|
+
// references in selectComponents can cause the DummyInput to be removed
|
|
98
|
+
// from DOM and recreated, losing focus. We restore focus after the re-render.
|
|
99
|
+
requestAnimationFrame(() => {
|
|
100
|
+
if (document.activeElement === document.body || document.activeElement === null) {
|
|
101
|
+
const newInput = wrapper.querySelector('[data-name="Select Values"] input');
|
|
102
|
+
newInput?.focus();
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} },
|
|
72
110
|
filterDropdown,
|
|
73
111
|
isInlineEditable && (React.createElement(Flex, { className: "twa:flex-1 twa:min-w-0" },
|
|
74
112
|
React.createElement(FloatingFilterInputList, { onKeyDown: props.onKeydown, columnId: props.columnId, disabled: props.disabled,
|
|
@@ -2,16 +2,68 @@ import * as React from 'react';
|
|
|
2
2
|
import Panel from '../../../../components/Panel';
|
|
3
3
|
import SimpleButton from '../../../../components/SimpleButton';
|
|
4
4
|
import { Box, Flex } from '../../../../components/Flex';
|
|
5
|
+
import clsx from 'clsx';
|
|
6
|
+
import { useEffect, useLayoutEffect } from 'react';
|
|
5
7
|
const ColumnFilterMenuItem = ({ active, onClick, icon, label, }) => {
|
|
6
8
|
return (React.createElement(SimpleButton, { className: "twa:p-1 twa:w-full", variant: "text", tone: active ? 'info' : 'none', onClick: onClick },
|
|
7
9
|
React.createElement(Box, { className: "twa:mr-2" }, icon),
|
|
8
10
|
React.createElement(Box, { className: "twa:text-2" }, label)));
|
|
9
11
|
};
|
|
10
12
|
export const ColumnFilterMenu = (props) => {
|
|
13
|
+
const [activeIndex, setActiveIndex] = React.useState(() => {
|
|
14
|
+
const index = props.predicateDefs.findIndex((predicateDef) => predicateDef.operator === props.predicate.operator);
|
|
15
|
+
return index === -1 ? 0 : index;
|
|
16
|
+
});
|
|
17
|
+
const activeIndexRef = React.useRef(activeIndex);
|
|
18
|
+
const onPredicateChangeRef = React.useRef(props.onPredicateChange);
|
|
19
|
+
const predicateDefsRef = React.useRef(props.predicateDefs);
|
|
20
|
+
useLayoutEffect(() => {
|
|
21
|
+
activeIndexRef.current = activeIndex;
|
|
22
|
+
onPredicateChangeRef.current = props.onPredicateChange;
|
|
23
|
+
predicateDefsRef.current = props.predicateDefs;
|
|
24
|
+
});
|
|
25
|
+
const confirm = React.useCallback((predicateDef) => {
|
|
26
|
+
onPredicateChangeRef.current({ operator: predicateDef.operator, args: [] });
|
|
27
|
+
}, []);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const onKeyDown = (e) => {
|
|
30
|
+
// Only handle arrow keys and Enter - let other keys (like Tab) pass through
|
|
31
|
+
if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp' && e.key !== 'Enter') {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const activeIndex = activeIndexRef.current;
|
|
35
|
+
const predicateDefs = predicateDefsRef.current;
|
|
36
|
+
if (e.key === 'Enter') {
|
|
37
|
+
const predicateDef = predicateDefs[activeIndex];
|
|
38
|
+
if (predicateDef) {
|
|
39
|
+
confirm(predicateDef);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
e.stopPropagation();
|
|
43
|
+
e.preventDefault();
|
|
44
|
+
const dir = e.key === 'ArrowDown' ? 1 : e.key === 'ArrowUp' ? -1 : 0;
|
|
45
|
+
if (dir) {
|
|
46
|
+
let nextIndex = activeIndex + dir;
|
|
47
|
+
if (nextIndex < 0) {
|
|
48
|
+
nextIndex = predicateDefs.length - 1;
|
|
49
|
+
}
|
|
50
|
+
else if (nextIndex >= predicateDefs.length) {
|
|
51
|
+
nextIndex = 0;
|
|
52
|
+
}
|
|
53
|
+
setActiveIndex(nextIndex);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
document.addEventListener('keydown', onKeyDown);
|
|
57
|
+
return () => {
|
|
58
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
59
|
+
};
|
|
60
|
+
}, [confirm]);
|
|
11
61
|
return (React.createElement(Panel, { className: "twa:min-w-max" }, props.predicateDefs?.map((predicateDef, index) => {
|
|
12
|
-
|
|
62
|
+
const active = activeIndex === index;
|
|
63
|
+
return (React.createElement(Flex, { className: clsx("twa:mb-1", active && "twa:bg-primarylight"), key: index, onMouseDownCapture: (e) => {
|
|
13
64
|
e.stopPropagation();
|
|
65
|
+
e.preventDefault();
|
|
14
66
|
} },
|
|
15
|
-
React.createElement(ColumnFilterMenuItem, { onClick: () =>
|
|
67
|
+
React.createElement(ColumnFilterMenuItem, { onClick: () => confirm(predicateDef), icon: predicateDef.icon, label: predicateDef.label, active: active })));
|
|
16
68
|
})));
|
|
17
69
|
};
|
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
export const isAdaptableRuleValid = (abObject, api, context) => {
|
|
2
2
|
if (abObject?.Rule?.Predicates?.length) {
|
|
3
3
|
if (!api.predicateApi.isEveryPredicateValid(abObject?.Rule?.Predicates)) {
|
|
4
|
-
return `The
|
|
4
|
+
return `The predicate${abObject?.Rule?.Predicates?.length === 1 ? ' is' : 's are'} not valid.`;
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
7
|
if (abObject?.Rule?.BooleanExpression) {
|
|
8
8
|
if (!api.expressionApi.isValidBooleanExpression(abObject?.Rule?.BooleanExpression, context.moduleInfo.ModuleName)) {
|
|
9
|
-
return 'The
|
|
9
|
+
return 'The Boolean expression is not valid.';
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
if (abObject?.Rule?.ObservableExpression) {
|
|
13
13
|
if (!api.expressionApi.isValidObservableExpression(abObject?.Rule?.ObservableExpression, context.moduleInfo.ModuleName)) {
|
|
14
|
-
return 'The
|
|
14
|
+
return 'The Observable expression is not valid.';
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
if (abObject?.Rule?.AggregatedBooleanExpression) {
|
|
18
18
|
if (!api.expressionApi.isValidAggregatedBooleanExpression(abObject?.Rule?.AggregatedBooleanExpression, context.moduleInfo.ModuleName)) {
|
|
19
|
-
return 'The
|
|
19
|
+
return 'The Aggregated Boolean expression is not valid.';
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
if (abObject?.Rule?.Predicates?.length) {
|
|
23
23
|
const isAPredicateWithInvalidColumnId = abObject?.Rule?.Predicates?.some((predicate) => predicate.ColumnId !== undefined && predicate.ColumnId === '');
|
|
24
24
|
if (isAPredicateWithInvalidColumnId) {
|
|
25
|
-
return 'Predicates with custom scope
|
|
25
|
+
return 'Predicates with a custom scope require a valid column.';
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
return true;
|
|
@@ -14,13 +14,13 @@ import { TagList } from '../../components/Tag/Tag';
|
|
|
14
14
|
export const isScopeValid = ({ Scope }) => {
|
|
15
15
|
const result = [];
|
|
16
16
|
if (!Scope) {
|
|
17
|
-
return '
|
|
17
|
+
return 'A scope is required.';
|
|
18
18
|
}
|
|
19
19
|
if (Scope && 'ColumnIds' in Scope && Scope.ColumnIds.length === 0) {
|
|
20
|
-
result.push('
|
|
20
|
+
result.push('Please select at least one column for the scope.');
|
|
21
21
|
}
|
|
22
22
|
if (Scope && 'DataTypes' in Scope && Scope.DataTypes.length === 0) {
|
|
23
|
-
result.push('
|
|
23
|
+
result.push('Please select at least one data type for the scope.');
|
|
24
24
|
}
|
|
25
25
|
return result.length ? result.join(', ') : true;
|
|
26
26
|
};
|
|
@@ -51,7 +51,7 @@ export const AdaptablePopupConfirmation = (props) => {
|
|
|
51
51
|
setDisableDeleteConfirmation(!disableDeleteConfirmation);
|
|
52
52
|
} }, "Do not show this again")),
|
|
53
53
|
props.showInputBox && (React.createElement(Box, { className: "twa:p-2", "data-name": "body" },
|
|
54
|
-
React.createElement("p", null, "Please enter a comment to confirm"),
|
|
54
|
+
React.createElement("p", null, "Please enter a comment to confirm."),
|
|
55
55
|
React.createElement(Input, { className: "twa:mt-2 twa:w-full", value: promptText, type: "string", placeholder: "Enter text", onChange: (e) => changeContent(e) }))),
|
|
56
56
|
React.createElement(Flex, { className: "twa:mt-3 twa:p-2", "data-name": "footer", justifyContent: "space-between" },
|
|
57
57
|
props.cancelButtonText != null ? (React.createElement(SimpleButton, { "data-name": "cancel", tone: "neutral", variant: "raised", onClick: () => onCancelForm() }, props.cancelButtonText)) : (React.createElement("div", null)),
|
|
@@ -18,13 +18,13 @@ export const renderCustomSortColumn = (data) => {
|
|
|
18
18
|
};
|
|
19
19
|
export const isValidCustomSortColumn = (data, allCustomSorts) => {
|
|
20
20
|
if (!data.Name) {
|
|
21
|
-
return '
|
|
21
|
+
return 'A name is required.';
|
|
22
22
|
}
|
|
23
23
|
if (allCustomSorts.some((customSort) => customSort.Name === data.Name && customSort.Uuid !== data.Uuid)) {
|
|
24
|
-
return 'A Custom Sort
|
|
24
|
+
return 'A Custom Sort with this name already exists.';
|
|
25
25
|
}
|
|
26
26
|
if (!data.ColumnId) {
|
|
27
|
-
return '
|
|
27
|
+
return 'Please select a column for the Custom Sort.';
|
|
28
28
|
}
|
|
29
29
|
return true;
|
|
30
30
|
};
|
|
@@ -11,7 +11,7 @@ import { parseToISO } from '../../../Utilities/Helpers/DateHelper';
|
|
|
11
11
|
import { TagList } from '../../../components/Tag';
|
|
12
12
|
export const isValidCustomSortOrder = (data) => {
|
|
13
13
|
if (!data.SortedValues || !data.SortedValues.length) {
|
|
14
|
-
return '
|
|
14
|
+
return 'At least one value is required for the Custom Sort order.';
|
|
15
15
|
}
|
|
16
16
|
return true;
|
|
17
17
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isAdaptableRuleValid } from '../../Components/EntityRulesEditor/Utilities';
|
|
2
2
|
export const isValidFlashingCellRules = (flashingCell, api, context) => {
|
|
3
3
|
if (!flashingCell.Rule?.Predicates?.length && !flashingCell.Rule.BooleanExpression) {
|
|
4
|
-
return '
|
|
4
|
+
return 'A rule is required for the Flashing Cell.';
|
|
5
5
|
}
|
|
6
6
|
const isRuleValid = isAdaptableRuleValid(flashingCell, api, context);
|
|
7
7
|
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
|
|
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;
|
|
@@ -40,15 +40,15 @@ export const renderFreeTextColumnSummary = (data) => {
|
|
|
40
40
|
export const isValidFreeTextColumn = (data, api) => {
|
|
41
41
|
const columns = api.columnApi.getUIAvailableColumns();
|
|
42
42
|
if (!data.ColumnId) {
|
|
43
|
-
return 'Column
|
|
43
|
+
return 'A Column ID is required.';
|
|
44
44
|
}
|
|
45
45
|
const columnsWithSameIdCount = columns.filter((c) => c.columnId === data.ColumnId).length;
|
|
46
46
|
const hasAlreadyExistingId = data.Uuid ? columnsWithSameIdCount > 1 : columnsWithSameIdCount > 0;
|
|
47
47
|
if (hasAlreadyExistingId) {
|
|
48
|
-
return 'A
|
|
48
|
+
return 'A column with this ID already exists.';
|
|
49
49
|
}
|
|
50
50
|
if (!data.FreeTextColumnSettings.DataType) {
|
|
51
|
-
return '
|
|
51
|
+
return 'A data type is required for the column.';
|
|
52
52
|
}
|
|
53
53
|
return true;
|
|
54
54
|
};
|
|
@@ -79,7 +79,7 @@ function mapDispatchToProps(dispatch) {
|
|
|
79
79
|
showMissingLayoutsError: () => {
|
|
80
80
|
dispatch(PopupRedux.PopupShowConfirmation({
|
|
81
81
|
Header: 'Missing Layouts',
|
|
82
|
-
Msg: '
|
|
82
|
+
Msg: 'No Layouts have been defined. Please check the console for details.',
|
|
83
83
|
ConfirmAction: null,
|
|
84
84
|
ConfirmButtonText: 'OK',
|
|
85
85
|
CancelButtonText: null,
|
|
@@ -19,7 +19,7 @@ export const isAggregationsSectionValid = (data) => {
|
|
|
19
19
|
AggFunc.type === 'weightedAverage')?.AggFunc
|
|
20
20
|
: null;
|
|
21
21
|
if (weightedAvg && !weightedAvg.weightedColumnId) {
|
|
22
|
-
return '
|
|
22
|
+
return 'Weighted Average requires a weight column to be selected.';
|
|
23
23
|
}
|
|
24
24
|
return true;
|
|
25
25
|
};
|
|
@@ -13,7 +13,7 @@ import { Box } from '../../../../components/Flex';
|
|
|
13
13
|
export const isColumnFiltersValid = (layout) => {
|
|
14
14
|
const invalidColumnFilters = (layout.ColumnFilters ?? [])?.filter((columnFilter) => !columnFilter?.Predicates[0]?.PredicateId);
|
|
15
15
|
if (invalidColumnFilters.length > 0) {
|
|
16
|
-
return 'Please select a
|
|
16
|
+
return 'Please select a predicate for each column filter.';
|
|
17
17
|
}
|
|
18
18
|
return true;
|
|
19
19
|
};
|
|
@@ -13,7 +13,7 @@ export const isGridFiltersValid = (layout, api) => {
|
|
|
13
13
|
return true;
|
|
14
14
|
}
|
|
15
15
|
return (api.internalApi.getQueryLanguageService().validateBoolean(expression, GridFilterModuleId)
|
|
16
|
-
.isValid || '
|
|
16
|
+
.isValid || 'The expression is not valid.');
|
|
17
17
|
};
|
|
18
18
|
export const GridFilterSectionSummary = () => {
|
|
19
19
|
const { data: layout } = useOnePageAdaptableWizardContext();
|
|
@@ -216,7 +216,7 @@ export const isPivotAggregationsSectionValid = (data) => {
|
|
|
216
216
|
.find((agg) => typeof agg === 'object' && agg.type === 'weightedAverage')
|
|
217
217
|
: null;
|
|
218
218
|
if (weightedAvg && !weightedAvg.weightedColumnId) {
|
|
219
|
-
return '
|
|
219
|
+
return 'Weighted Average requires a weight column to be selected.';
|
|
220
220
|
}
|
|
221
221
|
return true;
|
|
222
222
|
};
|
|
@@ -303,12 +303,12 @@ export const PivotAggregationsSection = (props) => {
|
|
|
303
303
|
}
|
|
304
304
|
const firstAggFuncName = getAggFuncName(aggregationColumns[0].AggFunc);
|
|
305
305
|
if (layout.PivotAggregationColumns?.some((aggCol) => getAggFuncName(aggCol.AggFunc) !== firstAggFuncName)) {
|
|
306
|
-
return '
|
|
306
|
+
return 'All columns must use the same aggregation function.';
|
|
307
307
|
}
|
|
308
308
|
// check that no Aggregation Total Column is enabled
|
|
309
309
|
const hasAggregationTotalColumn = aggregationColumns.some((aggCol) => aggCol.Total !== false && aggCol.Total != null);
|
|
310
310
|
if (hasAggregationTotalColumn) {
|
|
311
|
-
return '
|
|
311
|
+
return 'This option is not available when an Aggregation Total Column is present.';
|
|
312
312
|
}
|
|
313
313
|
return true;
|
|
314
314
|
};
|
|
@@ -24,7 +24,7 @@ export const areSummaryRowsValid = (layout) => {
|
|
|
24
24
|
layout.RowSummaries?.find((rowSummary) => {
|
|
25
25
|
for (const [_, fn] of Object.entries(rowSummary.ColumnsMap ?? {})) {
|
|
26
26
|
if (!fn) {
|
|
27
|
-
valid = '
|
|
27
|
+
valid = 'Each row summary column requires an aggregation function.';
|
|
28
28
|
return true;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -7,11 +7,11 @@ import { useOnePageAdaptableWizardContext } from '../../Wizard/OnePageAdaptableW
|
|
|
7
7
|
import { Box } from '../../../components/Flex';
|
|
8
8
|
export const isValidNamedQueryExpression = (data, api) => {
|
|
9
9
|
if (!data.BooleanExpression) {
|
|
10
|
-
return '
|
|
10
|
+
return 'An expression is required.';
|
|
11
11
|
}
|
|
12
12
|
const valid = api.expressionApi.isValidBooleanExpression(data.BooleanExpression, NamedQueryModuleId);
|
|
13
13
|
if (!valid) {
|
|
14
|
-
return '
|
|
14
|
+
return 'The query is not a valid Boolean expression.';
|
|
15
15
|
}
|
|
16
16
|
return valid;
|
|
17
17
|
};
|
|
@@ -24,16 +24,16 @@ export const PlusMinusSettingsSummary = (props) => {
|
|
|
24
24
|
};
|
|
25
25
|
export const isSettingsValid = (hasCondition) => (data, api, context) => {
|
|
26
26
|
if (!data.Name?.trim()) {
|
|
27
|
-
return '
|
|
27
|
+
return 'A name is required.';
|
|
28
28
|
}
|
|
29
29
|
const allPlusMinusNudges = api.plusMinusApi.getAllPlusMinus();
|
|
30
30
|
const isDuplicateName = allPlusMinusNudges.some((nudge) => nudge.Name === data.Name && nudge.Uuid !== data.Uuid);
|
|
31
31
|
if (isDuplicateName) {
|
|
32
|
-
return 'A Plus
|
|
32
|
+
return 'A Plus/Minus Nudge with this name already exists.';
|
|
33
33
|
}
|
|
34
34
|
if (hasCondition) {
|
|
35
35
|
if (!data?.Rule?.BooleanExpression) {
|
|
36
|
-
return '
|
|
36
|
+
return 'A valid rule is required.';
|
|
37
37
|
}
|
|
38
38
|
const ruleValidation = isAdaptableRuleValid(data, api, context);
|
|
39
39
|
if (typeof ruleValidation === 'string') {
|
|
@@ -41,10 +41,10 @@ export const isSettingsValid = (hasCondition) => (data, api, context) => {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
if (typeof data.NudgeValue !== 'number') {
|
|
44
|
-
return '
|
|
44
|
+
return 'A nudge value is required.';
|
|
45
45
|
}
|
|
46
46
|
if (data.NudgeValue === 0) {
|
|
47
|
-
return 'Nudge value must be
|
|
47
|
+
return 'Nudge value must not be zero.';
|
|
48
48
|
}
|
|
49
49
|
return true;
|
|
50
50
|
};
|
|
@@ -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 | "
|
|
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.";
|
|
@@ -3,50 +3,50 @@ import StringExtensions from '../../../../Utilities/Extensions/StringExtensions'
|
|
|
3
3
|
export const isSettingsValid = (schedule, api) => {
|
|
4
4
|
// Validate Name - mandatory and unique
|
|
5
5
|
if (!schedule.Name?.trim()) {
|
|
6
|
-
return '
|
|
6
|
+
return 'A name is required.';
|
|
7
7
|
}
|
|
8
8
|
const allSchedules = api.scheduleApi.getSchedules();
|
|
9
9
|
const isDuplicateName = allSchedules.some((s) => s.Name === schedule.Name && s.Uuid !== schedule.Uuid);
|
|
10
10
|
if (isDuplicateName) {
|
|
11
|
-
return 'A Schedule with this name already exists';
|
|
11
|
+
return 'A Schedule with this name already exists.';
|
|
12
12
|
}
|
|
13
13
|
if (schedule.ScheduleType === ScheduleType.Reminder) {
|
|
14
14
|
const reminder = schedule;
|
|
15
15
|
if (!reminder.MessageType) {
|
|
16
|
-
return '
|
|
16
|
+
return 'Please select a message type.';
|
|
17
17
|
}
|
|
18
18
|
if (StringExtensions.IsNullOrEmpty(reminder?.Header)) {
|
|
19
|
-
return '
|
|
19
|
+
return 'A reminder header is required.';
|
|
20
20
|
}
|
|
21
21
|
if (StringExtensions.IsNullOrEmpty(reminder?.Message)) {
|
|
22
|
-
return '
|
|
22
|
+
return 'A reminder message is required.';
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
if (schedule.ScheduleType === ScheduleType.Report) {
|
|
26
26
|
const report = schedule;
|
|
27
27
|
if (StringExtensions.IsNullOrEmpty(report?.ReportName)) {
|
|
28
|
-
return '
|
|
28
|
+
return 'Please select a report.';
|
|
29
29
|
}
|
|
30
30
|
if (StringExtensions.IsNullOrEmpty(report?.ReportFormat)) {
|
|
31
|
-
return '
|
|
31
|
+
return 'Please select a report format.';
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
if (schedule.ScheduleType === ScheduleType.ipushpull) {
|
|
35
35
|
const ipushpull = schedule;
|
|
36
36
|
if (StringExtensions.IsNullOrEmpty(ipushpull?.IPushPullReport?.ReportName)) {
|
|
37
|
-
return '
|
|
37
|
+
return 'Please select a report.';
|
|
38
38
|
}
|
|
39
39
|
if (StringExtensions.IsNullOrEmpty(ipushpull?.IPushPullReport?.Folder)) {
|
|
40
|
-
return '
|
|
40
|
+
return 'Please select a report folder.';
|
|
41
41
|
}
|
|
42
42
|
if (StringExtensions.IsNullOrEmpty(ipushpull?.IPushPullReport?.Page)) {
|
|
43
|
-
return '
|
|
43
|
+
return 'Please select a report page.';
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
if (schedule.ScheduleType === ScheduleType.OpenFin) {
|
|
47
47
|
const openfin = schedule;
|
|
48
48
|
if (StringExtensions.IsNullOrEmpty(openfin?.OpenFinReport?.ReportName)) {
|
|
49
|
-
return '
|
|
49
|
+
return 'Please select a report.';
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
return true;
|
|
@@ -6,7 +6,7 @@ export const handleExportState = (type, name, state, api) => {
|
|
|
6
6
|
Helper.copyToClipboard(stringifiedState);
|
|
7
7
|
break;
|
|
8
8
|
case 'Console':
|
|
9
|
-
api.consoleLog('Adaptable
|
|
9
|
+
api.consoleLog('Adaptable state:', state);
|
|
10
10
|
break;
|
|
11
11
|
case 'JSON':
|
|
12
12
|
const jsonFileName = name + '.json';
|
|
@@ -15,7 +15,7 @@ export const renderStyledColumnColumnSummary = (data) => {
|
|
|
15
15
|
};
|
|
16
16
|
export const isValidStyledColumnColumn = (data) => {
|
|
17
17
|
if (!data.ColumnId) {
|
|
18
|
-
return '
|
|
18
|
+
return 'Please select a column for the Styled Column.';
|
|
19
19
|
}
|
|
20
20
|
return true;
|
|
21
21
|
};
|