reorganization

pull/1094/head
gabrielburnworth 2019-01-13 16:16:22 -08:00
parent 622eaa4696
commit 5b19a55f56
30 changed files with 302 additions and 301 deletions

View File

@ -30,7 +30,6 @@ import "../regimens/editor/interfaces";
import "../regimens/interfaces";
import "../resources/interfaces";
import "../sequences/interfaces";
import "../sequences/step_tiles/tile_move_absolute/interfaces";
import "../tools/interfaces";
describe("interfaces", () => {

View File

@ -72,3 +72,21 @@ export interface WebcamFeed {
updated_at?: string;
created_at?: string;
}
export interface Sensor {
id?: number;
pin: number | undefined;
label: string;
mode: number;
}
export interface SensorReading {
id?: number | undefined;
x: number | undefined;
y: number | undefined;
z: number | undefined;
value: number;
mode: number;
pin: number;
created_at: string;
}

View File

@ -28,7 +28,7 @@ import {
import { error, warning } from "farmbot-toastr";
import {
fakeResourceIndex
} from "../../../sequences/step_tiles/tile_move_absolute/test_helpers";
} from "../../../sequences/locals_list/test_helpers";
import {
PinBindingType, PinBindingSpecialAction
} from "farmbot/dist/resources/api_resources";

View File

@ -1,7 +1,7 @@
import * as React from "react";
import { t } from "i18next";
import { connect } from "react-redux";
import { Everything, Color } from "../../interfaces";
import { Everything, ResourceColor } from "../../interfaces";
import { initSave } from "../../api/crud";
import {
Row, Col, BlurableInput, ColorPicker
@ -91,7 +91,7 @@ export class CreatePoints
};
}
changeColor = (color: Color) => {
changeColor = (color: ResourceColor) => {
this.setState({ color });
if (this.props.currentPoint) {
const { cx, cy, r } = this.props.currentPoint;
@ -149,7 +149,7 @@ export class CreatePoints
<Col xs={3}>
<label>{t("color")}</label>
<ColorPicker
current={color as Color || "green"}
current={color as ResourceColor || "green"}
onChange={this.changeColor} />
</Col>
</Row>;

View File

@ -33,3 +33,9 @@ export interface FarmwareConfigMenuProps {
}
export type Farmwares = Dictionary<FarmwareManifest | undefined>;
export interface FarmwareEnv {
id?: number;
key: string;
value: string | number | boolean;
}

View File

@ -2,38 +2,13 @@ import { AuthState } from "./auth/interfaces";
import { ConfigState } from "./config/interfaces";
import { BotState } from "./devices/interfaces";
import { Color as FarmBotJsColor } from "farmbot";
import { Point } from "farmbot/dist/resources/api_resources";
import { DraggableState } from "./draggable/interfaces";
import { PeripheralState } from "./controls/peripherals/interfaces";
import { RestResources } from "./resources/interfaces";
/** Regimens and sequences may have a "color" which determines how it looks
in the UI. Only certain colors are valid. */
export type Color = FarmBotJsColor;
export interface Sensor {
id?: number;
pin: number | undefined;
label: string;
mode: number;
}
export interface SensorReading {
id?: number | undefined;
x: number | undefined;
y: number | undefined;
z: number | undefined;
value: number;
mode: number;
pin: number;
created_at: string;
}
export interface FarmwareEnv {
id?: number;
key: string;
value: string | number | boolean;
}
export type ResourceColor = FarmBotJsColor;
export interface Everything {
config: ConfigState;
@ -51,5 +26,3 @@ export interface Everything {
*/
// tslint:disable-next-line:no-any
export type UnsafeError = any;
export type PointerTypeName = Point["pointer_type"];

View File

@ -1,4 +1,4 @@
import { Color } from "../interfaces";
import { ResourceColor } from "../interfaces";
import { Week } from "./bulk_scheduler/interfaces";
import { AuthState } from "../auth/interfaces";
import { BotState, ShouldDisplay } from "../devices/interfaces";
@ -50,7 +50,7 @@ export interface Regimen {
id?: number;
/** Friendly identifier for humans to easily identify regimens. */
name: string;
color: Color;
color: ResourceColor;
regimen_items: RegimenItem[];
}

View File

@ -11,10 +11,10 @@ import {
import { buildResourceIndex } from "../../__test_support__/resource_index_builder";
import {
sanitizeNodes
} from "../../sequences/step_tiles/tile_move_absolute/variables_support";
} from "../../sequences/locals_list/variables_support";
import {
formatPoint
} from "../../sequences/step_tiles/tile_move_absolute/generate_list";
} from "../../sequences/locals_list/location_form_list";
describe("determineDropdown", () => {
it("Returns a label for `parameter_declarations`", () => {

View File

@ -13,7 +13,7 @@ import { TaggedResource, TaggedSequence } from "farmbot";
import { ResourceIndex } from "./interfaces";
import {
sanitizeNodes
} from "../sequences/step_tiles/tile_move_absolute/variables_support";
} from "../sequences/locals_list/variables_support";
import {
selectAllFarmEvents,
findByKindAndId,

View File

@ -10,7 +10,7 @@ import { findSlotByToolId, findToolById } from "./selectors_by_id";
import { capitalize } from "lodash";
import {
formatPoint, safeEveryPointType, everyPointDDI
} from "../sequences/step_tiles/tile_move_absolute/generate_list";
} from "../sequences/locals_list/location_form_list";
export interface SequenceMeta {
celeryNode: ScopeDeclarationBodyItem;

View File

@ -2,7 +2,7 @@ import { get, set } from "lodash";
import { SequenceBodyItem, uuid } from "farmbot/dist";
import {
Traversable
} from "../sequences/step_tiles/tile_move_absolute/variables_support";
} from "../sequences/locals_list/variables_support";
/** HISTORICAL NOTES:
* This file is the result of some very subtle bugs relating to dynamic

View File

@ -6,7 +6,7 @@ import { TaggedSequence, SpecialStatus } from "farmbot";
import { TileMoveRelative } from "../step_tiles/tile_move_relative";
import { TileReadPin } from "../step_tiles/tile_read_pin";
import { TileWritePin } from "../step_tiles/tile_write_pin";
import { sanitizeNodes } from "../step_tiles/tile_move_absolute/variables_support";
import { sanitizeNodes } from "../locals_list/variables_support";
describe("<AllSteps/>", () => {
const TEST_CASE: TaggedSequence = {

View File

@ -1,4 +1,4 @@
import { Color } from "../interfaces";
import { ResourceColor } from "../interfaces";
import {
Sequence as CeleryScriptSequence,
SequenceBodyItem,
@ -70,7 +70,7 @@ export const NUMERIC_FIELDS = INT_NUMERIC_FIELDS.concat(FLOAT_NUMERIC_FIELDS);
export interface Sequence extends CeleryScriptSequence {
id?: number;
color: Color;
color: ResourceColor;
name: string;
}

View File

@ -1,9 +1,8 @@
import {
localListCallback, manuallyEditAxis, AxisEditProps
} from "../locals_list";
import { localListCallback } from "../locals_list";
import { fakeSequence } from "../../../__test_support__/fake_state/resources";
import { inputEvent } from "../../../__test_support__/fake_input_event";
import { VariableDeclaration, ScopeDeclarationBodyItem } from "farmbot";
import { AxisEditProps, manuallyEditAxis } from "../location_form";
describe("localListCallback", () => {
it("handles a new local declaration", () => {

View File

@ -1,87 +1,16 @@
import * as React from "react";
import { LocationForm, LocalsList } from "../locals_list";
import { LocalsList } from "../locals_list";
import { VariableDeclaration, Coordinate } from "farmbot";
import {
fakeSequence
} from "../../../__test_support__/fake_state/resources";
import { shallow, mount } from "enzyme";
import { shallow } from "enzyme";
import {
buildResourceIndex
} from "../../../__test_support__/resource_index_builder";
import { FBSelect, BlurableInput } from "../../../ui/index";
import {
LocationFormProps, LocalsListProps, PARENT, AllowedDeclaration
} from "../locals_list_support";
import { difference } from "lodash";
import { LocalsListProps, AllowedDeclaration } from "../locals_list_support";
import { VariableNameSet } from "../../../resources/interfaces";
import { locationFormList } from "../../step_tiles/tile_move_absolute/generate_list";
import { convertDDItoDeclaration } from "../handle_select";
describe("<LocationForm/>", () => {
const fakeProps = (): LocationFormProps => ({
variable: {
celeryNode: {
kind: "parameter_declaration",
args: { label: "label", data_type: "coordinate" }
},
dropdown: { label: "label", value: 0 },
vector: { x: 0, y: 0, z: 0 }
},
sequenceUuid: fakeSequence().uuid,
resources: buildResourceIndex().index,
onChange: jest.fn(),
shouldDisplay: jest.fn(),
allowedDeclarations: AllowedDeclaration.parameter,
});
it("renders correct UI components", () => {
const p = fakeProps();
const el = shallow(<LocationForm {...p} />);
const selects = el.find(FBSelect);
const inputs = el.find(BlurableInput);
expect(selects.length).toBe(1);
const select = selects.first().props();
expect(select.allowEmpty).toBe(true);
const choices = locationFormList(p.resources, [PARENT], true);
const actualLabels = select.list.map(x => x.label).sort();
const expectedLabels = choices.map(x => x.label).sort();
const diff = difference(actualLabels, expectedLabels);
expect(diff).toEqual([]);
const choice = choices[1];
select.onChange(choice);
expect(p.onChange)
.toHaveBeenCalledWith(convertDDItoDeclaration({ label: "label" })(choice));
expect(inputs.length).toBe(3);
});
it("uses local declaration data", () => {
const p = fakeProps();
p.declarations = [{
kind: "variable_declaration",
args: {
label: "label", data_value: {
kind: "identifier", args: { label: "new_var" }
}
}
}];
const wrapper = mount(<LocationForm {...p} />);
expect(wrapper.text().toLowerCase()).toContain("new_var");
});
it("shows parent in dropdown", () => {
const p = fakeProps();
p.shouldDisplay = () => true;
const wrapper = shallow(<LocationForm {...p} />);
expect(wrapper.find(FBSelect).first().props().list).toContain(PARENT);
});
it("doesn't show parent in dropdown", () => {
const p = fakeProps();
const wrapper = shallow(<LocationForm {...p} />);
expect(wrapper.find(FBSelect).first().props().list).not.toContain(PARENT);
});
});
import { LocationForm } from "../location_form";
describe("<LocalsList/>", () => {
const coordinate: Coordinate = {

View File

@ -1,4 +1,4 @@
import { locationFormList, dropDownName } from "../generate_list";
import { locationFormList, dropDownName } from "../location_form_list";
import { fakeResourceIndex } from "../test_helpers";
describe("locationFormList()", () => {

View File

@ -0,0 +1,82 @@
import * as React from "react";
import { LocationForm } from "../location_form";
import {
fakeSequence
} from "../../../__test_support__/fake_state/resources";
import { shallow, mount } from "enzyme";
import {
buildResourceIndex
} from "../../../__test_support__/resource_index_builder";
import { FBSelect, BlurableInput } from "../../../ui/index";
import {
LocationFormProps, PARENT, AllowedDeclaration
} from "../locals_list_support";
import { difference } from "lodash";
import { locationFormList } from "../location_form_list";
import { convertDDItoDeclaration } from "../handle_select";
describe("<LocationForm/>", () => {
const fakeProps = (): LocationFormProps => ({
variable: {
celeryNode: {
kind: "parameter_declaration",
args: { label: "label", data_type: "coordinate" }
},
dropdown: { label: "label", value: 0 },
vector: { x: 0, y: 0, z: 0 }
},
sequenceUuid: fakeSequence().uuid,
resources: buildResourceIndex().index,
onChange: jest.fn(),
shouldDisplay: jest.fn(),
allowedDeclarations: AllowedDeclaration.parameter,
});
it("renders correct UI components", () => {
const p = fakeProps();
const el = shallow(<LocationForm {...p} />);
const selects = el.find(FBSelect);
const inputs = el.find(BlurableInput);
expect(selects.length).toBe(1);
const select = selects.first().props();
expect(select.allowEmpty).toBe(true);
const choices = locationFormList(p.resources, [PARENT], true);
const actualLabels = select.list.map(x => x.label).sort();
const expectedLabels = choices.map(x => x.label).sort();
const diff = difference(actualLabels, expectedLabels);
expect(diff).toEqual([]);
const choice = choices[1];
select.onChange(choice);
expect(p.onChange)
.toHaveBeenCalledWith(convertDDItoDeclaration({ label: "label" })(choice));
expect(inputs.length).toBe(3);
});
it("uses local declaration data", () => {
const p = fakeProps();
p.declarations = [{
kind: "variable_declaration",
args: {
label: "label", data_value: {
kind: "identifier", args: { label: "new_var" }
}
}
}];
const wrapper = mount(<LocationForm {...p} />);
expect(wrapper.text().toLowerCase()).toContain("new_var");
});
it("shows parent in dropdown", () => {
const p = fakeProps();
p.shouldDisplay = () => true;
const wrapper = shallow(<LocationForm {...p} />);
expect(wrapper.find(FBSelect).first().props().list).toContain(PARENT);
});
it("doesn't show parent in dropdown", () => {
const p = fakeProps();
const wrapper = shallow(<LocationForm {...p} />);
expect(wrapper.find(FBSelect).first().props().list).not.toContain(PARENT);
});
});

View File

@ -1,4 +1,4 @@
import { fakeSequence } from "../../../../__test_support__/fake_state/resources";
import { fakeSequence } from "../../../__test_support__/fake_state/resources";
import { MoveAbsolute } from "farmbot";
import { sanitizeNodes } from "../variables_support";
import { get } from "lodash";

View File

@ -1,128 +1,16 @@
import * as React from "react";
import { Row, Col, FBSelect, BlurableInput } from "../../ui";
import { t } from "i18next";
import { locationFormList } from "../step_tiles/tile_move_absolute/generate_list";
import { addOrEditDeclaration } from "../locals_list/handle_select";
import {
convertDDItoDeclaration, addOrEditDeclaration
} from "../locals_list/handle_select";
import {
LocationFormProps, LocalsListProps, PARENT, AllowedDeclaration,
LocalsListProps, AllowedDeclaration
} from "../locals_list/locals_list_support";
import { defensiveClone, betterCompact } from "../../util/util";
import {
Xyz,
TaggedSequence,
ScopeDeclarationBodyItem,
ParameterDeclaration,
} from "farmbot";
import { overwrite } from "../../api/crud";
import {
determineVector, determineDropdown, determineEditable, SequenceMeta
} from "../../resources/sequence_meta";
import { ResourceIndex, UUID } from "../../resources/interfaces";
import { Feature } from "../../devices/interfaces";
/** For LocationForm coordinate input boxes. */
export interface AxisEditProps {
axis: Xyz;
onChange: (sd: ScopeDeclarationBodyItem) => void;
declaration: ScopeDeclarationBodyItem;
}
/** Update a VariableDeclaration coordinate. */
export const manuallyEditAxis = (props: AxisEditProps) =>
(e: React.SyntheticEvent<HTMLInputElement>) => {
const { axis, onChange, declaration } = props;
const num = parseFloat(e.currentTarget.value);
if (declaration.kind === "variable_declaration" &&
declaration.args.data_value.kind === "coordinate") {
declaration.args.data_value.args[axis] = num;
!isNaN(num) && onChange(declaration);
}
};
/**
* If a declaration with a matching label exists in local `declarations`
* (step body, etc.), use it instead of the one in scope declarations.
*/
const maybeUseStepData = ({ resources, declarations, variable, uuid }: {
resources: ResourceIndex,
declarations: ScopeDeclarationBodyItem[] | undefined,
variable: SequenceMeta,
uuid: UUID,
}): SequenceMeta => {
if (declarations) {
const executeStepData = declarations
.filter(v => v.args.label === variable.celeryNode.args.label)[0];
if (executeStepData) {
return {
celeryNode: executeStepData,
vector: determineVector(executeStepData, resources, uuid),
dropdown: determineDropdown(executeStepData, resources),
};
}
}
return variable;
};
/**
* Form with an "import from" dropdown and coordinate display/input boxes.
* Can be used to set a specific value, import a value, or declare a variable.
*/
export const LocationForm =
(props: LocationFormProps) => {
const {
sequenceUuid, resources, onChange, declarations, variable,
hideVariableLabel, locationDropdownKey, allowedDeclarations,
disallowGroups
} = props;
const { celeryNode, dropdown, vector } =
maybeUseStepData({
resources, declarations, variable, uuid: sequenceUuid
});
/** For disabling coordinate input boxes when using external data. */
const isDisabled = !determineEditable(celeryNode);
const useIdentifier = allowedDeclarations === AllowedDeclaration.identifier;
const variableListItems = (props.shouldDisplay(Feature.variables) &&
allowedDeclarations !== AllowedDeclaration.variable) ? [PARENT] : [];
const list = locationFormList(resources, variableListItems, !disallowGroups);
/** Variable name. */
const { label } = celeryNode.args;
const declaration = defensiveClone(celeryNode);
const axisPartialProps = { onChange, declaration };
const formTitle = hideVariableLabel
? t("Location")
: `${label} (${t("Location")})`;
return <div className="location-form">
<Row>
<Col xs={12}>
<label>{formTitle}</label>
<FBSelect
key={locationDropdownKey}
allowEmpty={true}
list={list}
selectedItem={dropdown}
customNullLabel={t("Coordinate")}
onChange={ddi =>
onChange(convertDDItoDeclaration({ label, useIdentifier })(ddi))} />
</Col>
</Row>
{vector &&
<Row>
{["x", "y", "z"].map((axis: Xyz) =>
<Col xs={props.width || 4} key={axis}>
<label>
{t("{{axis}} (mm)", { axis })}
</label>
<BlurableInput type="number"
disabled={isDisabled}
onCommit={manuallyEditAxis({ ...axisPartialProps, axis })}
name={`location-${axis}`}
value={"" + vector[axis]} />
</Col>)}
</Row>}
</div>;
};
import { LocationForm } from "./location_form";
interface LocalListCbProps {
dispatch: Function;

View File

@ -0,0 +1,117 @@
import * as React from "react";
import { Row, Col, FBSelect, BlurableInput } from "../../ui";
import { t } from "i18next";
import { locationFormList } from "./location_form_list";
import { convertDDItoDeclaration } from "../locals_list/handle_select";
import {
LocationFormProps, PARENT, AllowedDeclaration,
} from "../locals_list/locals_list_support";
import { defensiveClone } from "../../util/util";
import { Xyz, ScopeDeclarationBodyItem } from "farmbot";
import {
determineVector, determineDropdown, determineEditable, SequenceMeta
} from "../../resources/sequence_meta";
import { ResourceIndex, UUID } from "../../resources/interfaces";
import { Feature } from "../../devices/interfaces";
/** For LocationForm coordinate input boxes. */
export interface AxisEditProps {
axis: Xyz;
onChange: (sd: ScopeDeclarationBodyItem) => void;
declaration: ScopeDeclarationBodyItem;
}
/** Update a VariableDeclaration coordinate. */
export const manuallyEditAxis = (props: AxisEditProps) =>
(e: React.SyntheticEvent<HTMLInputElement>) => {
const { axis, onChange, declaration } = props;
const num = parseFloat(e.currentTarget.value);
if (declaration.kind === "variable_declaration" &&
declaration.args.data_value.kind === "coordinate") {
declaration.args.data_value.args[axis] = num;
!isNaN(num) && onChange(declaration);
}
};
/**
* If a declaration with a matching label exists in local `declarations`
* (step body, etc.), use it instead of the one in scope declarations.
*/
const maybeUseStepData = ({ resources, declarations, variable, uuid }: {
resources: ResourceIndex,
declarations: ScopeDeclarationBodyItem[] | undefined,
variable: SequenceMeta,
uuid: UUID,
}): SequenceMeta => {
if (declarations) {
const executeStepData = declarations
.filter(v => v.args.label === variable.celeryNode.args.label)[0];
if (executeStepData) {
return {
celeryNode: executeStepData,
vector: determineVector(executeStepData, resources, uuid),
dropdown: determineDropdown(executeStepData, resources),
};
}
}
return variable;
};
/**
* Form with an "import from" dropdown and coordinate display/input boxes.
* Can be used to set a specific value, import a value, or declare a variable.
*/
export const LocationForm =
(props: LocationFormProps) => {
const {
sequenceUuid, resources, onChange, declarations, variable,
hideVariableLabel, locationDropdownKey, allowedDeclarations,
disallowGroups
} = props;
const { celeryNode, dropdown, vector } =
maybeUseStepData({
resources, declarations, variable, uuid: sequenceUuid
});
/** For disabling coordinate input boxes when using external data. */
const isDisabled = !determineEditable(celeryNode);
const useIdentifier = allowedDeclarations === AllowedDeclaration.identifier;
const variableListItems = (props.shouldDisplay(Feature.variables) &&
allowedDeclarations !== AllowedDeclaration.variable) ? [PARENT] : [];
const list = locationFormList(resources, variableListItems, !disallowGroups);
/** Variable name. */
const { label } = celeryNode.args;
const declaration = defensiveClone(celeryNode);
const axisPartialProps = { onChange, declaration };
const formTitle = hideVariableLabel
? t("Location")
: `${label} (${t("Location")})`;
return <div className="location-form">
<Row>
<Col xs={12}>
<label>{formTitle}</label>
<FBSelect
key={locationDropdownKey}
allowEmpty={true}
list={list}
selectedItem={dropdown}
customNullLabel={t("Coordinate")}
onChange={ddi =>
onChange(convertDDItoDeclaration({ label, useIdentifier })(ddi))} />
</Col>
</Row>
{vector &&
<Row>
{["x", "y", "z"].map((axis: Xyz) =>
<Col xs={props.width || 4} key={axis}>
<label>
{t("{{axis}} (mm)", { axis })}
</label>
<BlurableInput type="number"
disabled={isDisabled}
onCommit={manuallyEditAxis({ ...axisPartialProps, axis })}
name={`location-${axis}`}
value={"" + vector[axis]} />
</Col>)}
</Row>}
</div>;
};

View File

@ -1,19 +1,19 @@
import { ResourceIndex } from "../../../resources/interfaces";
import { ResourceIndex } from "../../resources/interfaces";
import {
selectAllToolSlotPointers,
selectAllActivePoints
} from "../../../resources/selectors";
import { betterCompact } from "../../../util";
import { PointerTypeName } from "../../../interfaces";
} from "../../resources/selectors";
import { betterCompact } from "../../util";
import { TaggedTool, TaggedPoint } from "farmbot";
import { DropDownItem } from "../../../ui/index";
import { DropDownItem } from "../../ui";
import { Vector3 } from "farmbot/dist";
import { TOOL } from "./interfaces";
import * as _ from "lodash";
import { t } from "i18next";
import { capitalize } from "lodash";
import { joinKindAndId } from "../../../resources/reducer_support";
import { joinKindAndId } from "../../resources/reducer_support";
import { Point } from "farmbot/dist/resources/api_resources";
const TOOL: "Tool" = "Tool";
type ToolAndLocation = { tool: TaggedTool, location: Vector3 };
/** Return tool and location for all tools currently in tool slots. */
@ -32,6 +32,7 @@ export function activeTools(resources: ResourceIndex): ToolAndLocation[] {
: undefined));
}
type PointerTypeName = Point["pointer_type"];
type DropdownHeadingId = PointerTypeName | typeof TOOL | "Other";
/** Location selection menu section names. */

View File

@ -1,7 +1,7 @@
import { buildResourceIndex } from "../../../__test_support__/resource_index_builder";
import { ResourceIndex } from "../../../resources/interfaces";
import { buildResourceIndex } from "../../__test_support__/resource_index_builder";
import { ResourceIndex } from "../../resources/interfaces";
import { TaggedResource } from "farmbot";
import { newTaggedResource } from "../../../sync/actions";
import { newTaggedResource } from "../../sync/actions";
export function fakeResourceIndex(): ResourceIndex {
const fakeResources: TaggedResource[] = [

View File

@ -9,7 +9,7 @@ import {
import {
SequenceResource as Sequence
} from "farmbot/dist/resources/api_resources";
import { maybeTagStep } from "../../../resources/sequence_tagging";
import { maybeTagStep } from "../../resources/sequence_tagging";
// ======= TYPE DECLARATIONS =======
/** Less strict version of CeleryScript args. It's traversable, or unknown. */

View File

@ -1,4 +1,4 @@
import { fakeResourceIndex } from "../../tile_move_absolute/test_helpers";
import { fakeResourceIndex } from "../../../locals_list/test_helpers";
import { resourceUpdate } from "../assertion_support";
import { unpackStep, TOOL_MOUNT, DISMOUNTED } from "../unpack_step";
import {

View File

@ -39,9 +39,12 @@ import { StepInputBox } from "../inputs/step_input_box";
import {
determineDropdown, determineVector, findVariableByName
} from "../../resources/sequence_meta";
import { LocationForm } from "../locals_list/locals_list";
import { LocationForm } from "../locals_list/location_form";
import { AllowedDeclaration } from "../locals_list/locals_list_support";
/** Union of all types found in a move_abs "args" attribute. */
export type LocationData = MoveAbsolute["args"]["location"];
interface Args {
location: Tool | Coordinate | Point | Identifier;
speed: number;

View File

@ -1,13 +0,0 @@
import { MoveAbsolute } from "farmbot/dist";
export const TOOL: "Tool" = "Tool";
export interface InputBoxProps {
onCommit(e: React.SyntheticEvent<HTMLInputElement>): void;
children?: React.ReactNode;
disabled?: boolean;
name: string;
value: string;
}
/** Union of all types found in a move_abs "args" attribute. */
export type LocationData = MoveAbsolute["args"]["location"];

View File

@ -0,0 +1,29 @@
import { parseClassNames } from "../util";
describe("parseClassNames", () => {
it("parses class names correctly", () => {
const base = "hello, base.";
const results = parseClassNames({
xs: 1,
sm: 2,
md: 3,
lg: 4,
xsOffset: 5,
smOffset: 6,
mdOffset: 7,
lgOffset: 8,
}, base);
[
base,
"col-xs-1",
"col-sm-2",
"col-md-3",
"col-lg-4",
"col-xs-offset-5",
"col-sm-offset-6",
"col-md-offset-7",
"col-lg-offset-8",
].map(string => expect(results).toContain(string));
});
});

View File

@ -1,17 +1,17 @@
import * as React from "react";
import { Popover, Position } from "@blueprintjs/core";
import { Saucer } from "../ui/index";
import { Color } from "../interfaces";
import { ResourceColor } from "../interfaces";
import { colors } from "../util";
interface PickerProps {
current: Color;
onChange?: (color: Color) => void;
current: ResourceColor;
onChange?: (color: ResourceColor) => void;
}
export class ColorPicker extends React.Component<PickerProps, {}> {
private renderColors(color: Color, key: number) {
private renderColors(color: ResourceColor, key: number) {
const isActive = color === this.props.current;
const cb = this.props.onChange || function () { };
return <div key={key} onClick={() => cb(color)} >

View File

@ -1,6 +1,5 @@
import * as Util from "../util";
import { times } from "lodash";
import { parseClassNames } from "../../ui/util";
describe("util", () => {
describe("safeStringFetch", () => {
@ -149,35 +148,6 @@ describe("util", () => {
});
describe("parseClassNames", () => {
it("parses class names correctly", () => {
const base = "hello, base.";
const results = parseClassNames({
xs: 1,
sm: 2,
md: 3,
lg: 4,
xsOffset: 5,
smOffset: 6,
mdOffset: 7,
lgOffset: 8,
}, base);
[
base,
"col-xs-1",
"col-sm-2",
"col-md-3",
"col-lg-4",
"col-xs-offset-5",
"col-sm-offset-6",
"col-md-offset-7",
"col-lg-offset-8",
].map(string => expect(results).toContain(string));
});
});
describe("parseIntInput()", () => {
it("parses int from number input", () => {
expect(Util.parseIntInput("-1.1e+2")).toEqual(-110);

View File

@ -1,6 +1,6 @@
import { t } from "i18next";
import * as _ from "lodash";
import { Color } from "../interfaces";
import { ResourceColor } from "../interfaces";
import { box } from "boxed_value";
import {
TaggedResource,
@ -11,7 +11,7 @@ import {
} from "farmbot";
import { BotLocationData } from "../devices/interfaces";
export let colors: Array<Color> = [
export let colors: Array<ResourceColor> = [
"blue",
"green",
"yellow",
@ -23,7 +23,7 @@ export let colors: Array<Color> = [
];
/** Picks a color that is compliant with sequence / regimen color codes */
export function randomColor(): Color {
export function randomColor(): ResourceColor {
return _.sample(colors) as typeof colors[0];
}