update os update button

pull/647/head
gabrielburnworth 2018-01-28 13:00:16 -08:00
parent 2765d345ac
commit 6203326734
9 changed files with 115 additions and 44 deletions

View File

@ -262,19 +262,21 @@ describe("fetchReleases()", () => {
expect(axios.get).toHaveBeenCalledWith("url");
expect(mockError).not.toHaveBeenCalled();
expect(dispatch).toHaveBeenCalledWith({
payload: "1.0.0",
payload: { version: "1.0.0", commit: undefined },
type: Actions.FETCH_OS_UPDATE_INFO_OK
});
});
it("fetches latest beta OS release version", async () => {
mockGetRelease = Promise.resolve({ data: { tag_name: "v1.0.0-beta" } });
mockGetRelease = Promise.resolve({
data: { tag_name: "v1.0.0-beta", target_commitish: "commit" }
});
const dispatch = jest.fn();
await actions.fetchReleases("url", { beta: true })(dispatch, jest.fn());
expect(axios.get).toHaveBeenCalledWith("url");
expect(mockError).not.toHaveBeenCalled();
expect(dispatch).toHaveBeenCalledWith({
payload: "1.0.0-beta",
payload: { version: "1.0.0-beta", commit: "commit" },
type: Actions.FETCH_BETA_OS_UPDATE_INFO_OK
});
});

View File

