Make VizTypeControl use metadata from plugin (#6235)

* Render vis type item using information from registry

* adjust style

* fix unit test

* Remove large thumbnails

* Update addSlice
This commit is contained in:
Krist Wongsuphasawat 2018-11-01 11:39:24 -07:00 committed by Maxime Beauchemin
parent d1cbb0d000
commit 02f0616025
55 changed files with 104 additions and 62 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 968 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 511 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 433 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 777 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 578 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 738 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

View File

@ -3,17 +3,30 @@ import sinon from 'sinon';
import { shallow } from 'enzyme';
import { Modal } from 'react-bootstrap';
import VizTypeControl from '../../../../src/explore/components/controls/VizTypeControl';
import getChartMetadataRegistry from '../../../../src/visualizations/core/registries/ChartMetadataRegistrySingleton';
import ChartMetadata from '../../../../src/visualizations/core/models/ChartMetadata';
const defaultProps = {
name: 'viz_type',
label: 'Visualization Type',
value: 'table',
value: 'vis1',
onChange: sinon.spy(),
};
describe('VizTypeControl', () => {
let wrapper;
const registry = getChartMetadataRegistry();
registry
.registerValue('vis1', new ChartMetadata({
name: 'vis1',
thumbnail: '',
}))
.registerValue('vis2', new ChartMetadata({
name: 'vis2',
thumbnail: '',
}));
beforeEach(() => {
wrapper = shallow(<VizTypeControl {...defaultProps} />);
});
@ -28,8 +41,8 @@ describe('VizTypeControl', () => {
expect(defaultProps.onChange.called).toBe(true);
});
it('filters images based on text input', () => {
expect(wrapper.find('img').length).toBeGreaterThan(20);
wrapper.setState({ filter: 'time' });
expect(wrapper.find('img').length).toBeLessThan(10);
expect(wrapper.find('img')).toHaveLength(2);
wrapper.setState({ filter: 'vis2' });
expect(wrapper.find('img')).toHaveLength(1);
});
});

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Button, Panel } from 'react-bootstrap';
import Select from 'react-virtualized-select';
import { t } from '@superset-ui/translation';
import visTypes from '../explore/visTypes';
import getChartMetadataRegistry from '../visualizations/core/registries/ChartMetadataRegistrySingleton';
const propTypes = {
datasources: PropTypes.arrayOf(PropTypes.shape({
@ -17,11 +17,13 @@ const styleSelectWidth = { width: 300 };
export default class AddSliceContainer extends React.PureComponent {
constructor(props) {
super(props);
const visTypeKeys = Object.keys(visTypes);
this.vizTypeOptions = visTypeKeys.map(vt => ({ label: visTypes[vt].label, value: vt }));
this.state = {
visType: 'table',
};
this.changeDatasource = this.changeDatasource.bind(this);
this.changeVisType = this.changeVisType.bind(this);
this.gotoSlice = this.gotoSlice.bind(this);
}
exploreUrl() {
@ -54,6 +56,12 @@ export default class AddSliceContainer extends React.PureComponent {
}
render() {
const types = getChartMetadataRegistry().entries()
.map(({ key, value }) => ({
value: key,
label: value.name,
}));
return (
<div className="container">
<Panel header={<h3>{t('Create a new chart')}</h3>}>
@ -64,7 +72,7 @@ export default class AddSliceContainer extends React.PureComponent {
clearable={false}
style={styleSelectWidth}
name="select-datasource"
onChange={this.changeDatasource.bind(this)}
onChange={this.changeDatasource}
options={this.props.datasources}
placeholder={t('Choose a datasource')}
value={this.state.datasourceValue}
@ -86,8 +94,8 @@ export default class AddSliceContainer extends React.PureComponent {
clearable={false}
name="select-vis-type"
style={styleSelectWidth}
onChange={this.changeVisType.bind(this)}
options={this.vizTypeOptions}
onChange={this.changeVisType}
options={types}
placeholder={t('Choose a visualization type')}
value={this.state.visType}
/>
@ -96,7 +104,7 @@ export default class AddSliceContainer extends React.PureComponent {
<Button
bsStyle="primary"
disabled={this.isBtnDisabled()}
onClick={this.gotoSlice.bind(this)}
onClick={this.gotoSlice}
>
{t('Create new chart')}
</Button>

View File

@ -1,9 +1,11 @@
import React from 'react';
import { hot } from 'react-hot-loader';
import setupApp from '../setup/setupApp';
import setupPlugins from '../setup/setupPlugins';
import AddSliceContainer from './AddSliceContainer';
setupApp();
setupPlugins();
const addSliceContainer = document.getElementById('js-add-slice-container');
const bootstrapData = JSON.parse(addSliceContainer.getAttribute('data-bootstrap'));

View File

@ -0,0 +1,34 @@
.viztype-label {
margin-top: 10px;
text-align: center;
font-size: 14px;
}
.viztype-selector-container {
cursor: pointer;
margin-top: 10px;
margin-bottom: 10px;
}
.viztype-selector-container:hover img {
border: 1px solid #aaa;
}
.viztype-selector-container.selected {
cursor: not-allowed;
opacity: 1;
}
.viztype-selector-container.selected img {
border: 1px solid #333;
}
.viztype-selector-container img {
border: 1px solid #ddd;
border-radius: 4px;
transition: border-color .2s;
}
.viztype-control-search-box {
margin-bottom: 10px;
}

View File

@ -5,8 +5,9 @@ import {
Tooltip } from 'react-bootstrap';
import { t } from '@superset-ui/translation';
import visTypes from '../../visTypes';
import getChartMetadataRegistry from '../../../visualizations/core/registries/ChartMetadataRegistrySingleton';
import ControlHeader from '../ControlHeader';
import './VizTypeControl.css';
const propTypes = {
description: PropTypes.string,
@ -50,37 +51,47 @@ export default class VizTypeControl extends React.PureComponent {
this.searchRef.focus();
}
}
renderVizType(vizType) {
const vt = vizType;
renderItem(entry) {
const { value } = this.props;
const { key, value: type } = entry;
const isSelected = key === value;
return (
<div
className={`viztype-selector-container ${vt === this.props.value ? 'selected' : ''}`}
onClick={this.onChange.bind(this, vt)}
className={`viztype-selector-container ${isSelected ? 'selected' : ''}`}
onClick={this.onChange.bind(this, key)}
>
<img
alt={`viz-type-${vt}`}
alt={type.name}
width="100%"
className={`viztype-selector ${this.props.value === vt ? 'selected' : ''}`}
src={`/static/assets/images/viz_thumbnails/${vt}.png`}
className={`viztype-selector ${isSelected ? 'selected' : ''}`}
src={type.thumbnail}
/>
<div className="viztype-label">
{visTypes[vt].label}
{type.name}
</div>
</div>);
}
render() {
const filter = this.state.filter;
const filteredVizTypes = Object.keys(visTypes)
.filter(vt => filter.length === 0 || visTypes[vt].label.toLowerCase().includes(filter));
const { filter, showModal } = this.state;
const { value } = this.props;
const registry = getChartMetadataRegistry();
const types = registry.entries();
const filteredTypes = filter.length > 0
? types.filter(type => type.value.name.toLowerCase().includes(filter))
: types;
const selectedType = registry.get(value);
const imgPerRow = 6;
const rows = [];
for (let i = 0; i <= filteredVizTypes.length; i += imgPerRow) {
for (let i = 0; i <= filteredTypes.length; i += imgPerRow) {
rows.push(
<Row key={`row-${i}`}>
{filteredVizTypes.slice(i, i + imgPerRow).map(vt => (
<Col md={12 / imgPerRow} key={`grid-col-${vt}`}>
{this.renderVizType(vt)}
{filteredTypes.slice(i, i + imgPerRow).map(entry => (
<Col md={12 / imgPerRow} key={`grid-col-${entry.key}`}>
{this.renderItem(entry)}
</Col>
))}
</Row>);
@ -97,11 +108,11 @@ export default class VizTypeControl extends React.PureComponent {
}
>
<Label onClick={this.toggleModal} style={{ cursor: 'pointer' }}>
{visTypes[this.props.value].label}
{selectedType.name}
</Label>
</OverlayTrigger>
<Modal
show={this.state.showModal}
show={showModal}
onHide={this.toggleModal}
onEnter={this.focusSearch}
onExit={this.setSearchRef}
@ -111,21 +122,21 @@ export default class VizTypeControl extends React.PureComponent {
<Modal.Title>{t('Select a visualization type')}</Modal.Title>
</Modal.Header>
<Modal.Body>
<div>
<div className="viztype-control-search-box">
<FormControl
id="formControlsText"
inputRef={(ref) => { this.setSearchRef(ref); }}
inputRef={this.setSearchRef}
type="text"
bsSize="sm"
value={this.state.filter}
placeholder={t('Search / Filter')}
bsSize="md"
value={filter}
placeholder={t('Search')}
onChange={this.changeSearch}
/>
</div>
{rows}
</Modal.Body>
</Modal>
</div>);
</div>
);
}
}

View File

@ -47,32 +47,6 @@
background-color: transparent !important;
}
.viztype-label {
text-align: center;
font-size: 12px;
}
.viztype-selector-container {
cursor: pointer;
margin-top: 10px;
margin-bottom: 10px;
padding: 5px;
border: 1px solid #aaa;
}
.viztype-selector-container:hover {
border: 1px solid #000;
}
.viztype-selector-container.selected {
cursor: not-allowed;
opacity: 0.5;
}
.viztype-selector-container.selected {
cursor: not-allowed;
border: 1px solid #aaa;
}
.color-scheme-container {
list-style: none;
margin: 0;