jason-rails 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +34 -0
- data/README.md +6 -9
- data/app/assets/config/jason_engine_manifest.js +1 -0
- data/app/assets/images/jason/engine/.keep +0 -0
- data/app/assets/stylesheets/jason/engine/application.css +15 -0
- data/app/controllers/jason/api_controller.rb +36 -0
- data/app/helpers/jason/engine/application_helper.rb +6 -0
- data/app/jobs/jason/engine/application_job.rb +6 -0
- data/app/mailers/jason/engine/application_mailer.rb +8 -0
- data/app/models/jason/engine/application_record.rb +7 -0
- data/app/views/layouts/jason/engine/application.html.erb +15 -0
- data/client/babel.config.js +13 -0
- data/client/lib/JasonProvider.d.ts +5 -4
- data/client/lib/JasonProvider.js +30 -3
- data/client/lib/actionFactory.js +1 -1
- data/client/lib/createActions.d.ts +1 -1
- data/client/lib/createActions.js +2 -27
- data/client/lib/createJasonReducers.js +1 -0
- data/client/lib/createOptDis.d.ts +1 -0
- data/client/lib/createOptDis.js +45 -0
- data/client/lib/createPayloadHandler.d.ts +1 -1
- data/client/lib/createPayloadHandler.js +23 -6
- data/client/lib/deepCamelizeKeys.d.ts +1 -0
- data/client/lib/deepCamelizeKeys.js +23 -0
- data/client/lib/deepCamelizeKeys.test.d.ts +1 -0
- data/client/lib/deepCamelizeKeys.test.js +106 -0
- data/client/lib/index.d.ts +4 -4
- data/client/package.json +17 -4
- data/client/src/JasonProvider.tsx +33 -5
- data/client/src/actionFactory.ts +1 -1
- data/client/src/createActions.ts +2 -33
- data/client/src/createJasonReducers.ts +1 -0
- data/client/src/createOptDis.ts +47 -0
- data/client/src/createPayloadHandler.ts +26 -4
- data/client/src/deepCamelizeKeys.test.ts +113 -0
- data/client/src/deepCamelizeKeys.ts +17 -0
- data/client/yarn.lock +4539 -81
- data/config/routes.rb +4 -0
- data/jason-rails.gemspec +5 -0
- data/lib/jason.rb +7 -1
- data/lib/jason/api_model.rb +16 -0
- data/lib/jason/channel.rb +2 -2
- data/lib/jason/engine.rb +5 -0
- data/lib/jason/publisher.rb +38 -6
- data/lib/jason/subscription.rb +21 -24
- data/lib/jason/version.rb +1 -1
- metadata +81 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4231946f3742dee57b9eb0eff4a7367691a1ddff2a2842fbba8ffde0c4f5d460
|
4
|
+
data.tar.gz: c701f79deb2e23b464b4f15f96442084fb4837d429e87715007b6cc41e31ba9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1222df088d647e53b24a735cd9c85b1cf926831171cb21ebd628b67f12fb320003fca93272d94e8173b13d30c21c6ca3cbd55899d604bb2d572196efeb56e8b3
|
7
|
+
data.tar.gz: 34ba69d74e1a6729bd88695ff56d62ea40abf3a804065c9803380bd16c948b9cfea51d33eae986cdc3e240db8f051cda2678a63bebfa87e2c144484f2f0f027b
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
jason-rails (0.3.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.4.4)
|
10
|
+
rake (12.3.3)
|
11
|
+
rspec (3.10.0)
|
12
|
+
rspec-core (~> 3.10.0)
|
13
|
+
rspec-expectations (~> 3.10.0)
|
14
|
+
rspec-mocks (~> 3.10.0)
|
15
|
+
rspec-core (3.10.0)
|
16
|
+
rspec-support (~> 3.10.0)
|
17
|
+
rspec-expectations (3.10.0)
|
18
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
19
|
+
rspec-support (~> 3.10.0)
|
20
|
+
rspec-mocks (3.10.0)
|
21
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
22
|
+
rspec-support (~> 3.10.0)
|
23
|
+
rspec-support (3.10.0)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
jason-rails!
|
30
|
+
rake (~> 12.0)
|
31
|
+
rspec (~> 3.0)
|
32
|
+
|
33
|
+
BUNDLED WITH
|
34
|
+
1.17.3
|
data/README.md
CHANGED
@@ -14,23 +14,20 @@ Jason attempts to minimize this repitition by auto-generating API endpoints, red
|
|
14
14
|
|
15
15
|
## Installation
|
16
16
|
|
17
|
-
Add
|
17
|
+
Add the gem and the NPM package
|
18
18
|
|
19
19
|
```ruby
|
20
20
|
gem 'jason-rails'
|
21
21
|
```
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
Or install it yourself as:
|
28
|
-
|
29
|
-
$ gem install jason
|
23
|
+
```bash
|
24
|
+
yarn add @jamesr2323/jason
|
25
|
+
```
|
30
26
|
|
31
27
|
## Usage
|
32
28
|
|
33
|
-
|
29
|
+
### Define your schema
|
30
|
+
|
34
31
|
|
35
32
|
## Development
|
36
33
|
|
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/jason/engine .css
|
File without changes
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Jason::ApiController < ::ApplicationController
|
2
|
+
def schema
|
3
|
+
render json: JASON_API_MODEL.to_json
|
4
|
+
end
|
5
|
+
|
6
|
+
def action
|
7
|
+
type = params[:type]
|
8
|
+
entity = type.split('/')[0].underscore
|
9
|
+
api_model = Jason::ApiModel.new(entity.singularize)
|
10
|
+
model = entity.singularize.camelize.constantize
|
11
|
+
action = type.split('/')[1].underscore
|
12
|
+
|
13
|
+
if action == 'move_priority'
|
14
|
+
id, priority = params[:payload].values_at(:id, :priority)
|
15
|
+
|
16
|
+
instance = model.find(id)
|
17
|
+
priority_filter = instance.as_json.with_indifferent_access.slice(*api_model.priority_scope)
|
18
|
+
|
19
|
+
all_instance_ids = model.send(api_model.scope || :all).where(priority_filter).where.not(id: instance.id).order(:priority).pluck(:id)
|
20
|
+
all_instance_ids.insert(priority.to_i, instance.id)
|
21
|
+
|
22
|
+
all_instance_ids.each_with_index do |id, i|
|
23
|
+
model.find(id).update!(priority: i, skip_publish_json: true)
|
24
|
+
end
|
25
|
+
|
26
|
+
model.publish_all(model.find(all_instance_ids))
|
27
|
+
elsif action == 'upsert' || action == 'add'
|
28
|
+
payload = api_model.permit(params)
|
29
|
+
return render json: model.find_or_create_by_id!(payload).as_json(api_model.as_json_config)
|
30
|
+
elsif action == 'remove'
|
31
|
+
model.find(params[:payload]).destroy!
|
32
|
+
end
|
33
|
+
|
34
|
+
return head :ok
|
35
|
+
end
|
36
|
+
end
|
@@ -1,7 +1,8 @@
|
|
1
|
+
import React from 'react';
|
1
2
|
declare const JasonProvider: ({ reducers, middleware, extraActions, children }: {
|
2
|
-
reducers
|
3
|
-
middleware
|
4
|
-
extraActions
|
5
|
-
children
|
3
|
+
reducers?: any;
|
4
|
+
middleware?: any;
|
5
|
+
extraActions?: any;
|
6
|
+
children?: any;
|
6
7
|
}) => any;
|
7
8
|
export default JasonProvider;
|
data/client/lib/JasonProvider.js
CHANGED
@@ -31,22 +31,48 @@ const react_redux_1 = require("react-redux");
|
|
31
31
|
const toolkit_1 = require("@reduxjs/toolkit");
|
32
32
|
const createJasonReducers_1 = __importDefault(require("./createJasonReducers"));
|
33
33
|
const createPayloadHandler_1 = __importDefault(require("./createPayloadHandler"));
|
34
|
+
const createOptDis_1 = __importDefault(require("./createOptDis"));
|
34
35
|
const makeEager_1 = __importDefault(require("./makeEager"));
|
35
36
|
const humps_1 = require("humps");
|
36
37
|
const blueimp_md5_1 = __importDefault(require("blueimp-md5"));
|
37
38
|
const lodash_1 = __importDefault(require("lodash"));
|
38
39
|
const react_1 = __importStar(require("react"));
|
40
|
+
const uuid_1 = require("uuid");
|
39
41
|
const JasonProvider = ({ reducers, middleware, extraActions, children }) => {
|
40
42
|
const [store, setStore] = react_1.useState(null);
|
41
43
|
const [value, setValue] = react_1.useState(null);
|
42
44
|
const [connected, setConnected] = react_1.useState(false);
|
43
45
|
const csrfToken = document.querySelector("meta[name=csrf-token]").content;
|
44
46
|
axios_1.default.defaults.headers.common['X-CSRF-Token'] = csrfToken;
|
45
|
-
const restClient = axios_case_converter_1.default(axios_1.default.create()
|
47
|
+
const restClient = axios_case_converter_1.default(axios_1.default.create(), {
|
48
|
+
preservedKeys: (key) => {
|
49
|
+
return uuid_1.validate(key);
|
50
|
+
}
|
51
|
+
});
|
46
52
|
react_1.useEffect(() => {
|
47
53
|
restClient.get('/jason/api/schema')
|
48
54
|
.then(({ data: snakey_schema }) => {
|
49
55
|
const schema = humps_1.camelizeKeys(snakey_schema);
|
56
|
+
const serverActionQueue = function () {
|
57
|
+
const queue = [];
|
58
|
+
let inFlight = false;
|
59
|
+
return {
|
60
|
+
addItem: (item) => queue.push(item),
|
61
|
+
getItem: () => {
|
62
|
+
if (inFlight)
|
63
|
+
return false;
|
64
|
+
const item = queue.shift();
|
65
|
+
if (item) {
|
66
|
+
inFlight = true;
|
67
|
+
return item;
|
68
|
+
}
|
69
|
+
return false;
|
70
|
+
},
|
71
|
+
itemProcessed: () => inFlight = false,
|
72
|
+
fullySynced: () => queue.length === 0 && !inFlight,
|
73
|
+
getData: () => ({ queue, inFlight })
|
74
|
+
};
|
75
|
+
}();
|
50
76
|
const consumer = actioncable_1.createConsumer();
|
51
77
|
const allReducers = Object.assign(Object.assign({}, reducers), createJasonReducers_1.default(schema));
|
52
78
|
console.log({ schema, allReducers });
|
@@ -78,7 +104,7 @@ const JasonProvider = ({ reducers, middleware, extraActions, children }) => {
|
|
78
104
|
const md5Hash = blueimp_md5_1.default(JSON.stringify(config));
|
79
105
|
console.log('Subscribe with', config, md5Hash);
|
80
106
|
lodash_1.default.map(config, (v, model) => {
|
81
|
-
payloadHandlers[`${model}:${md5Hash}`] = createPayloadHandler_1.default(store.dispatch, subscription, model, schema[model]);
|
107
|
+
payloadHandlers[`${model}:${md5Hash}`] = createPayloadHandler_1.default(store.dispatch, serverActionQueue, subscription, model, schema[model]);
|
82
108
|
});
|
83
109
|
subscription.send({ createSubscription: config });
|
84
110
|
return () => removeSubscription(config);
|
@@ -90,7 +116,8 @@ const JasonProvider = ({ reducers, middleware, extraActions, children }) => {
|
|
90
116
|
delete payloadHandlers[`${model}:${md5Hash}`];
|
91
117
|
});
|
92
118
|
}
|
93
|
-
const
|
119
|
+
const optDis = createOptDis_1.default(schema, store.dispatch, restClient, serverActionQueue);
|
120
|
+
const actions = createActions_1.default(schema, store, restClient, optDis, extraActions);
|
94
121
|
const eager = makeEager_1.default(schema);
|
95
122
|
console.log({ actions });
|
96
123
|
setValue({
|
data/client/lib/actionFactory.js
CHANGED
@@ -23,7 +23,7 @@ exports.default = (dis, store, entity, { extraActions = {}, hasPriority = false
|
|
23
23
|
function remove(id) {
|
24
24
|
return dis({ type: `${pluralize_1.default(entity)}/remove`, payload: id });
|
25
25
|
}
|
26
|
-
const extraActionsResolved = lodash_1.default.mapValues(extraActions, v => v(dis, store, entity));
|
26
|
+
const extraActionsResolved = extraActions ? lodash_1.default.mapValues(extraActions, v => v(dis, store, entity)) : {};
|
27
27
|
if (hasPriority) {
|
28
28
|
return Object.assign({ add, upsert, setAll, remove, movePriority }, extraActionsResolved);
|
29
29
|
}
|
@@ -1,2 +1,2 @@
|
|
1
|
-
declare function createActions(schema: any, store: any, restClient: any, extraActions: any): any;
|
1
|
+
declare function createActions(schema: any, store: any, restClient: any, optDis: any, extraActions: any): any;
|
2
2
|
export default createActions;
|
data/client/lib/createActions.js
CHANGED
@@ -6,32 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const actionFactory_1 = __importDefault(require("./actionFactory"));
|
7
7
|
const pluralize_1 = __importDefault(require("pluralize"));
|
8
8
|
const lodash_1 = __importDefault(require("lodash"));
|
9
|
-
|
10
|
-
function enrich(type, payload) {
|
11
|
-
if (type.split('/')[1] === 'upsert' && !(type.split('/')[0] === 'session')) {
|
12
|
-
if (!payload.id) {
|
13
|
-
return Object.assign(Object.assign({}, payload), { id: uuid_1.v4() });
|
14
|
-
}
|
15
|
-
}
|
16
|
-
return payload;
|
17
|
-
}
|
18
|
-
function makeOptDis(schema, dispatch, restClient) {
|
19
|
-
const plurals = lodash_1.default.keys(schema).map(k => pluralize_1.default(k));
|
20
|
-
return function (action) {
|
21
|
-
const { type, payload } = action;
|
22
|
-
const data = enrich(type, payload);
|
23
|
-
dispatch(action);
|
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
|
-
function createActions(schema, store, restClient, extraActions) {
|
33
|
-
const dis = store.dispatch;
|
34
|
-
const optDis = makeOptDis(schema, dis, restClient);
|
9
|
+
function createActions(schema, store, restClient, optDis, extraActions) {
|
35
10
|
const actions = lodash_1.default.fromPairs(lodash_1.default.map(schema, (config, model) => {
|
36
11
|
if (config.priorityScope) {
|
37
12
|
return [pluralize_1.default(model), actionFactory_1.default(optDis, store, model, { hasPriority: true })];
|
@@ -40,7 +15,7 @@ function createActions(schema, store, restClient, extraActions) {
|
|
40
15
|
return [pluralize_1.default(model), actionFactory_1.default(optDis, store, model)];
|
41
16
|
}
|
42
17
|
}));
|
43
|
-
const extraActionsResolved = extraActions(optDis, store, restClient);
|
18
|
+
const extraActionsResolved = extraActions ? extraActions(optDis, store, restClient, actions) : {};
|
44
19
|
return lodash_1.default.merge(actions, extraActionsResolved);
|
45
20
|
}
|
46
21
|
exports.default = createActions;
|
@@ -19,6 +19,7 @@ function generateSlices(schema) {
|
|
19
19
|
add: adapter.addOne,
|
20
20
|
setAll: adapter.setAll,
|
21
21
|
remove: adapter.removeOne,
|
22
|
+
removeMany: adapter.removeMany,
|
22
23
|
movePriority: (s, { payload: { id, priority, parentFilter } }) => {
|
23
24
|
// Get IDs and insert our item at the new index
|
24
25
|
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);
|
@@ -0,0 +1 @@
|
|
1
|
+
export default function createOptDis(schema: any, dispatch: any, restClient: any, serverActionQueue: any): (action: any) => void;
|
@@ -0,0 +1,45 @@
|
|
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 lodash_1 = __importDefault(require("lodash"));
|
7
|
+
const pluralize_1 = __importDefault(require("pluralize"));
|
8
|
+
const uuid_1 = require("uuid");
|
9
|
+
function enrich(type, payload) {
|
10
|
+
if (type.split('/')[1] === 'upsert' && !(type.split('/')[0] === 'session')) {
|
11
|
+
if (!payload.id) {
|
12
|
+
return Object.assign(Object.assign({}, payload), { id: uuid_1.v4() });
|
13
|
+
}
|
14
|
+
}
|
15
|
+
return payload;
|
16
|
+
}
|
17
|
+
function createOptDis(schema, dispatch, restClient, serverActionQueue) {
|
18
|
+
const plurals = lodash_1.default.keys(schema).map(k => pluralize_1.default(k));
|
19
|
+
let inFlight = false;
|
20
|
+
function enqueueServerAction(action) {
|
21
|
+
serverActionQueue.addItem(action);
|
22
|
+
}
|
23
|
+
function dispatchServerAction() {
|
24
|
+
const action = serverActionQueue.getItem();
|
25
|
+
if (!action)
|
26
|
+
return;
|
27
|
+
inFlight = true;
|
28
|
+
restClient.post('/jason/api/action', action)
|
29
|
+
.then(serverActionQueue.itemProcessed)
|
30
|
+
.catch(e => {
|
31
|
+
dispatch({ type: 'upsertLocalUi', data: { error: JSON.stringify(e) } });
|
32
|
+
serverActionQueue.itemProcessed();
|
33
|
+
});
|
34
|
+
}
|
35
|
+
setInterval(dispatchServerAction, 10);
|
36
|
+
return function (action) {
|
37
|
+
const { type, payload } = action;
|
38
|
+
const data = enrich(type, payload);
|
39
|
+
dispatch({ type, payload: data });
|
40
|
+
if (plurals.indexOf(type.split('/')[0]) > -1) {
|
41
|
+
enqueueServerAction({ type, payload: data });
|
42
|
+
}
|
43
|
+
};
|
44
|
+
}
|
45
|
+
exports.default = createOptDis;
|
@@ -1 +1 @@
|
|
1
|
-
export default function createPayloadHandler(dispatch: any, subscription: any, model: any, config: any): (data: any) => null | undefined;
|
1
|
+
export default function createPayloadHandler(dispatch: any, serverActionQueue: any, subscription: any, model: any, config: any): (data: any) => null | undefined;
|
@@ -4,16 +4,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
const jsonpatch_1 = require("jsonpatch");
|
7
|
-
const
|
7
|
+
const deepCamelizeKeys_1 = __importDefault(require("./deepCamelizeKeys"));
|
8
8
|
const pluralize_1 = __importDefault(require("pluralize"));
|
9
9
|
const lodash_1 = __importDefault(require("lodash"));
|
10
|
+
const uuid_1 = require("uuid");
|
10
11
|
function diffSeconds(dt2, dt1) {
|
11
12
|
var diff = (dt2.getTime() - dt1.getTime()) / 1000;
|
12
13
|
return Math.abs(Math.round(diff));
|
13
14
|
}
|
14
|
-
function createPayloadHandler(dispatch, subscription, model, config) {
|
15
|
+
function createPayloadHandler(dispatch, serverActionQueue, subscription, model, config) {
|
15
16
|
console.log({ model, config });
|
16
|
-
let payload =
|
17
|
+
let payload = [];
|
18
|
+
let previousPayload = [];
|
17
19
|
let idx = 0;
|
18
20
|
let patchQueue = {};
|
19
21
|
let lastCheckAt = new Date();
|
@@ -23,16 +25,31 @@ function createPayloadHandler(dispatch, subscription, model, config) {
|
|
23
25
|
console.log({ getPayload: model, subscription });
|
24
26
|
subscription.send({ getPayload: { model, config } });
|
25
27
|
}
|
28
|
+
function camelizeKeys(item) {
|
29
|
+
return deepCamelizeKeys_1.default(item, key => uuid_1.validate(key));
|
30
|
+
}
|
26
31
|
const tGetPayload = lodash_1.default.throttle(getPayload, 10000);
|
27
32
|
function dispatchPayload() {
|
33
|
+
// We want to avoid updates from server overwriting changes to local state, so if there is a queue then wait.
|
34
|
+
if (!serverActionQueue.fullySynced()) {
|
35
|
+
console.log(serverActionQueue.getData());
|
36
|
+
setTimeout(dispatchPayload, 100);
|
37
|
+
return;
|
38
|
+
}
|
28
39
|
const includeModels = (config.includeModels || []).map(m => lodash_1.default.camelCase(m));
|
29
40
|
console.log("Dispatching", { payload, includeModels });
|
30
41
|
includeModels.forEach(m => {
|
31
|
-
const subPayload = lodash_1.default.flatten(lodash_1.default.compact(
|
32
|
-
|
42
|
+
const subPayload = lodash_1.default.flatten(lodash_1.default.compact(camelizeKeys(payload).map(instance => instance[m])));
|
43
|
+
const previousSubPayload = lodash_1.default.flatten(lodash_1.default.compact(camelizeKeys(previousPayload).map(instance => instance[m])));
|
44
|
+
// Find IDs that were in the payload but are no longer
|
45
|
+
const idsToRemove = lodash_1.default.difference(previousSubPayload.map(i => i.id), subPayload.map(i => i.id));
|
33
46
|
dispatch({ type: `${pluralize_1.default(m)}/upsertMany`, payload: subPayload });
|
47
|
+
dispatch({ type: `${pluralize_1.default(m)}/removeMany`, payload: idsToRemove });
|
34
48
|
});
|
35
|
-
|
49
|
+
const idsToRemove = lodash_1.default.difference(previousPayload.map(i => i.id), payload.map(i => i.id));
|
50
|
+
dispatch({ type: `${pluralize_1.default(model)}/upsertMany`, payload: camelizeKeys(payload) });
|
51
|
+
dispatch({ type: `${pluralize_1.default(model)}/removeMany`, payload: idsToRemove });
|
52
|
+
previousPayload = payload;
|
36
53
|
}
|
37
54
|
function processQueue() {
|
38
55
|
console.log({ idx, patchQueue });
|