Skip to content
Snippets Groups Projects
Unverified Commit d2aa71ea authored by Kyle Doherty's avatar Kyle Doherty Committed by GitHub
Browse files

Improve Toast workflow (#7755)

* initial version of withToast

* add dark card, use for undo item

* use triggerToast on AutomaticDashboardApp

* betterify

* fix flow
parent df06ba5f
No related branches found
No related tags found
No related merge requests found
......@@ -3,14 +3,15 @@ import { space } from "styled-system";
import { normal } from "metabase/lib/colors";
const Card = styled.div`
${space} background-color: white;
border: 1px solid #f5f6f7;
${space} background-color: ${props => (props.dark ? "#2e353b" : "white")};
border: 1px solid ${props => (props.dark ? "transparent" : "#f5f6f7")};
${props => props.dark && `color: white`};
border-radius: 6px;
box-shadow: 0 1px 3px ${normal.grey1};
box-shadow: 0 1px 3px ${props => (props.dark ? "#65686b" : normal.grey1)};
${props =>
props.hoverable &&
`&:hover {
box-shadow: 0 2px 3px #DCE1E4;
box-shadow: 0 2px 3px ${props.dark ? "#2e35b" : "#DCE1E4"};
}`};
`;
......
:local(.listing) {
composes: m2 from "style";
composes: fixed left bottom from "style";
z-index: 99;
}
:local(.undo) {
composes: mt2 p2 from "style";
composes: bordered rounded shadowed from "style";
composes: relative from "style";
composes: flex align-center from "style";
background-color: #2e353b;
color: white;
}
:local(.actions) {
composes: flex align-center flex-align-right from "style";
}
:local(.undoButton) {
composes: mx2 from "style";
composes: text-uppercase text-bold from "style";
color: var(--brand-color);
}
:local(.dismissButton) {
composes: cursor-pointer from "style";
color: var(--grey-1);
}
:local(.dismissButton):hover {
color: var(--grey-3);
}
/* enter and exit initial and final state */
.UndoListing-enter,
.UndoListing-leave.UndoListing-leave-active {
opacity: 0.01;
transition: opacity 300ms ease-in;
}
.UndoListing-leave,
.UndoListing-enter.UndoListing-enter-active {
opacity: 1;
}
......@@ -2,29 +2,33 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import styled from "styled-components";
import { space } from "styled-system";
import { Flex } from "rebass";
import { t } from "c-3po";
import S from "./UndoListing.css";
import { normal } from "metabase/lib/colors";
import { dismissUndo, performUndo } from "metabase/redux/undo";
import { getUndos } from "metabase/selectors/undo";
import { t } from "c-3po";
import Icon from "metabase/components/Icon";
import BodyComponent from "metabase/components/BodyComponent";
import Card from "metabase/components/Card";
import Icon from "metabase/components/Icon";
import Link from "metabase/components/Link";
import { CSSTransitionGroup } from "react-transition-group";
const mapStateToProps = (state, props) => {
return {
undos: getUndos(state, props),
};
};
const mapStateToProps = (state, props) => ({
undos: getUndos(state, props),
});
const mapDispatchToProps = {
dismissUndo,
performUndo,
};
const UndoList = styled.ul`
${space}, z-index: 99;
`;
@connect(mapStateToProps, mapDispatchToProps)
@BodyComponent
export default class UndoListing extends Component {
......@@ -37,37 +41,28 @@ export default class UndoListing extends Component {
render() {
const { undos, performUndo, dismissUndo } = this.props;
return (
<ul className={S.listing}>
<CSSTransitionGroup
transitionName="UndoListing"
transitionEnterTimeout={300}
transitionLeaveTimeout={300}
>
{undos.map(undo => (
<li key={undo._domId} className={S.undo}>
<div className={S.message}>
{typeof undo.message === "function"
? undo.message(undo)
: undo.message}
</div>
<UndoList m={2} className="fixed left bottom">
{undos.map(undo => (
<Card key={undo._domId} dark p={2}>
<Flex align="center">
{typeof undo.message === "function"
? undo.message(undo)
: undo.message}
{undo.actions && (
<div className={S.actions}>
<a
className={S.undoButton}
onClick={() => performUndo(undo.id)}
>{t`Undo`}</a>
<Icon
className={S.dismissButton}
name="close"
onClick={() => dismissUndo(undo.id)}
/>
</div>
<Link onClick={() => performUndo(undo.id)}>{t`Undo`}</Link>
)}
</li>
))}
</CSSTransitionGroup>
</ul>
<Icon
ml={1}
color={normal.grey1}
hover={{ color: normal.grey2 }}
name="close"
onClick={() => dismissUndo(undo.id)}
/>
</Flex>
</Card>
))}
</UndoList>
);
}
}
......@@ -6,6 +6,7 @@ import { connect } from "react-redux";
import { Link } from "react-router";
import title from "metabase/hoc/Title";
import withToast from "metabase/hoc/Toast";
import ActionButton from "metabase/components/ActionButton";
import Button from "metabase/components/Button";
import Icon from "metabase/components/Icon";
......@@ -18,8 +19,6 @@ import { Dashboard } from "metabase/dashboard/containers/Dashboard";
import DashboardData from "metabase/dashboard/hoc/DashboardData";
import Parameters from "metabase/parameters/components/Parameters";
import { addUndo, createUndo } from "metabase/redux/undo";
import { getMetadata } from "metabase/selectors/metadata";
import { getUserIsAdmin } from "metabase/selectors/user";
......@@ -40,8 +39,9 @@ const mapStateToProps = (state, props) => ({
dashboardId: getDashboardId(state, props),
});
@connect(mapStateToProps, { addUndo, createUndo })
@connect(mapStateToProps)
@DashboardData
@withToast
@title(({ dashboard }) => dashboard && dashboard.name)
class AutomaticDashboardApp extends React.Component {
state = {
......@@ -56,27 +56,22 @@ class AutomaticDashboardApp extends React.Component {
}
save = async () => {
const { dashboard, addUndo, createUndo } = this.props;
const { dashboard, triggerToast } = this.props;
// remove the transient id before trying to save
const newDashboard = await DashboardApi.save(dissoc(dashboard, "id"));
addUndo(
createUndo({
type: "metabase/automatic-dashboards/link-to-created-object",
message: () => (
<div className="flex align-center">
<Icon name="dashboard" size={22} className="mr2" color="#93A1AB" />
{t`Your dashboard was saved`}
<Link
className="link text-bold ml1"
to={Urls.dashboard(newDashboard.id)}
>
{t`See it`}
</Link>
</div>
),
action: null,
}),
triggerToast(
<div className="flex align-center">
<Icon name="dashboard" size={22} className="mr2" color="#93A1AB" />
{t`Your dashboard was saved`}
<Link
className="link text-bold ml1"
to={Urls.dashboard(newDashboard.id)}
>
{t`See it`}
</Link>
</div>,
);
this.setState({ savedDashboardId: newDashboard.id });
MetabaseAnalytics.trackEvent("AutoDashboard", "Save");
};
......
import React from "react";
import { connect } from "react-redux";
import { createUndo, addUndo } from "metabase/redux/undo";
const mapDispatchToProps = {
createUndo,
addUndo,
};
const withToaster = ComposedComponent => {
@connect(null, mapDispatchToProps)
class ToastedComponent extends React.Component {
_triggerToast = toastContent => {
const { addUndo, createUndo } = this.props;
addUndo(
createUndo({
type: "toast",
message: toastContent,
}),
);
};
render() {
return (
<ComposedComponent
triggerToast={this._triggerToast}
// TODO - omit createUndo, addUndo
{...this.props}
/>
);
}
}
return ToastedComponent;
};
export default withToaster;
/* @flow */
import React from "react";
import cx from "classnames";
import { Box, Flex, Subhead } from "rebass";
import { connect } from "react-redux";
import CopyToClipboard from "react-copy-to-clipboard";
import { addUndo, createUndo } from "metabase/redux/undo";
import { normal, saturated, harmony } from "metabase/lib/colors";
const SWATCH_SIZE = 150;
import withToast from "metabase/hoc/Toast";
const mapDispatchToProps = {
addUndo,
createUndo,
};
const SWATCH_SIZE = 150;
@connect(() => ({}), mapDispatchToProps)
@withToast
class ColorSwatch extends React.Component {
_onCopy(colorValue) {
const { addUndo, createUndo } = this.props;
addUndo(
createUndo({
type: "copy-color",
message: <div>Copied {colorValue} to clipboard</div>,
}),
);
}
render() {
const { color, name } = this.props;
const { color, name, triggerToast } = this.props;
return (
<CopyToClipboard text={color} onCopy={() => this._onCopy(color)}>
<CopyToClipboard
text={color}
onCopy={() => triggerToast(`${color} copied to clipboard`)}
>
<Box
w={SWATCH_SIZE}
style={{
......
......@@ -14,7 +14,7 @@ let nextUndoId = 0;
// A convenience shorthand for creating single undos
export function createUndo({ type, message, action }) {
return {
type: type,
type,
count: 1,
message,
actions: action ? [action] : null,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment