From 639addfaaa08ef95af1fe78d417ea10d0eab1240 Mon Sep 17 00:00:00 2001 From: Alexander Polyankin <alexander.polyankin@metabase.com> Date: Fri, 29 Oct 2021 11:58:12 +0300 Subject: [PATCH] Fix border width for the spinner (#18727) --- .../metabase/components/LoadingSpinner.css | 44 ----------------- .../metabase/components/LoadingSpinner.jsx | 25 ---------- .../LoadingSpinner/LoadingSpinner.jsx | 19 ++++++++ .../LoadingSpinner/LoadingSpinner.styled.jsx | 47 +++++++++++++++++++ .../components/LoadingSpinner/index.js | 1 + .../scenarios/dashboard/dashboard.cy.spec.js | 2 +- .../scenarios/dashboard/x-rays.cy.spec.js | 2 +- .../onboarding/home/activity-page.cy.spec.js | 2 +- .../search/recently-viewed.cy.spec.js | 2 +- .../search/search-typehead.cy.spec.js | 2 +- .../scenarios/question/filter.cy.spec.js | 2 +- .../scenarios/question/nulls.cy.spec.js | 4 +- ...es-show-row-details-on-pk-click.cy.spec.js | 2 +- 13 files changed, 76 insertions(+), 78 deletions(-) delete mode 100644 frontend/src/metabase/components/LoadingSpinner.css delete mode 100644 frontend/src/metabase/components/LoadingSpinner.jsx create mode 100644 frontend/src/metabase/components/LoadingSpinner/LoadingSpinner.jsx create mode 100644 frontend/src/metabase/components/LoadingSpinner/LoadingSpinner.styled.jsx create mode 100644 frontend/src/metabase/components/LoadingSpinner/index.js diff --git a/frontend/src/metabase/components/LoadingSpinner.css b/frontend/src/metabase/components/LoadingSpinner.css deleted file mode 100644 index 4294d35c247..00000000000 --- a/frontend/src/metabase/components/LoadingSpinner.css +++ /dev/null @@ -1,44 +0,0 @@ -.LoadingSpinner { - display: inline-block; - box-sizing: border-box; - width: 32px; - height: 32px; - border: 4px solid transparent; - border-top-color: currentColor; - border-radius: 99px; - - animation: LoadingSpinner-transition 1.3s infinite - cubic-bezier(0.785, 0.135, 0.15, 0.86); -} - -@media (prefers-reduced-motion) { - .LoadingSpinner { - animation: none; - } -} - -.LoadingSpinner:after { - content: ""; - - display: inherit; - box-sizing: inherit; - width: inherit; - height: inherit; - border: inherit; - border-color: currentColor; - border-radius: inherit; - - opacity: 0.25; - position: relative; - top: -4px; - left: -4px; -} - -@keyframes LoadingSpinner-transition { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/frontend/src/metabase/components/LoadingSpinner.jsx b/frontend/src/metabase/components/LoadingSpinner.jsx deleted file mode 100644 index dee77f59274..00000000000 --- a/frontend/src/metabase/components/LoadingSpinner.jsx +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-disable react/prop-types */ -import React, { Component } from "react"; - -import "./LoadingSpinner.css"; - -export default class LoadingSpinner extends Component { - static defaultProps = { - size: 32, - borderWidth: 4, - fill: "currentcolor", - spinnerClassName: "LoadingSpinner", - }; - - render() { - const { size, borderWidth, className, spinnerClassName } = this.props; - return ( - <div className={className}> - <div - className={spinnerClassName} - style={{ width: size, height: size, borderWidth }} - /> - </div> - ); - } -} diff --git a/frontend/src/metabase/components/LoadingSpinner/LoadingSpinner.jsx b/frontend/src/metabase/components/LoadingSpinner/LoadingSpinner.jsx new file mode 100644 index 00000000000..c3513edb3c0 --- /dev/null +++ b/frontend/src/metabase/components/LoadingSpinner/LoadingSpinner.jsx @@ -0,0 +1,19 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { SpinnerIcon, SpinnerRoot } from "./LoadingSpinner.styled"; + +const propTypes = { + className: PropTypes.string, + size: PropTypes.number, + borderWidth: PropTypes.number, +}; + +const LoadingSpinner = ({ className, size = 32, borderWidth = 4 }) => ( + <SpinnerRoot className={className} data-testid="loading-spinner"> + <SpinnerIcon iconSize={size} borderWidth={borderWidth} /> + </SpinnerRoot> +); + +LoadingSpinner.propTypes = propTypes; + +export default LoadingSpinner; diff --git a/frontend/src/metabase/components/LoadingSpinner/LoadingSpinner.styled.jsx b/frontend/src/metabase/components/LoadingSpinner/LoadingSpinner.styled.jsx new file mode 100644 index 00000000000..fea9264b968 --- /dev/null +++ b/frontend/src/metabase/components/LoadingSpinner/LoadingSpinner.styled.jsx @@ -0,0 +1,47 @@ +import styled, { keyframes } from "styled-components"; + +const spinnerAnimation = keyframes` + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +`; + +export const SpinnerRoot = styled.div` + font-size: 0; +`; + +export const SpinnerIcon = styled.div` + display: inline-block; + box-sizing: border-box; + width: ${props => `${props.iconSize}px`}; + height: ${props => `${props.iconSize}px`}; + border: ${props => `${props.borderWidth}px`} solid transparent; + border-top-color: currentColor; + border-radius: ${props => `${props.iconSize / 2}px`}; + + animation: ${spinnerAnimation} 1.3s infinite + cubic-bezier(0.785, 0.135, 0.15, 0.86); + + &::after { + content: ""; + + display: inherit; + box-sizing: inherit; + width: inherit; + height: inherit; + border: ${props => `${props.borderWidth}px`} solid currentColor; + border-radius: ${props => `${props.iconSize / 2}px`}; + + opacity: 0.25; + position: relative; + top: ${props => `-${props.borderWidth}px`}; + left: ${props => `-${props.borderWidth}px`}; + } + + @media (prefers-reduced-motion) { + animation: none; + } +`; diff --git a/frontend/src/metabase/components/LoadingSpinner/index.js b/frontend/src/metabase/components/LoadingSpinner/index.js new file mode 100644 index 00000000000..443fa62feb8 --- /dev/null +++ b/frontend/src/metabase/components/LoadingSpinner/index.js @@ -0,0 +1 @@ +export { default } from "./LoadingSpinner"; diff --git a/frontend/test/metabase/scenarios/dashboard/dashboard.cy.spec.js b/frontend/test/metabase/scenarios/dashboard/dashboard.cy.spec.js index 9e491d41f18..d4a0262c52d 100644 --- a/frontend/test/metabase/scenarios/dashboard/dashboard.cy.spec.js +++ b/frontend/test/metabase/scenarios/dashboard/dashboard.cy.spec.js @@ -425,7 +425,7 @@ describe("scenarios > dashboard", () => { cy.findByText("Orders, Count").click(); }); - cy.get(".LoadingSpinner").should("not.exist"); + cy.findByTestId("loading-spinner").should("not.exist"); cy.findAllByText("18,760").should("have.length", 2); }); }); diff --git a/frontend/test/metabase/scenarios/dashboard/x-rays.cy.spec.js b/frontend/test/metabase/scenarios/dashboard/x-rays.cy.spec.js index bb4f9676e4d..3097946c348 100644 --- a/frontend/test/metabase/scenarios/dashboard/x-rays.cy.spec.js +++ b/frontend/test/metabase/scenarios/dashboard/x-rays.cy.spec.js @@ -141,7 +141,7 @@ describe("scenarios > x-rays", () => { cy.contains("A look at your Orders table").click(); // There are a lot of spinners in this dashboard. Give them some time to disappear. - cy.get(".LoadingSpinner", { timeout: 10000 }).should("not.exist"); + cy.findByTestId("loading-spinner", { timeout: 10000 }).should("not.exist"); cy.button("Save this").click(); diff --git a/frontend/test/metabase/scenarios/onboarding/home/activity-page.cy.spec.js b/frontend/test/metabase/scenarios/onboarding/home/activity-page.cy.spec.js index d7a25ce59ad..d3474cac63c 100644 --- a/frontend/test/metabase/scenarios/onboarding/home/activity-page.cy.spec.js +++ b/frontend/test/metabase/scenarios/onboarding/home/activity-page.cy.spec.js @@ -68,7 +68,7 @@ describe("metabase > scenarios > home > activity-page", () => { .click(); sidebar().within(() => { - cy.get(".LoadingSpinner").should("not.exist"); + cy.findByTestId("loading-spinner").should("not.exist"); cy.findByText("Orders").click(); }); diff --git a/frontend/test/metabase/scenarios/onboarding/search/recently-viewed.cy.spec.js b/frontend/test/metabase/scenarios/onboarding/search/recently-viewed.cy.spec.js index b54283a48af..742a3fb84b8 100644 --- a/frontend/test/metabase/scenarios/onboarding/search/recently-viewed.cy.spec.js +++ b/frontend/test/metabase/scenarios/onboarding/search/recently-viewed.cy.spec.js @@ -23,7 +23,7 @@ describe(`search > recently viewed`, () => { cy.visit("/"); cy.findByPlaceholderText("Search…").click(); - cy.get(".LoadingSpinner").should("not.exist"); + cy.findByTestId("loading-spinner").should("not.exist"); assertRecentlyViewedItem(0, "Orders", "Question", "/question/1-orders"); assertRecentlyViewedItem( diff --git a/frontend/test/metabase/scenarios/onboarding/search/search-typehead.cy.spec.js b/frontend/test/metabase/scenarios/onboarding/search/search-typehead.cy.spec.js index b6e468a42fc..790db081ffd 100644 --- a/frontend/test/metabase/scenarios/onboarding/search/search-typehead.cy.spec.js +++ b/frontend/test/metabase/scenarios/onboarding/search/search-typehead.cy.spec.js @@ -15,7 +15,7 @@ import { USERS } from "__support__/e2e/cypress_data"; user === "admin" ? Object.entries(USERS).length : 1; cy.findByPlaceholderText("Search…").type("pers"); - cy.get(".LoadingSpinner").should("not.exist"); + cy.findByTestId("loading-spinner").should("not.exist"); cy.findAllByText(/personal collection$/i).should( "have.length", personalCollectionsLength, diff --git a/frontend/test/metabase/scenarios/question/filter.cy.spec.js b/frontend/test/metabase/scenarios/question/filter.cy.spec.js index 958486c4d38..07c7be4efa7 100644 --- a/frontend/test/metabase/scenarios/question/filter.cy.spec.js +++ b/frontend/test/metabase/scenarios/question/filter.cy.spec.js @@ -291,7 +291,7 @@ describe("scenarios > question > filter", () => { cy.findByText("Add filter").click(); cy.log("Reported failing on v0.36.4 and v0.36.5.1"); - cy.get(".LoadingSpinner").should("not.exist"); + cy.findByTestId("loading-spinner").should("not.exist"); cy.findAllByText("148.23"); // one of the subtotals for this product cy.findAllByText("Fantastic Wool Shirt").should("not.exist"); }); diff --git a/frontend/test/metabase/scenarios/question/nulls.cy.spec.js b/frontend/test/metabase/scenarios/question/nulls.cy.spec.js index 5990815092a..4af170b0d09 100644 --- a/frontend/test/metabase/scenarios/question/nulls.cy.spec.js +++ b/frontend/test/metabase/scenarios/question/nulls.cy.spec.js @@ -99,7 +99,7 @@ describe("scenarios > question > null", () => { cy.log("Reported failing in v0.37.0.2"); cy.get(".DashCard").within(() => { - cy.get(".LoadingSpinner").should("not.exist"); + cy.findByTestId("loading-spinner").should("not.exist"); cy.findByText("13626"); // [quarantine]: flaking in CircleCI, passing locally // TODO: figure out the cause of the failed test in CI after #13721 is merged @@ -150,7 +150,7 @@ describe("scenarios > question > null", () => { cy.visit(`/dashboard/${DASHBOARD_ID}`); cy.log("P0 regression in v0.37.1!"); - cy.get(".LoadingSpinner").should("not.exist"); + cy.findByTestId("loading-spinner").should("not.exist"); cy.findByText("13801_Q1"); cy.get(".ScalarValue").contains("0"); cy.findByText("13801_Q2"); diff --git a/frontend/test/metabase/scenarios/question/reproductions/13263-postgres-show-row-details-on-pk-click.cy.spec.js b/frontend/test/metabase/scenarios/question/reproductions/13263-postgres-show-row-details-on-pk-click.cy.spec.js index 261d1940ddc..77cf3dd1e8b 100644 --- a/frontend/test/metabase/scenarios/question/reproductions/13263-postgres-show-row-details-on-pk-click.cy.spec.js +++ b/frontend/test/metabase/scenarios/question/reproductions/13263-postgres-show-row-details-on-pk-click.cy.spec.js @@ -22,7 +22,7 @@ describe("postgres > user > query", () => { // Wait until "doing science" spinner disappears (DOM is ready for assertions) // TODO: if this proves to be reliable, extract it as a helper function for waiting on DOM to render - cy.get(".LoadingSpinner").should("not.exist"); + cy.findByTestId("loading-spinner").should("not.exist"); // Assertions cy.log("Fails in v0.36.6"); -- GitLab