You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ma...@apache.org on 2020/08/06 01:54:26 UTC
[incubator-superset] branch master updated: style: use tabs in
dashboard edit pane (#10394)
This is an automated email from the ASF dual-hosted git repository.
maximebeauchemin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new ece9192 style: use tabs in dashboard edit pane (#10394)
ece9192 is described below
commit ece91928a9339190163c0bc72b96e51217a90d1e
Author: Maxime Beauchemin <ma...@gmail.com>
AuthorDate: Wed Aug 5 18:53:53 2020 -0700
style: use tabs in dashboard edit pane (#10394)
* style: use tabs in dashboard edit pane
* fix tests
* more hackin'
* getting ready to rip cell measurer
* working
* pogress
* Fix cards
* done
* fix jest
* fix cy
---
.../integration/dashboard/edit_mode.test.js | 13 +-
.../cypress/integration/dashboard/save.test.js | 8 +-
superset-frontend/images/icons/more.svg | 21 +++
.../dashboard/components/DashboardBuilder_spec.jsx | 4 -
.../components/HeaderActionsDropdown_spec.jsx | 2 +-
.../dashboard/components/Header_spec.jsx | 19 +--
.../dashboard/fixtures/mockDashboardState.js | 2 -
.../dashboard/reducers/dashboardState_spec.js | 3 -
superset-frontend/src/components/Icon/index.tsx | 3 +
.../src/dashboard/actions/dashboardState.js | 4 +-
.../src/dashboard/components/AddSliceCard.jsx | 16 +-
.../dashboard/components/BuilderComponentPane.jsx | 67 ++++-----
.../dashboard/components/ColorComponentPane.jsx | 107 -------------
.../components/ColorSchemeControlWrapper.jsx | 72 +++++++++
.../src/dashboard/components/DashboardBuilder.jsx | 6 +-
.../src/dashboard/components/Header.jsx | 165 ++++++++-------------
.../dashboard/components/HeaderActionsDropdown.jsx | 125 +++++++---------
.../dashboard/components/InsertComponentPane.jsx | 118 ---------------
.../src/dashboard/components/PropertiesModal.jsx | 89 +++++++----
.../dashboard/components/RefreshIntervalModal.jsx | 11 +-
.../src/dashboard/components/SliceAdder.jsx | 45 ++----
.../components/dnd/AddSliceDragPreview.jsx | 5 +-
.../components/filterscope/FilterScopeSelector.jsx | 6 +-
.../src/dashboard/containers/DashboardBuilder.jsx | 1 -
.../src/dashboard/containers/DashboardHeader.jsx | 5 +-
.../src/dashboard/reducers/dashboardState.js | 7 +-
.../src/dashboard/reducers/getInitialState.js | 5 -
.../dashboard/stylesheets/builder-sidepane.less | 21 +--
.../src/dashboard/stylesheets/dashboard.less | 13 --
superset-frontend/src/dashboard/util/constants.ts | 7 -
.../src/dashboard/util/propShapes.jsx | 1 -
.../components/controls/ColorSchemeControl.jsx | 5 +-
.../components/controls/ColorSchemeControl.less} | 26 ++--
superset-frontend/src/explore/main.less | 14 --
.../src/views/CRUD/dashboard/DashboardList.tsx | 3 +-
.../stylesheets/less/cosmo/bootswatch.less | 1 +
superset/dashboards/dao.py | 3 +-
superset/dashboards/schemas.py | 2 +-
superset/views/chart/views.py | 1 +
39 files changed, 398 insertions(+), 628 deletions(-)
diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js
index b725354..1db86b5 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/edit_mode.test.js
@@ -23,7 +23,7 @@ describe('Dashboard edit mode', () => {
cy.server();
cy.login();
cy.visit(WORLD_HEALTH_DASHBOARD);
- cy.get('.dashboard-header').contains('Edit dashboard').click();
+ cy.get('.dashboard-header [data-test=pencil]').click();
});
it('remove, and add chart flow', () => {
@@ -38,11 +38,12 @@ describe('Dashboard edit mode', () => {
cy.get('.grid-container .box_plot').should('not.exist');
});
- // open charts list
- cy.get('.component-layer').contains('Your charts & filters').click();
+ cy.get('.tabs-components .nav-tabs li a').contains('Charts').click();
// find box plot is available from list
- cy.get('.slices-layer').find('.chart-card-container').contains('Box plot');
+ cy.get('.tabs-components')
+ .find('.chart-card-container')
+ .contains('Box plot');
// drag-n-drop
const dataTransfer = { data: {} };
@@ -62,14 +63,14 @@ describe('Dashboard edit mode', () => {
cy.get('.grid-container .box_plot').should('be.exist');
// should show Save changes button
- cy.get('.dashboard-header .button-container').contains('Save changes');
+ cy.get('.dashboard-header .button-container').contains('Save');
// undo 2 steps
cy.get('.dashboard-header .undo-action').click().click();
// no changes, can switch to view mode
cy.get('.dashboard-header .button-container')
- .contains('Switch to view mode')
+ .contains('Discard Changes')
.click();
});
});
diff --git a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js b/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js
index 650d372..028a236 100644
--- a/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js
+++ b/superset-frontend/cypress-base/cypress/integration/dashboard/save.test.js
@@ -53,20 +53,18 @@ describe('Dashboard save action', () => {
cy.get('.grid-container .box_plot', { timeout: 5000 }); // wait for 5 secs
// remove box_plot chart from dashboard
- cy.get('.dashboard-header')
- .contains('Edit dashboard')
- .trigger('click', { force: true });
+ cy.get('.dashboard-header [data-test=pencil]').click();
cy.get('.fa.fa-trash').last().trigger('click', { force: true });
cy.get('.grid-container .box_plot').should('not.exist');
cy.route('POST', '/superset/save_dash/**/').as('saveRequest');
cy.get('.dashboard-header')
- .contains('Save changes')
+ .contains('Save')
.trigger('click', { force: true });
// go back to view mode
cy.wait('@saveRequest');
- cy.get('.dashboard-header').contains('Edit dashboard');
+ cy.get('.dashboard-header [data-test=pencil]').click();
cy.get('.grid-container .box_plot').should('not.exist');
});
});
diff --git a/superset-frontend/images/icons/more.svg b/superset-frontend/images/icons/more.svg
new file mode 100644
index 0000000..5a66fe3
--- /dev/null
+++ b/superset-frontend/images/icons/more.svg
@@ -0,0 +1,21 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 10C10.8954 10 10 10.8954 10 12C10 13.1046 10.8954 14 12 14C13.1046 14 14 13.1046 14 12C14 10.8954 13.1046 10 12 10ZM5 10C3.89543 10 3 10.8954 3 12C3 13.1046 3.89543 14 5 14C6.10457 14 7 13.1046 7 12C7 10.8954 6.10457 10 5 10ZM19 10C17.8954 10 17 10.8954 17 12C17 13.1046 17.8954 14 19 14C20.1046 14 21 13.1046 21 12C21 10.8954 20.1046 10 19 10Z" fill="currentColor"/>
+</svg>
diff --git a/superset-frontend/spec/javascripts/dashboard/components/DashboardBuilder_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/DashboardBuilder_spec.jsx
index fd71eb6..3d0f363 100644
--- a/superset-frontend/spec/javascripts/dashboard/components/DashboardBuilder_spec.jsx
+++ b/superset-frontend/spec/javascripts/dashboard/components/DashboardBuilder_spec.jsx
@@ -32,7 +32,6 @@ import DashboardComponent from 'src/dashboard/containers/DashboardComponent';
import DashboardHeader from 'src/dashboard/containers/DashboardHeader';
import DashboardGrid from 'src/dashboard/containers/DashboardGrid';
import * as dashboardStateActions from 'src/dashboard/actions/dashboardState';
-import { BUILDER_PANE_TYPE } from 'src/dashboard/util/constants';
import WithDragDropContext from '../helpers/WithDragDropContext';
import {
@@ -64,7 +63,6 @@ describe('DashboardBuilder', () => {
deleteTopLevelTabs() {},
editMode: false,
showBuilderPane() {},
- builderPaneType: BUILDER_PANE_TYPE.NONE,
setColorSchemeAndUnsavedChanges() {},
colorScheme: undefined,
handleComponentDrop() {},
@@ -155,7 +153,6 @@ describe('DashboardBuilder', () => {
wrapper.setProps({
...props,
editMode: true,
- builderPaneType: BUILDER_PANE_TYPE.ADD_COMPONENTS,
});
expect(wrapper.find(BuilderComponentPane)).toExist();
});
@@ -167,7 +164,6 @@ describe('DashboardBuilder', () => {
wrapper.setProps({
...props,
editMode: true,
- builderPaneType: BUILDER_PANE_TYPE.COLORS,
});
expect(wrapper.find(BuilderComponentPane)).toExist();
});
diff --git a/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
index 815dd26..495e629 100644
--- a/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
+++ b/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
@@ -68,7 +68,7 @@ describe('HeaderActionsDropdown', () => {
it('should render two MenuItems', () => {
const wrapper = setup(overrideProps);
- expect(wrapper.find(MenuItem)).toHaveLength(2);
+ expect(wrapper.find(MenuItem)).toHaveLength(3);
});
it('should render the RefreshIntervalModal', () => {
diff --git a/superset-frontend/spec/javascripts/dashboard/components/Header_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/Header_spec.jsx
index a5425dc..bc05ddd 100644
--- a/superset-frontend/spec/javascripts/dashboard/components/Header_spec.jsx
+++ b/superset-frontend/spec/javascripts/dashboard/components/Header_spec.jsx
@@ -25,7 +25,6 @@ import PublishedStatus from 'src/dashboard/components/PublishedStatus';
import HeaderActionsDropdown from 'src/dashboard/components/HeaderActionsDropdown';
import Button from 'src/components/Button';
import UndoRedoKeylisteners from 'src/dashboard/components/UndoRedoKeylisteners';
-import { BUILDER_PANE_TYPE } from 'src/dashboard/util/constants';
describe('Header', () => {
const props = {
@@ -59,7 +58,6 @@ describe('Header', () => {
editMode: false,
setEditMode: () => {},
showBuilderPane: () => {},
- builderPaneType: BUILDER_PANE_TYPE.NONE,
updateCss: () => {},
hasUnsavedChanges: false,
maxUndoHistoryExceeded: false,
@@ -111,11 +109,6 @@ describe('Header', () => {
expect(wrapper.find(HeaderActionsDropdown)).toExist();
});
- it('should render one Button', () => {
- const wrapper = setup(overrideProps);
- expect(wrapper.find(Button)).toExist();
- });
-
it('should not set up undo/redo', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(UndoRedoKeylisteners)).not.toExist();
@@ -154,11 +147,6 @@ describe('Header', () => {
expect(wrapper.find(HeaderActionsDropdown)).toExist();
});
- it('should render one Button', () => {
- const wrapper = setup(overrideProps);
- expect(wrapper.find(Button)).toExist();
- });
-
it('should not set up undo/redo', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(UndoRedoKeylisteners)).not.toExist();
@@ -199,7 +187,7 @@ describe('Header', () => {
it('should render five Buttons', () => {
const wrapper = setup(overrideProps);
- expect(wrapper.find(Button)).toHaveLength(5);
+ expect(wrapper.find(Button)).toHaveLength(4);
});
it('should set up undo/redo', () => {
@@ -239,11 +227,6 @@ describe('Header', () => {
expect(wrapper.find(HeaderActionsDropdown)).toExist();
});
- it('should render one Button', () => {
- const wrapper = setup(overrideProps);
- expect(wrapper.find(Button)).toExist();
- });
-
it('should not set up undo/redo', () => {
const wrapper = setup(overrideProps);
expect(wrapper.find(UndoRedoKeylisteners)).not.toExist();
diff --git a/superset-frontend/spec/javascripts/dashboard/fixtures/mockDashboardState.js b/superset-frontend/spec/javascripts/dashboard/fixtures/mockDashboardState.js
index 1727422..f6809a2 100644
--- a/superset-frontend/spec/javascripts/dashboard/fixtures/mockDashboardState.js
+++ b/superset-frontend/spec/javascripts/dashboard/fixtures/mockDashboardState.js
@@ -16,14 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { BUILDER_PANE_TYPE } from 'src/dashboard/util/constants';
import { sliceId } from './mockChartQueries';
export default {
sliceIds: [sliceId],
expandedSlices: {},
editMode: false,
- builderPaneType: BUILDER_PANE_TYPE.NONE,
hasUnsavedChanges: false,
maxUndoHistoryExceeded: false,
isStarred: true,
diff --git a/superset-frontend/spec/javascripts/dashboard/reducers/dashboardState_spec.js b/superset-frontend/spec/javascripts/dashboard/reducers/dashboardState_spec.js
index fe5d098..8f6de34 100644
--- a/superset-frontend/spec/javascripts/dashboard/reducers/dashboardState_spec.js
+++ b/superset-frontend/spec/javascripts/dashboard/reducers/dashboardState_spec.js
@@ -30,7 +30,6 @@ import {
} from 'src/dashboard/actions/dashboardState';
import dashboardStateReducer from 'src/dashboard/reducers/dashboardState';
-import { BUILDER_PANE_TYPE } from 'src/dashboard/util/constants';
describe('dashboardState reducer', () => {
it('should return initial state', () => {
@@ -72,7 +71,6 @@ describe('dashboardState reducer', () => {
),
).toEqual({
editMode: true,
- builderPaneType: BUILDER_PANE_TYPE.ADD_COMPONENTS,
});
});
@@ -128,7 +126,6 @@ describe('dashboardState reducer', () => {
hasUnsavedChanges: false,
maxUndoHistoryExceeded: false,
editMode: false,
- builderPaneType: BUILDER_PANE_TYPE.NONE,
updatedColorScheme: false,
});
});
diff --git a/superset-frontend/src/components/Icon/index.tsx b/superset-frontend/src/components/Icon/index.tsx
index 7eb3916..a0d516d 100644
--- a/superset-frontend/src/components/Icon/index.tsx
+++ b/superset-frontend/src/components/Icon/index.tsx
@@ -32,6 +32,7 @@ import { ReactComponent as ErrorIcon } from 'images/icons/error.svg';
import { ReactComponent as FavoriteSelectedIcon } from 'images/icons/favorite-selected.svg';
import { ReactComponent as FavoriteUnselectedIcon } from 'images/icons/favorite-unselected.svg';
import { ReactComponent as PencilIcon } from 'images/icons/pencil.svg';
+import { ReactComponent as MoreIcon } from 'images/icons/more.svg';
import { ReactComponent as SearchIcon } from 'images/icons/search.svg';
import { ReactComponent as SortAscIcon } from 'images/icons/sort-asc.svg';
import { ReactComponent as SortDescIcon } from 'images/icons/sort-desc.svg';
@@ -55,6 +56,7 @@ type IconName =
| 'error'
| 'favorite-selected'
| 'favorite-unselected'
+ | 'more'
| 'pencil'
| 'search'
| 'sort'
@@ -84,6 +86,7 @@ export const iconsRegistry: Record<
close: CloseIcon,
compass: CompassIcon,
error: ErrorIcon,
+ more: MoreIcon,
pencil: PencilIcon,
search: SearchIcon,
sort: SortIcon,
diff --git a/superset-frontend/src/dashboard/actions/dashboardState.js b/superset-frontend/src/dashboard/actions/dashboardState.js
index 33737f8..024c884 100644
--- a/superset-frontend/src/dashboard/actions/dashboardState.js
+++ b/superset-frontend/src/dashboard/actions/dashboardState.js
@@ -253,8 +253,8 @@ export function fetchCharts(
}
export const SHOW_BUILDER_PANE = 'SHOW_BUILDER_PANE';
-export function showBuilderPane(builderPaneType) {
- return { type: SHOW_BUILDER_PANE, builderPaneType };
+export function showBuilderPane() {
+ return { type: SHOW_BUILDER_PANE };
}
export function addSliceToDashboard(id, component) {
diff --git a/superset-frontend/src/dashboard/components/AddSliceCard.jsx b/superset-frontend/src/dashboard/components/AddSliceCard.jsx
index 497cece..525aac5 100644
--- a/superset-frontend/src/dashboard/components/AddSliceCard.jsx
+++ b/superset-frontend/src/dashboard/components/AddSliceCard.jsx
@@ -22,24 +22,28 @@ import PropTypes from 'prop-types';
import { t } from '@superset-ui/translation';
const propTypes = {
- datasourceLink: PropTypes.string,
+ datasourceUrl: PropTypes.string,
+ datasourceName: PropTypes.string,
innerRef: PropTypes.func,
isSelected: PropTypes.bool,
- lastModified: PropTypes.string.isRequired,
+ lastModified: PropTypes.string,
sliceName: PropTypes.string.isRequired,
style: PropTypes.object,
visType: PropTypes.string.isRequired,
};
const defaultProps = {
- datasourceLink: '—',
+ datasourceUrl: null,
+ datasourceName: '-',
innerRef: null,
isSelected: false,
style: null,
+ lastModified: null,
};
function AddSliceCard({
- datasourceLink,
+ datasourceUrl,
+ datasourceName,
innerRef,
isSelected,
lastModified,
@@ -62,9 +66,7 @@ function AddSliceCard({
</div>
<div className="item">
<span>{t('Data source')} </span>
- <span // eslint-disable-next-line react/no-danger
- dangerouslySetInnerHTML={{ __html: datasourceLink }}
- />
+ <a href={datasourceUrl}>{datasourceName}</a>
</div>
</div>
</div>
diff --git a/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx b/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx
index 2d2ab08..336f399 100644
--- a/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx
+++ b/superset-frontend/src/dashboard/components/BuilderComponentPane.jsx
@@ -19,37 +19,53 @@
/* eslint-env browser */
import PropTypes from 'prop-types';
import React from 'react';
+import { Tabs, Tab } from 'react-bootstrap';
import { StickyContainer, Sticky } from 'react-sticky';
import { ParentSize } from '@vx/responsive';
-import InsertComponentPane, {
- SUPERSET_HEADER_HEIGHT,
-} from './InsertComponentPane';
-import ColorComponentPane from './ColorComponentPane';
-import { BUILDER_PANE_TYPE } from '../util/constants';
+import { t } from '@superset-ui/translation';
+
+import NewColumn from './gridComponents/new/NewColumn';
+import NewDivider from './gridComponents/new/NewDivider';
+import NewHeader from './gridComponents/new/NewHeader';
+import NewRow from './gridComponents/new/NewRow';
+import NewTabs from './gridComponents/new/NewTabs';
+import NewMarkdown from './gridComponents/new/NewMarkdown';
+import SliceAdder from '../containers/SliceAdder';
const propTypes = {
topOffset: PropTypes.number,
- showBuilderPane: PropTypes.func.isRequired,
- builderPaneType: PropTypes.string.isRequired,
- setColorSchemeAndUnsavedChanges: PropTypes.func.isRequired,
- colorScheme: PropTypes.string,
};
const defaultProps = {
topOffset: 0,
- colorScheme: undefined,
};
+const SUPERSET_HEADER_HEIGHT = 59;
+
class BuilderComponentPane extends React.PureComponent {
+ renderTabs(height) {
+ const { isSticky } = this.props;
+ return (
+ <Tabs className="m-t-10 tabs-components">
+ <Tab eventKey={1} title={t('Components')}>
+ <NewTabs />
+ <NewRow />
+ <NewColumn />
+ <NewHeader />
+ <NewMarkdown />
+ <NewDivider />
+ </Tab>
+ <Tab eventKey={2} title={t('Charts')} className="tab-charts">
+ <SliceAdder
+ height={height + (isSticky ? SUPERSET_HEADER_HEIGHT : 0)}
+ />
+ </Tab>
+ </Tabs>
+ );
+ }
render() {
- const {
- topOffset,
- builderPaneType,
- showBuilderPane,
- setColorSchemeAndUnsavedChanges,
- colorScheme,
- } = this.props;
+ const { topOffset } = this.props;
return (
<div
className="dashboard-builder-sidepane"
@@ -66,22 +82,7 @@ class BuilderComponentPane extends React.PureComponent {
className="viewport"
style={isSticky ? { ...style, top: topOffset } : null}
>
- {builderPaneType === BUILDER_PANE_TYPE.ADD_COMPONENTS && (
- <InsertComponentPane
- height={height}
- isSticky={isSticky}
- showBuilderPane={showBuilderPane}
- />
- )}
- {builderPaneType === BUILDER_PANE_TYPE.COLORS && (
- <ColorComponentPane
- showBuilderPane={showBuilderPane}
- setColorSchemeAndUnsavedChanges={
- setColorSchemeAndUnsavedChanges
- }
- colorScheme={colorScheme}
- />
- )}
+ {this.renderTabs(height)}
</div>
)}
</Sticky>
diff --git a/superset-frontend/src/dashboard/components/ColorComponentPane.jsx b/superset-frontend/src/dashboard/components/ColorComponentPane.jsx
deleted file mode 100644
index ee6aec5..0000000
--- a/superset-frontend/src/dashboard/components/ColorComponentPane.jsx
+++ /dev/null
@@ -1,107 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-/* eslint-env browser */
-import PropTypes from 'prop-types';
-import React from 'react';
-import { getCategoricalSchemeRegistry } from '@superset-ui/color';
-import { t } from '@superset-ui/translation';
-
-import ColorSchemeControl from '../../explore/components/controls/ColorSchemeControl';
-import { BUILDER_PANE_TYPE } from '../util/constants';
-
-const propTypes = {
- showBuilderPane: PropTypes.func.isRequired,
- setColorSchemeAndUnsavedChanges: PropTypes.func.isRequired,
- colorScheme: PropTypes.string,
-};
-
-const defaultProps = {
- colorScheme: undefined,
-};
-
-class ColorComponentPane extends React.PureComponent {
- constructor(props) {
- super(props);
- this.state = { hovered: false };
- this.categoricalSchemeRegistry = getCategoricalSchemeRegistry();
- this.getChoices = this.getChoices.bind(this);
- this.getSchemes = this.getSchemes.bind(this);
- this.onCloseButtonClick = this.onCloseButtonClick.bind(this);
- this.onMouseEnter = this.setHover.bind(this, true);
- this.onMouseLeave = this.setHover.bind(this, false);
- }
-
- onCloseButtonClick() {
- this.props.showBuilderPane(BUILDER_PANE_TYPE.NONE);
- }
-
- getChoices() {
- return this.categoricalSchemeRegistry.keys().map(s => [s, s]);
- }
-
- getSchemes() {
- return this.categoricalSchemeRegistry.getMap();
- }
-
- setHover(hovered) {
- this.setState({ hovered });
- }
-
- render() {
- const { setColorSchemeAndUnsavedChanges, colorScheme } = this.props;
-
- return (
- <div className="slider-container">
- <div className="component-layer slide-content">
- <div className="dashboard-builder-sidepane-header">
- <span>{'Color Settings'}</span>
- <i
- className="fa fa-times trigger"
- onClick={this.onCloseButtonClick}
- role="none"
- />
- </div>
- <div
- className="panel-body"
- onMouseEnter={this.onMouseEnter}
- onMouseLeave={this.onMouseLeave}
- >
- <ColorSchemeControl
- description={t(
- "Any color palette selected here will override the colors applied to this dashboard's individual charts",
- )}
- label={t('Color Scheme')}
- name="color_scheme"
- onChange={setColorSchemeAndUnsavedChanges}
- value={colorScheme}
- choices={this.getChoices}
- schemes={this.getSchemes}
- hovered={this.state.hovered}
- />
- </div>
- </div>
- </div>
- );
- }
-}
-
-ColorComponentPane.propTypes = propTypes;
-ColorComponentPane.defaultProps = defaultProps;
-
-export default ColorComponentPane;
diff --git a/superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx b/superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx
new file mode 100644
index 0000000..edbfa2a
--- /dev/null
+++ b/superset-frontend/src/dashboard/components/ColorSchemeControlWrapper.jsx
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/* eslint-env browser */
+import PropTypes from 'prop-types';
+import React from 'react';
+import { getCategoricalSchemeRegistry } from '@superset-ui/color';
+import { t } from '@superset-ui/translation';
+
+import ColorSchemeControl from 'src/explore/components/controls/ColorSchemeControl';
+
+const propTypes = {
+ onChange: PropTypes.func.isRequired,
+ colorScheme: PropTypes.string,
+};
+
+const defaultProps = {
+ colorScheme: undefined,
+ onChange: () => {},
+};
+
+class ColorSchemeControlWrapper extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = { hovered: false };
+ this.categoricalSchemeRegistry = getCategoricalSchemeRegistry();
+ this.choices = this.categoricalSchemeRegistry.keys().map(s => [s, s]);
+ this.schemes = this.categoricalSchemeRegistry.getMap();
+ }
+ setHover(hovered) {
+ this.setState({ hovered });
+ }
+
+ render() {
+ const { colorScheme } = this.props;
+ return (
+ <ColorSchemeControl
+ description={t(
+ "Any color palette selected here will override the colors applied to this dashboard's individual charts",
+ )}
+ label={t('Color Scheme')}
+ name="color_scheme"
+ onChange={this.props.onChange}
+ value={colorScheme}
+ choices={this.choices}
+ clearable
+ schemes={this.schemes}
+ hovered={this.state.hovered}
+ />
+ );
+ }
+}
+
+ColorSchemeControlWrapper.propTypes = propTypes;
+ColorSchemeControlWrapper.defaultProps = defaultProps;
+
+export default ColorSchemeControlWrapper;
diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder.jsx b/superset-frontend/src/dashboard/components/DashboardBuilder.jsx
index de9a94e..5ca6f2d 100644
--- a/superset-frontend/src/dashboard/components/DashboardBuilder.jsx
+++ b/superset-frontend/src/dashboard/components/DashboardBuilder.jsx
@@ -39,7 +39,6 @@ import getDragDropManager from '../util/getDragDropManager';
import findTabIndexByComponentId from '../util/findTabIndexByComponentId';
import {
- BUILDER_PANE_TYPE,
DASHBOARD_GRID_ID,
DASHBOARD_ROOT_ID,
DASHBOARD_ROOT_DEPTH,
@@ -56,7 +55,6 @@ const propTypes = {
deleteTopLevelTabs: PropTypes.func.isRequired,
editMode: PropTypes.bool.isRequired,
showBuilderPane: PropTypes.func.isRequired,
- builderPaneType: PropTypes.string.isRequired,
colorScheme: PropTypes.string,
setColorSchemeAndUnsavedChanges: PropTypes.func.isRequired,
handleComponentDrop: PropTypes.func.isRequired,
@@ -161,7 +159,6 @@ class DashboardBuilder extends React.Component {
dashboardLayout,
editMode,
showBuilderPane,
- builderPaneType,
setColorSchemeAndUnsavedChanges,
colorScheme,
} = this.props;
@@ -265,11 +262,10 @@ class DashboardBuilder extends React.Component {
)}
</ParentSize>
</div>
- {editMode && builderPaneType !== BUILDER_PANE_TYPE.NONE && (
+ {editMode && (
<BuilderComponentPane
topOffset={HEADER_HEIGHT + (topLevelTabs ? TABS_HEIGHT : 0)}
showBuilderPane={showBuilderPane}
- builderPaneType={builderPaneType}
setColorSchemeAndUnsavedChanges={setColorSchemeAndUnsavedChanges}
colorScheme={colorScheme}
/>
diff --git a/superset-frontend/src/dashboard/components/Header.jsx b/superset-frontend/src/dashboard/components/Header.jsx
index 3d04284..89f2084 100644
--- a/superset-frontend/src/dashboard/components/Header.jsx
+++ b/superset-frontend/src/dashboard/components/Header.jsx
@@ -21,20 +21,21 @@ import moment from 'moment';
import React from 'react';
import PropTypes from 'prop-types';
import styled from '@superset-ui/style';
+import { ButtonGroup } from 'react-bootstrap';
import { CategoricalColorNamespace } from '@superset-ui/color';
import { t } from '@superset-ui/translation';
+import Icon from 'src/components/Icon';
+
import HeaderActionsDropdown from './HeaderActionsDropdown';
import EditableTitle from '../../components/EditableTitle';
import Button from '../../components/Button';
import FaveStar from '../../components/FaveStar';
-import FilterScopeModal from './filterscope/FilterScopeModal';
import PublishedStatus from './PublishedStatus';
import UndoRedoKeylisteners from './UndoRedoKeylisteners';
import { chartPropShape } from '../util/propShapes';
import {
- BUILDER_PANE_TYPE,
UNDO_LIMIT,
SAVE_TYPE_OVERWRITE,
DASHBOARD_POSITION_DATA_LIMIT,
@@ -62,6 +63,7 @@ const propTypes = {
customCss: PropTypes.string.isRequired,
colorNamespace: PropTypes.string,
colorScheme: PropTypes.string,
+ setColorSchemeAndUnsavedChanges: PropTypes.func.isRequired,
isStarred: PropTypes.bool.isRequired,
isPublished: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired,
@@ -75,7 +77,6 @@ const propTypes = {
editMode: PropTypes.bool.isRequired,
setEditMode: PropTypes.func.isRequired,
showBuilderPane: PropTypes.func.isRequired,
- builderPaneType: PropTypes.string.isRequired,
updateCss: PropTypes.func.isRequired,
logEvent: PropTypes.func.isRequired,
hasUnsavedChanges: PropTypes.bool.isRequired,
@@ -124,10 +125,6 @@ class Header extends React.PureComponent {
this.handleChangeText = this.handleChangeText.bind(this);
this.handleCtrlZ = this.handleCtrlZ.bind(this);
this.handleCtrlY = this.handleCtrlY.bind(this);
- this.onInsertComponentsButtonClick = this.onInsertComponentsButtonClick.bind(
- this,
- );
- this.onColorsButtonClick = this.onColorsButtonClick.bind(this);
this.toggleEditMode = this.toggleEditMode.bind(this);
this.forceRefresh = this.forceRefresh.bind(this);
this.startPeriodicRender = this.startPeriodicRender.bind(this);
@@ -162,14 +159,6 @@ class Header extends React.PureComponent {
clearTimeout(this.ctrlZTimeout);
}
- onInsertComponentsButtonClick() {
- this.props.showBuilderPane(BUILDER_PANE_TYPE.ADD_COMPONENTS);
- }
-
- onColorsButtonClick() {
- this.props.showBuilderPane(BUILDER_PANE_TYPE.COLORS);
- }
-
handleChangeText(nextText) {
const { updateDashboardTitle, onChange } = this.props;
if (nextText && this.props.dashboardTitle !== nextText) {
@@ -340,6 +329,7 @@ class Header extends React.PureComponent {
expandedSlices,
customCss,
colorNamespace,
+ setColorSchemeAndUnsavedChanges,
colorScheme,
onUndo,
onRedo,
@@ -350,7 +340,6 @@ class Header extends React.PureComponent {
updateCss,
editMode,
isPublished,
- builderPaneType,
dashboardInfo,
hasUnsavedChanges,
isLoading,
@@ -366,7 +355,6 @@ class Header extends React.PureComponent {
const refreshWarning =
dashboardInfo.common.conf
.SUPERSET_DASHBOARD_PERIODICAL_REFRESH_WARNING_MESSAGE;
- const popButton = hasUnsavedChanges;
return (
<StyledDashboardHeader className="dashboard-header">
@@ -399,92 +387,63 @@ class Header extends React.PureComponent {
{userCanSaveAs && (
<div className="button-container">
{editMode && (
- <Button
- bsSize="small"
- onClick={onUndo}
- disabled={undoLength < 1}
- bsStyle={this.state.emphasizeUndo ? 'primary' : undefined}
- >
- <div title="Undo" className="undo-action fa fa-reply" />
- </Button>
- )}
-
- {editMode && (
- <Button
- bsSize="small"
- onClick={onRedo}
- disabled={redoLength < 1}
- bsStyle={this.state.emphasizeRedo ? 'primary' : undefined}
- >
- <div title="Redo" className="redo-action fa fa-share" />
- </Button>
- )}
-
- {editMode && (
- <Button
- active={builderPaneType === BUILDER_PANE_TYPE.ADD_COMPONENTS}
- bsSize="small"
- onClick={this.onInsertComponentsButtonClick}
- >
- {t('Components')}
- </Button>
- )}
-
- {editMode && (
- <Button
- active={builderPaneType === BUILDER_PANE_TYPE.COLORS}
- bsSize="small"
- onClick={this.onColorsButtonClick}
- >
- {t('Colors')}
- </Button>
- )}
-
- {editMode && (
- <FilterScopeModal
- triggerNode={<Button bsSize="small">{t('Filters')}</Button>}
- />
- )}
-
- {editMode && hasUnsavedChanges && (
- <Button
- bsSize="small"
- bsStyle={popButton ? 'primary' : undefined}
- onClick={this.overwriteDashboard}
- >
- {t('Save changes')}
- </Button>
- )}
-
- {editMode && !hasUnsavedChanges && (
- <Button
- bsSize="small"
- onClick={this.toggleEditMode}
- bsStyle={undefined}
- disabled={!userCanEdit}
- >
- {t('Switch to view mode')}
- </Button>
- )}
-
- {editMode && (
- <UndoRedoKeylisteners
- onUndo={this.handleCtrlZ}
- onRedo={this.handleCtrlY}
- />
+ <>
+ <ButtonGroup className="m-r-5">
+ <Button
+ bsSize="small"
+ onClick={onUndo}
+ disabled={undoLength < 1}
+ bsStyle={this.state.emphasizeUndo ? 'primary' : undefined}
+ >
+ <i title="Undo" className="undo-action fa fa-reply" />
+
+ </Button>
+ <Button
+ bsSize="small"
+ onClick={onRedo}
+ disabled={redoLength < 1}
+ bsStyle={this.state.emphasizeRedo ? 'primary' : undefined}
+ >
+
+ <i title="Redo" className="redo-action fa fa-share" />
+ </Button>
+ </ButtonGroup>
+ <Button
+ bsSize="small"
+ className="m-r-5"
+ onClick={this.constructor.discardChanges}
+ bsStyle="default"
+ >
+ {t('Discard Changes')}
+ </Button>
+ <Button
+ bsSize="small"
+ disabled={!hasUnsavedChanges}
+ bsStyle="primary"
+ onClick={this.overwriteDashboard}
+ >
+ {t('Save')}
+ </Button>
+ </>
)}
</div>
)}
+ {editMode && (
+ <UndoRedoKeylisteners
+ onUndo={this.handleCtrlZ}
+ onRedo={this.handleCtrlY}
+ />
+ )}
- {!editMode && !hasUnsavedChanges && (
- <Button
- bsSize="small"
+ {!editMode && (
+ <span
+ role="button"
+ tabIndex={0}
+ className="action-button"
onClick={this.toggleEditMode}
- bsStyle={popButton ? 'primary' : undefined}
- disabled={!userCanEdit}
>
- {t('Edit dashboard')}
- </Button>
+ <Icon name="pencil" />
+ </span>
)}
{this.state.showingPropertiesModal && (
@@ -492,12 +451,18 @@ class Header extends React.PureComponent {
dashboardId={dashboardInfo.id}
show={this.state.showingPropertiesModal}
onHide={this.hidePropertiesModal}
- onDashboardSave={updates => {
- this.props.dashboardInfoChanged({
+ colorScheme={this.props.colorScheme}
+ onSubmit={updates => {
+ const {
+ dashboardInfoChanged,
+ dashboardTitleChanged,
+ } = this.props;
+ dashboardInfoChanged({
slug: updates.slug,
metadata: JSON.parse(updates.jsonMetadata),
});
- this.props.dashboardTitleChanged(updates.title);
+ setColorSchemeAndUnsavedChanges(updates.colorScheme);
+ dashboardTitleChanged(updates.title);
if (updates.slug) {
history.pushState(
{ event: 'dashboard_properties_changed' },
diff --git a/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx b/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx
index da574e0..8a1c2e9 100644
--- a/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx
+++ b/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx
@@ -18,16 +18,20 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
+
import { SupersetClient } from '@superset-ui/connection';
import { DropdownButton, MenuItem } from 'react-bootstrap';
import { t } from '@superset-ui/translation';
+import Icon from 'src/components/Icon';
+
import CssEditor from './CssEditor';
import RefreshIntervalModal from './RefreshIntervalModal';
import SaveModal from './SaveModal';
import injectCustomCss from '../util/injectCustomCss';
import { SAVE_TYPE_NEWDASHBOARD } from '../util/constants';
import URLShortLinkModal from '../../components/URLShortLinkModal';
+import FilterScopeModal from './filterscope/FilterScopeModal';
import downloadAsImage from '../../utils/downloadAsImage';
import getDashboardUrl from '../util/getDashboardUrl';
import { getActiveFilters } from '../util/activeDashboardFilters';
@@ -38,7 +42,6 @@ const propTypes = {
dashboardInfo: PropTypes.object.isRequired,
dashboardId: PropTypes.number.isRequired,
dashboardTitle: PropTypes.string.isRequired,
- hasUnsavedChanges: PropTypes.bool.isRequired,
customCss: PropTypes.string.isRequired,
colorNamespace: PropTypes.string,
colorScheme: PropTypes.string,
@@ -128,7 +131,6 @@ class HeaderActionsDropdown extends React.PureComponent {
customCss,
colorNamespace,
colorScheme,
- hasUnsavedChanges,
layout,
expandedSlices,
onSave,
@@ -145,72 +147,36 @@ class HeaderActionsDropdown extends React.PureComponent {
return (
<DropdownButton
- title=""
+ title={<Icon name="more" />}
+ noCaret
id="save-dash-split-button"
- bsStyle={hasUnsavedChanges ? 'primary' : undefined}
bsSize="small"
+ style={{ border: 'none', padding: 0, marginLeft: '4px' }}
pullRight
>
{userCanSave && (
- <SaveModal
- addSuccessToast={this.props.addSuccessToast}
- addDangerToast={this.props.addDangerToast}
- dashboardId={dashboardId}
- dashboardTitle={dashboardTitle}
- dashboardInfo={dashboardInfo}
- saveType={SAVE_TYPE_NEWDASHBOARD}
- layout={layout}
- expandedSlices={expandedSlices}
- refreshFrequency={refreshFrequency}
- shouldPersistRefreshFrequency={shouldPersistRefreshFrequency}
- customCss={customCss}
- colorNamespace={colorNamespace}
- colorScheme={colorScheme}
- onSave={onSave}
- isMenuItem
- triggerNode={<span>{t('Save as')}</span>}
- canOverwrite={userCanEdit}
- />
- )}
-
- {hasUnsavedChanges && userCanSave && (
- <div>
- <MenuItem
- eventKey="discard"
- onSelect={HeaderActionsDropdown.discardChanges}
- >
- {t('Discard changes')}
- </MenuItem>
- </div>
- )}
-
- {userCanSave && <MenuItem divider />}
-
- <MenuItem onClick={forceRefreshAllCharts} disabled={isLoading}>
- {t('Force refresh dashboard')}
- </MenuItem>
-
- <RefreshIntervalModal
- refreshFrequency={refreshFrequency}
- refreshLimit={refreshLimit}
- refreshWarning={refreshWarning}
- onChange={this.changeRefreshInterval}
- editMode={editMode}
- triggerNode={
- <span>
- {editMode
- ? t('Set auto-refresh interval')
- : t('Auto-refresh dashboard')}
- </span>
- }
- />
-
- {editMode && (
- <MenuItem onClick={this.props.showPropertiesModal}>
- {t('Edit dashboard properties')}
- </MenuItem>
+ <>
+ <SaveModal
+ addSuccessToast={this.props.addSuccessToast}
+ addDangerToast={this.props.addDangerToast}
+ dashboardId={dashboardId}
+ dashboardTitle={dashboardTitle}
+ dashboardInfo={dashboardInfo}
+ saveType={SAVE_TYPE_NEWDASHBOARD}
+ layout={layout}
+ expandedSlices={expandedSlices}
+ refreshFrequency={refreshFrequency}
+ shouldPersistRefreshFrequency={shouldPersistRefreshFrequency}
+ customCss={customCss}
+ colorNamespace={colorNamespace}
+ colorScheme={colorScheme}
+ onSave={onSave}
+ isMenuItem
+ triggerNode={<span>{t('Save as')}</span>}
+ canOverwrite={userCanEdit}
+ />
+ </>
)}
-
<URLShortLinkModal
url={getDashboardUrl(
window.location.pathname,
@@ -223,14 +189,37 @@ class HeaderActionsDropdown extends React.PureComponent {
isMenuItem
triggerNode={<span>{t('Share dashboard')}</span>}
/>
+ <MenuItem onClick={forceRefreshAllCharts} disabled={isLoading}>
+ {t('Refresh dashboard')}
+ </MenuItem>
+ <MenuItem divider />
+ <RefreshIntervalModal
+ refreshFrequency={refreshFrequency}
+ refreshLimit={refreshLimit}
+ refreshWarning={refreshWarning}
+ onChange={this.changeRefreshInterval}
+ editMode={editMode}
+ triggerNode={<span>{t('Set auto-refresh interval')}</span>}
+ />
{editMode && (
- <CssEditor
- triggerNode={<span>{t('Edit CSS')}</span>}
- initialCss={this.state.css}
- templates={this.state.cssTemplates}
- onChange={this.changeCss}
- />
+ <>
+ <FilterScopeModal
+ className="m-r-5"
+ triggerNode={
+ <MenuItem bsSize="small">{t('Set filter mapping')}</MenuItem>
+ }
+ />
+ <MenuItem onClick={this.props.showPropertiesModal}>
+ {t('Edit dashboard properties')}
+ </MenuItem>
+ <CssEditor
+ triggerNode={<span>{t('Edit CSS')}</span>}
+ initialCss={this.state.css}
+ templates={this.state.cssTemplates}
+ onChange={this.changeCss}
+ />
+ </>
)}
{!editMode && (
diff --git a/superset-frontend/src/dashboard/components/InsertComponentPane.jsx b/superset-frontend/src/dashboard/components/InsertComponentPane.jsx
deleted file mode 100644
index 3141347..0000000
--- a/superset-frontend/src/dashboard/components/InsertComponentPane.jsx
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-/* eslint-env browser */
-import PropTypes from 'prop-types';
-import React from 'react';
-import cx from 'classnames';
-import { t } from '@superset-ui/translation';
-
-import NewColumn from './gridComponents/new/NewColumn';
-import NewDivider from './gridComponents/new/NewDivider';
-import NewHeader from './gridComponents/new/NewHeader';
-import NewRow from './gridComponents/new/NewRow';
-import NewTabs from './gridComponents/new/NewTabs';
-import NewMarkdown from './gridComponents/new/NewMarkdown';
-import SliceAdder from '../containers/SliceAdder';
-import { BUILDER_PANE_TYPE } from '../util/constants';
-
-export const SUPERSET_HEADER_HEIGHT = 59;
-
-const propTypes = {
- height: PropTypes.number.isRequired,
- isSticky: PropTypes.bool.isRequired,
- showBuilderPane: PropTypes.func.isRequired,
-};
-
-class InsertComponentPane extends React.PureComponent {
- constructor(props) {
- super(props);
- this.state = {
- slideDirection: 'slide-out',
- };
-
- this.onCloseButtonClick = this.onCloseButtonClick.bind(this);
- this.openSlicesPane = this.slide.bind(this, 'slide-in');
- this.closeSlicesPane = this.slide.bind(this, 'slide-out');
- }
-
- onCloseButtonClick() {
- this.props.showBuilderPane(BUILDER_PANE_TYPE.NONE);
- }
-
- slide(direction) {
- this.setState({
- slideDirection: direction,
- });
- }
-
- render() {
- return (
- <div className={cx('slider-container', this.state.slideDirection)}>
- <div className="component-layer slide-content">
- <div className="dashboard-builder-sidepane-header">
- <span>{t('Insert components')}</span>
- <i
- className="fa fa-times trigger"
- onClick={this.onCloseButtonClick}
- role="none"
- />
- </div>
- <div
- className="new-component static"
- role="none"
- onClick={this.openSlicesPane}
- >
- <div className="new-component-placeholder fa fa-area-chart" />
- <div className="new-component-label">
- {t('Your charts & filters')}
- </div>
-
- <i className="fa fa-arrow-right trigger" />
- </div>
- <NewTabs />
- <NewRow />
- <NewColumn />
- <NewHeader />
- <NewMarkdown />
- <NewDivider />
- </div>
- <div className="slices-layer slide-content">
- <div
- className="dashboard-builder-sidepane-header"
- onClick={this.closeSlicesPane}
- role="none"
- >
- <i className="fa fa-arrow-left trigger" />
- <span>{t('Your charts and filters')}</span>
- </div>
- <SliceAdder
- height={
- this.props.height +
- (this.props.isSticky ? SUPERSET_HEADER_HEIGHT : 0)
- }
- />
- </div>
- </div>
- );
- }
-}
-
-InsertComponentPane.propTypes = propTypes;
-
-export default InsertComponentPane;
diff --git a/superset-frontend/src/dashboard/components/PropertiesModal.jsx b/superset-frontend/src/dashboard/components/PropertiesModal.jsx
index 77c2995..aac3be2 100644
--- a/superset-frontend/src/dashboard/components/PropertiesModal.jsx
+++ b/superset-frontend/src/dashboard/components/PropertiesModal.jsx
@@ -27,6 +27,7 @@ import { t } from '@superset-ui/translation';
import { SupersetClient } from '@superset-ui/connection';
import FormLabel from 'src/components/FormLabel';
+import ColorSchemeControlWrapper from 'src/dashboard/components/ColorSchemeControlWrapper';
import getClientErrorObject from '../../utils/getClientErrorObject';
import withToasts from '../../messageToasts/enhancers/withToasts';
import '../stylesheets/buttons.less';
@@ -35,14 +36,20 @@ const propTypes = {
dashboardId: PropTypes.number.isRequired,
show: PropTypes.bool.isRequired,
onHide: PropTypes.func,
- onDashboardSave: PropTypes.func,
+ colorScheme: PropTypes.object,
+ setColorSchemeAndUnsavedChanges: PropTypes.func,
+ onSubmit: PropTypes.func,
addSuccessToast: PropTypes.func.isRequired,
+ onlyApply: PropTypes.bool,
};
const defaultProps = {
onHide: () => {},
- onDashboardSave: () => {},
+ setColorSchemeAndUnsavedChanges: () => {},
+ onSubmit: () => {},
show: false,
+ colorScheme: undefined,
+ onlyApply: false,
};
class PropertiesModal extends React.PureComponent {
@@ -55,6 +62,7 @@ class PropertiesModal extends React.PureComponent {
slug: '',
owners: [],
json_metadata: '',
+ colorScheme: props.colorScheme,
},
isDashboardLoaded: false,
isAdvancedOpen: false,
@@ -62,15 +70,19 @@ class PropertiesModal extends React.PureComponent {
this.onChange = this.onChange.bind(this);
this.onMetadataChange = this.onMetadataChange.bind(this);
this.onOwnersChange = this.onOwnersChange.bind(this);
- this.save = this.save.bind(this);
+ this.submit = this.submit.bind(this);
this.toggleAdvanced = this.toggleAdvanced.bind(this);
this.loadOwnerOptions = this.loadOwnerOptions.bind(this);
this.handleErrorResponse = this.handleErrorResponse.bind(this);
+ this.onColorSchemeChange = this.onColorSchemeChange.bind(this);
}
componentDidMount() {
this.fetchDashboardDetails();
}
+ onColorSchemeChange(value) {
+ this.updateFormState('colorScheme', value);
+ }
onOwnersChange(value) {
this.updateFormState('owners', value);
@@ -155,39 +167,55 @@ class PropertiesModal extends React.PureComponent {
});
}
- save(e) {
+ submit(e) {
e.preventDefault();
e.stopPropagation();
const { values } = this.state;
+ const { onlyApply } = this.props;
const owners = values.owners.map(o => o.value);
-
- SupersetClient.put({
- endpoint: `/api/v1/dashboard/${this.props.dashboardId}`,
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({
- dashboard_title: values.dashboard_title,
- slug: values.slug || null,
- json_metadata: values.json_metadata || null,
- owners,
- }),
- }).then(({ json }) => {
- this.props.addSuccessToast(t('The dashboard has been saved'));
- this.props.onDashboardSave({
+ if (onlyApply) {
+ this.props.onSubmit({
id: this.props.dashboardId,
- title: json.result.dashboard_title,
- slug: json.result.slug,
- jsonMetadata: json.result.json_metadata,
- ownerIds: json.result.owners,
+ title: values.dashboard_title,
+ slug: values.slug,
+ jsonMetadata: values.json_metadata,
+ ownerIds: owners,
+ colorScheme: values.colorScheme,
});
this.props.onHide();
- }, this.handleErrorResponse);
+ } else {
+ SupersetClient.put({
+ endpoint: `/api/v1/dashboard/${this.props.dashboardId}`,
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ dashboard_title: values.dashboard_title,
+ slug: values.slug || null,
+ json_metadata: values.json_metadata || null,
+ owners,
+ }),
+ }).then(({ json }) => {
+ this.props.addSuccessToast(t('The dashboard has been saved'));
+ this.props.onSubmit({
+ id: this.props.dashboardId,
+ title: json.result.dashboard_title,
+ slug: json.result.slug,
+ jsonMetadata: json.result.json_metadata,
+ ownerIds: json.result.owners,
+ colorScheme: values.colorScheme,
+ });
+ this.props.onHide();
+ }, this.handleErrorResponse);
+ }
}
render() {
- const { values, isDashboardLoaded, isAdvancedOpen } = this.state;
+ const { values, isDashboardLoaded, isAdvancedOpen, errors } = this.state;
+ const { onHide, onlyApply } = this.props;
+
+ const saveLabel = onlyApply ? t('Apply') : t('Save');
return (
<Modal show={this.props.show} onHide={this.props.onHide} bsSize="lg">
- <form onSubmit={this.save}>
+ <form onSubmit={this.submit}>
<Modal.Header closeButton>
<Modal.Title>
<div>
@@ -249,6 +277,13 @@ class PropertiesModal extends React.PureComponent {
)}
</p>
</Col>
+ <Col md={6}>
+ <h3 style={{ marginTop: '1em' }}>{t('Colors')}</h3>
+ <ColorSchemeControlWrapper
+ onChange={this.onColorSchemeChange}
+ colorScheme={values.colorScheme}
+ />
+ </Col>
</Row>
<Row>
<Col md={12}>
@@ -300,11 +335,11 @@ class PropertiesModal extends React.PureComponent {
bsSize="sm"
bsStyle="primary"
className="m-r-5"
- disabled={this.state.errors.length > 0}
+ disabled={errors.length > 0}
>
- {t('Save')}
+ {saveLabel}
</Button>
- <Button type="button" bsSize="sm" onClick={this.props.onHide}>
+ <Button type="button" bsSize="sm" onClick={onHide}>
{t('Cancel')}
</Button>
<Dialog
diff --git a/superset-frontend/src/dashboard/components/RefreshIntervalModal.jsx b/superset-frontend/src/dashboard/components/RefreshIntervalModal.jsx
index 592c322..c6957a3 100644
--- a/superset-frontend/src/dashboard/components/RefreshIntervalModal.jsx
+++ b/superset-frontend/src/dashboard/components/RefreshIntervalModal.jsx
@@ -22,7 +22,8 @@ import Select from 'src/components/Select';
import { t } from '@superset-ui/translation';
import { Alert, Button } from 'react-bootstrap';
-import ModalTrigger from '../../components/ModalTrigger';
+import ModalTrigger from 'src/components/ModalTrigger';
+import FormLabel from 'src/components/FormLabel';
const propTypes = {
triggerNode: PropTypes.node.isRequired,
@@ -96,7 +97,7 @@ class RefreshIntervalModal extends React.PureComponent {
modalTitle={t('Refresh Interval')}
modalBody={
<div>
- {t('Choose the refresh frequency for this dashboard')}
+ <FormLabel>{t('Refresh frequency')}</FormLabel>
<Select
options={options}
value={this.state.refreshFrequency}
@@ -115,10 +116,12 @@ class RefreshIntervalModal extends React.PureComponent {
}
modalFooter={
<>
- <Button bsStyle="primary" onClick={this.onSave}>
+ <Button bsStyle="primary" bsSize="sm" onClick={this.onSave}>
{editMode ? t('Save') : t('Save for this session')}
</Button>
- <Button onClick={this.onCancel}>{t('Cancel')}</Button>
+ <Button onClick={this.onCancel} bsSize="sm">
+ {t('Cancel')}
+ </Button>
</>
}
/>
diff --git a/superset-frontend/src/dashboard/components/SliceAdder.jsx b/superset-frontend/src/dashboard/components/SliceAdder.jsx
index f9c256f..76ebe52 100644
--- a/superset-frontend/src/dashboard/components/SliceAdder.jsx
+++ b/superset-frontend/src/dashboard/components/SliceAdder.jsx
@@ -20,7 +20,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { DropdownButton, MenuItem } from 'react-bootstrap';
-import { CellMeasurer, CellMeasurerCache, List } from 'react-virtualized';
+import { List } from 'react-virtualized';
import SearchInput, { createFilter } from 'react-search-input';
import { t } from '@superset-ui/translation';
@@ -60,14 +60,9 @@ const KEYS_TO_SORT = [
];
const MARGIN_BOTTOM = 16;
-const SIDEPANE_HEADER_HEIGHT = 55;
+const SIDEPANE_HEADER_HEIGHT = 30;
const SLICE_ADDER_CONTROL_HEIGHT = 64;
-const DEFAULT_CELL_HEIGHT = 136;
-
-const cache = new CellMeasurerCache({
- defaultHeight: DEFAULT_CELL_HEIGHT,
- fixedWidth: true,
-});
+const DEFAULT_CELL_HEIGHT = 112;
class SliceAdder extends React.Component {
static sortByComparator(attr) {
@@ -91,7 +86,6 @@ class SliceAdder extends React.Component {
sortBy: KEYS_TO_SORT.findIndex(item => item.key === 'changed_on'),
selectedSliceIdsSet: new Set(props.selectedSliceIds),
};
-
this.rowRenderer = this.rowRenderer.bind(this);
this.searchUpdated = this.searchUpdated.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
@@ -159,7 +153,7 @@ class SliceAdder extends React.Component {
});
}
- rowRenderer({ key, index, style, parent }) {
+ rowRenderer({ key, index, style }) {
const { filteredSlices, selectedSliceIdsSet } = this.state;
const cellData = filteredSlices[index];
const isSelected = selectedSliceIdsSet.has(cellData.slice_id);
@@ -190,23 +184,16 @@ class SliceAdder extends React.Component {
style={{}}
>
{({ dragSourceRef }) => (
- <CellMeasurer
- cache={cache}
- columnIndex={0}
- key={key}
- parent={parent}
- rowIndex={index}
- >
- <AddSliceCard
- innerRef={dragSourceRef}
- style={style}
- sliceName={cellData.slice_name}
- lastModified={cellData.changed_on_humanized}
- visType={cellData.viz_type}
- datasourceLink={cellData.datasource_link}
- isSelected={isSelected}
- />
- </CellMeasurer>
+ <AddSliceCard
+ innerRef={dragSourceRef}
+ style={style}
+ sliceName={cellData.slice_name}
+ lastModified={cellData.changed_on_humanized}
+ visType={cellData.viz_type}
+ datasourceUrl={cellData.datasource_url}
+ datasourceName={cellData.datasource_name}
+ isSelected={isSelected}
+ />
)}
</DragDroppable>
);
@@ -227,7 +214,6 @@ class SliceAdder extends React.Component {
onChange={this.searchUpdated}
onKeyPress={this.handleKeyPress}
/>
-
<DropdownButton
title={`Sort by ${KEYS_TO_SORT[this.state.sortBy].label}`}
onSelect={this.handleSelect}
@@ -246,8 +232,7 @@ class SliceAdder extends React.Component {
width={376}
height={slicesListHeight}
rowCount={this.state.filteredSlices.length}
- deferredMeasurementCache={cache}
- rowHeight={cache.rowHeight}
+ rowHeight={DEFAULT_CELL_HEIGHT}
rowRenderer={this.rowRenderer}
searchTerm={this.state.searchTerm}
sortBy={this.state.sortBy}
diff --git a/superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.jsx b/superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.jsx
index 494f4b5..404561e 100644
--- a/superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.jsx
+++ b/superset-frontend/src/dashboard/components/dnd/AddSliceDragPreview.jsx
@@ -72,9 +72,10 @@ function AddSliceDragPreview({ dragItem, slices, isDragging, currentOffset }) {
transform: `translate(${currentOffset.x}px, ${currentOffset.y}px)`,
}}
sliceName={slice.slice_name}
- lastModified={slice.modified}
+ lastModified={slice.changed_on_humanized}
visType={slice.viz_type}
- datasourceLink={slice.datasource_link}
+ datasourceUrl={slice.datasource_url}
+ datasourceName={slice.datasource_name}
/>
);
}
diff --git a/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx b/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx
index d4dad08..e3edd2b 100644
--- a/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx
+++ b/superset-frontend/src/dashboard/components/filterscope/FilterScopeSelector.jsx
@@ -513,9 +513,11 @@ export default class FilterScopeSelector extends React.PureComponent {
</div>
<div className="dashboard-modal-actions-container">
- <Button onClick={this.onClose}>{t('Close')}</Button>
+ <Button bsSize="sm" onClick={this.onClose}>
+ {t('Close')}
+ </Button>
{showSelector && (
- <Button bsStyle="primary" onClick={this.onSave}>
+ <Button bsSize="sm" bsStyle="primary" onClick={this.onSave}>
{t('Save')}
</Button>
)}
diff --git a/superset-frontend/src/dashboard/containers/DashboardBuilder.jsx b/superset-frontend/src/dashboard/containers/DashboardBuilder.jsx
index 9887295..5f31d47 100644
--- a/superset-frontend/src/dashboard/containers/DashboardBuilder.jsx
+++ b/superset-frontend/src/dashboard/containers/DashboardBuilder.jsx
@@ -36,7 +36,6 @@ function mapStateToProps({ dashboardLayout: undoableLayout, dashboardState }) {
editMode: dashboardState.editMode,
showBuilderPane: dashboardState.showBuilderPane,
directPathToChild: dashboardState.directPathToChild,
- builderPaneType: dashboardState.builderPaneType,
colorScheme: dashboardState.colorScheme,
};
}
diff --git a/superset-frontend/src/dashboard/containers/DashboardHeader.jsx b/superset-frontend/src/dashboard/containers/DashboardHeader.jsx
index 962fc9a..4bdc249 100644
--- a/superset-frontend/src/dashboard/containers/DashboardHeader.jsx
+++ b/superset-frontend/src/dashboard/containers/DashboardHeader.jsx
@@ -30,6 +30,7 @@ import {
fetchFaveStar,
saveFaveStar,
savePublished,
+ setColorSchemeAndUnsavedChanges,
fetchCharts,
updateCss,
onChange,
@@ -83,7 +84,8 @@ function mapStateToProps({
hasUnsavedChanges: !!dashboardState.hasUnsavedChanges,
maxUndoHistoryExceeded: !!dashboardState.maxUndoHistoryExceeded,
editMode: !!dashboardState.editMode,
- builderPaneType: dashboardState.builderPaneType,
+ slug: dashboardInfo.slug,
+ metadata: dashboardInfo.metadata,
};
}
@@ -97,6 +99,7 @@ function mapDispatchToProps(dispatch) {
onRedo: redoLayoutAction,
setEditMode,
showBuilderPane,
+ setColorSchemeAndUnsavedChanges,
fetchFaveStar,
saveFaveStar,
savePublished,
diff --git a/superset-frontend/src/dashboard/reducers/dashboardState.js b/superset-frontend/src/dashboard/reducers/dashboardState.js
index fc7e079..afb8521 100644
--- a/superset-frontend/src/dashboard/reducers/dashboardState.js
+++ b/superset-frontend/src/dashboard/reducers/dashboardState.js
@@ -35,7 +35,6 @@ import {
SET_DIRECT_PATH,
SET_FOCUSED_FILTER_FIELD,
} from '../actions/dashboardState';
-import { BUILDER_PANE_TYPE } from '../util/constants';
export default function dashboardStateReducer(state = {}, action) {
const actionHandlers = {
@@ -70,9 +69,6 @@ export default function dashboardStateReducer(state = {}, action) {
return {
...state,
editMode: action.editMode,
- builderPaneType: action.editMode
- ? BUILDER_PANE_TYPE.ADD_COMPONENTS
- : BUILDER_PANE_TYPE.NONE,
};
},
[SET_MAX_UNDO_HISTORY_EXCEEDED]() {
@@ -80,7 +76,7 @@ export default function dashboardStateReducer(state = {}, action) {
return { ...state, maxUndoHistoryExceeded };
},
[SHOW_BUILDER_PANE]() {
- return { ...state, builderPaneType: action.builderPaneType };
+ return { ...state };
},
[SET_COLOR_SCHEME]() {
return {
@@ -108,7 +104,6 @@ export default function dashboardStateReducer(state = {}, action) {
hasUnsavedChanges: false,
maxUndoHistoryExceeded: false,
editMode: false,
- builderPaneType: BUILDER_PANE_TYPE.NONE,
updatedColorScheme: false,
};
},
diff --git a/superset-frontend/src/dashboard/reducers/getInitialState.js b/superset-frontend/src/dashboard/reducers/getInitialState.js
index 4f77b07..770e249 100644
--- a/superset-frontend/src/dashboard/reducers/getInitialState.js
+++ b/superset-frontend/src/dashboard/reducers/getInitialState.js
@@ -31,7 +31,6 @@ import { getParam } from '../../modules/utils';
import { applyDefaultFormData } from '../../explore/store';
import { buildActiveFilters } from '../util/activeDashboardFilters';
import {
- BUILDER_PANE_TYPE,
DASHBOARD_HEADER_ID,
GRID_DEFAULT_CHART_WIDTH,
GRID_COLUMN_COUNT,
@@ -301,10 +300,6 @@ export default function (bootstrapData) {
colorScheme: dashboard.metadata.color_scheme,
editMode: dashboard.dash_edit_perm && editMode,
isPublished: dashboard.published,
- builderPaneType:
- dashboard.dash_edit_perm && editMode
- ? BUILDER_PANE_TYPE.ADD_COMPONENTS
- : BUILDER_PANE_TYPE.NONE,
hasUnsavedChanges: false,
maxUndoHistoryExceeded: false,
},
diff --git a/superset-frontend/src/dashboard/stylesheets/builder-sidepane.less b/superset-frontend/src/dashboard/stylesheets/builder-sidepane.less
index fd56f6f..7d9c35f 100644
--- a/superset-frontend/src/dashboard/stylesheets/builder-sidepane.less
+++ b/superset-frontend/src/dashboard/stylesheets/builder-sidepane.less
@@ -94,11 +94,13 @@
.chart-card {
border: 1px solid @gray-light;
font-weight: @font-weight-light;
- padding: 16px;
- margin: 0 16px 16px 16px;
+ padding: 8px;
+ margin: 0 8px 8px 8px;
position: relative;
cursor: move;
background: fade(@lightest, @opacity-medium-light);
+ white-space: nowrap;
+ overflow: hidden;
&:hover {
background: @gray-bg;
@@ -147,6 +149,7 @@
.slice-adder-container {
position: relative;
+ background-color: white;
min-height: 200px; /* for loader positioning */
.error-message {
@@ -185,18 +188,4 @@
outline: none;
}
}
-
- .color-scheme-container {
- list-style: none;
- margin: 0;
- padding: 0;
- display: flex;
- align-items: center;
- }
-
- .color-scheme-container li {
- flex-basis: 9px;
- height: 10px;
- margin: 9px 1px;
- }
}
diff --git a/superset-frontend/src/dashboard/stylesheets/dashboard.less b/superset-frontend/src/dashboard/stylesheets/dashboard.less
index b28b8ef..97f2f26 100644
--- a/superset-frontend/src/dashboard/stylesheets/dashboard.less
+++ b/superset-frontend/src/dashboard/stylesheets/dashboard.less
@@ -115,19 +115,6 @@ body {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
-
- & > :nth-child(3) {
- border-radius: @border-radius-normal 0px 0px @border-radius-normal;
- border-right: none;
- }
-
- & > :nth-child(4) {
- border-radius: 0px @border-radius-normal @border-radius-normal 0px;
- }
-
- & > :not(:nth-child(3)):not(:last-child) {
- margin-right: 8px;
- }
}
}
diff --git a/superset-frontend/src/dashboard/util/constants.ts b/superset-frontend/src/dashboard/util/constants.ts
index 5eae2a8..dbfd61b 100644
--- a/superset-frontend/src/dashboard/util/constants.ts
+++ b/superset-frontend/src/dashboard/util/constants.ts
@@ -63,13 +63,6 @@ export const SAVE_TYPE_NEWDASHBOARD = 'newDashboard';
// could be overwritten by server-side config
export const DASHBOARD_POSITION_DATA_LIMIT = 65535;
-// Dashboard pane types
-export const BUILDER_PANE_TYPE = {
- NONE: 'NONE',
- ADD_COMPONENTS: 'ADD_COMPONENTS',
- COLORS: 'COLORS',
-};
-
// filter indicators display length
export const FILTER_INDICATORS_DISPLAY_LENGTH = 3;
diff --git a/superset-frontend/src/dashboard/util/propShapes.jsx b/superset-frontend/src/dashboard/util/propShapes.jsx
index e1eb01c..3052ee5 100644
--- a/superset-frontend/src/dashboard/util/propShapes.jsx
+++ b/superset-frontend/src/dashboard/util/propShapes.jsx
@@ -102,7 +102,6 @@ export const dashboardStatePropShape = PropTypes.shape({
expandedSlices: PropTypes.object,
editMode: PropTypes.bool,
isPublished: PropTypes.bool.isRequired,
- builderPaneType: PropTypes.string.isRequired,
colorNamespace: PropTypes.string,
colorScheme: PropTypes.string,
updatedColorScheme: PropTypes.bool,
diff --git a/superset-frontend/src/explore/components/controls/ColorSchemeControl.jsx b/superset-frontend/src/explore/components/controls/ColorSchemeControl.jsx
index a9e285a..428cfe7 100644
--- a/superset-frontend/src/explore/components/controls/ColorSchemeControl.jsx
+++ b/superset-frontend/src/explore/components/controls/ColorSchemeControl.jsx
@@ -22,6 +22,7 @@ import { isFunction } from 'lodash';
import { CreatableSelect } from 'src/components/Select';
import ControlHeader from '../ControlHeader';
import TooltipWrapper from '../../../components/TooltipWrapper';
+import './ColorSchemeControl.less';
const propTypes = {
description: PropTypes.string,
@@ -29,6 +30,7 @@ const propTypes = {
name: PropTypes.string.isRequired,
onChange: PropTypes.func,
value: PropTypes.string,
+ clearable: PropTypes.bool,
default: PropTypes.string,
choices: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.array),
@@ -41,6 +43,7 @@ const propTypes = {
const defaultProps = {
choices: [],
schemes: {},
+ clearable: false,
onChange: () => {},
};
@@ -111,7 +114,7 @@ export default class ColorSchemeControl extends React.PureComponent {
options,
value: this.props.value,
autosize: false,
- clearable: false,
+ clearable: this.props.clearable,
onChange: this.onChange,
optionRenderer: this.renderOption,
valueRenderer: this.renderOption,
diff --git a/superset-frontend/spec/javascripts/dashboard/fixtures/mockDashboardState.js b/superset-frontend/src/explore/components/controls/ColorSchemeControl.less
similarity index 68%
copy from superset-frontend/spec/javascripts/dashboard/fixtures/mockDashboardState.js
copy to superset-frontend/src/explore/components/controls/ColorSchemeControl.less
index 1727422..94213b7 100644
--- a/superset-frontend/spec/javascripts/dashboard/fixtures/mockDashboardState.js
+++ b/superset-frontend/src/explore/components/controls/ColorSchemeControl.less
@@ -16,18 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { BUILDER_PANE_TYPE } from 'src/dashboard/util/constants';
-import { sliceId } from './mockChartQueries';
+.color-scheme-container {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ align-items: center;
-export default {
- sliceIds: [sliceId],
- expandedSlices: {},
- editMode: false,
- builderPaneType: BUILDER_PANE_TYPE.NONE,
- hasUnsavedChanges: false,
- maxUndoHistoryExceeded: false,
- isStarred: true,
- isPublished: true,
- css: '',
- focusedFilterField: [],
-};
+ li {
+ flex-basis: 9px;
+ height: 10px;
+ margin: 9px 1px;
+ }
+}
diff --git a/superset-frontend/src/explore/main.less b/superset-frontend/src/explore/main.less
index 856258e..4ca4a76 100644
--- a/superset-frontend/src/explore/main.less
+++ b/superset-frontend/src/explore/main.less
@@ -61,20 +61,6 @@
background-color: transparent !important;
}
-.color-scheme-container {
- list-style: none;
- margin: 0;
- padding: 0;
- display: flex;
- align-items: center;
-
- li {
- flex-basis: 9px;
- height: 10px;
- margin: 9px 1px;
- }
-}
-
.control-panel-section {
.panel-body {
margin-left: 15px;
diff --git a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx
index 273b01b..f91fb05 100644
--- a/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx
+++ b/superset-frontend/src/views/CRUD/dashboard/DashboardList.tsx
@@ -495,9 +495,8 @@ class DashboardList extends React.PureComponent<Props, State> {
{dashboardToEdit && (
<PropertiesModal
dashboardId={dashboardToEdit.id}
- onDashboardSave={this.handleDashboardEdit}
onHide={() => this.setState({ dashboardToEdit: null })}
- show
+ onSubmit={this.handleDashboardEdit}
/>
)}
<ListView
diff --git a/superset-frontend/stylesheets/less/cosmo/bootswatch.less b/superset-frontend/stylesheets/less/cosmo/bootswatch.less
index f65e95a..6daabb4 100644
--- a/superset-frontend/stylesheets/less/cosmo/bootswatch.less
+++ b/superset-frontend/stylesheets/less/cosmo/bootswatch.less
@@ -234,6 +234,7 @@ table,
& > li > a:hover,
& > li > a:focus {
background-image: none;
+ text-decoration: none;
}
}
diff --git a/superset/dashboards/dao.py b/superset/dashboards/dao.py
index 5859640..6345bb7 100644
--- a/superset/dashboards/dao.py
+++ b/superset/dashboards/dao.py
@@ -152,10 +152,9 @@ class DashboardDAO(BaseDAO):
key: v for key, v in default_filters_data.items() if int(key) in slice_ids
}
md["default_filters"] = json.dumps(applicable_filters)
+ md["color_scheme"] = data.get("color_scheme")
if data.get("color_namespace"):
md["color_namespace"] = data.get("color_namespace")
- if data.get("color_scheme"):
- md["color_scheme"] = data.get("color_scheme")
if data.get("label_colors"):
md["label_colors"] = data.get("label_colors")
dashboard.json_metadata = json.dumps(md)
diff --git a/superset/dashboards/schemas.py b/superset/dashboards/schemas.py
index ca9c25c..848a80c 100644
--- a/superset/dashboards/schemas.py
+++ b/superset/dashboards/schemas.py
@@ -104,7 +104,7 @@ class DashboardJSONMetadataSchema(Schema):
default_filters = fields.Str()
stagger_refresh = fields.Boolean()
stagger_time = fields.Integer()
- color_scheme = fields.Str()
+ color_scheme = fields.Str(allow_none=True)
label_colors = fields.Dict()
diff --git a/superset/views/chart/views.py b/superset/views/chart/views.py
index 896948e..db100a7 100644
--- a/superset/views/chart/views.py
+++ b/superset/views/chart/views.py
@@ -84,6 +84,7 @@ class SliceAsync(SliceModelView): # pylint: disable=too-many-ancestors
"creator",
"datasource_id",
"datasource_link",
+ "datasource_url",
"datasource_name_text",
"datasource_type",
"description",