sequence css and refactoring
parent
034e6ad033
commit
3d20563b67
|
@ -261,6 +261,9 @@ export namespace ToolTips {
|
|||
For example, you can mark a plant as "planted" during a seeding
|
||||
sequence or delete a weed after removing it.`);
|
||||
|
||||
export const UNKNOWN_STEP =
|
||||
trim(`Unable to properly display this step.`);
|
||||
|
||||
// Regimens
|
||||
export const BULK_SCHEDULER =
|
||||
trim(`Add sequences to your regimen by selecting a sequence from the
|
||||
|
|
|
@ -969,3 +969,9 @@ ul {
|
|||
width: 75%;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.parent-variable-form {
|
||||
.row {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,6 +96,12 @@
|
|||
&.take-photo-step {
|
||||
background: $brown;
|
||||
}
|
||||
&.resource-update-step {
|
||||
background: $brown;
|
||||
}
|
||||
&.unknown-step {
|
||||
background: $gray;
|
||||
}
|
||||
.help {
|
||||
float: right;
|
||||
}
|
||||
|
@ -174,6 +180,12 @@
|
|||
&.take-photo-step a {
|
||||
color: $dark_brown;
|
||||
}
|
||||
&.resource-update-step {
|
||||
background: $light_brown;
|
||||
}
|
||||
&.unknown-step {
|
||||
background: $light_gray;
|
||||
}
|
||||
input,
|
||||
select {
|
||||
width: 100%;
|
||||
|
|
|
@ -18,9 +18,15 @@ jest.mock("../../devices/actions", () => ({
|
|||
execSequence: jest.fn()
|
||||
}));
|
||||
|
||||
let mockParent = false;
|
||||
jest.mock("../locals_list", () => ({
|
||||
extractParent: () => mockParent,
|
||||
LocalsList: () => <div />,
|
||||
}));
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
SequenceEditorMiddleActive, onDrop
|
||||
SequenceEditorMiddleActive, onDrop, SequenceNameAndColor
|
||||
} from "../sequence_editor_middle_active";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { ActiveMiddleProps } from "../interfaces";
|
||||
|
@ -41,23 +47,21 @@ import { clickButton } from "../../__test_support__/helpers";
|
|||
describe("<SequenceEditorMiddleActive/>", () => {
|
||||
const sequence = fakeSequence();
|
||||
sequence.specialStatus = SpecialStatus.DIRTY;
|
||||
function fakeProps(): ActiveMiddleProps {
|
||||
return {
|
||||
dispatch: jest.fn(),
|
||||
sequence: sequence,
|
||||
resources: buildResourceIndex(FAKE_RESOURCES).index,
|
||||
syncStatus: "synced",
|
||||
hardwareFlags: fakeHardwareFlags(),
|
||||
farmwareInfo: {
|
||||
farmwareNames: [],
|
||||
firstPartyFarmwareNames: [],
|
||||
showFirstPartyFarmware: false,
|
||||
farmwareConfigs: {},
|
||||
},
|
||||
shouldDisplay: jest.fn(),
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
const fakeProps = (): ActiveMiddleProps => ({
|
||||
dispatch: jest.fn(),
|
||||
sequence,
|
||||
resources: buildResourceIndex(FAKE_RESOURCES).index,
|
||||
syncStatus: "synced",
|
||||
hardwareFlags: fakeHardwareFlags(),
|
||||
farmwareInfo: {
|
||||
farmwareNames: [],
|
||||
firstPartyFarmwareNames: [],
|
||||
showFirstPartyFarmware: false,
|
||||
farmwareConfigs: {},
|
||||
},
|
||||
shouldDisplay: jest.fn(),
|
||||
confirmStepDeletion: false,
|
||||
});
|
||||
|
||||
it("saves", () => {
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...fakeProps()} />);
|
||||
|
@ -93,25 +97,31 @@ describe("<SequenceEditorMiddleActive/>", () => {
|
|||
expect(wrapper.find(".drag-drop-area").text()).toEqual("DRAG COMMAND HERE");
|
||||
});
|
||||
|
||||
it("edits name", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = shallow(<SequenceEditorMiddleActive {...p} />);
|
||||
wrapper.find("BlurableInput").simulate("commit", {
|
||||
currentTarget: { value: "new name" }
|
||||
it("has correct height", () => {
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...fakeProps()} />);
|
||||
expect(wrapper.find(".sequence").props().style).toEqual({
|
||||
height: "calc(100vh - 25rem)"
|
||||
});
|
||||
expect(edit).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ uuid: p.sequence.uuid }),
|
||||
{ name: "new name" });
|
||||
});
|
||||
|
||||
it("edits color", () => {
|
||||
it("has correct height with variables", () => {
|
||||
mockParent = false;
|
||||
const p = fakeProps();
|
||||
const wrapper = shallow(<SequenceEditorMiddleActive {...p} />);
|
||||
wrapper.find("ColorPicker").simulate("change", "red");
|
||||
expect(editCurrentSequence).toHaveBeenCalledWith(
|
||||
expect.any(Function),
|
||||
expect.objectContaining({ uuid: p.sequence.uuid }),
|
||||
{ color: "red" });
|
||||
p.shouldDisplay = () => true;
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...p} />);
|
||||
expect(wrapper.find(".sequence").props().style).toEqual({
|
||||
height: "calc(100vh - 25rem)"
|
||||
});
|
||||
});
|
||||
|
||||
it("has correct height with variable form", () => {
|
||||
mockParent = true;
|
||||
const p = fakeProps();
|
||||
p.shouldDisplay = () => true;
|
||||
const wrapper = mount(<SequenceEditorMiddleActive {...p} />);
|
||||
expect(wrapper.find(".sequence").props().style).toEqual({
|
||||
height: "calc(100vh - 38rem)"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -147,3 +157,31 @@ describe("onDrop()", () => {
|
|||
expect(dispatch).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("<SequenceNameAndColor />", () => {
|
||||
const fakeProps = () => ({
|
||||
dispatch: jest.fn(),
|
||||
sequence: fakeSequence(),
|
||||
});
|
||||
|
||||
it("edits name", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = shallow(<SequenceNameAndColor {...p} />);
|
||||
wrapper.find("BlurableInput").simulate("commit", {
|
||||
currentTarget: { value: "new name" }
|
||||
});
|
||||
expect(edit).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ uuid: p.sequence.uuid }),
|
||||
{ name: "new name" });
|
||||
});
|
||||
|
||||
it("edits color", () => {
|
||||
const p = fakeProps();
|
||||
const wrapper = shallow(<SequenceNameAndColor {...p} />);
|
||||
wrapper.find("ColorPicker").simulate("change", "red");
|
||||
expect(editCurrentSequence).toHaveBeenCalledWith(
|
||||
expect.any(Function),
|
||||
expect.objectContaining({ uuid: p.sequence.uuid }),
|
||||
{ color: "red" });
|
||||
});
|
||||
});
|
||||
|
|
|
@ -48,6 +48,14 @@ export interface ActiveMiddleProps extends SequenceEditorMiddleProps {
|
|||
sequence: TaggedSequence;
|
||||
}
|
||||
|
||||
export interface SequenceHeaderProps {
|
||||
dispatch: Function;
|
||||
sequence: TaggedSequence;
|
||||
syncStatus: SyncStatus;
|
||||
resources: ResourceIndex;
|
||||
shouldDisplay: ShouldDisplay;
|
||||
}
|
||||
|
||||
export type ChannelName = ALLOWED_CHANNEL_NAMES;
|
||||
|
||||
export const INT_NUMERIC_FIELDS = ["milliseconds", "pin_mode", "pin_number",
|
||||
|
|
|
@ -178,15 +178,17 @@ export const ParentVariableForm =
|
|||
const isDisabled = (parent.kind == "parameter_declaration") ||
|
||||
data_value.kind !== "coordinate";
|
||||
|
||||
return <div>
|
||||
<br /> {/** Lol */}
|
||||
<h5>Import Coordinates From</h5>
|
||||
<FBSelect
|
||||
allowEmpty={true}
|
||||
list={generateList(resources, [PARENT])}
|
||||
selectedItem={ddiLabel}
|
||||
onChange={(ddi) => onChange(handleSelect(resources, ddi))} />
|
||||
<br /> {/** Lol */}
|
||||
return <div className="parent-variable-form">
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<h5>{t("Import Coordinates From")}</h5>
|
||||
<FBSelect
|
||||
allowEmpty={true}
|
||||
list={generateList(resources, [PARENT])}
|
||||
selectedItem={ddiLabel}
|
||||
onChange={(ddi) => onChange(handleSelect(resources, ddi))} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col xs={4}>
|
||||
<InputBox
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from "react";
|
||||
import { ActiveMiddleProps } from "./interfaces";
|
||||
import { ActiveMiddleProps, SequenceHeaderProps } from "./interfaces";
|
||||
import { execSequence } from "../devices/actions";
|
||||
import { editCurrentSequence } from "./actions";
|
||||
import { splice, move } from "./step_tiles/index";
|
||||
|
@ -8,12 +8,12 @@ import { BlurableInput, Row, Col, SaveBtn, ColorPicker } from "../ui/index";
|
|||
import { DropArea } from "../draggable/drop_area";
|
||||
import { stepGet } from "../draggable/actions";
|
||||
import { copySequence } from "./actions";
|
||||
import { TaggedSequence } from "farmbot";
|
||||
import { TaggedSequence, SyncStatus } from "farmbot";
|
||||
import { save, edit, destroy } from "../api/crud";
|
||||
import { TestButton } from "./test_button";
|
||||
import { warning } from "farmbot-toastr";
|
||||
import { AllSteps } from "./all_steps";
|
||||
import { LocalsList } from "./locals_list";
|
||||
import { LocalsList, extractParent } from "./locals_list";
|
||||
import { Feature } from "../devices/interfaces";
|
||||
|
||||
export const onDrop =
|
||||
|
@ -37,62 +37,83 @@ export const onDrop =
|
|||
}
|
||||
};
|
||||
|
||||
const copy = function (dispatch: Function, sequence: TaggedSequence) {
|
||||
return () => dispatch(copySequence(sequence));
|
||||
const SequenceBtnGroup = ({ dispatch, sequence, syncStatus }: {
|
||||
dispatch: Function, sequence: TaggedSequence, syncStatus: SyncStatus
|
||||
}) =>
|
||||
<div className="button-group">
|
||||
<SaveBtn status={sequence.specialStatus}
|
||||
onClick={() => dispatch(save(sequence.uuid))} />
|
||||
<TestButton
|
||||
syncStatus={syncStatus}
|
||||
sequence={sequence}
|
||||
onFail={warning}
|
||||
onClick={() => execSequence(sequence.body)} />
|
||||
<button
|
||||
className="fb-button red"
|
||||
onClick={() => dispatch(destroy(sequence.uuid))}>
|
||||
{t("Delete")}
|
||||
</button>
|
||||
<button
|
||||
className="fb-button yellow"
|
||||
onClick={() => dispatch(copySequence(sequence))}>
|
||||
{t("Copy")}
|
||||
</button>
|
||||
</div>;
|
||||
|
||||
export const SequenceNameAndColor = ({ dispatch, sequence }: {
|
||||
dispatch: Function, sequence: TaggedSequence
|
||||
}) =>
|
||||
<Row>
|
||||
<Col xs={11}>
|
||||
<BlurableInput value={sequence.body.name}
|
||||
placeholder={t("Sequence Name")}
|
||||
onCommit={e =>
|
||||
dispatch(edit(sequence, { name: e.currentTarget.value }))} />
|
||||
</Col>
|
||||
<Col xs={1} className="color-picker-col">
|
||||
<ColorPicker
|
||||
current={sequence.body.color}
|
||||
onChange={color =>
|
||||
editCurrentSequence(dispatch, sequence, { color })} />
|
||||
</Col>
|
||||
</Row>;
|
||||
|
||||
const SequenceHeader = (props: SequenceHeaderProps) => {
|
||||
const { sequence, dispatch } = props;
|
||||
const sequenceAndDispatch = { sequence, dispatch };
|
||||
return <div className="sequence-editor-tools">
|
||||
<SequenceBtnGroup {...sequenceAndDispatch} syncStatus={props.syncStatus} />
|
||||
<SequenceNameAndColor {...sequenceAndDispatch} />
|
||||
{props.shouldDisplay(Feature.variables) &&
|
||||
<LocalsList {...sequenceAndDispatch} resources={props.resources} />}
|
||||
</div>;
|
||||
};
|
||||
|
||||
export class SequenceEditorMiddleActive extends
|
||||
React.Component<ActiveMiddleProps, {}> {
|
||||
get stepSectionHeight() {
|
||||
const variable = this.props.shouldDisplay(Feature.variables)
|
||||
? !!extractParent(this.props.sequence.body.args.locals.body)
|
||||
: false;
|
||||
return `calc(100vh - ${variable ? "38" : "25"}rem)`;
|
||||
}
|
||||
render() {
|
||||
const { dispatch, sequence } = this.props;
|
||||
|
||||
return <div className="sequence-editor-content">
|
||||
<div className="sequence-editor-tools">
|
||||
<div className="button-group">
|
||||
<SaveBtn status={sequence.specialStatus}
|
||||
onClick={() => { dispatch(save(sequence.uuid)); }} />
|
||||
<TestButton
|
||||
syncStatus={this.props.syncStatus}
|
||||
sequence={sequence}
|
||||
onFail={warning}
|
||||
onClick={() => execSequence(sequence.body)} />
|
||||
<button
|
||||
className="fb-button red"
|
||||
onClick={() => dispatch(destroy(sequence.uuid))}>
|
||||
{t("Delete")}
|
||||
</button>
|
||||
<button
|
||||
className="fb-button yellow"
|
||||
onClick={copy(dispatch, sequence)}>
|
||||
{t("Copy")}
|
||||
</button>
|
||||
</div>
|
||||
<Row>
|
||||
<Col xs={11}>
|
||||
<BlurableInput value={sequence.body.name}
|
||||
placeholder={t("Sequence Name")}
|
||||
onCommit={(e) => {
|
||||
dispatch(edit(sequence, { name: e.currentTarget.value }));
|
||||
}} />
|
||||
</Col>
|
||||
<Col xs={1} className="color-picker-col">
|
||||
<ColorPicker
|
||||
current={sequence.body.color}
|
||||
onChange={color => editCurrentSequence(dispatch, sequence, { color })} />
|
||||
</Col>
|
||||
</Row>
|
||||
{this.props.shouldDisplay(Feature.variables) && <LocalsList
|
||||
sequence={this.props.sequence}
|
||||
resources={this.props.resources}
|
||||
dispatch={this.props.dispatch} />}
|
||||
<hr />
|
||||
</div>
|
||||
<div className="sequence" id="sequenceDiv">
|
||||
<SequenceHeader
|
||||
dispatch={this.props.dispatch}
|
||||
sequence={sequence}
|
||||
resources={this.props.resources}
|
||||
syncStatus={this.props.syncStatus}
|
||||
shouldDisplay={this.props.shouldDisplay} />
|
||||
<hr />
|
||||
<div className="sequence" id="sequenceDiv"
|
||||
style={{ height: this.stepSectionHeight }}>
|
||||
<AllSteps onDrop={onDrop(dispatch, sequence)} {...this.props} />
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<DropArea isLocked={true}
|
||||
callback={(key) => onDrop(dispatch, sequence)(Infinity, key)}>
|
||||
callback={key => onDrop(dispatch, sequence)(Infinity, key)}>
|
||||
{t("DRAG COMMAND HERE")}
|
||||
</DropArea>
|
||||
</Col>
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { fakeSequence } from "../../../__test_support__/fake_state/resources";
|
||||
import { StepParams } from "../../interfaces";
|
||||
import { emptyState } from "../../../resources/reducer";
|
||||
import { TileUnknown } from "../tile_unknown";
|
||||
import { SequenceBodyItem } from "farmbot";
|
||||
import { ToolTips } from "../../../constants";
|
||||
|
||||
describe("<TileUnknown/>", () => {
|
||||
const currentStep = {
|
||||
kind: "unknown_step",
|
||||
args: { "weird_arg": "hello" }
|
||||
};
|
||||
|
||||
const fakeProps = (): StepParams => ({
|
||||
currentSequence: fakeSequence(),
|
||||
currentStep: currentStep as SequenceBodyItem,
|
||||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
resources: emptyState().index,
|
||||
confirmStepDeletion: false,
|
||||
});
|
||||
|
||||
it("renders step", () => {
|
||||
const wrapper = mount(<TileUnknown {...fakeProps()} />);
|
||||
[ToolTips.UNKNOWN_STEP, "unknown_step", "weird_arg", "hello"].map(string =>
|
||||
expect(wrapper.text().toLowerCase()).toContain(string.toLowerCase()));
|
||||
});
|
||||
});
|
|
@ -21,6 +21,7 @@ import { overwrite } from "../../api/crud";
|
|||
import { TileFindHome } from "./tile_find_home";
|
||||
import { t } from "i18next";
|
||||
import { MarkAs } from "./mark_as";
|
||||
import { TileUnknown } from "./tile_unknown";
|
||||
|
||||
interface MoveParams {
|
||||
step: Step;
|
||||
|
@ -137,7 +138,7 @@ export function renderCeleryNode(props: StepParams) {
|
|||
case "wait": return <TileWait {...props} />;
|
||||
case "write_pin": return <TileWritePin {...props} />;
|
||||
case "resource_update": return <MarkAs {...props} />;
|
||||
default: return <div><hr /> ? Unknown step ? <hr /></div>;
|
||||
default: return <TileUnknown {...props} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ const NONE: DropDownItem = { value: 0, label: "" };
|
|||
|
||||
export class MarkAs extends React.Component<StepParams, MarkAsState> {
|
||||
state: MarkAsState = { nextResource: undefined };
|
||||
className = "wait-step";
|
||||
className = "resource-update-step";
|
||||
|
||||
commitSelection = (nextAction: DropDownItem) => {
|
||||
this.props.dispatch(commitStepChanges({
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
import * as React from "react";
|
||||
import { StepParams } from "../interfaces";
|
||||
import { ToolTips } from "../../constants";
|
||||
import { StepWrapper, StepHeader, StepContent } from "../step_ui";
|
||||
import { Col, Row } from "../../ui/index";
|
||||
import { t } from "i18next";
|
||||
|
||||
export function TileUnknown(props: StepParams) {
|
||||
const { dispatch, currentStep, index, currentSequence } = props;
|
||||
const className = "unknown-step";
|
||||
return <StepWrapper>
|
||||
<StepHeader
|
||||
className={className}
|
||||
helpText={ToolTips.UNKNOWN_STEP}
|
||||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<p>{t(ToolTips.UNKNOWN_STEP)}</p>
|
||||
<code>{JSON.stringify(currentStep)}</code>
|
||||
</Col>
|
||||
</Row>
|
||||
</StepContent>
|
||||
</StepWrapper>;
|
||||
}
|
Loading…
Reference in New Issue