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