From 73b37cc0b57ddc46511c87e2602cfeb1bb43d23d Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Mon, 27 Aug 2018 13:32:37 -0700 Subject: [PATCH] mobile sequence step reorder controls --- webpack/css/steps.scss | 6 +++ .../__tests__/step_icon_group_test.tsx | 52 +++++++++++++++++++ webpack/sequences/step_icon_group.tsx | 33 ++++++++++-- webpack/sequences/step_ui/step_header.tsx | 12 ++--- 4 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 webpack/sequences/__tests__/step_icon_group_test.tsx diff --git a/webpack/css/steps.scss b/webpack/css/steps.scss index 4d8c2333c..5f7db16ba 100644 --- a/webpack/css/steps.scss +++ b/webpack/css/steps.scss @@ -108,6 +108,12 @@ } } +.step-up-down-arrows { + text-align: center; + display: inline-block; + font-size: 2rem; +} + .step-control { margin-top: 0.3rem; margin-left: 2rem; diff --git a/webpack/sequences/__tests__/step_icon_group_test.tsx b/webpack/sequences/__tests__/step_icon_group_test.tsx new file mode 100644 index 000000000..53fded2f8 --- /dev/null +++ b/webpack/sequences/__tests__/step_icon_group_test.tsx @@ -0,0 +1,52 @@ +jest.mock("../step_tiles", () => ({ + splice: jest.fn(), + remove: jest.fn(), + move: jest.fn(), +})); + +import * as React from "react"; +import { mount, shallow } from "enzyme"; +import { StepIconGroup, StepIconBarProps } from "../step_icon_group"; +import { fakeSequence } from "../../__test_support__/fake_state/resources"; +import { splice, remove, move } from "../step_tiles"; + +describe("", () => { + const fakeProps = (): StepIconBarProps => ({ + index: 0, + dispatch: jest.fn(), + step: { kind: "wait", args: { milliseconds: 100 } }, + sequence: fakeSequence(), + helpText: "helpful text", + }); + + it("renders", () => { + const wrapper = mount(); + expect(wrapper.find("i").length).toEqual(4); + }); + + it("deletes step", () => { + const wrapper = mount(); + wrapper.find("i").at(2).simulate("click"); + expect(remove).toHaveBeenCalledWith(expect.objectContaining({ index: 0 })); + }); + + it("duplicates step", () => { + const wrapper = mount(); + wrapper.find("i").at(1).simulate("click"); + expect(splice).toHaveBeenCalledWith(expect.objectContaining({ + index: 0, + step: fakeProps().step + })); + }); + + it("moves step", () => { + const wrapper = shallow(); + // tslint:disable-next-line:no-any + (wrapper.find("StepUpDownButtonPopover").props() as any).onMove(-1)(); + expect(move).toHaveBeenCalledWith(expect.objectContaining({ + from: 0, + to: 0, + step: fakeProps().step + })); + }); +}); diff --git a/webpack/sequences/step_icon_group.tsx b/webpack/sequences/step_icon_group.tsx index ef0760c38..093b8549c 100644 --- a/webpack/sequences/step_icon_group.tsx +++ b/webpack/sequences/step_icon_group.tsx @@ -1,17 +1,40 @@ import * as React from "react"; import { Help } from "../ui/help"; +import { Popover, Position } from "@blueprintjs/core"; +import { SequenceBodyItem, TaggedSequence } from "farmbot"; +import { splice, remove, move } from "./step_tiles"; -interface StepIconBarProps { - onClone(): void; - onTrash(): void; +export interface StepIconBarProps { + index: number; + dispatch: Function; + step: SequenceBodyItem; + sequence: TaggedSequence; helpText: string; } +export function StepUpDownButtonPopover( + { onMove }: { onMove: (d: number) => () => void }) { + return + +
+ + +
+
; +} + export function StepIconGroup(props: StepIconBarProps) { - const { onClone, onTrash, helpText } = props; + const { index, dispatch, step, sequence, helpText } = props; + + const onClone = () => dispatch(splice({ step, index, sequence })); + const onTrash = () => remove({ dispatch, index, sequence }); + const onMove = (delta: number) => () => { + const to = Math.max(index + delta, 0); + dispatch(move({ step, sequence, from: index, to })); + }; return - + diff --git a/webpack/sequences/step_ui/step_header.tsx b/webpack/sequences/step_ui/step_header.tsx index cf340d6bd..0c7a8bdd5 100644 --- a/webpack/sequences/step_ui/step_header.tsx +++ b/webpack/sequences/step_ui/step_header.tsx @@ -4,7 +4,6 @@ import { Row, Col } from "../../ui/index"; import { TaggedSequence, SequenceBodyItem } from "farmbot"; import { StepTitleBar } from "../step_tiles/step_title_bar"; import { StepIconGroup } from "../step_icon_group"; -import { splice, remove } from "../step_tiles/index"; export interface StepHeaderProps { children?: React.ReactNode; @@ -34,13 +33,10 @@ export function StepHeader(props: StepHeaderProps) { step={currentStep} sequence={currentSequence} /> dispatch(splice({ - step: currentStep, - index, - sequence: currentSequence - }))} - onTrash={() => - remove({ dispatch, index, sequence: currentSequence })} + index={index} + dispatch={dispatch} + step={currentStep} + sequence={currentSequence} helpText={t(helpText)} /> {props.children}