Farmbot-Web-App/frontend/devices/components/fbos_settings/os_update_button.tsx

177 lines
6.4 KiB
TypeScript
Raw Normal View History

2017-06-29 12:54:02 -06:00
import * as React from "react";
2019-01-04 12:26:31 -07:00
import { JobProgress, ConfigurationName } from "farmbot/dist";
2017-11-09 09:45:11 -07:00
import { SemverResult, semverCompare } from "../../../util";
2018-01-28 14:00:16 -07:00
import { OsUpdateButtonProps } from "./interfaces";
2018-01-11 23:18:26 -07:00
import { checkControllerUpdates } from "../../actions";
2018-07-27 15:20:06 -06:00
import { isString } from "lodash";
2020-04-23 13:11:25 -06:00
import { BotState } from "../../interfaces";
2019-03-11 20:48:12 -06:00
import { Content } from "../../../constants";
2019-04-02 13:59:37 -06:00
import { t } from "../../../i18next_wrapper";
2017-06-29 12:54:02 -06:00
2018-07-27 15:20:06 -06:00
/** FBOS update button states. */
enum UpdateButton { upToDate, needsUpdate, unknown, none }
2018-01-10 17:37:36 -07:00
2018-09-10 14:20:00 -06:00
interface ButtonProps {
color: "green" | "gray" | "yellow";
text: string;
hoverText: string | undefined;
}
2018-07-27 15:20:06 -06:00
/** FBOS update button state => props. */
2018-09-10 14:20:00 -06:00
const buttonProps =
(status: UpdateButton, hoverText: string | undefined): ButtonProps => {
switch (status) {
case UpdateButton.needsUpdate:
return { color: "green", text: t("UPDATE"), hoverText };
case UpdateButton.upToDate:
return { color: "gray", text: t("UP TO DATE"), hoverText };
case UpdateButton.unknown:
const text = t("Can't connect to release server");
return { color: "yellow", text, hoverText };
default:
return { color: "yellow", text: t("Can't connect to bot"), hoverText };
}
};
2018-01-28 14:00:16 -07:00
2018-07-27 15:20:06 -06:00
/** FBOS update download in progress. */
const isWorking = (job: JobProgress | undefined) =>
job && (job.status == "working");
/** FBOS update download progress. */
export function downloadProgress(job: JobProgress | undefined) {
2018-07-27 15:20:06 -06:00
if (job && isWorking(job)) {
switch (job.unit) {
case "bytes":
const kiloBytes = Math.round(job.bytes / 1024);
const megaBytes = Math.round(job.bytes / 1048576);
if (kiloBytes < 1) {
return job.bytes + "B";
} else if (megaBytes < 1) {
return kiloBytes + "kB";
} else {
return megaBytes + "MB";
}
case "percent":
return job.percent + "%";
}
}
}
/** Determine the latest available version. */
const getLatestVersion = (
currentOSVersion: string | undefined,
currentBetaOSVersion: string | undefined,
2020-02-28 09:35:32 -07:00
betaOptIn: boolean,
2018-07-27 15:20:06 -06:00
): string | undefined => {
if (!betaOptIn) { return currentOSVersion; }
switch (semverCompare(currentOSVersion || "", currentBetaOSVersion || "")) {
case SemverResult.RIGHT_IS_GREATER: return currentBetaOSVersion;
default: return currentOSVersion;
}
};
2018-09-10 14:20:00 -06:00
/** Determine the installed version. */
const getInstalledVersion = (
controllerVersion: string | undefined,
currentlyOnBeta: boolean,
): string | undefined => {
if (!isString(controllerVersion)) { return undefined; }
2019-09-13 12:01:27 -06:00
if (controllerVersion.includes("beta")) { return controllerVersion; }
2018-09-10 14:20:00 -06:00
return currentlyOnBeta ? controllerVersion + "-beta" : controllerVersion;
};
2018-07-27 15:20:06 -06:00
/** Unequal beta commits => needs update. */
const betaCommitsAreEqual = (
fbosCommit: string | undefined,
currentBetaOSCommit: string | undefined): boolean =>
!(isString(fbosCommit) && isString(currentBetaOSCommit)
&& fbosCommit !== currentBetaOSCommit);
/** Determine the FBOS update button state. */
const compareWithBotVersion = (
candidate: string | undefined,
2020-02-28 09:35:32 -07:00
installedVersion: string | undefined,
2018-07-27 15:20:06 -06:00
): UpdateButton => {
2018-09-10 14:20:00 -06:00
if (!isString(installedVersion)) { return UpdateButton.none; }
2018-07-27 15:20:06 -06:00
if (!isString(candidate)) { return UpdateButton.unknown; }
2018-09-10 14:20:00 -06:00
// If all values are known, match comparison result with button state.
switch (semverCompare(candidate, installedVersion)) {
2018-07-27 15:20:06 -06:00
case SemverResult.RIGHT_IS_GREATER:
case SemverResult.EQUAL:
return UpdateButton.upToDate;
default:
return UpdateButton.needsUpdate;
}
};
2018-09-10 14:20:00 -06:00
/** Installed version equal to latest. */
const equalToLatest = (
latest: string | undefined,
2020-02-28 09:35:32 -07:00
installedVersion: string | undefined,
2018-09-10 14:20:00 -06:00
): boolean =>
isString(installedVersion) && isString(latest) &&
semverCompare(installedVersion, latest) === SemverResult.EQUAL;
/** Color, text, and hover text for update button: release version status. */
const buttonVersionStatus =
2020-02-28 09:35:32 -07:00
({ bot, betaOptIn }: { bot: BotState, betaOptIn: boolean }): ButtonProps => {
2018-09-10 14:20:00 -06:00
// Information about available releases.
const { currentOSVersion, currentBetaOSVersion, currentBetaOSCommit } = bot;
// Currently installed FBOS version data.
const botInfo = bot.hardware.informational_settings;
2018-11-26 20:39:35 -07:00
const {
controller_version, commit, currently_on_beta, update_available
2018-11-27 11:55:07 -07:00
} = botInfo;
2018-09-10 14:20:00 -06:00
/** Newest release version, given settings and data available. */
const latestReleaseV =
getLatestVersion(currentOSVersion, currentBetaOSVersion, betaOptIn);
/** Installed version. */
const installedVersion =
getInstalledVersion(controller_version, !!currently_on_beta);
/** FBOS update button status. */
const btnStatus = compareWithBotVersion(latestReleaseV, installedVersion);
/** Beta update special cases. */
const uncertainty = (btnStatus === UpdateButton.upToDate) &&
equalToLatest(latestReleaseV, installedVersion) && betaOptIn;
/** `1.0.0-beta vs 1.0.0-beta`: installed beta is older. */
const oldBetaCommit = (latestReleaseV === currentBetaOSVersion) &&
!betaCommitsAreEqual(commit, currentBetaOSCommit);
2018-11-26 20:39:35 -07:00
/** Button status modification required for release edge cases. */
const updateStatusOverride = update_available
|| (uncertainty && oldBetaCommit);
2018-09-10 14:20:00 -06:00
return buttonProps(
updateStatusOverride ? UpdateButton.needsUpdate : btnStatus,
latestReleaseV);
};
/** Shows update availability or download progress. Updates FBOS on click. */
2018-07-27 15:20:06 -06:00
export const OsUpdateButton = (props: OsUpdateButtonProps) => {
const { bot, sourceFbosConfig, botOnline } = props;
2019-03-11 20:48:12 -06:00
const { controller_version } = bot.hardware.informational_settings;
2018-01-28 14:00:16 -07:00
2018-07-27 15:20:06 -06:00
/** FBOS beta release opt-in setting. */
2020-04-23 13:11:25 -06:00
const betaOptIn =
sourceFbosConfig("update_channel" as ConfigurationName).value !== "stable";
2018-09-10 14:20:00 -06:00
/** FBOS update availability. */
const buttonStatusProps = buttonVersionStatus({ bot, betaOptIn });
2017-08-28 15:28:12 -06:00
2018-07-27 15:20:06 -06:00
/** FBOS update download progress data. */
2017-08-28 15:28:12 -06:00
const osUpdateJob = (bot.hardware.jobs || {})["FBOS_OTA"];
2019-03-11 20:48:12 -06:00
const tooOld = controller_version
&& (semverCompare("6.0.0", controller_version)
=== SemverResult.LEFT_IS_GREATER ? Content.TOO_OLD_TO_UPDATE : undefined);
2018-01-11 23:18:26 -07:00
return <button
2019-03-11 20:48:12 -06:00
className={`fb-button ${tooOld ? "yellow" : buttonStatusProps.color}`}
2018-09-10 14:20:00 -06:00
title={buttonStatusProps.hoverText}
disabled={isWorking(osUpdateJob) || !botOnline}
2018-07-27 15:20:06 -06:00
onClick={checkControllerUpdates}>
2019-03-11 20:48:12 -06:00
{tooOld || downloadProgress(osUpdateJob) || buttonStatusProps.text}
2018-01-11 23:18:26 -07:00
</button>;
2017-06-29 12:54:02 -06:00
};