commit
87d2a0f524
10
Gemfile.lock
10
Gemfile.lock
|
@ -96,7 +96,7 @@ GEM
|
|||
factory_bot_rails (5.0.2)
|
||||
factory_bot (~> 5.0.2)
|
||||
railties (>= 4.2.0)
|
||||
faker (2.3.0)
|
||||
faker (2.4.0)
|
||||
i18n (~> 1.6.0)
|
||||
faraday (0.15.4)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
|
@ -152,7 +152,7 @@ GEM
|
|||
mimemagic (0.3.3)
|
||||
mini_mime (1.0.2)
|
||||
mini_portile2 (2.4.0)
|
||||
minitest (5.11.3)
|
||||
minitest (5.12.0)
|
||||
multi_json (1.13.1)
|
||||
multipart-post (2.1.1)
|
||||
mutations (0.9.0)
|
||||
|
@ -162,7 +162,7 @@ GEM
|
|||
mini_portile2 (~> 2.4.0)
|
||||
orm_adapter (0.5.0)
|
||||
os (1.0.1)
|
||||
passenger (6.0.2)
|
||||
passenger (6.0.4)
|
||||
rack
|
||||
rake (>= 0.8.1)
|
||||
pg (1.1.4)
|
||||
|
@ -213,7 +213,7 @@ GEM
|
|||
rake (>= 0.8.7)
|
||||
thor (>= 0.19.0, < 2.0)
|
||||
rake (12.3.3)
|
||||
redis (4.1.2)
|
||||
redis (4.1.3)
|
||||
representable (3.0.4)
|
||||
declarative (< 0.1.0)
|
||||
declarative-option (< 0.2.0)
|
||||
|
@ -255,7 +255,7 @@ GEM
|
|||
faraday (~> 0.9)
|
||||
jwt (>= 1.5, < 3.0)
|
||||
multi_json (~> 1.10)
|
||||
simplecov (0.17.0)
|
||||
simplecov (0.17.1)
|
||||
docile (~> 1.1)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
|
|
|
@ -6,6 +6,10 @@ module Api
|
|||
render json: your_point_groups
|
||||
end
|
||||
|
||||
def show
|
||||
render json: the_point_group
|
||||
end
|
||||
|
||||
def create
|
||||
mutate PointGroups::Create.run(raw_json, point_group_params)
|
||||
end
|
||||
|
|
|
@ -111,18 +111,18 @@ class Device < ApplicationRecord
|
|||
Rails.cache.write(CACHE_KEY % self.id, Device.new(self.as_json))
|
||||
end
|
||||
|
||||
# Sets the `throttled_at` field, but only if it is unpopulated.
|
||||
# Performs no-op if `throttled_at` was already set.
|
||||
# Sets the `throttled_until` and `throttled_at` fields if unpopulated or
|
||||
# the throttle time period increases. Notifies user of cooldown period.
|
||||
def maybe_throttle(violation)
|
||||
end_t = violation.ends_at
|
||||
# Some log validation errors will result in until_time being `nil`.
|
||||
if (violation && throttled_until.nil?)
|
||||
et = violation.ends_at
|
||||
reload.update_attributes!(throttled_until: et,
|
||||
if (violation && (throttled_until.nil? || end_t > throttled_until))
|
||||
reload.update_attributes!(throttled_until: end_t,
|
||||
throttled_at: Time.now)
|
||||
refresh_cache
|
||||
cooldown = et.in_time_zone(self.timezone || "UTC").strftime("%I:%M%p")
|
||||
cooldown = end_t.in_time_zone(self.timezone || "UTC").strftime("%I:%M%p")
|
||||
info = [violation.explanation, cooldown]
|
||||
cooldown_notice(THROTTLE_ON % info, et, "warn")
|
||||
cooldown_notice(THROTTLE_ON % info, end_t, "warn")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@ class Log < ApplicationRecord
|
|||
|
||||
validates :device, presence: true
|
||||
validates :type, presence: true
|
||||
serialize :meta
|
||||
validates :meta, presence: true
|
||||
# http://stackoverflow.com/a/5127684/1064917
|
||||
before_validation :set_defaults
|
||||
|
||||
|
@ -32,27 +30,6 @@ class Log < ApplicationRecord
|
|||
self.channels ||= []
|
||||
end
|
||||
|
||||
# Legacy shims ===============================================================
|
||||
# TODO: Remove these once FBOS stops using the `meta` field (FBOS < v6.4.0).
|
||||
def meta
|
||||
{
|
||||
type: self.type,
|
||||
major_version: self.major_version,
|
||||
minor_version: self.minor_version,
|
||||
verbosity: self.verbosity,
|
||||
x: self.x,
|
||||
y: self.y,
|
||||
z: self.z,
|
||||
}
|
||||
end
|
||||
|
||||
def meta=(hash)
|
||||
hash.map { |(key, value)| self.send("#{key}=", value) }
|
||||
self.meta
|
||||
end
|
||||
|
||||
# End Legacy shims ===========================================================
|
||||
|
||||
def broadcast? # Logs get their own special channel. Don't echo twice!
|
||||
false
|
||||
end
|
||||
|
|
|
@ -16,6 +16,7 @@ class Sequence < ApplicationRecord
|
|||
include CeleryScriptSettingsBag
|
||||
|
||||
belongs_to :device
|
||||
belongs_to :fbos_config, foreign_key: :boot_sequence_id
|
||||
has_one :sequence_usage_report
|
||||
has_many :farm_events, as: :executable
|
||||
has_many :regimen_items
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
module Configs
|
||||
class Update < Mutations::Command
|
||||
HOTFIX = [ :encoder_scaling_x, :encoder_scaling_y, :encoder_scaling_z ]
|
||||
BAD = 56
|
||||
GOOD = 5556
|
||||
HOTFIX = [:encoder_scaling_x, :encoder_scaling_y, :encoder_scaling_z]
|
||||
BAD = 56
|
||||
GOOD = 5556
|
||||
|
||||
required do
|
||||
duck :target, methods: [:update_attributes!]
|
||||
|
@ -11,6 +11,7 @@ module Configs
|
|||
|
||||
def execute
|
||||
target.assign_attributes(sliced_attrs)
|
||||
# Remove HOTFIX after November 12, 2019 - RC
|
||||
HOTFIX.map do |attr|
|
||||
target.assign_attributes(attr => GOOD) if target.try(attr) == BAD
|
||||
end
|
||||
|
@ -20,7 +21,7 @@ module Configs
|
|||
|
||||
def sliced_attrs
|
||||
whitelist = target.class.column_names.map(&:to_sym)
|
||||
updates = update_attrs
|
||||
updates = update_attrs
|
||||
.deep_symbolize_keys
|
||||
.except(:device_id, :id, :created_at)
|
||||
updates.slice(*whitelist)
|
||||
|
|
|
@ -2,22 +2,27 @@ module Devices
|
|||
class Sync < Mutations::Command
|
||||
SEL = "SELECT id, updated_at FROM"
|
||||
WHERE = "WHERE device_id = "
|
||||
WHERE2 = "devices WHERE id = "
|
||||
|
||||
def self.basic_query(plural_resource, where = WHERE)
|
||||
[SEL, plural_resource, where].join(" ")
|
||||
end
|
||||
|
||||
QUERIES = {
|
||||
devices: [SEL, WHERE2].join(" "),
|
||||
farm_events: [SEL, "farm_events", WHERE].join(" "),
|
||||
farmware_envs: [SEL, "farmware_envs", WHERE].join(" "),
|
||||
farmware_installations: [SEL, "farmware_installations", WHERE].join(" "),
|
||||
peripherals: [SEL, "peripherals", WHERE].join(" "),
|
||||
pin_bindings: [SEL, "pin_bindings", WHERE].join(" "),
|
||||
points: [SEL, "points", WHERE].join(" "),
|
||||
regimens: [SEL, "regimens", WHERE].join(" "),
|
||||
sensor_readings: [SEL, "sensor_readings", WHERE].join(" "),
|
||||
sensors: [SEL, "sensors", WHERE].join(" "),
|
||||
sequences: [SEL, "sequences", WHERE].join(" "),
|
||||
tools: [SEL, "tools", WHERE].join(" "),
|
||||
fbos_configs: [SEL, "fbos_configs", WHERE].join(" "),
|
||||
firmware_configs: [SEL, "firmware_configs", WHERE].join(" "),
|
||||
devices: basic_query("devices", "WHERE id = "),
|
||||
farm_events: basic_query("farm_events"),
|
||||
farmware_envs: basic_query("farmware_envs"),
|
||||
farmware_installations: basic_query("farmware_installations"),
|
||||
peripherals: basic_query("peripherals"),
|
||||
pin_bindings: basic_query("pin_bindings"),
|
||||
points: basic_query("points"),
|
||||
regimens: basic_query("regimens"),
|
||||
sensor_readings: basic_query("sensor_readings"),
|
||||
sensors: basic_query("sensors"),
|
||||
sequences: basic_query("sequences"),
|
||||
tools: basic_query("tools"),
|
||||
fbos_configs: basic_query("fbos_configs"),
|
||||
firmware_configs: basic_query("firmware_configs"),
|
||||
point_groups: basic_query("point_groups"),
|
||||
}
|
||||
|
||||
STUB_FARMWARES = Api::FirstPartyFarmwaresController::STUBS.values.map do |x|
|
||||
|
|
|
@ -7,9 +7,9 @@ module Devices
|
|||
end
|
||||
|
||||
optional do
|
||||
string :name
|
||||
string :timezone#, in: Device::TIMEZONES
|
||||
time :last_saw_mq
|
||||
string :name
|
||||
string :timezone
|
||||
time :last_saw_mq
|
||||
integer :mounted_tool_id, nils: true
|
||||
end
|
||||
|
||||
|
@ -23,7 +23,7 @@ module Devices
|
|||
device
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def bad_tool_id
|
||||
add_error :mounted_tool_id, :mounted_tool_id, BAD_TOOL_ID % better_tool_id
|
||||
|
@ -38,7 +38,7 @@ module Devices
|
|||
end
|
||||
|
||||
def mounted_tool_data
|
||||
mounted_tool_id_present? ? {mounted_tool_id: better_tool_id} : {}
|
||||
mounted_tool_id_present? ? { mounted_tool_id: better_tool_id } : {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
module Sequences
|
||||
class Destroy < Mutations::Command
|
||||
IN_USE = "Sequence is still in use by"
|
||||
IN_USE = "Sequence is still in use by"
|
||||
THE_FOLLOWING = " the following %{resource}: %{items}"
|
||||
AND = " and"
|
||||
AND = " and"
|
||||
# Override `THE_FOLLOWING` here.
|
||||
SPECIAL_CASES = {
|
||||
FarmEvent => " %{resource} on the following dates: %{items}"
|
||||
FarmEvent => " %{resource} on the following dates: %{items}",
|
||||
}
|
||||
|
||||
required do
|
||||
|
@ -22,7 +22,7 @@ module Sequences
|
|||
return ""
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def pin_bindings
|
||||
@pin_bindings ||= PinBinding
|
||||
|
@ -45,7 +45,7 @@ module Sequences
|
|||
def regimens
|
||||
@regimens ||= Regimen
|
||||
.includes(:regimen_items)
|
||||
.where(regimen_items: {sequence_id: sequence.id})
|
||||
.where(regimen_items: { sequence_id: sequence.id })
|
||||
.to_a
|
||||
end
|
||||
|
||||
|
@ -57,23 +57,43 @@ module Sequences
|
|||
.to_a
|
||||
end
|
||||
|
||||
class FancyName
|
||||
attr_reader :fancy_name
|
||||
|
||||
def self.table_name
|
||||
"items"
|
||||
end
|
||||
|
||||
def initialize(name)
|
||||
@fancy_name = name
|
||||
end
|
||||
end
|
||||
|
||||
def fbos_config
|
||||
@fbos_config ||= FbosConfig
|
||||
.where(device_id: device.id,
|
||||
boot_sequence_id: sequence.id)
|
||||
.any? ? [FancyName.new("boot sequence")] : []
|
||||
end
|
||||
|
||||
def format_dep_list(klass, items)
|
||||
(SPECIAL_CASES[klass] || THE_FOLLOWING) % {
|
||||
resource: klass.table_name.humanize,
|
||||
items: items.map(&:fancy_name).uniq.join(", ")
|
||||
resource: klass.table_name.humanize.downcase,
|
||||
items: items.map(&:fancy_name).uniq.join(", "),
|
||||
} unless items.empty?
|
||||
end
|
||||
|
||||
def all_deps
|
||||
@all_deps ||= []
|
||||
.concat(farm_events) # FarmEvent
|
||||
.concat(pin_bindings) # PinBinding
|
||||
.concat(regimens) # Regimen
|
||||
.concat(farm_events) # FarmEvent
|
||||
.concat(pin_bindings) # PinBinding
|
||||
.concat(regimens) # Regimen
|
||||
.concat(sibling_sequences) # Sequence
|
||||
.concat(fbos_config)
|
||||
.compact
|
||||
.group_by { |x| x.class }
|
||||
.to_a
|
||||
.map { |(klass, items)| format_dep_list(klass, items) }
|
||||
.map { |(klass, items)| format_dep_list(klass, items) }
|
||||
.compact
|
||||
.join(AND)
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ FarmBot::Application.routes.draw do
|
|||
peripherals: [:create, :destroy, :index, :show, :update],
|
||||
pin_bindings: [:create, :destroy, :index, :show, :update],
|
||||
plant_templates: [:create, :destroy, :index, :update],
|
||||
point_groups: [:index, :create, :update, :destroy],
|
||||
point_groups: [:index, :show, :create, :update, :destroy],
|
||||
regimens: [:create, :destroy, :index, :show, :update],
|
||||
sensor_readings: [:create, :destroy, :index, :show],
|
||||
sensors: [:create, :destroy, :index, :show, :update],
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
class BeginBootSequenceFeature < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
add_column :fbos_configs, :boot_sequence_id, :integer
|
||||
add_column :devices, :last_ota, :datetime
|
||||
add_column :devices, :last_ota_check, :datetime
|
||||
end
|
||||
end
|
|
@ -275,7 +275,9 @@ CREATE TABLE public.devices (
|
|||
created_at timestamp without time zone,
|
||||
updated_at timestamp without time zone,
|
||||
serial_number character varying(32),
|
||||
mqtt_rate_limit_email_sent_at timestamp without time zone
|
||||
mqtt_rate_limit_email_sent_at timestamp without time zone,
|
||||
last_ota timestamp without time zone,
|
||||
last_ota_check timestamp without time zone
|
||||
);
|
||||
|
||||
|
||||
|
@ -505,7 +507,8 @@ CREATE TABLE public.fbos_configs (
|
|||
arduino_debug_messages boolean DEFAULT false,
|
||||
firmware_path character varying,
|
||||
firmware_debug_log boolean DEFAULT false,
|
||||
update_channel character varying(7) DEFAULT 'stable'::character varying
|
||||
update_channel character varying(7) DEFAULT 'stable'::character varying,
|
||||
boot_sequence_id integer
|
||||
);
|
||||
|
||||
|
||||
|
@ -3270,6 +3273,7 @@ INSERT INTO "schema_migrations" (version) VALUES
|
|||
('20190729134954'),
|
||||
('20190804194135'),
|
||||
('20190804194154'),
|
||||
('20190823164837');
|
||||
('20190823164837'),
|
||||
('20190918185359');
|
||||
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
module.exports = {};
|
|
@ -354,7 +354,6 @@ type ResourceLookupTable = Record<TaggedResource["kind"], ResourceGroupNumber>;
|
|||
const KIND_PRIORITY: ResourceLookupTable = {
|
||||
User: 0,
|
||||
Device: 0,
|
||||
FbosConfig: 0,
|
||||
FirmwareConfig: 0,
|
||||
FarmwareEnv: 0,
|
||||
FarmwareInstallation: 0,
|
||||
|
@ -369,6 +368,7 @@ const KIND_PRIORITY: ResourceLookupTable = {
|
|||
PointGroup: 2,
|
||||
SensorReading: 2,
|
||||
Sequence: 2,
|
||||
FbosConfig: 3,
|
||||
Regimen: 3,
|
||||
PinBinding: 3,
|
||||
FarmEvent: 4,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
let mockPath = "";
|
||||
jest.mock("../history", () => ({
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import { safeEveryPointType } from "../sequences/locals_list/location_form_list";
|
||||
|
||||
describe("safeEveryPointType", () => {
|
||||
it("crashes on unknown values", () => {
|
||||
const boom = () => safeEveryPointType("nope");
|
||||
expect(boom).toThrowError("'nope' is not of type EveryPointType");
|
||||
});
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
jest.mock("../labs/labs_features", () => ({ LabsFeatures: () => <div /> }));
|
||||
|
||||
import * as React from "react";
|
||||
|
|
|
@ -27,8 +27,7 @@ interface State {
|
|||
warnThem: boolean;
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Account extends React.Component<Props, State> {
|
||||
export class RawAccount extends React.Component<Props, State> {
|
||||
state: State = { warnThem: false };
|
||||
|
||||
/** WHAT WE NEED: The ability to tell users to check their email if they try
|
||||
|
@ -113,3 +112,5 @@ export class Account extends React.Component<Props, State> {
|
|||
</Page>;
|
||||
}
|
||||
}
|
||||
|
||||
export const Account = connect(mapStateToProps)(RawAccount);
|
||||
|
|
|
@ -97,8 +97,7 @@ const MUST_LOAD: ResourceName[] = [
|
|||
"Tool" // Sequence editor needs this for rendering.
|
||||
];
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class App extends React.Component<AppProps, {}> {
|
||||
export class RawApp extends React.Component<AppProps, {}> {
|
||||
private get isLoaded() {
|
||||
return (MUST_LOAD.length ===
|
||||
intersection(this.props.loaded, MUST_LOAD).length);
|
||||
|
@ -152,3 +151,5 @@ export class App extends React.Component<AppProps, {}> {
|
|||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export const App = connect(mapStateToProps)(RawApp);
|
||||
|
|
|
@ -7,7 +7,10 @@ jest.mock("../../api/crud", () => {
|
|||
});
|
||||
|
||||
jest.mock("../../resources/getters", () => {
|
||||
return { getWebAppConfig: jest.fn(() => (undefined)) };
|
||||
return {
|
||||
getWebAppConfig: jest.fn(() => (undefined)),
|
||||
getFbosConfig: jest.fn(() => (undefined)),
|
||||
};
|
||||
});
|
||||
|
||||
describe("toggleWebAppBool", () => {
|
||||
|
|
|
@ -10,7 +10,7 @@ import { DeepPartial } from "redux";
|
|||
import { AuthState } from "../../../auth/interfaces";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
|
||||
describe("connectDevice()", async () => {
|
||||
describe("connectDevice()", () => {
|
||||
it("connects a FarmBot to the network", async () => {
|
||||
const auth: DeepPartial<AuthState> = { token: {} };
|
||||
const dispatch = jest.fn();
|
||||
|
|
|
@ -2,6 +2,11 @@ import { connectivityReducer, DEFAULT_STATE } from "../reducer";
|
|||
import { networkUp, networkDown } from "../actions";
|
||||
|
||||
describe("connectivityReducer", () => {
|
||||
it("ignores `bot.mqtt` because that is handled by PING_OK/PING_NO", () => {
|
||||
const state = connectivityReducer(DEFAULT_STATE, networkUp("bot.mqtt"));
|
||||
expect(state).toEqual(DEFAULT_STATE);
|
||||
});
|
||||
|
||||
it("goes up", () => {
|
||||
const state = connectivityReducer(DEFAULT_STATE,
|
||||
networkUp("user.mqtt"));
|
||||
|
|
|
@ -24,32 +24,39 @@ export function readPing(bot: Farmbot, direction: Direction): number | undefined
|
|||
}
|
||||
|
||||
export function sendOutboundPing(bot: Farmbot) {
|
||||
const id = uuid();
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = uuid();
|
||||
|
||||
const x = { done: false };
|
||||
const x = { done: false };
|
||||
|
||||
const ok = () => {
|
||||
if (!x.done) {
|
||||
x.done = true;
|
||||
pingOK(id, now());
|
||||
}
|
||||
};
|
||||
const ok = () => {
|
||||
if (!x.done) {
|
||||
x.done = true;
|
||||
pingOK(id, now());
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
const no = () => {
|
||||
if (!x.done) {
|
||||
x.done = true;
|
||||
pingNO(id, now());
|
||||
}
|
||||
};
|
||||
const no = () => {
|
||||
if (!x.done) {
|
||||
x.done = true;
|
||||
pingNO(id, now());
|
||||
reject(new Error("sendOutboundPing failed: " + id));
|
||||
}
|
||||
};
|
||||
|
||||
dispatchQosStart(id);
|
||||
setTimeout(no, PING_INTERVAL + 150);
|
||||
bot.ping().then(ok, no);
|
||||
dispatchQosStart(id);
|
||||
setTimeout(no, PING_INTERVAL + 150);
|
||||
bot.ping().then(ok, no);
|
||||
});
|
||||
}
|
||||
|
||||
const beep = (bot: Farmbot) => sendOutboundPing(bot)
|
||||
.then(() => { }, () => { }); // Silence errors;
|
||||
|
||||
export function startPinging(bot: Farmbot) {
|
||||
sendOutboundPing(bot);
|
||||
setInterval(() => sendOutboundPing(bot), PING_INTERVAL);
|
||||
beep(bot);
|
||||
setInterval(() => beep(bot), PING_INTERVAL);
|
||||
}
|
||||
|
||||
export function pingAPI() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
|
|
|
@ -12,8 +12,7 @@ import { SensorReadings } from "./sensor_readings/sensor_readings";
|
|||
import { isBotOnline } from "../devices/must_be_online";
|
||||
|
||||
/** Controls page. */
|
||||
@connect(mapStateToProps)
|
||||
export class Controls extends React.Component<Props, {}> {
|
||||
export class RawControls extends React.Component<Props, {}> {
|
||||
get arduinoBusy() {
|
||||
return !!this.props.bot.hardware.informational_settings.busy;
|
||||
}
|
||||
|
@ -92,3 +91,5 @@ export class Controls extends React.Component<Props, {}> {
|
|||
</Page>;
|
||||
}
|
||||
}
|
||||
|
||||
export const Controls = connect(mapStateToProps)(RawControls);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
import * as React from "react";
|
||||
import { shallow, render } from "enzyme";
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
let mockReleaseNoteData = {};
|
||||
jest.mock("axios", () => ({
|
||||
get: jest.fn(() => Promise.resolve(mockReleaseNoteData))
|
||||
|
@ -18,7 +19,15 @@ import axios from "axios";
|
|||
import { fakeTimeSettings } from "../../../__test_support__/fake_time_settings";
|
||||
import { edit } from "../../../api/crud";
|
||||
|
||||
describe("<FarmbotOsSettings/>", () => {
|
||||
jest.mock("react-redux", () => ({
|
||||
connect: jest.fn(() => {
|
||||
return () => {
|
||||
return () => "";
|
||||
};
|
||||
})
|
||||
}));
|
||||
|
||||
describe("<FarmbotOsSettings />", () => {
|
||||
beforeEach(() => {
|
||||
window.alert = jest.fn();
|
||||
});
|
||||
|
|
|
@ -16,6 +16,7 @@ import { PowerAndReset } from "./fbos_settings/power_and_reset";
|
|||
import { SendDiagnosticReport } from "./send_diagnostic_report";
|
||||
import axios from "axios";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
import { BootSequenceSelector } from "./fbos_settings/boot_sequence_selector";
|
||||
|
||||
export enum ColWidth {
|
||||
label = 3,
|
||||
|
@ -98,6 +99,16 @@ export class FarmbotOsSettings
|
|||
value={this.props.deviceAccount.body.name} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col xs={ColWidth.label}>
|
||||
<label>
|
||||
{t("BOOT SEQUENCE")}
|
||||
</label>
|
||||
</Col>
|
||||
<Col xs={9}>
|
||||
<BootSequenceSelector />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col xs={ColWidth.label}>
|
||||
<label>
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
import { sequence2ddi, mapStateToProps, RawBootSequenceSelector } from "../boot_sequence_selector";
|
||||
import { fakeSequence, fakeFbosConfig } from "../../../../__test_support__/fake_state/resources";
|
||||
import { fakeState } from "../../../../__test_support__/fake_state";
|
||||
import { buildResourceIndex } from "../../../../__test_support__/resource_index_builder";
|
||||
import React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { FBSelect } from "../../../../ui";
|
||||
// import { mount } from "enzyme";
|
||||
// import React from "react";
|
||||
// import { FBSelect } from "../../../../ui";
|
||||
|
||||
describe("sequence2ddi", () => {
|
||||
it("converts TaggedSequences", () => {
|
||||
const s = fakeSequence();
|
||||
s.body.id = 1;
|
||||
s.body.args.locals.body = [];
|
||||
const result1 = sequence2ddi(s);
|
||||
expect(result1).toBeTruthy();
|
||||
s.body.args.locals.body = undefined;
|
||||
const result2 = sequence2ddi(s);
|
||||
expect(result2).toBeTruthy();
|
||||
});
|
||||
|
||||
it("doesn't convert TaggedSequences with variables", () => {
|
||||
const s = fakeSequence();
|
||||
s.body.id = 1;
|
||||
s.body.args.locals.body = [{
|
||||
kind: "variable_declaration",
|
||||
args: {
|
||||
label: "foo",
|
||||
data_value: {
|
||||
kind: "point",
|
||||
args: {
|
||||
pointer_id: 1,
|
||||
pointer_type: "GenericPointer"
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
const result1 = sequence2ddi(s);
|
||||
expect(result1).not.toBeTruthy();
|
||||
});
|
||||
|
||||
it("doesn't convert TaggedSequences missing an ID", () => {
|
||||
const s = fakeSequence();
|
||||
s.body.id = undefined;
|
||||
const result1 = sequence2ddi(s);
|
||||
expect(result1).not.toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
const fakeProps = () => {
|
||||
const state = fakeState();
|
||||
const sequence = fakeSequence();
|
||||
const config = fakeFbosConfig();
|
||||
sequence.body.id = 1;
|
||||
config.body.boot_sequence_id = 1;
|
||||
state.resources =
|
||||
buildResourceIndex([config, fakeFbosConfig(), sequence]);
|
||||
return mapStateToProps(state);
|
||||
};
|
||||
|
||||
describe("mapStateToProps", () => {
|
||||
it("creates props", () => {
|
||||
const result = fakeProps();
|
||||
if (result.selectedItem) {
|
||||
expect(result.selectedItem.value).toEqual(1);
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
});
|
||||
|
||||
it("crashes when config is missing", () => {
|
||||
const state = fakeState();
|
||||
const boom = () => mapStateToProps(state);
|
||||
expect(boom).toThrowError("No config found?");
|
||||
});
|
||||
});
|
||||
|
||||
describe("RawBootSequenceSelector", () => {
|
||||
it("handles the `onChange` event", () => {
|
||||
const props = fakeProps();
|
||||
const el = new RawBootSequenceSelector(props);
|
||||
el.onChange({ label: "X", value: 3 });
|
||||
expect(props.dispatch).toHaveBeenCalled();
|
||||
expect(props.dispatch)
|
||||
.toHaveBeenCalledWith(expect.objectContaining({ type: "EDIT_RESOURCE" }));
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
const props = fakeProps();
|
||||
const el = mount(<RawBootSequenceSelector {...props} />);
|
||||
expect(el.find(FBSelect).length).toEqual(1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,67 @@
|
|||
import * as React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Everything } from "../../../interfaces";
|
||||
import { getFbosConfig } from "../../../resources/getters";
|
||||
import { FBSelect, DropDownItem } from "../../../ui";
|
||||
import { edit, save } from "../../../api/crud";
|
||||
import { TaggedFbosConfig, TaggedSequence } from "farmbot";
|
||||
import { selectAllSequences, findSequenceById } from "../../../resources/selectors";
|
||||
import { betterCompact } from "../../../util";
|
||||
|
||||
interface Props {
|
||||
list: DropDownItem[];
|
||||
selectedItem: Readonly<DropDownItem> | undefined;
|
||||
config: TaggedFbosConfig;
|
||||
dispatch: Function;
|
||||
}
|
||||
|
||||
export const sequence2ddi = (x: TaggedSequence): DropDownItem | undefined => {
|
||||
const { body } = x;
|
||||
const emptyScope = (body.args.locals.body || []).length == 0;
|
||||
if (emptyScope && body.id) {
|
||||
return { label: body.name, value: body.id };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export function mapStateToProps(p: Everything): Props {
|
||||
const { index } = p.resources;
|
||||
const fbosConfig = getFbosConfig(index);
|
||||
if (fbosConfig) {
|
||||
const list = betterCompact(selectAllSequences(index).map(sequence2ddi));
|
||||
const { boot_sequence_id } = fbosConfig.body;
|
||||
const bs = boot_sequence_id ?
|
||||
findSequenceById(index, boot_sequence_id) : undefined;
|
||||
return {
|
||||
list,
|
||||
selectedItem: bs ? sequence2ddi(bs) : undefined,
|
||||
config: fbosConfig,
|
||||
dispatch: p.dispatch
|
||||
};
|
||||
|
||||
} else {
|
||||
throw new Error("No config found?");
|
||||
}
|
||||
}
|
||||
|
||||
export class RawBootSequenceSelector extends React.Component<Props, {}> {
|
||||
onChange = (_selected: DropDownItem) => {
|
||||
const payload = { boot_sequence_id: _selected.value as number | undefined };
|
||||
this.props.dispatch(edit(this.props.config, payload));
|
||||
this.props.dispatch(save(this.props.config.uuid));
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div>
|
||||
<FBSelect
|
||||
allowEmpty={true}
|
||||
list={this.props.list}
|
||||
selectedItem={this.props.selectedItem}
|
||||
onChange={this.onChange} />
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export const BootSequenceSelector =
|
||||
connect(mapStateToProps)(RawBootSequenceSelector);
|
|
@ -0,0 +1,23 @@
|
|||
jest.mock("../../../connectivity", () => {
|
||||
return {
|
||||
pingNO: jest.fn(),
|
||||
dispatchQosStart: jest.fn()
|
||||
};
|
||||
});
|
||||
import { sendOutboundPing } from "../../../connectivity/ping_mqtt";
|
||||
import { DeepPartial } from "redux";
|
||||
import { Farmbot } from "farmbot";
|
||||
import { pingNO } from "../../../connectivity";
|
||||
|
||||
describe("sendOutboundPing()", () => {
|
||||
it("handles failure", (done) => {
|
||||
const fakeBot: DeepPartial<Farmbot> = {
|
||||
ping: jest.fn(() => Promise.reject())
|
||||
};
|
||||
expect(pingNO).not.toHaveBeenCalled();
|
||||
sendOutboundPing(fakeBot as Farmbot).then(fail, () => {
|
||||
expect(pingNO).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -10,8 +10,7 @@ import { selectAllDiagnosticDumps } from "../resources/selectors";
|
|||
import { getStatus } from "../connectivity/reducer_support";
|
||||
import { isFwHardwareValue } from "./components/firmware_hardware_support";
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Devices extends React.Component<Props, {}> {
|
||||
export class RawDevices extends React.Component<Props, {}> {
|
||||
render() {
|
||||
if (this.props.auth) {
|
||||
const { botToMqtt } = this.props;
|
||||
|
@ -61,3 +60,5 @@ export class Devices extends React.Component<Props, {}> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Devices = connect(mapStateToProps)(RawDevices);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/// <reference path="../typings/index.d.ts" />
|
||||
/// <reference path="./hacks.d.ts" />
|
||||
/**
|
||||
* THIS IS THE ENTRY POINT FOR THE MAIN PORTION OF THE WEB APP.
|
||||
*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
let mockPath = "/app/designer/plants";
|
||||
jest.mock("../../history", () => ({
|
||||
|
@ -12,7 +12,7 @@ jest.mock("../../api/crud", () => ({
|
|||
}));
|
||||
|
||||
import * as React from "react";
|
||||
import { FarmDesigner } from "../index";
|
||||
import { RawFarmDesigner } from "../index";
|
||||
import { mount } from "enzyme";
|
||||
import { Props } from "../interfaces";
|
||||
import { GardenMapLegendProps } from "../map/interfaces";
|
||||
|
@ -27,7 +27,7 @@ import { fakeState } from "../../__test_support__/fake_state";
|
|||
import { edit } from "../../api/crud";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
|
||||
describe("<FarmDesigner/>", () => {
|
||||
describe("<RawFarmDesigner/>", () => {
|
||||
function fakeProps(): Props {
|
||||
|
||||
return {
|
||||
|
@ -63,7 +63,7 @@ describe("<FarmDesigner/>", () => {
|
|||
}
|
||||
|
||||
it("loads default map settings", () => {
|
||||
const wrapper = mount(<FarmDesigner {...fakeProps()} />);
|
||||
const wrapper = mount(<RawFarmDesigner {...fakeProps()} />);
|
||||
const legendProps =
|
||||
wrapper.find("GardenMapLegend").props() as GardenMapLegendProps;
|
||||
expect(legendProps.legendMenuOpen).toBeFalsy();
|
||||
|
@ -86,7 +86,7 @@ describe("<FarmDesigner/>", () => {
|
|||
image1.body.created_at = "2001-01-03T00:00:00.000Z";
|
||||
image2.body.created_at = "2001-01-01T00:00:00.000Z";
|
||||
p.latestImages = [image1, image2];
|
||||
const wrapper = mount(<FarmDesigner {...p} />);
|
||||
const wrapper = mount(<RawFarmDesigner {...p} />);
|
||||
const legendProps =
|
||||
wrapper.find("GardenMapLegend").props() as GardenMapLegendProps;
|
||||
expect(legendProps.imageAgeInfo)
|
||||
|
@ -95,7 +95,7 @@ describe("<FarmDesigner/>", () => {
|
|||
|
||||
it("renders nav titles", () => {
|
||||
mockPath = "/app/designer/plants";
|
||||
const wrapper = mount(<FarmDesigner {...fakeProps()} />);
|
||||
const wrapper = mount(<RawFarmDesigner {...fakeProps()} />);
|
||||
["Map", "Plants", "Events"].map(string =>
|
||||
expect(wrapper.text()).toContain(string));
|
||||
expect(wrapper.find(".panel-nav").first().hasClass("hidden")).toBeTruthy();
|
||||
|
@ -105,7 +105,7 @@ describe("<FarmDesigner/>", () => {
|
|||
|
||||
it("hides panel", () => {
|
||||
mockPath = "/app/designer";
|
||||
const wrapper = mount(<FarmDesigner {...fakeProps()} />);
|
||||
const wrapper = mount(<RawFarmDesigner {...fakeProps()} />);
|
||||
["Map", "Plants", "Events"].map(string =>
|
||||
expect(wrapper.text()).toContain(string));
|
||||
expect(wrapper.find(".panel-nav").first().hasClass("hidden")).toBeFalsy();
|
||||
|
@ -116,7 +116,7 @@ describe("<FarmDesigner/>", () => {
|
|||
it("renders saved garden indicator", () => {
|
||||
const p = fakeProps();
|
||||
p.designer.openedSavedGarden = "SavedGardenUuid";
|
||||
const wrapper = mount(<FarmDesigner {...p} />);
|
||||
const wrapper = mount(<RawFarmDesigner {...p} />);
|
||||
expect(wrapper.text().toLowerCase()).toContain("viewing saved garden");
|
||||
});
|
||||
|
||||
|
@ -126,7 +126,7 @@ describe("<FarmDesigner/>", () => {
|
|||
const dispatch = jest.fn();
|
||||
state.resources = buildResourceIndex([fakeWebAppConfig()]);
|
||||
p.dispatch = jest.fn(x => x(dispatch, () => state));
|
||||
const wrapper = mount<FarmDesigner>(<FarmDesigner {...p} />);
|
||||
const wrapper = mount<RawFarmDesigner>(<RawFarmDesigner {...p} />);
|
||||
wrapper.instance().toggle(BooleanSetting.show_plants)();
|
||||
expect(edit).toHaveBeenCalledWith(expect.any(Object), { bot_origin_quadrant: 2 });
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
const mockDevice = { moveAbsolute: jest.fn(() => Promise.resolve()) };
|
||||
jest.mock("../../device", () => ({ getDevice: () => mockDevice }));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../config_storage/actions", () => ({
|
||||
getWebAppConfigValue: jest.fn(x => { x(); return jest.fn(() => true); }),
|
||||
|
@ -8,7 +8,7 @@ jest.mock("../../config_storage/actions", () => ({
|
|||
import * as React from "react";
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
import {
|
||||
DesignerSettings, DesignerSettingsProps, mapStateToProps
|
||||
RawDesignerSettings, DesignerSettingsProps, mapStateToProps
|
||||
} from "../settings";
|
||||
import { fakeState } from "../../__test_support__/fake_state";
|
||||
import { BooleanSetting, NumericSetting } from "../../session_keys";
|
||||
|
@ -22,14 +22,14 @@ const getSetting =
|
|||
return setting;
|
||||
};
|
||||
|
||||
describe("<DesignerSettings />", () => {
|
||||
describe("<RawDesignerSettings />", () => {
|
||||
const fakeProps = (): DesignerSettingsProps => ({
|
||||
dispatch: jest.fn(),
|
||||
getConfigValue: jest.fn(),
|
||||
});
|
||||
|
||||
it("renders settings", () => {
|
||||
const wrapper = mount(<DesignerSettings {...fakeProps()} />);
|
||||
const wrapper = mount(<RawDesignerSettings {...fakeProps()} />);
|
||||
expect(wrapper.text()).toContain("size");
|
||||
const settings = wrapper.find(".designer-setting");
|
||||
expect(settings.length).toEqual(7);
|
||||
|
@ -38,13 +38,13 @@ describe("<DesignerSettings />", () => {
|
|||
it("renders defaultOn setting", () => {
|
||||
const p = fakeProps();
|
||||
p.getConfigValue = () => undefined;
|
||||
const wrapper = mount(<DesignerSettings {...p} />);
|
||||
const wrapper = mount(<RawDesignerSettings {...p} />);
|
||||
const confirmDeletion = getSetting(wrapper, 6, "confirm plant");
|
||||
expect(confirmDeletion.find("button").text()).toEqual("on");
|
||||
});
|
||||
|
||||
it("toggles setting", () => {
|
||||
const wrapper = mount(<DesignerSettings {...fakeProps()} />);
|
||||
const wrapper = mount(<RawDesignerSettings {...fakeProps()} />);
|
||||
const trailSetting = getSetting(wrapper, 1, "trail");
|
||||
trailSetting.find("button").simulate("click");
|
||||
expect(setWebAppConfigValue)
|
||||
|
@ -54,7 +54,7 @@ describe("<DesignerSettings />", () => {
|
|||
it("changes origin", () => {
|
||||
const p = fakeProps();
|
||||
p.getConfigValue = () => 2;
|
||||
const wrapper = mount(<DesignerSettings {...p} />);
|
||||
const wrapper = mount(<RawDesignerSettings {...p} />);
|
||||
const originSetting = getSetting(wrapper, 5, "origin");
|
||||
originSetting.find("div").last().simulate("click");
|
||||
expect(setWebAppConfigValue).toHaveBeenCalledWith(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../../history", () => ({ history: { push: jest.fn() } }));
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
jest.mock("react-redux", () => ({
|
||||
connect: jest.fn()
|
||||
connect: jest.fn(() => (x: {}) => x)
|
||||
}));
|
||||
|
||||
jest.mock("../../../history", () => ({
|
||||
|
|
|
@ -22,8 +22,7 @@ interface State {
|
|||
uuid: string;
|
||||
}
|
||||
|
||||
@connect(mapStateToPropsAddEdit)
|
||||
export class AddFarmEvent
|
||||
export class RawAddFarmEvent
|
||||
extends React.Component<AddEditFarmEventProps, Partial<State>> {
|
||||
|
||||
constructor(props: AddEditFarmEventProps) {
|
||||
|
@ -122,3 +121,5 @@ export class AddFarmEvent
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const AddFarmEvent = connect(mapStateToPropsAddEdit)(RawAddFarmEvent);
|
||||
|
|
|
@ -7,8 +7,7 @@ import { TaggedFarmEvent } from "farmbot";
|
|||
import { EditFEForm } from "./edit_fe_form";
|
||||
import { t } from "../../i18next_wrapper";
|
||||
|
||||
@connect(mapStateToPropsAddEdit)
|
||||
export class EditFarmEvent extends React.Component<AddEditFarmEventProps, {}> {
|
||||
export class RawEditFarmEvent extends React.Component<AddEditFarmEventProps, {}> {
|
||||
redirect() {
|
||||
history.push("/app/designer/events");
|
||||
return <div>{t("Loading")}...</div>;
|
||||
|
@ -34,3 +33,5 @@ export class EditFarmEvent extends React.Component<AddEditFarmEventProps, {}> {
|
|||
return fe ? this.renderForm(fe) : this.redirect();
|
||||
}
|
||||
}
|
||||
|
||||
export const EditFarmEvent = connect(mapStateToPropsAddEdit)(RawEditFarmEvent);
|
||||
|
|
|
@ -45,8 +45,7 @@ export const getGridSize =
|
|||
|
||||
export const gridOffset: AxisNumberProperty = { x: 50, y: 50 };
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
||||
export class RawFarmDesigner extends React.Component<Props, Partial<State>> {
|
||||
|
||||
initializeSetting =
|
||||
(name: keyof State, defaultValue: boolean): boolean => {
|
||||
|
@ -201,3 +200,5 @@ export class FarmDesigner extends React.Component<Props, Partial<State>> {
|
|||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export const FarmDesigner = connect(mapStateToProps)(RawFarmDesigner);
|
||||
|
|
|
@ -99,8 +99,7 @@ export class MoveToForm extends React.Component<MoveToFormProps, MoveToFormState
|
|||
}
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class MoveTo extends React.Component<MoveToProps, {}> {
|
||||
export class RawMoveTo extends React.Component<MoveToProps, {}> {
|
||||
|
||||
componentDidMount() {
|
||||
unselectPlant(this.props.dispatch)();
|
||||
|
@ -153,3 +152,5 @@ export const chooseLocation = (props: {
|
|||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const MoveTo = connect(mapStateToProps)(RawMoveTo);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
let mockPath = "";
|
||||
jest.mock("../../../history", () => ({
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
jest.mock("react-redux", () => ({
|
||||
connect: jest.fn()
|
||||
connect: jest.fn(() => (x: {}) => x)
|
||||
}));
|
||||
|
||||
jest.mock("../../../api/crud", () => ({
|
||||
|
@ -13,7 +13,7 @@ jest.mock("../../../farmware/weed_detector/actions", () => ({
|
|||
import * as React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import {
|
||||
CreatePoints,
|
||||
RawCreatePoints as CreatePoints,
|
||||
CreatePointsProps,
|
||||
mapStateToProps
|
||||
} from "../create_points";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
jest.mock("react-redux", () => ({
|
||||
connect: jest.fn()
|
||||
connect: jest.fn(() => (x: {}) => x)
|
||||
}));
|
||||
|
||||
jest.mock("lodash", () => ({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
let mockPath = "";
|
||||
jest.mock("../../../history", () => ({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
let mockPath = "/app/designer/plants/1";
|
||||
jest.mock("../../../history", () => ({
|
||||
|
@ -13,7 +13,7 @@ jest.mock("../../../api/crud", () => ({
|
|||
}));
|
||||
|
||||
import * as React from "react";
|
||||
import { PlantInfo } from "../plant_info";
|
||||
import { RawPlantInfo as PlantInfo } from "../plant_info";
|
||||
import { mount } from "enzyme";
|
||||
import { fakePlant } from "../../../__test_support__/fake_state/resources";
|
||||
import { EditPlantInfoProps } from "../../interfaces";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
import * as React from "react";
|
||||
import { Plants, PlantInventoryProps } from "../plant_inventory";
|
||||
import { RawPlants, PlantInventoryProps } from "../plant_inventory";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { fakePlant } from "../../../__test_support__/fake_state/resources";
|
||||
|
||||
|
@ -13,7 +13,7 @@ describe("<PlantInventory />", () => {
|
|||
});
|
||||
|
||||
it("renders", () => {
|
||||
const wrapper = mount(<Plants {...fakeProps()} />);
|
||||
const wrapper = mount(<RawPlants {...fakeProps()} />);
|
||||
["Map",
|
||||
"Plants",
|
||||
"Events",
|
||||
|
@ -25,13 +25,13 @@ describe("<PlantInventory />", () => {
|
|||
});
|
||||
|
||||
it("has link to crops", () => {
|
||||
const wrapper = mount(<Plants {...fakeProps()} />);
|
||||
const wrapper = mount(<RawPlants {...fakeProps()} />);
|
||||
expect(wrapper.html()).toContain("fa-plus");
|
||||
expect(wrapper.html()).toContain("/app/designer/plants/crop_search");
|
||||
});
|
||||
|
||||
it("updates search term", () => {
|
||||
const wrapper = shallow<Plants>(<Plants {...fakeProps()} />);
|
||||
const wrapper = shallow<RawPlants>(<RawPlants {...fakeProps()} />);
|
||||
expect(wrapper.state().searchTerm).toEqual("");
|
||||
wrapper.find("input").first().simulate("change",
|
||||
{ currentTarget: { value: "mint" } });
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
let mockPath = "/app/designer/points/1";
|
||||
jest.mock("../../../history", () => ({
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../../history", () => ({
|
||||
push: jest.fn(),
|
||||
|
@ -7,7 +7,7 @@ jest.mock("../../../history", () => ({
|
|||
|
||||
import * as React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { Points, PointsProps } from "../point_inventory";
|
||||
import { RawPoints, PointsProps } from "../point_inventory";
|
||||
import { fakePoint } from "../../../__test_support__/fake_state/resources";
|
||||
import { push } from "../../../history";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
|
@ -16,21 +16,21 @@ import {
|
|||
} from "../../../__test_support__/resource_index_builder";
|
||||
import { mapStateToProps } from "../point_inventory";
|
||||
|
||||
describe("<Points />", () => {
|
||||
describe("<RawPoints> />", () => {
|
||||
const fakeProps = (): PointsProps => ({
|
||||
points: [],
|
||||
dispatch: jest.fn(),
|
||||
});
|
||||
|
||||
it("renders no points", () => {
|
||||
const wrapper = mount(<Points {...fakeProps()} />);
|
||||
const wrapper = mount(<RawPoints {...fakeProps()} />);
|
||||
expect(wrapper.text()).toContain("No points yet.");
|
||||
});
|
||||
|
||||
it("renders points", () => {
|
||||
const p = fakeProps();
|
||||
p.points = [fakePoint()];
|
||||
const wrapper = mount(<Points {...p} />);
|
||||
const wrapper = mount(<RawPoints {...p} />);
|
||||
expect(wrapper.text()).toContain("Point 1");
|
||||
});
|
||||
|
||||
|
@ -38,7 +38,7 @@ describe("<Points />", () => {
|
|||
const p = fakeProps();
|
||||
p.points = [fakePoint()];
|
||||
p.points[0].body.id = 1;
|
||||
const wrapper = mount(<Points {...p} />);
|
||||
const wrapper = mount(<RawPoints {...p} />);
|
||||
wrapper.find(".point-search-item").first().simulate("click");
|
||||
expect(push).toHaveBeenCalledWith("/app/designer/points/1");
|
||||
});
|
||||
|
@ -48,7 +48,7 @@ describe("<Points />", () => {
|
|||
p.points = [fakePoint(), fakePoint()];
|
||||
p.points[0].body.name = "point 0";
|
||||
p.points[1].body.name = "point 1";
|
||||
const wrapper = shallow<Points>(<Points {...p} />);
|
||||
const wrapper = shallow<RawPoints>(<RawPoints {...p} />);
|
||||
wrapper.find("input").first().simulate("change",
|
||||
{ currentTarget: { value: "0" } });
|
||||
expect(wrapper.state().searchTerm).toEqual("0");
|
||||
|
@ -59,7 +59,7 @@ describe("<Points />", () => {
|
|||
p.points = [fakePoint(), fakePoint()];
|
||||
p.points[0].body.name = "point 0";
|
||||
p.points[1].body.name = "point 1";
|
||||
const wrapper = mount(<Points {...p} />);
|
||||
const wrapper = mount(<RawPoints {...p} />);
|
||||
wrapper.setState({ searchTerm: "0" });
|
||||
expect(wrapper.text()).not.toContain("point 1");
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
let mockPath = "";
|
||||
jest.mock("../../../history", () => ({
|
||||
|
|
|
@ -42,8 +42,7 @@ export interface AddPlantProps {
|
|||
openfarmSearch: OpenfarmSearch;
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class AddPlant extends React.Component<AddPlantProps, {}> {
|
||||
export class RawAddPlant extends React.Component<AddPlantProps, {}> {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch(searchForCurrentCrop(this.props.openfarmSearch));
|
||||
|
@ -72,3 +71,5 @@ export class AddPlant extends React.Component<AddPlantProps, {}> {
|
|||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
export const AddPlant = connect(mapStateToProps)(RawAddPlant);
|
||||
|
|
|
@ -50,8 +50,7 @@ const DEFAULTS: CurrentPointPayl = {
|
|||
color: "red"
|
||||
};
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class CreatePoints
|
||||
export class RawCreatePoints
|
||||
extends React.Component<CreatePointsProps, Partial<CreatePointsState>> {
|
||||
constructor(props: CreatePointsProps) {
|
||||
super(props);
|
||||
|
@ -250,3 +249,5 @@ export class CreatePoints
|
|||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
export const CreatePoints = connect(mapStateToProps)(RawCreatePoints);
|
||||
|
|
|
@ -28,8 +28,7 @@ export function mapStateToProps(props: Everything): CropCatalogProps {
|
|||
};
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class CropCatalog extends React.Component<CropCatalogProps, {}> {
|
||||
export class RawCropCatalog extends React.Component<CropCatalogProps, {}> {
|
||||
|
||||
debouncedOFSearch = debounce((searchTerm: string) => {
|
||||
this.props.openfarmSearch(searchTerm)(this.props.dispatch);
|
||||
|
@ -99,3 +98,5 @@ export class CropCatalog extends React.Component<CropCatalogProps, {}> {
|
|||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
export const CropCatalog = connect(mapStateToProps)(RawCropCatalog);
|
||||
|
|
|
@ -219,8 +219,7 @@ export const searchForCurrentCrop = (openfarmSearch: OpenfarmSearch) =>
|
|||
unselectPlant(dispatch)();
|
||||
};
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class CropInfo extends React.Component<CropInfoProps, {}> {
|
||||
export class RawCropInfo extends React.Component<CropInfoProps, {}> {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch(searchForCurrentCrop(this.props.openfarmSearch));
|
||||
|
@ -270,3 +269,5 @@ export class CropInfo extends React.Component<CropInfoProps, {}> {
|
|||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
export const CropInfo = connect(mapStateToProps)(RawCropInfo);
|
||||
|
|
|
@ -12,8 +12,7 @@ import { history, getPathArray } from "../../history";
|
|||
import { destroy, edit, save } from "../../api/crud";
|
||||
import { BooleanSetting } from "../../session_keys";
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class PlantInfo extends React.Component<EditPlantInfoProps, {}> {
|
||||
export class RawPlantInfo extends React.Component<EditPlantInfoProps, {}> {
|
||||
get templates() { return isString(this.props.openedSavedGarden); }
|
||||
get stringyID() { return getPathArray()[this.templates ? 5 : 4] || ""; }
|
||||
get plant() { return this.props.findPlant(this.stringyID); }
|
||||
|
@ -64,3 +63,5 @@ export class PlantInfo extends React.Component<EditPlantInfoProps, {}> {
|
|||
return plant_info ? this.default(plant_info) : this.fallback();
|
||||
}
|
||||
}
|
||||
|
||||
export const PlantInfo = connect(mapStateToProps)(RawPlantInfo);
|
||||
|
|
|
@ -34,8 +34,7 @@ function mapStateToProps(props: Everything): PlantInventoryProps {
|
|||
};
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Plants extends React.Component<PlantInventoryProps, State> {
|
||||
export class RawPlants extends React.Component<PlantInventoryProps, State> {
|
||||
|
||||
state: State = { searchTerm: "" };
|
||||
|
||||
|
@ -72,3 +71,5 @@ export class Plants extends React.Component<PlantInventoryProps, State> {
|
|||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
export const Plants = connect(mapStateToProps)(RawPlants);
|
||||
|
|
|
@ -24,8 +24,7 @@ export const mapStateToProps = (props: Everything): EditPointProps => ({
|
|||
findPoint: id => maybeFindPointById(props.resources.index, id),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class EditPoint extends React.Component<EditPointProps, {}> {
|
||||
export class RawEditPoint extends React.Component<EditPointProps, {}> {
|
||||
get stringyID() { return getPathArray()[4] || ""; }
|
||||
get point() {
|
||||
if (this.stringyID) {
|
||||
|
@ -84,3 +83,5 @@ export class EditPoint extends React.Component<EditPointProps, {}> {
|
|||
return this.point ? this.default(this.point) : this.fallback();
|
||||
}
|
||||
}
|
||||
|
||||
export const EditPoint = connect(mapStateToProps)(RawEditPoint);
|
||||
|
|
|
@ -31,9 +31,7 @@ export function mapStateToProps(props: Everything): PointsProps {
|
|||
};
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Points extends React.Component<PointsProps, PointsState> {
|
||||
|
||||
export class RawPoints extends React.Component<PointsProps, PointsState> {
|
||||
state: PointsState = { searchTerm: "" };
|
||||
|
||||
update = ({ currentTarget }: React.SyntheticEvent<HTMLInputElement>) => {
|
||||
|
@ -71,3 +69,5 @@ export class Points extends React.Component<PointsProps, PointsState> {
|
|||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
export const Points = connect(mapStateToProps)(RawPoints);
|
||||
|
|
|
@ -29,10 +29,7 @@ export interface SelectPlantsProps {
|
|||
selected: string[];
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class SelectPlants
|
||||
extends React.Component<SelectPlantsProps, {}> {
|
||||
|
||||
export class RawSelectPlants extends React.Component<SelectPlantsProps, {}> {
|
||||
componentDidMount() {
|
||||
const { dispatch, selected } = this.props;
|
||||
if (selected && selected.length == 1) {
|
||||
|
@ -116,3 +113,5 @@ export class SelectPlants
|
|||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
export const SelectPlants = connect(mapStateToProps)(RawSelectPlants);
|
||||
|
|
|
@ -45,7 +45,7 @@ describe("<GroupDetail />", () => {
|
|||
mockId = -23;
|
||||
const store = fakeStore();
|
||||
const el = mount(<Provider store={store}>
|
||||
<GroupDetail {...({} as GroupDetail["props"])} />
|
||||
<GroupDetail />
|
||||
</Provider>);
|
||||
const result = el.find(GroupDetailActive);
|
||||
expect(result.length).toEqual(0);
|
||||
|
@ -56,7 +56,7 @@ describe("<GroupDetail />", () => {
|
|||
mockId = GOOD_ID;
|
||||
const store = fakeStore();
|
||||
const el = mount(<Provider store={store}>
|
||||
<GroupDetail {...({} as GroupDetail["props"])} />
|
||||
<GroupDetail />
|
||||
</Provider>);
|
||||
const result = el.find(GroupDetailActive);
|
||||
expect(result.length).toEqual(1);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../../history", () => ({
|
||||
getPathArray: jest.fn(() => ["L", "O", "L"]),
|
||||
|
@ -7,7 +7,7 @@ jest.mock("../../../history", () => ({
|
|||
|
||||
import React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { GroupListPanel, GroupListPanelProps, mapStateToProps } from "../group_list_panel";
|
||||
import { RawGroupListPanel as GroupListPanel, GroupListPanelProps, mapStateToProps } from "../group_list_panel";
|
||||
import { fakePointGroup } from "../../../__test_support__/fake_state/resources";
|
||||
import { history } from "../../../history";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
|
|
|
@ -53,8 +53,7 @@ function mapStateToProps(props: Everything): GroupDetailProps {
|
|||
return { plants, group, dispatch: props.dispatch };
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class GroupDetail extends React.Component<GroupDetailProps, {}> {
|
||||
export class RawGroupDetail extends React.Component<GroupDetailProps, {}> {
|
||||
|
||||
render() {
|
||||
const { group } = this.props;
|
||||
|
@ -66,3 +65,4 @@ export class GroupDetail extends React.Component<GroupDetailProps, {}> {
|
|||
}
|
||||
}
|
||||
}
|
||||
export const GroupDetail = connect(mapStateToProps)(RawGroupDetail);
|
||||
|
|
|
@ -28,8 +28,7 @@ export function mapStateToProps(props: Everything): GroupListPanelProps {
|
|||
return { groups, dispatch: props.dispatch };
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class GroupListPanel extends React.Component<GroupListPanelProps, State> {
|
||||
export class RawGroupListPanel extends React.Component<GroupListPanelProps, State> {
|
||||
|
||||
state: State = { searchTerm: "" };
|
||||
|
||||
|
@ -72,3 +71,5 @@ export class GroupListPanel extends React.Component<GroupListPanelProps, State>
|
|||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
export const GroupListPanel = connect(mapStateToProps)(RawGroupListPanel);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../actions", () => ({
|
||||
snapshotGarden: jest.fn(),
|
||||
|
|
|
@ -28,8 +28,7 @@ export const mapStateToProps = (props: Everything): SavedGardensProps => ({
|
|||
openedSavedGarden: props.resources.consumers.farm_designer.openedSavedGarden,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class SavedGardens extends React.Component<SavedGardensProps, {}> {
|
||||
export class RawSavedGardens extends React.Component<SavedGardensProps, {}> {
|
||||
|
||||
componentDidMount() {
|
||||
unselectPlant(this.props.dispatch)();
|
||||
|
@ -104,3 +103,5 @@ export const SavedGardenHUD = (props: { dispatch: Function }) =>
|
|||
{t("Exit")}
|
||||
</button>
|
||||
</div>;
|
||||
|
||||
export const SavedGardens = connect(mapStateToProps)(RawSavedGardens);
|
||||
|
|
|
@ -26,8 +26,7 @@ export interface DesignerSettingsProps {
|
|||
getConfigValue: GetWebAppConfigValue;
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class DesignerSettings
|
||||
export class RawDesignerSettings
|
||||
extends React.Component<DesignerSettingsProps, {}> {
|
||||
|
||||
render() {
|
||||
|
@ -142,3 +141,5 @@ const OriginSelector = (props: DesignerSettingsProps) => {
|
|||
</div>
|
||||
</div>;
|
||||
};
|
||||
|
||||
export const DesignerSettings = connect(mapStateToProps)(RawDesignerSettings);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../../api/crud", () => ({ initSave: jest.fn() }));
|
||||
|
||||
import * as React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { AddTool, AddToolProps, mapStateToProps } from "../add_tool";
|
||||
import { RawAddTool as AddTool, AddToolProps, mapStateToProps } from "../add_tool";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
import { SaveBtn } from "../../../ui";
|
||||
import { initSave } from "../../../api/crud";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../../api/crud", () => ({ edit: jest.fn() }));
|
||||
|
||||
|
@ -9,7 +9,7 @@ jest.mock("../../../history", () => ({
|
|||
|
||||
import * as React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { EditTool, EditToolProps, mapStateToProps } from "../edit_tool";
|
||||
import { RawEditTool as EditTool, EditToolProps, mapStateToProps } from "../edit_tool";
|
||||
import { fakeTool } from "../../../__test_support__/fake_state/resources";
|
||||
import { fakeState } from "../../../__test_support__/fake_state";
|
||||
import {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../../history", () => ({
|
||||
history: { push: jest.fn() },
|
||||
|
@ -7,7 +7,7 @@ jest.mock("../../../history", () => ({
|
|||
|
||||
import * as React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { Tools, ToolsProps, mapStateToProps } from "../index";
|
||||
import { RawTools as Tools, ToolsProps, mapStateToProps } from "../index";
|
||||
import {
|
||||
fakeTool, fakeToolSlot
|
||||
} from "../../../__test_support__/fake_state/resources";
|
||||
|
|
|
@ -21,8 +21,7 @@ export const mapStateToProps = (props: Everything): AddToolProps => ({
|
|||
dispatch: props.dispatch,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class AddTool extends React.Component<AddToolProps, AddToolState> {
|
||||
export class RawAddTool extends React.Component<AddToolProps, AddToolState> {
|
||||
state: AddToolState = { toolName: "" };
|
||||
render() {
|
||||
return <DesignerPanel panelName={"tool"} panelColor={"gray"}>
|
||||
|
@ -43,3 +42,5 @@ export class AddTool extends React.Component<AddToolProps, AddToolState> {
|
|||
</DesignerPanel>;
|
||||
}
|
||||
}
|
||||
|
||||
export const AddTool = connect(mapStateToProps)(RawAddTool);
|
||||
|
|
|
@ -27,8 +27,7 @@ export const mapStateToProps = (props: Everything): EditToolProps => ({
|
|||
dispatch: props.dispatch,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class EditTool extends React.Component<EditToolProps, EditToolState> {
|
||||
export class RawEditTool extends React.Component<EditToolProps, EditToolState> {
|
||||
state: EditToolState = { toolName: this.tool ? this.tool.body.name || "" : "" };
|
||||
|
||||
get stringyID() { return getPathArray()[4] || ""; }
|
||||
|
@ -65,3 +64,5 @@ export class EditTool extends React.Component<EditToolProps, EditToolState> {
|
|||
return this.tool ? this.default(this.tool) : this.fallback();
|
||||
}
|
||||
}
|
||||
|
||||
export const EditTool = connect(mapStateToProps)(RawEditTool);
|
||||
|
|
|
@ -34,8 +34,7 @@ export const mapStateToProps = (props: Everything): ToolsProps => ({
|
|||
dispatch: props.dispatch,
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Tools extends React.Component<ToolsProps, ToolsState> {
|
||||
export class RawTools extends React.Component<ToolsProps, ToolsState> {
|
||||
state: ToolsState = { searchTerm: "" };
|
||||
|
||||
update = ({ currentTarget }: React.SyntheticEvent<HTMLInputElement>) => {
|
||||
|
@ -125,3 +124,5 @@ const ToolInventoryItem = (props: ToolInventoryItemProps) =>
|
|||
</p>
|
||||
</Col>
|
||||
</Row>;
|
||||
|
||||
export const Tools = connect(mapStateToProps)(RawTools);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
const mockDevice = { execScript: jest.fn(() => Promise.resolve({})) };
|
||||
jest.mock("../../device", () => ({ getDevice: () => mockDevice }));
|
||||
|
|
|
@ -115,8 +115,7 @@ export const BasicFarmwarePage = ({ farmwareName, farmware, botOnline }:
|
|||
</p>
|
||||
</div>;
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class FarmwarePage extends React.Component<FarmwareProps, {}> {
|
||||
export class RawFarmwarePage extends React.Component<FarmwareProps, {}> {
|
||||
get current() { return this.props.currentFarmware; }
|
||||
|
||||
get botOnline() {
|
||||
|
@ -264,3 +263,5 @@ export class FarmwarePage extends React.Component<FarmwareProps, {}> {
|
|||
</Page>;
|
||||
}
|
||||
}
|
||||
|
||||
export const FarmwarePage = connect(mapStateToProps)(RawFarmwarePage);
|
||||
|
|
|
@ -8,16 +8,13 @@ jest.mock("../../../device", () => ({
|
|||
return mockDevice;
|
||||
}
|
||||
}));
|
||||
|
||||
jest.mock("react-redux", () => ({
|
||||
connect: jest.fn()
|
||||
}));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../images/actions", () => ({ selectImage: jest.fn() }));
|
||||
|
||||
import * as React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { WeedDetector, namespace } from "../index";
|
||||
import { RawWeedDetector as WeedDetector, namespace } from "../index";
|
||||
import { FarmwareProps } from "../../../devices/interfaces";
|
||||
import { API } from "../../../api";
|
||||
import { selectImage } from "../../images/actions";
|
||||
|
|
|
@ -23,8 +23,7 @@ export const namespace = (prefix: string) => (key: string): WDENVKey => {
|
|||
}
|
||||
};
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class WeedDetector
|
||||
export class RawWeedDetector
|
||||
extends React.Component<FarmwareProps, Partial<DetectorState>> {
|
||||
|
||||
constructor(props: FarmwareProps) {
|
||||
|
@ -103,3 +102,5 @@ export class WeedDetector
|
|||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
export const WeedDetector = connect(mapStateToProps)(RawWeedDetector);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/// <reference path="react-redux.d.ts" />
|
||||
|
||||
/** This contains all of the global ENV vars passed from server => client.
|
||||
* Previously was `process.env.XYZ`. */
|
||||
declare var globalConfig: { [k: string]: string };
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
|
|
|
@ -11,8 +11,7 @@ export function mapStateToProps(props: Everything): { dispatch: Function } {
|
|||
return { dispatch };
|
||||
}
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Help extends React.Component<{ dispatch: Function }, {}> {
|
||||
export class RawHelp extends React.Component<{ dispatch: Function }, {}> {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch({ type: Actions.START_TOUR, payload: undefined });
|
||||
|
@ -27,3 +26,5 @@ export class Help extends React.Component<{ dispatch: Function }, {}> {
|
|||
</Page>;
|
||||
}
|
||||
}
|
||||
|
||||
export const Help = connect(mapStateToProps)(RawHelp);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
const mockStorj: Dictionary<number | boolean> = {};
|
||||
|
||||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
import { Logs } from "../index";
|
||||
import { RawLogs as Logs } from "../index";
|
||||
import { ToolTips } from "../../constants";
|
||||
import { TaggedLog, Dictionary } from "farmbot";
|
||||
import { NumericSetting } from "../../session_keys";
|
||||
|
|
|
@ -25,8 +25,7 @@ export const formatLogTime =
|
|||
.utcOffset(timeSettings.utcOffset)
|
||||
.format(`MMM D, ${timeFormatString(timeSettings)}`);
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
|
||||
export class RawLogs extends React.Component<LogsProps, Partial<LogsState>> {
|
||||
|
||||
/** Initialize log type verbosity level to the configured or default value. */
|
||||
initialize = (name: NumberConfigKey, defaultValue: number): number => {
|
||||
|
@ -131,3 +130,5 @@ export class Logs extends React.Component<LogsProps, Partial<LogsState>> {
|
|||
</Page>;
|
||||
}
|
||||
}
|
||||
|
||||
export const Logs = connect(mapStateToProps)(RawLogs);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
import * as React from "react";
|
||||
import { mount } from "enzyme";
|
||||
|
|
|
@ -7,8 +7,7 @@ import { mapStateToProps } from "./state_to_props";
|
|||
import { MessagesProps } from "./interfaces";
|
||||
import { Link } from "../link";
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Messages extends React.Component<MessagesProps, {}> {
|
||||
export class RawMessages extends React.Component<MessagesProps, {}> {
|
||||
render() {
|
||||
return <Page className="messages-page">
|
||||
<Row>
|
||||
|
@ -35,3 +34,5 @@ export class Messages extends React.Component<MessagesProps, {}> {
|
|||
</Page>;
|
||||
}
|
||||
}
|
||||
|
||||
export const Messages = connect(mapStateToProps)(RawMessages);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../history", () => ({
|
||||
push: () => jest.fn(),
|
||||
|
|
|
@ -27,8 +27,7 @@ export const RegimenBackButton = (props: RegimenBackButtonProps) => {
|
|||
title={schedulerOpen ? t("back to regimen") : t("back to regimens")} />;
|
||||
};
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Regimens extends React.Component<Props, {}> {
|
||||
export class RawRegimens extends React.Component<Props, {}> {
|
||||
UNSAFE_componentWillMount() {
|
||||
if (!this.props.current) { setActiveRegimenByName(); }
|
||||
}
|
||||
|
@ -87,3 +86,4 @@ export class Regimens extends React.Component<Props, {}> {
|
|||
</Page>;
|
||||
}
|
||||
}
|
||||
export const Regimens = connect(mapStateToProps)(RawRegimens);
|
||||
|
|
|
@ -26,10 +26,11 @@ describe("resourceUsageList", () => {
|
|||
"Sequence.Sequence": {
|
||||
"Regimen.9.9": { "Sequence.10.10": true, "Sequence.11.11": true }
|
||||
},
|
||||
"Sequence.FbosConfig": { "Device.99.99": { "Sequence.12.12": true } }
|
||||
};
|
||||
const actual = Object.keys(resourceUsageList(x)).sort();
|
||||
const expected =
|
||||
["FarmEvent.0.0", "FarmEvent.3.3", "Regimen.6.6", "Regimen.9.9"].sort();
|
||||
["FarmEvent.0.0", "FarmEvent.3.3", "Regimen.6.6", "Regimen.9.9", "Device.99.99"].sort();
|
||||
expect(actual.length).toEqual(expected.length);
|
||||
expected.map(y => expect(actual).toContain(y));
|
||||
});
|
||||
|
|
|
@ -21,7 +21,8 @@ export type UsageKind =
|
|||
| "Regimen.FarmEvent"
|
||||
| "Sequence.Regimen"
|
||||
| "Sequence.FarmEvent"
|
||||
| "Sequence.Sequence";
|
||||
| "Sequence.Sequence"
|
||||
| "Sequence.FbosConfig";
|
||||
|
||||
/** This variable ensures that `EVERY_USAGE_KIND` does not have typos and is
|
||||
* up-to-date all `UsageKind`s */
|
||||
|
@ -30,6 +31,7 @@ const values: Record<UsageKind, UsageKind> = {
|
|||
"Sequence.Regimen": "Sequence.Regimen",
|
||||
"Sequence.FarmEvent": "Sequence.FarmEvent",
|
||||
"Sequence.Sequence": "Sequence.Sequence",
|
||||
"Sequence.FbosConfig": "Sequence.FbosConfig"
|
||||
};
|
||||
|
||||
/** Array that contains every `UsageKind` token for easy runtime iteration. */
|
||||
|
|
|
@ -72,6 +72,7 @@ export const emptyState = (): RestResources => {
|
|||
"Sequence.FarmEvent": {},
|
||||
"Sequence.Regimen": {},
|
||||
"Sequence.Sequence": {},
|
||||
"Sequence.FbosConfig": {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
selectAllFarmEvents,
|
||||
findByKindAndId,
|
||||
selectAllLogs,
|
||||
selectAllRegimens
|
||||
selectAllRegimens,
|
||||
} from "./selectors_by_kind";
|
||||
import { ExecutableType } from "farmbot/dist/resources/api_resources";
|
||||
import { betterCompact, unpackUUID } from "../util";
|
||||
|
@ -28,6 +28,7 @@ import { ReduxAction } from "../redux/interfaces";
|
|||
import { ActionHandler } from "../redux/generate_reducer";
|
||||
import { get } from "lodash";
|
||||
import { Actions } from "../constants";
|
||||
import { getFbosConfig } from "./getters";
|
||||
|
||||
export function findByUuid(index: ResourceIndex, uuid: string): TaggedResource {
|
||||
const x = index.references[uuid];
|
||||
|
@ -195,6 +196,23 @@ const BEFORE_HOOKS: IndexerHook = {
|
|||
};
|
||||
|
||||
const AFTER_HOOKS: IndexerHook = {
|
||||
FbosConfig: (i) => {
|
||||
const conf = getFbosConfig(i);
|
||||
|
||||
if (conf && conf.body.boot_sequence_id) {
|
||||
const { boot_sequence_id } = conf.body;
|
||||
const tracker = i.inUse["Sequence.FbosConfig"];
|
||||
const uuid = i.byKindAndId[joinKindAndId("Sequence", boot_sequence_id)];
|
||||
if (uuid) {
|
||||
console.log("Hmmm");
|
||||
console.log("DING !");
|
||||
tracker[uuid] = tracker[uuid] || {};
|
||||
tracker[uuid][conf.uuid] = true;
|
||||
}
|
||||
} else {
|
||||
i.inUse["Sequence.FbosConfig"] = {};
|
||||
}
|
||||
},
|
||||
FarmEvent: reindexAllFarmEventUsage,
|
||||
Sequence: reindexAllSequences,
|
||||
Regimen: (i) => {
|
||||
|
|
|
@ -51,7 +51,7 @@ export class RootComponent extends React.Component<RootComponentProps, RootCompo
|
|||
try {
|
||||
return <ErrorBoundary>
|
||||
<Provider store={_store}>
|
||||
<App {...{} as App["props"]}>
|
||||
<App>
|
||||
<Route {...props} />
|
||||
</App>
|
||||
</Provider>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
jest.mock("../../history", () => ({
|
||||
push: jest.fn(),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
jest.mock("react-redux", () => ({ connect: jest.fn() }));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
import { mapStateToProps } from "../state_to_props";
|
||||
import { fakeState } from "../../__test_support__/fake_state";
|
||||
|
|
|
@ -29,8 +29,7 @@ export const SequenceBackButton = (props: SequenceBackButtonProps) => {
|
|||
title={insertingStep ? t("back to sequence") : t("back to sequences")} />;
|
||||
};
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Sequences extends React.Component<Props, {}> {
|
||||
export class RawSequences extends React.Component<Props, {}> {
|
||||
UNSAFE_componentWillMount() {
|
||||
if (!this.props.sequence) { setActiveSequenceByName(); }
|
||||
}
|
||||
|
@ -90,3 +89,5 @@ export class Sequences extends React.Component<Props, {}> {
|
|||
</Page>;
|
||||
}
|
||||
}
|
||||
|
||||
export const Sequences = connect(mapStateToProps)(RawSequences);
|
||||
|
|
|
@ -63,7 +63,6 @@ export async function fetchSyncData(dispatch: Function) {
|
|||
0: () => Promise.all<{}>([
|
||||
get("User", API.current.usersPath),
|
||||
get("Device", API.current.devicePath),
|
||||
get("FbosConfig", API.current.fbosConfigPath),
|
||||
get("FirmwareConfig", API.current.firmwareConfigPath),
|
||||
get("FarmwareEnv", API.current.farmwareEnvPath),
|
||||
get("FarmwareInstallation", API.current.farmwareInstallationPath),
|
||||
|
@ -84,6 +83,7 @@ export async function fetchSyncData(dispatch: Function) {
|
|||
get("PointGroup", API.current.pointGroupsPath)
|
||||
]),
|
||||
3: () => Promise.all<{}>([
|
||||
get("FbosConfig", API.current.fbosConfigPath),
|
||||
get("Regimen", API.current.regimensPath),
|
||||
get("PinBinding", API.current.pinBindingPath),
|
||||
]),
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
jest.mock("react-redux", () => ({
|
||||
connect: jest.fn()
|
||||
}));
|
||||
jest.mock("react-redux", () => ({ connect: jest.fn(() => (x: {}) => x) }));
|
||||
|
||||
import * as React from "react";
|
||||
import { mount, shallow } from "enzyme";
|
||||
|
|
|
@ -5,8 +5,7 @@ import { Col, Row, Page } from "../ui";
|
|||
import { ToolBayList, ToolBayForm, ToolList, ToolForm } from "./components";
|
||||
import { mapStateToProps } from "./state_to_props";
|
||||
|
||||
@connect(mapStateToProps)
|
||||
export class Tools extends React.Component<Props, Partial<ToolsState>> {
|
||||
export class RawTools extends React.Component<Props, Partial<ToolsState>> {
|
||||
state: ToolsState = { editingBays: false, editingTools: false };
|
||||
|
||||
toggle = (name: keyof ToolsState) =>
|
||||
|
@ -48,3 +47,5 @@ export class Tools extends React.Component<Props, Partial<ToolsState>> {
|
|||
</Page>;
|
||||
}
|
||||
}
|
||||
|
||||
export const Tools = connect(mapStateToProps)(RawTools);
|
||||
|
|
|
@ -45,8 +45,8 @@
|
|||
"coveralls": "3.0.6",
|
||||
"enzyme": "3.10.0",
|
||||
"enzyme-adapter-react-16": "1.14.0",
|
||||
"farmbot": "8.2.0-rc1",
|
||||
"i18next": "17.0.14",
|
||||
"farmbot": "8.2.2",
|
||||
"i18next": "17.0.16",
|
||||
"lodash": "4.17.15",
|
||||
"markdown-it": "10.0.0",
|
||||
"markdown-it-emoji": "1.4.0",
|
||||
|
|
|
@ -28,6 +28,7 @@ describe Api::DevicesController do
|
|||
FactoryBot.create(:sensor, device: device)
|
||||
FactoryBot.create(:tool_slot, device: device)
|
||||
FactoryBot.create(:tool, device: device)
|
||||
FactoryBot.create(:point_group, device: device)
|
||||
FakeSequence.create(device: device)
|
||||
|
||||
get :sync, params: {}, session: { format: :json }
|
||||
|
|
|
@ -12,7 +12,7 @@ describe Api::LogsController do
|
|||
expect(response.status).to eq(200)
|
||||
expect(json.first[:id]).to eq(logs.first.id)
|
||||
expect(json.first[:created_at]).to eq(logs.first.created_at.to_i)
|
||||
expect(json.last[:meta][:type]).to eq(logs.last.type)
|
||||
expect(json.last[:type]).to eq(logs.last.type)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue