misc fixes
parent
83d9cb8287
commit
cb44640ca5
|
@ -1,8 +1,3 @@
|
||||||
let mockDev = false;
|
|
||||||
jest.mock("../account/dev/dev_support", () => ({
|
|
||||||
DevSettings: { futureFeaturesEnabled: () => mockDev }
|
|
||||||
}));
|
|
||||||
|
|
||||||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||||
|
|
||||||
let mockPath = "";
|
let mockPath = "";
|
||||||
|
@ -16,7 +11,7 @@ import { App, AppProps, mapStateToProps } from "../app";
|
||||||
import { mount } from "enzyme";
|
import { mount } from "enzyme";
|
||||||
import { bot } from "../__test_support__/fake_state/bot";
|
import { bot } from "../__test_support__/fake_state/bot";
|
||||||
import {
|
import {
|
||||||
fakeUser, fakeWebAppConfig, fakeEnigma
|
fakeUser, fakeWebAppConfig
|
||||||
} from "../__test_support__/fake_state/resources";
|
} from "../__test_support__/fake_state/resources";
|
||||||
import { fakeState } from "../__test_support__/fake_state";
|
import { fakeState } from "../__test_support__/fake_state";
|
||||||
import {
|
import {
|
||||||
|
@ -147,21 +142,4 @@ describe("mapStateToProps()", () => {
|
||||||
const result = mapStateToProps(state);
|
const result = mapStateToProps(state);
|
||||||
expect(result.axisInversion.x).toEqual(true);
|
expect(result.axisInversion.x).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("doesn't show API alerts", () => {
|
|
||||||
const state = fakeState();
|
|
||||||
state.resources = buildResourceIndex([fakeEnigma()]);
|
|
||||||
mockDev = false;
|
|
||||||
const props = mapStateToProps(state);
|
|
||||||
expect(props.alertCount).toEqual(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shows API alerts", () => {
|
|
||||||
const state = fakeState();
|
|
||||||
const enigma = fakeEnigma();
|
|
||||||
state.resources = buildResourceIndex([enigma]);
|
|
||||||
mockDev = true;
|
|
||||||
const props = mapStateToProps(state);
|
|
||||||
expect(props.alertCount).toEqual(1);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,12 +10,11 @@ import {
|
||||||
maybeFetchUser,
|
maybeFetchUser,
|
||||||
maybeGetTimeSettings,
|
maybeGetTimeSettings,
|
||||||
getDeviceAccountSettings,
|
getDeviceAccountSettings,
|
||||||
selectAllEnigmas,
|
|
||||||
} from "./resources/selectors";
|
} from "./resources/selectors";
|
||||||
import { HotKeys } from "./hotkeys";
|
import { HotKeys } from "./hotkeys";
|
||||||
import { ControlsPopup } from "./controls_popup";
|
import { ControlsPopup } from "./controls_popup";
|
||||||
import { Content } from "./constants";
|
import { Content } from "./constants";
|
||||||
import { validBotLocationData, validFwConfig, validFbosConfig, betterCompact } from "./util";
|
import { validBotLocationData, validFwConfig, validFbosConfig } from "./util";
|
||||||
import { BooleanSetting } from "./session_keys";
|
import { BooleanSetting } from "./session_keys";
|
||||||
import { getPathArray } from "./history";
|
import { getPathArray } from "./history";
|
||||||
import {
|
import {
|
||||||
|
@ -29,7 +28,7 @@ import { t } from "./i18next_wrapper";
|
||||||
import { ResourceIndex } from "./resources/interfaces";
|
import { ResourceIndex } from "./resources/interfaces";
|
||||||
import { isBotOnline } from "./devices/must_be_online";
|
import { isBotOnline } from "./devices/must_be_online";
|
||||||
import { getStatus } from "./connectivity/reducer_support";
|
import { getStatus } from "./connectivity/reducer_support";
|
||||||
import { DevSettings } from "./account/dev/dev_support";
|
import { getAlerts } from "./messages/state_to_props";
|
||||||
|
|
||||||
/** For the logger module */
|
/** For the logger module */
|
||||||
init();
|
init();
|
||||||
|
@ -56,10 +55,6 @@ export interface AppProps {
|
||||||
export function mapStateToProps(props: Everything): AppProps {
|
export function mapStateToProps(props: Everything): AppProps {
|
||||||
const webAppConfigValue = getWebAppConfigValue(() => props);
|
const webAppConfigValue = getWebAppConfigValue(() => props);
|
||||||
const fbosConfig = validFbosConfig(getFbosConfig(props.resources.index));
|
const fbosConfig = validFbosConfig(getFbosConfig(props.resources.index));
|
||||||
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 {
|
||||||
timeSettings: maybeGetTimeSettings(props.resources.index),
|
timeSettings: maybeGetTimeSettings(props.resources.index),
|
||||||
dispatch: props.dispatch,
|
dispatch: props.dispatch,
|
||||||
|
@ -80,7 +75,7 @@ export function mapStateToProps(props: Everything): AppProps {
|
||||||
tour: props.resources.consumers.help.currentTour,
|
tour: props.resources.consumers.help.currentTour,
|
||||||
resources: props.resources.index,
|
resources: props.resources.index,
|
||||||
autoSync: !!(fbosConfig && fbosConfig.auto_sync),
|
autoSync: !!(fbosConfig && fbosConfig.auto_sync),
|
||||||
alertCount: alerts.length,
|
alertCount: getAlerts(props.resources.index, props.bot).length,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/** Time at which the app gives up and asks the user to refresh */
|
/** Time at which the app gives up and asks the user to refresh */
|
||||||
|
|
|
@ -422,8 +422,7 @@ export namespace Content {
|
||||||
|
|
||||||
// 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 deleting a sequence step.`);
|
||||||
icon is pressed.`);
|
|
||||||
|
|
||||||
export const HIDE_WEBCAM_WIDGET =
|
export const HIDE_WEBCAM_WIDGET =
|
||||||
trim(`If not using a webcam, use this setting to remove the
|
trim(`If not using a webcam, use this setting to remove the
|
||||||
|
|
|
@ -13,7 +13,7 @@ describe("calcMicrostepsPerMm()", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("calculates value with microstepping", () => {
|
it("calculates value with microstepping", () => {
|
||||||
expect(calcMicrostepsPerMm(5, 4)).toEqual(20);
|
expect(calcMicrostepsPerMm(5, 4)).toEqual(5);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ describe("calculateAxialLengths()", () => {
|
||||||
firmwareSettings.movement_step_per_mm_z = 25;
|
firmwareSettings.movement_step_per_mm_z = 25;
|
||||||
firmwareSettings.movement_microsteps_z = 4;
|
firmwareSettings.movement_microsteps_z = 4;
|
||||||
expect(calculateAxialLengths({ firmwareSettings })).toEqual({
|
expect(calculateAxialLengths({ firmwareSettings })).toEqual({
|
||||||
x: 0, y: 20, z: 1
|
x: 0, y: 20, z: 4
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,8 @@ import { McuParams } from "farmbot";
|
||||||
export const calcMicrostepsPerMm = (
|
export const calcMicrostepsPerMm = (
|
||||||
steps_per_mm: number | undefined,
|
steps_per_mm: number | undefined,
|
||||||
microsteps_per_step: number | undefined) =>
|
microsteps_per_step: number | undefined) =>
|
||||||
(steps_per_mm || 1) * (microsteps_per_step || 1);
|
// The firmware currently interprets steps_per_mm as microsteps_per_mm.
|
||||||
|
(steps_per_mm || 1) * (1 || microsteps_per_step || 1);
|
||||||
|
|
||||||
const calcAxisLength = (
|
const calcAxisLength = (
|
||||||
nr_steps: number | undefined,
|
nr_steps: number | undefined,
|
||||||
|
|
|
@ -26,9 +26,6 @@
|
||||||
0% {
|
0% {
|
||||||
transform: translateX(-11rem)
|
transform: translateX(-11rem)
|
||||||
}
|
}
|
||||||
90% {
|
|
||||||
transform: translateX(1rem)
|
|
||||||
}
|
|
||||||
100% {
|
100% {
|
||||||
transform: translateX(0)
|
transform: translateX(0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ nav {
|
||||||
}
|
}
|
||||||
div {
|
div {
|
||||||
display: inline;
|
display: inline;
|
||||||
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,9 @@ export function EncodersAndEndStops(props: EncodersProps) {
|
||||||
x={"encoder_scaling_x"}
|
x={"encoder_scaling_x"}
|
||||||
y={"encoder_scaling_y"}
|
y={"encoder_scaling_y"}
|
||||||
z={"encoder_scaling_z"}
|
z={"encoder_scaling_z"}
|
||||||
|
xScale={sourceFwConfig("movement_microsteps_x").value}
|
||||||
|
yScale={sourceFwConfig("movement_microsteps_y").value}
|
||||||
|
zScale={sourceFwConfig("movement_microsteps_z").value}
|
||||||
intSize={shouldDisplay(Feature.long_scaling_factor) ? "long" : "short"}
|
intSize={shouldDisplay(Feature.long_scaling_factor) ? "long" : "short"}
|
||||||
gray={encodersDisabled}
|
gray={encodersDisabled}
|
||||||
sourceFwConfig={sourceFwConfig}
|
sourceFwConfig={sourceFwConfig}
|
||||||
|
|
|
@ -37,7 +37,7 @@ describe("<Tour />", () => {
|
||||||
const wrapper = shallow<Tour>(<Tour steps={steps} />);
|
const wrapper = shallow<Tour>(<Tour steps={steps} />);
|
||||||
wrapper.instance().callback(fakeCallbackData({ type: "tour:end" }));
|
wrapper.instance().callback(fakeCallbackData({ type: "tour:end" }));
|
||||||
expect(wrapper.state()).toEqual({ run: false, index: 0 });
|
expect(wrapper.state()).toEqual({ run: false, index: 0 });
|
||||||
expect(history.push).toHaveBeenCalledWith("/app/help");
|
expect(history.push).toHaveBeenCalledWith("/app/messages");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("navigates through tour: next", () => {
|
it("navigates through tour: next", () => {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
|
||||||
import Joyride, { Step as TourStep, CallBackProps } from "react-joyride";
|
import Joyride, { Step as TourStep, CallBackProps } from "react-joyride";
|
||||||
import { Color } from "../ui";
|
import { Color } from "../ui";
|
||||||
import { history } from "../history";
|
import { history } from "../history";
|
||||||
|
@ -44,7 +43,7 @@ export class Tour extends React.Component<TourProps, TourState> {
|
||||||
}
|
}
|
||||||
if (type === "tour:end") {
|
if (type === "tour:end") {
|
||||||
this.setState({ run: false });
|
this.setState({ run: false });
|
||||||
history.push("/app/help");
|
history.push("/app/messages");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ describe("<Alerts />", () => {
|
||||||
apiFirmwareValue: undefined,
|
apiFirmwareValue: undefined,
|
||||||
timeSettings: fakeTimeSettings(),
|
timeSettings: fakeTimeSettings(),
|
||||||
dispatch: jest.fn(),
|
dispatch: jest.fn(),
|
||||||
|
findApiAlertById: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders no alerts", () => {
|
it("renders no alerts", () => {
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
jest.mock("../../api/crud", () => ({ destroy: jest.fn() }));
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { mount } from "enzyme";
|
import { mount } from "enzyme";
|
||||||
import { AlertCard } from "../cards";
|
import { AlertCard } from "../cards";
|
||||||
import { AlertCardProps } from "../interfaces";
|
import { AlertCardProps } from "../interfaces";
|
||||||
import { fakeTimeSettings } from "../../__test_support__/fake_time_settings";
|
import { fakeTimeSettings } from "../../__test_support__/fake_time_settings";
|
||||||
import { FBSelect } from "../../ui";
|
import { FBSelect } from "../../ui";
|
||||||
|
import { destroy } from "../../api/crud";
|
||||||
|
|
||||||
describe("<AlertCard />", () => {
|
describe("<AlertCard />", () => {
|
||||||
const fakeProps = (): AlertCardProps => ({
|
const fakeProps = (): AlertCardProps => ({
|
||||||
|
@ -19,8 +22,13 @@ describe("<AlertCard />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders unknown card", () => {
|
it("renders unknown card", () => {
|
||||||
const wrapper = mount(<AlertCard {...fakeProps()} />);
|
const p = fakeProps();
|
||||||
|
p.alert.id = 1;
|
||||||
|
p.findApiAlertById = () => "uuid";
|
||||||
|
const wrapper = mount(<AlertCard {...p} />);
|
||||||
expect(wrapper.text()).toContain("noun: verb (author)");
|
expect(wrapper.text()).toContain("noun: verb (author)");
|
||||||
|
wrapper.find(".fa-times").simulate("click");
|
||||||
|
expect(destroy).toHaveBeenCalledWith("uuid");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders firmware card", () => {
|
it("renders firmware card", () => {
|
||||||
|
@ -28,6 +36,8 @@ describe("<AlertCard />", () => {
|
||||||
p.alert.problem_tag = "farmbot_os.firmware.missing";
|
p.alert.problem_tag = "farmbot_os.firmware.missing";
|
||||||
const wrapper = mount(<AlertCard {...p} />);
|
const wrapper = mount(<AlertCard {...p} />);
|
||||||
expect(wrapper.text()).toContain("Firmware missing");
|
expect(wrapper.text()).toContain("Firmware missing");
|
||||||
|
wrapper.find(".fa-times").simulate("click");
|
||||||
|
expect(destroy).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders seed data card", () => {
|
it("renders seed data card", () => {
|
||||||
|
|
|
@ -12,6 +12,7 @@ describe("<Messages />", () => {
|
||||||
apiFirmwareValue: undefined,
|
apiFirmwareValue: undefined,
|
||||||
timeSettings: fakeTimeSettings(),
|
timeSettings: fakeTimeSettings(),
|
||||||
dispatch: Function,
|
dispatch: Function,
|
||||||
|
findApiAlertById: jest.fn(),
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders page", () => {
|
it("renders page", () => {
|
||||||
|
|
|
@ -6,7 +6,9 @@ jest.mock("../../account/dev/dev_support", () => ({
|
||||||
import { fakeState } from "../../__test_support__/fake_state";
|
import { fakeState } from "../../__test_support__/fake_state";
|
||||||
import { mapStateToProps } from "../state_to_props";
|
import { mapStateToProps } from "../state_to_props";
|
||||||
import { buildResourceIndex } from "../../__test_support__/resource_index_builder";
|
import { buildResourceIndex } from "../../__test_support__/resource_index_builder";
|
||||||
import { fakeEnigma, fakeFbosConfig } from "../../__test_support__/fake_state/resources";
|
import {
|
||||||
|
fakeEnigma, fakeFbosConfig
|
||||||
|
} from "../../__test_support__/fake_state/resources";
|
||||||
|
|
||||||
describe("mapStateToProps()", () => {
|
describe("mapStateToProps()", () => {
|
||||||
it("handles undefined", () => {
|
it("handles undefined", () => {
|
||||||
|
@ -18,7 +20,9 @@ describe("mapStateToProps()", () => {
|
||||||
|
|
||||||
it("doesn't show API alerts", () => {
|
it("doesn't show API alerts", () => {
|
||||||
const state = fakeState();
|
const state = fakeState();
|
||||||
state.resources = buildResourceIndex([fakeEnigma()]);
|
const enigma = fakeEnigma();
|
||||||
|
enigma.body.problem_tag = "api.seed_data.missing";
|
||||||
|
state.resources = buildResourceIndex([enigma]);
|
||||||
mockDev = false;
|
mockDev = false;
|
||||||
const props = mapStateToProps(state);
|
const props = mapStateToProps(state);
|
||||||
expect(props.alerts).toEqual([]);
|
expect(props.alerts).toEqual([]);
|
||||||
|
@ -27,6 +31,7 @@ describe("mapStateToProps()", () => {
|
||||||
it("shows API alerts", () => {
|
it("shows API alerts", () => {
|
||||||
const state = fakeState();
|
const state = fakeState();
|
||||||
const enigma = fakeEnigma();
|
const enigma = fakeEnigma();
|
||||||
|
enigma.body.problem_tag = "api.seed_data.missing";
|
||||||
state.resources = buildResourceIndex([enigma]);
|
state.resources = buildResourceIndex([enigma]);
|
||||||
mockDev = true;
|
mockDev = true;
|
||||||
const props = mapStateToProps(state);
|
const props = mapStateToProps(state);
|
||||||
|
@ -42,4 +47,13 @@ describe("mapStateToProps()", () => {
|
||||||
const props = mapStateToProps(state);
|
const props = mapStateToProps(state);
|
||||||
expect(props.apiFirmwareValue).toEqual("arduino");
|
expect(props.apiFirmwareValue).toEqual("arduino");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("finds alert", () => {
|
||||||
|
const state = fakeState();
|
||||||
|
const alert = fakeEnigma();
|
||||||
|
alert.body.id = 1;
|
||||||
|
state.resources = buildResourceIndex([alert]);
|
||||||
|
const props = mapStateToProps(state);
|
||||||
|
expect(props.findApiAlertById(1)).toEqual(alert.uuid);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -37,6 +37,7 @@ export const Alerts = (props: AlertsProps) =>
|
||||||
alert={x}
|
alert={x}
|
||||||
dispatch={props.dispatch}
|
dispatch={props.dispatch}
|
||||||
apiFirmwareValue={props.apiFirmwareValue}
|
apiFirmwareValue={props.apiFirmwareValue}
|
||||||
timeSettings={props.timeSettings} />)}
|
timeSettings={props.timeSettings}
|
||||||
|
findApiAlertById={props.findApiAlertById} />)}
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
|
|
@ -3,7 +3,8 @@ import { t } from "../i18next_wrapper";
|
||||||
import {
|
import {
|
||||||
AlertCardProps, AlertCardTemplateProps, FirmwareMissingProps,
|
AlertCardProps, AlertCardTemplateProps, FirmwareMissingProps,
|
||||||
SeedDataMissingProps, SeedDataMissingState, TourNotTakenProps,
|
SeedDataMissingProps, SeedDataMissingState, TourNotTakenProps,
|
||||||
CommonAlertCardProps
|
CommonAlertCardProps,
|
||||||
|
DismissAlertProps
|
||||||
} from "./interfaces";
|
} from "./interfaces";
|
||||||
import { formatLogTime } from "../logs";
|
import { formatLogTime } from "../logs";
|
||||||
import {
|
import {
|
||||||
|
@ -13,20 +14,21 @@ import { DropDownItem, Row, Col, FBSelect, docLink } from "../ui";
|
||||||
import { Content } from "../constants";
|
import { Content } from "../constants";
|
||||||
import { TourList } from "../help/tour_list";
|
import { TourList } from "../help/tour_list";
|
||||||
import { splitProblemTag } from "./alerts";
|
import { splitProblemTag } from "./alerts";
|
||||||
|
import { destroy } from "../api/crud";
|
||||||
|
|
||||||
export const AlertCard = (props: AlertCardProps) => {
|
export const AlertCard = (props: AlertCardProps) => {
|
||||||
const { alert, timeSettings } = props;
|
const { alert, timeSettings, findApiAlertById, dispatch } = props;
|
||||||
const commonProps = { alert, timeSettings };
|
const commonProps = { alert, timeSettings, findApiAlertById, dispatch };
|
||||||
switch (alert.problem_tag) {
|
switch (alert.problem_tag) {
|
||||||
case "farmbot_os.firmware.missing":
|
case "farmbot_os.firmware.missing":
|
||||||
return <FirmwareMissing {...commonProps}
|
return <FirmwareMissing {...commonProps}
|
||||||
apiFirmwareValue={props.apiFirmwareValue} />;
|
apiFirmwareValue={props.apiFirmwareValue} />;
|
||||||
case "api.seed_data.missing":
|
case "api.seed_data.missing":
|
||||||
return <SeedDataMissing {...commonProps}
|
return <SeedDataMissing {...commonProps}
|
||||||
dispatch={props.dispatch} />;
|
dispatch={dispatch} />;
|
||||||
case "api.tour.not_taken":
|
case "api.tour.not_taken":
|
||||||
return <TourNotTaken {...commonProps}
|
return <TourNotTaken {...commonProps}
|
||||||
dispatch={props.dispatch} />;
|
dispatch={dispatch} />;
|
||||||
case "api.user.not_welcomed":
|
case "api.user.not_welcomed":
|
||||||
return <UserNotWelcomed {...commonProps} />;
|
return <UserNotWelcomed {...commonProps} />;
|
||||||
case "api.documentation.unread":
|
case "api.documentation.unread":
|
||||||
|
@ -35,20 +37,27 @@ export const AlertCard = (props: AlertCardProps) => {
|
||||||
return UnknownAlert(commonProps);
|
return UnknownAlert(commonProps);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const dismissAlert = (props: DismissAlertProps) => () =>
|
||||||
|
(props.id && props.findApiAlertById && props.dispatch)
|
||||||
|
? props.dispatch(destroy(props.findApiAlertById(props.id)))
|
||||||
|
: () => { };
|
||||||
|
|
||||||
const AlertCardTemplate = (props: AlertCardTemplateProps) =>
|
const AlertCardTemplate = (props: AlertCardTemplateProps) => {
|
||||||
<div className={`problem-alert ${props.className}`}>
|
const { alert, findApiAlertById, dispatch } = props;
|
||||||
|
return <div className={`problem-alert ${props.className}`}>
|
||||||
<div className="problem-alert-title">
|
<div className="problem-alert-title">
|
||||||
<i className="fa fa-exclamation-triangle" />
|
<i className="fa fa-exclamation-triangle" />
|
||||||
<h3>{t(props.title)}</h3>
|
<h3>{t(props.title)}</h3>
|
||||||
<p>{formatLogTime(props.alert.created_at, props.timeSettings)}</p>
|
<p>{formatLogTime(alert.created_at, props.timeSettings)}</p>
|
||||||
<i className="fa fa-times" />
|
<i className="fa fa-times"
|
||||||
|
onClick={dismissAlert({ id: alert.id, findApiAlertById, dispatch })} />
|
||||||
</div>
|
</div>
|
||||||
<div className="problem-alert-content">
|
<div className="problem-alert-content">
|
||||||
<p>{t(props.message)}</p>
|
<p>{t(props.message)}</p>
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
const UnknownAlert = (props: CommonAlertCardProps) => {
|
const UnknownAlert = (props: CommonAlertCardProps) => {
|
||||||
const { problem_tag, created_at, priority } = props.alert;
|
const { problem_tag, created_at, priority } = props.alert;
|
||||||
|
@ -60,7 +69,9 @@ const UnknownAlert = (props: CommonAlertCardProps) => {
|
||||||
title={`${t(noun)}: ${t(verb)} (${t(author)})`}
|
title={`${t(noun)}: ${t(verb)} (${t(author)})`}
|
||||||
message={t("Unknown problem of priority {{priority}} created at {{createdAt}}",
|
message={t("Unknown problem of priority {{priority}} created at {{createdAt}}",
|
||||||
{ priority, createdAt })}
|
{ priority, createdAt })}
|
||||||
timeSettings={props.timeSettings} />;
|
timeSettings={props.timeSettings}
|
||||||
|
dispatch={props.dispatch}
|
||||||
|
findApiAlertById={props.findApiAlertById} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const FirmwareMissing = (props: FirmwareMissingProps) =>
|
const FirmwareMissing = (props: FirmwareMissingProps) =>
|
||||||
|
@ -69,7 +80,9 @@ const FirmwareMissing = (props: FirmwareMissingProps) =>
|
||||||
className={"firmware-missing-alert"}
|
className={"firmware-missing-alert"}
|
||||||
title={t("Firmware missing")}
|
title={t("Firmware missing")}
|
||||||
message={t("Your device has no firmware installed.")}
|
message={t("Your device has no firmware installed.")}
|
||||||
timeSettings={props.timeSettings}>
|
timeSettings={props.timeSettings}
|
||||||
|
dispatch={props.dispatch}
|
||||||
|
findApiAlertById={props.findApiAlertById}>
|
||||||
<FirmwareActions
|
<FirmwareActions
|
||||||
apiFirmwareValue={props.apiFirmwareValue}
|
apiFirmwareValue={props.apiFirmwareValue}
|
||||||
botOnline={true} />
|
botOnline={true} />
|
||||||
|
@ -92,7 +105,9 @@ class SeedDataMissing
|
||||||
className={"seed-data-missing-alert"}
|
className={"seed-data-missing-alert"}
|
||||||
title={t("Choose your FarmBot")}
|
title={t("Choose your FarmBot")}
|
||||||
message={t(Content.SEED_DATA_SELECTION)}
|
message={t(Content.SEED_DATA_SELECTION)}
|
||||||
timeSettings={this.props.timeSettings}>
|
timeSettings={this.props.timeSettings}
|
||||||
|
dispatch={this.props.dispatch}
|
||||||
|
findApiAlertById={this.props.findApiAlertById}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={4}>
|
<Col xs={4}>
|
||||||
<label>{t("Choose your FarmBot")}</label>
|
<label>{t("Choose your FarmBot")}</label>
|
||||||
|
@ -115,7 +130,9 @@ const TourNotTaken = (props: TourNotTakenProps) =>
|
||||||
className={"tour-not-taken-alert"}
|
className={"tour-not-taken-alert"}
|
||||||
title={t("Take a guided tour")}
|
title={t("Take a guided tour")}
|
||||||
message={t(Content.TAKE_A_TOUR)}
|
message={t(Content.TAKE_A_TOUR)}
|
||||||
timeSettings={props.timeSettings}>
|
timeSettings={props.timeSettings}
|
||||||
|
dispatch={props.dispatch}
|
||||||
|
findApiAlertById={props.findApiAlertById}>
|
||||||
<p>{t("Choose a tour to begin")}:</p>
|
<p>{t("Choose a tour to begin")}:</p>
|
||||||
<TourList dispatch={props.dispatch} />
|
<TourList dispatch={props.dispatch} />
|
||||||
</AlertCardTemplate>;
|
</AlertCardTemplate>;
|
||||||
|
@ -126,7 +143,9 @@ const UserNotWelcomed = (props: CommonAlertCardProps) =>
|
||||||
className={"user-not-welcomed-alert"}
|
className={"user-not-welcomed-alert"}
|
||||||
title={t("Welcome to the FarmBot Web App")}
|
title={t("Welcome to the FarmBot Web App")}
|
||||||
message={t(Content.WELCOME)}
|
message={t(Content.WELCOME)}
|
||||||
timeSettings={props.timeSettings}>
|
timeSettings={props.timeSettings}
|
||||||
|
dispatch={props.dispatch}
|
||||||
|
findApiAlertById={props.findApiAlertById}>
|
||||||
<p>
|
<p>
|
||||||
{t("You're currently viewing the")} <b>{t("Message Center")}</b>.
|
{t("You're currently viewing the")} <b>{t("Message Center")}</b>.
|
||||||
{t(Content.MESSAGE_CENTER_WELCOME)}
|
{t(Content.MESSAGE_CENTER_WELCOME)}
|
||||||
|
@ -142,7 +161,9 @@ const DocumentationUnread = (props: CommonAlertCardProps) =>
|
||||||
className={"documentation-unread-alert"}
|
className={"documentation-unread-alert"}
|
||||||
title={t("Learn more about the app")}
|
title={t("Learn more about the app")}
|
||||||
message={t(Content.READ_THE_DOCS)}
|
message={t(Content.READ_THE_DOCS)}
|
||||||
timeSettings={props.timeSettings}>
|
timeSettings={props.timeSettings}
|
||||||
|
dispatch={props.dispatch}
|
||||||
|
findApiAlertById={props.findApiAlertById}>
|
||||||
<p>
|
<p>
|
||||||
{t("Head over to")}
|
{t("Head over to")}
|
||||||
<a href={docLink()} target="_blank"
|
<a href={docLink()} target="_blank"
|
||||||
|
|
|
@ -24,7 +24,8 @@ export class Messages extends React.Component<MessagesProps, {}> {
|
||||||
<Alerts alerts={this.props.alerts}
|
<Alerts alerts={this.props.alerts}
|
||||||
dispatch={this.props.dispatch}
|
dispatch={this.props.dispatch}
|
||||||
apiFirmwareValue={this.props.apiFirmwareValue}
|
apiFirmwareValue={this.props.apiFirmwareValue}
|
||||||
timeSettings={this.props.timeSettings} />
|
timeSettings={this.props.timeSettings}
|
||||||
|
findApiAlertById={this.props.findApiAlertById} />
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<div className="link-to-logs">
|
<div className="link-to-logs">
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { FirmwareHardware, Enigma } from "farmbot";
|
import { FirmwareHardware, Enigma } from "farmbot";
|
||||||
import { TimeSettings } from "../interfaces";
|
import { TimeSettings } from "../interfaces";
|
||||||
import { BotState } from "../devices/interfaces";
|
import { BotState } from "../devices/interfaces";
|
||||||
|
import { UUID } from "../resources/interfaces";
|
||||||
|
|
||||||
export interface MessagesProps {
|
export interface MessagesProps {
|
||||||
alerts: Alert[];
|
alerts: Alert[];
|
||||||
apiFirmwareValue: FirmwareHardware | undefined;
|
apiFirmwareValue: FirmwareHardware | undefined;
|
||||||
timeSettings: TimeSettings;
|
timeSettings: TimeSettings;
|
||||||
dispatch: Function;
|
dispatch: Function;
|
||||||
|
findApiAlertById(id: number): UUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AlertsProps {
|
export interface AlertsProps {
|
||||||
|
@ -14,6 +16,7 @@ export interface AlertsProps {
|
||||||
apiFirmwareValue: string | undefined;
|
apiFirmwareValue: string | undefined;
|
||||||
timeSettings: TimeSettings;
|
timeSettings: TimeSettings;
|
||||||
dispatch: Function;
|
dispatch: Function;
|
||||||
|
findApiAlertById(id: number): UUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProblemTag {
|
export interface ProblemTag {
|
||||||
|
@ -36,11 +39,14 @@ export interface AlertCardProps {
|
||||||
apiFirmwareValue: string | undefined;
|
apiFirmwareValue: string | undefined;
|
||||||
timeSettings: TimeSettings;
|
timeSettings: TimeSettings;
|
||||||
dispatch: Function;
|
dispatch: Function;
|
||||||
|
findApiAlertById?(id: number): UUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommonAlertCardProps {
|
export interface CommonAlertCardProps {
|
||||||
alert: Alert;
|
alert: Alert;
|
||||||
timeSettings: TimeSettings;
|
timeSettings: TimeSettings;
|
||||||
|
findApiAlertById?(id: number): UUID;
|
||||||
|
dispatch?: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AlertCardTemplateProps {
|
export interface AlertCardTemplateProps {
|
||||||
|
@ -50,6 +56,14 @@ export interface AlertCardTemplateProps {
|
||||||
message: string;
|
message: string;
|
||||||
timeSettings: TimeSettings;
|
timeSettings: TimeSettings;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
|
findApiAlertById?(id: number): UUID;
|
||||||
|
dispatch?: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DismissAlertProps {
|
||||||
|
id?: number;
|
||||||
|
findApiAlertById?(id: number): UUID;
|
||||||
|
dispatch?: Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FirmwareMissingProps extends CommonAlertCardProps {
|
export interface FirmwareMissingProps extends CommonAlertCardProps {
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
import { Everything } from "../interfaces";
|
import { Everything } from "../interfaces";
|
||||||
import { MessagesProps } from "./interfaces";
|
import { MessagesProps, Alert } from "./interfaces";
|
||||||
import { validFbosConfig, betterCompact } from "../util";
|
import { validFbosConfig, betterCompact } from "../util";
|
||||||
import { getFbosConfig } from "../resources/getters";
|
import { getFbosConfig } from "../resources/getters";
|
||||||
import { sourceFbosConfigValue } from "../devices/components/source_config_value";
|
import { sourceFbosConfigValue } from "../devices/components/source_config_value";
|
||||||
import { DevSettings } from "../account/dev/dev_support";
|
import { DevSettings } from "../account/dev/dev_support";
|
||||||
import { selectAllEnigmas, maybeGetTimeSettings } from "../resources/selectors";
|
import {
|
||||||
|
selectAllEnigmas, maybeGetTimeSettings, findResourceById
|
||||||
|
} from "../resources/selectors";
|
||||||
import { isFwHardwareValue } from "../devices/components/fbos_settings/board_type";
|
import { isFwHardwareValue } from "../devices/components/fbos_settings/board_type";
|
||||||
|
import { ResourceIndex, UUID } from "../resources/interfaces";
|
||||||
|
import { BotState } from "../devices/interfaces";
|
||||||
|
|
||||||
export const mapStateToProps = (props: Everything): MessagesProps => {
|
export const mapStateToProps = (props: Everything): MessagesProps => {
|
||||||
const { hardware } = props.bot;
|
const { hardware } = props.bot;
|
||||||
|
@ -13,15 +17,23 @@ export const mapStateToProps = (props: Everything): MessagesProps => {
|
||||||
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 findApiAlertById = (id: number): UUID =>
|
||||||
const apiAlerts = selectAllEnigmas(props.resources.index).map(x => x.body);
|
findResourceById(props.resources.index, "Enigma", id);
|
||||||
const alerts =
|
|
||||||
botAlerts.concat(DevSettings.futureFeaturesEnabled() ? apiAlerts : []);
|
|
||||||
return {
|
return {
|
||||||
alerts,
|
alerts: getAlerts(props.resources.index, props.bot),
|
||||||
apiFirmwareValue: isFwHardwareValue(apiFirmwareValue)
|
apiFirmwareValue: isFwHardwareValue(apiFirmwareValue)
|
||||||
? apiFirmwareValue : undefined,
|
? apiFirmwareValue : undefined,
|
||||||
timeSettings: maybeGetTimeSettings(props.resources.index),
|
timeSettings: maybeGetTimeSettings(props.resources.index),
|
||||||
dispatch: props.dispatch,
|
dispatch: props.dispatch,
|
||||||
|
findApiAlertById,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getAlerts =
|
||||||
|
(resourceIndex: ResourceIndex, bot: BotState): Alert[] => {
|
||||||
|
const botAlerts = betterCompact(Object.values(bot.hardware.enigmas || {}));
|
||||||
|
const apiAlerts = selectAllEnigmas(resourceIndex).map(x => x.body)
|
||||||
|
.filter(x => DevSettings.futureFeaturesEnabled() ||
|
||||||
|
x.problem_tag !== "api.seed_data.missing");
|
||||||
|
return botAlerts.concat(apiAlerts);
|
||||||
|
};
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import { stopIE } from "../stop_ie";
|
|
||||||
|
|
||||||
describe("stopIE()", () => {
|
|
||||||
it("not IE", () => {
|
|
||||||
expect(stopIE).not.toThrow();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { updatePageInfo, attachToRoot } from "../page";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
describe("updatePageInfo()", () => {
|
||||||
|
it("sets page title", () => {
|
||||||
|
updatePageInfo("page name");
|
||||||
|
expect(document.title).toEqual("Page name - FarmBot");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets page title: Farm Designer", () => {
|
||||||
|
updatePageInfo("designer");
|
||||||
|
expect(document.title).toEqual("Farm designer - FarmBot");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("attachToRoot()", () => {
|
||||||
|
class Foo extends React.Component<{ text: string }> {
|
||||||
|
render() { return <p>{this.props.text}</p>; }
|
||||||
|
}
|
||||||
|
it("attaches page", () => {
|
||||||
|
attachToRoot(Foo, { text: "Bar" });
|
||||||
|
expect(document.body.innerHTML).toEqual(`<div id="root"><p>Bar</p></div>`);
|
||||||
|
expect(document.body.textContent).toEqual("Bar");
|
||||||
|
});
|
||||||
|
});
|
|
@ -4,14 +4,13 @@ import {
|
||||||
Attributes
|
Attributes
|
||||||
} from "react";
|
} from "react";
|
||||||
import { render } from "react-dom";
|
import { render } from "react-dom";
|
||||||
|
|
||||||
import { capitalize } from "lodash";
|
import { capitalize } from "lodash";
|
||||||
import { t } from "../i18next_wrapper";
|
import { t } from "../i18next_wrapper";
|
||||||
|
|
||||||
/** Dynamically change the meta title of the page. */
|
/** Dynamically change the meta title of the page. */
|
||||||
export function updatePageInfo(pageName: string) {
|
export function updatePageInfo(pageName: string) {
|
||||||
if (pageName === "designer") { pageName = "Farm Designer"; }
|
if (pageName === "designer") { pageName = "Farm Designer"; }
|
||||||
document.title = t(capitalize(pageName));
|
document.title = `${t(capitalize(pageName))} - FarmBot`;
|
||||||
// Possibly add meta "content" here dynamically as well
|
// Possibly add meta "content" here dynamically as well
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue