Merge branch 'staging' of github.com:FarmBot/Farmbot-Web-App into time_format_24_hour

pull/1154/head
Rick Carlino 2019-04-13 19:52:58 -07:00
commit e2ae388b6d
24 changed files with 163 additions and 61 deletions

View File

@ -24,6 +24,7 @@ import {
TaggedToolSlotPointer, TaggedToolSlotPointer,
TaggedFarmwareEnv, TaggedFarmwareEnv,
TaggedFarmwareInstallation, TaggedFarmwareInstallation,
TaggedEnigma,
} from "farmbot"; } from "farmbot";
import { fakeResource } from "../fake_resource"; import { fakeResource } from "../fake_resource";
import { ExecutableType, PinBindingType } from "farmbot/dist/resources/api_resources"; import { ExecutableType, PinBindingType } from "farmbot/dist/resources/api_resources";
@ -307,7 +308,8 @@ export function fakeWebAppConfig(): TaggedWebAppConfig {
home_button_homing: false, home_button_homing: false,
show_motor_plot: false, show_motor_plot: false,
show_historic_points: false, show_historic_points: false,
time_format_24_hour: false time_format_24_hour: false,
show_pins: false,
}); });
} }
@ -423,3 +425,12 @@ export function fakeFarmwareInstallation(): TaggedFarmwareInstallation {
package_error: undefined, package_error: undefined,
}); });
} }
export function fakeEnigma(): TaggedEnigma {
return fakeResource("Enigma", {
uuid: "uuid",
created_at: 123,
problem_tag: "api.noun.verb",
priority: 100,
});
}

View File

@ -364,6 +364,7 @@ const KIND_PRIORITY: ResourceLookupTable = {
Point: 1, Point: 1,
Sensor: 1, Sensor: 1,
Tool: 1, Tool: 1,
Enigma: 1,
SensorReading: 2, SensorReading: 2,
Sequence: 2, Sequence: 2,
Regimen: 3, Regimen: 3,

View File

@ -152,5 +152,7 @@ export class API {
get farmwareInstallationPath() { get farmwareInstallationPath() {
return `${this.baseUrl}/api/farmware_installations/`; return `${this.baseUrl}/api/farmware_installations/`;
} }
/** /api/enigmas/:id */
get enigmaPath() { return `${this.baseUrl}/api/enigmas/`; }
get syncPatch() { return `${this.baseUrl}/api/device/sync/`; } get syncPatch() { return `${this.baseUrl}/api/device/sync/`; }
} }

View File

@ -261,6 +261,7 @@ export function urlFor(tag: ResourceName) {
PlantTemplate: API.current.plantTemplatePath, PlantTemplate: API.current.plantTemplatePath,
FarmwareEnv: API.current.farmwareEnvPath, FarmwareEnv: API.current.farmwareEnvPath,
FarmwareInstallation: API.current.farmwareInstallationPath, FarmwareInstallation: API.current.farmwareInstallationPath,
Enigma: API.current.enigmaPath,
}; };
const url = OPTIONS[tag]; const url = OPTIONS[tag];
if (url) { if (url) {

View File

@ -381,6 +381,13 @@ export namespace Content {
trim(`Export request received. Please allow up to 10 minutes for trim(`Export request received. Please allow up to 10 minutes for
delivery.`); delivery.`);
export const SEED_DATA_SELECTION =
trim(`To finish setting up your account and FarmBot, please select which
FarmBot you have. Once you make a selection, we'll automatically add some
tools, sensors, peripherals, sequences, and more to get you up and running
faster. If you want to start completely from scratch, feel free to select
"Custom bot" and we won't change a thing.`);
// App Settings // App Settings
export const CONFIRM_STEP_DELETION = export const CONFIRM_STEP_DELETION =
trim(`Show a confirmation dialog when the sequence delete step trim(`Show a confirmation dialog when the sequence delete step

View File

@ -33,3 +33,11 @@
transform: translateX(0) transform: translateX(0)
} }
} }
.controls-page {
@media (min-width:992px) {
.col-md-offset-1 {
margin-left: 5%;
}
}
}

View File

@ -891,6 +891,12 @@ ul {
.bp3-popover-target { .bp3-popover-target {
float: right; float: right;
} }
@media screen and (max-width: 1075px) {
padding-left: 15px !important;
}
@media screen and (max-width: 974px) {
padding-left: 0 !important;
}
} }
.logs-settings-menu { .logs-settings-menu {

View File

@ -13,6 +13,13 @@ const FIRMWARE_MISSING_ALERT: Alert = {
uuid: "uuid", uuid: "uuid",
}; };
const SEED_DATA_MISSING_ALERT: Alert = {
created_at: 123,
problem_tag: "api.seed_data.missing",
priority: 300,
uuid: "uuid",
};
const UNKNOWN_ALERT: Alert = { const UNKNOWN_ALERT: Alert = {
created_at: 123, created_at: 123,
problem_tag: "farmbot_os.firmware.alert", problem_tag: "farmbot_os.firmware.alert",
@ -41,10 +48,11 @@ describe("<Alerts />", () => {
it("renders alerts", () => { it("renders alerts", () => {
const p = fakeProps(); const p = fakeProps();
p.alerts = [FIRMWARE_MISSING_ALERT]; p.alerts = [FIRMWARE_MISSING_ALERT, SEED_DATA_MISSING_ALERT];
const wrapper = mount(<Alerts {...p} />); const wrapper = mount(<Alerts {...p} />);
expect(wrapper.text()).toContain("1"); expect(wrapper.text()).toContain("2");
expect(wrapper.text()).toContain("Your device has no firmware installed"); expect(wrapper.text()).toContain("Your device has no firmware installed");
expect(wrapper.text()).toContain("Choose your FarmBot");
}); });
it("renders unknown alert", () => { it("renders unknown alert", () => {

View File

@ -1,9 +1,18 @@
let mockDev = false;
jest.mock("../../account/dev/dev_support", () => ({
DevSettings: {
futureFeaturesEnabled: () => mockDev,
}
}));
import { mapStateToProps } from "../state_to_props"; import { mapStateToProps } from "../state_to_props";
import { fakeState } from "../../__test_support__/fake_state"; import { fakeState } from "../../__test_support__/fake_state";
import { buildResourceIndex } from "../../__test_support__/resource_index_builder"; import { buildResourceIndex } from "../../__test_support__/resource_index_builder";
import { TaggedLog } from "farmbot"; import { TaggedLog } from "farmbot";
import { times } from "lodash"; import { times } from "lodash";
import { fakeFbosConfig, fakeLog } from "../../__test_support__/fake_state/resources"; import {
fakeFbosConfig, fakeLog, fakeEnigma
} from "../../__test_support__/fake_state/resources";
describe("mapStateToProps()", () => { describe("mapStateToProps()", () => {
function fakeLogs(count: number): TaggedLog[] { function fakeLogs(count: number): TaggedLog[] {
@ -45,9 +54,25 @@ describe("mapStateToProps()", () => {
it("handles undefined", () => { it("handles undefined", () => {
const state = fakeState(); const state = fakeState();
// tslint:disable-next-line:no-any state.bot.hardware.enigmas = undefined;
state.bot.hardware.enigmas = undefined as any;
const props = mapStateToProps(state); const props = mapStateToProps(state);
expect(props.alerts).toEqual([]); expect(props.alerts).toEqual([]);
}); });
it("doesn't show API alerts", () => {
const state = fakeState();
state.resources = buildResourceIndex([fakeEnigma()]);
mockDev = false;
const props = mapStateToProps(state);
expect(props.alerts).toEqual([]);
});
it("shows API alerts", () => {
const state = fakeState();
const enigma = fakeEnigma();
state.resources = buildResourceIndex([enigma]);
mockDev = true;
const props = mapStateToProps(state);
expect(props.alerts).toEqual([enigma.body]);
});
}); });

View File

@ -9,6 +9,7 @@ import { formatLogTime } from "./index";
import { TimeSettings } from "../interfaces"; import { TimeSettings } from "../interfaces";
import { Enigma } from "farmbot"; import { Enigma } from "farmbot";
import { sortBy } from "lodash"; import { sortBy } from "lodash";
import { Content } from "../constants";
export interface AlertsProps { export interface AlertsProps {
alerts: Alert[]; alerts: Alert[];
@ -71,11 +72,12 @@ export const FirmwareAlerts = (props: FirmwareAlertsProps) => {
const firmwareAlerts = sortAlerts(alerts) const firmwareAlerts = sortAlerts(alerts)
.filter(x => splitTag(x.problem_tag).noun === "firmware"); .filter(x => splitTag(x.problem_tag).noun === "firmware");
return <div className="firmware-alerts"> return <div className="firmware-alerts">
{firmwareAlerts.map((x, i) => {firmwareAlerts.filter(x => x.problem_tag && x.priority && x.created_at)
<AlertCard key={i} .map((x, i) =>
alert={x} <AlertCard key={i}
apiFirmwareValue={props.apiFirmwareValue} alert={x}
timeSettings={props.timeSettings} />)} apiFirmwareValue={props.apiFirmwareValue}
timeSettings={props.timeSettings} />)}
</div>; </div>;
}; };
@ -94,6 +96,10 @@ const AlertCard = (props: AlertCardProps) => {
createdAt={props.alert.created_at} createdAt={props.alert.created_at}
apiFirmwareValue={props.apiFirmwareValue} apiFirmwareValue={props.apiFirmwareValue}
timeSettings={props.timeSettings} />; timeSettings={props.timeSettings} />;
case "api.seed_data.missing":
return <SeedDataMissing
createdAt={props.alert.created_at}
timeSettings={props.timeSettings} />;
default: default:
return UnknownAlert(props.alert, props.timeSettings); return UnknownAlert(props.alert, props.timeSettings);
} }
@ -118,12 +124,15 @@ const UnknownAlert = (alert: Alert, timeSettings: TimeSettings) => {
</div>; </div>;
}; };
interface FirmwareMissingProps { interface CommonAlertCardProps {
createdAt: number; createdAt: number;
apiFirmwareValue: string | undefined;
timeSettings: TimeSettings; timeSettings: TimeSettings;
} }
interface FirmwareMissingProps extends CommonAlertCardProps {
apiFirmwareValue: string | undefined;
}
const FirmwareMissing = (props: FirmwareMissingProps) => const FirmwareMissing = (props: FirmwareMissingProps) =>
<div className="problem-alert firmware-missing-alert"> <div className="problem-alert firmware-missing-alert">
<div className="problem-alert-title"> <div className="problem-alert-title">
@ -138,3 +147,15 @@ const FirmwareMissing = (props: FirmwareMissingProps) =>
botOnline={true} /> botOnline={true} />
</div> </div>
</div>; </div>;
const SeedDataMissing = (props: CommonAlertCardProps) =>
<div className="problem-alert seed-data-missing-alert">
<div className="problem-alert-title">
<i className="fa fa-exclamation-triangle" />
<h3>{t("Choose your FarmBot")}</h3>
<p>{formatLogTime(props.createdAt, props.timeSettings)}</p>
</div>
<div className="problem-alert-content">
<p>{Content.SEED_DATA_SELECTION}</p>
</div>
</div>;

View File

@ -1,5 +1,7 @@
import { Everything } from "../interfaces"; import { Everything } from "../interfaces";
import { selectAllLogs, maybeGetTimeSettings } from "../resources/selectors"; import {
selectAllLogs, maybeGetTimeSettings, selectAllEnigmas
} from "../resources/selectors";
import { LogsProps } from "./interfaces"; import { LogsProps } from "./interfaces";
import { import {
sourceFbosConfigValue sourceFbosConfigValue
@ -11,6 +13,7 @@ import { getWebAppConfigValue } from "../config_storage/actions";
import { getFbosConfig } from "../resources/getters"; import { getFbosConfig } from "../resources/getters";
import { chain } from "lodash"; import { chain } from "lodash";
import { isFwHardwareValue } from "../devices/components/fbos_settings/board_type"; import { isFwHardwareValue } from "../devices/components/fbos_settings/board_type";
import { DevSettings } from "../account/dev/dev_support";
/** Take the specified number of logs after sorting by time created. */ /** Take the specified number of logs after sorting by time created. */
export function takeSortedLogs( export function takeSortedLogs(
@ -28,13 +31,17 @@ export function mapStateToProps(props: Everything): LogsProps {
const sourceFbosConfig = const sourceFbosConfig =
sourceFbosConfigValue(fbosConfig, hardware.configuration); sourceFbosConfigValue(fbosConfig, hardware.configuration);
const apiFirmwareValue = sourceFbosConfig("firmware_hardware").value; const apiFirmwareValue = sourceFbosConfig("firmware_hardware").value;
const botAlerts = betterCompact(Object.values(props.bot.hardware.enigmas || {}));
const apiAlerts = selectAllEnigmas(props.resources.index).map(x => x.body);
const alerts =
botAlerts.concat(DevSettings.futureFeaturesEnabled() ? apiAlerts : []);
return { return {
dispatch: props.dispatch, dispatch: props.dispatch,
sourceFbosConfig, sourceFbosConfig,
logs: takeSortedLogs(250, props.resources.index), logs: takeSortedLogs(250, props.resources.index),
timeSettings: maybeGetTimeSettings(props.resources.index), timeSettings: maybeGetTimeSettings(props.resources.index),
getConfigValue: getWebAppConfigValue(() => props), getConfigValue: getWebAppConfigValue(() => props),
alerts: betterCompact(Object.values(props.bot.hardware.enigmas || {})), alerts,
apiFirmwareValue: isFwHardwareValue(apiFirmwareValue) apiFirmwareValue: isFwHardwareValue(apiFirmwareValue)
? apiFirmwareValue : undefined, ? apiFirmwareValue : undefined,
}; };

View File

@ -57,7 +57,8 @@ export const emptyState = (): RestResources => {
PinBinding: {}, PinBinding: {},
PlantTemplate: {}, PlantTemplate: {},
SavedGarden: {}, SavedGarden: {},
DiagnosticDump: {} DiagnosticDump: {},
Enigma: {},
}, },
byKindAndId: {}, byKindAndId: {},
references: {}, references: {},

View File

@ -20,6 +20,7 @@ import {
TaggedPlantTemplate, TaggedPlantTemplate,
TaggedFarmwareEnv, TaggedFarmwareEnv,
TaggedFarmwareInstallation, TaggedFarmwareInstallation,
TaggedEnigma,
} from "farmbot"; } from "farmbot";
import { import {
isTaggedResource, isTaggedResource,
@ -99,6 +100,8 @@ export const selectAllWebcamFeeds =
(i: ResourceIndex) => findAll<TaggedWebcamFeed>(i, "WebcamFeed"); (i: ResourceIndex) => findAll<TaggedWebcamFeed>(i, "WebcamFeed");
export const selectAllSavedPeripherals = export const selectAllSavedPeripherals =
(input: ResourceIndex) => selectAllPeripherals(input).filter(isSaved); (input: ResourceIndex) => selectAllPeripherals(input).filter(isSaved);
export const selectAllEnigmas =
(i: ResourceIndex) => findAll<TaggedEnigma>(i, "Enigma");
export const findByKindAndId = <T extends TaggedResource>( export const findByKindAndId = <T extends TaggedResource>(
i: ResourceIndex, kind: T["kind"], id: number | undefined): T => { i: ResourceIndex, kind: T["kind"], id: number | undefined): T => {

View File

@ -71,9 +71,8 @@ describe("<SequenceEditorMiddleActive/>", () => {
farmwareConfigs: {}, farmwareConfigs: {},
}, },
shouldDisplay: jest.fn(), shouldDisplay: jest.fn(),
confirmStepDeletion: false, getWebAppConfigValue: jest.fn(),
menuOpen: false, menuOpen: false,
showPins: true,
}; };
}; };
@ -254,13 +253,12 @@ describe("<SequenceSettingsMenu />", () => {
it("renders settings", () => { it("renders settings", () => {
const wrapper = mount(<SequenceSettingsMenu const wrapper = mount(<SequenceSettingsMenu
dispatch={jest.fn()} dispatch={jest.fn()}
confirmStepDeletion={false} getWebAppConfigValue={jest.fn()} />);
showPins={false} />);
wrapper.find("button").first().simulate("click"); wrapper.find("button").first().simulate("click");
expect(setWebAppConfigValue).toHaveBeenCalledWith( expect(setWebAppConfigValue).toHaveBeenCalledWith(
BooleanSetting.confirm_step_deletion, true); BooleanSetting.confirm_step_deletion, true);
wrapper.find("button").last().simulate("click"); wrapper.find("button").last().simulate("click");
expect(setWebAppConfigValue).toHaveBeenCalledWith( expect(setWebAppConfigValue).toHaveBeenCalledWith(
"show_pins", true); BooleanSetting.show_pins, true);
}); });
}); });

View File

@ -25,9 +25,8 @@ describe("<SequenceEditorMiddle/>", () => {
farmwareConfigs: {}, farmwareConfigs: {},
}, },
shouldDisplay: jest.fn(), shouldDisplay: jest.fn(),
confirmStepDeletion: false, getWebAppConfigValue: jest.fn(),
menuOpen: false, menuOpen: false,
showPins: true,
}; };
} }

View File

@ -34,10 +34,9 @@ describe("<Sequences/>", () => {
farmwareConfigs: {}, farmwareConfigs: {},
}, },
shouldDisplay: jest.fn(), shouldDisplay: jest.fn(),
confirmStepDeletion: false, getWebAppConfigValue: jest.fn(),
menuOpen: false, menuOpen: false,
stepIndex: undefined, stepIndex: undefined,
showPins: true,
}); });
it("renders", () => { it("renders", () => {

View File

@ -14,6 +14,7 @@ import { StepMoveDataXfer, StepSpliceDataXfer } from "../draggable/interfaces";
import { TaggedSequence } from "farmbot"; import { TaggedSequence } from "farmbot";
import { ResourceIndex, VariableNameSet, UUID } from "../resources/interfaces"; import { ResourceIndex, VariableNameSet, UUID } from "../resources/interfaces";
import { ShouldDisplay } from "../devices/interfaces"; import { ShouldDisplay } from "../devices/interfaces";
import { GetWebAppConfigValue } from "../config_storage/actions";
export interface HardwareFlags { export interface HardwareFlags {
findHomeEnabled: Record<Xyz, boolean>; findHomeEnabled: Record<Xyz, boolean>;
@ -44,10 +45,9 @@ export interface Props {
hardwareFlags: HardwareFlags; hardwareFlags: HardwareFlags;
farmwareInfo: FarmwareInfo; farmwareInfo: FarmwareInfo;
shouldDisplay: ShouldDisplay; shouldDisplay: ShouldDisplay;
confirmStepDeletion: boolean; getWebAppConfigValue: GetWebAppConfigValue;
menuOpen: boolean; menuOpen: boolean;
stepIndex: number | undefined; stepIndex: number | undefined;
showPins: boolean;
} }
export interface SequenceEditorMiddleProps { export interface SequenceEditorMiddleProps {
@ -58,9 +58,8 @@ export interface SequenceEditorMiddleProps {
hardwareFlags: HardwareFlags; hardwareFlags: HardwareFlags;
farmwareInfo: FarmwareInfo; farmwareInfo: FarmwareInfo;
shouldDisplay: ShouldDisplay; shouldDisplay: ShouldDisplay;
confirmStepDeletion: boolean; getWebAppConfigValue: GetWebAppConfigValue;
menuOpen: boolean; menuOpen: boolean;
showPins: boolean;
} }
export interface ActiveMiddleProps extends SequenceEditorMiddleProps { export interface ActiveMiddleProps extends SequenceEditorMiddleProps {
@ -76,8 +75,7 @@ export interface SequenceHeaderProps {
menuOpen: boolean; menuOpen: boolean;
variablesCollapsed: boolean; variablesCollapsed: boolean;
toggleVarShow: () => void; toggleVarShow: () => void;
confirmStepDeletion: boolean; getWebAppConfigValue: GetWebAppConfigValue;
showPins: boolean;
} }
export type ChannelName = ALLOWED_CHANNEL_NAMES; export type ChannelName = ALLOWED_CHANNEL_NAMES;

View File

@ -25,8 +25,7 @@ export class SequenceEditorMiddle
hardwareFlags={this.props.hardwareFlags} hardwareFlags={this.props.hardwareFlags}
farmwareInfo={this.props.farmwareInfo} farmwareInfo={this.props.farmwareInfo}
shouldDisplay={this.props.shouldDisplay} shouldDisplay={this.props.shouldDisplay}
confirmStepDeletion={this.props.confirmStepDeletion} getWebAppConfigValue={this.props.getWebAppConfigValue}
showPins={this.props.showPins}
menuOpen={this.props.menuOpen} />} menuOpen={this.props.menuOpen} />}
</EmptyStateWrapper>; </EmptyStateWrapper>;
} }

View File

@ -22,9 +22,8 @@ import { Actions } from "../constants";
import { Popover, Position } from "@blueprintjs/core"; import { Popover, Position } from "@blueprintjs/core";
import { ToggleButton } from "../controls/toggle_button"; import { ToggleButton } from "../controls/toggle_button";
import { Content } from "../constants"; import { Content } from "../constants";
import { setWebAppConfigValue } from "../config_storage/actions"; import { setWebAppConfigValue, GetWebAppConfigValue } from "../config_storage/actions";
import { BooleanSetting } from "../session_keys"; import { BooleanSetting } from "../session_keys";
import { BooleanConfigKey } from "farmbot/dist/resources/configs/web_app";
export const onDrop = export const onDrop =
(dispatch1: Function, sequence: TaggedSequence) => (dispatch1: Function, sequence: TaggedSequence) =>
@ -49,13 +48,15 @@ export const onDrop =
export interface SequenceSettingsMenuProps { export interface SequenceSettingsMenuProps {
dispatch: Function; dispatch: Function;
confirmStepDeletion: boolean; getWebAppConfigValue: GetWebAppConfigValue;
showPins: boolean;
} }
export const SequenceSettingsMenu = export const SequenceSettingsMenu =
({ dispatch, confirmStepDeletion, showPins }: SequenceSettingsMenuProps) => ({ dispatch, getWebAppConfigValue }: SequenceSettingsMenuProps) => {
<div className="sequence-settings-menu"> const confirmStepDeletion =
!!getWebAppConfigValue(BooleanSetting.confirm_step_deletion);
const showPins = !!getWebAppConfigValue(BooleanSetting.show_pins);
return <div className="sequence-settings-menu">
<fieldset> <fieldset>
<label> <label>
{t("Confirm step deletion")} {t("Confirm step deletion")}
@ -74,9 +75,10 @@ export const SequenceSettingsMenu =
<ToggleButton <ToggleButton
toggleValue={showPins} toggleValue={showPins}
toggleAction={() => dispatch(setWebAppConfigValue( toggleAction={() => dispatch(setWebAppConfigValue(
"show_pins" as BooleanConfigKey, !showPins))} /> BooleanSetting.show_pins, !showPins))} />
</fieldset> </fieldset>
</div>; </div>;
};
interface SequenceBtnGroupProps { interface SequenceBtnGroupProps {
dispatch: Function; dispatch: Function;
@ -85,13 +87,12 @@ interface SequenceBtnGroupProps {
resources: ResourceIndex; resources: ResourceIndex;
shouldDisplay: ShouldDisplay; shouldDisplay: ShouldDisplay;
menuOpen: boolean; menuOpen: boolean;
confirmStepDeletion: boolean; getWebAppConfigValue: GetWebAppConfigValue;
showPins: boolean;
} }
const SequenceBtnGroup = ({ const SequenceBtnGroup = ({
dispatch, sequence, syncStatus, resources, shouldDisplay, menuOpen, dispatch, sequence, syncStatus, resources, shouldDisplay, menuOpen,
confirmStepDeletion, showPins getWebAppConfigValue
}: SequenceBtnGroupProps) => }: SequenceBtnGroupProps) =>
<div className="button-group"> <div className="button-group">
<SaveBtn status={sequence.specialStatus} <SaveBtn status={sequence.specialStatus}
@ -119,8 +120,7 @@ const SequenceBtnGroup = ({
<i className="fa fa-gear" /> <i className="fa fa-gear" />
<SequenceSettingsMenu <SequenceSettingsMenu
dispatch={dispatch} dispatch={dispatch}
showPins={showPins} getWebAppConfigValue={getWebAppConfigValue} />
confirmStepDeletion={confirmStepDeletion} />
</Popover> </Popover>
</div> </div>
</div>; </div>;
@ -155,8 +155,7 @@ const SequenceHeader = (props: SequenceHeaderProps) => {
syncStatus={props.syncStatus} syncStatus={props.syncStatus}
resources={props.resources} resources={props.resources}
shouldDisplay={props.shouldDisplay} shouldDisplay={props.shouldDisplay}
confirmStepDeletion={props.confirmStepDeletion} getWebAppConfigValue={props.getWebAppConfigValue}
showPins={props.showPins}
menuOpen={props.menuOpen} /> menuOpen={props.menuOpen} />
<SequenceNameAndColor {...sequenceAndDispatch} /> <SequenceNameAndColor {...sequenceAndDispatch} />
<LocalsList <LocalsList
@ -194,6 +193,21 @@ export class SequenceEditorMiddleActive extends
return `calc(100vh - ${subHeight}px)`; return `calc(100vh - ${subHeight}px)`;
} }
get stepProps() {
const getConfig = this.props.getWebAppConfigValue;
return {
sequence: this.props.sequence,
onDrop: onDrop(this.props.dispatch, this.props.sequence),
dispatch: this.props.dispatch,
resources: this.props.resources,
hardwareFlags: this.props.hardwareFlags,
farmwareInfo: this.props.farmwareInfo,
shouldDisplay: this.props.shouldDisplay,
confirmStepDeletion: !!getConfig(BooleanSetting.confirm_step_deletion),
showPins: !!getConfig(BooleanSetting.confirm_step_deletion),
};
}
render() { render() {
const { dispatch, sequence } = this.props; const { dispatch, sequence } = this.props;
return <div className="sequence-editor-content"> return <div className="sequence-editor-content">
@ -206,13 +220,12 @@ export class SequenceEditorMiddleActive extends
variablesCollapsed={this.state.variablesCollapsed} variablesCollapsed={this.state.variablesCollapsed}
toggleVarShow={() => toggleVarShow={() =>
this.setState({ variablesCollapsed: !this.state.variablesCollapsed })} this.setState({ variablesCollapsed: !this.state.variablesCollapsed })}
confirmStepDeletion={this.props.confirmStepDeletion} getWebAppConfigValue={this.props.getWebAppConfigValue}
showPins={this.props.showPins}
menuOpen={this.props.menuOpen} /> menuOpen={this.props.menuOpen} />
<hr /> <hr />
<div className="sequence" id="sequenceDiv" <div className="sequence" id="sequenceDiv"
style={{ height: this.stepSectionHeight }}> style={{ height: this.stepSectionHeight }}>
<AllSteps onDrop={onDrop(dispatch, sequence)} {...this.props} /> <AllSteps {...this.stepProps} />
<Row> <Row>
<Col xs={12}> <Col xs={12}>
<DropArea isLocked={true} <DropArea isLocked={true}

View File

@ -69,8 +69,7 @@ export class Sequences extends React.Component<Props, {}> {
hardwareFlags={this.props.hardwareFlags} hardwareFlags={this.props.hardwareFlags}
farmwareInfo={this.props.farmwareInfo} farmwareInfo={this.props.farmwareInfo}
shouldDisplay={this.props.shouldDisplay} shouldDisplay={this.props.shouldDisplay}
confirmStepDeletion={this.props.confirmStepDeletion} getWebAppConfigValue={this.props.getWebAppConfigValue}
showPins={this.props.showPins}
menuOpen={this.props.menuOpen} /> menuOpen={this.props.menuOpen} />
</CenterPanel> </CenterPanel>
<RightPanel <RightPanel

View File

@ -15,7 +15,6 @@ import { getFirmwareConfig } from "../resources/getters";
import { Farmwares } from "../farmware/interfaces"; import { Farmwares } from "../farmware/interfaces";
import { manifestInfo } from "../farmware/generate_manifest_info"; import { manifestInfo } from "../farmware/generate_manifest_info";
import { DevSettings } from "../account/dev/dev_support"; import { DevSettings } from "../account/dev/dev_support";
import { BooleanConfigKey } from "farmbot/dist/resources/configs/web_app";
export function mapStateToProps(props: Everything): Props { export function mapStateToProps(props: Everything): Props {
const uuid = props.resources.consumers.sequences.current; const uuid = props.resources.consumers.sequences.current;
@ -70,10 +69,6 @@ export function mapStateToProps(props: Everything): Props {
const installedOsVersion = determineInstalledOsVersion( const installedOsVersion = determineInstalledOsVersion(
props.bot, maybeGetDevice(props.resources.index)); props.bot, maybeGetDevice(props.resources.index));
const confirmStepDeletion = !!getConfig(BooleanSetting.confirm_step_deletion);
const showPins = !!getConfig("show_pins" as BooleanConfigKey);
const fbosVersionOverride = DevSettings.overriddenFbosVersion(); const fbosVersionOverride = DevSettings.overriddenFbosVersion();
const shouldDisplay = shouldDisplayFunc( const shouldDisplay = shouldDisplayFunc(
installedOsVersion, props.bot.minOsFeatureData, fbosVersionOverride); installedOsVersion, props.bot.minOsFeatureData, fbosVersionOverride);
@ -96,9 +91,8 @@ export function mapStateToProps(props: Everything): Props {
farmwareConfigs, farmwareConfigs,
}, },
shouldDisplay, shouldDisplay,
confirmStepDeletion, getWebAppConfigValue: getConfig,
menuOpen: props.resources.consumers.sequences.menuOpen, menuOpen: props.resources.consumers.sequences.menuOpen,
stepIndex: props.resources.consumers.sequences.stepIndex, stepIndex: props.resources.consumers.sequences.stepIndex,
showPins,
}; };
} }

View File

@ -21,6 +21,7 @@ export const BooleanSetting: Record<BooleanConfigKey, BooleanConfigKey> = {
show_motor_plot: "show_motor_plot", show_motor_plot: "show_motor_plot",
show_historic_points: "show_historic_points", show_historic_points: "show_historic_points",
time_format_24_hour: "time_format_24_hour", time_format_24_hour: "time_format_24_hour",
show_pins: "show_pins",
/** "Labs" feature names. (App preferences) */ /** "Labs" feature names. (App preferences) */
stub_config: "stub_config", stub_config: "stub_config",

View File

@ -75,7 +75,8 @@ export async function fetchSyncData(dispatch: Function) {
get("Peripheral", API.current.peripheralsPath), get("Peripheral", API.current.peripheralsPath),
get("Point", API.current.allPointsPath), get("Point", API.current.allPointsPath),
get("Sensor", API.current.sensorPath), get("Sensor", API.current.sensorPath),
get("Tool", API.current.toolsPath) get("Tool", API.current.toolsPath),
get("Enigma", API.current.enigmaPath),
]), ]),
2: () => Promise.all<{}>([ 2: () => Promise.all<{}>([
get("SensorReading", API.current.sensorReadingPath), get("SensorReading", API.current.sensorReadingPath),

View File

@ -43,7 +43,7 @@
"coveralls": "3.0.3", "coveralls": "3.0.3",
"enzyme": "3.9.0", "enzyme": "3.9.0",
"enzyme-adapter-react-16": "1.12.1", "enzyme-adapter-react-16": "1.12.1",
"farmbot": "7.0.2", "farmbot": "7.0.4-rc1",
"farmbot-toastr": "1.0.3", "farmbot-toastr": "1.0.3",
"i18next": "15.0.9", "i18next": "15.0.9",
"jest": "24.7.1", "jest": "24.7.1",