@adaptabletools/adaptable 15.0.0-canary.1 → 15.0.0-canary.2
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/bundle.cjs.js +210 -210
- package/package.json +1 -1
- package/publishTimestamp.d.ts +1 -1
- package/publishTimestamp.js +1 -1
- package/src/AdaptableInterfaces/IAdaptable.d.ts +2 -2
- package/src/AdaptableOptions/ActionOptions.d.ts +30 -30
- package/src/AdaptableOptions/AdaptableOptions.d.ts +13 -13
- package/src/AdaptableOptions/AdaptableQLOptions.d.ts +4 -4
- package/src/AdaptableOptions/AlertOptions.d.ts +14 -14
- package/src/AdaptableOptions/ChartingOptions.d.ts +2 -3
- package/src/AdaptableOptions/DataChangeHistoryOptions.d.ts +6 -6
- package/src/AdaptableOptions/EditOptions.d.ts +8 -8
- package/src/AdaptableOptions/ExportOptions.d.ts +1 -1
- package/src/AdaptableOptions/ExpressionOptions.d.ts +1 -1
- package/src/AdaptableOptions/FilterOptions.d.ts +3 -3
- package/src/AdaptableOptions/GeneralOptions.d.ts +9 -9
- package/src/AdaptableOptions/MenuOptions.d.ts +3 -3
- package/src/AdaptableOptions/PredicateOptions.d.ts +1 -1
- package/src/AdaptableOptions/SearchOptions.d.ts +2 -2
- package/src/AdaptableOptions/UserInterfaceOptions.d.ts +23 -23
- package/src/Api/ChartingApi.d.ts +18 -19
- package/src/Api/EventApi.d.ts +13 -1
- package/src/Api/Events/ActionRowSubmitted.d.ts +7 -7
- package/src/Api/Events/GridDataChanged.d.ts +3 -3
- package/src/Api/Events/ThemeChanged.d.ts +6 -0
- package/src/Api/GridApi.d.ts +4 -4
- package/src/Api/Implementation/ColumnApiImpl.d.ts +1 -1
- package/src/Api/Implementation/ThemeApiImpl.d.ts +4 -0
- package/src/Api/Implementation/ThemeApiImpl.js +14 -0
- package/src/Api/OptionsApi.d.ts +1 -1
- package/src/Api/ThemeApi.d.ts +18 -0
- package/src/PredefinedConfig/Common/AdaptableAlert.d.ts +7 -7
- package/src/PredefinedConfig/Common/AdaptableColumn.d.ts +2 -2
- package/src/PredefinedConfig/Common/AdaptableComparerFunction.d.ts +4 -4
- package/src/PredefinedConfig/Common/CellDataChangedInfo.d.ts +4 -4
- package/src/PredefinedConfig/Common/CellSummary.d.ts +4 -4
- package/src/PredefinedConfig/Common/Menu.d.ts +8 -8
- package/src/PredefinedConfig/Selection/GridCell.d.ts +3 -3
- package/src/PredefinedConfig/Selection/GridRow.d.ts +3 -3
- package/src/PredefinedConfig/Selection/SelectedCellInfo.d.ts +3 -3
- package/src/PredefinedConfig/Selection/SelectedRowInfo.d.ts +2 -2
- package/src/PredefinedConfig/StatusBarState.d.ts +1 -1
- package/src/PredefinedConfig/StatusBarState.js +1 -1
- package/src/PredefinedConfig/SystemState.d.ts +1 -2
- package/src/PredefinedConfig/ThemeState.d.ts +4 -0
- package/src/Redux/ActionsReducers/GridRedux.d.ts +2 -2
- package/src/Redux/ActionsReducers/ThemeRedux.d.ts +27 -0
- package/src/Redux/ActionsReducers/ThemeRedux.js +63 -1
- package/src/Strategy/ExportModule.js +1 -1
- package/src/Utilities/Constants/GeneralConstants.d.ts +1 -0
- package/src/Utilities/Constants/GeneralConstants.js +3 -2
- package/src/Utilities/Defaults/DefaultAdaptableOptions.js +1 -1
- package/src/Utilities/Defaults/DefaultSettingsPanel.js +2 -2
- package/src/Utilities/ObjectFactory.d.ts +3 -1
- package/src/Utilities/ObjectFactory.js +10 -1
- package/src/Utilities/Services/Interface/IThemeService.d.ts +3 -0
- package/src/Utilities/Services/Interface/IThemeService.js +2 -0
- package/src/Utilities/Services/MetamodelService.d.ts +2 -0
- package/src/Utilities/Services/MetamodelService.js +26 -19
- package/src/Utilities/Services/ThemeService.d.ts +12 -0
- package/src/Utilities/Services/ThemeService.js +49 -0
- package/src/View/AdaptableWizardView/AdaptableConfigurationDialog/AdaptableOptionsForm.js +5 -5
- package/src/View/Charting/ShowChartButton.js +2 -1
- package/src/View/Charting/useChartingElements.js +2 -1
- package/src/View/Components/FilterForm/QuickFilterForm.js +1 -1
- package/src/View/Components/ToolPanel/AdaptableToolPanel.js +1 -1
- package/src/View/DataChangeHistory/buildActionColumnButton.d.ts +1 -1
- package/src/View/Theme/ThemeEditor.d.ts +7 -0
- package/src/View/Theme/ThemeEditor.js +186 -0
- package/src/View/Theme/ThemePopup.d.ts +3 -0
- package/src/View/Theme/ThemePopup.js +30 -6
- package/src/agGrid/Adaptable.d.ts +3 -2
- package/src/agGrid/Adaptable.js +8 -17
- package/src/agGrid/createAgStatusPanelComponent.js +1 -1
- package/src/metamodel/adaptable-metamodel-model.d.ts +9 -9
- package/src/metamodel/adaptable.metamodel.d.ts +1698 -3141
- package/src/metamodel/adaptable.metamodel.js +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
|
@@ -7,14 +7,7 @@ const DefaultAdaptableOptions_1 = require("../Defaults/DefaultAdaptableOptions")
|
|
|
7
7
|
const LoggingHelper_1 = require("../Helpers/LoggingHelper");
|
|
8
8
|
const DocumentationLinkConstants_1 = require("../Constants/DocumentationLinkConstants");
|
|
9
9
|
const StringExtensions_1 = tslib_1.__importDefault(require("../Extensions/StringExtensions"));
|
|
10
|
-
const supportedMetamodelTypes = [
|
|
11
|
-
'string',
|
|
12
|
-
'number',
|
|
13
|
-
'boolean',
|
|
14
|
-
'array',
|
|
15
|
-
'function',
|
|
16
|
-
'REFERENCE',
|
|
17
|
-
];
|
|
10
|
+
const supportedMetamodelTypes = ['s', 'n', 'b', 'a', 'f', 'R'];
|
|
18
11
|
class MetamodelService {
|
|
19
12
|
constructor(getAdaptableOptions) {
|
|
20
13
|
this.gridInfoOptions = new Map();
|
|
@@ -57,23 +50,23 @@ class MetamodelService {
|
|
|
57
50
|
validateOptionsObject(validationErrors, optionsObjectName, optionsObject, optionsObjectMetamodel, optionsObjectDefaultValues) {
|
|
58
51
|
Object.entries(optionsObject).forEach(([optionKey, optionValue]) => {
|
|
59
52
|
var _a;
|
|
60
|
-
const optionMetamodel = (_a = optionsObjectMetamodel === null || optionsObjectMetamodel === void 0 ? void 0 : optionsObjectMetamodel.
|
|
53
|
+
const optionMetamodel = (_a = optionsObjectMetamodel === null || optionsObjectMetamodel === void 0 ? void 0 : optionsObjectMetamodel.props) === null || _a === void 0 ? void 0 : _a.find((metamodelProperty) => metamodelProperty.name === optionKey);
|
|
61
54
|
if (!optionMetamodel) {
|
|
62
55
|
validationErrors.push(`${optionsObjectName}.${optionKey} (value=${optionValue}) :: unknown/unsupported property, will be ignored`);
|
|
63
56
|
return;
|
|
64
57
|
}
|
|
65
58
|
// let's try to validate the type of the provided value
|
|
66
59
|
const expectedOptionsValueType = this.getExpectedOptionsValueType(optionMetamodel);
|
|
67
|
-
const providedOptionsValueType = Array.isArray(optionValue) ? '
|
|
60
|
+
const providedOptionsValueType = Array.isArray(optionValue) ? 'a' : typeof optionValue;
|
|
68
61
|
if (!expectedOptionsValueType) {
|
|
69
62
|
return;
|
|
70
63
|
}
|
|
71
64
|
// if it's a REFERENCE, we try to go (recursively) deeper
|
|
72
|
-
if (expectedOptionsValueType === '
|
|
73
|
-
const referenceObjectName = optionMetamodel.
|
|
65
|
+
if (expectedOptionsValueType === 'R') {
|
|
66
|
+
const referenceObjectName = optionMetamodel.ref;
|
|
74
67
|
const referenceObject = optionsObject[optionKey];
|
|
75
68
|
const referenceObjectMetamodel = this.getAdaptableMetamodel()[referenceObjectName];
|
|
76
|
-
if (referenceObject && (referenceObjectMetamodel === null || referenceObjectMetamodel === void 0 ? void 0 : referenceObjectMetamodel.kind) === '
|
|
69
|
+
if (referenceObject && (referenceObjectMetamodel === null || referenceObjectMetamodel === void 0 ? void 0 : referenceObjectMetamodel.kind) === 'I') {
|
|
77
70
|
this.validateOptionsObject(validationErrors, referenceObjectName, referenceObject, referenceObjectMetamodel, optionsObjectDefaultValues === null || optionsObjectDefaultValues === void 0 ? void 0 : optionsObjectDefaultValues[optionKey]);
|
|
78
71
|
}
|
|
79
72
|
}
|
|
@@ -107,10 +100,10 @@ class MetamodelService {
|
|
|
107
100
|
items: baseOptionsItems,
|
|
108
101
|
});
|
|
109
102
|
// map containers
|
|
110
|
-
adaptableOptionsMetamodel.
|
|
103
|
+
adaptableOptionsMetamodel.props
|
|
111
104
|
.filter((optionItem) => optionItem.gridInfo === 'container')
|
|
112
105
|
.forEach((containerOptionItem) => {
|
|
113
|
-
const containerMetamodelName = containerOptionItem.
|
|
106
|
+
const containerMetamodelName = containerOptionItem.ref;
|
|
114
107
|
const adaptableOptionsName = containerOptionItem.name;
|
|
115
108
|
const containerOptionsMetamodel = adaptableMetamodel[containerMetamodelName];
|
|
116
109
|
// @ts-ignore
|
|
@@ -125,21 +118,21 @@ class MetamodelService {
|
|
|
125
118
|
}
|
|
126
119
|
const optionItems = this.mapGridInfoContainerItems(containerOptionsMetamodel, containerOptionsValues, containerOptionsDefaultValues, filterItemProperty);
|
|
127
120
|
gridInfoOptions.set(containerOptionItem.name, {
|
|
128
|
-
containerLabel: containerOptionItem
|
|
121
|
+
containerLabel: this.extractUiLabel(containerOptionItem),
|
|
129
122
|
items: optionItems,
|
|
130
123
|
});
|
|
131
124
|
});
|
|
132
125
|
return gridInfoOptions;
|
|
133
126
|
}
|
|
134
127
|
mapGridInfoContainerItems(optionItemContainer, adaptableOptionsValues, defaultAdaptableOptionsValues, filter = (itemProperty) => itemProperty.gridInfo === 'item') {
|
|
135
|
-
return optionItemContainer.
|
|
128
|
+
return optionItemContainer.props.filter(filter).map((itemProperty) => {
|
|
136
129
|
return {
|
|
137
130
|
name: itemProperty.name,
|
|
138
131
|
value: adaptableOptionsValues === null || adaptableOptionsValues === void 0 ? void 0 : adaptableOptionsValues[itemProperty.name],
|
|
139
132
|
defaultValue: defaultAdaptableOptionsValues[itemProperty.name],
|
|
140
133
|
kind: itemProperty.kind,
|
|
141
|
-
description: StringExtensions_1.default.UnescapeHtmlEntities(itemProperty.
|
|
142
|
-
uiLabel: itemProperty
|
|
134
|
+
description: StringExtensions_1.default.UnescapeHtmlEntities(itemProperty.desc),
|
|
135
|
+
uiLabel: this.extractUiLabel(itemProperty),
|
|
143
136
|
};
|
|
144
137
|
});
|
|
145
138
|
}
|
|
@@ -152,5 +145,19 @@ class MetamodelService {
|
|
|
152
145
|
getAdaptableOptionsMetamodel() {
|
|
153
146
|
return this.getAdaptableMetamodel()['AdaptableOptions'];
|
|
154
147
|
}
|
|
148
|
+
extractUiLabel(item) {
|
|
149
|
+
return item.uiLabel || this.formatCamelCaseToHumanText(item.name);
|
|
150
|
+
}
|
|
151
|
+
formatCamelCaseToHumanText(camelCase) {
|
|
152
|
+
if (!camelCase || camelCase == null) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const rex = /([A-Z])([A-Z])([a-z])|([a-z])([A-Z])/g;
|
|
156
|
+
const words = camelCase.replace(rex, '$1$4 $2$3$5').replace('.', ' ').split(' ');
|
|
157
|
+
return words
|
|
158
|
+
.map((word) => word.substring(0, 1).toUpperCase() +
|
|
159
|
+
(word.length > 1 ? word.substring(1, word.length) : ''))
|
|
160
|
+
.join(' ');
|
|
161
|
+
}
|
|
155
162
|
}
|
|
156
163
|
exports.MetamodelService = MetamodelService;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AdaptableApi, AdaptableTheme } from '../../types';
|
|
2
|
+
import { IThemeService } from './Interface/IThemeService';
|
|
3
|
+
export declare class ThemeService implements IThemeService {
|
|
4
|
+
private api;
|
|
5
|
+
private unsubscribe;
|
|
6
|
+
private styleSheetObject;
|
|
7
|
+
constructor(api: AdaptableApi);
|
|
8
|
+
subscribe(): void;
|
|
9
|
+
onThemeChanged: () => void;
|
|
10
|
+
applyNewThemeVariables(theme: AdaptableTheme): void;
|
|
11
|
+
destroy(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ThemeService = void 0;
|
|
4
|
+
class ThemeService {
|
|
5
|
+
constructor(api) {
|
|
6
|
+
var _a;
|
|
7
|
+
this.unsubscribe = () => { };
|
|
8
|
+
this.onThemeChanged = () => {
|
|
9
|
+
const currentTheme = this.api.themeApi.getCurrentThemeObject();
|
|
10
|
+
this.applyNewThemeVariables(currentTheme);
|
|
11
|
+
};
|
|
12
|
+
this.api = api;
|
|
13
|
+
this.subscribe();
|
|
14
|
+
if (!this.styleSheetObject) {
|
|
15
|
+
this.styleSheetObject = new CSSStyleSheet();
|
|
16
|
+
// ts does not know about adoptedStyleSheets
|
|
17
|
+
document.adoptedStyleSheets = [
|
|
18
|
+
...((_a = document.adoptedStyleSheets) !== null && _a !== void 0 ? _a : []),
|
|
19
|
+
this.styleSheetObject,
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
subscribe() {
|
|
24
|
+
const themeChangedUnsubscribe = this.api.eventApi.on('ThemeChanged', this.onThemeChanged);
|
|
25
|
+
const themeEditedUnsubscribe = this.api.eventApi.on('ThemeEdited', this.onThemeChanged);
|
|
26
|
+
this.unsubscribe = () => {
|
|
27
|
+
themeChangedUnsubscribe();
|
|
28
|
+
themeEditedUnsubscribe();
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
applyNewThemeVariables(theme) {
|
|
32
|
+
var _a;
|
|
33
|
+
const variables = (_a = theme.CSSVariables) !== null && _a !== void 0 ? _a : {};
|
|
34
|
+
let str = ':root {';
|
|
35
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
36
|
+
if (key.includes('--')) {
|
|
37
|
+
str += `${key}: ${value};`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
str += '}';
|
|
41
|
+
this.styleSheetObject.replaceSync(str);
|
|
42
|
+
}
|
|
43
|
+
destroy() {
|
|
44
|
+
this.api = null;
|
|
45
|
+
this.unsubscribe();
|
|
46
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets].filter((sheet) => sheet !== this.styleSheetObject);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.ThemeService = ThemeService;
|
|
@@ -12,7 +12,7 @@ const StringExtensions_1 = tslib_1.__importDefault(require("../../../Utilities/E
|
|
|
12
12
|
const MetamodelService_1 = require("../../../Utilities/Services/MetamodelService");
|
|
13
13
|
const AdaptablePopover_1 = require("../../AdaptablePopover");
|
|
14
14
|
const LABEL_WIDTH = 250;
|
|
15
|
-
const SUPPORTED_PRIMITEVE_TYPES = ['
|
|
15
|
+
const SUPPORTED_PRIMITEVE_TYPES = ['s', 'n', 'b'];
|
|
16
16
|
const OptionInput = (props) => {
|
|
17
17
|
const { name, defaultValue, value, description, uiLabel } = props.option;
|
|
18
18
|
const label = uiLabel !== null && uiLabel !== void 0 ? uiLabel : StringExtensions_1.default.Humanize(name);
|
|
@@ -54,13 +54,13 @@ const OptionInput = (props) => {
|
|
|
54
54
|
}
|
|
55
55
|
else {
|
|
56
56
|
switch (option.kind) {
|
|
57
|
-
case '
|
|
57
|
+
case 'n':
|
|
58
58
|
input = React.createElement(Input_1.default, Object.assign({ type: "number", onChange: handleInputChange }, inputProps));
|
|
59
59
|
break;
|
|
60
|
-
case '
|
|
60
|
+
case 's':
|
|
61
61
|
input = React.createElement(Input_1.default, Object.assign({ type: "text", onChange: handleInputChange }, inputProps));
|
|
62
62
|
break;
|
|
63
|
-
case '
|
|
63
|
+
case 'b':
|
|
64
64
|
input = (React.createElement(CheckBox_1.CheckBox, { onChange: handleCheckboxChange, checked: Boolean(value), type: "date" }, label));
|
|
65
65
|
break;
|
|
66
66
|
}
|
|
@@ -71,7 +71,7 @@ const OptionInput = (props) => {
|
|
|
71
71
|
" ",
|
|
72
72
|
info),
|
|
73
73
|
input));
|
|
74
|
-
if (option.kind === '
|
|
74
|
+
if (option.kind === 'b') {
|
|
75
75
|
content = (React.createElement(rebass_1.Flex, { alignItems: "center" },
|
|
76
76
|
input,
|
|
77
77
|
" ",
|
|
@@ -7,6 +7,7 @@ const SimpleButton_1 = tslib_1.__importDefault(require("../../components/SimpleB
|
|
|
7
7
|
const AdaptableContext_1 = require("../AdaptableContext");
|
|
8
8
|
const DropdownButton_1 = tslib_1.__importDefault(require("../../components/DropdownButton"));
|
|
9
9
|
const useChartState_1 = require("./useChartState");
|
|
10
|
+
const GeneralConstants_1 = require("../../Utilities/Constants/GeneralConstants");
|
|
10
11
|
const ShowChartButton = (props) => {
|
|
11
12
|
var _a, _b;
|
|
12
13
|
const adaptable = (0, AdaptableContext_1.useAdaptable)();
|
|
@@ -21,7 +22,7 @@ const ShowChartButton = (props) => {
|
|
|
21
22
|
}
|
|
22
23
|
const containerOptions = [
|
|
23
24
|
{
|
|
24
|
-
label: (_b = chartingOptions.agGridContainerName) !== null && _b !== void 0 ? _b :
|
|
25
|
+
label: (_b = chartingOptions.agGridContainerName) !== null && _b !== void 0 ? _b : GeneralConstants_1.AG_GRID_CHART_WINDOW,
|
|
25
26
|
onClick: () => {
|
|
26
27
|
showChart(null);
|
|
27
28
|
},
|
|
@@ -12,6 +12,7 @@ const AdaptableHelper_1 = tslib_1.__importDefault(require("../../Utilities/Helpe
|
|
|
12
12
|
const useChartState_1 = require("./useChartState");
|
|
13
13
|
const DeleteChartButton_1 = require("./DeleteChartButton");
|
|
14
14
|
const EditChartButton_1 = require("./EditChartButton");
|
|
15
|
+
const GeneralConstants_1 = require("../../Utilities/Constants/GeneralConstants");
|
|
15
16
|
const useChartingElements = ({ elementType, accessLevel, size = 'normal', }) => {
|
|
16
17
|
var _a, _b;
|
|
17
18
|
const adaptable = (0, AdaptableContext_1.useAdaptable)();
|
|
@@ -75,7 +76,7 @@ const useChartingElements = ({ elementType, accessLevel, size = 'normal', }) =>
|
|
|
75
76
|
iconSize = 15;
|
|
76
77
|
}
|
|
77
78
|
const chartSelector = (React.createElement(DropdownButton_1.default, { style: style, width: "100%", columns: ['label'], className: `ab-${elementType}__Chart__select`, items: options, disabled: !hasCharts }, content));
|
|
78
|
-
const containerSelector = Boolean(chartContainers === null || chartContainers === void 0 ? void 0 : chartContainers.length) && (React.createElement(DropdownButton_1.default, { style: style, width: "100%", columns: ['label'], items: containerOptions, disabled: !isSelectedChart }, (selectedContainer === null || selectedContainer === void 0 ? void 0 : selectedContainer.name) || chartingOptions.agGridContainerName ||
|
|
79
|
+
const containerSelector = Boolean(chartContainers === null || chartContainers === void 0 ? void 0 : chartContainers.length) && (React.createElement(DropdownButton_1.default, { style: style, width: "100%", columns: ['label'], items: containerOptions, disabled: !isSelectedChart }, (selectedContainer === null || selectedContainer === void 0 ? void 0 : selectedContainer.name) || chartingOptions.agGridContainerName || GeneralConstants_1.AG_GRID_CHART_WINDOW));
|
|
79
80
|
const chartButton = (React.createElement(SimpleButton_1.default, { style: style, mr: 1, onClick: () => (isOpen ? closeChart() : showChart(selectedContainer)), disabled: !Boolean(selectedChart), variant: 'text', tone: 'neutral', icon: isOpen ? 'visibility-off' : 'visibility', tooltip: isOpen ? 'Hide Chart' : 'Show Chart' }));
|
|
80
81
|
const deleteButton = (React.createElement(DeleteChartButton_1.DeleteChartButton, { iconSize: iconSize, chart: selectedChart, accessLevel: chartAccessLevel }));
|
|
81
82
|
const editButton = (React.createElement(EditChartButton_1.EditChartButton, { iconSize: iconSize, chart: selectedChart, accessLevel: chartAccessLevel, isOpen: isOpen }));
|
|
@@ -206,7 +206,7 @@ class QuickFilterFormComponent extends React.Component {
|
|
|
206
206
|
var _a, _b;
|
|
207
207
|
return (React.createElement(AdaptableInput_1.default, { disabled: this.isFilterDisabled(), key: index, type: predicateInput.type === 'number' ? 'text' : predicateInput.type,
|
|
208
208
|
// autoFocus has to be FALSE because if the input receives focus in the init phase,
|
|
209
|
-
// it may scroll the
|
|
209
|
+
// it may scroll the AG Grid header viewport into view and de-synchronize it (relative to the content viewport)
|
|
210
210
|
autoFocus: false, value: (_b = (_a = filter.Predicate.Inputs) === null || _a === void 0 ? void 0 : _a[index]) !== null && _b !== void 0 ? _b : '', onChange: (e) => this.changeColumnPredicateInput(e.target.value, index), onKeyDownCapture: (e) => {
|
|
211
211
|
if (e.nativeEvent.key === 'Escape') {
|
|
212
212
|
e.nativeEvent.preventDefault();
|
|
@@ -244,7 +244,7 @@ const getAdaptableToolPanelAgGridComponent = (adaptable) => {
|
|
|
244
244
|
const api = adaptable.api;
|
|
245
245
|
this.gui = document.createElement('div');
|
|
246
246
|
this.gui.id = getContainerId();
|
|
247
|
-
// preserve
|
|
247
|
+
// preserve AG Grid naming convention
|
|
248
248
|
this.gui.className = 'ag-adaptable-panel';
|
|
249
249
|
Object.keys(toolPanelContainerStyle).forEach((key) => {
|
|
250
250
|
//@ts-ignore
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { IRowNode } from '@ag-grid-community/core';
|
|
2
2
|
import { ActionColumnContext, AdaptableButton, DataChangeHistoryOptions } from '../../types';
|
|
3
|
-
export declare const buildActionColumnButton: (options: DataChangeHistoryOptions, undoRowNode: (rowNode: IRowNode) => void) => AdaptableButton<ActionColumnContext
|
|
3
|
+
export declare const buildActionColumnButton: (options: DataChangeHistoryOptions, undoRowNode: (rowNode: IRowNode) => void) => AdaptableButton<ActionColumnContext<any>>[];
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ThemeEditor = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const React = tslib_1.__importStar(require("react"));
|
|
6
|
+
const ColorPicker_1 = require("../../components/ColorPicker");
|
|
7
|
+
const FormLayout_1 = tslib_1.__importStar(require("../../components/FormLayout"));
|
|
8
|
+
const StyleHelper_1 = require("../../Utilities/Helpers/StyleHelper");
|
|
9
|
+
const AdaptableContext_1 = require("../AdaptableContext");
|
|
10
|
+
const AdaptableInput_1 = tslib_1.__importDefault(require("../Components/AdaptableInput"));
|
|
11
|
+
const throttle_1 = tslib_1.__importDefault(require("lodash/throttle"));
|
|
12
|
+
const SimpleButton_1 = tslib_1.__importDefault(require("../../components/SimpleButton"));
|
|
13
|
+
const rebass_1 = require("rebass");
|
|
14
|
+
const Panel_1 = tslib_1.__importDefault(require("../../components/Panel"));
|
|
15
|
+
const fields = [
|
|
16
|
+
{
|
|
17
|
+
name: 'Primary Color',
|
|
18
|
+
type: 'color',
|
|
19
|
+
variable: '--ab-color-primary',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'Primary Dark Color',
|
|
23
|
+
type: 'color',
|
|
24
|
+
variable: '--ab-color-primarydark',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'Primary Light Color',
|
|
28
|
+
type: 'color',
|
|
29
|
+
variable: '--ab-color-primarylight',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'Text on Primary Color',
|
|
33
|
+
type: 'color',
|
|
34
|
+
variable: '--ab-color-text-on-primary',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'Text on Primary Dark Color',
|
|
38
|
+
type: 'color',
|
|
39
|
+
variable: '--ab-color-text-on-primarydark',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Secondary Color',
|
|
43
|
+
type: 'color',
|
|
44
|
+
variable: '--ab-color-secondary',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'Secondary Dark Color',
|
|
48
|
+
type: 'color',
|
|
49
|
+
variable: '--ab-color-secondarydark',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'Secondary Light Color',
|
|
53
|
+
type: 'color',
|
|
54
|
+
variable: '--ab-color-secondarylight',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'Text on Secondary Color',
|
|
58
|
+
type: 'color',
|
|
59
|
+
variable: '--ab-color-text-on-secondary',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'Text on Secondary Light Color',
|
|
63
|
+
type: 'color',
|
|
64
|
+
variable: '--ab-color-text-on-secondarylight',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'Default background',
|
|
68
|
+
type: 'color',
|
|
69
|
+
variable: '--ab-color-defaultbackground',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'Text Color on Default Background',
|
|
73
|
+
type: 'color',
|
|
74
|
+
variable: '--ab-color-text-on-defaultbackground',
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
const Field = (props) => {
|
|
78
|
+
const adaptable = (0, AdaptableContext_1.useAdaptable)();
|
|
79
|
+
let input = null;
|
|
80
|
+
let value = props.value;
|
|
81
|
+
const throttledOnChange = React.useMemo(() => {
|
|
82
|
+
return (0, throttle_1.default)((value) => {
|
|
83
|
+
props.onChange(value);
|
|
84
|
+
}, 300);
|
|
85
|
+
}, []);
|
|
86
|
+
if (value === undefined) {
|
|
87
|
+
value = (0, StyleHelper_1.getVariableColor)(`var(${props.variable})`);
|
|
88
|
+
}
|
|
89
|
+
switch (props.type) {
|
|
90
|
+
case 'number':
|
|
91
|
+
input = (React.createElement(AdaptableInput_1.default, { disabled: props.disabled, type: "number", onChange: (event) => throttledOnChange(event.target.value), value: value }));
|
|
92
|
+
break;
|
|
93
|
+
case 'color':
|
|
94
|
+
input = (React.createElement(ColorPicker_1.ColorPicker, { disabled: props.disabled, includeAlpha: false, api: adaptable.api, value: value, onChange: (color) => throttledOnChange(color) }));
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
return (React.createElement(FormLayout_1.FormRow, { label: props.name },
|
|
98
|
+
React.createElement(rebass_1.Flex, null,
|
|
99
|
+
input,
|
|
100
|
+
' ',
|
|
101
|
+
React.createElement(SimpleButton_1.default, { disabled: props.value === undefined, onClick: () => props.onChange(false) }, "Clear"))));
|
|
102
|
+
};
|
|
103
|
+
const ThemeEditor = (props) => {
|
|
104
|
+
var _a, _b;
|
|
105
|
+
const adaptable = (0, AdaptableContext_1.useAdaptable)();
|
|
106
|
+
const allThemes = adaptable.api.themeApi.getUserThemes();
|
|
107
|
+
const disabled = props.accessLevel === 'ReadOnly';
|
|
108
|
+
const [currentThemeObject, setCurrentThemeObject] = React.useState(() => {
|
|
109
|
+
return adaptable.api.themeApi.getCurrentThemeObject();
|
|
110
|
+
});
|
|
111
|
+
// THEME variables
|
|
112
|
+
const themeVariables = currentThemeObject === null || currentThemeObject === void 0 ? void 0 : currentThemeObject.CSSVariables;
|
|
113
|
+
const valuesFromTheme = fields.reduce((acc, field) => {
|
|
114
|
+
if (themeVariables === null || themeVariables === void 0 ? void 0 : themeVariables[field.variable]) {
|
|
115
|
+
acc[field.variable] = themeVariables === null || themeVariables === void 0 ? void 0 : themeVariables[field.variable];
|
|
116
|
+
}
|
|
117
|
+
return acc;
|
|
118
|
+
}, {});
|
|
119
|
+
React.useEffect(() => {
|
|
120
|
+
setCurrentThemeObject(adaptable.api.themeApi.getCurrentThemeObject());
|
|
121
|
+
}, [props.theme]);
|
|
122
|
+
// This is needed when clearing variables, so the new value is pickedup up from the document
|
|
123
|
+
React.useEffect(() => {
|
|
124
|
+
const updateTheme = () => {
|
|
125
|
+
const theme = adaptable.api.themeApi.getCurrentThemeObject();
|
|
126
|
+
setCurrentThemeObject(Object.assign({}, theme));
|
|
127
|
+
};
|
|
128
|
+
const themeChangedUnsubscribe = adaptable.api.eventApi.on('ThemeChanged', updateTheme);
|
|
129
|
+
const themeEditedUnsubscribe = adaptable.api.eventApi.on('ThemeEdited', updateTheme);
|
|
130
|
+
return () => {
|
|
131
|
+
themeChangedUnsubscribe();
|
|
132
|
+
themeEditedUnsubscribe();
|
|
133
|
+
};
|
|
134
|
+
}, []);
|
|
135
|
+
const handleNameDescriptionChangeThrottled = React.useMemo(() => {
|
|
136
|
+
return (0, throttle_1.default)((key, value) => {
|
|
137
|
+
const theme = adaptable.api.themeApi.getCurrentThemeObject();
|
|
138
|
+
const newTheme = Object.assign(Object.assign({}, theme), { [key]: value });
|
|
139
|
+
adaptable.api.themeApi.editTheme(newTheme);
|
|
140
|
+
}, 600);
|
|
141
|
+
}, []);
|
|
142
|
+
const handleDescriptionChange = React.useCallback((key, value) => {
|
|
143
|
+
setCurrentThemeObject((prev) => (Object.assign(Object.assign({}, prev), { [key]: value })));
|
|
144
|
+
handleNameDescriptionChangeThrottled(key, value);
|
|
145
|
+
}, []);
|
|
146
|
+
const handleDeleteTheme = React.useCallback(() => {
|
|
147
|
+
adaptable.api.themeApi.loadLightTheme();
|
|
148
|
+
adaptable.api.themeApi.deleteUserTheme(currentThemeObject);
|
|
149
|
+
}, []);
|
|
150
|
+
const handleSaveName = () => {
|
|
151
|
+
const name = currentThemeObject.Name;
|
|
152
|
+
setCurrentThemeObject((prev) => (Object.assign(Object.assign({}, prev), { Name: name })));
|
|
153
|
+
handleNameDescriptionChangeThrottled('Name', name);
|
|
154
|
+
};
|
|
155
|
+
const nameHasChanged = currentThemeObject.Name !== props.theme;
|
|
156
|
+
const nameIsNotUnique = allThemes.some((theme) => theme.Uuid !== currentThemeObject.Uuid && currentThemeObject.Name === theme.Name);
|
|
157
|
+
const saveNameDisabled = !nameHasChanged || nameIsNotUnique || currentThemeObject.Name === '';
|
|
158
|
+
return (React.createElement(Panel_1.default, { header: React.createElement(rebass_1.Flex, { alignItems: "center", width: "100%" },
|
|
159
|
+
React.createElement(rebass_1.Box, { flex: 1 }, " Edit Custom Theme"),
|
|
160
|
+
React.createElement(SimpleButton_1.default, { "data-name": "delete", disabled: props.accessLevel !== 'Full', icon: "trash", onClick: handleDeleteTheme, variant: "text" })) },
|
|
161
|
+
React.createElement(FormLayout_1.default, null,
|
|
162
|
+
React.createElement(FormLayout_1.FormRow, { label: "Theme Name" },
|
|
163
|
+
React.createElement(AdaptableInput_1.default, { mr: 2, onChange: (event) => setCurrentThemeObject(Object.assign(Object.assign({}, currentThemeObject), { Name: event.target.value.replace(/ /g, '-') })), value: (_a = currentThemeObject.Name) !== null && _a !== void 0 ? _a : '' }),
|
|
164
|
+
React.createElement(SimpleButton_1.default, { onClick: handleSaveName, disabled: saveNameDisabled, icon: "save" }),
|
|
165
|
+
React.createElement(rebass_1.Text, { fontSize: 2, marginTop: 1 }, "The name cannot contain spaces."),
|
|
166
|
+
nameIsNotUnique && (React.createElement(rebass_1.Text, { fontSize: 2, color: "var(--ab-color-error)" }, "Name must be unique."))),
|
|
167
|
+
React.createElement(FormLayout_1.FormRow, { label: "Description" },
|
|
168
|
+
React.createElement(AdaptableInput_1.default, { onChange: (event) => handleDescriptionChange('Description', event.target.value), value: (_b = currentThemeObject === null || currentThemeObject === void 0 ? void 0 : currentThemeObject.Description) !== null && _b !== void 0 ? _b : '' })),
|
|
169
|
+
fields.map((field) => {
|
|
170
|
+
return (React.createElement(Field, { disabled: disabled, key: field.name, type: field.type, name: field.name, value: valuesFromTheme[field.variable], variable: field.variable, onChange: (val) => {
|
|
171
|
+
// needs a fresh copy
|
|
172
|
+
const currentThemeObject = adaptable.api.themeApi.getCurrentThemeObject();
|
|
173
|
+
let newTheme = null;
|
|
174
|
+
if (val === false) {
|
|
175
|
+
newTheme = Object.assign(Object.assign({}, currentThemeObject), { CSSVariables: Object.assign({}, currentThemeObject === null || currentThemeObject === void 0 ? void 0 : currentThemeObject.CSSVariables) });
|
|
176
|
+
delete newTheme.CSSVariables[field.variable];
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
newTheme = Object.assign(Object.assign({}, currentThemeObject), { CSSVariables: Object.assign(Object.assign({}, currentThemeObject === null || currentThemeObject === void 0 ? void 0 : currentThemeObject.CSSVariables), { [field.variable]: val }) });
|
|
180
|
+
}
|
|
181
|
+
setCurrentThemeObject(newTheme);
|
|
182
|
+
adaptable.api.themeApi.editTheme(newTheme);
|
|
183
|
+
} }));
|
|
184
|
+
}))));
|
|
185
|
+
};
|
|
186
|
+
exports.ThemeEditor = ThemeEditor;
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import * as ThemeRedux from '../../Redux/ActionsReducers/ThemeRedux';
|
|
3
3
|
import { ModuleViewPopupProps } from '../Components/SharedProps/ModuleViewPopupProps';
|
|
4
|
+
import { AdaptableTheme } from '../../PredefinedConfig/ThemeState';
|
|
4
5
|
interface ThemePopupProps extends ModuleViewPopupProps<ThemePopupComponent> {
|
|
5
6
|
CurrentTheme: string;
|
|
7
|
+
UserThemes: AdaptableTheme[];
|
|
6
8
|
SelectTheme: (newTheme: string) => ThemeRedux.ThemeSelectAction;
|
|
7
9
|
}
|
|
8
10
|
declare class ThemePopupComponent extends React.Component<ThemePopupProps, {}> {
|
|
9
11
|
render(): JSX.Element;
|
|
10
12
|
onChangeTheme(value: string): void;
|
|
13
|
+
handleCreateNewTheme: () => void;
|
|
11
14
|
}
|
|
12
15
|
export declare let ThemePopup: import("react-redux").ConnectedComponent<typeof ThemePopupComponent, any>;
|
|
13
16
|
export {};
|
|
@@ -8,11 +8,31 @@ const ThemeRedux = tslib_1.__importStar(require("../../Redux/ActionsReducers/The
|
|
|
8
8
|
const PopupPanel_1 = require("../Components/Popups/AdaptablePopup/PopupPanel");
|
|
9
9
|
const FormLayout_1 = tslib_1.__importStar(require("../../components/FormLayout"));
|
|
10
10
|
const DropdownButton_1 = tslib_1.__importDefault(require("../../components/DropdownButton"));
|
|
11
|
+
const ThemeEditor_1 = require("./ThemeEditor");
|
|
12
|
+
const rebass_1 = require("rebass");
|
|
13
|
+
const ButtonNew_1 = require("../Components/Buttons/ButtonNew");
|
|
14
|
+
const ObjectFactory_1 = tslib_1.__importDefault(require("../../Utilities/ObjectFactory"));
|
|
11
15
|
class ThemePopupComponent extends React.Component {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.handleCreateNewTheme = () => {
|
|
19
|
+
let nthItem = this.props.UserThemes.length + 1;
|
|
20
|
+
let name = 'Custom-Theme-' + nthItem;
|
|
21
|
+
// make sure it is unique
|
|
22
|
+
while (this.props.UserThemes.some((theme) => theme.Name === name)) {
|
|
23
|
+
nthItem++;
|
|
24
|
+
name = 'Custom-Theme-' + nthItem;
|
|
25
|
+
}
|
|
26
|
+
const newTheme = ObjectFactory_1.default.CreateEmptyTheme(name);
|
|
27
|
+
this.props.api.themeApi.addUserTheme(newTheme);
|
|
28
|
+
this.props.api.themeApi.loadTheme(newTheme.Name);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
12
31
|
render() {
|
|
13
32
|
const availableThemes = this.props.api.themeApi.getThemes();
|
|
14
|
-
|
|
15
|
-
|
|
33
|
+
const theme = this.props.api.themeApi.getCurrentThemeObject();
|
|
34
|
+
const currentThemeDescription = theme.Description || theme.Name;
|
|
35
|
+
const optionThemes = availableThemes.map((theme) => {
|
|
16
36
|
if (typeof theme === 'string') {
|
|
17
37
|
// protection against old state, which could be string
|
|
18
38
|
theme = {
|
|
@@ -20,19 +40,22 @@ class ThemePopupComponent extends React.Component {
|
|
|
20
40
|
Description: theme,
|
|
21
41
|
};
|
|
22
42
|
}
|
|
23
|
-
if (theme.Name === this.props.CurrentTheme) {
|
|
24
|
-
currentThemeDescription = theme.Description;
|
|
25
|
-
}
|
|
26
43
|
return {
|
|
27
44
|
value: theme.Name,
|
|
28
45
|
label: theme.Description,
|
|
29
46
|
onClick: () => this.onChangeTheme(theme.Name),
|
|
30
47
|
};
|
|
31
48
|
});
|
|
49
|
+
const isCustomTheme = this.props.api.themeApi
|
|
50
|
+
.getUserThemes()
|
|
51
|
+
.some((theme) => theme.Name === this.props.CurrentTheme);
|
|
32
52
|
return (React.createElement(PopupPanel_1.PopupPanel, { headerText: this.props.moduleInfo.FriendlyName, glyphicon: this.props.moduleInfo.Glyph, infoLink: this.props.moduleInfo.HelpPage, infoLinkDisabled: !this.props.api.internalApi.isDocumentationLinksDisplayed() },
|
|
33
53
|
React.createElement(FormLayout_1.default, null,
|
|
34
54
|
React.createElement(FormLayout_1.FormRow, { label: "Current Theme:" },
|
|
35
|
-
React.createElement(DropdownButton_1.default, { "data-name": "select-theme-dropdown", columns: ['label'], style: { width: '50%', minWidth: 200 }, placeholder: "Select theme", value: this.props.CurrentTheme, items: optionThemes, accessLevel: this.props.accessLevel }, currentThemeDescription)
|
|
55
|
+
React.createElement(DropdownButton_1.default, { "data-name": "select-theme-dropdown", columns: ['label'], style: { width: '50%', minWidth: 200 }, placeholder: "Select theme", value: this.props.CurrentTheme, items: optionThemes, accessLevel: this.props.accessLevel }, currentThemeDescription),
|
|
56
|
+
React.createElement(ButtonNew_1.ButtonNew, { ml: 2, onClick: this.handleCreateNewTheme, accessLevel: this.props.accessLevel }))),
|
|
57
|
+
isCustomTheme && (React.createElement(rebass_1.Box, { mt: 3 },
|
|
58
|
+
React.createElement(ThemeEditor_1.ThemeEditor, { accessLevel: this.props.accessLevel, theme: this.props.CurrentTheme })))));
|
|
36
59
|
}
|
|
37
60
|
onChangeTheme(value) {
|
|
38
61
|
this.props.SelectTheme(value);
|
|
@@ -41,6 +64,7 @@ class ThemePopupComponent extends React.Component {
|
|
|
41
64
|
function mapStateToProps(state, ownProps) {
|
|
42
65
|
return {
|
|
43
66
|
CurrentTheme: state.Theme.CurrentTheme,
|
|
67
|
+
UserThemes: state.Theme.UserThemes,
|
|
44
68
|
};
|
|
45
69
|
}
|
|
46
70
|
function mapDispatchToProps(dispatch) {
|
|
@@ -61,6 +61,7 @@ export declare class Adaptable implements IAdaptable {
|
|
|
61
61
|
RowEditService: IRowEditService;
|
|
62
62
|
private LicenseService;
|
|
63
63
|
private ChartingService;
|
|
64
|
+
private ThemeService;
|
|
64
65
|
embedColumnMenu: boolean;
|
|
65
66
|
gridOptions: GridOptions;
|
|
66
67
|
isInitialised: boolean;
|
|
@@ -198,8 +199,8 @@ export declare class Adaptable implements IAdaptable {
|
|
|
198
199
|
suppressClientSideFilter?: boolean;
|
|
199
200
|
gridCells: GridCell[];
|
|
200
201
|
}>;
|
|
201
|
-
getDistinctCustomSortValuesForColumn(column: AdaptableColumn, visibleRowsOnly: boolean, skipRowNode?: IRowNode): Promise<GridCell[]>;
|
|
202
|
-
getDistinctBulkUpdateValuesForColumn(column: AdaptableColumn, visibleRowsOnly: boolean, selectedGridCells: GridCell[], skipRowNode?: IRowNode): Promise<GridCell[]>;
|
|
202
|
+
getDistinctCustomSortValuesForColumn(column: AdaptableColumn, visibleRowsOnly: boolean, skipRowNode?: IRowNode): Promise<GridCell<any>[]>;
|
|
203
|
+
getDistinctBulkUpdateValuesForColumn(column: AdaptableColumn, visibleRowsOnly: boolean, selectedGridCells: GridCell[], skipRowNode?: IRowNode): Promise<GridCell<any>[]>;
|
|
203
204
|
getColumnValueDisplayValuePairList(columnId: string, visibleRowsOnly: boolean, onlyIncludeIds?: {
|
|
204
205
|
[key: string]: boolean;
|
|
205
206
|
}): GridCell[];
|