@ -66,7 +66,7 @@ describe("botRedcuer", () => {
it("fetches OS update info", () => {
const r = botReducer(initialState(), {
type: Actions.FETCH_OS_UPDATE_INFO_OK,
payload: "1.2.3"
payload: { version: "1.2.3", commit: undefined }
}).currentOSVersion;
expect(r).toBe("1.2.3");
});

View File

@ -143,13 +143,13 @@ export let fetchReleases =
axios
.get(url)
.then((resp: HttpData<GithubRelease>) => {
const version = resp.data.tag_name;
const versionWithoutV = version.toLowerCase().replace("v", "");
const { tag_name, target_commitish } = resp.data;
const version = tag_name.toLowerCase().replace("v", "");
dispatch({
type: options.beta
? Actions.FETCH_BETA_OS_UPDATE_INFO_OK
: Actions.FETCH_OS_UPDATE_INFO_OK,
payload: versionWithoutV
payload: { version, commit: target_commitish }
});
})
.catch((ferror) => {

View File

@ -12,6 +12,7 @@ import * as React from "react";
import { mount } from "enzyme";
import { bot } from "../../../../__test_support__/fake_state/bot";
import { OsUpdateButton } from "../os_update_button";
import { OsUpdateButtonProps } from "../interfaces";
describe("<OsUpdateButton/>", () => {
beforeEach(function () {
@ -19,17 +20,37 @@ describe("<OsUpdateButton/>", () => {
bot.hardware.configuration.beta_opt_in = false;
jest.clearAllMocks();
});
const fakeProps = (): OsUpdateButtonProps => {
return {
bot,
sourceFbosConfig: (x) => {
return { value: bot.hardware.configuration[x], consistent: true };
}
};
};
it("renders buttons: not connected", () => {
const buttons = mount(<OsUpdateButton bot={bot} />);
bot.currentOSVersion = undefined;
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
expect(buttons.find("button").length).toBe(1);
const autoUpdate = buttons.find("button").first();
expect(autoUpdate.hasClass("yellow")).toBeTruthy();
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("Can't Connect to release server");
expect(osUpdateButton.text()).toBe("Can't connect to release server");
});
it("renders buttons: not connected to bot", () => {
bot.hardware.informational_settings.controller_version = undefined;
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
expect(buttons.find("button").length).toBe(1);
const autoUpdate = buttons.find("button").first();
expect(autoUpdate.hasClass("yellow")).toBeTruthy();
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("Can't connect to bot");
});
it("renders buttons: no beta releases", () => {
bot.hardware.configuration.beta_opt_in = true;
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
expect(buttons.find("button").length).toBe(1);
const autoUpdate = buttons.find("button").first();
expect(autoUpdate.hasClass("yellow")).toBeTruthy();
@ -38,21 +59,21 @@ describe("<OsUpdateButton/>", () => {
});
it("up to date", () => {
bot.hardware.informational_settings.controller_version = "3.1.6";
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("UP TO DATE");
expect(osUpdateButton.props().title).toBe("3.1.6");
});
it("up to date: newer", () => {
bot.hardware.informational_settings.controller_version = "5.0.0";
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("UP TO DATE");
expect(osUpdateButton.props().title).toBe("3.1.6");
});
it("update available", () => {
bot.hardware.informational_settings.controller_version = "3.1.5";
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("UPDATE");
expect(osUpdateButton.props().title).toBe("3.1.6");
@ -61,13 +82,24 @@ describe("<OsUpdateButton/>", () => {
bot.hardware.informational_settings.controller_version = "3.1.5";
bot.hardware.configuration.beta_opt_in = true;
bot.currentBetaOSVersion = "5.0.0-beta";
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("UPDATE");
expect(osUpdateButton.props().title).toBe("5.0.0-beta");
});
it("beta update has same numeric version: newer commit", () => {
bot.hardware.informational_settings.controller_version = "5.0.0";
bot.hardware.informational_settings.commit = "old commit";
bot.hardware.configuration.beta_opt_in = true;
bot.currentBetaOSVersion = "5.0.0-beta";
bot.currentBetaOSCommit = "new commit";
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("UPDATE");
expect(osUpdateButton.props().title).toBe("5.0.0-beta");
});
it("calls checkUpdates", () => {
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
osUpdateButton.simulate("click");
expect(mockDevice.checkUpdates).toHaveBeenCalledTimes(1);
@ -78,7 +110,7 @@ describe("<OsUpdateButton/>", () => {
bot.hardware.jobs = {
"FBOS_OTA": { status: "working", bytes: progress, unit: "bytes" }
};
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe(text);
});
@ -91,7 +123,7 @@ describe("<OsUpdateButton/>", () => {
bot.hardware.jobs = {
"FBOS_OTA": { status: "working", percent: 10, unit: "percent" }
};
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("10%");
});
@ -100,7 +132,7 @@ describe("<OsUpdateButton/>", () => {
"FBOS_OTA": { status: "complete", percent: 100, unit: "percent" }
};
bot.hardware.informational_settings.controller_version = "3.1.6";
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("UP TO DATE");
});
@ -109,7 +141,7 @@ describe("<OsUpdateButton/>", () => {
"FBOS_OTA": { status: "error", percent: 10, unit: "percent" }
};
bot.hardware.informational_settings.controller_version = "3.1.5";
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
expect(osUpdateButton.text()).toBe("UPDATE");
});
@ -117,7 +149,7 @@ describe("<OsUpdateButton/>", () => {
bot.hardware.jobs = {
"FBOS_OTA": { status: "working", percent: 10, unit: "percent" }
};
const buttons = mount(<OsUpdateButton bot={bot} />);
const buttons = mount(<OsUpdateButton {...fakeProps() } />);
const osUpdateButton = buttons.find("button").last();
osUpdateButton.simulate("click");
expect(mockDevice.checkUpdates).not.toHaveBeenCalled();

View File

@ -74,7 +74,7 @@ export function FarmbotOsRow(props: FarmbotOsRowProps) {
</Popover>
</Col>
<Col xs={3}>
<OsUpdateButton bot={bot} />
<OsUpdateButton bot={bot} sourceFbosConfig={sourceFbosConfig} />
</Col>
</Row >;
}

View File

@ -40,3 +40,8 @@ export interface FbosDetailsProps {
dispatch: Function;
sourceFbosConfig: SourceFbosConfig;
}
export interface OsUpdateButtonProps {
bot: BotState;
sourceFbosConfig: SourceFbosConfig;
}

View File

@ -3,16 +3,34 @@ import { t } from "i18next";
import * as _ from "lodash";
import { JobProgress } from "farmbot/dist";
import { SemverResult, semverCompare } from "../../../util";
import { BotProp } from "../../interfaces";
import { OsUpdateButtonProps } from "./interfaces";
import { checkControllerUpdates } from "../../actions";
export let OsUpdateButton = ({ bot }: BotProp) => {
let buttonStr = "Can't Connect to bot";
let buttonColor = "yellow";
enum UpdateButton { upToDate, needsUpdate, unknown, unknownBeta, none }
const { beta_opt_in } = bot.hardware.configuration;
const { currentOSVersion, currentBetaOSVersion } = bot;
const latestReleaseV = beta_opt_in
const buttonProps = (status: UpdateButton) => {
switch (status) {
case UpdateButton.needsUpdate:
return { color: "green", text: t("UPDATE") };
case UpdateButton.upToDate:
return { color: "gray", text: t("UP TO DATE") };
case UpdateButton.unknownBeta:
return { color: "yellow", text: t("No beta releases available") };
case UpdateButton.unknown:
return { color: "yellow", text: t("Can't connect to release server") };
default:
return { color: "yellow", text: t("Can't connect to bot") };
}
};
export let OsUpdateButton = (props: OsUpdateButtonProps) => {
const { bot, sourceFbosConfig } = props;
let buttonStatus = UpdateButton.none;
const betaOptIn = sourceFbosConfig("beta_opt_in").value;
const { currentOSVersion, currentBetaOSVersion, currentBetaOSCommit } = bot;
const { commit } = bot.hardware.informational_settings;
const latestReleaseV = betaOptIn
? currentBetaOSVersion
: currentOSVersion;
const { controller_version } = bot.hardware.informational_settings;
@ -20,17 +38,22 @@ export let OsUpdateButton = ({ bot }: BotProp) => {
switch (semverCompare(latestReleaseV, controller_version)) {
case SemverResult.RIGHT_IS_GREATER:
case SemverResult.EQUAL:
buttonStr = t("UP TO DATE");
buttonColor = "gray";
buttonStatus = UpdateButton.upToDate;
break;
default:
buttonStr = t("UPDATE");
buttonColor = "green";
buttonStatus = UpdateButton.needsUpdate;
}
} else {
buttonStr = beta_opt_in
? "No beta releases available"
: "Can't Connect to release server";
if (!_.isString(latestReleaseV)) {
buttonStatus = betaOptIn
? UpdateButton.unknownBeta
: UpdateButton.unknown;
}
}
if (betaOptIn
&& _.isString(commit) && _.isString(currentBetaOSCommit)
&& commit !== currentBetaOSCommit) {
buttonStatus = UpdateButton.needsUpdate;
}
const osUpdateJob = (bot.hardware.jobs || {})["FBOS_OTA"];
@ -58,10 +81,10 @@ export let OsUpdateButton = ({ bot }: BotProp) => {
}
return <button
className={"fb-button " + buttonColor}
className={"fb-button " + buttonProps(buttonStatus).color}
title={latestReleaseV}
disabled={isWorking(osUpdateJob)}
onClick={() => checkControllerUpdates()}>
{downloadProgress(osUpdateJob) || buttonStr}
{downloadProgress(osUpdateJob) || buttonProps(buttonStatus).text}
</button>;
};

View File

@ -62,6 +62,8 @@ export interface BotState {
currentOSVersion?: string;
/** The current beta os version on the github release api */
currentBetaOSVersion?: string;
/** The current beta os commit on the github release api */
currentBetaOSCommit?: string;
/** Is the bot in sync with the api */
dirty: boolean;
/** The state of the bot, as reported by the bot over MQTT. */
@ -76,13 +78,17 @@ export interface BotState {
connectivity: ConnectionState;
}
export interface BotProp { bot: BotState; }
/** Status registers for the bot's status */
export type HardwareState = BotStateTree;
export interface GithubRelease {
tag_name: string;
target_commitish: string;
}
export interface OsUpdateInfo {
version: string;
commit: string;
}
export interface MoveRelProps {

View File

@ -1,4 +1,6 @@
import { BotState, HardwareState, Xyz, ControlPanelState } from "./interfaces";
import {
BotState, HardwareState, Xyz, ControlPanelState, OsUpdateInfo
} from "./interfaces";
import { generateReducer } from "../redux/generate_reducer";
import { Actions } from "../constants";
import { EncoderDisplay } from "../controls/interfaces";
@ -144,12 +146,13 @@ export let botReducer = generateReducer<BotState>(initialState(), afterEach)
s.controlPanelState.danger_zone = a.payload;
return s;
})
.add<string>(Actions.FETCH_OS_UPDATE_INFO_OK, (s, { payload }) => {
s.currentOSVersion = payload;
.add<OsUpdateInfo>(Actions.FETCH_OS_UPDATE_INFO_OK, (s, { payload }) => {
s.currentOSVersion = payload.version;
return s;
})
.add<string>(Actions.FETCH_BETA_OS_UPDATE_INFO_OK, (s, { payload }) => {
s.currentBetaOSVersion = payload;
.add<OsUpdateInfo>(Actions.FETCH_BETA_OS_UPDATE_INFO_OK, (s, { payload }) => {
s.currentBetaOSVersion = payload.version;
s.currentBetaOSCommit = payload.commit;
return s;
})
.add<HardwareState>(Actions.BOT_CHANGE, (state, { payload }) => {