Skip to content

Commit

Permalink
fix(dashboard): Only fetch CSS templates for dashboard header menu wh…
Browse files Browse the repository at this point in the history
…en in edit mode (#27411)

Co-authored-by: Michael S. Molina <[email protected]>
  • Loading branch information
mskelton and michael-s-molina committed Mar 8, 2024
1 parent 9ced255 commit fde93dc
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { render, screen, waitFor } from 'spec/helpers/testing-library';
import { CssEditor as AceCssEditor } from 'src/components/AsyncAceEditor';
import { IAceEditorProps } from 'react-ace';
import userEvent from '@testing-library/user-event';
import fetchMock from 'fetch-mock';
import CssEditor from '.';

jest.mock('src/components/AsyncAceEditor', () => ({
Expand All @@ -33,46 +34,59 @@ jest.mock('src/components/AsyncAceEditor', () => ({
}));

const templates = [
{ label: 'Template A', css: 'background-color: red;' },
{ label: 'Template B', css: 'background-color: blue;' },
{ label: 'Template C', css: 'background-color: yellow;' },
{ template_name: 'Template A', css: 'background-color: red;' },
{ template_name: 'Template B', css: 'background-color: blue;' },
{ template_name: 'Template C', css: 'background-color: yellow;' },
];

fetchMock.get('glob:*/csstemplateasyncmodelview/api/read', {
result: templates,
});

AceCssEditor.preload = () => new Promise(() => {});

test('renders with default props', () => {
render(<CssEditor triggerNode={<>Click</>} />);
const defaultProps = {
triggerNode: <>Click</>,
addDangerToast: jest.fn(),
};

test('renders with default props', async () => {
await waitFor(() => render(<CssEditor {...defaultProps} />));
expect(screen.getByRole('button', { name: 'Click' })).toBeInTheDocument();
});

test('renders with initial CSS', () => {
test('renders with initial CSS', async () => {
const initialCss = 'margin: 10px;';
render(<CssEditor triggerNode={<>Click</>} initialCss={initialCss} />);
await waitFor(() =>
render(<CssEditor {...defaultProps} initialCss={initialCss} />),
);
userEvent.click(screen.getByRole('button', { name: 'Click' }));
expect(screen.getByText(initialCss)).toBeInTheDocument();
});

test('renders with templates', async () => {
render(<CssEditor triggerNode={<>Click</>} templates={templates} />);
await waitFor(() => render(<CssEditor {...defaultProps} />));
userEvent.click(screen.getByRole('button', { name: 'Click' }));
userEvent.hover(screen.getByText('Load a CSS template'));
await waitFor(() => {
templates.forEach(template =>
expect(screen.getByText(template.label)).toBeInTheDocument(),
expect(screen.getByText(template.template_name)).toBeInTheDocument(),
);
});
});

test('triggers onChange when using the editor', () => {
test('triggers onChange when using the editor', async () => {
const onChange = jest.fn();
const initialCss = 'margin: 10px;';
const additionalCss = 'color: red;';
render(
<CssEditor
triggerNode={<>Click</>}
initialCss={initialCss}
onChange={onChange}
/>,
await waitFor(() =>
render(
<CssEditor
{...defaultProps}
initialCss={initialCss}
onChange={onChange}
/>,
),
);
userEvent.click(screen.getByRole('button', { name: 'Click' }));
expect(onChange).not.toHaveBeenCalled();
Expand All @@ -82,12 +96,8 @@ test('triggers onChange when using the editor', () => {

test('triggers onChange when selecting a template', async () => {
const onChange = jest.fn();
render(
<CssEditor
triggerNode={<>Click</>}
templates={templates}
onChange={onChange}
/>,
await waitFor(() =>
render(<CssEditor {...defaultProps} onChange={onChange} />),
);
userEvent.click(screen.getByRole('button', { name: 'Click' }));
userEvent.click(screen.getByText('Load a CSS template'));
Expand Down
25 changes: 21 additions & 4 deletions superset-frontend/src/dashboard/components/CssEditor/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import PropTypes from 'prop-types';
import { AntdDropdown } from 'src/components';
import { Menu } from 'src/components/Menu';
import Button from 'src/components/Button';
import { t, styled } from '@superset-ui/core';
import { t, styled, SupersetClient } from '@superset-ui/core';
import ModalTrigger from 'src/components/ModalTrigger';
import { CssEditor as AceCssEditor } from 'src/components/AsyncAceEditor';

Expand All @@ -47,7 +47,7 @@ const propTypes = {
initialCss: PropTypes.string,
triggerNode: PropTypes.node.isRequired,
onChange: PropTypes.func,
templates: PropTypes.array,
addDangerToast: PropTypes.func.isRequired,
};

const defaultProps = {
Expand All @@ -60,13 +60,30 @@ class CssEditor extends React.PureComponent {
super(props);
this.state = {
css: props.initialCss,
templates: [],
};
this.changeCss = this.changeCss.bind(this);
this.changeCssTemplate = this.changeCssTemplate.bind(this);
}

componentDidMount() {
AceCssEditor.preload();

SupersetClient.get({ endpoint: '/csstemplateasyncmodelview/api/read' })
.then(({ json }) => {
const templates = json.result.map(row => ({
value: row.template_name,
css: row.css,
label: row.template_name,
}));

this.setState({ templates });
})
.catch(() => {
this.props.addDangerToast(
t('An error occurred while fetching available CSS templates'),
);
});
}

changeCss(css) {
Expand All @@ -80,10 +97,10 @@ class CssEditor extends React.PureComponent {
}

renderTemplateSelector() {
if (this.props.templates) {
if (this.state.templates) {
const menu = (
<Menu onClick={this.changeCssTemplate}>
{this.props.templates.map(template => (
{this.state.templates.map(template => (
<Menu.Item key={template.css}>{template.label}</Menu.Item>
))}
</Menu>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { isEmpty } from 'lodash';
import { SupersetClient, t } from '@superset-ui/core';
import { t } from '@superset-ui/core';
import { Menu } from 'src/components/Menu';
import { URL_PARAMS } from 'src/constants';
import ShareMenuItems from 'src/dashboard/components/menu/ShareMenuItems';
Expand Down Expand Up @@ -99,7 +99,6 @@ class HeaderActionsDropdown extends React.PureComponent {
super(props);
this.state = {
css: props.customCss,
cssTemplates: [],
showReportSubMenu: null,
};

Expand All @@ -109,23 +108,6 @@ class HeaderActionsDropdown extends React.PureComponent {
this.setShowReportSubMenu = this.setShowReportSubMenu.bind(this);
}

UNSAFE_componentWillMount() {
SupersetClient.get({ endpoint: '/csstemplateasyncmodelview/api/read' })
.then(({ json }) => {
const cssTemplates = json.result.map(row => ({
value: row.template_name,
css: row.css,
label: row.template_name,
}));
this.setState({ cssTemplates });
})
.catch(() => {
this.props.addDangerToast(
t('An error occurred while fetching available CSS templates'),
);
});
}

UNSAFE_componentWillReceiveProps(nextProps) {
if (this.props.customCss !== nextProps.customCss) {
this.setState({ css: nextProps.customCss }, () => {
Expand Down Expand Up @@ -257,8 +239,8 @@ class HeaderActionsDropdown extends React.PureComponent {
<CssEditor
triggerNode={<span>{t('Edit CSS')}</span>}
initialCss={this.state.css}
templates={this.state.cssTemplates}
onChange={this.changeCss}
addDangerToast={addDangerToast}
/>
</Menu.Item>
)}
Expand Down

0 comments on commit fde93dc

Please sign in to comment.