mobile sequence step reorder controls
This commit is contained in:
parent
1c05dde5fe
commit
73b37cc0b5
|
@ -108,6 +108,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.step-up-down-arrows {
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.step-control {
|
.step-control {
|
||||||
margin-top: 0.3rem;
|
margin-top: 0.3rem;
|
||||||
margin-left: 2rem;
|
margin-left: 2rem;
|
||||||
|
|
52
webpack/sequences/__tests__/step_icon_group_test.tsx
Normal file
52
webpack/sequences/__tests__/step_icon_group_test.tsx
Normal file
|
@ -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("<StepIconGroup />", () => {
|
||||||
|
const fakeProps = (): StepIconBarProps => ({
|
||||||
|
index: 0,
|
||||||
|
dispatch: jest.fn(),
|
||||||
|
step: { kind: "wait", args: { milliseconds: 100 } },
|
||||||
|
sequence: fakeSequence(),
|
||||||
|
helpText: "helpful text",
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders", () => {
|
||||||
|
const wrapper = mount(<StepIconGroup {...fakeProps()} />);
|
||||||
|
expect(wrapper.find("i").length).toEqual(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("deletes step", () => {
|
||||||
|
const wrapper = mount(<StepIconGroup {...fakeProps()} />);
|
||||||
|
wrapper.find("i").at(2).simulate("click");
|
||||||
|
expect(remove).toHaveBeenCalledWith(expect.objectContaining({ index: 0 }));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("duplicates step", () => {
|
||||||
|
const wrapper = mount(<StepIconGroup {...fakeProps()} />);
|
||||||
|
wrapper.find("i").at(1).simulate("click");
|
||||||
|
expect(splice).toHaveBeenCalledWith(expect.objectContaining({
|
||||||
|
index: 0,
|
||||||
|
step: fakeProps().step
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("moves step", () => {
|
||||||
|
const wrapper = shallow(<StepIconGroup {...fakeProps()} />);
|
||||||
|
// 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
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,17 +1,40 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Help } from "../ui/help";
|
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 {
|
export interface StepIconBarProps {
|
||||||
onClone(): void;
|
index: number;
|
||||||
onTrash(): void;
|
dispatch: Function;
|
||||||
|
step: SequenceBodyItem;
|
||||||
|
sequence: TaggedSequence;
|
||||||
helpText: string;
|
helpText: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function StepUpDownButtonPopover(
|
||||||
|
{ onMove }: { onMove: (d: number) => () => void }) {
|
||||||
|
return <Popover position={Position.TOP} usePortal={false}>
|
||||||
|
<i className="fa fa-arrows-v step-control" />
|
||||||
|
<div className={"step-up-down-arrows"}>
|
||||||
|
<i className="fa fa-arrow-circle-up" onClick={onMove(-1)} />
|
||||||
|
<i className="fa fa-arrow-circle-down" onClick={onMove(2)} />
|
||||||
|
</div>
|
||||||
|
</Popover>;
|
||||||
|
}
|
||||||
|
|
||||||
export function StepIconGroup(props: StepIconBarProps) {
|
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 <span>
|
return <span>
|
||||||
<i className="fa fa-arrows-v step-control" />
|
<StepUpDownButtonPopover onMove={onMove} />
|
||||||
<i className="fa fa-clone step-control" onClick={onClone} />
|
<i className="fa fa-clone step-control" onClick={onClone} />
|
||||||
<i className="fa fa-trash step-control" onClick={onTrash} />
|
<i className="fa fa-trash step-control" onClick={onTrash} />
|
||||||
<Help text={helpText} />
|
<Help text={helpText} />
|
||||||
|
|
|
@ -4,7 +4,6 @@ import { Row, Col } from "../../ui/index";
|
||||||
import { TaggedSequence, SequenceBodyItem } from "farmbot";
|
import { TaggedSequence, SequenceBodyItem } from "farmbot";
|
||||||
import { StepTitleBar } from "../step_tiles/step_title_bar";
|
import { StepTitleBar } from "../step_tiles/step_title_bar";
|
||||||
import { StepIconGroup } from "../step_icon_group";
|
import { StepIconGroup } from "../step_icon_group";
|
||||||
import { splice, remove } from "../step_tiles/index";
|
|
||||||
|
|
||||||
export interface StepHeaderProps {
|
export interface StepHeaderProps {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
@ -34,13 +33,10 @@ export function StepHeader(props: StepHeaderProps) {
|
||||||
step={currentStep}
|
step={currentStep}
|
||||||
sequence={currentSequence} />
|
sequence={currentSequence} />
|
||||||
<StepIconGroup
|
<StepIconGroup
|
||||||
onClone={() => dispatch(splice({
|
index={index}
|
||||||
step: currentStep,
|
dispatch={dispatch}
|
||||||
index,
|
step={currentStep}
|
||||||
sequence: currentSequence
|
sequence={currentSequence}
|
||||||
}))}
|
|
||||||
onTrash={() =>
|
|
||||||
remove({ dispatch, index, sequence: currentSequence })}
|
|
||||||
helpText={t(helpText)} />
|
helpText={t(helpText)} />
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue