2018-10-30 12:16:06 -06:00
|
|
|
import { generateReducer } from "../redux/generate_reducer";
|
2018-11-08 09:41:09 -07:00
|
|
|
import { RestResources } from "./interfaces";
|
2018-08-01 07:03:35 -06:00
|
|
|
import {
|
2018-11-08 09:41:09 -07:00
|
|
|
indexUpsert,
|
|
|
|
mutateSpecialStatus,
|
2018-10-25 16:05:03 -06:00
|
|
|
findByUuid,
|
2018-11-08 09:41:09 -07:00
|
|
|
indexRemove,
|
2018-10-25 16:05:03 -06:00
|
|
|
initResourceReducer,
|
2018-11-18 12:09:04 -07:00
|
|
|
afterEach,
|
2019-12-04 13:01:49 -07:00
|
|
|
beforeEach,
|
2019-12-05 14:52:01 -07:00
|
|
|
folderIndexer,
|
2020-02-28 09:35:32 -07:00
|
|
|
reindexFolders,
|
2018-10-25 16:05:03 -06:00
|
|
|
} from "./reducer_support";
|
2018-11-08 09:41:09 -07:00
|
|
|
import { TaggedResource, SpecialStatus } from "farmbot";
|
|
|
|
import { Actions } from "../constants";
|
|
|
|
import { EditResourceParams } from "../api/interfaces";
|
2019-07-31 10:54:56 -06:00
|
|
|
import { defensiveClone, equals } from "../util";
|
|
|
|
import { merge } from "lodash";
|
2018-11-08 09:41:09 -07:00
|
|
|
import { SyncBodyContents } from "../sync/actions";
|
|
|
|
import { GeneralizedError } from "./actions";
|
|
|
|
import { initialState as helpState } from "../help/reducer";
|
|
|
|
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";
|
2019-07-15 13:44:40 -06:00
|
|
|
import { initialState as alertState } from "../messages/reducer";
|
2019-12-11 15:44:54 -07:00
|
|
|
import { ingest } from "../folders/data_transfer";
|
|
|
|
import { searchFolderTree } from "../folders/search_folder_tree";
|
2018-11-13 12:55:55 -07:00
|
|
|
|
2018-11-01 07:47:56 -06:00
|
|
|
export const emptyState = (): RestResources => {
|
|
|
|
return {
|
|
|
|
consumers: {
|
|
|
|
sequences: sequenceState,
|
|
|
|
regimens: regimenState,
|
|
|
|
farm_designer: designerState,
|
|
|
|
farmware: farmwareState,
|
|
|
|
help: helpState,
|
2019-07-15 13:44:40 -06:00
|
|
|
alerts: alertState
|
2018-11-01 07:47:56 -06:00
|
|
|
},
|
|
|
|
loaded: [],
|
|
|
|
index: {
|
2018-12-01 19:02:02 -07:00
|
|
|
all: {},
|
2018-11-01 07:47:56 -06:00
|
|
|
byKind: {
|
2019-08-05 15:45:19 -06:00
|
|
|
Alert: {},
|
|
|
|
Crop: {},
|
2018-11-01 07:47:56 -06:00
|
|
|
Device: {},
|
|
|
|
FarmEvent: {},
|
2019-08-05 15:45:19 -06:00
|
|
|
FarmwareEnv: {},
|
|
|
|
FarmwareInstallation: {},
|
|
|
|
FbosConfig: {},
|
|
|
|
FirmwareConfig: {},
|
2019-12-03 16:30:03 -07:00
|
|
|
Folder: {},
|
2018-11-01 07:47:56 -06:00
|
|
|
Image: {},
|
|
|
|
Log: {},
|
|
|
|
Peripheral: {},
|
2019-08-05 15:45:19 -06:00
|
|
|
PinBinding: {},
|
|
|
|
Plant: {},
|
|
|
|
PlantTemplate: {},
|
2018-11-01 07:47:56 -06:00
|
|
|
Point: {},
|
2019-08-05 15:45:19 -06:00
|
|
|
PointGroup: {},
|
2018-11-01 07:47:56 -06:00
|
|
|
Regimen: {},
|
2019-08-05 15:45:19 -06:00
|
|
|
SavedGarden: {},
|
|
|
|
Sensor: {},
|
|
|
|
SensorReading: {},
|
2018-11-01 07:47:56 -06:00
|
|
|
Sequence: {},
|
|
|
|
Tool: {},
|
|
|
|
User: {},
|
|
|
|
WebAppConfig: {},
|
2019-08-05 15:45:19 -06:00
|
|
|
WebcamFeed: {},
|
2018-10-29 18:13:41 -06:00
|
|
|
},
|
2018-11-01 07:47:56 -06:00
|
|
|
byKindAndId: {},
|
2018-11-01 09:45:29 -06:00
|
|
|
references: {},
|
2018-11-28 08:59:00 -07:00
|
|
|
sequenceMetas: {},
|
2018-11-17 13:36:16 -07:00
|
|
|
inUse: {
|
2018-11-17 16:24:07 -07:00
|
|
|
"Regimen.FarmEvent": {},
|
|
|
|
"Sequence.FarmEvent": {},
|
2018-11-20 17:24:45 -07:00
|
|
|
"Sequence.Regimen": {},
|
2018-11-17 13:36:16 -07:00
|
|
|
"Sequence.Sequence": {},
|
2019-12-20 16:48:56 -07:00
|
|
|
"Sequence.PinBinding": {},
|
2019-09-19 07:37:05 -06:00
|
|
|
"Sequence.FbosConfig": {}
|
2019-12-04 08:49:55 -07:00
|
|
|
},
|
|
|
|
sequenceFolders: {
|
2019-12-05 09:12:14 -07:00
|
|
|
localMetaAttributes: {},
|
|
|
|
folders: {
|
|
|
|
folders: [],
|
|
|
|
noFolder: [],
|
|
|
|
},
|
2018-11-17 13:36:16 -07:00
|
|
|
}
|
2018-11-01 07:47:56 -06:00
|
|
|
}
|
2018-10-29 18:13:41 -06:00
|
|
|
};
|
2018-11-01 07:47:56 -06:00
|
|
|
};
|
2017-06-29 12:54:02 -06:00
|
|
|
|
|
|
|
/** Responsible for all RESTful resources. */
|
2019-12-10 11:52:48 -07:00
|
|
|
export const resourceReducer =
|
2019-07-30 15:30:07 -06:00
|
|
|
generateReducer<RestResources>(emptyState())
|
2019-07-31 10:54:56 -06:00
|
|
|
.beforeEach(beforeEach)
|
2019-07-30 15:30:07 -06:00
|
|
|
.afterEach(afterEach)
|
2018-10-25 16:05:03 -06:00
|
|
|
.add<TaggedResource>(Actions.SAVE_RESOURCE_OK, (s, { payload }) => {
|
2018-11-25 15:04:59 -07:00
|
|
|
indexUpsert(s.index, [payload], "ongoing");
|
2018-10-29 06:52:32 -06:00
|
|
|
mutateSpecialStatus(payload.uuid, s.index, SpecialStatus.SAVED);
|
2017-06-29 12:54:02 -06:00
|
|
|
return s;
|
2018-10-25 16:05:03 -06:00
|
|
|
})
|
|
|
|
.add<EditResourceParams>(Actions.EDIT_RESOURCE, (s, { payload }) => {
|
|
|
|
const { update } = payload;
|
2018-10-29 07:36:39 -06:00
|
|
|
const target = findByUuid(s.index, payload.uuid);
|
2018-10-25 16:05:03 -06:00
|
|
|
const before = defensiveClone(target.body);
|
|
|
|
merge(target, { body: update });
|
2018-10-29 06:52:32 -06:00
|
|
|
const didChange = !equals(before, target.body);
|
2018-11-30 09:09:25 -07:00
|
|
|
if (didChange) {
|
|
|
|
mutateSpecialStatus(target.uuid, s.index, SpecialStatus.DIRTY);
|
|
|
|
indexUpsert(s.index, [target], "ongoing");
|
|
|
|
}
|
2018-10-25 16:05:03 -06:00
|
|
|
return s;
|
|
|
|
})
|
|
|
|
.add<EditResourceParams>(Actions.OVERWRITE_RESOURCE, (s, { payload }) => {
|
2018-11-06 15:53:57 -07:00
|
|
|
const { uuid, update, specialStatus } = payload;
|
2018-11-06 17:14:38 -07:00
|
|
|
const original = findByUuid(s.index, uuid);
|
|
|
|
original.body = update;
|
2018-11-25 15:04:59 -07:00
|
|
|
indexUpsert(s.index, [original], "ongoing");
|
2018-11-06 17:14:38 -07:00
|
|
|
mutateSpecialStatus(uuid, s.index, specialStatus);
|
|
|
|
return s;
|
2018-10-25 16:05:03 -06:00
|
|
|
})
|
2019-12-04 13:01:49 -07:00
|
|
|
.add<SyncBodyContents<TaggedResource>>(Actions.RESOURCE_READY, (s, { payload }) => {
|
|
|
|
!s.loaded.includes(payload.kind) && s.loaded.push(payload.kind);
|
|
|
|
indexUpsert(s.index, payload.body, "initial");
|
|
|
|
return s;
|
|
|
|
})
|
2018-10-29 07:36:39 -06:00
|
|
|
.add<TaggedResource>(Actions.REFRESH_RESOURCE_OK, (s, { payload }) => {
|
2018-11-25 15:04:59 -07:00
|
|
|
indexUpsert(s.index, [payload], "ongoing");
|
2018-10-29 12:28:01 -06:00
|
|
|
mutateSpecialStatus(payload.uuid, s.index);
|
2018-10-29 07:36:39 -06:00
|
|
|
return s;
|
|
|
|
})
|
2018-10-29 06:52:32 -06:00
|
|
|
.add<TaggedResource>(Actions.DESTROY_RESOURCE_OK, (s, { payload }) => {
|
2018-10-29 12:28:01 -06:00
|
|
|
indexRemove(s.index, payload);
|
2019-12-04 13:01:49 -07:00
|
|
|
folderIndexer(payload, s.index);
|
2018-10-29 06:52:32 -06:00
|
|
|
return s;
|
|
|
|
})
|
|
|
|
.add<GeneralizedError>(Actions._RESOURCE_NO, (s, { payload }) => {
|
|
|
|
merge(findByUuid(s.index, payload.uuid), payload);
|
|
|
|
mutateSpecialStatus(payload.uuid, s.index, payload.statusBeforeError);
|
|
|
|
return s;
|
|
|
|
})
|
2018-10-28 14:52:54 -06:00
|
|
|
.add<TaggedResource>(Actions.INIT_RESOURCE, initResourceReducer)
|
2018-10-25 16:05:03 -06:00
|
|
|
.add<string>(Actions.REFRESH_RESOURCE_START, (s, a) => {
|
|
|
|
mutateSpecialStatus(a.payload, s.index, SpecialStatus.SAVING);
|
|
|
|
return s;
|
|
|
|
})
|
2018-10-28 15:19:29 -06:00
|
|
|
.add<GeneralizedError>(Actions.REFRESH_RESOURCE_NO, (s, { payload }) => {
|
|
|
|
mutateSpecialStatus(payload.uuid, s.index);
|
2018-10-25 16:05:03 -06:00
|
|
|
return s;
|
|
|
|
})
|
2018-10-26 14:50:05 -06:00
|
|
|
.add<TaggedResource>(Actions.SAVE_RESOURCE_START, (s, { payload }) => {
|
|
|
|
mutateSpecialStatus(payload.uuid, s.index, SpecialStatus.SAVING);
|
2018-10-25 16:05:03 -06:00
|
|
|
return s;
|
|
|
|
})
|
|
|
|
.add<TaggedResource[]>(Actions.BATCH_INIT, (s, { payload }) => {
|
|
|
|
return payload.reduce((state, resource) => {
|
2018-10-26 14:50:05 -06:00
|
|
|
return initResourceReducer(state, {
|
|
|
|
type: Actions.INIT_RESOURCE,
|
|
|
|
payload: resource
|
|
|
|
});
|
2018-10-25 16:05:03 -06:00
|
|
|
}, s);
|
2019-12-05 14:52:01 -07:00
|
|
|
})
|
|
|
|
.add<{ id: number }>(Actions.FOLDER_TOGGLE, (s, { payload }) => {
|
|
|
|
const { localMetaAttributes } = s.index.sequenceFolders;
|
|
|
|
const record = localMetaAttributes[parseInt("" + payload.id)];
|
2019-12-21 12:47:19 -07:00
|
|
|
record.open = !(record.open ?? true);
|
2019-12-05 14:52:01 -07:00
|
|
|
reindexFolders(s.index);
|
|
|
|
return s;
|
|
|
|
})
|
2019-12-05 15:40:06 -07:00
|
|
|
.add<boolean>(Actions.FOLDER_TOGGLE_ALL, (s, { payload }) => {
|
|
|
|
const { localMetaAttributes } = s.index.sequenceFolders;
|
|
|
|
Object.keys(localMetaAttributes).map((x) => {
|
|
|
|
localMetaAttributes[parseInt("" + x)].open = payload;
|
|
|
|
});
|
|
|
|
reindexFolders(s.index);
|
|
|
|
return s;
|
|
|
|
})
|
2019-12-05 15:18:50 -07:00
|
|
|
.add<{ id: number }>(Actions.FOLDER_TOGGLE_EDIT, (s, { payload }) => {
|
|
|
|
const { localMetaAttributes } = s.index.sequenceFolders;
|
|
|
|
const record = localMetaAttributes[parseInt("" + payload.id)];
|
|
|
|
record.editing = !record.editing;
|
|
|
|
|
|
|
|
reindexFolders(s.index);
|
|
|
|
|
2019-12-06 08:47:52 -07:00
|
|
|
return s;
|
|
|
|
})
|
2019-12-10 12:26:32 -07:00
|
|
|
.add<string | undefined>(Actions.FOLDER_SEARCH, (s, { payload }) => {
|
|
|
|
s.index.sequenceFolders.searchTerm = payload;
|
2019-12-11 14:08:07 -07:00
|
|
|
if (payload) {
|
2019-12-11 15:44:54 -07:00
|
|
|
const folders = searchFolderTree({
|
2019-12-10 12:26:32 -07:00
|
|
|
references: s.index.references,
|
|
|
|
input: payload,
|
|
|
|
root: s.index.sequenceFolders.folders
|
|
|
|
});
|
2019-12-10 15:13:16 -07:00
|
|
|
const { localMetaAttributes } = s.index.sequenceFolders;
|
|
|
|
Object /** Expand all folders when searching. */
|
|
|
|
.keys(localMetaAttributes)
|
|
|
|
.map(x => {
|
|
|
|
s
|
|
|
|
.index
|
|
|
|
.sequenceFolders
|
|
|
|
.localMetaAttributes[x as unknown as number]
|
|
|
|
.open = true;
|
|
|
|
});
|
2019-12-10 12:26:32 -07:00
|
|
|
const nextFolder = ingest({
|
2019-12-10 15:13:16 -07:00
|
|
|
localMetaAttributes,
|
2019-12-10 12:26:32 -07:00
|
|
|
folders
|
|
|
|
});
|
2019-12-13 14:11:22 -07:00
|
|
|
nextFolder.noFolder = nextFolder.noFolder.filter(uuid => {
|
|
|
|
const sq = s.index.references[uuid];
|
|
|
|
if (sq && sq.kind === "Sequence") {
|
|
|
|
const n = sq.body.name.toLowerCase();
|
|
|
|
return n.includes(payload);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
});
|
2019-12-10 12:26:32 -07:00
|
|
|
s.index.sequenceFolders.filteredFolders = nextFolder;
|
|
|
|
} else {
|
|
|
|
s.index.sequenceFolders.filteredFolders = undefined;
|
|
|
|
}
|
|
|
|
reindexFolders(s.index);
|
2019-12-05 15:18:50 -07:00
|
|
|
return s;
|
|
|
|
});
|