state event handlers - API
This commit is contained in:
parent
9953989de6
commit
bfda230aae
|
@ -2,5 +2,5 @@ Contributors
|
||||||
===
|
===
|
||||||
|
|
||||||
* Michael Shanks - [@mjashanks](https://github.com/mjashanks)
|
* Michael Shanks - [@mjashanks](https://github.com/mjashanks)
|
||||||
* Dan - [@danbudi](https://github.com/danbudi)
|
* Daniel Loudon - [@danbudi](https://github.com/marblekirby)
|
||||||
* Joe - [@joebudi](https://github.com/joebudi)
|
* Joe - [@joebudi](https://github.com/joebudi)
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { ERROR } from "../state/standardState";
|
||||||
|
import {loadRecord} from "./loadRecord";
|
||||||
|
import {listRecords} from "./listRecords";
|
||||||
|
|
||||||
|
export const createApi = ({rootPath, setState, getState}) => {
|
||||||
|
|
||||||
|
const apiCall = (method) => ({url, body, notFound, badRequest, forbidden}) => {
|
||||||
|
fetch(url, {
|
||||||
|
method: method,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: body && JSON.stringify(body),
|
||||||
|
credentials: "same-origin"
|
||||||
|
}).then(r => {
|
||||||
|
switch (r.status) {
|
||||||
|
case 200:
|
||||||
|
return r.json();
|
||||||
|
case 404:
|
||||||
|
return error(notFound || `${url} Not found`);
|
||||||
|
case 400:
|
||||||
|
return error(badRequest || `${url} Bad Request`);
|
||||||
|
case 403:
|
||||||
|
return error(forbidden || `${url} Forbidden`);
|
||||||
|
default:
|
||||||
|
if(r.status.toString().startsWith("2")
|
||||||
|
|| r.status.toString().startsWith("3"))
|
||||||
|
return r.json()
|
||||||
|
else
|
||||||
|
return error(`${url} - ${r.statusText}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const post = apiCall("POST");
|
||||||
|
const get = apiCall("GET");
|
||||||
|
const patch = apiCall("PATCH");
|
||||||
|
const del = apiCall("DELETE");
|
||||||
|
|
||||||
|
const ERROR_MEMBER = "##error";
|
||||||
|
const error = message => {
|
||||||
|
const e = {};
|
||||||
|
e[ERROR_MEMBER] = message;
|
||||||
|
setState(ERROR, message);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSuccess = obj => !!obj[ERROR_MEMBER];
|
||||||
|
|
||||||
|
const apiOpts = {
|
||||||
|
rootPath, setState, getState, isSuccess, error,
|
||||||
|
post, get, patch, delete:del
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
loadRecord:loadRecord(apiOpts),
|
||||||
|
listRecords: listRecords(api)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
export const listRecords = api => async ({indexKey, statePath}) => {
|
||||||
|
if(!recordKey) {
|
||||||
|
api.error("Load Record: record key not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!statePath) {
|
||||||
|
api.error("Load Record: state path not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const records = get({
|
||||||
|
url:`${rootPath}/api/listRecords/${indexKey}`
|
||||||
|
});
|
||||||
|
|
||||||
|
if(api.isSuccess(records))
|
||||||
|
api.setState(statePath, records);
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
|
||||||
|
export const loadRecord = (api) => async ({recordKey, statePath}) => {
|
||||||
|
|
||||||
|
if(!recordKey) {
|
||||||
|
api.error("Load Record: record key not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!statePath) {
|
||||||
|
api.error("Load Record: state path not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const record = await get({
|
||||||
|
url:`${rootPath}/api/record/${key}`
|
||||||
|
});
|
||||||
|
|
||||||
|
if(api.isSuccess(record))
|
||||||
|
api.setState(statePath, record);
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
|
||||||
|
|
||||||
|
export const saveRecord = (api) => async ({statePath}) => {
|
||||||
|
|
||||||
|
if(!statePath) {
|
||||||
|
api.error("Load Record: state path not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const recordtoSave = api.getState(statePath);
|
||||||
|
|
||||||
|
if(!recordtoSave) {
|
||||||
|
api.error(`there is no record in state: ${statePath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!recordtoSave.key) {
|
||||||
|
api.error(`item in state does not appear to be a record - it has no key (${statePath})`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const savedRecord = await post({
|
||||||
|
url:`${rootPath}/api/record/${recordtoSave.key}`,
|
||||||
|
body: recordtoSave
|
||||||
|
});
|
||||||
|
|
||||||
|
if(api.isSuccess(record))
|
||||||
|
api.setState(statePath, savedRecord);
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
export const createCoreApp = (appDefinition, user) => {
|
||||||
|
const app = {
|
||||||
|
datastore: null,
|
||||||
|
crypto:null,
|
||||||
|
publish: () => {},
|
||||||
|
hierarchy: appDefinition.hierarchy,
|
||||||
|
actions: appDefinition.actions
|
||||||
|
};
|
||||||
|
|
||||||
|
app.asUser(user);
|
||||||
|
|
||||||
|
return app;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { createCoreApp } from "./createCoreApp"
|
||||||
|
import {
|
||||||
|
getNew, getNewChild
|
||||||
|
} from "../../../core/src/recordApi/getNew";
|
||||||
|
|
||||||
|
export const createCoreApi = (appDefinition, user) => {
|
||||||
|
|
||||||
|
const app = createCoreApp(appDefinition, user);
|
||||||
|
|
||||||
|
return {
|
||||||
|
recordApi: {
|
||||||
|
getNew: getNew(app),
|
||||||
|
getNewChild: getNewChild(app)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,8 +5,9 @@ import {
|
||||||
import {writable} from "svelte/store";
|
import {writable} from "svelte/store";
|
||||||
import { $ } from "./core/common";
|
import { $ } from "./core/common";
|
||||||
import { setupBinding } from "./state/stateBinding";
|
import { setupBinding } from "./state/stateBinding";
|
||||||
|
import { createCoreApi } from "./core";
|
||||||
|
|
||||||
export const createApp = componentLibraries => {
|
export const createApp = (componentLibraries, appDefinition, user) => {
|
||||||
|
|
||||||
const initialiseComponent = (props, htmlElement) => {
|
const initialiseComponent = (props, htmlElement) => {
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ export const createApp = componentLibraries => {
|
||||||
|
|
||||||
if(!componentName || !libName) return;
|
if(!componentName || !libName) return;
|
||||||
|
|
||||||
const {initialProps, bind} = setupBinding(store, props);
|
const {initialProps, bind} = setupBinding(store, props, coreApi);
|
||||||
|
|
||||||
const component = new (componentLibraries[libName][componentName])({
|
const component = new (componentLibraries[libName][componentName])({
|
||||||
target: htmlElement,
|
target: htmlElement,
|
||||||
|
@ -25,6 +26,7 @@ export const createApp = componentLibraries => {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const coreApi = createCoreApi(appDefinition, user);
|
||||||
const store = writable({});
|
const store = writable({});
|
||||||
|
|
||||||
const _app = {
|
const _app = {
|
||||||
|
|
|
@ -4,6 +4,12 @@ import { createApp } from "./createApp";
|
||||||
export const loadBudibase = async (componentLibraries, props) => {
|
export const loadBudibase = async (componentLibraries, props) => {
|
||||||
|
|
||||||
const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
|
const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
|
||||||
|
const user = localStorage.getItem("budibase:user") || {
|
||||||
|
name: "annonymous",
|
||||||
|
permissions : [],
|
||||||
|
isUser:false,
|
||||||
|
temp:false
|
||||||
|
}
|
||||||
|
|
||||||
if(!componentLibraries) {
|
if(!componentLibraries) {
|
||||||
|
|
||||||
|
@ -22,7 +28,7 @@ export const loadBudibase = async (componentLibraries, props) => {
|
||||||
props = appDefinition.props;
|
props = appDefinition.props;
|
||||||
}
|
}
|
||||||
|
|
||||||
const _app = createApp(componentLibraries);
|
const _app = createApp(componentLibraries, user);
|
||||||
_app.initialiseComponent(
|
_app.initialiseComponent(
|
||||||
props,
|
props,
|
||||||
document.body);
|
document.body);
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
import { ERROR } from "./standardState";
|
||||||
|
|
||||||
|
export const getNewChildRecordToState = (store, coreApi) =>
|
||||||
|
({recordKey, collectionName,childRecordType,statePath}) => {
|
||||||
|
const error = errorHandler(setState);
|
||||||
|
try {
|
||||||
|
if(!recordKey) {
|
||||||
|
error("getNewChild > recordKey not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!collectionName) {
|
||||||
|
error("getNewChild > collectionName not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!childRecordType) {
|
||||||
|
error("getNewChild > childRecordType not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!statePath) {
|
||||||
|
error("getNewChild > statePath not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rec = coreApi.recordApi.getNewChild(recordKey, collectionName, childRecordType);
|
||||||
|
setState(store, statePath, rec);
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
error(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export const getNewRecordToState = (store, coreApi) =>
|
||||||
|
({collectionKey,childRecordType,statePath}) => {
|
||||||
|
const error = errorHandler(setState);
|
||||||
|
try {
|
||||||
|
if(!collectionKey) {
|
||||||
|
error("getNewChild > collectionKey not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!childRecordType) {
|
||||||
|
error("getNewChild > childRecordType not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!statePath) {
|
||||||
|
error("getNewChild > statePath not set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rec = coreApi.recordApi.getNew(collectionKey, childRecordType);
|
||||||
|
setState(store, statePath, rec);
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
error(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const errorHandler = setState => message => setState(ERROR, message);
|
|
@ -1,22 +1,43 @@
|
||||||
import {
|
import { setState } from "./setState";
|
||||||
setState
|
import { getState } from "./getState";
|
||||||
} from "./setState";
|
|
||||||
import {
|
import {
|
||||||
isArray, isUndefined
|
isArray, isUndefined
|
||||||
} from "lodash/fp";
|
} from "lodash/fp";
|
||||||
|
|
||||||
|
import { createApi } from "../api";
|
||||||
|
import {
|
||||||
|
getNewChildRecordToState, getNewRecordToState
|
||||||
|
} from "./coreHandlers";
|
||||||
|
|
||||||
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType";
|
export const EVENT_TYPE_MEMBER_NAME = "##eventHandlerType";
|
||||||
|
|
||||||
export const eventHandlers = store => {
|
export const eventHandlers = (store,coreApi) => {
|
||||||
|
|
||||||
const handler = (parameters, execute) => ({
|
const handler = (parameters, execute) => ({
|
||||||
execute, parameters
|
execute, parameters
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const api = createApi({
|
||||||
|
rootPath:"",
|
||||||
|
setState: (path, value) => setState(store, path, value),
|
||||||
|
getState: (path, fallback) => getState(store, path, fallback)
|
||||||
|
});
|
||||||
|
|
||||||
const setStateHandler = ({path, value}) => setState(store, path, value);
|
const setStateHandler = ({path, value}) => setState(store, path, value);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"Set State": handler(["path", "value"], setStateHandler)
|
"Set State": handler(["path", "value"], setStateHandler),
|
||||||
|
"Load Record": handler(["recordKey", "statePath"], api.loadRecord),
|
||||||
|
"List Records": handler(["indexKey", "statePath"], api.listRecords),
|
||||||
|
"Save Record": handler(["statePath"], api.saveRecord),
|
||||||
|
|
||||||
|
"Get New Child Record": handler(
|
||||||
|
["recordKey", "collectionName", "childRecordType", "statePath"],
|
||||||
|
getNewChildRecordToState(store, coreApi)),
|
||||||
|
|
||||||
|
"Get New Record": handler(
|
||||||
|
["collectionKey", "childRecordType", "statePath"],
|
||||||
|
getNewRecordToState(store, coreApi)),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
export const ERROR = "##error_message";
|
|
@ -9,7 +9,7 @@ import {
|
||||||
export const BB_STATE_BINDINGPATH = "##bbstate";
|
export const BB_STATE_BINDINGPATH = "##bbstate";
|
||||||
export const BB_STATE_FALLBACK = "##bbstatefallback";
|
export const BB_STATE_FALLBACK = "##bbstatefallback";
|
||||||
const doNothing = () => {};
|
const doNothing = () => {};
|
||||||
export const setupBinding = (store, props) => {
|
export const setupBinding = (store, props, coreApi) => {
|
||||||
|
|
||||||
const initialProps = {...props};
|
const initialProps = {...props};
|
||||||
const boundProps = [];
|
const boundProps = [];
|
||||||
|
@ -50,7 +50,7 @@ export const setupBinding = (store, props) => {
|
||||||
|
|
||||||
if(boundProps.length === 0 && componentEventHandlers.length === 0) return;
|
if(boundProps.length === 0 && componentEventHandlers.length === 0) return;
|
||||||
|
|
||||||
const handlerTypes = eventHandlers(store);
|
const handlerTypes = eventHandlers(store, coreApi);
|
||||||
|
|
||||||
const unsubscribe = store.subscribe(s => {
|
const unsubscribe = store.subscribe(s => {
|
||||||
const newProps = {};
|
const newProps = {};
|
||||||
|
|
Loading…
Reference in New Issue