Merge branch 'staging' of github.com:FarmBot/Farmbot-Web-App into time_format_24_hour
commit
e2ae388b6d
|
@ -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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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/`; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -33,3 +33,11 @@
|
||||||
transform: translateX(0)
|
transform: translateX(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.controls-page {
|
||||||
|
@media (min-width:992px) {
|
||||||
|
.col-md-offset-1 {
|
||||||
|
margin-left: 5%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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", () => {
|
||||||
|
|
|
@ -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]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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>;
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,7 +57,8 @@ export const emptyState = (): RestResources => {
|
||||||
PinBinding: {},
|
PinBinding: {},
|
||||||
PlantTemplate: {},
|
PlantTemplate: {},
|
||||||
SavedGarden: {},
|
SavedGarden: {},
|
||||||
DiagnosticDump: {}
|
DiagnosticDump: {},
|
||||||
|
Enigma: {},
|
||||||
},
|
},
|
||||||
byKindAndId: {},
|
byKindAndId: {},
|
||||||
references: {},
|
references: {},
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
|
@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -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,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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", () => {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in New Issue