Skip to content

Commit 87e4c5d

Browse files
authored
Merge pull request #956 from plotly/disable
Disable / Enable attrs based on custom config
2 parents dbcee7d + 6015025 commit 87e4c5d

40 files changed

+938
-528
lines changed

dev/App.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import 'brace/theme/textmate';
1414
// https://github.com/plotly/react-chart-editor#mapbox-access-tokens
1515
import ACCESS_TOKENS from '../accessTokens';
1616

17+
import {customConfigTest} from '../src/__stories__';
18+
1719
const dataSourceOptions = Object.keys(dataSources).map(name => ({
1820
value: name,
1921
label: name,
@@ -183,6 +185,7 @@ class App extends Component {
183185
// makeDefaultTrace={() => ({type: 'scattergl', mode: 'markers'})}
184186
// fontOptions={[{label:'Arial', value: 'arial'}]}
185187
// chartHelp={chartHelp}
188+
// customConfig={customConfigTest}
186189
>
187190
<DefaultEditor
188191
// menuPanelOrder={[

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "react-chart-editor",
33
"description": "plotly.js chart editor react component UI",
4-
"version": "0.38.1",
4+
"version": "0.39.0",
55
"author": "Plotly, Inc.",
66
"bugs": {
77
"url": "https://github.com/plotly/react-chart-editor/issues"

scripts/translationKeys/combined-translation-keys.txt

Lines changed: 273 additions & 268 deletions
Large diffs are not rendered by default.

scripts/translationKeys/translation-keys.txt

Lines changed: 247 additions & 242 deletions
Large diffs are not rendered by default.

src/EditorControls.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import DefaultEditor from './DefaultEditor';
22
import PropTypes from 'prop-types';
33
import React, {Component} from 'react';
4-
import {bem, localizeString, plotlyTraceToCustomTrace, traceTypeToPlotlyInitFigure} from './lib';
4+
import {
5+
bem,
6+
localizeString,
7+
plotlyTraceToCustomTrace,
8+
traceTypeToPlotlyInitFigure,
9+
hasValidCustomConfigVisibilityRules,
10+
} from './lib';
511
import {
612
shamefullyClearAxisTypes,
713
shamefullyAdjustAxisRef,
@@ -59,6 +65,10 @@ class EditorControls extends Component {
5965
mapBoxAccess: this.props.mapBoxAccess,
6066
fontOptions: this.props.fontOptions,
6167
chartHelp: this.props.chartHelp,
68+
customConfig: this.props.customConfig,
69+
hasValidCustomConfigVisibilityRules: hasValidCustomConfigVisibilityRules(
70+
this.props.customConfig
71+
),
6272
};
6373
}
6474

@@ -391,6 +401,7 @@ EditorControls.propTypes = {
391401
mapBoxAccess: PropTypes.bool,
392402
fontOptions: PropTypes.array,
393403
chartHelp: PropTypes.object,
404+
customConfig: PropTypes.object,
394405
};
395406

396407
EditorControls.defaultProps = {
@@ -432,6 +443,8 @@ EditorControls.childContextTypes = {
432443
mapBoxAccess: PropTypes.bool,
433444
fontOptions: PropTypes.array,
434445
chartHelp: PropTypes.object,
446+
customConfig: PropTypes.object,
447+
hasValidCustomConfigVisibilityRules: PropTypes.bool,
435448
};
436449

437450
export default EditorControls;

src/PlotlyEditor.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ class PlotlyEditor extends Component {
4040
mapBoxAccess={Boolean(this.props.config && this.props.config.mapboxAccessToken)}
4141
fontOptions={this.props.fontOptions}
4242
chartHelp={this.props.chartHelp}
43+
customConfig={this.props.customConfig}
4344
>
4445
{this.props.children}
4546
</EditorControls>
@@ -91,6 +92,7 @@ PlotlyEditor.propTypes = {
9192
glByDefault: PropTypes.bool,
9293
fontOptions: PropTypes.array,
9394
chartHelp: PropTypes.object,
95+
customConfig: PropTypes.object,
9496
};
9597

9698
PlotlyEditor.defaultProps = {

src/__stories__/index.js

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,72 @@ import './stories.css';
1212

1313
import React from 'react';
1414
import {storiesOf} from '@storybook/react';
15+
export const customConfigTest = {
16+
visibility_rules: {
17+
blacklist: [
18+
{type: 'attrName', regex_match: 'font.family'},
19+
{type: 'attrName', regex_match: 'font.size'},
20+
{
21+
type: 'attrName',
22+
regex_match: 'color',
23+
exceptions: [
24+
{
25+
type: 'attrName',
26+
regex_match: 'colorbar',
27+
exceptions: [
28+
{type: 'attrName', regex_match: 'colorbar.bgcolor'},
29+
{type: 'attrName', regex_match: 'colorbar.tickfont.color'},
30+
{type: 'attrName', regex_match: 'colorbar.title.font.color'},
31+
{type: 'attrName', regex_match: 'colorbar.outlinecolor'},
32+
{type: 'attrName', regex_match: 'colorbar.bordercolor'},
33+
{type: 'attrName', regex_match: 'colorbar.tickcolor'},
34+
],
35+
},
36+
{
37+
type: 'attrName',
38+
regex_match: 'coloraxis',
39+
exceptions: [
40+
{type: 'attrName', regex_match: 'coloraxis.colorscale'},
41+
{type: 'attrName', regex_match: 'coloraxis.colorbar.outlinecolor'},
42+
{type: 'attrName', regex_match: 'coloraxis.colorbar.bordercolor'},
43+
{type: 'attrName', regex_match: 'coloraxis.colorbar.bgcolor'},
44+
{type: 'attrName', regex_match: 'coloraxis.colorbar.tickcolor'},
45+
{type: 'attrName', regex_match: 'coloraxis.colorbar.tickfont.color'},
46+
{type: 'attrName', regex_match: 'coloraxis.colorbar.title.font.color'},
47+
],
48+
},
49+
{
50+
type: 'attrName',
51+
regex_match: 'colorscales',
52+
exceptions: [
53+
{
54+
type: 'attrName',
55+
regex_match: 'colorscales.items.concentrationscales.colorscale',
56+
},
57+
],
58+
},
59+
{type: 'attrName', regex_match: 'autocolorscale'},
60+
{type: 'attrName', regex_match: 'usecolormap'},
61+
{type: 'attrName', regex_match: 'bundlecolors'},
62+
{
63+
type: 'attrName',
64+
regex_match: 'marker.color',
65+
exceptions: [
66+
{type: 'controlType', regex_match: '^UnconnectedMultiColorPicker$'},
67+
{type: 'controlType', regex_match: '^UnconnectedColorscalePicker$'},
68+
{type: 'attrName', regex_match: 'marker.colorbar.outlinecolor'},
69+
{type: 'attrName', regex_match: 'marker.colorbar.bordercolor'},
70+
{type: 'attrName', regex_match: 'marker.colorbar.bgcolor'},
71+
{type: 'attrName', regex_match: 'marker.colorbar.tickcolor'},
72+
{type: 'attrName', regex_match: 'marker.colorbar.tickfont.color'},
73+
{type: 'attrName', regex_match: 'marker.colorbar.title.font.color'},
74+
],
75+
},
76+
],
77+
},
78+
],
79+
},
80+
};
1581

1682
/**
1783
* To add more Percy tests - add a mock file to /dev/percy, add it to /dev/percy/index.js
@@ -34,7 +100,7 @@ window.URL.createObjectURL = function() {
34100
return null;
35101
};
36102

37-
const panelFixture = (Panel, group, name, figure) => {
103+
const panelFixture = (Panel, group, name, figure, customConfig) => {
38104
const gd = setupGraphDiv(figure, plotly);
39105
gd._context = plotly.setPlotConfig();
40106
gd._context.setBackground = () => {
@@ -48,6 +114,7 @@ const panelFixture = (Panel, group, name, figure) => {
48114
graphDiv={gd}
49115
dataSources={fixtures.scatter().dataSources}
50116
dataSourceOptions={fixtures.scatter().dataSourceOptions}
117+
customConfig={customConfig || {}}
51118
>
52119
<PanelMenuWrapper>
53120
<Panel group={group} name={name} />
@@ -67,8 +134,10 @@ Object.keys(mocks).forEach(m => {
67134
const panelGroup = words[0];
68135
const panelName = words.slice(1, -1).join(' ');
69136

70-
stories = stories.add(`${m}_${p}`, () =>
71-
panelFixture(panels[p], panelGroup, panelName, mocks[m])
72-
);
137+
stories = stories
138+
.add(`${m}_${p}`, () => panelFixture(panels[p], panelGroup, panelName, mocks[m]))
139+
.add(`${m}_${p}_withCustomConfig`, () =>
140+
panelFixture(panels[p], panelGroup, panelName, mocks[m], customConfigTest)
141+
);
73142
});
74143
});

src/components/containers/PlotlySection.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import React, {Component} from 'react';
22
import PropTypes from 'prop-types';
3-
import {containerConnectedContextTypes, unpackPlotProps} from '../../lib';
3+
import {
4+
containerConnectedContextTypes,
5+
unpackPlotProps,
6+
isVisibleGivenCustomConfig,
7+
} from '../../lib';
48

59
export class Section extends Component {
610
constructor() {
@@ -45,7 +49,7 @@ export default class PlotlySection extends Section {
4549

4650
determineVisibility(nextProps, nextContext) {
4751
const {isVisible} = unpackPlotProps(nextProps, nextContext);
48-
this.sectionVisible = Boolean(isVisible);
52+
this.sectionVisible = isVisibleGivenCustomConfig(isVisible, nextProps, nextContext);
4953

5054
React.Children.forEach(nextProps.children, child => {
5155
if (!child || this.sectionVisible) {
@@ -57,7 +61,13 @@ export default class PlotlySection extends Section {
5761
if (child.type.modifyPlotProps) {
5862
child.type.modifyPlotProps(child.props, nextContext, plotProps);
5963
}
60-
this.sectionVisible = this.sectionVisible || plotProps.isVisible;
64+
65+
this.sectionVisible = isVisibleGivenCustomConfig(
66+
this.sectionVisible || plotProps.isVisible,
67+
child.props,
68+
nextContext,
69+
child.type && child.type.displayName ? child.type.displayName : null
70+
);
6171
return;
6272
}
6373

src/components/containers/__tests__/ConnectedContainersVisibility-test.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,57 @@ describe('Basic PlotlySection rules', () => {
7474
it('HIDES Field', () => expect(wrapper.find('input').length).toEqual(0));
7575
});
7676

77+
describe('PlotlyPanel > PlotlySection > Field-with-no-visible-attr-based-on-customConfig', () => {
78+
const wrapper = mount(
79+
<TestEditor
80+
{...fixtures.scatter({
81+
customConfig: {
82+
visibility_rules: {
83+
blacklist: [{type: 'attrName', regex_match: 'color'}],
84+
},
85+
},
86+
})}
87+
>
88+
<LayoutPanel>
89+
<PlotlySection>
90+
<Numeric attr="title.font.color" />
91+
</PlotlySection>
92+
</LayoutPanel>
93+
</TestEditor>
94+
);
95+
96+
it('HIDES Field based on customConfig', () =>
97+
expect(wrapper.find('input').length).toEqual(0));
98+
it('HIDES PlotlySection because no visible children according to custom config', () =>
99+
expect(wrapper.find('div.section').length).toEqual(0));
100+
});
101+
102+
describe('PlotlyPanel > PlotlySection > Field-with-no-visible-attr-based-on-customConfig', () => {
103+
const wrapper = mount(
104+
<TestEditor
105+
{...fixtures.scatter({
106+
customConfig: {
107+
visibility_rules: {
108+
blacklist: [{type: 'attrName', regex_match: 'color'}],
109+
},
110+
},
111+
})}
112+
>
113+
<LayoutPanel>
114+
<PlotlySection attr="title">
115+
<Numeric attr="title.font.color" />
116+
<Numeric attr="title" />
117+
</PlotlySection>
118+
</LayoutPanel>
119+
</TestEditor>
120+
);
121+
122+
it('HIDES the title.font.color Field based on customConfig', () =>
123+
expect(wrapper.find('input').length).toEqual(1));
124+
it('SHOWS PlotlySection if it has an attr that is accepted by customConfig', () =>
125+
expect(wrapper.find('div.section').length).toEqual(1));
126+
});
127+
77128
describe('div > PlotlySection > Field-with-visible-attr', () => {
78129
const wrapper = mount(
79130
<TestEditor {...fixtures.scatter()}>

src/components/fields/ColorArrayPicker.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,6 @@ UnconnectedColorArrayPicker.contextTypes = {
130130
updateContainer: PropTypes.func,
131131
};
132132

133+
UnconnectedColorArrayPicker.displayName = 'UnconnectedColorArrayPicker';
134+
133135
export default connectToContainer(UnconnectedColorArrayPicker);

src/components/fields/ColorPicker.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,6 @@ UnconnectedColorPicker.propTypes = {
5151
...Field.propTypes,
5252
};
5353

54+
UnconnectedColorPicker.displayName = 'UnconnectedColorPicker';
55+
5456
export default connectToContainer(UnconnectedColorPicker);

src/components/fields/ColorscalePicker.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,6 @@ UnconnectedColorscalePicker.contextTypes = {
6565
onUpdate: PropTypes.func,
6666
};
6767

68+
UnconnectedColorscalePicker.displayName = 'UnconnectedColorscalePicker';
69+
6870
export default connectToContainer(UnconnectedColorscalePicker);

src/components/fields/ColorwayPicker.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ UnconnectedColorwayPicker.propTypes = {
2525
...Field.propTypes,
2626
};
2727

28+
UnconnectedColorwayPicker.displayName = 'UnconnectedColorwayPicker';
29+
2830
export default connectToContainer(UnconnectedColorwayPicker);

src/components/fields/DataSelector.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ UnconnectedDataSelector.contextTypes = {
156156
container: PropTypes.object,
157157
};
158158

159+
UnconnectedDataSelector.displayName = 'UnconnectedDataSelector';
160+
159161
function modifyPlotProps(props, context, plotProps) {
160162
if (
161163
attributeIsData(plotProps.attrMeta) &&

src/components/fields/DateTimePicker.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ UnconnectedDateTimePicker.propTypes = {
2525
...Field.propTypes,
2626
};
2727

28+
UnconnectedDateTimePicker.displayName = 'UnconnectedDateTimePicker';
29+
2830
export default connectToContainer(UnconnectedDateTimePicker);

src/components/fields/Dropdown.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,6 @@ UnconnectedDropdown.propTypes = {
3939
...Field.propTypes,
4040
};
4141

42+
UnconnectedDropdown.displayName = 'UnconnectedDropdown';
43+
4244
export default connectToContainer(UnconnectedDropdown);

src/components/fields/DropdownCustom.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,6 @@ UnconnectedDropdownCustom.contextTypes = {
9797
updateContainer: PropTypes.func,
9898
};
9999

100+
UnconnectedDropdownCustom.displayName = 'UnconnectedDropdownCustom';
101+
100102
export default connectToContainer(UnconnectedDropdownCustom);

src/components/fields/Dropzone.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,6 @@ UnconnectedDropzone.propTypes = {
2424
...Field.propTypes,
2525
};
2626

27+
UnconnectedDropzone.displayName = 'UnconnectedDropzone';
28+
2729
export default connectToContainer(UnconnectedDropzone);

src/components/fields/DualNumeric.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,6 @@ UnconnectedDualNumericFraction.contextTypes = {
9090
fullContainer: PropTypes.object,
9191
};
9292

93+
UnconnectedDualNumericFraction.displayName = 'UnconnectedDualNumericFraction';
94+
9395
export default connectToContainer(UnconnectedDualNumericFraction);

src/components/fields/Flaglist.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,6 @@ UnconnectedFlaglist.propTypes = {
2525
...Field.propTypes,
2626
};
2727

28+
UnconnectedFlaglist.displayName = 'UnconnectedFlaglist';
29+
2830
export default connectToContainer(UnconnectedFlaglist);

src/components/fields/GroupCreator.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,6 @@ UnconnectedGroupCreator.contextTypes = {
8181
fullData: PropTypes.array,
8282
};
8383

84+
UnconnectedGroupCreator.displayName = 'UnconnectedGroupCreator';
85+
8486
export default connectToContainer(UnconnectedGroupCreator);

src/components/fields/HoverLabelNameLength.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ UnconnectedHoverLabelNameLength.contextTypes = {
8181
localize: PropTypes.func,
8282
};
8383

84+
UnconnectedHoverLabelNameLength.displayName = 'UnconnectedHoverLabelNameLength';
85+
8486
export default connectToContainer(UnconnectedHoverLabelNameLength, {
8587
modifyPlotProps: (props, context, plotProps) => {
8688
const {container} = plotProps;

src/components/fields/MarkerColor.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,6 @@ UnconnectedMarkerColor.contextTypes = {
226226
container: PropTypes.object,
227227
};
228228

229+
UnconnectedMarkerColor.displayName = 'UnconnectedMarkerColor';
230+
229231
export default connectToContainer(UnconnectedMarkerColor);

src/components/fields/MarkerSize.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,6 @@ UnconnectedMarkerSize.contextTypes = {
9797
updateContainer: PropTypes.func,
9898
};
9999

100+
UnconnectedMarkerSize.displayName = 'UnconnectedMarkerSize';
101+
100102
export default connectToContainer(UnconnectedMarkerSize);

0 commit comments

Comments
 (0)