Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Color consistency #17089

Merged
merged 31 commits into from
Nov 3, 2021
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
c01c940
Update label colors on the fly
geido Sep 8, 2021
df8d585
Clean up
geido Sep 8, 2021
8b60722
Improve getFormDataWithExtraFilters
geido Sep 8, 2021
92c4829
Merge branch 'master' of https://github.com/apache/superset into fix/…
geido Oct 7, 2021
f284259
Improve code structure
geido Oct 7, 2021
69b7b62
Remove labelColors from formData
geido Oct 7, 2021
1c24ec5
Merge branch 'master' of https://github.com/apache/superset into fix/…
geido Oct 8, 2021
3f9ea84
Exclude label_colors from URL
geido Oct 8, 2021
70b477e
Refactor color scheme implementation
geido Oct 13, 2021
600e1e2
Clean up
geido Oct 13, 2021
c97cbc3
Refactor and simplify
geido Oct 15, 2021
bf1e1fb
Merge branch 'master' of https://github.com/apache/superset into fix/…
geido Oct 15, 2021
13aacf1
Fix lint
geido Oct 15, 2021
eb4b85a
Merge with latest changes
geido Oct 18, 2021
8b94bfe
Remove unnecessary ColorMapControl
geido Oct 18, 2021
0f408db
Merge branch 'master' of https://github.com/apache/superset into fix/…
geido Oct 20, 2021
5eb2e5a
Merge
geido Oct 26, 2021
a327e74
Lint
geido Oct 26, 2021
c70d6ba
Give json color scheme precedence
geido Oct 26, 2021
40640c7
Add label_colors prop in metadata
geido Oct 27, 2021
3520606
Merge branch 'master' of https://github.com/apache/superset into fix/…
geido Nov 2, 2021
56d9bc8
Separate owners and dashboard meta requests
geido Nov 2, 2021
81359c2
Remove label_colors control
geido Nov 3, 2021
f24d57e
bump superset-ui 0.18.19
geido Nov 3, 2021
dfe719b
Merge branch 'master' of https://github.com/apache/superset into fix/…
geido Nov 3, 2021
98650af
Fix end of file
geido Nov 3, 2021
3988496
Update tests
geido Nov 3, 2021
364e39b
Fix lint
geido Nov 3, 2021
65ba985
Update Cypress
geido Nov 3, 2021
3fccee6
Update setColorScheme method
geido Nov 3, 2021
acacba5
Use Antd modal body
geido Nov 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions superset-frontend/src/chart/Chart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const propTypes = {
// formData contains chart's own filter parameter
// and merged with extra filter that current dashboard applying
formData: PropTypes.object.isRequired,
labelColors: PropTypes.object,
width: PropTypes.number,
height: PropTypes.number,
setControlValue: PropTypes.func,
Expand Down
2 changes: 2 additions & 0 deletions superset-frontend/src/chart/ChartRenderer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const propTypes = {
datasource: PropTypes.object,
initialValues: PropTypes.object,
formData: PropTypes.object.isRequired,
labelColors: PropTypes.object,
height: PropTypes.number,
width: PropTypes.number,
setControlValue: PropTypes.func,
Expand Down Expand Up @@ -100,6 +101,7 @@ class ChartRenderer extends React.Component {
nextProps.height !== this.props.height ||
nextProps.width !== this.props.width ||
nextProps.triggerRender ||
nextProps.labelColors !== this.props.labelColors ||
nextProps.formData.color_scheme !== this.props.formData.color_scheme ||
nextProps.cacheBusterProp !== this.props.cacheBusterProp
);
Expand Down
21 changes: 20 additions & 1 deletion superset-frontend/src/dashboard/actions/dashboardInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,32 @@
* under the License.
*/
import { Dispatch } from 'redux';
import { makeApi } from '@superset-ui/core';
import { makeApi, CategoricalColorNamespace } from '@superset-ui/core';
import { isString } from 'lodash';
import { ChartConfiguration, DashboardInfo } from '../reducers/types';

export const DASHBOARD_INFO_UPDATED = 'DASHBOARD_INFO_UPDATED';

// updates partially changed dashboard info
export function dashboardInfoChanged(newInfo: { metadata: any }) {
const { metadata } = newInfo;
const { color_namespace: namespace, label_colors: labelColors } = metadata;

const categoricalNamespace = CategoricalColorNamespace.getNamespace(
namespace,
);

categoricalNamespace.resetColors();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that in superset-frontend/src/dashboard/actions/hydrate.js you're not calling resetColors before setting the colors. Is it ok or do we need to change something?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine. Resetting the colors is only useful when the colors of the label change or are removed. This is only the case here. As for the QA approval, we will need to discuss how is best to proceed as this requires potentially disruptive changes in Superset-UI.


if (metadata?.label_colors) {
const colorMap = isString(labelColors)
? JSON.parse(labelColors)
: labelColors;
Object.keys(colorMap).forEach(label => {
categoricalNamespace.setColor(label, colorMap[label]);
});
}

return { type: DASHBOARD_INFO_UPDATED, newInfo };
}
export const SET_CHART_CONFIG_BEGIN = 'SET_CHART_CONFIG_BEGIN';
Expand Down
10 changes: 5 additions & 5 deletions superset-frontend/src/dashboard/actions/hydrate.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,16 @@ export const hydrateDashboard = (dashboardData, chartData) => (
// Priming the color palette with user's label-color mapping provided in
// the dashboard's JSON metadata
if (metadata?.label_colors) {
const scheme = metadata.color_scheme;
const namespace = metadata.color_namespace;
const colorMap = isString(metadata.label_colors)
? JSON.parse(metadata.label_colors)
: metadata.label_colors;
const categoricalNamespace = CategoricalColorNamespace.getNamespace(
namespace,
);

Object.keys(colorMap).forEach(label => {
CategoricalColorNamespace.getScale(scheme, namespace).setColor(
label,
colorMap[label],
);
categoricalNamespace.setColor(label, colorMap[label]);
});
}

Expand Down
19 changes: 5 additions & 14 deletions superset-frontend/src/dashboard/components/Header/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import moment from 'moment';
import React from 'react';
import PropTypes from 'prop-types';
import { styled, CategoricalColorNamespace, t } from '@superset-ui/core';
import { styled, t } from '@superset-ui/core';
import ButtonGroup from 'src/components/ButtonGroup';

import {
Expand Down Expand Up @@ -341,19 +341,10 @@ class Header extends React.PureComponent {
lastModifiedTime,
} = this.props;

const scale = CategoricalColorNamespace.getScale(
colorScheme,
colorNamespace,
);

// use the colorScheme for default labels
let labelColors = colorScheme ? scale.getColorMap() : {};
// but allow metadata to overwrite if it exists
// eslint-disable-next-line camelcase
const metadataLabelColors = dashboardInfo.metadata?.label_colors;
if (metadataLabelColors) {
labelColors = { ...labelColors, ...metadataLabelColors };
}
const labelColors =
colorScheme && dashboardInfo?.metadata?.label_colors
? dashboardInfo.metadata.label_colors
: {};

// check refresh frequency is for current session or persist
const refreshFrequency = shouldPersistRefreshFrequency
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
t,
SupersetClient,
getCategoricalSchemeRegistry,
CategoricalColorNamespace,
} from '@superset-ui/core';

import Modal from 'src/components/Modal';
Expand Down Expand Up @@ -140,14 +139,14 @@ class PropertiesModal extends React.PureComponent {
JsonEditor.preload();
}

onColorSchemeChange(value, { updateMetadata = true } = {}) {
onColorSchemeChange(colorScheme, { updateMetadata = true } = {}) {
// check that color_scheme is valid
const colorChoices = getCategoricalSchemeRegistry().keys();
const { json_metadata: jsonMetadata } = this.state.values;
const jsonMetadataObj = jsonMetadata?.length
? JSON.parse(jsonMetadata)
: {};
if (!colorChoices.includes(value)) {
if (!colorChoices.includes(colorScheme)) {
Modal.error({
title: 'Error',
content: t('A valid color scheme is required'),
Expand All @@ -161,20 +160,12 @@ class PropertiesModal extends React.PureComponent {
updateMetadata &&
Object.keys(jsonMetadataObj).includes('color_scheme')
) {
jsonMetadataObj.color_scheme = value;
jsonMetadataObj.label_colors = Object.keys(
jsonMetadataObj.label_colors ?? {},
).reduce(
(prev, next) => ({
...prev,
[next]: CategoricalColorNamespace.getScale(value)(next),
}),
{},
);
jsonMetadataObj.color_scheme = colorScheme;

this.onMetadataChange(jsonStringify(jsonMetadataObj));
}

this.updateFormState('colorScheme', value);
this.updateFormState('colorScheme', colorScheme);
}

onOwnersChange(value) {
Expand Down
12 changes: 6 additions & 6 deletions superset-frontend/src/dashboard/components/SaveModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import React from 'react';
import { Radio } from 'src/components/Radio';
import { RadioChangeEvent, Input } from 'src/common/components';
import Button from 'src/components/Button';
import { t, CategoricalColorNamespace, JsonResponse } from '@superset-ui/core';
import { t, JsonResponse } from '@superset-ui/core';

import ModalTrigger from 'src/components/ModalTrigger';
import Checkbox from 'src/components/Checkbox';
Expand Down Expand Up @@ -131,11 +131,11 @@ class SaveModal extends React.PureComponent<SaveModalProps, SaveModalState> {
lastModifiedTime,
} = this.props;

const scale = CategoricalColorNamespace.getScale(
colorScheme,
colorNamespace,
);
const labelColors = colorScheme ? scale.getColorMap() : {};
const labelColors =
colorScheme && dashboardInfo?.metadata?.label_colors
? dashboardInfo.metadata.label_colors
: {};

// check refresh frequency is for current session or persist
const refreshFrequency = shouldPersistRefreshFrequency
? currentRefreshFrequency
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ const propTypes = {
// from redux
chart: chartPropShape.isRequired,
formData: PropTypes.object.isRequired,
labelColors: PropTypes.object,
datasource: PropTypes.object,
slice: slicePropShape.isRequired,
sliceName: PropTypes.string.isRequired,
Expand Down Expand Up @@ -274,6 +275,7 @@ export default class Chart extends React.Component {
editMode,
filters,
formData,
labelColors,
updateSliceName,
sliceName,
toggleExpandSlice,
Expand Down Expand Up @@ -396,6 +398,7 @@ export default class Chart extends React.Component {
dashboardId={dashboardId}
initialValues={initialValues}
formData={formData}
labelColors={labelColors}
ownState={ownState}
filterState={filterState}
queriesResponse={chart.queriesResponse}
Expand Down
4 changes: 3 additions & 1 deletion superset-frontend/src/dashboard/containers/Chart.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function mapStateToProps(
(chart && chart.form_data && datasources[chart.form_data.datasource]) ||
PLACEHOLDER_DATASOURCE;
const { colorScheme, colorNamespace } = dashboardState;

const labelColors = dashboardInfo?.metadata?.label_colors || {};
// note: this method caches filters if possible to prevent render cascades
const formData = getFormDataWithExtraFilters({
layout: dashboardLayout.present,
Expand All @@ -75,13 +75,15 @@ function mapStateToProps(
sliceId: id,
nativeFilters,
dataMask,
labelColors,
});

formData.dashboardId = dashboardInfo.id;

return {
chart,
datasource,
labelColors,
slice: sliceEntities.slices[id],
timeout: dashboardInfo.common.conf.SUPERSET_WEBSERVER_TIMEOUT,
filters: getActiveFilters() || EMPTY_OBJECT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
import {
CategoricalColorNamespace,
DataRecordFilters,
JsonObject,
} from '@superset-ui/core';
import { DataRecordFilters, JsonObject } from '@superset-ui/core';
import { ChartQueryPayload, Charts, LayoutItem } from 'src/dashboard/types';
import { getExtraFormData } from 'src/dashboard/components/nativeFilters/utils';
import { DataMaskStateWithId } from 'src/dataMask/types';
Expand All @@ -45,6 +41,7 @@ export interface GetFormDataWithExtraFiltersArguments {
sliceId: number;
dataMask: DataMaskStateWithId;
nativeFilters: NativeFiltersState;
labelColors?: Record<string, string>;
}

// this function merge chart's formData with dashboard filters value,
Expand All @@ -61,11 +58,8 @@ export default function getFormDataWithExtraFilters({
sliceId,
layout,
dataMask,
labelColors,
}: GetFormDataWithExtraFiltersArguments) {
// Propagate color mapping to chart
const scale = CategoricalColorNamespace.getScale(colorScheme, colorNamespace);
const labelColors = scale.getColorMap();

// if dashboard metadata + filters have not changed, use cache if possible
const cachedFormData = cachedFormdataByChart[sliceId];
if (
Expand Down Expand Up @@ -109,11 +103,12 @@ export default function getFormDataWithExtraFilters({

const formData = {
...chart.formData,
...(colorScheme && { color_scheme: colorScheme }),
label_colors: labelColors,
...(colorScheme && { color_scheme: colorScheme }),
extra_filters: getEffectiveExtraFilters(filters),
...extraData,
};

cachedFiltersByChart[sliceId] = filters;
cachedFormdataByChart[sliceId] = { ...formData, dataMask };

Expand Down
4 changes: 3 additions & 1 deletion superset-frontend/src/explore/components/Control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ export default function Control(props: ControlProps) {

const ControlComponent = typeof type === 'string' ? controlMap[type] : type;
if (!ControlComponent) {
return <>Unknown controlType: {type}</>;
// eslint-disable-next-line no-console
console.warn(`Unknown controlType: ${type}`);
return null;
}

return (
Expand Down
55 changes: 54 additions & 1 deletion superset-frontend/src/explore/components/ExploreChartHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import PropTypes from 'prop-types';
import Icons from 'src/components/Icons';
import { styled, t } from '@superset-ui/core';
import {
CategoricalColorNamespace,
SupersetClient,
styled,
t,
} from '@superset-ui/core';
import { Tooltip } from 'src/components/Tooltip';
import ReportModal from 'src/components/ReportModal';
import {
Expand All @@ -31,6 +36,7 @@ import {
} from 'src/reports/actions/reports';
import { isFeatureEnabled, FeatureFlag } from 'src/featureFlags';
import HeaderReportActionsDropdown from 'src/components/ReportModal/HeaderReportActionsDropdown';
import { getClientErrorObject } from 'src/utils/getClientErrorObject';
import { chartPropShape } from '../../dashboard/util/propShapes';
import ExploreActionButtons from './ExploreActionButtons';
import RowCountLabel from './RowCountLabel';
Expand All @@ -53,6 +59,7 @@ const propTypes = {
addHistory: PropTypes.func,
can_overwrite: PropTypes.bool.isRequired,
can_download: PropTypes.bool.isRequired,
dashboardId: PropTypes.number,
isStarred: PropTypes.bool.isRequired,
slice: PropTypes.object,
sliceName: PropTypes.string,
Expand Down Expand Up @@ -108,12 +115,15 @@ export class ExploreChartHeader extends React.PureComponent {
this.state = {
isPropertiesModalOpen: false,
showingReportModal: false,
existingOwners: [],
permissionsError: null,
};
this.openPropertiesModal = this.openPropertiesModal.bind(this);
this.closePropertiesModal = this.closePropertiesModal.bind(this);
this.showReportModal = this.showReportModal.bind(this);
this.hideReportModal = this.hideReportModal.bind(this);
this.renderReportModal = this.renderReportModal.bind(this);
this.fetchChartData = this.fetchChartData.bind(this);
}

componentDidMount() {
Expand All @@ -127,6 +137,47 @@ export class ExploreChartHeader extends React.PureComponent {
chart.id,
);
}
this.fetchChartData();
}

async fetchChartData() {
try {
const { dashboardId, slice } = this.props;
const response = await SupersetClient.get({
endpoint: `/api/v1/chart/${slice.slice_id}`,
});
const chart = response.json.result;
const dashboards = chart.dashboards || [];
const dashboard =
dashboardId &&
dashboards.length &&
dashboards.find(d => d.id === dashboardId);

if (dashboard && dashboard.json_metadata) {
// setting the chart to use the dashboard custom label colors if any
const labelColors =
JSON.parse(dashboard.json_metadata).label_colors || {};
const categoricalNamespace = CategoricalColorNamespace.getNamespace();

Object.keys(labelColors).forEach(label => {
categoricalNamespace.setColor(label, labelColors[label]);
});
}

const existingOwners = chart.owners.map(owner => ({
value: owner.id,
label: `${owner.first_name} ${owner.last_name}`,
}));

this.setState({
existingOwners,
});
} catch (response) {
const clientError = await getClientErrorObject(response);
this.setState({
permissionsError: clientError,
});
}
}

getSliceName() {
Expand Down Expand Up @@ -244,6 +295,8 @@ export class ExploreChartHeader extends React.PureComponent {
onHide={this.closePropertiesModal}
onSave={this.props.sliceUpdated}
slice={this.props.slice}
error={this.state.permissionsError}
existingOwners={this.state.existingOwners}
/>
<Tooltip
id="edit-desc-tooltip"
Expand Down
Loading