You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by mi...@apache.org on 2024/03/14 12:35:18 UTC

(superset) 02/05: fix(dashboard): Only fetch CSS templates for dashboard header menu when in edit mode (#27411)

This is an automated email from the ASF dual-hosted git repository.

michaelsmolina pushed a commit to branch 4.0
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 759863553d342f9c72a7dcd66661b39adeaeb707
Author: Mark Skelton <ma...@federato.ai>
AuthorDate: Fri Mar 8 07:21:36 2024 -0600

    fix(dashboard): Only fetch CSS templates for dashboard header menu when in edit mode (#27411)
    
    Co-authored-by: Michael S. Molina <mi...@gmail.com>
    (cherry picked from commit fde93dcf08122d8b41ca296213e09616d1b71782)
---
 .../components/CssEditor/CssEditor.test.tsx        | 54 +++++++++++++---------
 .../src/dashboard/components/CssEditor/index.jsx   | 25 ++++++++--
 .../Header/HeaderActionsDropdown/index.jsx         | 22 +--------
 3 files changed, 55 insertions(+), 46 deletions(-)

diff --git a/superset-frontend/src/dashboard/components/CssEditor/CssEditor.test.tsx b/superset-frontend/src/dashboard/components/CssEditor/CssEditor.test.tsx
index 16b2a1afbb..28ac7672f6 100644
--- a/superset-frontend/src/dashboard/components/CssEditor/CssEditor.test.tsx
+++ b/superset-frontend/src/dashboard/components/CssEditor/CssEditor.test.tsx
@@ -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', () => ({
@@ -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();
@@ -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'));
diff --git a/superset-frontend/src/dashboard/components/CssEditor/index.jsx b/superset-frontend/src/dashboard/components/CssEditor/index.jsx
index ad12cb6c78..9fcd1768a8 100644
--- a/superset-frontend/src/dashboard/components/CssEditor/index.jsx
+++ b/superset-frontend/src/dashboard/components/CssEditor/index.jsx
@@ -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';
 
@@ -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 = {
@@ -60,6 +60,7 @@ 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);
@@ -67,6 +68,22 @@ class CssEditor extends React.PureComponent {
 
   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) {
@@ -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>
diff --git a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx
index f1a3f59039..1926a975bb 100644
--- a/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx
+++ b/superset-frontend/src/dashboard/components/Header/HeaderActionsDropdown/index.jsx
@@ -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';
@@ -99,7 +99,6 @@ class HeaderActionsDropdown extends React.PureComponent {
     super(props);
     this.state = {
       css: props.customCss,
-      cssTemplates: [],
       showReportSubMenu: null,
     };
 
@@ -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 }, () => {
@@ -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>
         )}