[UNSTABLE] Weed out more type errors

pull/1027/head
Rick Carlino 2018-10-30 15:36:52 -05:00
parent 66e686a4c1
commit 0ae0921a87
13 changed files with 73 additions and 48 deletions

View File

@ -1,5 +1,4 @@
import {
ResourceName,
SpecialStatus,
TaggedDevice,
TaggedLog,
@ -320,12 +319,14 @@ export
function buildResourceIndex(resources: TaggedResource[] = FAKE_RESOURCES,
state = emptyState()) {
const KIND: keyof TaggedResource = "kind"; // Safety first, kids.
return _(resources)
const t = _(resources)
.groupBy(KIND)
.toPairs()
.map((x: [(TaggedResource["kind"]), TaggedResource[]]) => x)
.map((y: [ResourceName, TaggedResource[]]) => {
return resourceReady((y[0] as any), y[1].map(x => x.body as any));
.map((x: [TaggedResource["kind"], TaggedResource[]]) => x)
.map((y) => {
const [kind, list] = y;
return resourceReady(kind, list);
})
.reduce(resourceReducer, state);
return t;
}

View File

@ -23,6 +23,7 @@ import { API } from "../api";
import { betterCompact } from "../../util";
import { SpecialStatus } from "farmbot";
import * as _ from "lodash";
import { arrayUnwrap } from "../../resources/util";
describe("AJAX data tracking", () => {
API.setBaseUrl("http://blah.whatever.party");
@ -57,10 +58,12 @@ describe("AJAX data tracking", () => {
expect(uuids.length).toEqual(r.length);
});
it("sets consistency when calling initSave()", () => {
mockBody = resources()[0].body;
fit("sets consistency when calling initSave()", () => {
const tr = arrayUnwrap(resources());
mockBody = tr.body;
// tslint:disable-next-line:no-any
store.dispatch(initSave(resources()[0]) as any);
const action: any = initSave(tr);
store.dispatch(action);
expect(maybeStartTracking).toHaveBeenCalled();
});
});

View File

@ -4,10 +4,9 @@ import { resourceReady } from "../../sync/actions";
describe("Connectivity Reducer - RESOURCE_READY", () => {
it("handles `undefined` status", () => {
const action = resourceReady("Device", {
...fakeDevice().body,
last_saw_mq: "Tue, 03 Oct 2017 09:00:00 -0500"
});
const device = fakeDevice();
device.body.last_saw_mq = "Tue, 03 Oct 2017 09:00:00 -0500";
const action = resourceReady("Device", device);
const result = connectivityReducer(DEFAULT_STATE, action);
expect(result["bot.mqtt"]).not.toBe(undefined);
});

View File

@ -31,8 +31,8 @@ export let connectivityReducer =
})
.add<SyncBodyContents<TaggedDevice>>(Actions.RESOURCE_READY, (s, a) => {
const d = arrayUnwrap(a.payload.body);
if (d && a.payload.kind === "Device") {
s["bot.mqtt"] = computeBestTime(s["bot.mqtt"], d && d.last_saw_mq);
if (d && d.kind === "Device") {
s["bot.mqtt"] = computeBestTime(s["bot.mqtt"], d && d.body.last_saw_mq);
}
return s;
})

View File

@ -1,9 +1,14 @@
const mockGet = jest.fn(() => Promise.resolve({ data: [] }));
const mockGet = jest.fn(() => {
return Promise.resolve({ data: [mockLog.body] });
});
jest.mock("axios", () => ({ default: { get: mockGet } }));
import { refreshLogs } from "../refresh_logs";
import axios from "axios";
import { API } from "../../api";
import { resourceReady } from "../../sync/actions";
import { fakeLog } from "../../__test_support__/fake_state/resources";
const mockLog = fakeLog();
describe("refreshLogs", () => {
it("dispatches the appropriate action", async () => {
@ -11,7 +16,7 @@ describe("refreshLogs", () => {
API.setBaseUrl("localhost");
await refreshLogs(dispatch);
expect(axios.get).toHaveBeenCalled();
expect(dispatch).toHaveBeenCalledWith(resourceReady("Log", []));
const action = resourceReady("Log", mockLog);
expect(dispatch).toHaveBeenCalledWith(action);
});
});

View File

@ -6,12 +6,19 @@ import { revertToEnglishMiddleware } from "../revert_to_english_middleware";
import { revertToEnglish } from "../../revert_to_english";
import { resourceReady } from "../../sync/actions";
import { WebAppConfig } from "farmbot/dist/resources/configs/web_app";
import { generateUuid } from "../../resources/util";
import { SpecialStatus } from "farmbot";
fdescribe("revertToEnglishMiddleware", () => {
fit("calls `revertToEnglish` when appropriate", () => {
describe("revertToEnglishMiddleware", () => {
it("calls `revertToEnglish` when appropriate", () => {
const dispatch = jest.fn(() => ({}));
const data = { disable_i18n: true } as WebAppConfig;
const action = resourceReady("WebAppConfig", data);
const action = resourceReady("WebAppConfig", {
kind: "WebAppConfig",
uuid: generateUuid(data.id, "WebAppConfig"),
specialStatus: SpecialStatus.SAVED,
body: data
});
expect(revertToEnglish).not.toHaveBeenCalled();
// tslint:disable-next-line:no-any
revertToEnglishMiddleware.fn({} as any)(dispatch)(action);

View File

@ -3,7 +3,7 @@ import { noop, throttle } from "lodash";
import axios from "axios";
import { ResourceName } from "farmbot";
import { Log } from "farmbot/dist/resources/api_resources";
import { resourceReady } from "../sync/actions";
import { resourceReady, newTaggedResource } from "../sync/actions";
const kind: ResourceName = "Log";
/** re-Downloads all logs from the API and force replaces all entries for logs
@ -11,7 +11,9 @@ const kind: ResourceName = "Log";
export const refreshLogs = async (dispatch: Function) => {
return axios
.get<Log[]>(API.current.filteredLogsPath)
.then(({ data }) => dispatch(resourceReady(kind, data)), noop);
.then(({ data }) => {
dispatch(resourceReady(kind, newTaggedResource("Log", data)));
}, noop);
};
export const throttledLogRefresh = throttle(refreshLogs, 1000);

View File

@ -29,7 +29,10 @@ const fn: Middleware = () => (dispatch) => (action: any) => {
&& x.payload.body
&& x.payload.kind === WEB_APP_CONFIG) {
const conf = arrayUnwrap(x.payload.body);
conf && conf.disable_i18n && revertToEnglish();
conf
&& conf.body
&& conf.body.disable_i18n
&& revertToEnglish();
}
return dispatch(action);

View File

@ -60,8 +60,8 @@ describe("resource reducer", () => {
let id = 1;
it("covers save resource branches", () => {
const testResource = (kind: TaggedResource["kind"]) => {
const resource = fakeResource(kind, { id: ++id });
const action = resourceReady(resource.kind, resource.body);
const resource = fakeResource(kind, { id: ++id }) as TaggedResource;
const action = resourceReady(resource.kind, [resource]);
const newState = resourceReducer(fakeState().resources, action);
const uuid = newState.index.byKindAndId[joinKindAndId(kind, resource.body.id)];
const expectation = newState.index.references[uuid || "?"];

View File

@ -16,6 +16,7 @@ import {
import * as _ from "lodash";
import { resourceReducer, emptyState } from "../reducer";
import { resourceReady } from "../../sync/actions";
// import { Actions } from "../../constants";
const TOOL_ID = 99;
const SLOT_ID = 100;
@ -73,9 +74,9 @@ describe("getFeeds", () => {
it("finds the only WebcamFeed", () => {
const feed = fakeWebcamFeed();
const state = [
resourceReady("WebcamFeed", feed.body)
resourceReady("WebcamFeed", feed)
].reduce(resourceReducer, emptyState());
debugger;
expect(Selector.selectAllWebcamFeeds(state.index)[0].body).toEqual(feed);
});
});

View File

@ -9,7 +9,7 @@ import { generateReducer } from "../redux/generate_reducer";
import { initialState as regimenState } from "../regimens/reducer";
import { initialState as sequenceState } from "../sequences/reducer";
import { SyncBodyContents } from "../sync/actions";
import { betterCompact, defensiveClone, equals } from "../util";
import { defensiveClone, equals } from "../util";
import { GeneralizedError } from "./actions";
import { ResourceIndex, RestResources } from "./interfaces";
import {
@ -19,11 +19,7 @@ import {
mutateSpecialStatus
} from "./reducer_support";
import { INDEXES } from "./resource_index_chain";
import { isTaggedResource } from "./tagged_resources";
import {
arrayWrap,
generateUuid
} from "./util";
import { arrayWrap } from "./util";
const ups = INDEXES.map(x => x.up);
@ -111,15 +107,7 @@ export let resourceReducer =
})
.add<SyncBodyContents<TaggedResource>>(Actions.RESOURCE_READY, (s, { payload }) => {
!s.loaded.includes(payload.kind) && s.loaded.push(payload.kind);
betterCompact(arrayWrap(payload.body)).map(body => {
const x = {
kind: payload.kind,
uuid: generateUuid(body.id, payload.kind),
specialStatus: SpecialStatus.SAVED,
body
};
if (isTaggedResource(x)) { indexUpsert(s.index, x); }
});
payload.body.map(x => indexUpsert(s.index, x));
return s;
})
.add<TaggedResource>(Actions.REFRESH_RESOURCE_OK, (s, { payload }) => {

View File

@ -20,8 +20,12 @@ const REFERENCES: Indexer = { // ========
};
const ALL: Indexer = {
up(r, s) { s.all.push(r.uuid); },
down(r, i) { i.all = i.all.filter(filterOutUuid(r)); },
up(r, s) {
s.all.push(r.uuid);
},
down(r, i) {
i.all = i.all.filter(filterOutUuid(r));
},
};
const BY_KIND: Indexer = {

View File

@ -1,13 +1,13 @@
import axios from "axios";
import { API } from "../api";
import { Actions } from "../constants";
import { TaggedResource as TR } from "farmbot";
import { TaggedResource as TR, SpecialStatus } from "farmbot";
import { Session } from "../session";
import { arrayWrap } from "../resources/util";
export interface SyncBodyContents<T extends TR> {
kind: T["kind"];
body: T["body"][];
body: T[];
}
export interface SyncResponse<T extends TR> {
type: Actions.RESOURCE_READY;
@ -15,18 +15,30 @@ export interface SyncResponse<T extends TR> {
}
export const resourceReady =
<T extends TR>(kind: T["kind"], body: T["body"] | T["body"][]): SyncResponse<T> => {
<T extends TR>(kind: T["kind"], body: T | T[]): SyncResponse<T> => {
return {
type: Actions.RESOURCE_READY,
payload: { kind, body: arrayWrap(body) }
};
};
export const newTaggedResource = <T extends TR>(kind: T["kind"],
bodies: T["body"] | T["body"][],
specialStatus = SpecialStatus.SAVED): T[] => {
return arrayWrap(bodies).map((body: T["body"]): T => {
const tr = newTaggedResource(kind, body)[0];
tr.specialStatus = specialStatus;
return tr;
});
};
export function fetchSyncData(dispatch: Function) {
const fetch =
<T extends TR>(kind: T["kind"], url: string) => axios
.get<T["body"] | T["body"][]>(url)
.then(({ data }) => dispatch(resourceReady(kind, data)), Session.clear);
.then(({ data }) => {
dispatch(resourceReady(kind, newTaggedResource(kind, data)))
}, Session.clear);
fetch("User", API.current.usersPath);
fetch("Device", API.current.devicePath);