jason-rails 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/client/lib/JasonContext.d.ts +2 -0
- data/client/lib/JasonContext.js +5 -0
- data/client/lib/JasonProvider.d.ts +7 -0
- data/client/lib/JasonProvider.js +109 -0
- data/client/lib/actionFactory.d.ts +5 -0
- data/client/lib/actionFactory.js +33 -0
- data/client/lib/createActions.d.ts +2 -0
- data/client/lib/createActions.js +46 -0
- data/client/lib/createJasonReducers.d.ts +1 -0
- data/client/lib/createJasonReducers.js +36 -0
- data/client/lib/createPayloadHandler.d.ts +1 -0
- data/client/lib/createPayloadHandler.js +87 -0
- data/client/lib/index.d.ts +10 -0
- data/client/lib/index.js +12 -0
- data/client/lib/makeEager.d.ts +1 -0
- data/client/lib/makeEager.js +51 -0
- data/client/lib/useAct.d.ts +1 -0
- data/client/lib/useAct.js +12 -0
- data/client/lib/useSub.d.ts +1 -0
- data/client/lib/useSub.js +14 -0
- data/client/package.json +27 -0
- data/client/src/JasonContext.ts +5 -0
- data/client/src/JasonProvider.tsx +108 -0
- data/client/src/actionFactory.ts +34 -0
- data/client/src/createActions.ts +50 -0
- data/client/src/createJasonReducers.ts +34 -0
- data/client/src/createPayloadHandler.ts +95 -0
- data/client/src/index.ts +7 -0
- data/client/src/makeEager.ts +46 -0
- data/client/src/useAct.ts +9 -0
- data/client/src/useSub.ts +10 -0
- data/client/tsconfig.json +15 -0
- data/client/yarn.lock +140 -0
- data/jason-rails.gemspec +25 -0
- data/lib/jason.rb +10 -0
- data/lib/jason/api_model.rb +47 -0
- data/lib/jason/channel.rb +37 -0
- data/lib/jason/publisher.rb +79 -0
- data/lib/jason/subscription.rb +172 -0
- data/lib/jason/version.rb +3 -0
- metadata +96 -0
@@ -0,0 +1 @@
|
|
1
|
+
export default function createJasonReducers(schema: any): any;
|
@@ -0,0 +1,36 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const toolkit_1 = require("@reduxjs/toolkit");
|
7
|
+
const pluralize_1 = __importDefault(require("pluralize"));
|
8
|
+
const lodash_1 = __importDefault(require("lodash"));
|
9
|
+
function generateSlices(schema) {
|
10
|
+
const sliceNames = schema.map(k => pluralize_1.default(k));
|
11
|
+
const adapter = toolkit_1.createEntityAdapter();
|
12
|
+
return lodash_1.default.fromPairs(lodash_1.default.map(sliceNames, name => {
|
13
|
+
return [name, toolkit_1.createSlice({
|
14
|
+
name,
|
15
|
+
initialState: adapter.getInitialState(),
|
16
|
+
reducers: {
|
17
|
+
upsert: adapter.upsertOne,
|
18
|
+
upsertMany: adapter.upsertMany,
|
19
|
+
add: adapter.addOne,
|
20
|
+
setAll: adapter.setAll,
|
21
|
+
remove: adapter.removeOne,
|
22
|
+
movePriority: (s, { payload: { id, priority, parentFilter } }) => {
|
23
|
+
// Get IDs and insert our item at the new index
|
24
|
+
var affectedIds = lodash_1.default.orderBy(lodash_1.default.filter(lodash_1.default.values(s.entities), parentFilter).filter(e => e.id !== id), 'priority').map(e => e.id);
|
25
|
+
affectedIds.splice(priority, 0, id);
|
26
|
+
// Apply update
|
27
|
+
affectedIds.forEach((id, i) => s.entities[id].priority = i);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}).reducer];
|
31
|
+
}));
|
32
|
+
}
|
33
|
+
function createJasonReducers(schema) {
|
34
|
+
return generateSlices(lodash_1.default.keys(schema));
|
35
|
+
}
|
36
|
+
exports.default = createJasonReducers;
|
@@ -0,0 +1 @@
|
|
1
|
+
export default function createPayloadHandler(dispatch: any, subscription: any, model: any, config: any): (data: any) => null | undefined;
|
@@ -0,0 +1,87 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const jsonpatch_1 = require("jsonpatch");
|
7
|
+
const humps_1 = require("humps");
|
8
|
+
const pluralize_1 = __importDefault(require("pluralize"));
|
9
|
+
const lodash_1 = __importDefault(require("lodash"));
|
10
|
+
function diffSeconds(dt2, dt1) {
|
11
|
+
var diff = (dt2.getTime() - dt1.getTime()) / 1000;
|
12
|
+
return Math.abs(Math.round(diff));
|
13
|
+
}
|
14
|
+
function createPayloadHandler(dispatch, subscription, model, config) {
|
15
|
+
console.log({ model, config });
|
16
|
+
let payload = {};
|
17
|
+
let idx = 0;
|
18
|
+
let patchQueue = {};
|
19
|
+
let lastCheckAt = new Date();
|
20
|
+
let updateDeadline = null;
|
21
|
+
let checkInterval;
|
22
|
+
function getPayload() {
|
23
|
+
console.log({ getPayload: model, subscription });
|
24
|
+
subscription.send({ getPayload: { model, config } });
|
25
|
+
}
|
26
|
+
const tGetPayload = lodash_1.default.throttle(getPayload, 10000);
|
27
|
+
function dispatchPayload() {
|
28
|
+
const includeModels = (config.includeModels || []).map(m => lodash_1.default.camelCase(m));
|
29
|
+
console.log("Dispatching", { payload, includeModels });
|
30
|
+
includeModels.forEach(m => {
|
31
|
+
const subPayload = lodash_1.default.flatten(lodash_1.default.compact(humps_1.camelizeKeys(payload).map(instance => instance[m])));
|
32
|
+
console.log({ type: `${pluralize_1.default(m)}/upsertMany`, payload: subPayload });
|
33
|
+
dispatch({ type: `${pluralize_1.default(m)}/upsertMany`, payload: subPayload });
|
34
|
+
});
|
35
|
+
dispatch({ type: `${pluralize_1.default(model)}/upsertMany`, payload: humps_1.camelizeKeys(payload) });
|
36
|
+
}
|
37
|
+
function processQueue() {
|
38
|
+
console.log({ idx, patchQueue });
|
39
|
+
lastCheckAt = new Date();
|
40
|
+
if (patchQueue[idx]) {
|
41
|
+
payload = jsonpatch_1.apply_patch(payload, patchQueue[idx]);
|
42
|
+
if (patchQueue[idx]) {
|
43
|
+
dispatchPayload();
|
44
|
+
}
|
45
|
+
delete patchQueue[idx];
|
46
|
+
idx++;
|
47
|
+
updateDeadline = null;
|
48
|
+
processQueue();
|
49
|
+
// If there are updates in the queue that are ahead of the index, some have arrived out of order
|
50
|
+
// Set a deadline for new updates before it declares the update missing and refetches.
|
51
|
+
}
|
52
|
+
else if (lodash_1.default.keys(patchQueue).length > 0 && !updateDeadline) {
|
53
|
+
var t = new Date();
|
54
|
+
t.setSeconds(t.getSeconds() + 3);
|
55
|
+
updateDeadline = t;
|
56
|
+
setTimeout(processQueue, 3100);
|
57
|
+
// If more than 10 updates in queue, or deadline has passed, restart
|
58
|
+
}
|
59
|
+
else if (lodash_1.default.keys(patchQueue).length > 10 || (updateDeadline && diffSeconds(updateDeadline, new Date()) < 0)) {
|
60
|
+
tGetPayload();
|
61
|
+
updateDeadline = null;
|
62
|
+
}
|
63
|
+
}
|
64
|
+
function handlePayload(data) {
|
65
|
+
const { value, idx: newIdx, diff, latency, type } = data;
|
66
|
+
console.log({ data });
|
67
|
+
if (type === 'payload') {
|
68
|
+
if (!value)
|
69
|
+
return null;
|
70
|
+
payload = value;
|
71
|
+
dispatchPayload();
|
72
|
+
idx = newIdx + 1;
|
73
|
+
// Clear any old changes left in the queue
|
74
|
+
patchQueue = lodash_1.default.pick(patchQueue, lodash_1.default.keys(patchQueue).filter(k => k > newIdx + 1));
|
75
|
+
return;
|
76
|
+
}
|
77
|
+
patchQueue[newIdx] = diff;
|
78
|
+
processQueue();
|
79
|
+
if (diffSeconds((new Date()), lastCheckAt) >= 3) {
|
80
|
+
lastCheckAt = new Date();
|
81
|
+
console.log('Interval lost. Pulling from server');
|
82
|
+
tGetPayload();
|
83
|
+
}
|
84
|
+
}
|
85
|
+
return handlePayload;
|
86
|
+
}
|
87
|
+
exports.default = createPayloadHandler;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import _useAct from './useAct';
|
2
|
+
import _useSub from './useSub';
|
3
|
+
export declare const JasonProvider: ({ reducers, middleware, extraActions, children }: {
|
4
|
+
reducers: any;
|
5
|
+
middleware: any;
|
6
|
+
extraActions: any;
|
7
|
+
children: any;
|
8
|
+
}) => any;
|
9
|
+
export declare const useAct: typeof _useAct;
|
10
|
+
export declare const useSub: typeof _useSub;
|
data/client/lib/index.js
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.useSub = exports.useAct = exports.JasonProvider = void 0;
|
7
|
+
const JasonProvider_1 = __importDefault(require("./JasonProvider"));
|
8
|
+
const useAct_1 = __importDefault(require("./useAct"));
|
9
|
+
const useSub_1 = __importDefault(require("./useSub"));
|
10
|
+
exports.JasonProvider = JasonProvider_1.default;
|
11
|
+
exports.useAct = useAct_1.default;
|
12
|
+
exports.useSub = useSub_1.default;
|
@@ -0,0 +1 @@
|
|
1
|
+
export default function (schema: any): (entity: any, id?: null, relations?: never[]) => any;
|
@@ -0,0 +1,51 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const pluralize_1 = __importDefault(require("pluralize"));
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
8
|
+
const react_redux_1 = require("react-redux");
|
9
|
+
function default_1(schema) {
|
10
|
+
function addRelations(s, objects, objectType, relations) {
|
11
|
+
// first find out relation name
|
12
|
+
if (lodash_1.default.isArray(relations)) {
|
13
|
+
relations.forEach(relation => {
|
14
|
+
objects = addRelations(s, objects, objectType, relation);
|
15
|
+
});
|
16
|
+
}
|
17
|
+
else if (typeof (relations) === 'object') {
|
18
|
+
const relation = Object.keys(relations)[0];
|
19
|
+
const subRelations = relations[relation];
|
20
|
+
objects = addRelations(s, objects, objectType, relation);
|
21
|
+
objects[relation] = addRelations(s, objects[relation], pluralize_1.default(relation), subRelations);
|
22
|
+
// #
|
23
|
+
}
|
24
|
+
else if (typeof (relations) === 'string') {
|
25
|
+
const relation = relations;
|
26
|
+
if (lodash_1.default.isArray(objects)) {
|
27
|
+
objects = objects.map(obj => addRelations(s, obj, objectType, relation));
|
28
|
+
}
|
29
|
+
else {
|
30
|
+
const relatedObjects = lodash_1.default.values(s[pluralize_1.default(relation)].entities);
|
31
|
+
if (pluralize_1.default.isSingular(relation)) {
|
32
|
+
objects = Object.assign(Object.assign({}, objects), { [relation]: lodash_1.default.find(relatedObjects, { id: objects[relation + 'Id'] }) });
|
33
|
+
}
|
34
|
+
else {
|
35
|
+
objects = Object.assign(Object.assign({}, objects), { [relation]: relatedObjects.filter(e => e[pluralize_1.default.singular(objectType) + 'Id'] === objects.id) });
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
return objects;
|
40
|
+
}
|
41
|
+
function useEager(entity, id = null, relations = []) {
|
42
|
+
if (id) {
|
43
|
+
return react_redux_1.useSelector(s => addRelations(s, Object.assign({}, s[entity].entities[String(id)]), entity, relations));
|
44
|
+
}
|
45
|
+
else {
|
46
|
+
return react_redux_1.useSelector(s => addRelations(s, lodash_1.default.values(s[entity].entities), entity, relations));
|
47
|
+
}
|
48
|
+
}
|
49
|
+
return useEager;
|
50
|
+
}
|
51
|
+
exports.default = default_1;
|
@@ -0,0 +1 @@
|
|
1
|
+
export default function useAct(): any;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const JasonContext_1 = __importDefault(require("./JasonContext"));
|
7
|
+
const react_1 = require("react");
|
8
|
+
function useAct() {
|
9
|
+
const { actions } = react_1.useContext(JasonContext_1.default);
|
10
|
+
return actions;
|
11
|
+
}
|
12
|
+
exports.default = useAct;
|
@@ -0,0 +1 @@
|
|
1
|
+
export default function useSub(config: any): void;
|
@@ -0,0 +1,14 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
const JasonContext_1 = __importDefault(require("./JasonContext"));
|
7
|
+
const react_1 = require("react");
|
8
|
+
function useSub(config) {
|
9
|
+
const subscribe = react_1.useContext(JasonContext_1.default).subscribe;
|
10
|
+
react_1.useEffect(() => {
|
11
|
+
return subscribe(config);
|
12
|
+
}, []);
|
13
|
+
}
|
14
|
+
exports.default = useSub;
|
data/client/package.json
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
{
|
2
|
+
"name": "@jamesr2323/jason",
|
3
|
+
"version": "0.3.0",
|
4
|
+
"module": "./lib/index.js",
|
5
|
+
"scripts": {
|
6
|
+
"build": "tsc"
|
7
|
+
},
|
8
|
+
"dependencies": {
|
9
|
+
"@rails/actioncable": "^6.0.3-4",
|
10
|
+
"axios": "^0.21.0",
|
11
|
+
"axios-case-converter": "^0.6.0",
|
12
|
+
"blueimp-md5": "^2.18.0",
|
13
|
+
"humps": "^2.0.1",
|
14
|
+
"jsonpatch": "^3.0.1",
|
15
|
+
"lodash": "^4.17.20",
|
16
|
+
"pluralize": "^8.0.0",
|
17
|
+
"uuid": "^8.3.1"
|
18
|
+
},
|
19
|
+
"devDependencies": {
|
20
|
+
"typescript": "^4.1.2"
|
21
|
+
},
|
22
|
+
"peerDependencies": {
|
23
|
+
"react": "^16.8.3",
|
24
|
+
"react-redux": "^7.2.2",
|
25
|
+
"@reduxjs/toolkit": "^1.5.0"
|
26
|
+
}
|
27
|
+
}
|
@@ -0,0 +1,108 @@
|
|
1
|
+
import createActions from './createActions'
|
2
|
+
import { createConsumer } from "@rails/actioncable"
|
3
|
+
import JasonContext from './JasonContext'
|
4
|
+
import axios from 'axios'
|
5
|
+
import applyCaseMiddleware from 'axios-case-converter'
|
6
|
+
import { Provider } from 'react-redux'
|
7
|
+
import { createEntityAdapter, createSlice, createReducer, configureStore } from '@reduxjs/toolkit'
|
8
|
+
import createJasonReducers from './createJasonReducers'
|
9
|
+
import createPayloadHandler from './createPayloadHandler'
|
10
|
+
import makeEager from './makeEager'
|
11
|
+
import { camelizeKeys } from 'humps'
|
12
|
+
import md5 from 'blueimp-md5'
|
13
|
+
import _ from 'lodash'
|
14
|
+
import React, { useState, useEffect } from 'react'
|
15
|
+
|
16
|
+
const JasonProvider = ({ reducers, middleware, extraActions, children }) => {
|
17
|
+
const [store, setStore] = useState(null)
|
18
|
+
const [value, setValue] = useState(null)
|
19
|
+
const [connected, setConnected] = useState(false)
|
20
|
+
|
21
|
+
const csrfToken = (document.querySelector("meta[name=csrf-token]") as any).content
|
22
|
+
axios.defaults.headers.common['X-CSRF-Token'] = csrfToken
|
23
|
+
const restClient = applyCaseMiddleware(axios.create())
|
24
|
+
|
25
|
+
useEffect(() => {
|
26
|
+
restClient.get('/jason/api/schema')
|
27
|
+
.then(({ data: snakey_schema }) => {
|
28
|
+
const schema = camelizeKeys(snakey_schema)
|
29
|
+
|
30
|
+
const consumer = createConsumer()
|
31
|
+
const allReducers = {
|
32
|
+
...reducers,
|
33
|
+
...createJasonReducers(schema)
|
34
|
+
}
|
35
|
+
|
36
|
+
console.log({ schema, allReducers })
|
37
|
+
const store = configureStore({ reducer: allReducers, middleware })
|
38
|
+
|
39
|
+
let payloadHandlers = {}
|
40
|
+
function handlePayload(payload) {
|
41
|
+
const { model, md5Hash } = payload
|
42
|
+
console.log({ md5Hash, fn: `${model}:${md5Hash}`, payloadHandlers, model: _.camelCase(model), payload })
|
43
|
+
const handler = payloadHandlers[`${_.camelCase(model)}:${md5Hash}`]
|
44
|
+
if (handler) {
|
45
|
+
handler({ ...payload, model: _.camelCase(model) })
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
const subscription = (consumer.subscriptions.create({
|
50
|
+
channel: 'Jason::Channel'
|
51
|
+
}, {
|
52
|
+
connected: () => {
|
53
|
+
setConnected(true)
|
54
|
+
},
|
55
|
+
received: payload => {
|
56
|
+
console.log("Payload received", payload)
|
57
|
+
handlePayload(payload)
|
58
|
+
},
|
59
|
+
disconnected: () => console.warn('Disconnected from ActionCable')
|
60
|
+
}));
|
61
|
+
|
62
|
+
console.log('sending message')
|
63
|
+
subscription.send({ message: 'test' })
|
64
|
+
|
65
|
+
function createSubscription(config) {
|
66
|
+
const md5Hash = md5(JSON.stringify(config))
|
67
|
+
console.log('Subscribe with', config, md5Hash)
|
68
|
+
|
69
|
+
_.map(config, (v, model) => {
|
70
|
+
payloadHandlers[`${model}:${md5Hash}`] = createPayloadHandler(store.dispatch, subscription, model, schema[model])
|
71
|
+
})
|
72
|
+
subscription.send({ createSubscription: config })
|
73
|
+
|
74
|
+
return () => removeSubscription(config)
|
75
|
+
}
|
76
|
+
|
77
|
+
function removeSubscription(config) {
|
78
|
+
subscription.send({ removeSubscription: config })
|
79
|
+
const md5Hash = md5(JSON.stringify(config))
|
80
|
+
_.map(config, (v, model) => {
|
81
|
+
delete payloadHandlers[`${model}:${md5Hash}`]
|
82
|
+
})
|
83
|
+
}
|
84
|
+
|
85
|
+
const actions = createActions(schema, store, restClient, extraActions)
|
86
|
+
const eager = makeEager(schema)
|
87
|
+
|
88
|
+
console.log({ actions })
|
89
|
+
|
90
|
+
setValue({
|
91
|
+
actions: actions,
|
92
|
+
subscribe: (config) => createSubscription(config),
|
93
|
+
eager
|
94
|
+
})
|
95
|
+
setStore(store)
|
96
|
+
})
|
97
|
+
}, [])
|
98
|
+
|
99
|
+
if(!(store && value && connected)) return <div /> // Wait for async fetch of schema to complete
|
100
|
+
|
101
|
+
return <Provider store={store}>
|
102
|
+
<JasonContext.Provider value={value}>{ children }</JasonContext.Provider>
|
103
|
+
</Provider>
|
104
|
+
}
|
105
|
+
|
106
|
+
export default JasonProvider
|
107
|
+
|
108
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
import pluralize from 'pluralize'
|
2
|
+
import _ from 'lodash'
|
3
|
+
import { v4 as uuidv4 } from 'uuid'
|
4
|
+
|
5
|
+
export default (dis, store, entity, { extraActions = {}, hasPriority = false } = {}) => {
|
6
|
+
function add(data = {}) {
|
7
|
+
const id = uuidv4()
|
8
|
+
return dis({ type: `${pluralize(entity)}/add`, payload: { id, ...data } })
|
9
|
+
}
|
10
|
+
|
11
|
+
function upsert(id, data) {
|
12
|
+
return dis({ type: `${pluralize(entity)}/upsert`, payload: { id, ...data } })
|
13
|
+
}
|
14
|
+
|
15
|
+
function movePriority(id, priority, parentFilter = {}) {
|
16
|
+
return dis({ type: `${pluralize(entity)}/movePriority`, payload: { id, priority, parentFilter } })
|
17
|
+
}
|
18
|
+
|
19
|
+
function setAll(data) {
|
20
|
+
return dis({ type: `${pluralize(entity)}/setAll`, payload: data })
|
21
|
+
}
|
22
|
+
|
23
|
+
function remove(id) {
|
24
|
+
return dis({ type: `${pluralize(entity)}/remove`, payload: id })
|
25
|
+
}
|
26
|
+
|
27
|
+
const extraActionsResolved = _.mapValues(extraActions, v => v(dis, store, entity))
|
28
|
+
|
29
|
+
if (hasPriority) {
|
30
|
+
return { add, upsert, setAll, remove, movePriority, ...extraActionsResolved }
|
31
|
+
} else {
|
32
|
+
return { add, upsert, setAll, remove, ...extraActionsResolved }
|
33
|
+
}
|
34
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import actionFactory from './actionFactory'
|
2
|
+
import pluralize from 'pluralize'
|
3
|
+
import _ from 'lodash'
|
4
|
+
import { v4 as uuidv4 } from 'uuid'
|
5
|
+
|
6
|
+
function enrich(type, payload) {
|
7
|
+
if (type.split('/')[1] === 'upsert' && !(type.split('/')[0] === 'session')) {
|
8
|
+
if (!payload.id) {
|
9
|
+
return { ...payload, id: uuidv4() }
|
10
|
+
}
|
11
|
+
}
|
12
|
+
return payload
|
13
|
+
}
|
14
|
+
|
15
|
+
function makeOptDis(schema, dispatch, restClient) {
|
16
|
+
const plurals = _.keys(schema).map(k => pluralize(k))
|
17
|
+
|
18
|
+
return function (action) {
|
19
|
+
const { type, payload } = action
|
20
|
+
const data = enrich(type, payload)
|
21
|
+
|
22
|
+
dispatch(action)
|
23
|
+
|
24
|
+
if (plurals.indexOf(type.split('/')[0]) > -1) {
|
25
|
+
return restClient.post('/jason/api/action', { type, payload: data } )
|
26
|
+
.catch(e => {
|
27
|
+
dispatch({ type: 'upsertLocalUi', data: { error: JSON.stringify(e) } })
|
28
|
+
})
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
function createActions(schema, store, restClient, extraActions) {
|
34
|
+
const dis = store.dispatch;
|
35
|
+
const optDis = makeOptDis(schema, dis, restClient)
|
36
|
+
|
37
|
+
const actions = _.fromPairs(_.map(schema, (config, model: string) => {
|
38
|
+
if (config.priorityScope) {
|
39
|
+
return [pluralize(model), actionFactory(optDis, store, model, { hasPriority: true })]
|
40
|
+
} else {
|
41
|
+
return [pluralize(model), actionFactory(optDis, store, model)]
|
42
|
+
}
|
43
|
+
}))
|
44
|
+
|
45
|
+
const extraActionsResolved = extraActions(optDis, store, restClient)
|
46
|
+
|
47
|
+
return _.merge(actions, extraActionsResolved)
|
48
|
+
}
|
49
|
+
|
50
|
+
export default createActions
|