@adaptabletools/adaptable 22.1.0-canary.1 → 22.1.1-canary.0
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 +8 -9
- package/package.json +1 -1
- package/src/AdaptableInterfaces/IAdaptable.d.ts +2 -2
- package/src/AdaptableOptions/AdaptableOptions.d.ts +2 -21
- package/src/AdaptableOptions/AlertOptions.d.ts +0 -5
- package/src/AdaptableOptions/CellSummaryOptions.d.ts +2 -0
- package/src/AdaptableOptions/ChartingOptions.d.ts +2 -0
- package/src/AdaptableOptions/ColumnOptions.d.ts +0 -2
- package/src/AdaptableOptions/CommentOptions.d.ts +6 -0
- package/src/AdaptableOptions/ContainerOptions.d.ts +0 -6
- package/src/AdaptableOptions/DashboardOptions.d.ts +0 -2
- package/src/AdaptableOptions/DataChangeHistoryOptions.d.ts +0 -2
- package/src/AdaptableOptions/DataSetOptions.d.ts +2 -0
- package/src/AdaptableOptions/DefaultAdaptableOptions.js +35 -3
- package/src/AdaptableOptions/EditOptions.d.ts +0 -1
- package/src/AdaptableOptions/EntitlementOptions.d.ts +0 -2
- package/src/AdaptableOptions/ExportOptions.d.ts +1 -7
- package/src/AdaptableOptions/ExpressionOptions.d.ts +0 -18
- package/src/AdaptableOptions/Fdc3Options.d.ts +5 -1
- package/src/AdaptableOptions/FilterOptions.d.ts +3 -18
- package/src/AdaptableOptions/NoteOptions.d.ts +6 -0
- package/src/AdaptableOptions/NotificationsOptions.d.ts +0 -10
- package/src/AdaptableOptions/PredicateOptions.d.ts +12 -1
- package/src/AdaptableOptions/QuickSearchOptions.d.ts +0 -4
- package/src/AdaptableOptions/SettingsPanelOptions.d.ts +15 -5
- package/src/AdaptableOptions/TeamSharingOptions.d.ts +0 -4
- package/src/AdaptableOptions/ToolPanelOptions.d.ts +0 -1
- package/src/AdaptableOptions/UserInterfaceOptions.d.ts +6 -7
- package/src/AdaptableState/Common/AdaptableFormat.d.ts +9 -0
- package/src/AdaptableState/Common/AdaptableFormatPresets.d.ts +31 -0
- package/src/AdaptableState/Common/AdaptableFormatPresets.js +181 -0
- package/src/AdaptableState/Common/Menu.d.ts +1 -1
- package/src/AdaptableState/Common/Menu.js +2 -0
- package/src/AdaptableState/FormatColumnState.d.ts +6 -3
- package/src/Api/EventApi.d.ts +6 -6
- package/src/Api/Implementation/EntitlementApiImpl.js +5 -4
- package/src/Api/Implementation/FormatColumnApiImpl.js +8 -3
- package/src/Api/Implementation/GridApiImpl.js +1 -12
- package/src/Api/Internal/FormatColumnInternalApi.js +4 -2
- package/src/Api/Internal/LayoutInternalApi.js +5 -2
- package/src/Redux/Store/AdaptableStore.js +4 -4
- package/src/Strategy/AdaptableModuleBase.js +8 -7
- package/src/Strategy/AlertModule.d.ts +1 -1
- package/src/Strategy/BulkUpdateModule.d.ts +1 -1
- package/src/Strategy/BulkUpdateModule.js +2 -1
- package/src/Strategy/CalculatedColumnModule.d.ts +1 -1
- package/src/Strategy/CellSummaryModule.d.ts +1 -1
- package/src/Strategy/CellSummaryModule.js +2 -1
- package/src/Strategy/ColumnFilterModule.js +7 -3
- package/src/Strategy/ColumnInfoModule.d.ts +1 -1
- package/src/Strategy/ColumnInfoModule.js +2 -1
- package/src/Strategy/CommentModule.d.ts +1 -1
- package/src/Strategy/CommentModule.js +12 -2
- package/src/Strategy/ExportModule.d.ts +1 -1
- package/src/Strategy/Fdc3Module.d.ts +1 -1
- package/src/Strategy/FlashingCellModule.d.ts +1 -1
- package/src/Strategy/GridFilterModule.js +2 -1
- package/src/Strategy/GridInfoModule.d.ts +1 -1
- package/src/Strategy/GridInfoModule.js +2 -1
- package/src/Strategy/LayoutModule.d.ts +1 -1
- package/src/Strategy/NamedQueryModule.js +0 -16
- package/src/Strategy/NoteModule.d.ts +1 -1
- package/src/Strategy/NoteModule.js +16 -3
- package/src/Strategy/PlusMinusModule.js +8 -2
- package/src/Strategy/ScheduleModule.js +5 -4
- package/src/Strategy/SettingsPanelModule.d.ts +1 -1
- package/src/Strategy/ShortcutModule.js +5 -4
- package/src/Strategy/SmartEditModule.d.ts +1 -1
- package/src/Strategy/SmartEditModule.js +4 -4
- package/src/Strategy/SystemStatusModule.d.ts +1 -1
- package/src/Utilities/Constants/GeneralConstants.d.ts +4 -0
- package/src/Utilities/Constants/GeneralConstants.js +4 -0
- package/src/Utilities/Extensions/NumberExtensions.d.ts +2 -0
- package/src/Utilities/Extensions/NumberExtensions.js +8 -0
- package/src/Utilities/Helpers/AdaptableHelper.js +3 -2
- package/src/Utilities/Helpers/FormatHelper.js +26 -15
- package/src/Utilities/Services/AnnotationsService.js +10 -1
- package/src/Utilities/Services/Interface/IMetamodelService.d.ts +0 -1
- package/src/Utilities/Services/MetamodelService.d.ts +0 -2
- package/src/Utilities/Services/MetamodelService.js +6 -12
- package/src/View/AdaptableWizardView/AdaptableConfigurationDialog/EntitlementsForm.js +7 -6
- package/src/View/Alert/AlertEmptyView.js +2 -1
- package/src/View/BulkUpdate/BulkUpdateViewPanel.js +1 -1
- package/src/View/CellSummary/CellSummaryViewPanel.js +2 -1
- package/src/View/Comments/CommentsEditor.js +2 -1
- package/src/View/Comments/CommentsPopup.js +3 -1
- package/src/View/Components/Buttons/ButtonBase/index.js +3 -2
- package/src/View/Components/Buttons/EntityListActionButtons.js +7 -6
- package/src/View/Components/Buttons/SuspendToggleButton/SuspendToggleButton.js +2 -1
- package/src/View/Components/ColumnFilter/components/ColumnFilterInput.js +3 -2
- package/src/View/Components/ColumnFilter/components/ColumnFilterInputList.js +4 -1
- package/src/View/Components/Panels/PanelDashboard/index.js +2 -1
- package/src/View/Components/Popups/AdaptablePopup/AdaptablePopup.js +4 -2
- package/src/View/Components/Popups/AdaptablePopup/AdaptablePopupModuleView.js +2 -1
- package/src/View/Components/ToolPanel/AdaptableToolPanel.js +3 -2
- package/src/View/Components/ToolPanel/CustomToolPanelContent.js +2 -1
- package/src/View/Dashboard/CustomDashboardButton.js +3 -2
- package/src/View/Dashboard/Dashboard.js +3 -2
- package/src/View/Dashboard/DashboardPopup.js +3 -2
- package/src/View/Dashboard/PinnedToolbarsSelector.js +2 -1
- package/src/View/DataChangeHistory/DataChangeHistoryGrid.js +2 -1
- package/src/View/Export/ExportViewPanel.js +3 -1
- package/src/View/Filter/FilterViewPanel.js +2 -1
- package/src/View/FormatColumn/Wizard/FormatColumnFormatWizardSection.js +137 -181
- package/src/View/FormatColumn/Wizard/FormatColumnWizard.js +20 -8
- package/src/View/GridFilter/GridFilterPopupUI/index.d.ts +3 -2
- package/src/View/GridFilter/GridFilterPopupUI/index.js +2 -1
- package/src/View/GridFilter/GridFilterViewPanel.js +3 -2
- package/src/View/GridInfo/GridInfoPopup/GridInfoPopup.js +179 -6
- package/src/View/Layout/LayoutCloneButton.js +2 -1
- package/src/View/Layout/LayoutViewPanel.js +3 -1
- package/src/View/Layout/TransposedPopup.js +2 -1
- package/src/View/Layout/Wizard/sections/RowSelectionSection.js +6 -6
- package/src/View/Note/NotePopup.js +3 -1
- package/src/View/SmartEdit/SmartEditViewPanel.js +2 -1
- package/src/View/StateManagement/StateManagementViewPanel.js +3 -1
- package/src/View/StatusBar/StatusBarPopup.js +2 -1
- package/src/View/Theme/ThemeEditor.js +2 -1
- package/src/View/Theme/ThemePopup.js +2 -1
- package/src/View/Theme/ThemeSelector.js +3 -1
- package/src/View/Theme/ThemeViewPanel.js +3 -1
- package/src/View/Wizard/OnePageWizards.js +3 -2
- package/src/agGrid/AdaptableAgGrid.d.ts +2 -2
- package/src/agGrid/AdaptableAgGrid.js +7 -29
- package/src/agGrid/AgGridAdapter.js +2 -2
- package/src/agGrid/AgGridColumnAdapter.js +11 -4
- package/src/agGrid/AgGridExportAdapter.js +4 -2
- package/src/agGrid/cellRenderers/ActionColumnRenderer.js +2 -1
- package/src/components/Dashboard/Dashboard.js +2 -1
- package/src/components/Dashboard/DashboardToolbar.js +2 -1
- package/src/components/Datepicker/index.js +2 -1
- package/src/components/ExpressionEditor/QueryBuilder/QueryBuilderInputs.js +1 -1
- package/src/components/Select/Select.js +4 -3
- package/src/components/SimpleButton/index.js +3 -2
- package/src/env.js +2 -2
- package/src/metamodel/adaptable-metamodel-model.d.ts +0 -2
- package/src/metamodel/adaptable.metamodel.d.ts +10 -197
- package/src/metamodel/adaptable.metamodel.js +1 -1
- package/src/types.d.ts +2 -0
- package/src/types.js +1 -0
- package/themes/dark.css +3 -1
- package/tsconfig.esm.tsbuildinfo +1 -1
- package/index.css.map +0 -1
|
@@ -7,6 +7,7 @@ import { ButtonClear } from '../Components/Buttons/ButtonClear';
|
|
|
7
7
|
import { CheckBox } from '../../components/CheckBox';
|
|
8
8
|
import { connect } from 'react-redux';
|
|
9
9
|
import { getColumnFiltersSelector } from '../../Redux/ActionsReducers/LayoutRedux';
|
|
10
|
+
import { ACCESS_LEVEL_READ_ONLY } from '../../Utilities/Constants/GeneralConstants';
|
|
10
11
|
import SimpleButton from '../../components/SimpleButton';
|
|
11
12
|
import join from '../../components/utils/join';
|
|
12
13
|
import { Flex } from '../../components/Flex';
|
|
@@ -31,7 +32,7 @@ class FilterViewPanelComponent extends React.Component {
|
|
|
31
32
|
ArrayExtensions.IsNotNullOrEmpty(this.props.ColumnFilters) && (React.createElement(AdaptablePopover, { popupPadding: 0, className: `ab-${elementType}__Filter__info`, headerText: "", bodyText: [React.createElement(ActiveFiltersPanel, null)], useButton: true, showEvent: 'focus', hideEvent: "blur", popoverMinWidth: 400 })),
|
|
32
33
|
React.createElement(ButtonClear, { "aria-label": 'Clear Filters', className: `ab-${elementType}__Filter__clear twa:mx-1 twa:mb-0`, onClick: () => this.onClearFilters(), tooltip: "Clear Filters", disabled: this.props.ColumnFilters.length == 0, showText: this.props.viewType === 'ToolPanel' }, this.props.viewType === 'ToolPanel' && 'Clear'),
|
|
33
34
|
React.createElement(SimpleButton, { "aria-label": isAtLeastOneFilterActive ? 'Suspend All Filters' : 'Resume All Filters', className: join(`ab-${elementType}__Filter__suspend-button`, isAtLeastOneFilterActive && `ab-${elementType}__Filter__suspend-all`, !isAtLeastOneFilterActive && `ab-${elementType}__Filter__un-suspend-all`), disabled: !isAtLeastOneFilter, onClick: handleSuspendUnsuspendAll, tone: isAtLeastOneFilterActive ? 'neutral' : 'success', variant: "text", icon: isAtLeastOneFilterActive ? 'pause' : 'play', accessLevel: this.props.accessLevel })),
|
|
34
|
-
React.createElement(Flex, { alignItems: "center" }, this.props.api.filterApi.columnFilterApi.isQuickFilterAvailable() && (React.createElement(CheckBox, { "data-name": "quick-filter-toggle", className: `ab-${elementType}__Filter__active-check twa:my-0 twa:text-2 twa:p-1`, disabled: this.props.accessLevel ===
|
|
35
|
+
React.createElement(Flex, { alignItems: "center" }, this.props.api.filterApi.columnFilterApi.isQuickFilterAvailable() && (React.createElement(CheckBox, { "data-name": "quick-filter-toggle", className: `ab-${elementType}__Filter__active-check twa:my-0 twa:text-2 twa:p-1`, disabled: this.props.accessLevel === ACCESS_LEVEL_READ_ONLY ||
|
|
35
36
|
this.props.api.layoutApi.isCurrentLayoutPivot(), checked: this.props.IsQuickFilterVisible, onChange: (checked) => {
|
|
36
37
|
checked ? this.props.onShowQuickFilterBar() : this.props.onHideQuickFilterBar();
|
|
37
38
|
} }, "Filter Bar")))));
|
|
@@ -4,6 +4,7 @@ import clamp from '../../../Utilities/utils/clamp';
|
|
|
4
4
|
import HelpBlock from '../../../components/HelpBlock';
|
|
5
5
|
import Input from '../../../components/Input';
|
|
6
6
|
import SimpleButton from '../../../components/SimpleButton';
|
|
7
|
+
import { isAdaptableNumericFormatPreset, resolveDisplayFormat, } from '../../../AdaptableState/Common/AdaptableFormatPresets';
|
|
7
8
|
import { CheckBox } from '../../../components/CheckBox';
|
|
8
9
|
import FormLayout, { FormRow } from '../../../components/FormLayout';
|
|
9
10
|
import { AdaptableObjectRow } from '../../Components/AdaptableObjectRow';
|
|
@@ -22,56 +23,6 @@ import { FormatColumnPlaceholderDocsLink } from '../../../Utilities/Constants/Do
|
|
|
22
23
|
import { PIVOT_AGGREGATION_TOTAL_COLUMN_TYPE, PIVOT_ANY_TOTAL_COLUMN_TYPE, PIVOT_COLUMN_TOTAL_COLUMN_TYPE, PIVOT_GRAND_TOTAL_COLUMN_TYPE, } from '../../../AdaptableState/Common/AdaptableColumn';
|
|
23
24
|
import { Box, Flex } from '../../../components/Flex';
|
|
24
25
|
import { Card } from '../../../components/Card';
|
|
25
|
-
const DOLLAR_OPTIONS = {
|
|
26
|
-
FractionDigits: 2,
|
|
27
|
-
FractionSeparator: '.',
|
|
28
|
-
IntegerDigits: undefined,
|
|
29
|
-
IntegerSeparator: ',',
|
|
30
|
-
Prefix: '$',
|
|
31
|
-
Suffix: '',
|
|
32
|
-
Multiplier: 1,
|
|
33
|
-
Parentheses: false,
|
|
34
|
-
};
|
|
35
|
-
const STERLING_OPTIONS = {
|
|
36
|
-
FractionDigits: 2,
|
|
37
|
-
FractionSeparator: '.',
|
|
38
|
-
IntegerDigits: undefined,
|
|
39
|
-
IntegerSeparator: ',',
|
|
40
|
-
Prefix: '£',
|
|
41
|
-
Suffix: '',
|
|
42
|
-
Multiplier: 1,
|
|
43
|
-
Parentheses: false,
|
|
44
|
-
};
|
|
45
|
-
const MILLION_OPTIONS = {
|
|
46
|
-
FractionDigits: undefined,
|
|
47
|
-
FractionSeparator: '.',
|
|
48
|
-
IntegerDigits: undefined,
|
|
49
|
-
IntegerSeparator: ',',
|
|
50
|
-
Prefix: '',
|
|
51
|
-
Suffix: 'M',
|
|
52
|
-
Multiplier: 0.000001,
|
|
53
|
-
Parentheses: false,
|
|
54
|
-
};
|
|
55
|
-
const THOUSAND_OPTIONS = {
|
|
56
|
-
FractionDigits: undefined,
|
|
57
|
-
FractionSeparator: '.',
|
|
58
|
-
IntegerDigits: undefined,
|
|
59
|
-
IntegerSeparator: ',',
|
|
60
|
-
Prefix: '',
|
|
61
|
-
Suffix: 'K',
|
|
62
|
-
Multiplier: 0.001,
|
|
63
|
-
Parentheses: false,
|
|
64
|
-
};
|
|
65
|
-
const PERCENT_OPTIONS = {
|
|
66
|
-
FractionDigits: 2,
|
|
67
|
-
FractionSeparator: '.',
|
|
68
|
-
IntegerDigits: undefined,
|
|
69
|
-
IntegerSeparator: ',',
|
|
70
|
-
Prefix: '',
|
|
71
|
-
Suffix: '%',
|
|
72
|
-
Multiplier: 100,
|
|
73
|
-
Parentheses: false,
|
|
74
|
-
};
|
|
75
26
|
const DateFormatPresets = [
|
|
76
27
|
'MM/dd/yyyy',
|
|
77
28
|
'dd-MM-yyyy',
|
|
@@ -83,33 +34,37 @@ const DateFormatPresets = [
|
|
|
83
34
|
];
|
|
84
35
|
export const getFormatColumnFormatSummaryValue = (data) => {
|
|
85
36
|
let content = 'N/A';
|
|
86
|
-
|
|
37
|
+
const resolved = resolveDisplayFormat(data.DisplayFormat);
|
|
38
|
+
if (!resolved) {
|
|
87
39
|
content = 'N/A';
|
|
88
40
|
}
|
|
89
41
|
else {
|
|
90
|
-
if (
|
|
91
|
-
content = FormatHelper.NumberFormatter(DEFAULT_DOUBLE_DISPLAY_VALUE,
|
|
42
|
+
if (resolved.Formatter === 'NumberFormatter') {
|
|
43
|
+
content = FormatHelper.NumberFormatter(DEFAULT_DOUBLE_DISPLAY_VALUE, resolved.Options);
|
|
92
44
|
}
|
|
93
|
-
if (
|
|
94
|
-
content = FormatHelper.DateFormatter(new Date(),
|
|
45
|
+
if (resolved.Formatter === 'DateFormatter') {
|
|
46
|
+
content = FormatHelper.DateFormatter(new Date(), resolved.Options);
|
|
95
47
|
}
|
|
96
|
-
if (
|
|
97
|
-
content = FormatHelper.StringFormatter(DEFAULT_STRING_DISPLAY_VALUE,
|
|
48
|
+
if (resolved.Formatter === 'StringFormatter') {
|
|
49
|
+
content = FormatHelper.StringFormatter(DEFAULT_STRING_DISPLAY_VALUE, resolved.Options);
|
|
98
50
|
}
|
|
99
51
|
}
|
|
100
52
|
return content;
|
|
101
53
|
};
|
|
102
|
-
const renderCustomFormatter = (data, customFormatter, setFormatOption) =>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
newCustomFormats = [
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
54
|
+
const renderCustomFormatter = (data, customFormatter, setFormatOption) => {
|
|
55
|
+
const resolved = resolveDisplayFormat(data.DisplayFormat);
|
|
56
|
+
return (React.createElement(FormRow, { key: customFormatter.id, label: customFormatter.label ?? customFormatter.id },
|
|
57
|
+
React.createElement(CheckBox, { "data-name": customFormatter.id, checked: resolved?.Options.CustomDisplayFormats?.some?.((item) => item === customFormatter.id), onChange: (checked) => {
|
|
58
|
+
let newCustomFormats = resolved?.Options?.CustomDisplayFormats ?? [];
|
|
59
|
+
if (checked) {
|
|
60
|
+
newCustomFormats = [...newCustomFormats, customFormatter.id];
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
newCustomFormats = newCustomFormats.filter((item) => item !== customFormatter.id);
|
|
64
|
+
}
|
|
65
|
+
setFormatOption('CustomDisplayFormats', newCustomFormats);
|
|
66
|
+
} })));
|
|
67
|
+
};
|
|
113
68
|
export const renderFormatColumnFormatSummary = (data) => {
|
|
114
69
|
return React.createElement(Tag, null, getFormatColumnFormatSummaryValue(data));
|
|
115
70
|
};
|
|
@@ -209,7 +164,8 @@ export const getFormatDisplayTypeForScope = (scope, api) => {
|
|
|
209
164
|
return undefined;
|
|
210
165
|
};
|
|
211
166
|
const renderDateFormat = (data, _onChange, setFormatOption, scopedCustomFormatters) => {
|
|
212
|
-
|
|
167
|
+
const resolved = resolveDisplayFormat(data.DisplayFormat);
|
|
168
|
+
if (resolved?.Formatter !== 'DateFormatter') {
|
|
213
169
|
return null;
|
|
214
170
|
}
|
|
215
171
|
return (React.createElement(Box, { className: "twa:p-2" },
|
|
@@ -223,9 +179,9 @@ const renderDateFormat = (data, _onChange, setFormatOption, scopedCustomFormatte
|
|
|
223
179
|
")."),
|
|
224
180
|
React.createElement(FormLayout, null,
|
|
225
181
|
React.createElement(FormRow, { label: "Pattern" },
|
|
226
|
-
React.createElement(Input, { "data-name": "pattern", value:
|
|
227
|
-
React.createElement("span", null,
|
|
228
|
-
FormatHelper.DateFormatter(new Date(),
|
|
182
|
+
React.createElement(Input, { "data-name": "pattern", value: resolved.Options.Pattern ?? '', onChange: (e) => setFormatOption('Pattern', e.currentTarget.value), className: "twa:mr-2" }),
|
|
183
|
+
React.createElement("span", null, resolved.Options.Pattern &&
|
|
184
|
+
FormatHelper.DateFormatter(new Date(), resolved.Options, true)))))),
|
|
229
185
|
scopedCustomFormatters.length > 0 && (React.createElement(Tabs, { className: "twa:mt-2", keyboardNavigation: false },
|
|
230
186
|
React.createElement(Tabs.Tab, null, "Custom Formats"),
|
|
231
187
|
React.createElement(Tabs.Content, null,
|
|
@@ -251,128 +207,113 @@ const renderDateFormat = (data, _onChange, setFormatOption, scopedCustomFormatte
|
|
|
251
207
|
] })))))));
|
|
252
208
|
};
|
|
253
209
|
const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatters, api) => {
|
|
254
|
-
|
|
210
|
+
const resolved = resolveDisplayFormat(data.DisplayFormat);
|
|
211
|
+
if (resolved?.Formatter !== 'NumberFormatter') {
|
|
255
212
|
return null;
|
|
256
213
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
});
|
|
264
|
-
};
|
|
265
|
-
const setDivideThousandPreset = () => {
|
|
266
|
-
onChange({
|
|
267
|
-
DisplayFormat: {
|
|
268
|
-
Formatter: 'NumberFormatter',
|
|
269
|
-
Options: THOUSAND_OPTIONS,
|
|
270
|
-
},
|
|
271
|
-
});
|
|
272
|
-
};
|
|
273
|
-
const setDivideMillionPreset = () => {
|
|
274
|
-
onChange({
|
|
275
|
-
DisplayFormat: {
|
|
276
|
-
Formatter: 'NumberFormatter',
|
|
277
|
-
Options: MILLION_OPTIONS,
|
|
278
|
-
},
|
|
279
|
-
});
|
|
280
|
-
};
|
|
281
|
-
const setDollarPreset = () => {
|
|
282
|
-
onChange({
|
|
283
|
-
DisplayFormat: {
|
|
284
|
-
Formatter: 'NumberFormatter',
|
|
285
|
-
Options: DOLLAR_OPTIONS,
|
|
286
|
-
},
|
|
287
|
-
});
|
|
288
|
-
};
|
|
289
|
-
const setSterlingPreset = () => {
|
|
290
|
-
onChange({
|
|
291
|
-
DisplayFormat: {
|
|
292
|
-
Formatter: 'NumberFormatter',
|
|
293
|
-
Options: STERLING_OPTIONS,
|
|
294
|
-
},
|
|
295
|
-
});
|
|
214
|
+
// A preset is now stored as a bare string ('Percentage', 'Dollar', ...)
|
|
215
|
+
// — selecting a preset just writes the name. The active preset is
|
|
216
|
+
// therefore a simple string comparison instead of the old fragile
|
|
217
|
+
// suffix/multiplier heuristic.
|
|
218
|
+
const setPreset = (preset) => {
|
|
219
|
+
onChange({ DisplayFormat: preset });
|
|
296
220
|
};
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
const IS_THOUSAND =
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
const IS_DOLLAR =
|
|
304
|
-
const IS_STERLING =
|
|
221
|
+
const activePreset = isAdaptableNumericFormatPreset(data.DisplayFormat) ? data.DisplayFormat : undefined;
|
|
222
|
+
const IS_PERCENT = activePreset === 'Percentage';
|
|
223
|
+
const IS_THOUSAND = activePreset === 'Thousand';
|
|
224
|
+
const IS_MILLION = activePreset === 'Million';
|
|
225
|
+
const IS_BILLION = activePreset === 'Billion';
|
|
226
|
+
const IS_BASIS_POINTS = activePreset === 'BasisPoints';
|
|
227
|
+
const IS_DOLLAR = activePreset === 'Dollar';
|
|
228
|
+
const IS_STERLING = activePreset === 'Sterling';
|
|
229
|
+
const IS_EURO = activePreset === 'Euro';
|
|
230
|
+
const IS_YEN = activePreset === 'Yen';
|
|
231
|
+
const IS_BITCOIN = activePreset === 'Bitcoin';
|
|
232
|
+
const IS_INTEGER = activePreset === 'Integer';
|
|
233
|
+
const IS_DECIMAL = activePreset === 'Decimal';
|
|
234
|
+
const IS_ACCOUNTING = activePreset === 'Accounting';
|
|
235
|
+
const IS_FX_RATE = activePreset === 'FXRate';
|
|
236
|
+
const IS_SCIENTIFIC = activePreset === 'Scientific';
|
|
305
237
|
const showDocumentationLinks = api.internalApi.isDocumentationLinksDisplayed();
|
|
306
238
|
return (React.createElement(Box, { "data-name": 'format-column-display-format', className: "twa:p-2" },
|
|
307
|
-
React.createElement(Tabs,
|
|
239
|
+
React.createElement(Tabs, { autoFocus: false, keyboardNavigation: false },
|
|
240
|
+
React.createElement(Tabs.Tab, null, "Presets"),
|
|
241
|
+
React.createElement(Tabs.Content, null,
|
|
242
|
+
React.createElement(Flex, { flexDirection: "row", className: "twa:m-2" },
|
|
243
|
+
React.createElement(Flex, { flexDirection: "column", className: "twa:mr-6" },
|
|
244
|
+
React.createElement(Radio, { "data-name": "preset-dollar", className: "twa:my-1", checked: IS_DOLLAR, onChange: () => setPreset('Dollar') }, "Dollar"),
|
|
245
|
+
React.createElement(Radio, { "data-name": "preset-sterling", className: "twa:my-1", checked: IS_STERLING, onChange: () => setPreset('Sterling') }, "Sterling"),
|
|
246
|
+
React.createElement(Radio, { "data-name": "preset-euro", className: "twa:my-1", checked: IS_EURO, onChange: () => setPreset('Euro') }, "Euro"),
|
|
247
|
+
React.createElement(Radio, { "data-name": "preset-yen", className: "twa:my-1", checked: IS_YEN, onChange: () => setPreset('Yen') }, "Yen")),
|
|
248
|
+
React.createElement(Flex, { flexDirection: "column", className: "twa:mr-6" },
|
|
249
|
+
React.createElement(Radio, { "data-name": "preset-thousand", className: "twa:my-1", checked: IS_THOUSAND, onChange: () => setPreset('Thousand') }, "K (Thousand)"),
|
|
250
|
+
React.createElement(Radio, { "data-name": "preset-million", className: "twa:my-1", checked: IS_MILLION, onChange: () => setPreset('Million') }, "M (Million)"),
|
|
251
|
+
React.createElement(Radio, { "data-name": "preset-billion", className: "twa:my-1", checked: IS_BILLION, onChange: () => setPreset('Billion') }, "B (Billion)"),
|
|
252
|
+
React.createElement(Radio, { "data-name": "preset-basis-points", className: "twa:my-1", checked: IS_BASIS_POINTS, onChange: () => setPreset('BasisPoints') }, "bps (Basis Pts)")),
|
|
253
|
+
React.createElement(Flex, { flexDirection: "column", className: "twa:mr-6" },
|
|
254
|
+
React.createElement(Radio, { "data-name": "preset-integer", className: "twa:my-1", checked: IS_INTEGER, onChange: () => setPreset('Integer') }, "Integer"),
|
|
255
|
+
React.createElement(Radio, { "data-name": "preset-decimal", className: "twa:my-1", checked: IS_DECIMAL, onChange: () => setPreset('Decimal') }, "Decimal"),
|
|
256
|
+
React.createElement(Radio, { "data-name": "preset-percentage", className: "twa:my-1", checked: IS_PERCENT, onChange: () => setPreset('Percentage') }, "Percentage"),
|
|
257
|
+
React.createElement(Radio, { "data-name": "preset-scientific", className: "twa:my-1", checked: IS_SCIENTIFIC, onChange: () => setPreset('Scientific') }, "Scientific")),
|
|
258
|
+
React.createElement(Flex, { flexDirection: "column" },
|
|
259
|
+
React.createElement(Radio, { "data-name": "preset-accounting", className: "twa:my-1", checked: IS_ACCOUNTING, onChange: () => setPreset('Accounting') }, "Accounting"),
|
|
260
|
+
React.createElement(Radio, { "data-name": "preset-fx-rate", className: "twa:my-1", checked: IS_FX_RATE, onChange: () => setPreset('FXRate') }, "FX Rate"),
|
|
261
|
+
React.createElement(Radio, { "data-name": "preset-bitcoin", className: "twa:my-1", checked: IS_BITCOIN, onChange: () => setPreset('Bitcoin') }, "Bitcoin"))))),
|
|
262
|
+
React.createElement(Tabs, { className: "twa:mt-2" },
|
|
308
263
|
React.createElement(Tabs.Tab, null, "Format"),
|
|
309
264
|
React.createElement(Tabs.Content, null,
|
|
310
265
|
React.createElement(Flex, { flexDirection: "row" },
|
|
311
266
|
React.createElement(FormLayout, { className: "twa:mr-3" },
|
|
312
|
-
React.createElement(FormRow, { label: "Fraction Separator" },
|
|
313
|
-
React.createElement(Input, { "data-name": "fraction-separator", value: data.DisplayFormat.Options.FractionSeparator ?? '', onChange: (e) => setFormatOption('FractionSeparator', e.currentTarget.value) }),
|
|
314
|
-
' '),
|
|
315
|
-
React.createElement(FormRow, { label: "Integer Separator" },
|
|
316
|
-
React.createElement(Input, { "data-name": "integer-separator", value: data.DisplayFormat.Options.IntegerSeparator ?? '', onChange: (e) => setFormatOption('IntegerSeparator', e.currentTarget.value) })),
|
|
317
|
-
React.createElement(FormRow, { label: "Prefix" },
|
|
318
|
-
React.createElement(Input, { "data-name": "prefix", value: data.DisplayFormat.Options.Prefix ?? '', onChange: (e) => setFormatOption('Prefix', e.currentTarget.value) })),
|
|
319
|
-
React.createElement(FormRow, { label: "Suffix" },
|
|
320
|
-
React.createElement(Input, { "data-name": "suffix", value: data.DisplayFormat.Options.Suffix ?? '', onChange: (e) => setFormatOption('Suffix', e.currentTarget.value) })),
|
|
321
|
-
React.createElement(FormRow, { label: "Truncate" },
|
|
322
|
-
React.createElement(CheckBox, { "data-name": "truncate-checkbox", checked: data.DisplayFormat.Options.Truncate, onChange: (checked) => setFormatOption('Truncate', checked) })),
|
|
323
|
-
React.createElement(FormRow, { label: "Ceiling" },
|
|
324
|
-
React.createElement(CheckBox, { "data-name": "ceiling-checkbox", checked: data.DisplayFormat.Options.Ceiling, onChange: (checked) => setFormatOption('Ceiling', checked) })),
|
|
325
|
-
' ',
|
|
326
|
-
React.createElement(FormRow, { label: "Absolute" },
|
|
327
|
-
React.createElement(CheckBox, { "data-name": "abs-checkbox", checked: data.DisplayFormat.Options.Abs, onChange: (checked) => setFormatOption('Abs', checked) }))),
|
|
328
|
-
React.createElement(FormLayout, null,
|
|
329
267
|
React.createElement(FormRow, { label: "Fraction Digits" },
|
|
330
|
-
React.createElement(Input, { "data-name": "fraction-digits", type: "number", min: "0",
|
|
331
|
-
|
|
332
|
-
value: typeof data.DisplayFormat.Options.FractionDigits === 'number'
|
|
333
|
-
? data.DisplayFormat.Options.FractionDigits
|
|
268
|
+
React.createElement(Input, { "data-name": "fraction-digits", type: "number", min: "0", value: typeof resolved.Options.FractionDigits === 'number'
|
|
269
|
+
? resolved.Options.FractionDigits
|
|
334
270
|
: '', onChange: (e) => setFormatOption('FractionDigits', StringExtensions.IsNumeric(e.currentTarget.value)
|
|
335
271
|
? clamp(Number(e.currentTarget.value), 0, 20)
|
|
336
272
|
: undefined) })),
|
|
337
273
|
React.createElement(FormRow, { label: "Integer Digits" },
|
|
338
|
-
React.createElement(Input, { "data-name": "integer-digits", type: "number", min: "0", value:
|
|
274
|
+
React.createElement(Input, { "data-name": "integer-digits", type: "number", min: "0", value: resolved.Options.IntegerDigits, onChange: (e) => setFormatOption('IntegerDigits', StringExtensions.IsNumeric(e.currentTarget.value)
|
|
339
275
|
? clamp(Number(e.currentTarget.value), 0, 20)
|
|
340
276
|
: undefined) })),
|
|
277
|
+
React.createElement(FormRow, { label: "Fraction Separator" },
|
|
278
|
+
React.createElement(Input, { "data-name": "fraction-separator", value: resolved.Options.FractionSeparator ?? '', onChange: (e) => setFormatOption('FractionSeparator', e.currentTarget.value) })),
|
|
279
|
+
React.createElement(FormRow, { label: "Integer Separator" },
|
|
280
|
+
React.createElement(Input, { "data-name": "integer-separator", value: resolved.Options.IntegerSeparator ?? '', onChange: (e) => setFormatOption('IntegerSeparator', e.currentTarget.value) })),
|
|
341
281
|
React.createElement(FormRow, { label: "Multiplier" },
|
|
342
|
-
React.createElement(Input, { "data-name": "multiplier", type: "number", value:
|
|
343
|
-
|
|
282
|
+
React.createElement(Input, { "data-name": "multiplier", type: "number", value: resolved.Options.Multiplier, onChange: (e) => setFormatOption('Multiplier', Number(e.currentTarget.value)) }))),
|
|
283
|
+
React.createElement(FormLayout, { className: "twa:mr-3" },
|
|
284
|
+
React.createElement(FormRow, { label: "Prefix" },
|
|
285
|
+
React.createElement(Input, { "data-name": "prefix", value: resolved.Options.Prefix ?? '', onChange: (e) => setFormatOption('Prefix', e.currentTarget.value) })),
|
|
286
|
+
React.createElement(FormRow, { label: "Suffix" },
|
|
287
|
+
React.createElement(Input, { "data-name": "suffix", value: resolved.Options.Suffix ?? '', onChange: (e) => setFormatOption('Suffix', e.currentTarget.value) })),
|
|
344
288
|
React.createElement(FormRow, { label: "Parentheses" },
|
|
345
|
-
React.createElement(CheckBox, { "data-name": "parentheses-checkbox", checked:
|
|
346
|
-
React.createElement(FormRow, { label: "Floor" },
|
|
347
|
-
React.createElement(CheckBox, { "data-name": "floor-checkbox", checked: data.DisplayFormat.Options.Floor, onChange: (checked) => setFormatOption('Floor', checked) })),
|
|
348
|
-
React.createElement(FormRow, { label: "Round" },
|
|
349
|
-
React.createElement(CheckBox, { "data-name": "round-checkbox", checked: data.DisplayFormat.Options.Round, onChange: (checked) => setFormatOption('Round', checked) })),
|
|
289
|
+
React.createElement(CheckBox, { "data-name": "parentheses-checkbox", checked: resolved.Options.Parentheses, onChange: (checked) => setFormatOption('Parentheses', checked) })),
|
|
350
290
|
React.createElement(FormRow, { label: "Empty" },
|
|
351
|
-
React.createElement(CheckBox, { "data-name": "empty-checkbox", checked:
|
|
291
|
+
React.createElement(CheckBox, { "data-name": "empty-checkbox", checked: resolved.Options.Empty, onChange: (checked) => setFormatOption('Empty', checked) }))),
|
|
292
|
+
React.createElement(FormLayout, null,
|
|
293
|
+
React.createElement(FormRow, { label: "Truncate" },
|
|
294
|
+
React.createElement(CheckBox, { "data-name": "truncate-checkbox", checked: resolved.Options.Truncate, onChange: (checked) => setFormatOption('Truncate', checked) })),
|
|
295
|
+
React.createElement(FormRow, { label: "Round" },
|
|
296
|
+
React.createElement(CheckBox, { "data-name": "round-checkbox", checked: resolved.Options.Round, onChange: (checked) => setFormatOption('Round', checked) })),
|
|
297
|
+
React.createElement(FormRow, { label: "Ceiling" },
|
|
298
|
+
React.createElement(CheckBox, { "data-name": "ceiling-checkbox", checked: resolved.Options.Ceiling, onChange: (checked) => setFormatOption('Ceiling', checked) })),
|
|
299
|
+
React.createElement(FormRow, { label: "Floor" },
|
|
300
|
+
React.createElement(CheckBox, { "data-name": "floor-checkbox", checked: resolved.Options.Floor, onChange: (checked) => setFormatOption('Floor', checked) })),
|
|
301
|
+
React.createElement(FormRow, { label: "Absolute" },
|
|
302
|
+
React.createElement(CheckBox, { "data-name": "abs-checkbox", checked: resolved.Options.Abs, onChange: (checked) => setFormatOption('Abs', checked) })),
|
|
303
|
+
React.createElement(FormRow, { label: "Scientific" },
|
|
304
|
+
React.createElement(CheckBox, { "data-name": "scientific-checkbox", checked: resolved.Options.Notation === 'scientific', onChange: (checked) => setFormatOption('Notation', checked ? 'scientific' : undefined) })))))),
|
|
352
305
|
scopedCustomFormatters.length > 0 && (React.createElement(Tabs, { className: "twa:mt-2", keyboardNavigation: false },
|
|
353
306
|
React.createElement(Tabs.Tab, null, "Custom Formats"),
|
|
354
307
|
React.createElement(Tabs.Content, null,
|
|
355
308
|
React.createElement(Flex, { flexDirection: "row" },
|
|
356
309
|
React.createElement(FormLayout, null, scopedCustomFormatters.map((formatter) => renderCustomFormatter(data, formatter, setFormatOption))))))),
|
|
357
|
-
React.createElement(Tabs, { className: "twa:mt-2", autoFocus: false, keyboardNavigation: false },
|
|
358
|
-
React.createElement(Tabs.Tab, null, "Presets"),
|
|
359
|
-
React.createElement(Tabs.Content, null,
|
|
360
|
-
React.createElement(Box, { className: "twa:p-2 twa:text-2" }, "Select a preset for common use cases"),
|
|
361
|
-
React.createElement(Flex, { flexDirection: "row" },
|
|
362
|
-
React.createElement(FormLayout, { className: "twa:m-2" },
|
|
363
|
-
React.createElement(FormRow, { label: "Show As:" },
|
|
364
|
-
React.createElement(Radio, { "data-name": "preset-percentage", className: "twa:ml-2", checked: IS_PERCENT, onChange: () => setPercentPreset() }, "Percentage"),
|
|
365
|
-
React.createElement(Radio, { "data-name": "preset-thousand", className: "twa:ml-3", checked: IS_THOUSAND, onChange: () => setDivideThousandPreset() }, "K (Thousand)"),
|
|
366
|
-
React.createElement(Radio, { "data-name": "preset-million", className: "twa:ml-3", checked: IS_MILLION, onChange: () => setDivideMillionPreset() }, "M (Million)"),
|
|
367
|
-
React.createElement(Radio, { "data-name": "preset-dollar", className: "twa:ml-3", checked: IS_DOLLAR, onChange: () => setDollarPreset() }, "Dollar"),
|
|
368
|
-
React.createElement(Radio, { "data-name": "preset-sterling", className: "twa:ml-3", checked: IS_STERLING, onChange: () => setSterlingPreset() }, "Sterling")))))),
|
|
369
310
|
React.createElement(Tabs, { className: "twa:mt-2", autoFocus: false, keyboardNavigation: false },
|
|
370
311
|
React.createElement(Tabs.Tab, null, "Dynamic Content"),
|
|
371
312
|
React.createElement(Tabs.Content, null,
|
|
372
313
|
React.createElement(Box, { className: "twa:p-2 twa:text-2" }, "Provide dynamic content through the use of Placeholders"),
|
|
373
314
|
React.createElement(FormLayout, { className: "twa:m-2" },
|
|
374
315
|
React.createElement(FormRow, { label: "" },
|
|
375
|
-
React.createElement(Textarea, { className: "twa:min-w-[300px] twa:mt-2", rows: 3, placeholder: "", type: 'text', autoFocus: false, value:
|
|
316
|
+
React.createElement(Textarea, { className: "twa:min-w-[300px] twa:mt-2", rows: 3, placeholder: "", type: 'text', autoFocus: false, value: resolved.Options.Content?.toString() ?? '', onChange: (e) => setFormatOption('Content', e.currentTarget.value) }),
|
|
376
317
|
showDocumentationLinks && (React.createElement(HelpBlock, { "data-name": "query-documentation", className: "twa:mt-3 twa:mb-2 twa:p-0 twa:text-3" },
|
|
377
318
|
React.createElement(ButtonInfo, { className: "twa:mr-2", onClick: () => window.open(FormatColumnPlaceholderDocsLink, '_blank') }),
|
|
378
319
|
"Learn more about using placeholders"))),
|
|
@@ -387,27 +328,28 @@ const renderNumberFormat = (data, onChange, setFormatOption, scopedCustomFormatt
|
|
|
387
328
|
React.createElement(AdaptableObjectRow, { colItems: [
|
|
388
329
|
{ Content: DEFAULT_DOUBLE_DISPLAY_VALUE, Size: 1 },
|
|
389
330
|
{
|
|
390
|
-
Content: FormatHelper.NumberFormatter(DEFAULT_DOUBLE_DISPLAY_VALUE,
|
|
331
|
+
Content: FormatHelper.NumberFormatter(DEFAULT_DOUBLE_DISPLAY_VALUE, resolved.Options),
|
|
391
332
|
Size: 1,
|
|
392
333
|
},
|
|
393
334
|
] }),
|
|
394
335
|
React.createElement(AdaptableObjectRow, { colItems: [
|
|
395
336
|
{ Content: '-' + DEFAULT_DOUBLE_DISPLAY_VALUE, Size: 1 },
|
|
396
337
|
{
|
|
397
|
-
Content: FormatHelper.NumberFormatter(-DEFAULT_DOUBLE_DISPLAY_VALUE,
|
|
338
|
+
Content: FormatHelper.NumberFormatter(-DEFAULT_DOUBLE_DISPLAY_VALUE, resolved.Options),
|
|
398
339
|
Size: 1,
|
|
399
340
|
},
|
|
400
341
|
] }),
|
|
401
342
|
React.createElement(AdaptableObjectRow, { colItems: [
|
|
402
343
|
{ Content: '0.123', Size: 1 },
|
|
403
344
|
{
|
|
404
|
-
Content: FormatHelper.NumberFormatter(0.123,
|
|
345
|
+
Content: FormatHelper.NumberFormatter(0.123, resolved.Options),
|
|
405
346
|
Size: 1,
|
|
406
347
|
},
|
|
407
348
|
] })))));
|
|
408
349
|
};
|
|
409
350
|
const renderStringFormat = (data, _onChange, setFormatOption, scopedCustomFormatters, api) => {
|
|
410
|
-
|
|
351
|
+
const resolved = resolveDisplayFormat(data.DisplayFormat);
|
|
352
|
+
if (resolved?.Formatter !== 'StringFormatter') {
|
|
411
353
|
return null;
|
|
412
354
|
}
|
|
413
355
|
const showDocumentationLinks = api.internalApi.isDocumentationLinksDisplayed();
|
|
@@ -418,23 +360,23 @@ const renderStringFormat = (data, _onChange, setFormatOption, scopedCustomFormat
|
|
|
418
360
|
React.createElement(Flex, { flexDirection: "row", className: "twa:gap-2 twa:col-span-2 twa:items-center" },
|
|
419
361
|
React.createElement("label", null, "Case:"),
|
|
420
362
|
React.createElement(ToggleGroup, null,
|
|
421
|
-
React.createElement(Toggle, { pressed:
|
|
422
|
-
React.createElement(Toggle, { pressed:
|
|
423
|
-
React.createElement(Toggle, { pressed:
|
|
424
|
-
React.createElement(CheckBox, { "data-name": "trim-checkbox", className: "twa:ml-5", checked:
|
|
363
|
+
React.createElement(Toggle, { pressed: resolved.Options.Case === 'Upper', onPressedChange: (pressed) => setFormatOption('Case', pressed ? 'Upper' : undefined), icon: "case-upper" }),
|
|
364
|
+
React.createElement(Toggle, { pressed: resolved.Options.Case === 'Lower', onPressedChange: (pressed) => setFormatOption('Case', pressed ? 'Lower' : undefined), icon: "case-lower" }),
|
|
365
|
+
React.createElement(Toggle, { pressed: resolved.Options.Case === 'Sentence', onPressedChange: (pressed) => setFormatOption('Case', pressed ? 'Sentence' : undefined), icon: "case-sentence" })),
|
|
366
|
+
React.createElement(CheckBox, { "data-name": "trim-checkbox", className: "twa:ml-5", checked: resolved.Options.Trim, onChange: (checked) => setFormatOption('Trim', checked) }, "Trim")),
|
|
425
367
|
React.createElement(Flex, { flexDirection: "column", className: "twa:gap-2" },
|
|
426
368
|
React.createElement("label", null, "Prefix"),
|
|
427
|
-
React.createElement(Input, { "data-name": "prefix", value:
|
|
369
|
+
React.createElement(Input, { "data-name": "prefix", value: resolved.Options.Prefix ?? '', onChange: (e) => setFormatOption('Prefix', e.currentTarget.value) })),
|
|
428
370
|
React.createElement(Flex, { flexDirection: "column", className: "twa:gap-2" },
|
|
429
371
|
React.createElement("label", null, "Suffix"),
|
|
430
|
-
React.createElement(Input, { "data-name": "suffix", value:
|
|
372
|
+
React.createElement(Input, { "data-name": "suffix", value: resolved.Options.Suffix ?? '', onChange: (e) => setFormatOption('Suffix', e.currentTarget.value) })),
|
|
431
373
|
React.createElement(Flex, { flexDirection: "column", className: "twa:col-span-2 twa:gap-2" },
|
|
432
374
|
React.createElement("label", null, "Content"),
|
|
433
|
-
React.createElement(Textarea, { className: "twa:min-w-[300px]", rows: 3, placeholder: "", type: 'text', autoFocus: false, value:
|
|
375
|
+
React.createElement(Textarea, { className: "twa:min-w-[300px]", rows: 3, placeholder: "", type: 'text', autoFocus: false, value: resolved.Options.Content ?? '', onChange: (e) => setFormatOption('Content', e.currentTarget.value) }),
|
|
434
376
|
showDocumentationLinks && (React.createElement(HelpBlock, { "data-name": "query-documentation", className: "twa:mt-3 twa:mb-2 twa:p-0 twa:text-3" },
|
|
435
377
|
React.createElement(ButtonInfo, { className: "twa:mr-2", onClick: () => window.open(FormatColumnPlaceholderDocsLink, '_blank') }),
|
|
436
378
|
"See how to create dynamic Display Format using placeholders"))),
|
|
437
|
-
React.createElement(CheckBox, { className: "twa:col-span-2", "data-name": "empty-checkbox", checked:
|
|
379
|
+
React.createElement(CheckBox, { className: "twa:col-span-2", "data-name": "empty-checkbox", checked: resolved.Options.Empty, onChange: (checked) => setFormatOption('Empty', checked) }, "Empty"))),
|
|
438
380
|
scopedCustomFormatters.length > 0 && (React.createElement(Card, { shadow: false },
|
|
439
381
|
React.createElement(Card.Title, null, "Custom Formats"),
|
|
440
382
|
React.createElement(Card.Body, null,
|
|
@@ -451,7 +393,7 @@ const renderStringFormat = (data, _onChange, setFormatOption, scopedCustomFormat
|
|
|
451
393
|
{ Content: '"' + DEFAULT_STRING_DISPLAY_VALUE + '"', Size: 1 },
|
|
452
394
|
{
|
|
453
395
|
Content: '"' +
|
|
454
|
-
FormatHelper.StringFormatter(DEFAULT_STRING_DISPLAY_VALUE,
|
|
396
|
+
FormatHelper.StringFormatter(DEFAULT_STRING_DISPLAY_VALUE, resolved.Options) +
|
|
455
397
|
'"',
|
|
456
398
|
Size: 1,
|
|
457
399
|
},
|
|
@@ -466,12 +408,26 @@ export const FormatColumnFormatWizardSection = (props) => {
|
|
|
466
408
|
props.onChange({ ...data, ...updated });
|
|
467
409
|
};
|
|
468
410
|
const setFormatOption = (key, value) => {
|
|
469
|
-
|
|
470
|
-
//
|
|
471
|
-
|
|
411
|
+
// If the user is currently on a preset (e.g. 'Dollar'), materialise
|
|
412
|
+
// it into a concrete AdaptableFormat *before* applying the edit so
|
|
413
|
+
// that tweaking any field "forks" the preset into a bespoke format.
|
|
414
|
+
const current = resolveDisplayFormat(data.DisplayFormat);
|
|
415
|
+
if (!current)
|
|
416
|
+
return;
|
|
417
|
+
// The cast is safe: we copy `current.Formatter` and merge into
|
|
418
|
+
// `current.Options`, so the discriminant and the Options shape
|
|
419
|
+
// are always kept in sync — TypeScript just can't correlate the
|
|
420
|
+
// two ends of the discriminated union across a generic merge.
|
|
421
|
+
const DisplayFormat = {
|
|
422
|
+
Formatter: current.Formatter,
|
|
423
|
+
Options: { ...current.Options, [key]: value },
|
|
424
|
+
};
|
|
472
425
|
update({ DisplayFormat });
|
|
473
426
|
};
|
|
474
|
-
|
|
427
|
+
// A preset string is logically a NumberFormatter for this routing.
|
|
428
|
+
const Type = isAdaptableNumericFormatPreset(data.DisplayFormat)
|
|
429
|
+
? 'NumberFormatter'
|
|
430
|
+
: data.DisplayFormat && data.DisplayFormat.Formatter;
|
|
475
431
|
const customScopedFormatters = customDisplayFormatters.filter((displayFormatter) => adaptable.api.columnScopeApi.isScopeInScope(data.Scope, displayFormatter.scope));
|
|
476
432
|
if (Type === 'NumberFormatter') {
|
|
477
433
|
return renderNumberFormat(data, update, setFormatOption, customScopedFormatters, adaptable.api);
|
|
@@ -18,6 +18,7 @@ import { isAdaptableRuleValid } from '../../Components/EntityRulesEditor/Utiliti
|
|
|
18
18
|
import { FormatColumnRuleWizardSection } from './FormatColumnRuleWizardSection';
|
|
19
19
|
import { DEFAULT_PREDICATE_ID_FOR_FORMAT_COLUMN } from './constants';
|
|
20
20
|
import { isObjectEmpty } from '../../../Utilities/Extensions/ObjectExtensions';
|
|
21
|
+
import { isAdaptableNumericFormatPreset, } from '../../../AdaptableState/Common/AdaptableFormatPresets';
|
|
21
22
|
import { Box, Flex } from '../../../components/Flex';
|
|
22
23
|
const adjustDisplayFormat = (fc, api) => {
|
|
23
24
|
const formatColumn = { ...fc };
|
|
@@ -41,22 +42,26 @@ const adjustDisplayFormat = (fc, api) => {
|
|
|
41
42
|
if (!formatDataType && formatColumn.DisplayFormat) {
|
|
42
43
|
formatColumn.DisplayFormat = undefined;
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
// For shape-detection purposes a numeric preset name is equivalent to a
|
|
46
|
+
// NumberFormatter. We only need to materialise an object literal when
|
|
47
|
+
// there is no DisplayFormat at all (or the existing one targets a
|
|
48
|
+
// different Formatter type to the new scope).
|
|
49
|
+
const resolvedFormatter = isAdaptableNumericFormatPreset(formatColumn.DisplayFormat)
|
|
50
|
+
? 'NumberFormatter'
|
|
51
|
+
: formatColumn.DisplayFormat?.Formatter;
|
|
52
|
+
if (resolvedFormatter !== 'NumberFormatter' && formatDataType === 'number') {
|
|
46
53
|
formatColumn.DisplayFormat = {
|
|
47
54
|
Formatter: 'NumberFormatter',
|
|
48
55
|
Options: {},
|
|
49
56
|
};
|
|
50
57
|
}
|
|
51
|
-
if (
|
|
52
|
-
formatDataType === 'date') {
|
|
58
|
+
if (resolvedFormatter !== 'DateFormatter' && formatDataType === 'date') {
|
|
53
59
|
formatColumn.DisplayFormat = {
|
|
54
60
|
Formatter: 'DateFormatter',
|
|
55
61
|
Options: {},
|
|
56
62
|
};
|
|
57
63
|
}
|
|
58
|
-
if (
|
|
59
|
-
formatDataType === 'text') {
|
|
64
|
+
if (resolvedFormatter !== 'StringFormatter' && formatDataType === 'text') {
|
|
60
65
|
formatColumn.DisplayFormat = {
|
|
61
66
|
Formatter: 'StringFormatter',
|
|
62
67
|
Options: {},
|
|
@@ -90,8 +95,15 @@ export function FormatColumnWizard(props) {
|
|
|
90
95
|
}, []);
|
|
91
96
|
const dispatch = useDispatch();
|
|
92
97
|
const handleFinish = () => {
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
// If the user opened the wizard, picked a Formatter type, but never
|
|
99
|
+
// touched any options (and didn't pick a preset), drop the empty
|
|
100
|
+
// DisplayFormat object so we don't persist an empty shell. Preset
|
|
101
|
+
// strings are always meaningful and should never be removed here.
|
|
102
|
+
const df = formatColumn?.DisplayFormat;
|
|
103
|
+
if (df &&
|
|
104
|
+
!isAdaptableNumericFormatPreset(df) &&
|
|
105
|
+
df.Options &&
|
|
106
|
+
isObjectEmpty(df.Options)) {
|
|
95
107
|
delete formatColumn.DisplayFormat;
|
|
96
108
|
}
|
|
97
109
|
if (formatColumn.Style && isObjectEmpty(formatColumn.Style)) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { NamedQuery, CachedQuery } from '../../../AdaptableState/NamedQueryState';
|
|
3
|
+
import { AccessLevel } from '../../../AdaptableState/Common/Entitlement';
|
|
3
4
|
/**
|
|
4
5
|
* Column item for the dropdown menu
|
|
5
6
|
*/
|
|
@@ -61,8 +62,8 @@ export interface GridFilterPopupUIProps {
|
|
|
61
62
|
/** Called when setting the grid filter expression directly */
|
|
62
63
|
onSetGridFilterExpression: (query: string) => void;
|
|
63
64
|
/** Access level for grid filter operations */
|
|
64
|
-
gridFilterAccessLevel:
|
|
65
|
+
gridFilterAccessLevel: AccessLevel;
|
|
65
66
|
/** Access level for named query operations */
|
|
66
|
-
namedQueryAccessLevel:
|
|
67
|
+
namedQueryAccessLevel: AccessLevel;
|
|
67
68
|
}
|
|
68
69
|
export declare const GridFilterPopupUI: (props: GridFilterPopupUIProps) => React.JSX.Element;
|
|
@@ -14,9 +14,10 @@ import { ButtonUnsuspend } from '../../Components/Buttons/ButtonUnsuspend';
|
|
|
14
14
|
import { PopupPanel } from '../../Components/Popups/AdaptablePopup/PopupPanel';
|
|
15
15
|
import { NamedQuerySelector } from './../NamedQuerySelector';
|
|
16
16
|
import { Box, Flex } from '../../../components/Flex';
|
|
17
|
+
import { ACCESS_LEVEL_READ_ONLY } from '../../../Utilities/Constants/GeneralConstants';
|
|
17
18
|
export const GridFilterPopupUI = (props) => {
|
|
18
19
|
const { expression, isExpressionValid, isExpressionNamedQuery, isSuspended, isReadOnly, availableColumns, namedQueries, cachedQueries, currentGridFilterExpression, headerText, glyphicon, infoLink, infoLinkDisabled, onExpressionChange, onRunQuery, onClearQuery, onSaveQuery, onSuspend, onUnsuspend, onExpand, onSelectNamedQuery, onSetGridFilterExpression, gridFilterAccessLevel, namedQueryAccessLevel, } = props;
|
|
19
|
-
const disabled = isReadOnly || isSuspended || gridFilterAccessLevel ===
|
|
20
|
+
const disabled = isReadOnly || isSuspended || gridFilterAccessLevel === ACCESS_LEVEL_READ_ONLY;
|
|
20
21
|
const handleKeyDown = (e) => {
|
|
21
22
|
if (e.key === 'Enter') {
|
|
22
23
|
onRunQuery();
|
|
@@ -12,13 +12,14 @@ import { NamedQuerySelector } from './NamedQuerySelector';
|
|
|
12
12
|
import { useGridFilterExpressionEditor } from './useGridFilterExpressionEditor';
|
|
13
13
|
import { Box, Flex } from '../../components/Flex';
|
|
14
14
|
import Tooltip from '../../components/Tooltip';
|
|
15
|
+
import { ACCESS_LEVEL_READ_ONLY } from '../../Utilities/Constants/GeneralConstants';
|
|
15
16
|
const QueryViewPanelComponent = (props) => {
|
|
16
17
|
const { cachedQueries, expression, isExpressionNamedQuery, isExpressionValid, isSuspended, gridFilter, isAdaptableReady, namedQueries, runQuery, onExpand, clearQuery, namedQueryModuleAccessLevel, saveQuery, suspendGridFilter, unSuspendGridFilter, setGridFilterExpression, gridFilterAccessLevel, isReadOnly, } = useGridFilterExpressionEditor();
|
|
17
18
|
if (!isAdaptableReady) {
|
|
18
19
|
return null;
|
|
19
20
|
}
|
|
20
21
|
const elementType = props.viewType === 'Toolbar' ? 'DashboardToolbar' : 'ToolPanel';
|
|
21
|
-
const disabled = isReadOnly || isSuspended || gridFilterAccessLevel ===
|
|
22
|
+
const disabled = isReadOnly || isSuspended || gridFilterAccessLevel === ACCESS_LEVEL_READ_ONLY;
|
|
22
23
|
const buttonExpand = (React.createElement(ButtonExpand, { disabled: disabled, accessLevel: gridFilterAccessLevel, variant: "text", tone: "neutral", onClick: onExpand, tooltip: "Edit the Expression in UI", className: "twa:ml-1" }));
|
|
23
24
|
const renderExpressionLabel = () => {
|
|
24
25
|
const baseClasses = 'twa:font-mono twa:text-s twa:py-2 twa:px-2 twa:overflow-hidden twa:text-ellipsis twa:whitespace-nowrap twa:bg-defaultbackground twa:text-text-on-defaultbackground twa:rounded twa:cursor-pointer twa:leading-4 twa:flex twa:items-center';
|
|
@@ -37,7 +38,7 @@ const QueryViewPanelComponent = (props) => {
|
|
|
37
38
|
const hasActiveGridFilter = gridFilter != null && hasExpression;
|
|
38
39
|
const hasNamedQueries = namedQueries && namedQueries.length > 0;
|
|
39
40
|
const clearButton = hasExpression ? (React.createElement(ButtonClear, { onClick: () => clearQuery(), tooltip: "Clear Grid Filter", accessLevel: gridFilterAccessLevel, variant: "text", tone: "neutral" })) : null;
|
|
40
|
-
const saveButton = hasExpression ? (React.createElement(ButtonSave, { onClick: () => saveQuery(), tooltip: "Save as Named Query", accessLevel: namedQueryModuleAccessLevel, disabled: isReadOnly || gridFilterAccessLevel ===
|
|
41
|
+
const saveButton = hasExpression ? (React.createElement(ButtonSave, { onClick: () => saveQuery(), tooltip: "Save as Named Query", accessLevel: namedQueryModuleAccessLevel, disabled: isReadOnly || gridFilterAccessLevel === ACCESS_LEVEL_READ_ONLY || !isExpressionValid || isExpressionNamedQuery, variant: "text", tone: "neutral" })) : null;
|
|
41
42
|
const suspendButton = hasActiveGridFilter ? (React.createElement(ButtonPause, { onClick: () => suspendGridFilter(), tooltip: "Suspend Grid Filter", accessLevel: gridFilterAccessLevel, disabled: disabled || !isExpressionValid, variant: "text", tone: "neutral" })) : null;
|
|
42
43
|
const unSuspendButton = hasActiveGridFilter ? (React.createElement(ButtonUnsuspend, { onClick: () => unSuspendGridFilter(), tooltip: "Unsuspend Grid Filter", accessLevel: gridFilterAccessLevel, disabled: !isExpressionValid, variant: "text", tone: "neutral" })) : null;
|
|
43
44
|
const namedQuerySelector = hasNamedQueries ? (React.createElement(NamedQuerySelector, { namedQueries: namedQueries, cachedQueries: cachedQueries, currentQuery: gridFilter?.Expression, onSelect: (query) => runQuery(query), setGridFilterExpression: (query) => setGridFilterExpression(query) })) : null;
|