remove deprecated code
parent
36eba926e3
commit
fb14f89d6f
|
@ -30,6 +30,7 @@ const fakeProps = (): AppProps => {
|
|||
firmwareConfig: undefined,
|
||||
xySwap: false,
|
||||
animate: false,
|
||||
getConfigValue: jest.fn(),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -8,14 +8,7 @@ jest.mock("axios", () => ({
|
|||
}
|
||||
}));
|
||||
|
||||
jest.mock("../session", () => {
|
||||
return {
|
||||
Session: {
|
||||
clear: jest.fn(),
|
||||
deprecatedGetBool: jest.fn(),
|
||||
}
|
||||
};
|
||||
});
|
||||
jest.mock("../session", () => ({ Session: { clear: jest.fn(), } }));
|
||||
|
||||
import { maybeRefreshToken } from "../refresh_token";
|
||||
import { API } from "../api/index";
|
||||
|
|
|
@ -6,8 +6,6 @@ let mockAuth: AuthState | undefined = undefined;
|
|||
jest.mock("../session", () => ({
|
||||
Session: {
|
||||
fetchStoredToken: jest.fn(() => mockAuth),
|
||||
deprecatedGetNum: () => undefined,
|
||||
deprecatedGetBool: () => undefined,
|
||||
getAll: () => undefined,
|
||||
clear: jest.fn()
|
||||
}
|
||||
|
|
|
@ -1,24 +1,3 @@
|
|||
import { fakeWebAppConfig } from "../__test_support__/fake_state/resources";
|
||||
import { fakeState } from "../__test_support__/fake_state";
|
||||
|
||||
const mockConfig = fakeWebAppConfig();
|
||||
jest.mock("../resources/selectors_by_kind", () => ({
|
||||
getWebAppConfig: () => mockConfig
|
||||
}));
|
||||
|
||||
jest.mock("../api/crud", () => ({
|
||||
edit: jest.fn(),
|
||||
save: jest.fn(),
|
||||
}));
|
||||
|
||||
const mockState = fakeState();
|
||||
jest.mock("../redux/store", () => ({
|
||||
store: {
|
||||
dispatch: jest.fn(),
|
||||
getState: () => mockState,
|
||||
}
|
||||
}));
|
||||
|
||||
import {
|
||||
isNumericSetting,
|
||||
isBooleanSetting,
|
||||
|
@ -27,7 +6,6 @@ import {
|
|||
Session,
|
||||
} from "../session";
|
||||
import { auth } from "../__test_support__/fake_state/token";
|
||||
import { edit, save } from "../api/crud";
|
||||
|
||||
describe("fetchStoredToken", () => {
|
||||
it("can't fetch token", () => {
|
||||
|
@ -61,41 +39,6 @@ describe("safeBooleanSetting", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("deprecatedGetNum", () => {
|
||||
it("gets number", () => {
|
||||
const result = Session.deprecatedGetNum("success_log");
|
||||
expect(result).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe("deprecatedSetNum", () => {
|
||||
it("sets number", () => {
|
||||
Session.deprecatedSetNum("success_log", 0);
|
||||
expect(edit).toHaveBeenCalledWith(expect.any(Object), { success_log: 0 });
|
||||
expect(save).toHaveBeenCalledWith(mockConfig.uuid);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setBool", () => {
|
||||
it("sets bool", () => {
|
||||
Session.setBool("x_axis_inverted", false);
|
||||
expect(edit).toHaveBeenCalledWith(expect.any(Object), {
|
||||
x_axis_inverted: false
|
||||
});
|
||||
expect(save).toHaveBeenCalledWith(mockConfig.uuid);
|
||||
});
|
||||
});
|
||||
|
||||
describe("invertBool", () => {
|
||||
it("inverts bool", () => {
|
||||
Session.invertBool("x_axis_inverted");
|
||||
expect(edit).toHaveBeenCalledWith(expect.any(Object), {
|
||||
x_axis_inverted: true
|
||||
});
|
||||
expect(save).toHaveBeenCalledWith(mockConfig.uuid);
|
||||
});
|
||||
});
|
||||
|
||||
describe("safeNumericSetting", () => {
|
||||
it("safely returns num", () => {
|
||||
expect(() => safeNumericSetting("no")).toThrow();
|
||||
|
|
|
@ -79,7 +79,9 @@ export class Account extends React.Component<Props, State> {
|
|||
<ChangePassword />
|
||||
</Row>
|
||||
<Row>
|
||||
<LabsFeatures />
|
||||
<LabsFeatures
|
||||
dispatch={this.props.dispatch}
|
||||
getConfigValue={this.props.getConfigValue} />
|
||||
</Row>
|
||||
<Row>
|
||||
<DeleteAccount onClick={deleteAcct} />
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { User } from "../auth/interfaces";
|
||||
import { TaggedUser } from "farmbot";
|
||||
import { GetWebAppConfigValue } from "../config_storage/actions";
|
||||
|
||||
export interface Props {
|
||||
user: TaggedUser;
|
||||
dispatch: Function;
|
||||
getConfigValue: GetWebAppConfigValue;
|
||||
}
|
||||
|
||||
/** JSON form that gets POSTed to the API when user updates their info. */
|
||||
|
|
|
@ -3,7 +3,7 @@ import { fetchLabFeatures } from "../labs_features_list_data";
|
|||
describe("fetchLabFeatures", () => {
|
||||
window.location.reload = jest.fn();
|
||||
it("basically just initializes stuff", () => {
|
||||
const val = fetchLabFeatures();
|
||||
const val = fetchLabFeatures(jest.fn());
|
||||
expect(val.length).toBe(9);
|
||||
expect(val[0].value).toBeFalsy();
|
||||
const { callback } = val[0];
|
||||
|
|
|
@ -1,20 +1,5 @@
|
|||
const mockStorj: Dictionary<boolean> = {};
|
||||
|
||||
jest.mock("../../../session", () => {
|
||||
return {
|
||||
Session: {
|
||||
deprecatedGetBool: (k: string) => {
|
||||
mockStorj[k] = !!mockStorj[k];
|
||||
return mockStorj[k];
|
||||
},
|
||||
invertBool: (k: string) => {
|
||||
mockStorj[k] = !mockStorj[k];
|
||||
return mockStorj[k];
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
import { Dictionary } from "farmbot";
|
||||
import { maybeToggleFeature, LabsFeature } from "../labs_features_list_data";
|
||||
import { BooleanSetting } from "../../../session_keys";
|
||||
|
@ -29,7 +14,7 @@ describe("maybeToggleFeature()", () => {
|
|||
storageKey: BooleanSetting.stub_config,
|
||||
confirmationMessage: "are you sure?"
|
||||
};
|
||||
const out = maybeToggleFeature(data);
|
||||
const out = maybeToggleFeature(x => mockStorj[x], jest.fn())(data);
|
||||
expect(data.value).toBeFalsy();
|
||||
expect(out).toBeUndefined();
|
||||
expect(window.confirm).toHaveBeenCalledWith(data.confirmationMessage);
|
||||
|
@ -44,7 +29,7 @@ describe("maybeToggleFeature()", () => {
|
|||
storageKey: BooleanSetting.stub_config,
|
||||
confirmationMessage: "are you sure?"
|
||||
};
|
||||
const out = maybeToggleFeature(data);
|
||||
const out = maybeToggleFeature(x => mockStorj[x], jest.fn())(data);
|
||||
out ?
|
||||
expect(out.value).toBeTruthy() : fail("out === undefined. Thats bad");
|
||||
expect(out).toBeTruthy();
|
||||
|
@ -52,7 +37,7 @@ describe("maybeToggleFeature()", () => {
|
|||
|
||||
it("Does not require consent when going from true to false", () => {
|
||||
window.confirm = jest.fn(() => true);
|
||||
const output = maybeToggleFeature({
|
||||
const output = maybeToggleFeature(x => mockStorj[x], jest.fn())({
|
||||
name: "Example",
|
||||
value: (mockStorj[BooleanSetting.stub_config] = true),
|
||||
description: "I stub this.",
|
||||
|
@ -71,7 +56,7 @@ describe("maybeToggleFeature()", () => {
|
|||
description: "I stub this.",
|
||||
storageKey: BooleanSetting.stub_config
|
||||
};
|
||||
const out = maybeToggleFeature(data);
|
||||
const out = maybeToggleFeature(x => mockStorj[x], jest.fn())(data);
|
||||
out ?
|
||||
expect(out.value).toBeTruthy() : fail("out === undefined. Thats bad");
|
||||
expect(out).toBeTruthy();
|
||||
|
|
|
@ -9,7 +9,7 @@ const mockFeatures = [
|
|||
];
|
||||
|
||||
const mocks = {
|
||||
"maybeToggleFeature": jest.fn(),
|
||||
"maybeToggleFeature": jest.fn(() => jest.fn()),
|
||||
"fetchLabFeatures": jest.fn(() => mockFeatures)
|
||||
};
|
||||
|
||||
|
@ -21,7 +21,9 @@ import { LabsFeatures } from "../labs_features";
|
|||
|
||||
describe("<LabsFeatures/>", () => {
|
||||
it("triggers the correct callback on click", () => {
|
||||
const el = mount(<LabsFeatures />);
|
||||
const el = mount(<LabsFeatures
|
||||
dispatch={jest.fn()}
|
||||
getConfigValue={jest.fn()} />);
|
||||
expect(mocks.fetchLabFeatures.mock.calls.length).toBeGreaterThan(0);
|
||||
el.find("button").simulate("click");
|
||||
expect(mockFeatures[0].callback).toHaveBeenCalled();
|
||||
|
|
|
@ -4,20 +4,29 @@ import { LabsFeaturesList } from "./labs_features_list_ui";
|
|||
import { maybeToggleFeature } from "./labs_features_list_data";
|
||||
import { t } from "i18next";
|
||||
import { ToolTips } from "../../constants";
|
||||
import { GetWebAppConfigValue } from "../../config_storage/actions";
|
||||
|
||||
export class LabsFeatures extends React.Component<{}, {}> {
|
||||
interface LabsFeaturesProps {
|
||||
getConfigValue: GetWebAppConfigValue;
|
||||
dispatch: Function;
|
||||
}
|
||||
|
||||
export class LabsFeatures extends React.Component<LabsFeaturesProps, {}> {
|
||||
state = {};
|
||||
|
||||
render() {
|
||||
const { getConfigValue, dispatch } = this.props;
|
||||
return <Widget className="peripherals-widget">
|
||||
<WidgetHeader title={t("App Settings")}
|
||||
helpText={ToolTips.LABS}>
|
||||
</WidgetHeader>
|
||||
<WidgetBody>
|
||||
<LabsFeaturesList onToggle={(x) => {
|
||||
maybeToggleFeature(x);
|
||||
this.forceUpdate();
|
||||
}} />
|
||||
<LabsFeaturesList
|
||||
getConfigValue={getConfigValue}
|
||||
onToggle={x => {
|
||||
maybeToggleFeature(getConfigValue, dispatch)(x);
|
||||
this.forceUpdate();
|
||||
}} />
|
||||
</WidgetBody>
|
||||
</Widget>;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { Session } from "../../session";
|
||||
import { t } from "i18next";
|
||||
import { BooleanConfigKey } from "../../config_storage/web_app_configs";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
import { Content } from "../../constants";
|
||||
import { VirtualTrail } from "../../farm_designer/map/virtual_farmbot/bot_trail";
|
||||
import { GetWebAppConfigValue, setWebAppConfigValue } from "../../config_storage/actions";
|
||||
|
||||
export interface LabsFeature {
|
||||
/** Toggle label. */
|
||||
|
@ -21,88 +22,91 @@ export interface LabsFeature {
|
|||
callback?(): void;
|
||||
}
|
||||
|
||||
export const fetchLabFeatures = (): LabsFeature[] => ([
|
||||
{
|
||||
name: t("Internationalize Web App"),
|
||||
description: t("Turn off to set Web App to English."),
|
||||
storageKey: BooleanSetting.disable_i18n,
|
||||
value: false,
|
||||
displayInvert: true,
|
||||
callback: () => window.location.reload()
|
||||
},
|
||||
{
|
||||
name: t("Confirm Sequence step deletion"),
|
||||
description: t(Content.CONFIRM_STEP_DELETION),
|
||||
storageKey: BooleanSetting.confirm_step_deletion,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Hide Webcam widget"),
|
||||
description: t(Content.HIDE_WEBCAM_WIDGET),
|
||||
storageKey: BooleanSetting.hide_webcam_widget,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Dynamic map size"),
|
||||
description: t(Content.DYNAMIC_MAP_SIZE),
|
||||
storageKey: BooleanSetting.dynamic_map,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Double default map dimensions"),
|
||||
description: t(Content.DOUBLE_MAP_DIMENSIONS),
|
||||
storageKey: BooleanSetting.map_xl,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Display plant animations"),
|
||||
description: t(Content.PLANT_ANIMATIONS),
|
||||
storageKey: BooleanSetting.disable_animations,
|
||||
value: false,
|
||||
displayInvert: true
|
||||
},
|
||||
{
|
||||
name: t("Read speak logs in browser"),
|
||||
description: t(Content.BROWSER_SPEAK_LOGS),
|
||||
storageKey: BooleanSetting.enable_browser_speak,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Discard Unsaved Changes"),
|
||||
description: t(Content.DISCARD_UNSAVED_CHANGES),
|
||||
storageKey: BooleanSetting.discard_unsaved,
|
||||
value: false,
|
||||
confirmationMessage: t(Content.DISCARD_UNSAVED_CHANGES_CONFIRM)
|
||||
},
|
||||
{
|
||||
name: t("Display virtual FarmBot trail"),
|
||||
description: t(Content.VIRTUAL_TRAIL),
|
||||
storageKey: BooleanSetting.display_trail,
|
||||
value: false,
|
||||
callback: () => sessionStorage.setItem("virtualTrailRecords", "[]")
|
||||
},
|
||||
].map(fetchRealValue));
|
||||
export const fetchLabFeatures =
|
||||
(getConfigValue: GetWebAppConfigValue): LabsFeature[] => ([
|
||||
{
|
||||
name: t("Internationalize Web App"),
|
||||
description: t("Turn off to set Web App to English."),
|
||||
storageKey: BooleanSetting.disable_i18n,
|
||||
value: false,
|
||||
displayInvert: true,
|
||||
callback: () => window.location.reload()
|
||||
},
|
||||
{
|
||||
name: t("Confirm Sequence step deletion"),
|
||||
description: t(Content.CONFIRM_STEP_DELETION),
|
||||
storageKey: BooleanSetting.confirm_step_deletion,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Hide Webcam widget"),
|
||||
description: t(Content.HIDE_WEBCAM_WIDGET),
|
||||
storageKey: BooleanSetting.hide_webcam_widget,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Dynamic map size"),
|
||||
description: t(Content.DYNAMIC_MAP_SIZE),
|
||||
storageKey: BooleanSetting.dynamic_map,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Double default map dimensions"),
|
||||
description: t(Content.DOUBLE_MAP_DIMENSIONS),
|
||||
storageKey: BooleanSetting.map_xl,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Display plant animations"),
|
||||
description: t(Content.PLANT_ANIMATIONS),
|
||||
storageKey: BooleanSetting.disable_animations,
|
||||
value: false,
|
||||
displayInvert: true
|
||||
},
|
||||
{
|
||||
name: t("Read speak logs in browser"),
|
||||
description: t(Content.BROWSER_SPEAK_LOGS),
|
||||
storageKey: BooleanSetting.enable_browser_speak,
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: t("Discard Unsaved Changes"),
|
||||
description: t(Content.DISCARD_UNSAVED_CHANGES),
|
||||
storageKey: BooleanSetting.discard_unsaved,
|
||||
value: false,
|
||||
confirmationMessage: t(Content.DISCARD_UNSAVED_CHANGES_CONFIRM)
|
||||
},
|
||||
{
|
||||
name: t("Display virtual FarmBot trail"),
|
||||
description: t(Content.VIRTUAL_TRAIL),
|
||||
storageKey: BooleanSetting.display_trail,
|
||||
value: false,
|
||||
callback: () => sessionStorage.setItem(VirtualTrail.records, "[]")
|
||||
},
|
||||
].map(fetchSettingValue(getConfigValue)));
|
||||
|
||||
/** Always allow toggling from true => false (deactivate).
|
||||
* Require a disclaimer when going from false => true (activate). */
|
||||
export const maybeToggleFeature =
|
||||
(x: LabsFeature): LabsFeature | undefined => {
|
||||
return (x.value
|
||||
|| !x.confirmationMessage
|
||||
|| window.confirm(x.confirmationMessage)) ?
|
||||
toggleFeatureValue(x) : undefined;
|
||||
};
|
||||
|
||||
/** Stub this when testing if need be. */
|
||||
const fetchVal = (k: BooleanConfigKey) => !!Session.deprecatedGetBool(k);
|
||||
(getConfigValue: GetWebAppConfigValue, dispatch: Function) =>
|
||||
(x: LabsFeature): LabsFeature | undefined =>
|
||||
(x.value
|
||||
|| !x.confirmationMessage
|
||||
|| window.confirm(x.confirmationMessage)) ?
|
||||
toggleFeatureValue(getConfigValue, dispatch)(x) : undefined;
|
||||
|
||||
/** Takes a `LabFeature` (probably one with an uninitialized fallback / default
|
||||
* value) and sets it to the _real_ value that's in the API. */
|
||||
const fetchRealValue = (x: LabsFeature): LabsFeature => {
|
||||
return { ...x, value: fetchVal(x.storageKey) };
|
||||
};
|
||||
const fetchSettingValue = (getConfigValue: GetWebAppConfigValue) =>
|
||||
(x: LabsFeature): LabsFeature => {
|
||||
return { ...x, value: !!getConfigValue(x.storageKey) };
|
||||
};
|
||||
|
||||
/** Toggle the `.value` of a `LabsToggle` object */
|
||||
const toggleFeatureValue = (x: LabsFeature) => {
|
||||
return { ...x, value: Session.invertBool(x.storageKey) };
|
||||
};
|
||||
const toggleFeatureValue =
|
||||
(getConfigValue: GetWebAppConfigValue, dispatch: Function) =>
|
||||
(x: LabsFeature) => {
|
||||
const value = !getConfigValue(x.storageKey);
|
||||
dispatch(setWebAppConfigValue(x.storageKey, value));
|
||||
return { ...x, value };
|
||||
};
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
import * as React from "react";
|
||||
import { fetchLabFeatures, LabsFeature } from "./labs_features_list_data";
|
||||
import { KeyValShowRow } from "../../controls/key_val_show_row";
|
||||
import { GetWebAppConfigValue } from "../../config_storage/actions";
|
||||
|
||||
interface LabsFeaturesListProps {
|
||||
onToggle(feature: LabsFeature): void;
|
||||
getConfigValue: GetWebAppConfigValue;
|
||||
}
|
||||
|
||||
export function LabsFeaturesList(props: LabsFeaturesListProps) {
|
||||
return <div>
|
||||
{fetchLabFeatures().map((p, i) => {
|
||||
{fetchLabFeatures(props.getConfigValue).map((p, i) => {
|
||||
const displayValue = p.displayInvert ? !p.value : p.value;
|
||||
return <KeyValShowRow key={i}
|
||||
label={p.name}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import { Everything } from "../interfaces";
|
||||
import { Props } from "./interfaces";
|
||||
import { getUserAccountSettings } from "../resources/selectors";
|
||||
import { getWebAppConfigValue } from "../config_storage/actions";
|
||||
|
||||
export function mapStateToProps(props: Everything): Props {
|
||||
const user = getUserAccountSettings(props.resources.index);
|
||||
|
||||
return {
|
||||
user,
|
||||
dispatch: () => { throw new Error("NEVER SHOULD HAPPEN"); }
|
||||
dispatch: () => { throw new Error("NEVER SHOULD HAPPEN"); },
|
||||
getConfigValue: getWebAppConfigValue(() => props),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import { validBotLocationData, validFwConfig } from "./util";
|
|||
import { BooleanSetting } from "./session_keys";
|
||||
import { getPathArray } from "./history";
|
||||
import { FirmwareConfig } from "./config_storage/firmware_configs";
|
||||
import { getWebAppConfigValue } from "./config_storage/actions";
|
||||
import { getWebAppConfigValue, GetWebAppConfigValue } from "./config_storage/actions";
|
||||
import { takeSortedLogs } from "./logs/state_to_props";
|
||||
|
||||
/** Remove 300ms delay on touch devices - https://github.com/ftlabs/fastclick */
|
||||
|
@ -44,6 +44,7 @@ export interface AppProps {
|
|||
xySwap: boolean;
|
||||
firmwareConfig: FirmwareConfig | undefined;
|
||||
animate: boolean;
|
||||
getConfigValue: GetWebAppConfigValue;
|
||||
}
|
||||
|
||||
function mapStateToProps(props: Everything): AppProps {
|
||||
|
@ -64,6 +65,7 @@ function mapStateToProps(props: Everything): AppProps {
|
|||
xySwap: !!webAppConfigValue(BooleanSetting.xy_swap),
|
||||
firmwareConfig: validFwConfig(getFirmwareConfig(props.resources.index)),
|
||||
animate: !webAppConfigValue(BooleanSetting.disable_animations),
|
||||
getConfigValue: webAppConfigValue,
|
||||
};
|
||||
}
|
||||
/** Time at which the app gives up and asks the user to refresh */
|
||||
|
@ -111,7 +113,8 @@ export class App extends React.Component<AppProps, {}> {
|
|||
user={this.props.user}
|
||||
bot={this.props.bot}
|
||||
dispatch={this.props.dispatch}
|
||||
logs={this.props.logs} />
|
||||
logs={this.props.logs}
|
||||
getConfigValue={this.props.getConfigValue} />
|
||||
{!syncLoaded && <LoadingPlant animate={this.props.animate} />}
|
||||
{syncLoaded && this.props.children}
|
||||
{!(["controls", "account", "regimens"].includes(currentPage)) &&
|
||||
|
|
|
@ -19,8 +19,6 @@ jest.mock("axios", () => ({
|
|||
jest.mock("../../session", () => ({
|
||||
Session: {
|
||||
fetchStoredToken: jest.fn(),
|
||||
deprecatedGetNum: () => undefined,
|
||||
deprecatedGetBool: () => undefined,
|
||||
getAll: () => undefined,
|
||||
clear: jest.fn()
|
||||
}
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
import { store } from "../redux/store";
|
||||
import { BooleanConfigKey, NumberConfigKey } from "../config_storage/web_app_configs";
|
||||
import { edit, save } from "../api/crud";
|
||||
import { getWebAppConfig } from "../resources/selectors_by_kind";
|
||||
|
||||
/**
|
||||
* HISTORICAL CONTEXT: We once stored user settings (like map zoom level) in
|
||||
* localStorage and would retrieve values via `Session.getBool("zoom_level")`
|
||||
*
|
||||
* PROBLEM: localStorage is no longer used. Many parts of the app were accessing
|
||||
* values in places that did not have access to the Redux store.
|
||||
*
|
||||
* SOLUTION: Create a temporary shim that will "cheat" and directly call Redux
|
||||
* store without a lot of boilerplate props passing.
|
||||
*
|
||||
* WHY NOT JUST INLINE THESE FUNCTIONS?: It's easier to stub out calls in tests
|
||||
* that already exist.
|
||||
*/
|
||||
|
||||
/** Avoid using this function in new places. Pass props instead. */
|
||||
export function getBoolViaRedux(key: BooleanConfigKey): boolean | undefined {
|
||||
const conf = getWebAppConfig(store.getState().resources.index);
|
||||
// tslint:disable-next-line:no-any
|
||||
return conf && (conf.body as any)[key];
|
||||
}
|
||||
|
||||
/** Avoid using this function in new places. Pass props instead. */
|
||||
export function setBoolViaRedux(key: BooleanConfigKey, val: boolean) {
|
||||
const conf = getWebAppConfig(store.getState().resources.index);
|
||||
if (conf) {
|
||||
store.dispatch(edit(conf, { [key]: val }));
|
||||
// tslint:disable-next-line:no-any
|
||||
store.dispatch(save(conf.uuid) as any);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/** Avoid using this function in new places. Pass props instead. */
|
||||
export function getNumViaRedux(key: NumberConfigKey): number | undefined {
|
||||
const conf = getWebAppConfig(store.getState().resources.index);
|
||||
return conf && conf.body[key];
|
||||
}
|
||||
|
||||
/** Avoid using this function in new places. Pass props instead. */
|
||||
export function setNumViaRedux(key: NumberConfigKey, val: number): number {
|
||||
const conf = getWebAppConfig(store.getState().resources.index);
|
||||
if (conf) {
|
||||
store.dispatch(edit(conf, { [key]: val }));
|
||||
// tslint:disable-next-line:no-any
|
||||
store.dispatch(save(conf.uuid) as any);
|
||||
}
|
||||
return val;
|
||||
}
|
|
@ -9,12 +9,6 @@ jest.mock("../../history", () => ({
|
|||
},
|
||||
}));
|
||||
|
||||
jest.mock("../../session", () => ({
|
||||
Session: {
|
||||
deprecatedGetBool: () => true // Simulate opt-in to beta features.
|
||||
}
|
||||
}));
|
||||
|
||||
const mockDevice = {
|
||||
execScript: jest.fn(() => Promise.resolve({})),
|
||||
};
|
||||
|
|
|
@ -4,30 +4,26 @@ import { shallow } from "enzyme";
|
|||
import { NavBar } from "../index";
|
||||
import { bot } from "../../__test_support__/fake_state/bot";
|
||||
import { taggedUser } from "../../__test_support__/user";
|
||||
import { NavBarProps } from "../interfaces";
|
||||
|
||||
describe("NavBar", () => {
|
||||
const fakeProps = (): NavBarProps => ({
|
||||
timeOffset: 0,
|
||||
consistent: true,
|
||||
logs: [],
|
||||
bot,
|
||||
user: taggedUser,
|
||||
dispatch: jest.fn(),
|
||||
getConfigValue: jest.fn(),
|
||||
});
|
||||
|
||||
it("has correct parent classname", () => {
|
||||
const wrapper = shallow(
|
||||
<NavBar
|
||||
timeOffset={0}
|
||||
consistent={true}
|
||||
logs={[]}
|
||||
bot={bot}
|
||||
user={taggedUser}
|
||||
dispatch={jest.fn()} />
|
||||
);
|
||||
const wrapper = shallow(<NavBar {...fakeProps()} />);
|
||||
expect(wrapper.find("div").first().hasClass("nav-wrapper")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("closes nav menu", () => {
|
||||
const wrapper = shallow<NavBar>(<NavBar
|
||||
timeOffset={0}
|
||||
consistent={true}
|
||||
logs={[]}
|
||||
bot={bot}
|
||||
user={taggedUser}
|
||||
dispatch={jest.fn()} />);
|
||||
const wrapper = shallow<NavBar>(<NavBar {...fakeProps()} />);
|
||||
const link = wrapper.find("Link").first();
|
||||
link.simulate("click");
|
||||
expect(wrapper.instance().state.mobileMenuOpen).toBeFalsy();
|
||||
|
|
|
@ -1,25 +1,5 @@
|
|||
const mockStorj: Dictionary<number | boolean> = {};
|
||||
|
||||
jest.mock("../../session", () => {
|
||||
return {
|
||||
Session: {
|
||||
deprecatedGetNum: (k: string) => {
|
||||
return mockStorj[k];
|
||||
},
|
||||
deprecatedSetNum: (k: string, v: number) => {
|
||||
mockStorj[k] = v;
|
||||
},
|
||||
deprecatedGetBool: (k: string) => {
|
||||
mockStorj[k] = !!mockStorj[k];
|
||||
return mockStorj[k];
|
||||
}
|
||||
},
|
||||
// tslint:disable-next-line:no-any
|
||||
safeNumericSetting: (x: any) => x
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { TickerList } from "../ticker_list";
|
||||
|
@ -41,6 +21,7 @@ describe("<TickerList />", () => {
|
|||
logs: [fakeTaggedLog(), fakeTaggedLog()],
|
||||
tickerListOpen: false,
|
||||
toggle: jest.fn(),
|
||||
getConfigValue: x => mockStorj[x],
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -55,15 +55,17 @@ export class NavBar extends React.Component<NavBarProps, Partial<NavBarState>> {
|
|||
|
||||
const { toggle, close } = this;
|
||||
const { mobileMenuOpen, tickerListOpen, accountMenuOpen } = this.state;
|
||||
const { logs, timeOffset } = this.props;
|
||||
|
||||
const { logs, timeOffset, getConfigValue } = this.props;
|
||||
const tickerListProps = {
|
||||
logs, tickerListOpen, toggle, timeOffset, getConfigValue
|
||||
};
|
||||
return <ErrorBoundary>
|
||||
<div className="nav-wrapper">
|
||||
<nav role="navigation">
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<div>
|
||||
<TickerList {...{ logs, tickerListOpen, toggle, timeOffset }} />
|
||||
<TickerList {...tickerListProps} />
|
||||
<div className="nav-group">
|
||||
<div className="nav-left">
|
||||
<i
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { BotState } from "../devices/interfaces";
|
||||
import { TaggedUser, TaggedLog } from "farmbot";
|
||||
import { GetWebAppConfigValue } from "../config_storage/actions";
|
||||
|
||||
export interface NavButtonProps {
|
||||
user: TaggedUser | undefined;
|
||||
|
@ -16,6 +17,7 @@ export interface NavBarProps {
|
|||
user: TaggedUser | undefined;
|
||||
dispatch: Function;
|
||||
timeOffset: number;
|
||||
getConfigValue: GetWebAppConfigValue;
|
||||
}
|
||||
|
||||
export interface NavBarState {
|
||||
|
@ -36,6 +38,7 @@ export interface TickerListProps {
|
|||
logs: TaggedLog[]
|
||||
tickerListOpen: boolean;
|
||||
timeOffset: number;
|
||||
getConfigValue: GetWebAppConfigValue;
|
||||
}
|
||||
|
||||
export interface NavLinksProps {
|
||||
|
|
|
@ -5,18 +5,20 @@ import { TickerListProps } from "./interfaces";
|
|||
import { Link } from "react-router";
|
||||
import { t } from "i18next";
|
||||
import { formatLogTime } from "../logs/index";
|
||||
import { Session, safeNumericSetting } from "../session";
|
||||
import { safeNumericSetting } from "../session";
|
||||
import { ErrorBoundary } from "../error_boundary";
|
||||
import { ALLOWED_MESSAGE_TYPES, TaggedLog, SpecialStatus } from "farmbot";
|
||||
import { filterByVerbosity } from "../logs/components/logs_table";
|
||||
import { isNumber } from "lodash";
|
||||
import { GetWebAppConfigValue } from "../config_storage/actions";
|
||||
|
||||
/** Get current verbosity filter level for a message type from WebAppConfig. */
|
||||
const getFilterLevel = (type: ALLOWED_MESSAGE_TYPES): number => {
|
||||
const filterLevel =
|
||||
Session.deprecatedGetNum(safeNumericSetting(type + "_log"));
|
||||
return isNumber(filterLevel) ? filterLevel : 1;
|
||||
};
|
||||
const getFilterLevel = (getConfigValue: GetWebAppConfigValue) =>
|
||||
(type: ALLOWED_MESSAGE_TYPES): number => {
|
||||
const filterLevel =
|
||||
getConfigValue(safeNumericSetting(type + "_log"));
|
||||
return isNumber(filterLevel) ? filterLevel : 1;
|
||||
};
|
||||
|
||||
/** Generate a fallback TaggedLog to display in the first line of the ticker. */
|
||||
const generateFallbackLog = (uuid: string, message: string): TaggedLog => {
|
||||
|
@ -34,19 +36,21 @@ const generateFallbackLog = (uuid: string, message: string): TaggedLog => {
|
|||
};
|
||||
|
||||
/** Choose the log to display in the first line of the ticker. */
|
||||
const getfirstTickerLog = (logs: TaggedLog[]): TaggedLog => {
|
||||
if (logs.length == 0) {
|
||||
return generateFallbackLog("no_logs_yet", t("No logs yet."));
|
||||
} else {
|
||||
const filteredLogs = filterByVerbosity(getFilterLevel, logs);
|
||||
if (filteredLogs.length > 0) {
|
||||
return filteredLogs[0];
|
||||
const getfirstTickerLog = (getConfigValue: GetWebAppConfigValue) =>
|
||||
(logs: TaggedLog[]): TaggedLog => {
|
||||
if (logs.length == 0) {
|
||||
return generateFallbackLog("no_logs_yet", t("No logs yet."));
|
||||
} else {
|
||||
return generateFallbackLog("no_logs_to_display",
|
||||
t("No logs to display. Visit Logs page to view filters."));
|
||||
const filteredLogs =
|
||||
filterByVerbosity(getFilterLevel(getConfigValue), logs);
|
||||
if (filteredLogs.length > 0) {
|
||||
return filteredLogs[0];
|
||||
} else {
|
||||
return generateFallbackLog("no_logs_to_display",
|
||||
t("No logs to display. Visit Logs page to view filters."));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/** Format a single log for display in the ticker. */
|
||||
const Ticker = (log: TaggedLog, timeOffset: number) => {
|
||||
|
@ -70,10 +74,11 @@ export let TickerList = (props: TickerListProps) => {
|
|||
return <ErrorBoundary>
|
||||
<div className="ticker-list" onClick={props.toggle("tickerListOpen")} >
|
||||
<div className="first-ticker">
|
||||
{Ticker(getfirstTickerLog(props.logs), props.timeOffset)}
|
||||
{Ticker(getfirstTickerLog(props.getConfigValue)(props.logs),
|
||||
props.timeOffset)}
|
||||
</div>
|
||||
<Collapse isOpen={props.tickerListOpen}>
|
||||
{filterByVerbosity(getFilterLevel, props.logs)
|
||||
{filterByVerbosity(getFilterLevel(props.getConfigValue), props.logs)
|
||||
// Don't use first log again since it's already displayed in first row
|
||||
.filter((_, index) => index !== 0)
|
||||
.map((log: TaggedLog) => Ticker(log, props.timeOffset))}
|
||||
|
|
|
@ -61,7 +61,8 @@ describe("<AllSteps/>", () => {
|
|||
sequence={TEST_CASE}
|
||||
onDrop={() => { }}
|
||||
dispatch={jest.fn()}
|
||||
resources={buildResourceIndex([]).index} />);
|
||||
resources={buildResourceIndex([]).index}
|
||||
confirmStepDeletion={false} />);
|
||||
[TileMoveRelative, TileReadPin, TileWritePin]
|
||||
.map(q => {
|
||||
expect(el.find(q).length).toEqual(1);
|
||||
|
|
|
@ -55,6 +55,7 @@ describe("<SequenceEditorMiddleActive/>", () => {
|
|||
farmwareConfigs: {},
|
||||
},
|
||||
shouldDisplay: jest.fn(),
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ describe("<SequenceEditorMiddle/>", () => {
|
|||
farmwareConfigs: {},
|
||||
},
|
||||
shouldDisplay: jest.fn(),
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ describe("<Sequences/>", () => {
|
|||
farmwareConfigs: {},
|
||||
},
|
||||
shouldDisplay: jest.fn(),
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ describe("<StepIconGroup />", () => {
|
|||
step: { kind: "wait", args: { milliseconds: 100 } },
|
||||
sequence: fakeSequence(),
|
||||
helpText: "helpful text",
|
||||
confirmStepDeletion: false,
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
|
|
|
@ -17,6 +17,7 @@ interface AllStepsProps {
|
|||
hardwareFlags?: HardwareFlags;
|
||||
farmwareInfo?: FarmwareInfo;
|
||||
shouldDisplay?: ShouldDisplay;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
||||
export class AllSteps extends React.Component<AllStepsProps, {}> {
|
||||
|
@ -50,6 +51,7 @@ export class AllSteps extends React.Component<AllStepsProps, {}> {
|
|||
hardwareFlags,
|
||||
farmwareInfo,
|
||||
shouldDisplay,
|
||||
confirmStepDeletion: this.props.confirmStepDeletion,
|
||||
})}
|
||||
</div>
|
||||
</StepDragger>
|
||||
|
|
|
@ -30,6 +30,7 @@ export interface Props {
|
|||
hardwareFlags: HardwareFlags;
|
||||
farmwareInfo: FarmwareInfo;
|
||||
shouldDisplay: ShouldDisplay;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
||||
export interface SequenceEditorMiddleProps {
|
||||
|
@ -40,11 +41,11 @@ export interface SequenceEditorMiddleProps {
|
|||
hardwareFlags: HardwareFlags;
|
||||
farmwareInfo: FarmwareInfo;
|
||||
shouldDisplay: ShouldDisplay;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
||||
export interface ActiveMiddleProps extends SequenceEditorMiddleProps {
|
||||
sequence: TaggedSequence;
|
||||
syncStatus: SyncStatus;
|
||||
}
|
||||
|
||||
export type ChannelName = ALLOWED_CHANNEL_NAMES;
|
||||
|
@ -156,4 +157,5 @@ export interface StepParams {
|
|||
hardwareFlags?: HardwareFlags;
|
||||
farmwareInfo?: FarmwareInfo;
|
||||
shouldDisplay?: ShouldDisplay;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
|
|
@ -7,24 +7,17 @@ import { SequenceEditorMiddleActive } from "./sequence_editor_middle_active";
|
|||
export class SequenceEditorMiddle
|
||||
extends React.Component<SequenceEditorMiddleProps, {}> {
|
||||
render() {
|
||||
const {
|
||||
dispatch,
|
||||
sequence,
|
||||
resources,
|
||||
syncStatus,
|
||||
hardwareFlags,
|
||||
farmwareInfo,
|
||||
shouldDisplay,
|
||||
} = this.props;
|
||||
const { sequence } = this.props;
|
||||
if (sequence && isTaggedSequence(sequence)) {
|
||||
return <SequenceEditorMiddleActive
|
||||
dispatch={dispatch}
|
||||
dispatch={this.props.dispatch}
|
||||
sequence={sequence}
|
||||
resources={resources}
|
||||
syncStatus={syncStatus}
|
||||
hardwareFlags={hardwareFlags}
|
||||
farmwareInfo={farmwareInfo}
|
||||
shouldDisplay={shouldDisplay} />;
|
||||
resources={this.props.resources}
|
||||
syncStatus={this.props.syncStatus}
|
||||
hardwareFlags={this.props.hardwareFlags}
|
||||
farmwareInfo={this.props.farmwareInfo}
|
||||
shouldDisplay={this.props.shouldDisplay}
|
||||
confirmStepDeletion={this.props.confirmStepDeletion} />;
|
||||
} else {
|
||||
return <SequenceEditorMiddleInactive />;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,8 @@ export class Sequences extends React.Component<Props, {}> {
|
|||
resources={this.props.resources}
|
||||
hardwareFlags={this.props.hardwareFlags}
|
||||
farmwareInfo={this.props.farmwareInfo}
|
||||
shouldDisplay={this.props.shouldDisplay} />
|
||||
shouldDisplay={this.props.shouldDisplay}
|
||||
confirmStepDeletion={this.props.confirmStepDeletion} />
|
||||
</CenterPanel>
|
||||
<RightPanel
|
||||
className="step-button-cluster-panel"
|
||||
|
|
|
@ -9,6 +9,8 @@ import {
|
|||
betterCompact, shouldDisplay, determineInstalledOsVersion, validFwConfig
|
||||
} from "../util";
|
||||
import { getWebAppConfig } from "../resources/selectors";
|
||||
import { BooleanSetting } from "../session_keys";
|
||||
import { getWebAppConfigValue } from "../config_storage/actions";
|
||||
|
||||
export function mapStateToProps(props: Everything): Props {
|
||||
const uuid = props.resources.consumers.sequences.current;
|
||||
|
@ -63,6 +65,9 @@ export function mapStateToProps(props: Everything): Props {
|
|||
const installedOsVersion = determineInstalledOsVersion(
|
||||
props.bot, maybeGetDevice(props.resources.index));
|
||||
|
||||
const confirmStepDeletion =
|
||||
!!getWebAppConfigValue(() => props)(BooleanSetting.confirm_step_deletion);
|
||||
|
||||
return {
|
||||
dispatch: props.dispatch,
|
||||
sequences: selectAllSequences(props.resources.index),
|
||||
|
@ -81,5 +86,6 @@ export function mapStateToProps(props: Everything): Props {
|
|||
farmwareConfigs,
|
||||
},
|
||||
shouldDisplay: shouldDisplay(installedOsVersion, props.bot.minOsFeatureData),
|
||||
confirmStepDeletion,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ export interface StepIconBarProps {
|
|||
step: SequenceBodyItem;
|
||||
sequence: TaggedSequence;
|
||||
helpText: string;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
||||
export function StepUpDownButtonPopover(
|
||||
|
@ -24,10 +25,13 @@ export function StepUpDownButtonPopover(
|
|||
}
|
||||
|
||||
export function StepIconGroup(props: StepIconBarProps) {
|
||||
const { index, dispatch, step, sequence, helpText } = props;
|
||||
const {
|
||||
index, dispatch, step, sequence, helpText, confirmStepDeletion
|
||||
} = props;
|
||||
|
||||
const onClone = () => dispatch(splice({ step, index, sequence }));
|
||||
const onTrash = () => remove({ dispatch, index, sequence });
|
||||
const onTrash = () =>
|
||||
remove({ dispatch, index, sequence, confirmStepDeletion });
|
||||
const onMove = (delta: number) => () => {
|
||||
const to = Math.max(index + delta, 0);
|
||||
dispatch(move({ step, sequence, from: index, to }));
|
||||
|
|
|
@ -1,39 +1,76 @@
|
|||
const mockStorj: Dictionary<boolean> = {};
|
||||
jest.mock("../../../api/crud", () => ({
|
||||
overwrite: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock("../../../session", () => {
|
||||
return {
|
||||
Session: {
|
||||
deprecatedGetBool: (k: string) => {
|
||||
mockStorj[k] = !!mockStorj[k];
|
||||
return mockStorj[k];
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
import { Dictionary } from "farmbot";
|
||||
import { remove } from "../index";
|
||||
import { remove, move, splice } from "../index";
|
||||
import { fakeSequence } from "../../../__test_support__/fake_state/resources";
|
||||
import { BooleanSetting } from "../../../session_keys";
|
||||
import { overwrite } from "../../../api/crud";
|
||||
import { Wait } from "farmbot";
|
||||
|
||||
describe("remove()", () => {
|
||||
const fakeProps = () => ({
|
||||
index: 0,
|
||||
dispatch: jest.fn(),
|
||||
sequence: fakeSequence(),
|
||||
confirmStepDeletion: false,
|
||||
});
|
||||
|
||||
it("deletes step without confirmation", () => {
|
||||
const dispatch = jest.fn();
|
||||
mockStorj[BooleanSetting.confirm_step_deletion] = false;
|
||||
remove({ index: 0, dispatch, sequence: fakeSequence() });
|
||||
expect(dispatch).toHaveBeenCalled();
|
||||
const p = fakeProps();
|
||||
remove(p);
|
||||
expect(p.dispatch).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("deletes step with confirmation", () => {
|
||||
const dispatch = jest.fn();
|
||||
mockStorj[BooleanSetting.confirm_step_deletion] = true;
|
||||
const p = fakeProps();
|
||||
p.confirmStepDeletion = true;
|
||||
window.confirm = jest.fn();
|
||||
remove({ index: 0, dispatch, sequence: fakeSequence() });
|
||||
remove(p);
|
||||
expect(window.confirm).toHaveBeenCalledWith(
|
||||
expect.stringContaining("delete this step?"));
|
||||
expect(dispatch).not.toHaveBeenCalled();
|
||||
expect(p.dispatch).not.toHaveBeenCalled();
|
||||
window.confirm = jest.fn(() => true);
|
||||
remove({ index: 0, dispatch, sequence: fakeSequence() });
|
||||
expect(dispatch).toHaveBeenCalled();
|
||||
remove(p);
|
||||
expect(p.dispatch).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("move()", () => {
|
||||
const sequence = fakeSequence();
|
||||
const step1: Wait = { kind: "wait", args: { milliseconds: 100 } };
|
||||
const step2: Wait = { kind: "wait", args: { milliseconds: 200 } };
|
||||
sequence.body.body = [step1, step2];
|
||||
const fakeProps = () => ({ step: step2, sequence, to: 0, from: 1, });
|
||||
|
||||
it("moves step backward", () => {
|
||||
const p = fakeProps();
|
||||
p.from = 1;
|
||||
p.to = 0;
|
||||
move(p);
|
||||
expect(overwrite).toHaveBeenCalledWith(expect.any(Object),
|
||||
expect.objectContaining({ body: [step2, step1] }));
|
||||
});
|
||||
|
||||
it("moves step forward", () => {
|
||||
const p = fakeProps();
|
||||
p.sequence.body.body = [step2, step1];
|
||||
p.from = 0;
|
||||
p.to = 2;
|
||||
move(p);
|
||||
expect(overwrite).toHaveBeenCalledWith(expect.any(Object),
|
||||
expect.objectContaining({ body: [step1, step2] }));
|
||||
});
|
||||
});
|
||||
|
||||
describe("splice()", () => {
|
||||
const sequence = fakeSequence();
|
||||
const step: Wait = { kind: "wait", args: { milliseconds: 100 } };
|
||||
const fakeProps = () => ({ step, sequence, index: 1, });
|
||||
|
||||
it("adds step", () => {
|
||||
const p = fakeProps();
|
||||
splice(p);
|
||||
expect(overwrite).toHaveBeenCalledWith(expect.any(Object),
|
||||
expect.objectContaining({ body: [step] }));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -289,7 +289,8 @@ describe("Pin and Peripheral support files", () => {
|
|||
dispatch,
|
||||
currentSequence,
|
||||
currentStep,
|
||||
index
|
||||
index,
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
const callback = setArgsDotPinNumber(stepParams);
|
||||
const ddi: DropDownItem = { label: "hmm", value: 0 };
|
||||
|
|
|
@ -26,7 +26,8 @@ describe("<TileExecuteScript/>", () => {
|
|||
firstPartyFarmwareNames: ["one"],
|
||||
showFirstPartyFarmware: false,
|
||||
farmwareConfigs: { "farmware-to-execute": [] },
|
||||
}
|
||||
},
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -20,11 +20,12 @@ function fakeProps(): ExecBlockParams {
|
|||
};
|
||||
return {
|
||||
currentSequence: fakeSequence(),
|
||||
currentStep: currentStep,
|
||||
currentStep,
|
||||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
resources: emptyState().index,
|
||||
shouldDisplay: () => false,
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from "react";
|
||||
import { TileFindHome } from "../tile_find_home";
|
||||
import { TileFindHome, FindHomeParams } from "../tile_find_home";
|
||||
import { mount } from "enzyme";
|
||||
import { fakeSequence } from "../../../__test_support__/fake_state/resources";
|
||||
import { FindHome } from "farmbot/dist";
|
||||
|
@ -7,9 +7,10 @@ import { emptyState } from "../../../resources/reducer";
|
|||
import {
|
||||
fakeHardwareFlags
|
||||
} from "../../../__test_support__/sequence_hardware_settings";
|
||||
import { HardwareFlags } from "../../interfaces";
|
||||
|
||||
describe("<TileFindHome/>", () => {
|
||||
const fakeProps = () => {
|
||||
const fakeProps = (): FindHomeParams => {
|
||||
const currentStep: FindHome = {
|
||||
kind: "find_home",
|
||||
args: {
|
||||
|
@ -23,7 +24,8 @@ describe("<TileFindHome/>", () => {
|
|||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
resources: emptyState().index,
|
||||
hardwareFlags: fakeHardwareFlags()
|
||||
hardwareFlags: fakeHardwareFlags(),
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -49,7 +51,7 @@ describe("<TileFindHome/>", () => {
|
|||
it("doesn't render warning", () => {
|
||||
const p = fakeProps();
|
||||
p.currentStep.args.axis = "x";
|
||||
p.hardwareFlags.findHomeEnabled.x = true;
|
||||
(p.hardwareFlags as HardwareFlags).findHomeEnabled.x = true;
|
||||
const wrapper = mount(<TileFindHome {...p} />);
|
||||
expect(wrapper.text()).not.toContain(CONFLICT_TEXT_BASE);
|
||||
});
|
||||
|
@ -57,7 +59,7 @@ describe("<TileFindHome/>", () => {
|
|||
it("renders warning: all axes", () => {
|
||||
const p = fakeProps();
|
||||
p.currentStep.args.axis = "all";
|
||||
p.hardwareFlags.findHomeEnabled.x = false;
|
||||
(p.hardwareFlags as HardwareFlags).findHomeEnabled.x = false;
|
||||
const wrapper = mount(<TileFindHome {...p} />);
|
||||
expect(wrapper.text()).toContain(CONFLICT_TEXT_BASE + ": x");
|
||||
});
|
||||
|
@ -65,7 +67,7 @@ describe("<TileFindHome/>", () => {
|
|||
it("renders warning: one axis", () => {
|
||||
const p = fakeProps();
|
||||
p.currentStep.args.axis = "x";
|
||||
p.hardwareFlags.findHomeEnabled.x = false;
|
||||
(p.hardwareFlags as HardwareFlags).findHomeEnabled.x = false;
|
||||
const wrapper = mount(<TileFindHome {...p} />);
|
||||
expect(wrapper.text()).toContain(CONFLICT_TEXT_BASE + ": x");
|
||||
});
|
||||
|
|
|
@ -23,7 +23,8 @@ describe("<TileIf/>", () => {
|
|||
currentStep={currentStep}
|
||||
dispatch={jest.fn()}
|
||||
index={0}
|
||||
resources={emptyState().index} />)
|
||||
resources={emptyState().index}
|
||||
confirmStepDeletion={false} />)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ describe("<TileMoveAbsolute/>", () => {
|
|||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
resources: emptyState().index,
|
||||
hardwareFlags: fakeHardwareFlags()
|
||||
hardwareFlags: fakeHardwareFlags(),
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -100,7 +101,8 @@ describe("<TileMoveAbsolute/>", () => {
|
|||
currentStep={currentStep}
|
||||
dispatch={jest.fn()}
|
||||
index={0}
|
||||
resources={index} />).instance() as TileMoveAbsolute;
|
||||
resources={index}
|
||||
confirmStepDeletion={false} />).instance() as TileMoveAbsolute;
|
||||
|
||||
expect(component.tool).toEqual(tool);
|
||||
});
|
||||
|
|
|
@ -22,7 +22,8 @@ describe("<TileMoveRelative/>", () => {
|
|||
currentStep={currentStep}
|
||||
dispatch={jest.fn()}
|
||||
index={0}
|
||||
resources={emptyState().index} />)
|
||||
resources={emptyState().index}
|
||||
confirmStepDeletion={false} />)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@ describe("Pin tile support functions", () => {
|
|||
currentStep,
|
||||
dispatch,
|
||||
index,
|
||||
resources
|
||||
resources,
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ describe("<TileReadPin/>", () => {
|
|||
currentStep={currentStep}
|
||||
dispatch={jest.fn()}
|
||||
index={0}
|
||||
resources={emptyState().index} />)
|
||||
resources={emptyState().index}
|
||||
confirmStepDeletion={false} />)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ describe("<TileSendMessage/>", () => {
|
|||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
resources: emptyState().index,
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ describe("<TileTakePhoto/>", () => {
|
|||
currentStep={currentStep}
|
||||
dispatch={jest.fn()}
|
||||
index={0}
|
||||
resources={emptyState().index} />)
|
||||
resources={emptyState().index}
|
||||
confirmStepDeletion={false} />)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ describe("<TileWait/>", () => {
|
|||
currentStep={currentStep}
|
||||
dispatch={jest.fn()}
|
||||
index={0}
|
||||
resources={emptyState().index} />)
|
||||
resources={emptyState().index}
|
||||
confirmStepDeletion={false} />)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@ describe("<TileWritePin/>", () => {
|
|||
currentStep: currentStep,
|
||||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
resources: emptyState().index
|
||||
resources: emptyState().index,
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ import * as _ from "lodash";
|
|||
import { overwrite } from "../../api/crud";
|
||||
import { TileFindHome } from "./tile_find_home";
|
||||
import { t } from "i18next";
|
||||
import { Session } from "../../session";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
|
||||
interface MoveParams {
|
||||
step: Step;
|
||||
|
@ -64,10 +62,12 @@ interface RemoveParams {
|
|||
index: number;
|
||||
dispatch: Function;
|
||||
sequence: TaggedSequence;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
||||
export function remove({ dispatch, index, sequence }: RemoveParams) {
|
||||
if (!Session.deprecatedGetBool(BooleanSetting.confirm_step_deletion) ||
|
||||
export function remove(props: RemoveParams) {
|
||||
const { dispatch, index, sequence, confirmStepDeletion } = props;
|
||||
if (!confirmStepDeletion ||
|
||||
confirm(t("Are you sure you want to delete this step?"))) {
|
||||
const original = sequence;
|
||||
const update = defensiveClone(original);
|
||||
|
|
|
@ -21,7 +21,8 @@ export function ExecuteBlock(p: StepParams) {
|
|||
index={p.index}
|
||||
dispatch={p.dispatch}
|
||||
resources={p.resources}
|
||||
shouldDisplay={p.shouldDisplay || (() => false)} />;
|
||||
shouldDisplay={p.shouldDisplay || (() => false)}
|
||||
confirmStepDeletion={p.confirmStepDeletion} />;
|
||||
} else {
|
||||
throw new Error("Thats not an execute block!");
|
||||
}
|
||||
|
@ -34,6 +35,7 @@ export interface ExecBlockParams {
|
|||
index: number;
|
||||
resources: ResourceIndex;
|
||||
shouldDisplay: ShouldDisplay;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
export class RefactoredExecuteBlock extends React.Component<ExecBlockParams, {}> {
|
||||
changeSelection = (input: DropDownItem) => {
|
||||
|
@ -99,7 +101,8 @@ export class RefactoredExecuteBlock extends React.Component<ExecBlockParams, {}>
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index} />
|
||||
index={index}
|
||||
confirmStepDeletion={this.props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
|
|
|
@ -9,8 +9,8 @@ import { editStep } from "../../api/crud";
|
|||
import { ExecuteScript, FarmwareConfig } from "farmbot";
|
||||
import { FarmwareInputs, farmwareList } from "./tile_execute_script_support";
|
||||
|
||||
export function TileExecuteScript({
|
||||
dispatch, currentStep, index, currentSequence, farmwareInfo }: StepParams) {
|
||||
export function TileExecuteScript(props: StepParams) {
|
||||
const { dispatch, currentStep, index, currentSequence, farmwareInfo } = props;
|
||||
if (currentStep.kind === "execute_script") {
|
||||
|
||||
const farmwareName = currentStep.args.label;
|
||||
|
@ -63,7 +63,8 @@ export function TileExecuteScript({
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index} />
|
||||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
|
|
|
@ -20,18 +20,20 @@ export function TileFindHome(props: StepParams) {
|
|||
dispatch={props.dispatch}
|
||||
index={props.index}
|
||||
resources={props.resources}
|
||||
hardwareFlags={props.hardwareFlags} />;
|
||||
hardwareFlags={props.hardwareFlags}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />;
|
||||
} else {
|
||||
throw new Error("TileFindHome expects find_home");
|
||||
}
|
||||
}
|
||||
interface FindHomeParams {
|
||||
export interface FindHomeParams {
|
||||
currentStep: FindHome;
|
||||
currentSequence: TaggedSequence;
|
||||
dispatch: Function;
|
||||
index: number;
|
||||
resources: ResourceIndex;
|
||||
hardwareFlags: HardwareFlags | undefined;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
||||
const AXIS_CHOICES: ALLOWED_AXIS[] = ["x", "y", "z", "all"];
|
||||
|
@ -87,7 +89,8 @@ class InnerFindHome extends React.Component<FindHomeParams, {}> {
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index}>
|
||||
index={index}
|
||||
confirmStepDeletion={this.props.confirmStepDeletion}>
|
||||
{some(this.settingConflicts) &&
|
||||
<StepWarning
|
||||
warning={this.settingConflictWarning}
|
||||
|
|
|
@ -10,7 +10,8 @@ export function TileIf(props: StepParams) {
|
|||
dispatch={props.dispatch}
|
||||
index={props.index}
|
||||
resources={props.resources}
|
||||
shouldDisplay={props.shouldDisplay} />;
|
||||
shouldDisplay={props.shouldDisplay}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />;
|
||||
} else {
|
||||
return <p> Expected "_if" node</p>;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,8 @@ describe("<Else/>", () => {
|
|||
currentStep,
|
||||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
resources: emptyState().index
|
||||
resources: emptyState().index,
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ describe("<If_/>", () => {
|
|||
index: 0,
|
||||
resources: emptyState().index,
|
||||
shouldDisplay: jest.fn(),
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ function fakeProps(): IfParams {
|
|||
index: 0,
|
||||
resources: fakeResourceIndex,
|
||||
shouldDisplay: jest.fn(),
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ describe("<Then/>", () => {
|
|||
currentStep,
|
||||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
resources: emptyState().index
|
||||
resources: emptyState().index,
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ export interface IfParams {
|
|||
index: number;
|
||||
resources: ResourceIndex;
|
||||
shouldDisplay?: ShouldDisplay;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
||||
export type Operator = "lhs"
|
||||
|
@ -88,7 +89,8 @@ export function InnerIf(props: IfParams) {
|
|||
index,
|
||||
dispatch,
|
||||
currentStep,
|
||||
currentSequence
|
||||
currentSequence,
|
||||
confirmStepDeletion,
|
||||
} = props;
|
||||
const recursive = isRecursive(currentStep, currentSequence);
|
||||
const className = "if-step";
|
||||
|
@ -99,7 +101,8 @@ export function InnerIf(props: IfParams) {
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index}>
|
||||
index={index}
|
||||
confirmStepDeletion={confirmStepDeletion}>
|
||||
{recursive && (
|
||||
<span>
|
||||
<i className="fa fa-exclamation-triangle"></i>
|
||||
|
|
|
@ -169,7 +169,8 @@ export class TileMoveAbsolute extends Component<StepParams, MoveAbsState> {
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index}>
|
||||
index={index}
|
||||
confirmStepDeletion={this.props.confirmStepDeletion}>
|
||||
{_.some(this.settingConflicts) &&
|
||||
<StepWarning
|
||||
warning={this.settingConflictWarning}
|
||||
|
|
|
@ -6,8 +6,8 @@ import { ToolTips } from "../../constants";
|
|||
import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
|
||||
import { Row, Col } from "../../ui/index";
|
||||
|
||||
export function TileMoveRelative({
|
||||
dispatch, currentStep, index, currentSequence }: StepParams) {
|
||||
export function TileMoveRelative(props: StepParams) {
|
||||
const { dispatch, currentStep, index, currentSequence } = props;
|
||||
const className = "move-relative-step";
|
||||
return <StepWrapper>
|
||||
<StepHeader
|
||||
|
@ -16,7 +16,8 @@ export function TileMoveRelative({
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index} />
|
||||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<Row>
|
||||
<Col xs={6} md={3}>
|
||||
|
|
|
@ -35,7 +35,8 @@ export function TileReadPin(props: StepParams) {
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index} />
|
||||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<Row>
|
||||
<Col xs={6} md={6}>
|
||||
|
|
|
@ -23,7 +23,8 @@ export function TileSendMessage(props: StepParams) {
|
|||
currentSequence={props.currentSequence}
|
||||
dispatch={props.dispatch}
|
||||
index={props.index}
|
||||
resources={props.resources} />;
|
||||
resources={props.resources}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />;
|
||||
} else {
|
||||
throw new Error("TileSendMessage expects send_message");
|
||||
}
|
||||
|
@ -35,6 +36,7 @@ interface SendMessageParams {
|
|||
dispatch: Function;
|
||||
index: number;
|
||||
resources: ResourceIndex;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
||||
export class RefactoredSendMessage
|
||||
|
@ -102,7 +104,8 @@ export class RefactoredSendMessage
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index} />
|
||||
index={index}
|
||||
confirmStepDeletion={this.props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
|
|
|
@ -6,8 +6,8 @@ import { StepWrapper, StepHeader, StepContent } from "../step_ui";
|
|||
import { Col, Row } from "../../ui/index";
|
||||
import { t } from "i18next";
|
||||
|
||||
export function TileTakePhoto({
|
||||
dispatch, currentStep, index, currentSequence }: StepParams) {
|
||||
export function TileTakePhoto(props: StepParams) {
|
||||
const { dispatch, currentStep, index, currentSequence } = props;
|
||||
const className = "take-photo-step";
|
||||
return <StepWrapper>
|
||||
<StepHeader
|
||||
|
@ -16,7 +16,8 @@ export function TileTakePhoto({
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index} />
|
||||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
|
|
|
@ -6,8 +6,8 @@ import { ToolTips } from "../../constants";
|
|||
import { StepWrapper, StepHeader, StepContent } from "../step_ui/index";
|
||||
import { Row, Col } from "../../ui/index";
|
||||
|
||||
export function TileWait({
|
||||
dispatch, currentStep, index, currentSequence }: StepParams) {
|
||||
export function TileWait(props: StepParams) {
|
||||
const { dispatch, currentStep, index, currentSequence } = props;
|
||||
const className = "wait-step";
|
||||
return <StepWrapper>
|
||||
<StepHeader
|
||||
|
@ -16,7 +16,8 @@ export function TileWait({
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index} />
|
||||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<Row>
|
||||
<Col xs={6} md={3}>
|
||||
|
|
|
@ -46,7 +46,8 @@ export function TileWritePin(props: StepParams) {
|
|||
currentSequence={currentSequence}
|
||||
currentStep={currentStep}
|
||||
dispatch={dispatch}
|
||||
index={index} />
|
||||
index={index}
|
||||
confirmStepDeletion={props.confirmStepDeletion} />
|
||||
<StepContent className={className}>
|
||||
<Row>
|
||||
<Col xs={6} md={6}>
|
||||
|
|
|
@ -30,7 +30,8 @@ describe("<StepHeader />", () => {
|
|||
currentStep: { kind: "take_photo", args: {} },
|
||||
dispatch: jest.fn(),
|
||||
index: 0,
|
||||
children: "child"
|
||||
children: "child",
|
||||
confirmStepDeletion: false,
|
||||
};
|
||||
|
||||
it("renders", () => {
|
||||
|
|
|
@ -13,6 +13,7 @@ export interface StepHeaderProps {
|
|||
currentStep: SequenceBodyItem;
|
||||
dispatch: Function;
|
||||
index: number;
|
||||
confirmStepDeletion: boolean;
|
||||
}
|
||||
|
||||
export function StepHeader(props: StepHeaderProps) {
|
||||
|
@ -22,7 +23,8 @@ export function StepHeader(props: StepHeaderProps) {
|
|||
currentSequence,
|
||||
currentStep,
|
||||
dispatch,
|
||||
index
|
||||
index,
|
||||
confirmStepDeletion,
|
||||
} = props;
|
||||
return <Row>
|
||||
<Col sm={12}>
|
||||
|
@ -37,7 +39,8 @@ export function StepHeader(props: StepHeaderProps) {
|
|||
dispatch={dispatch}
|
||||
step={currentStep}
|
||||
sequence={currentSequence}
|
||||
helpText={t(helpText)} />
|
||||
helpText={t(helpText)}
|
||||
confirmStepDeletion={confirmStepDeletion} />
|
||||
{props.children}
|
||||
</div>
|
||||
</Col>
|
||||
|
|
|
@ -2,7 +2,6 @@ import { AuthState } from "./auth/interfaces";
|
|||
import { box } from "boxed_value";
|
||||
import { BooleanConfigKey, NumberConfigKey } from "./config_storage/web_app_configs";
|
||||
import { BooleanSetting, NumericSetting } from "./session_keys";
|
||||
import * as LegacyShim from "./config/legacy_shims";
|
||||
|
||||
/** The `Session` namespace is a wrapper for `localStorage`.
|
||||
* Use this to avoid direct access of `localStorage` where possible.
|
||||
|
@ -43,33 +42,6 @@ export namespace Session {
|
|||
window.location.assign(window.location.origin || "/");
|
||||
return undefined as never;
|
||||
}
|
||||
|
||||
/** @deprecated Don't use this anymore. This is a legacy articfact of when we
|
||||
* used localStorage to store API settings. */
|
||||
export function deprecatedGetBool(key: BooleanConfigKey): boolean | undefined {
|
||||
return LegacyShim.getBoolViaRedux(key);
|
||||
}
|
||||
|
||||
/** @deprecated Store a boolean value in `localStorage` */
|
||||
export function setBool(key: BooleanConfigKey, val: boolean): boolean {
|
||||
return LegacyShim.setBoolViaRedux(key, val);
|
||||
}
|
||||
|
||||
/** @deprecated */
|
||||
export function invertBool(key: BooleanConfigKey): boolean {
|
||||
return Session.setBool(key, !Session.deprecatedGetBool(key));
|
||||
}
|
||||
|
||||
/** @deprecated Extract numeric settings from `localStorage`. Returns `undefined` when
|
||||
* none are found. */
|
||||
export function deprecatedGetNum(key: NumberConfigKey): number | undefined {
|
||||
return LegacyShim.getNumViaRedux(key);
|
||||
}
|
||||
|
||||
/** @deprecated Set a numeric value in `localStorage`. */
|
||||
export function deprecatedSetNum(key: NumberConfigKey, val: number): void {
|
||||
LegacyShim.setNumViaRedux(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
export const isBooleanSetting =
|
||||
|
|
Loading…
Reference in New Issue