Done: Start at midnight, disable dropdown if not auto-updating, move OTA selector to device pane. TODO: Use user-selected hour format (24 v. 12h format)
parent
19a6cabf70
commit
de7af7c867
|
@ -52,7 +52,7 @@ describe("<FarmbotOsSettings />", () => {
|
|||
it("renders settings", () => {
|
||||
const osSettings = mount(<FarmbotOsSettings {...fakeProps()} />);
|
||||
expect(osSettings.find("input").length).toBe(1);
|
||||
expect(osSettings.find("button").length).toBe(6);
|
||||
expect(osSettings.find("button").length).toBe(7);
|
||||
["NAME", "TIME ZONE", "FARMBOT OS", "CAMERA", "FIRMWARE"]
|
||||
.map(string => expect(osSettings.text()).toContain(string));
|
||||
});
|
||||
|
|
|
@ -121,25 +121,6 @@ export class FarmbotOsSettings
|
|||
networkState={this.props.botToMqttStatus}
|
||||
lockOpen={process.env.NODE_ENV !== "production"
|
||||
|| this.props.isValidFbosConfig}>
|
||||
<FarmbotOsRow
|
||||
bot={this.props.bot}
|
||||
osReleaseNotesHeading={this.osReleaseNotes.heading}
|
||||
osReleaseNotes={this.osReleaseNotes.notes}
|
||||
dispatch={this.props.dispatch}
|
||||
sourceFbosConfig={sourceFbosConfig}
|
||||
shouldDisplay={this.props.shouldDisplay}
|
||||
botOnline={botOnline}
|
||||
botToMqttLastSeen={new Date(this.props.botToMqttLastSeen).getTime()}
|
||||
timeSettings={this.props.timeSettings}
|
||||
deviceAccount={this.props.deviceAccount} />
|
||||
<AutoUpdateRow
|
||||
dispatch={this.props.dispatch}
|
||||
sourceFbosConfig={sourceFbosConfig} />
|
||||
{(location.host.includes("localhost")
|
||||
|| !isUndefined(sourceFbosConfig("auto_sync").value)) &&
|
||||
<AutoSyncRow
|
||||
dispatch={this.props.dispatch}
|
||||
sourceFbosConfig={sourceFbosConfig} />}
|
||||
<CameraSelection
|
||||
env={this.props.env}
|
||||
botOnline={botOnline}
|
||||
|
@ -154,6 +135,26 @@ export class FarmbotOsSettings
|
|||
shouldDisplay={this.props.shouldDisplay}
|
||||
timeSettings={this.props.timeSettings}
|
||||
sourceFbosConfig={sourceFbosConfig} />
|
||||
<AutoUpdateRow
|
||||
device={this.props.deviceAccount}
|
||||
dispatch={this.props.dispatch}
|
||||
sourceFbosConfig={sourceFbosConfig} />
|
||||
<FarmbotOsRow
|
||||
bot={this.props.bot}
|
||||
osReleaseNotesHeading={this.osReleaseNotes.heading}
|
||||
osReleaseNotes={this.osReleaseNotes.notes}
|
||||
dispatch={this.props.dispatch}
|
||||
sourceFbosConfig={sourceFbosConfig}
|
||||
shouldDisplay={this.props.shouldDisplay}
|
||||
botOnline={botOnline}
|
||||
botToMqttLastSeen={new Date(this.props.botToMqttLastSeen).getTime()}
|
||||
timeSettings={this.props.timeSettings}
|
||||
deviceAccount={this.props.deviceAccount} />
|
||||
{(location.host.includes("localhost")
|
||||
|| !isUndefined(sourceFbosConfig("auto_sync").value)) &&
|
||||
<AutoSyncRow
|
||||
dispatch={this.props.dispatch}
|
||||
sourceFbosConfig={sourceFbosConfig} />}
|
||||
{this.props.shouldDisplay(Feature.boot_sequence) &&
|
||||
<BootSequenceSelector />}
|
||||
<PowerAndReset
|
||||
|
|
|
@ -11,7 +11,7 @@ import { fakeState } from "../../../../__test_support__/fake_state";
|
|||
import { edit, save } from "../../../../api/crud";
|
||||
import { fakeFbosConfig } from "../../../../__test_support__/fake_state/resources";
|
||||
import {
|
||||
buildResourceIndex
|
||||
buildResourceIndex, fakeDevice
|
||||
} from "../../../../__test_support__/resource_index_builder";
|
||||
|
||||
describe("<AutoUpdateRow/>", () => {
|
||||
|
@ -20,6 +20,7 @@ describe("<AutoUpdateRow/>", () => {
|
|||
state.resources = buildResourceIndex([fakeConfig]);
|
||||
|
||||
const fakeProps = (): AutoUpdateRowProps => ({
|
||||
device: fakeDevice(),
|
||||
dispatch: jest.fn(x => x(jest.fn(), () => state)),
|
||||
sourceFbosConfig: () => ({ value: 1, consistent: true })
|
||||
});
|
||||
|
@ -33,7 +34,7 @@ describe("<AutoUpdateRow/>", () => {
|
|||
const p = fakeProps();
|
||||
p.sourceFbosConfig = () => ({ value: 0, consistent: true });
|
||||
const wrapper = mount(<AutoUpdateRow {...p} />);
|
||||
wrapper.find("button").first().simulate("click");
|
||||
wrapper.find("button").at(1).simulate("click");
|
||||
expect(edit).toHaveBeenCalledWith(fakeConfig, { os_auto_update: true });
|
||||
expect(save).toHaveBeenCalledWith(fakeConfig.uuid);
|
||||
});
|
||||
|
@ -42,7 +43,7 @@ describe("<AutoUpdateRow/>", () => {
|
|||
const p = fakeProps();
|
||||
p.sourceFbosConfig = () => ({ value: 1, consistent: true });
|
||||
const wrapper = mount(<AutoUpdateRow {...p} />);
|
||||
wrapper.find("button").first().simulate("click");
|
||||
wrapper.find("button").at(1).simulate("click");
|
||||
expect(edit).toHaveBeenCalledWith(fakeConfig, { os_auto_update: false });
|
||||
expect(save).toHaveBeenCalledWith(fakeConfig.uuid);
|
||||
});
|
||||
|
|
|
@ -6,26 +6,33 @@ import { updateConfig } from "../../actions";
|
|||
import { Content } from "../../../constants";
|
||||
import { AutoUpdateRowProps } from "./interfaces";
|
||||
import { t } from "../../../i18next_wrapper";
|
||||
import { OtaTimeSelector, changeOtaHour } from "./ota_time_selector";
|
||||
|
||||
export function AutoUpdateRow(props: AutoUpdateRowProps) {
|
||||
const osAutoUpdate = props.sourceFbosConfig("os_auto_update");
|
||||
return <Row>
|
||||
<Col xs={ColWidth.label}>
|
||||
<label>
|
||||
{t("FARMBOT OS AUTO UPDATE")}
|
||||
</label>
|
||||
</Col>
|
||||
<Col xs={ColWidth.description}>
|
||||
<p>
|
||||
{t(Content.OS_AUTO_UPDATE)}
|
||||
</p>
|
||||
</Col>
|
||||
<Col xs={ColWidth.button}>
|
||||
<ToggleButton toggleValue={osAutoUpdate.value}
|
||||
dim={!osAutoUpdate.consistent}
|
||||
toggleAction={() => props.dispatch(updateConfig({
|
||||
os_auto_update: !osAutoUpdate.value
|
||||
}))} />
|
||||
</Col>
|
||||
</Row>;
|
||||
return <div>
|
||||
<OtaTimeSelector
|
||||
disabled={!osAutoUpdate.value}
|
||||
value={props.device.body.ota_hour}
|
||||
onChange={changeOtaHour(props.dispatch, props.device)} />
|
||||
<Row>
|
||||
<Col xs={ColWidth.label}>
|
||||
<label>
|
||||
{t("FARMBOT OS AUTO UPDATE")}
|
||||
</label>
|
||||
</Col>
|
||||
<Col xs={ColWidth.description}>
|
||||
<p>
|
||||
{t(Content.OS_AUTO_UPDATE)}
|
||||
</p>
|
||||
</Col>
|
||||
<Col xs={ColWidth.button}>
|
||||
<ToggleButton toggleValue={osAutoUpdate.value}
|
||||
dim={!osAutoUpdate.consistent}
|
||||
toggleAction={() => props.dispatch(updateConfig({
|
||||
os_auto_update: !osAutoUpdate.value
|
||||
}))} />
|
||||
</Col>
|
||||
</Row>
|
||||
</div>;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import moment from "moment";
|
|||
import { timeFormatString } from "../../../util";
|
||||
import { TimeSettings } from "../../../interfaces";
|
||||
import { StringConfigKey } from "farmbot/dist/resources/configs/fbos";
|
||||
import { OtaTimeSelector, changeOtaHour } from "./ota_time_selector";
|
||||
|
||||
/** Return an indicator color for the given temperature (C). */
|
||||
export const colorFromTemp = (temp: number | undefined): string => {
|
||||
|
@ -280,9 +279,6 @@ export function FbosDetails(props: FbosDetailsProps) {
|
|||
<VoltageDisplay chip={target} throttled={throttled} />
|
||||
<BetaReleaseOptIn
|
||||
dispatch={props.dispatch} sourceFbosConfig={props.sourceFbosConfig} />
|
||||
<OtaTimeSelector
|
||||
onChange={changeOtaHour(props.dispatch, props.deviceAccount)}
|
||||
value={props.deviceAccount.body.ota_hour} />
|
||||
{last_ota_checkup && <p><b>{t("Last checked for updates")}: </b>
|
||||
{reformatDatetime(last_ota_checkup, props.timeSettings)}</p>}
|
||||
{last_ota && <p><b>{t("Last updated")}: </b>
|
||||
|
|
|
@ -13,6 +13,7 @@ export interface AutoSyncRowProps {
|
|||
export interface AutoUpdateRowProps {
|
||||
dispatch: Function;
|
||||
sourceFbosConfig: SourceFbosConfig;
|
||||
device: TaggedDevice;
|
||||
}
|
||||
|
||||
export interface CameraSelectionProps {
|
||||
|
|
|
@ -7,14 +7,20 @@ import { fakeDevice } from "../../../../../__test_support__/resource_index_build
|
|||
describe("OTA time selector", () => {
|
||||
it("selects an OTA update time", () => {
|
||||
const onUpdate = jest.fn();
|
||||
const el = shallow(<OtaTimeSelector onChange={onUpdate} value={3} />);
|
||||
const el = shallow(<OtaTimeSelector
|
||||
disabled={false}
|
||||
onChange={onUpdate}
|
||||
value={3} />);
|
||||
el.find(FBSelect).simulate("change", { label: "at 5 PM", value: 17 });
|
||||
expect(onUpdate).toHaveBeenCalledWith(17);
|
||||
});
|
||||
|
||||
it("unselects an OTA update time", () => {
|
||||
const onUpdate = jest.fn();
|
||||
const el = shallow(<OtaTimeSelector onChange={onUpdate} value={3} />);
|
||||
const el = shallow(<OtaTimeSelector
|
||||
disabled={false}
|
||||
onChange={onUpdate}
|
||||
value={3} />);
|
||||
el.find(FBSelect).simulate("change", { label: "no", value: -1 });
|
||||
// tslint:disable-next-line:no-null-keyword
|
||||
expect(onUpdate).toHaveBeenCalledWith(null);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { DropDownItem, FBSelect } from "../../../../ui";
|
||||
import { DropDownItem, FBSelect, Row, Col } from "../../../../ui";
|
||||
import React from "react";
|
||||
import { t } from "../../../../i18next_wrapper";
|
||||
import { TaggedDevice } from "farmbot";
|
||||
import { edit, save } from "../../../../api/crud";
|
||||
import { ColWidth } from "../../farmbot_os_settings";
|
||||
|
||||
const IMMEDIATELY = -1;
|
||||
|
||||
|
@ -40,6 +41,7 @@ const OTA_TIMES: Record<number, DropDownItem> = {
|
|||
const DEFAULT_HOUR = OTA_TIMES[IMMEDIATELY];
|
||||
|
||||
interface OtaTimeSelectorProps {
|
||||
disabled: boolean;
|
||||
onChange(hour24: number | undefined): void;
|
||||
value: number | undefined;
|
||||
}
|
||||
|
@ -51,7 +53,8 @@ export const changeOtaHour =
|
|||
dispatch(save(device.uuid));
|
||||
};
|
||||
/** Label and toggle button for opting in to FBOS beta releases. */
|
||||
export const OtaTimeSelector = ({ onChange, value }: OtaTimeSelectorProps): JSX.Element => {
|
||||
export const OtaTimeSelector = (props: OtaTimeSelectorProps): JSX.Element => {
|
||||
const { onChange, value, disabled } = props;
|
||||
const cb = (ddi: DropDownItem) => {
|
||||
const v = parseInt("" + ddi.value, 10);
|
||||
if ((v == IMMEDIATELY)) {
|
||||
|
@ -63,16 +66,20 @@ export const OtaTimeSelector = ({ onChange, value }: OtaTimeSelectorProps): JSX.
|
|||
|
||||
const list = Object
|
||||
.values(OTA_TIMES)
|
||||
.reverse()
|
||||
.map(x => ({ ...x, label: t(x.label) }));
|
||||
|
||||
return <fieldset className={"os-release-channel"}>
|
||||
<label>
|
||||
{t("Apply Software Updates ")}
|
||||
</label>
|
||||
<FBSelect
|
||||
selectedItem={value ? OTA_TIMES[value] : DEFAULT_HOUR}
|
||||
onChange={cb}
|
||||
list={list} />
|
||||
</fieldset>;
|
||||
return <Row>
|
||||
<Col xs={ColWidth.label}>
|
||||
<label>
|
||||
{t("Apply Software Updates ")}
|
||||
</label>
|
||||
</Col>
|
||||
<Col xs={ColWidth.description}>
|
||||
<FBSelect
|
||||
selectedItem={value ? OTA_TIMES[value] : DEFAULT_HOUR}
|
||||
onChange={cb}
|
||||
list={list}
|
||||
extraClass={disabled ? "disabled" : ""} />
|
||||
</Col>
|
||||
</Row>;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue