commit
42430c569b
|
@ -28,7 +28,7 @@ import { t } from "./i18next_wrapper";
|
|||
import { ResourceIndex } from "./resources/interfaces";
|
||||
import { isBotOnline } from "./devices/must_be_online";
|
||||
import { getStatus } from "./connectivity/reducer_support";
|
||||
import { getAlerts } from "./messages/state_to_props";
|
||||
import { getAllAlerts } from "./messages/state_to_props";
|
||||
|
||||
/** For the logger module */
|
||||
init();
|
||||
|
@ -75,7 +75,7 @@ export function mapStateToProps(props: Everything): AppProps {
|
|||
tour: props.resources.consumers.help.currentTour,
|
||||
resources: props.resources.index,
|
||||
autoSync: !!(fbosConfig && fbosConfig.auto_sync),
|
||||
alertCount: getAlerts(props.resources.index).length,
|
||||
alertCount: getAllAlerts(props.resources).length,
|
||||
};
|
||||
}
|
||||
/** Time at which the app gives up and asks the user to refresh */
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
} from "../farmware/state_to_props";
|
||||
import { getFbosConfig, getFirmwareConfig } from "../resources/getters";
|
||||
import { DevSettings } from "../account/dev/dev_support";
|
||||
import { getAlerts } from "../messages/state_to_props";
|
||||
import { getAllAlerts } from "../messages/state_to_props";
|
||||
|
||||
export function mapStateToProps(props: Everything): Props {
|
||||
const { hardware } = props.bot;
|
||||
|
@ -50,6 +50,6 @@ export function mapStateToProps(props: Everything): Props {
|
|||
env,
|
||||
saveFarmwareEnv: saveOrEditFarmwareEnv(props.resources.index),
|
||||
timeSettings: maybeGetTimeSettings(props.resources.index),
|
||||
alerts: getAlerts(props.resources.index),
|
||||
alerts: getAllAlerts(props.resources),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import { fakeFbosConfig } from "../../__test_support__/fake_state/resources";
|
||||
import { AlertReducerState } from "../interfaces";
|
||||
import { batchInitResources } from "../../connectivity/connect_device";
|
||||
import { alertsReducer } from "../reducer";
|
||||
import { overwrite } from "../../api/crud";
|
||||
|
||||
describe("Contextual `Alert` creation", () => {
|
||||
it("toggles on", () => {
|
||||
const c = fakeFbosConfig();
|
||||
// tslint:disable-next-line:no-any
|
||||
c.body.firmware_hardware = undefined as any;
|
||||
const s: AlertReducerState = {
|
||||
alerts: {}
|
||||
};
|
||||
const { alerts } = alertsReducer(s, batchInitResources([c]));
|
||||
const results = Object.values(alerts);
|
||||
expect(results[0]).toEqual({
|
||||
created_at: 1,
|
||||
problem_tag: "farmbot_os.firmware.missing",
|
||||
priority: 99999,
|
||||
slug: "firmware-missing",
|
||||
});
|
||||
});
|
||||
|
||||
it("toggles off", () => {
|
||||
const c = fakeFbosConfig();
|
||||
const s: AlertReducerState = {
|
||||
alerts: {}
|
||||
};
|
||||
const action =
|
||||
overwrite(c, { ...c.body, firmware_hardware: "none" });
|
||||
const { alerts } = alertsReducer(s, action);
|
||||
const results = Object.values(alerts);
|
||||
expect(results[0]).toEqual(undefined);
|
||||
});
|
||||
});
|
|
@ -6,7 +6,7 @@ import {
|
|||
CommonAlertCardProps,
|
||||
DismissAlertProps,
|
||||
Bulletin,
|
||||
BulletinAlertState
|
||||
AlertComponentState
|
||||
} from "./interfaces";
|
||||
import { formatLogTime } from "../logs";
|
||||
import {
|
||||
|
@ -83,8 +83,8 @@ const ICON_LOOKUP: { [x: string]: string } = {
|
|||
};
|
||||
|
||||
class BulletinAlert
|
||||
extends React.Component<CommonAlertCardProps, BulletinAlertState> {
|
||||
state: BulletinAlertState = { bulletin: undefined, no_content: false };
|
||||
extends React.Component<CommonAlertCardProps, AlertComponentState> {
|
||||
state: AlertComponentState = { bulletin: undefined, no_content: false };
|
||||
|
||||
componentDidMount() {
|
||||
fetchBulletinContent(this.props.alert.slug)
|
||||
|
@ -144,6 +144,7 @@ const FIRMWARE_CHOICES: DropDownItem[] = [
|
|||
{ label: "Farmduino (Genesis v1.3)", value: "farmduino" },
|
||||
{ label: "Farmduino (Genesis v1.4)", value: "farmduino_k14" },
|
||||
{ label: "Farmduino (Express v1.0)", value: "express_k10" },
|
||||
{ label: "None", value: "none" },
|
||||
];
|
||||
|
||||
const FIRMWARE_CHOICES_DDI: { [x: string]: DropDownItem } = {};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { FirmwareHardware, Alert } from "farmbot";
|
||||
import { FirmwareHardware, Alert, Dictionary } from "farmbot";
|
||||
import { TimeSettings } from "../interfaces";
|
||||
import { UUID } from "../resources/interfaces";
|
||||
|
||||
|
@ -89,7 +89,11 @@ export interface Bulletin {
|
|||
title: string | undefined;
|
||||
}
|
||||
|
||||
export interface BulletinAlertState {
|
||||
export interface AlertComponentState {
|
||||
bulletin: Bulletin | undefined;
|
||||
no_content: boolean;
|
||||
}
|
||||
|
||||
export interface AlertReducerState {
|
||||
alerts: Dictionary<Alert | undefined>;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
import { AlertReducerState as State } from "./interfaces";
|
||||
import { generateReducer } from "../redux/generate_reducer";
|
||||
import { SyncBodyContents } from "../sync/actions";
|
||||
import { TaggedResource, TaggedFbosConfig } from "farmbot";
|
||||
import { Actions } from "../constants";
|
||||
import { ReduxAction } from "../redux/interfaces";
|
||||
import { EditResourceParams } from "../api/interfaces";
|
||||
import { unpackUUID } from "../util";
|
||||
|
||||
type Reducer =
|
||||
(state: State, fn: ReduxAction<TaggedResource>) => State;
|
||||
const DEFAULT: Reducer =
|
||||
(s, a) => handleFbosConf(s, a.payload);
|
||||
const FIRMWARE_MISSING =
|
||||
"farmbot_os.firmware.missing";
|
||||
|
||||
export const initialState: State = { alerts: {} };
|
||||
|
||||
const toggleAlert = (s: State, body: TaggedFbosConfig["body"]) => {
|
||||
if (body.firmware_hardware) {
|
||||
delete s.alerts[FIRMWARE_MISSING];
|
||||
} else {
|
||||
s.alerts[FIRMWARE_MISSING] = {
|
||||
created_at: 1,
|
||||
problem_tag: FIRMWARE_MISSING,
|
||||
priority: 99999,
|
||||
slug: "firmware-missing",
|
||||
};
|
||||
}
|
||||
return s;
|
||||
};
|
||||
const handleFbosConf =
|
||||
(s: State, resource: TaggedResource): State => {
|
||||
return (resource.kind === "FbosConfig") ?
|
||||
toggleAlert(s, resource.body) : s;
|
||||
};
|
||||
|
||||
const pickConfigs = (x: TaggedResource) => x.kind === "FbosConfig";
|
||||
|
||||
export const alertsReducer =
|
||||
generateReducer<State>(initialState)
|
||||
.add<SyncBodyContents<TaggedResource>>(Actions.RESOURCE_READY, (s, a) => {
|
||||
const conf = a.payload.body.filter(pickConfigs)[0];
|
||||
|
||||
return (conf) ? handleFbosConf(s, conf) : s;
|
||||
})
|
||||
.add<TaggedResource[]>(Actions.BATCH_INIT, (s, a) => {
|
||||
const conf = a.payload.filter(pickConfigs)[0];
|
||||
|
||||
return conf ? handleFbosConf(s, conf) : s;
|
||||
})
|
||||
.add<EditResourceParams>(Actions.OVERWRITE_RESOURCE, (s, a) => {
|
||||
const x = unpackUUID(a.payload.uuid);
|
||||
const y: TaggedResource["body"] = a.payload.update;
|
||||
if (x.kind === "FbosConfig") {
|
||||
return toggleAlert(s, y as TaggedFbosConfig["body"]);
|
||||
}
|
||||
return s;
|
||||
})
|
||||
.add<TaggedResource>(Actions.REFRESH_RESOURCE_OK, DEFAULT)
|
||||
.add<TaggedResource>(Actions.SAVE_RESOURCE_OK, DEFAULT)
|
||||
.add<TaggedResource>(Actions.SAVE_RESOURCE_START, DEFAULT);
|
|
@ -1,6 +1,6 @@
|
|||
import { Everything } from "../interfaces";
|
||||
import { MessagesProps } from "./interfaces";
|
||||
import { validFbosConfig } from "../util";
|
||||
import { MessagesProps, AlertReducerState } from "./interfaces";
|
||||
import { validFbosConfig, betterCompact } from "../util";
|
||||
import { getFbosConfig } from "../resources/getters";
|
||||
import { sourceFbosConfigValue } from "../devices/components/source_config_value";
|
||||
import {
|
||||
|
@ -19,7 +19,7 @@ export const mapStateToProps = (props: Everything): MessagesProps => {
|
|||
const findApiAlertById = (id: number): UUID =>
|
||||
findResourceById(props.resources.index, "Alert", id);
|
||||
return {
|
||||
alerts: getAlerts(props.resources.index),
|
||||
alerts: getAllAlerts(props.resources),
|
||||
apiFirmwareValue: isFwHardwareValue(apiFirmwareValue)
|
||||
? apiFirmwareValue : undefined,
|
||||
timeSettings: maybeGetTimeSettings(props.resources.index),
|
||||
|
@ -28,6 +28,16 @@ export const mapStateToProps = (props: Everything): MessagesProps => {
|
|||
};
|
||||
};
|
||||
|
||||
export const getAlerts = (resourceIndex: ResourceIndex): Alert[] => {
|
||||
return selectAllAlerts(resourceIndex).map(x => x.body);
|
||||
};
|
||||
export const getAllAlerts =
|
||||
(resources: Everything["resources"]) => {
|
||||
return [
|
||||
...getLocalAlerts(resources.consumers.alerts),
|
||||
...getApiAlerts(resources.index)
|
||||
];
|
||||
};
|
||||
|
||||
export const getApiAlerts = (resourceIndex: ResourceIndex): Alert[] =>
|
||||
selectAllAlerts(resourceIndex).map(x => x.body);
|
||||
|
||||
export const getLocalAlerts = ({ alerts }: AlertReducerState) =>
|
||||
betterCompact(Object.values(alerts));
|
||||
|
|
|
@ -5,7 +5,7 @@ import { Dictionary } from "farmbot";
|
|||
|
||||
/** A function that responds to a particular action from within a
|
||||
* generated reducer. */
|
||||
interface ActionHandler<State, Payl = unknown> {
|
||||
export interface ActionHandler<State, Payl = unknown> {
|
||||
(state: State, action: ReduxAction<Payl>): State;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import { FarmwareState } from "../farmware/interfaces";
|
|||
import { HelpState } from "../help/reducer";
|
||||
import { UsageIndex } from "./in_use";
|
||||
import { SequenceMeta } from "./sequence_meta";
|
||||
import { AlertReducerState } from "../messages/interfaces";
|
||||
|
||||
export type UUID = string;
|
||||
export type VariableNameSet = Record<string, SequenceMeta | undefined>;
|
||||
|
@ -83,6 +84,7 @@ export interface RestResources {
|
|||
farm_designer: DesignerState;
|
||||
farmware: FarmwareState;
|
||||
help: HelpState;
|
||||
alerts: AlertReducerState;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import { initialState as designerState } from "../farm_designer/reducer";
|
|||
import { farmwareState } from "../farmware/reducer";
|
||||
import { initialState as regimenState } from "../regimens/reducer";
|
||||
import { initialState as sequenceState } from "../sequences/reducer";
|
||||
import { initialState as alertState } from "../messages/reducer";
|
||||
|
||||
export const emptyState = (): RestResources => {
|
||||
return {
|
||||
|
@ -29,6 +30,7 @@ export const emptyState = (): RestResources => {
|
|||
farm_designer: designerState,
|
||||
farmware: farmwareState,
|
||||
help: helpState,
|
||||
alerts: alertState
|
||||
},
|
||||
loaded: [],
|
||||
index: {
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
import { ExecutableType } from "farmbot/dist/resources/api_resources";
|
||||
import { betterCompact } from "../util";
|
||||
import { createSequenceMeta } from "./sequence_meta";
|
||||
import { alertsReducer as alerts } from "../messages/reducer";
|
||||
|
||||
export function findByUuid(index: ResourceIndex, uuid: string): TaggedResource {
|
||||
const x = index.references[uuid];
|
||||
|
@ -148,7 +149,8 @@ const consumerReducer = combineReducers<RestResources["consumers"]>({
|
|||
sequences,
|
||||
farm_designer,
|
||||
farmware,
|
||||
help
|
||||
help,
|
||||
alerts
|
||||
} as any); // tslint:disable-line
|
||||
|
||||
/** The resource reducer must have the first say when a resource-related action
|
||||
|
@ -162,6 +164,7 @@ export const afterEach = (state: RestResources, a: ReduxAction<unknown>) => {
|
|||
farm_designer: state.consumers.farm_designer,
|
||||
farmware: state.consumers.farmware,
|
||||
help: state.consumers.help,
|
||||
alerts: state.consumers.alerts
|
||||
}, a);
|
||||
return state;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue