version updates

pull/1767/head
gabrielburnworth 2020-04-23 12:11:25 -07:00
parent 6213028f0f
commit d3732aed20
9 changed files with 53 additions and 62 deletions

View File

@ -11,12 +11,15 @@ import { OsUpdateButton } from "../os_update_button";
import { OsUpdateButtonProps } from "../interfaces"; import { OsUpdateButtonProps } from "../interfaces";
import { ShouldDisplay } from "../../../interfaces"; import { ShouldDisplay } from "../../../interfaces";
import { Content } from "../../../../constants"; import { Content } from "../../../../constants";
import { ConfigurationName } from "farmbot";
const UPDATE_CHANNEL = "update_channel" as ConfigurationName;
describe("<OsUpdateButton/>", () => { describe("<OsUpdateButton/>", () => {
beforeEach(() => { beforeEach(() => {
bot.currentOSVersion = "6.1.6"; bot.currentOSVersion = "6.1.6";
bot.hardware.informational_settings.controller_version = "6.1.6"; bot.hardware.informational_settings.controller_version = "6.1.6";
bot.hardware.configuration.beta_opt_in = false; (bot.hardware.configuration[UPDATE_CHANNEL] as string) = "stable";
}); });
const fakeProps = (): OsUpdateButtonProps => ({ const fakeProps = (): OsUpdateButtonProps => ({
@ -33,7 +36,6 @@ describe("<OsUpdateButton/>", () => {
availableVersion: string | undefined; availableVersion: string | undefined;
availableBetaVersion: string | undefined; availableBetaVersion: string | undefined;
availableBetaCommit: string | undefined; availableBetaCommit: string | undefined;
betaOptIn: boolean | undefined;
onBeta: boolean | undefined; onBeta: boolean | undefined;
update_available?: boolean | undefined; update_available?: boolean | undefined;
shouldDisplay: ShouldDisplay; shouldDisplay: ShouldDisplay;
@ -46,7 +48,6 @@ describe("<OsUpdateButton/>", () => {
availableVersion: "6.1.6", availableVersion: "6.1.6",
availableBetaVersion: undefined, availableBetaVersion: undefined,
availableBetaCommit: undefined, availableBetaCommit: undefined,
betaOptIn: false,
onBeta: false, onBeta: false,
shouldDisplay: () => false, shouldDisplay: () => false,
update_channel: "stable", update_channel: "stable",
@ -104,7 +105,7 @@ describe("<OsUpdateButton/>", () => {
expected: Results) => { expected: Results) => {
const { const {
installedVersion, installedCommit, onBeta, update_available, installedVersion, installedCommit, onBeta, update_available,
availableVersion, availableBetaVersion, availableBetaCommit, betaOptIn, availableVersion, availableBetaVersion, availableBetaCommit,
shouldDisplay, update_channel, shouldDisplay, update_channel,
} = testProps; } = testProps;
bot.hardware.informational_settings.controller_version = installedVersion; bot.hardware.informational_settings.controller_version = installedVersion;
@ -115,9 +116,7 @@ describe("<OsUpdateButton/>", () => {
bot.currentOSVersion = availableVersion; bot.currentOSVersion = availableVersion;
bot.currentBetaOSVersion = availableBetaVersion; bot.currentBetaOSVersion = availableBetaVersion;
bot.currentBetaOSCommit = availableBetaCommit; bot.currentBetaOSCommit = availableBetaCommit;
bot.hardware.configuration.beta_opt_in = betaOptIn; (bot.hardware.configuration[UPDATE_CHANNEL] as string) = update_channel;
// tslint:disable-next-line:no-any
(bot.hardware.configuration as any).update_channel = update_channel;
const p = fakeProps(); const p = fakeProps();
p.shouldDisplay = shouldDisplay; p.shouldDisplay = shouldDisplay;
@ -156,7 +155,7 @@ describe("<OsUpdateButton/>", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.installedVersion = "6.1.6"; testProps.installedVersion = "6.1.6";
testProps.availableVersion = undefined; testProps.availableVersion = undefined;
testProps.betaOptIn = true; testProps.update_channel = "beta";
const expectedResults = cantConnect("release server"); const expectedResults = cantConnect("release server");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
}); });
@ -166,7 +165,7 @@ describe("<OsUpdateButton/>", () => {
testProps.installedVersion = "6.1.6"; testProps.installedVersion = "6.1.6";
testProps.availableVersion = undefined; testProps.availableVersion = undefined;
testProps.availableBetaVersion = "6.1.7-beta"; testProps.availableBetaVersion = "6.1.7-beta";
testProps.betaOptIn = true; testProps.update_channel = "beta";
const expectedResults = updateNeeded("6.1.7-beta"); const expectedResults = updateNeeded("6.1.7-beta");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
}); });
@ -175,7 +174,7 @@ describe("<OsUpdateButton/>", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.installedVersion = "6.1.6"; testProps.installedVersion = "6.1.6";
testProps.availableBetaVersion = undefined; testProps.availableBetaVersion = undefined;
testProps.betaOptIn = true; testProps.update_channel = "beta";
const expectedResults = upToDate("6.1.6"); const expectedResults = upToDate("6.1.6");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
}); });
@ -205,7 +204,7 @@ describe("<OsUpdateButton/>", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.installedVersion = "6.1.5"; testProps.installedVersion = "6.1.5";
testProps.availableBetaVersion = "7.0.0-beta"; testProps.availableBetaVersion = "7.0.0-beta";
testProps.betaOptIn = true; testProps.update_channel = "beta";
const expectedResults = updateNeeded("7.0.0-beta"); const expectedResults = updateNeeded("7.0.0-beta");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
}); });
@ -214,7 +213,7 @@ describe("<OsUpdateButton/>", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.installedVersion = "6.1.6"; testProps.installedVersion = "6.1.6";
testProps.availableBetaVersion = "6.1.6-beta"; testProps.availableBetaVersion = "6.1.6-beta";
testProps.betaOptIn = true; testProps.update_channel = "beta";
const expectedResults = upToDate("6.1.6"); const expectedResults = upToDate("6.1.6");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
}); });
@ -223,7 +222,7 @@ describe("<OsUpdateButton/>", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.installedVersion = "6.1.6"; testProps.installedVersion = "6.1.6";
testProps.availableBetaVersion = "6.1.6-beta"; testProps.availableBetaVersion = "6.1.6-beta";
testProps.betaOptIn = true; testProps.update_channel = "beta";
testProps.onBeta = true; testProps.onBeta = true;
const expectedResults = updateNeeded("6.1.6"); const expectedResults = updateNeeded("6.1.6");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
@ -233,7 +232,7 @@ describe("<OsUpdateButton/>", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.installedVersion = "6.1.6"; testProps.installedVersion = "6.1.6";
testProps.availableBetaVersion = "6.1.6-beta"; testProps.availableBetaVersion = "6.1.6-beta";
testProps.betaOptIn = false; testProps.update_channel = "stable";
testProps.onBeta = true; testProps.onBeta = true;
const expectedResults = updateNeeded("6.1.6"); const expectedResults = updateNeeded("6.1.6");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
@ -243,7 +242,7 @@ describe("<OsUpdateButton/>", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.installedVersion = "6.1.7"; testProps.installedVersion = "6.1.7";
testProps.availableBetaVersion = "6.1.7-beta"; testProps.availableBetaVersion = "6.1.7-beta";
testProps.betaOptIn = true; testProps.update_channel = "beta";
testProps.onBeta = true; testProps.onBeta = true;
const expectedResults = upToDate("6.1.7-beta"); const expectedResults = upToDate("6.1.7-beta");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
@ -253,7 +252,7 @@ describe("<OsUpdateButton/>", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.installedVersion = "6.1.7-beta"; testProps.installedVersion = "6.1.7-beta";
testProps.availableBetaVersion = "6.1.7-beta"; testProps.availableBetaVersion = "6.1.7-beta";
testProps.betaOptIn = true; testProps.update_channel = "beta";
const expectedResults = upToDate("6.1.7-beta"); const expectedResults = upToDate("6.1.7-beta");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
}); });
@ -264,7 +263,7 @@ describe("<OsUpdateButton/>", () => {
testProps.installedCommit = "old commit"; testProps.installedCommit = "old commit";
testProps.availableBetaVersion = "7.0.0-beta"; testProps.availableBetaVersion = "7.0.0-beta";
testProps.availableBetaCommit = "new commit"; testProps.availableBetaCommit = "new commit";
testProps.betaOptIn = true; testProps.update_channel = "beta";
testProps.onBeta = true; testProps.onBeta = true;
const expectedResults = updateNeeded("7.0.0-beta"); const expectedResults = updateNeeded("7.0.0-beta");
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
@ -273,7 +272,7 @@ describe("<OsUpdateButton/>", () => {
it("handles installed version newer than available (beta enabled)", () => { it("handles installed version newer than available (beta enabled)", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.installedVersion = "6.1.7"; testProps.installedVersion = "6.1.7";
testProps.betaOptIn = true; testProps.update_channel = "beta";
testProps.onBeta = false; testProps.onBeta = false;
testProps.availableBetaVersion = "6.1.7-beta"; testProps.availableBetaVersion = "6.1.7-beta";
const expectedResults = upToDate("6.1.7-beta"); const expectedResults = upToDate("6.1.7-beta");
@ -308,16 +307,6 @@ describe("<OsUpdateButton/>", () => {
testButtonState(testProps, expectedResults); testButtonState(testProps, expectedResults);
}); });
it("doesn't use update_channel value", () => {
const testProps = defaultTestProps();
testProps.installedVersion = "6.1.6";
testProps.shouldDisplay = () => false;
testProps.update_channel = "beta";
testProps.availableBetaVersion = "6.1.7-beta";
const expectedResults = upToDate("6.1.6");
testButtonState(testProps, expectedResults);
});
it("compares release candidates: newer", () => { it("compares release candidates: newer", () => {
const testProps = defaultTestProps(); const testProps = defaultTestProps();
testProps.availableVersion = "6.1.5"; testProps.availableVersion = "6.1.5";

View File

@ -4,7 +4,7 @@ import { SemverResult, semverCompare } from "../../../util";
import { OsUpdateButtonProps } from "./interfaces"; import { OsUpdateButtonProps } from "./interfaces";
import { checkControllerUpdates } from "../../actions"; import { checkControllerUpdates } from "../../actions";
import { isString } from "lodash"; import { isString } from "lodash";
import { BotState, Feature } from "../../interfaces"; import { BotState } from "../../interfaces";
import { Content } from "../../../constants"; import { Content } from "../../../constants";
import { t } from "../../../i18next_wrapper"; import { t } from "../../../i18next_wrapper";
@ -154,9 +154,8 @@ export const OsUpdateButton = (props: OsUpdateButtonProps) => {
const { controller_version } = bot.hardware.informational_settings; const { controller_version } = bot.hardware.informational_settings;
/** FBOS beta release opt-in setting. */ /** FBOS beta release opt-in setting. */
const betaOptIn = props.shouldDisplay(Feature.use_update_channel) const betaOptIn =
? sourceFbosConfig("update_channel" as ConfigurationName).value !== "stable" sourceFbosConfig("update_channel" as ConfigurationName).value !== "stable";
: !!sourceFbosConfig("beta_opt_in").value;
/** FBOS update availability. */ /** FBOS update availability. */
const buttonStatusProps = buttonVersionStatus({ bot, betaOptIn }); const buttonStatusProps = buttonVersionStatus({ bot, betaOptIn });

View File

@ -117,7 +117,6 @@ describe("<Logs />", () => {
it("shows filtered overall filter status", () => { it("shows filtered overall filter status", () => {
const p = fakeProps(); const p = fakeProps();
p.shouldDisplay = () => true;
const wrapper = mount(<Logs {...p} />); const wrapper = mount(<Logs {...p} />);
const state = fakeLogsState(); const state = fakeLogsState();
state.assertion = 2; state.assertion = 2;
@ -129,10 +128,9 @@ describe("<Logs />", () => {
it("shows unfiltered overall filter status", () => { it("shows unfiltered overall filter status", () => {
const p = fakeProps(); const p = fakeProps();
p.shouldDisplay = () => false;
const wrapper = mount(<Logs {...p} />); const wrapper = mount(<Logs {...p} />);
const state = fakeLogsState(); const state = fakeLogsState();
state.assertion = 2; state.assertion = 3;
wrapper.setState(state); wrapper.setState(state);
const filterBtn = wrapper.find("button").first(); const filterBtn = wrapper.find("button").first();
expect(filterBtn.text().toLowerCase()).toEqual("filter"); expect(filterBtn.text().toLowerCase()).toEqual("filter");

View File

@ -5,7 +5,6 @@ import { Filters } from "../interfaces";
import { startCase } from "lodash"; import { startCase } from "lodash";
import { MESSAGE_TYPES, MessageType } from "../../sequences/interfaces"; import { MESSAGE_TYPES, MessageType } from "../../sequences/interfaces";
import { t } from "../../i18next_wrapper"; import { t } from "../../i18next_wrapper";
import { Feature, ShouldDisplay } from "../../devices/interfaces";
const MENU_ORDER: string[] = [ const MENU_ORDER: string[] = [
MessageType.success, MessageType.success,
@ -26,11 +25,9 @@ const menuSort = (a: string, b: string) =>
/** Get log filter keys from LogsState. */ /** Get log filter keys from LogsState. */
export const filterStateKeys = export const filterStateKeys =
(state: LogsState, shouldDisplay: ShouldDisplay) => (state: LogsState) =>
Object.keys(state) Object.keys(state)
.filter(key => !["autoscroll", "markdown", "searchTerm"].includes(key)) .filter(key => !["autoscroll", "markdown", "searchTerm"].includes(key));
.filter(key => shouldDisplay(Feature.assertion_block)
|| key !== "assertion");
export const LogsFilterMenu = (props: LogsFilterMenuProps) => { export const LogsFilterMenu = (props: LogsFilterMenuProps) => {
/** Filter level 0: logs hidden. */ /** Filter level 0: logs hidden. */
@ -56,7 +53,7 @@ export const LogsFilterMenu = (props: LogsFilterMenuProps) => {
{t("normal")} {t("normal")}
</button> </button>
</fieldset> </fieldset>
{filterStateKeys(props.state, props.shouldDisplay).sort(menuSort) {filterStateKeys(props.state).sort(menuSort)
.map((logType: keyof Filters) => .map((logType: keyof Filters) =>
<fieldset key={logType}> <fieldset key={logType}>
<label> <label>

View File

@ -76,7 +76,7 @@ export class RawLogs extends React.Component<LogsProps, Partial<LogsState>> {
/** Determine if log type filters are active. */ /** Determine if log type filters are active. */
get filterActive() { get filterActive() {
const filterKeys = filterStateKeys(this.state, this.props.shouldDisplay); const filterKeys = filterStateKeys(this.state);
const filterValues = filterKeys const filterValues = filterKeys
.map((key: keyof Filters) => this.state[key]); .map((key: keyof Filters) => this.state[key]);
// Filters active if every log type level is not equal to 3 (max verbosity) // Filters active if every log type level is not equal to 3 (max verbosity)

View File

@ -33,7 +33,8 @@ describe("<StepButtonCluster />", () => {
it("has correct drag data", () => { it("has correct drag data", () => {
const p = fakeProps(); const p = fakeProps();
const wrapper = mount(<StepButtonCluster {...p} />); const wrapper = mount(<StepButtonCluster {...p} />);
const stepButton = wrapper.find("div").last(); const steps = wrapper.find(".step-dragger");
const stepButton = steps.at(steps.length - 2);
expect(stepButton.text().toLowerCase()).toEqual("take photo"); expect(stepButton.text().toLowerCase()).toEqual("take photo");
stepButton.simulate("dragStart", { dataTransfer: { setData: jest.fn() } }); stepButton.simulate("dragStart", { dataTransfer: { setData: jest.fn() } });
expect(p.dispatch).toHaveBeenCalledWith(expect.objectContaining({ expect(p.dispatch).toHaveBeenCalledWith(expect.objectContaining({

View File

@ -9,7 +9,6 @@ import {
determineVector, determineDropdown, SequenceMeta, determineVarDDILabel, determineVector, determineDropdown, SequenceMeta, determineVarDDILabel,
} from "../../resources/sequence_meta"; } from "../../resources/sequence_meta";
import { ResourceIndex, UUID } from "../../resources/interfaces"; import { ResourceIndex, UUID } from "../../resources/interfaces";
import { Feature } from "../../devices/interfaces";
import { DefaultValueForm } from "./default_value_form"; import { DefaultValueForm } from "./default_value_form";
import { t } from "../../i18next_wrapper"; import { t } from "../../i18next_wrapper";
import { CoordinateInputBoxes } from "./location_form_coordinate_input_boxes"; import { CoordinateInputBoxes } from "./location_form_coordinate_input_boxes";
@ -49,13 +48,12 @@ export const LocationForm =
const { celeryNode, dropdown, vector } = maybeUseStepData({ const { celeryNode, dropdown, vector } = maybeUseStepData({
resources, bodyVariables, variable, uuid: sequenceUuid resources, bodyVariables, variable, uuid: sequenceUuid
}); });
const displayVariables = props.shouldDisplay(Feature.variables) && const displayVariables = allowedVariableNodes !== AllowedVariableNodes.variable;
allowedVariableNodes !== AllowedVariableNodes.variable;
const headerForm = allowedVariableNodes === AllowedVariableNodes.parameter; const headerForm = allowedVariableNodes === AllowedVariableNodes.parameter;
const variableListItems = displayVariables ? [PARENT(determineVarDDILabel({ const variableListItems = displayVariables ? [PARENT(determineVarDDILabel({
label: "parent", resources, uuid: sequenceUuid, forceExternal: headerForm label: "parent", resources, uuid: sequenceUuid, forceExternal: headerForm
}))] : []; }))] : [];
const displayGroups = props.shouldDisplay(Feature.groups) && !hideGroups; const displayGroups = !hideGroups;
const unfiltered = locationFormList(resources, variableListItems, displayGroups); const unfiltered = locationFormList(resources, variableListItems, displayGroups);
const list = props.customFilterRule ? const list = props.customFilterRule ?
unfiltered.filter(props.customFilterRule) : unfiltered; unfiltered.filter(props.customFilterRule) : unfiltered;

View File

@ -163,22 +163,21 @@ export function StepButtonCluster(props: StepButtonProps) {
step={{ kind: "take_photo", args: {} }}> step={{ kind: "take_photo", args: {} }}>
{t("TAKE PHOTO")} {t("TAKE PHOTO")}
</StepButton>, </StepButton>,
<StepButton
{...commonStepProps}
step={{
kind: "assertion",
args: {
lua: "return 2 + 2 == 4",
_then: { kind: "nothing", args: {} },
assertion_type: "abort_recover",
}
}}
color="purple">
{t("ASSERTION")}
</StepButton>,
]; ];
shouldDisplay(Feature.assertion_block) && ALL_THE_BUTTONS.push(<StepButton
{...commonStepProps}
step={{
kind: "assertion",
args: {
lua: "return 2 + 2 == 4",
_then: { kind: "nothing", args: {} },
assertion_type: "abort_recover",
}
}}
color="purple">
{t("ASSERTION")}
</StepButton>);
shouldDisplay(Feature.update_resource) && ALL_THE_BUTTONS.push(<StepButton shouldDisplay(Feature.update_resource) && ALL_THE_BUTTONS.push(<StepButton
{...commonStepProps} {...commonStepProps}
step={{ step={{
@ -196,6 +195,7 @@ export function StepButtonCluster(props: StepButtonProps) {
color="brown"> color="brown">
{t("Mark As...")} {t("Mark As...")}
</StepButton>); </StepButton>);
return <Row> return <Row>
<div className="step-button-cluster"> <div className="step-button-cluster">
{ALL_THE_BUTTONS.map((stepButton, inx) => {ALL_THE_BUTTONS.map((stepButton, inx) =>

View File

@ -104,10 +104,19 @@ export enum FbosVersionFallback {
NULL = "0.0.0", NULL = "0.0.0",
} }
const fallbackData: MinOsFeatureLookup = {
[Feature.api_farmware_env]: "8.0.0",
[Feature.api_farmware_installations]: "8.0.0",
[Feature.criteria_groups]: "9.2.2",
[Feature.update_resource]: MinVersionOverride.NEVER,
[Feature.boot_sequence]: MinVersionOverride.NEVER,
};
/** /**
* Determine whether a feature should be displayed based on * Determine whether a feature should be displayed based on
* the user's current FBOS version. Min FBOS version feature data is pulled * the user's current FBOS version. Min FBOS version feature data is pulled
* from an external source to allow App and FBOS development flexibility. * from an external source to allow App and FBOS development flexibility.
* Device-less accounts can use features compatible with supported versions.
* *
* @param current installed OS version string to compare against data ("0.0.0") * @param current installed OS version string to compare against data ("0.0.0")
* @param lookupData min req versions data, for example {"feature": "1.0.0"} * @param lookupData min req versions data, for example {"feature": "1.0.0"}
@ -120,7 +129,7 @@ export function createShouldDisplayFn(
const fallback = globalConfig.FBOS_END_OF_LIFE_VERSION || const fallback = globalConfig.FBOS_END_OF_LIFE_VERSION ||
FbosVersionFallback.NULL; FbosVersionFallback.NULL;
const target = override || current || fallback; const target = override || current || fallback;
const table = lookupData || {}; const table = lookupData || fallbackData;
const min = table[feature] || MinVersionOverride.NEVER; const min = table[feature] || MinVersionOverride.NEVER;
switch (semverCompare(target, min)) { switch (semverCompare(target, min)) {
case SemverResult.LEFT_IS_GREATER: case SemverResult.LEFT_IS_GREATER: