From db203a444a75dae7c5b49cf24c57d7b04318be2c Mon Sep 17 00:00:00 2001 From: gabrielburnworth Date: Fri, 28 Jun 2019 12:05:19 -0700 Subject: [PATCH] regimen variable labels --- frontend/css/regimens.scss | 15 +++++-- .../regimens/__tests__/state_to_props_test.ts | 45 +++++++++++++++++-- .../editor/__tests__/active_editor_test.tsx | 28 +++++++++--- .../regimens/editor/__tests__/index_test.tsx | 3 +- frontend/regimens/editor/active_editor.tsx | 36 ++++++++++++--- frontend/regimens/interfaces.ts | 2 + frontend/regimens/state_to_props.ts | 13 +++++- frontend/resources/sequence_meta.ts | 4 +- .../sequences/locals_list/variable_support.ts | 2 +- 9 files changed, 125 insertions(+), 23 deletions(-) diff --git a/frontend/css/regimens.scss b/frontend/css/regimens.scss index 70782766a..25f5696de 100644 --- a/frontend/css/regimens.scss +++ b/frontend/css/regimens.scss @@ -42,10 +42,11 @@ } .regimen-event { + position: relative; background: $gray; padding: 0.7rem; border-radius: 3px; - height: 3.5rem; + min-height: 3.5rem; margin-bottom: 1rem; } @@ -58,12 +59,18 @@ .regimen-event-time { margin-left: 1.5rem; + margin-right: 1.5rem; +} + +.regimen-event-variable { + display: inline-block; + margin-right: 1.5rem; } .regimen-control { - float: right; - margin-right: 0.7rem; - margin-top: 0.3rem; + position: absolute; + top: 1rem; + right: 1rem; } .regimen-days-label { diff --git a/frontend/regimens/__tests__/state_to_props_test.ts b/frontend/regimens/__tests__/state_to_props_test.ts index 9a95014a2..f509a122f 100644 --- a/frontend/regimens/__tests__/state_to_props_test.ts +++ b/frontend/regimens/__tests__/state_to_props_test.ts @@ -1,11 +1,15 @@ import { mapStateToProps } from "../state_to_props"; import { fakeState } from "../../__test_support__/fake_state"; import { TaggedResource } from "farmbot"; -import { buildResourceIndex } from "../../__test_support__/resource_index_builder"; +import { + buildResourceIndex +} from "../../__test_support__/resource_index_builder"; import { newTaggedResource } from "../../sync/actions"; import { selectAllRegimens } from "../../resources/selectors"; import { fakeVariableNameSet } from "../../__test_support__/fake_variables"; -import { fakeRegimen, fakeSequence } from "../../__test_support__/fake_state/resources"; +import { + fakeRegimen, fakeSequence +} from "../../__test_support__/fake_state/resources"; describe("mapStateToProps()", () => { it("returns props: no regimen selected", () => { @@ -48,7 +52,9 @@ describe("mapStateToProps()", () => { it("returns variableData", () => { const reg = fakeRegimen(); const seq = fakeSequence(); - reg.body.regimen_items = [{ sequence_id: seq.body.id || 0, time_offset: 1000 }]; + reg.body.regimen_items = [{ + sequence_id: seq.body.id || 0, time_offset: 1000 + }]; const state = fakeState(); state.resources = buildResourceIndex([reg, seq]); state.resources.consumers.regimens.currentRegimen = reg.uuid; @@ -57,4 +63,37 @@ describe("mapStateToProps()", () => { const props = mapStateToProps(state); expect(props.variableData).toEqual(varData); }); + + it("returns calendar rows", () => { + const reg = fakeRegimen(); + const seq = fakeSequence(); + seq.body.body = [{ + kind: "move_absolute", args: { + location: { kind: "identifier", args: { label: "variable" } }, + offset: { kind: "coordinate", args: { x: 0, y: 0, z: 0 } }, + speed: 100, + } + }]; + seq.body.args.locals.body = [{ + kind: "parameter_declaration", + args: { + label: "variable", + default_value: { kind: "coordinate", args: { x: 1, y: 2, z: 3 } } + } + }]; + reg.body.regimen_items = [{ + sequence_id: seq.body.id || 0, time_offset: 1000 + }]; + const state = fakeState(); + state.resources = buildResourceIndex([reg, seq]); + state.resources.consumers.regimens.currentRegimen = reg.uuid; + const props = mapStateToProps(state); + expect(props.calendar).toEqual([{ + day: "1", + items: [expect.objectContaining({ + item: reg.body.regimen_items[0], + sortKey: 1000, variable: "variable" + })] + }]); + }); }); diff --git a/frontend/regimens/editor/__tests__/active_editor_test.tsx b/frontend/regimens/editor/__tests__/active_editor_test.tsx index 2bccea0e4..77ba55c98 100644 --- a/frontend/regimens/editor/__tests__/active_editor_test.tsx +++ b/frontend/regimens/editor/__tests__/active_editor_test.tsx @@ -1,6 +1,4 @@ -jest.mock("../../../api/crud", () => ({ - overwrite: jest.fn(), -})); +jest.mock("../../../api/crud", () => ({ overwrite: jest.fn() })); import * as React from "react"; import { mount } from "enzyme"; @@ -18,8 +16,8 @@ import { Actions } from "../../../constants"; const testVariable: VariableDeclaration = { kind: "variable_declaration", args: { - label: "label", data_value: { - kind: "identifier", args: { label: "new_var" } + label: "variable", data_value: { + kind: "coordinate", args: { x: 1, y: 2, z: 3 } } } }; @@ -40,7 +38,8 @@ describe("", () => { regimen: fakeRegimen(), item: { sequence_id: 0, time_offset: 1000 - } + }, + variable: undefined, }] }], resources: buildResourceIndex([]).index, @@ -115,6 +114,23 @@ describe("", () => { wrapper.instance().toggleVarShow(); expect(wrapper.state()).toEqual({ variablesCollapsed: true }); }); + + it("shows location variable label: coordinate", () => { + const p = fakeProps(); + p.calendar[0].items[0].regimen.body.body = [testVariable]; + p.calendar[0].items[0].variable = testVariable.args.label; + const wrapper = mount(); + expect(wrapper.find(".regimen-event-variable").text()) + .toEqual("Location Variable - Coordinate (1, 2, 3)"); + }); + + it("doesn't show location variable label", () => { + const p = fakeProps(); + p.calendar[0].items[0].regimen.body.body = []; + p.calendar[0].items[0].variable = "variable"; + const wrapper = mount(); + expect(wrapper.find(".regimen-event-variable").length).toEqual(0); + }); }); describe("editRegimenVariables()", () => { diff --git a/frontend/regimens/editor/__tests__/index_test.tsx b/frontend/regimens/editor/__tests__/index_test.tsx index 827048eda..3d20b845a 100644 --- a/frontend/regimens/editor/__tests__/index_test.tsx +++ b/frontend/regimens/editor/__tests__/index_test.tsx @@ -37,7 +37,8 @@ describe("", () => { regimen: regimen, item: { sequence_id: 0, time_offset: 1000 - } + }, + variable: undefined, }] }], resources: buildResourceIndex([]).index, diff --git a/frontend/regimens/editor/active_editor.tsx b/frontend/regimens/editor/active_editor.tsx index 2b4dae0f2..ca7131936 100644 --- a/frontend/regimens/editor/active_editor.tsx +++ b/frontend/regimens/editor/active_editor.tsx @@ -17,6 +17,9 @@ import { import { addOrEditBodyVariables } from "../../sequences/locals_list/handle_select"; import { t } from "../../i18next_wrapper"; import { Actions } from "../../constants"; +import { reduceVariables } from "../../sequences/locals_list/variable_support"; +import { determineDropdown, withPrefix } from "../../resources/sequence_meta"; +import { ResourceIndex } from "../../resources/interfaces"; /** * The bottom half of the regimen editor panel (when there's something to @@ -60,7 +63,8 @@ export class ActiveEditor + varsCollapsed={this.state.variablesCollapsed} + resources={this.props.resources} /> ; } } @@ -111,28 +115,32 @@ interface RegimenRowsProps { calendar: CalendarRow[]; dispatch: Function; varsCollapsed: boolean; + resources: ResourceIndex; } const RegimenRows = (props: RegimenRowsProps) =>
- {props.calendar.map(regimenDay(props.dispatch))} + {props.calendar.map(regimenDay(props.dispatch, props.resources))}
; -const regimenDay = (dispatch: Function) => +const regimenDay = (dispatch: Function, resources: ResourceIndex) => (group: CalendarRow, dayIndex: number) =>
- {group.items.map(regimenItemRow(dispatch, dayIndex))} + {group.items.map(regimenItemRow(dispatch, resources, dayIndex))}
; -const regimenItemRow = (dispatch: Function, dayIndex: number) => +const regimenItemRow = ( + dispatch: Function, resources: ResourceIndex, dayIndex: number +) => (row: RegimenItemCalendarRow, itemIndex: number) =>
{row.name} {row.hhmm} + dispatch(removeRegimenItem(row.item, row.regimen))} />
; @@ -142,3 +150,21 @@ const removeRegimenItem = (item: RegimenItem, r: TaggedRegimen) => { copy.body.regimen_items = r.body.regimen_items.filter(x => x !== item); return overwrite(r, copy.body); }; + +interface DisplayVarValueProps { + row: RegimenItemCalendarRow; + resources: ResourceIndex; +} + +const DisplayVarValue = (props: DisplayVarValueProps) => { + const { variable, regimen } = props.row; + if (variable) { + const variableNode = reduceVariables(regimen.body.body)[variable]; + if (variableNode) { + return + {withPrefix(determineDropdown(variableNode, props.resources).label)} + ; + } + } + return ; +}; diff --git a/frontend/regimens/interfaces.ts b/frontend/regimens/interfaces.ts index 08e3d1987..56c42ddb3 100644 --- a/frontend/regimens/interfaces.ts +++ b/frontend/regimens/interfaces.ts @@ -38,6 +38,8 @@ export interface RegimenItemCalendarRow { sortKey: number; day: number; dispatch: Function; + /** Variable label. */ + variable: string | undefined; } /** Used by UI widgets that modify a regimen */ diff --git a/frontend/regimens/state_to_props.ts b/frontend/regimens/state_to_props.ts index 056524b47..4c0ca23dd 100644 --- a/frontend/regimens/state_to_props.ts +++ b/frontend/regimens/state_to_props.ts @@ -13,7 +13,7 @@ import { findSequenceById, maybeGetTimeSettings } from "../resources/selectors"; -import { TaggedRegimen } from "farmbot"; +import { TaggedRegimen, TaggedSequence } from "farmbot"; import moment from "moment"; import { ResourceIndex, UUID, VariableNameSet } from "../resources/interfaces"; import { @@ -109,6 +109,7 @@ const createRows = ( (item: RegimenItem): RegimenItemCalendarRow => { const uuid = findId(index, "Sequence", item.sequence_id); const sequence = findSequence(index, uuid); + const variable = getParameterLabel(sequence); const { time_offset } = item; const d = moment.duration(time_offset); const { name } = sequence.body; @@ -116,5 +117,13 @@ const createRows = ( const FORMAT = timeFormatString(timeSettings); const hhmm = moment({ hour: d.hours(), minute: d.minutes() }).format(FORMAT); const day = Math.floor(moment.duration(time_offset).asDays()) + 1; - return { name, hhmm, color, day, dispatch, regimen, item, sortKey: time_offset }; + return { + name, hhmm, color, day, dispatch, regimen, item, variable, + sortKey: time_offset + }; }; + +const getParameterLabel = (sequence: TaggedSequence): string | undefined => + (sequence.body.args.locals.body || []) + .filter(variable => variable.kind === "parameter_declaration") + .map(variable => variable.args.label)[0]; diff --git a/frontend/resources/sequence_meta.ts b/frontend/resources/sequence_meta.ts index 3d0660ba3..101e10a8e 100644 --- a/frontend/resources/sequence_meta.ts +++ b/frontend/resources/sequence_meta.ts @@ -57,7 +57,9 @@ const maybeFindVariable = ( ): SequenceMeta | undefined => uuid ? findVariableByName(resources, uuid, label) : undefined; -const withPrefix = (label: string) => `${t("Location Variable")} - ${label}`; +/** Add "Location Variable - " prefix to string. */ +export const withPrefix = (label: string) => + `${t("Location Variable")} - ${label}`; interface DetermineVarDDILabelProps { label: string; diff --git a/frontend/sequences/locals_list/variable_support.ts b/frontend/sequences/locals_list/variable_support.ts index e5d519d86..c44674264 100644 --- a/frontend/sequences/locals_list/variable_support.ts +++ b/frontend/sequences/locals_list/variable_support.ts @@ -51,7 +51,7 @@ export const addOrEditParamApps = }; /** Convert array to a dictionary. */ -const reduceVariables = ( +export const reduceVariables = ( variables: T[]): Dictionary => { const items: Dictionary = {};