@akanjs/store 0.0.53 → 0.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.mjs +1 -0
- package/package.json +7 -1
- package/src/index.mjs +2 -0
- package/src/storeDecorators.mjs +1095 -0
- package/src/types.mjs +0 -0
package/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/store",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.55",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -17,5 +17,11 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"react": "^18.3.1",
|
|
19
19
|
"zustand": "^5.0.2"
|
|
20
|
+
},
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"require": "./index.js",
|
|
24
|
+
"import": "./index.mjs"
|
|
25
|
+
}
|
|
20
26
|
}
|
|
21
27
|
}
|
package/src/index.mjs
ADDED
|
@@ -0,0 +1,1095 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { DataList } from "@akanjs/base";
|
|
3
|
+
import {
|
|
4
|
+
applyMixins,
|
|
5
|
+
capitalize,
|
|
6
|
+
deepObjectify,
|
|
7
|
+
isQueryEqual,
|
|
8
|
+
Logger,
|
|
9
|
+
lowerlize,
|
|
10
|
+
pathSet
|
|
11
|
+
} from "@akanjs/common";
|
|
12
|
+
import {
|
|
13
|
+
getClassMeta,
|
|
14
|
+
getFieldMetas,
|
|
15
|
+
getFullModelRef,
|
|
16
|
+
getLightModelRef
|
|
17
|
+
} from "@akanjs/constant";
|
|
18
|
+
import { msg } from "@akanjs/dictionary";
|
|
19
|
+
import {
|
|
20
|
+
getGqlOnStorage,
|
|
21
|
+
immerify
|
|
22
|
+
} from "@akanjs/signal";
|
|
23
|
+
import { useEffect, useRef } from "react";
|
|
24
|
+
import { create } from "zustand";
|
|
25
|
+
import { devtools, subscribeWithSelector } from "zustand/middleware";
|
|
26
|
+
import { immer } from "zustand/middleware/immer";
|
|
27
|
+
const st = {};
|
|
28
|
+
class StoreStorage {
|
|
29
|
+
}
|
|
30
|
+
const getStoreMeta = (storeName) => {
|
|
31
|
+
const storeMeta = Reflect.getMetadata(storeName, StoreStorage.prototype);
|
|
32
|
+
if (!storeMeta)
|
|
33
|
+
throw new Error(`storeMeta is not defined: ${storeName}`);
|
|
34
|
+
return storeMeta;
|
|
35
|
+
};
|
|
36
|
+
const setStoreMeta = (storeName, storeMeta) => {
|
|
37
|
+
Reflect.defineMetadata(storeName, storeMeta, StoreStorage.prototype);
|
|
38
|
+
};
|
|
39
|
+
const getStoreNames = () => {
|
|
40
|
+
const storeNames = Reflect.getMetadataKeys(StoreStorage.prototype);
|
|
41
|
+
if (!storeNames)
|
|
42
|
+
throw new Error(`storeNames is not defined`);
|
|
43
|
+
return storeNames;
|
|
44
|
+
};
|
|
45
|
+
const createState = (gql) => {
|
|
46
|
+
const [fieldName, className] = [lowerlize(gql.refName), capitalize(gql.refName)];
|
|
47
|
+
const names = {
|
|
48
|
+
model: fieldName,
|
|
49
|
+
Model: className,
|
|
50
|
+
modelLoading: `${fieldName}Loading`,
|
|
51
|
+
modelForm: `${fieldName}Form`,
|
|
52
|
+
modelFormLoading: `${fieldName}FormLoading`,
|
|
53
|
+
modelSubmit: `${fieldName}Submit`,
|
|
54
|
+
modelViewAt: `${fieldName}ViewAt`,
|
|
55
|
+
modelModal: `${fieldName}Modal`,
|
|
56
|
+
modelOperation: `${fieldName}Operation`,
|
|
57
|
+
defaultModel: `default${className}`,
|
|
58
|
+
defaultModelInsight: `default${className}Insight`,
|
|
59
|
+
modelList: `${fieldName}List`,
|
|
60
|
+
modelListLoading: `${fieldName}ListLoading`,
|
|
61
|
+
modelInitList: `${fieldName}InitList`,
|
|
62
|
+
modelInitAt: `${fieldName}InitAt`,
|
|
63
|
+
modelSelection: `${fieldName}Selection`,
|
|
64
|
+
modelInsight: `${fieldName}Insight`,
|
|
65
|
+
lastPageOfModel: `lastPageOf${className}`,
|
|
66
|
+
pageOfModel: `pageOf${className}`,
|
|
67
|
+
limitOfModel: `limitOf${className}`,
|
|
68
|
+
queryArgsOfModel: `queryArgsOf${className}`,
|
|
69
|
+
sortOfModel: `sortOf${className}`
|
|
70
|
+
};
|
|
71
|
+
const baseState = {
|
|
72
|
+
[names.model]: null,
|
|
73
|
+
[names.modelLoading]: true,
|
|
74
|
+
[names.modelForm]: { ...gql[names.defaultModel] },
|
|
75
|
+
[names.modelFormLoading]: true,
|
|
76
|
+
[names.modelSubmit]: { disabled: true, loading: false, times: 0 },
|
|
77
|
+
[names.modelViewAt]: /* @__PURE__ */ new Date(0),
|
|
78
|
+
[names.modelModal]: null,
|
|
79
|
+
[names.modelOperation]: "sleep"
|
|
80
|
+
};
|
|
81
|
+
const sliceState = gql.slices.reduce((acc, { sliceName, defaultArgs }) => {
|
|
82
|
+
const SliceName = capitalize(sliceName);
|
|
83
|
+
const namesOfSlice = {
|
|
84
|
+
defaultModel: SliceName.replace(names.Model, names.defaultModel),
|
|
85
|
+
//clusterInSelf Cluster
|
|
86
|
+
modelList: sliceName.replace(names.model, names.modelList),
|
|
87
|
+
modelListLoading: sliceName.replace(names.model, names.modelListLoading),
|
|
88
|
+
modelInitList: sliceName.replace(names.model, names.modelInitList),
|
|
89
|
+
modelInitAt: sliceName.replace(names.model, names.modelInitAt),
|
|
90
|
+
modelSelection: sliceName.replace(names.model, names.modelSelection),
|
|
91
|
+
modelInsight: sliceName.replace(names.model, names.modelInsight),
|
|
92
|
+
lastPageOfModel: SliceName.replace(names.Model, names.lastPageOfModel),
|
|
93
|
+
pageOfModel: SliceName.replace(names.Model, names.pageOfModel),
|
|
94
|
+
limitOfModel: SliceName.replace(names.Model, names.limitOfModel),
|
|
95
|
+
queryArgsOfModel: SliceName.replace(names.Model, names.queryArgsOfModel),
|
|
96
|
+
sortOfModel: SliceName.replace(names.Model, names.sortOfModel)
|
|
97
|
+
};
|
|
98
|
+
const singleSliceState = {
|
|
99
|
+
[namesOfSlice.defaultModel]: { ...gql[names.defaultModel] },
|
|
100
|
+
[namesOfSlice.modelList]: new DataList(),
|
|
101
|
+
[namesOfSlice.modelListLoading]: true,
|
|
102
|
+
[namesOfSlice.modelInitList]: new DataList(),
|
|
103
|
+
[namesOfSlice.modelInitAt]: /* @__PURE__ */ new Date(0),
|
|
104
|
+
[namesOfSlice.modelSelection]: new DataList(),
|
|
105
|
+
[namesOfSlice.modelInsight]: gql[names.defaultModelInsight],
|
|
106
|
+
[namesOfSlice.lastPageOfModel]: 1,
|
|
107
|
+
[namesOfSlice.pageOfModel]: 1,
|
|
108
|
+
[namesOfSlice.limitOfModel]: 20,
|
|
109
|
+
[namesOfSlice.queryArgsOfModel]: defaultArgs,
|
|
110
|
+
[namesOfSlice.sortOfModel]: "latest"
|
|
111
|
+
};
|
|
112
|
+
return Object.assign(acc, singleSliceState);
|
|
113
|
+
}, {});
|
|
114
|
+
return { ...baseState, ...sliceState };
|
|
115
|
+
};
|
|
116
|
+
const createActions = (gql) => {
|
|
117
|
+
const formSetterActions = makeFormSetter(gql);
|
|
118
|
+
const baseActions = makeActions(gql);
|
|
119
|
+
return { ...formSetterActions, ...baseActions };
|
|
120
|
+
};
|
|
121
|
+
const makeFormSetter = (gql) => {
|
|
122
|
+
const fileGql = getGqlOnStorage("file");
|
|
123
|
+
const [fieldName, className] = [lowerlize(gql.refName), capitalize(gql.refName)];
|
|
124
|
+
const modelRef = getFullModelRef(gql.refName);
|
|
125
|
+
const fieldMetas = getFieldMetas(modelRef);
|
|
126
|
+
const names = {
|
|
127
|
+
model: fieldName,
|
|
128
|
+
Model: className,
|
|
129
|
+
modelForm: `${fieldName}Form`,
|
|
130
|
+
writeOnModel: `writeOn${className}`,
|
|
131
|
+
addModelFiles: `add${className}Files`
|
|
132
|
+
};
|
|
133
|
+
const baseSetAction = {
|
|
134
|
+
[names.writeOnModel]: function(path, value) {
|
|
135
|
+
this.set((state) => {
|
|
136
|
+
pathSet(state[names.modelForm], path, value);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const fieldSetAction = fieldMetas.reduce((acc, fieldMeta) => {
|
|
141
|
+
const [fieldKeyName, classKeyName] = [lowerlize(fieldMeta.key), capitalize(fieldMeta.key)];
|
|
142
|
+
const namesOfField = {
|
|
143
|
+
field: fieldKeyName,
|
|
144
|
+
Field: classKeyName,
|
|
145
|
+
setFieldOnModel: `set${classKeyName}On${className}`,
|
|
146
|
+
addFieldOnModel: `add${classKeyName}On${className}`,
|
|
147
|
+
subFieldOnModel: `sub${classKeyName}On${className}`,
|
|
148
|
+
addOrSubFieldOnModel: `addOrSub${classKeyName}On${className}`,
|
|
149
|
+
uploadFieldOnModel: `upload${classKeyName}On${className}`
|
|
150
|
+
};
|
|
151
|
+
const singleFieldSetAction = {
|
|
152
|
+
[namesOfField.setFieldOnModel]: function(value) {
|
|
153
|
+
this.set((state) => {
|
|
154
|
+
const setValue = fieldMeta.isClass ? immerify(fieldMeta.modelRef, value) : value;
|
|
155
|
+
state[names.modelForm][namesOfField.field] = setValue;
|
|
156
|
+
});
|
|
157
|
+
},
|
|
158
|
+
...fieldMeta.isArray ? {
|
|
159
|
+
[namesOfField.addFieldOnModel]: function(value, options = {}) {
|
|
160
|
+
const form = this.get()[names.modelForm];
|
|
161
|
+
const length = form[namesOfField.field].length;
|
|
162
|
+
if (options.limit && options.limit <= length)
|
|
163
|
+
return;
|
|
164
|
+
const idx = options.idx ?? length;
|
|
165
|
+
const setValue = fieldMeta.isClass ? immerify(fieldMeta.modelRef, value) : value;
|
|
166
|
+
this.set((state) => {
|
|
167
|
+
state[names.modelForm][namesOfField.field] = [
|
|
168
|
+
...form[namesOfField.field].slice(0, idx),
|
|
169
|
+
...Array.isArray(setValue) ? setValue : [setValue],
|
|
170
|
+
...form[namesOfField.field].slice(idx)
|
|
171
|
+
];
|
|
172
|
+
});
|
|
173
|
+
},
|
|
174
|
+
[namesOfField.subFieldOnModel]: function(idx) {
|
|
175
|
+
const form = this.get()[names.modelForm];
|
|
176
|
+
this.set((state) => {
|
|
177
|
+
state[names.modelForm][namesOfField.field] = typeof idx === "number" ? form[namesOfField.field].filter((_, i) => i !== idx) : form[namesOfField.field].filter((_, i) => !idx.includes(i));
|
|
178
|
+
});
|
|
179
|
+
},
|
|
180
|
+
[namesOfField.addOrSubFieldOnModel]: function(value, options = {}) {
|
|
181
|
+
const { [names.modelForm]: form } = this.get();
|
|
182
|
+
const index = form[namesOfField.field].findIndex((v) => v === value);
|
|
183
|
+
if (index === -1)
|
|
184
|
+
this[namesOfField.addFieldOnModel](value, options);
|
|
185
|
+
else
|
|
186
|
+
this[namesOfField.subFieldOnModel](index);
|
|
187
|
+
}
|
|
188
|
+
} : {},
|
|
189
|
+
...fieldMeta.name === "File" ? {
|
|
190
|
+
[namesOfField.uploadFieldOnModel]: async function(fileList, index) {
|
|
191
|
+
const form = this.get()[names.modelForm];
|
|
192
|
+
if (!fileList.length)
|
|
193
|
+
return;
|
|
194
|
+
const files = await gql[names.addModelFiles](
|
|
195
|
+
fileList,
|
|
196
|
+
form.id
|
|
197
|
+
);
|
|
198
|
+
if (fieldMeta.isArray) {
|
|
199
|
+
const idx = index ?? form[namesOfField.field].length;
|
|
200
|
+
this.set((state) => {
|
|
201
|
+
state[names.modelForm][namesOfField.field] = [
|
|
202
|
+
...form[namesOfField.field].slice(0, idx),
|
|
203
|
+
...files,
|
|
204
|
+
...form[namesOfField.field].slice(idx)
|
|
205
|
+
];
|
|
206
|
+
});
|
|
207
|
+
} else {
|
|
208
|
+
this.set((state) => {
|
|
209
|
+
state[names.modelForm][namesOfField.field] = files[0];
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
files.map((file) => {
|
|
213
|
+
const intervalKey = setInterval(() => {
|
|
214
|
+
void (async () => {
|
|
215
|
+
const currentFile = await fileGql.file(file.id);
|
|
216
|
+
if (fieldMeta.isArray)
|
|
217
|
+
this.set((state) => {
|
|
218
|
+
state[names.modelForm][namesOfField.field] = state[names.modelForm][namesOfField.field].map(
|
|
219
|
+
(file2) => file2.id === currentFile.id ? currentFile : file2
|
|
220
|
+
);
|
|
221
|
+
});
|
|
222
|
+
else
|
|
223
|
+
this.set((state) => {
|
|
224
|
+
state[names.modelForm][namesOfField.field] = currentFile;
|
|
225
|
+
});
|
|
226
|
+
if (currentFile.status !== "uploading")
|
|
227
|
+
clearInterval(intervalKey);
|
|
228
|
+
})();
|
|
229
|
+
}, 3e3);
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
} : {}
|
|
233
|
+
};
|
|
234
|
+
return Object.assign(acc, singleFieldSetAction);
|
|
235
|
+
}, {});
|
|
236
|
+
return Object.assign(fieldSetAction, baseSetAction);
|
|
237
|
+
};
|
|
238
|
+
const makeActions = (gql) => {
|
|
239
|
+
const [fieldName, className] = [lowerlize(gql.refName), capitalize(gql.refName)];
|
|
240
|
+
const modelRef = getFullModelRef(className);
|
|
241
|
+
const lightModelRef = getLightModelRef(modelRef);
|
|
242
|
+
const names = {
|
|
243
|
+
model: fieldName,
|
|
244
|
+
_model: `_${fieldName}`,
|
|
245
|
+
Model: className,
|
|
246
|
+
purifyModel: `purify${className}`,
|
|
247
|
+
crystalizeModel: `crystalize${className}`,
|
|
248
|
+
lightCrystalizeModel: `lightCrystalize${className}`,
|
|
249
|
+
crystalizeInsight: `crystalize${className}Insight`,
|
|
250
|
+
modelOperation: `${fieldName}Operation`,
|
|
251
|
+
defaultModel: `default${className}`,
|
|
252
|
+
modelInsight: `${fieldName}Insight`,
|
|
253
|
+
modelForm: `${fieldName}Form`,
|
|
254
|
+
modelSubmit: `${fieldName}Submit`,
|
|
255
|
+
modelLoading: `${fieldName}Loading`,
|
|
256
|
+
modelFormLoading: `${fieldName}FormLoading`,
|
|
257
|
+
modelList: `${fieldName}List`,
|
|
258
|
+
modelListLoading: `${fieldName}ListLoading`,
|
|
259
|
+
modelSelection: `${fieldName}Selection`,
|
|
260
|
+
createModelInForm: `create${className}InForm`,
|
|
261
|
+
updateModelInForm: `modify${className}InForm`,
|
|
262
|
+
createModel: `create${className}`,
|
|
263
|
+
updateModel: `update${className}`,
|
|
264
|
+
removeModel: `remove${className}`,
|
|
265
|
+
checkModelSubmitable: `check${className}Submitable`,
|
|
266
|
+
submitModel: `submit${className}`,
|
|
267
|
+
newModel: `new${className}`,
|
|
268
|
+
editModel: `edit${className}`,
|
|
269
|
+
mergeModel: `merge${className}`,
|
|
270
|
+
viewModel: `view${className}`,
|
|
271
|
+
setModel: `set${className}`,
|
|
272
|
+
resetModel: `reset${className}`,
|
|
273
|
+
modelViewAt: `${fieldName}ViewAt`,
|
|
274
|
+
modelModal: `${fieldName}Modal`,
|
|
275
|
+
initModel: `init${className}`,
|
|
276
|
+
modelInitList: `${fieldName}InitList`,
|
|
277
|
+
modelInitAt: `${fieldName}InitAt`,
|
|
278
|
+
refreshModel: `refresh${className}`,
|
|
279
|
+
selectModel: `select${className}`,
|
|
280
|
+
setPageOfModel: `setPageOf${className}`,
|
|
281
|
+
addPageOfModel: `addPageOf${className}`,
|
|
282
|
+
setLimitOfModel: `setLimitOf${className}`,
|
|
283
|
+
setQueryArgsOfModel: `setQueryArgsOf${className}`,
|
|
284
|
+
setSortOfModel: `setSortOf${className}`,
|
|
285
|
+
lastPageOfModel: `lastPageOf${className}`,
|
|
286
|
+
pageOfModel: `pageOf${className}`,
|
|
287
|
+
limitOfModel: `limitOf${className}`,
|
|
288
|
+
queryArgsOfModel: `queryArgsOf${className}`,
|
|
289
|
+
sortOfModel: `sortOf${className}`
|
|
290
|
+
};
|
|
291
|
+
const baseAction = {
|
|
292
|
+
[names.createModelInForm]: async function({ idx, path, modal, sliceName = names.model, onError, onSuccess } = {}) {
|
|
293
|
+
const SliceName = capitalize(sliceName);
|
|
294
|
+
const namesOfSlice = {
|
|
295
|
+
defaultModel: SliceName.replace(names.Model, names.defaultModel),
|
|
296
|
+
modelList: sliceName.replace(names.model, names.modelList),
|
|
297
|
+
modelListLoading: sliceName.replace(names.model, names.modelListLoading),
|
|
298
|
+
modelInsight: sliceName.replace(names.model, names.modelInsight)
|
|
299
|
+
};
|
|
300
|
+
const currentState = this.get();
|
|
301
|
+
const modelForm = currentState[names.modelForm];
|
|
302
|
+
const modelList = currentState[namesOfSlice.modelList];
|
|
303
|
+
const modelListLoading = currentState[namesOfSlice.modelListLoading];
|
|
304
|
+
const modelInsight = currentState[namesOfSlice.modelInsight];
|
|
305
|
+
const defaultModel = currentState[namesOfSlice.defaultModel];
|
|
306
|
+
const modelInput = gql[names.purifyModel](modelForm);
|
|
307
|
+
if (!modelInput)
|
|
308
|
+
return;
|
|
309
|
+
this.set({ [names.modelLoading]: true });
|
|
310
|
+
const model = await gql[names.createModel](modelInput, { onError });
|
|
311
|
+
const newModelList = modelListLoading ? modelList : new DataList([...modelList.slice(0, idx ?? 0), model, ...modelList.slice(idx ?? 0)]);
|
|
312
|
+
const newModelInsight = gql[names.crystalizeInsight]({
|
|
313
|
+
...modelInsight,
|
|
314
|
+
count: modelInsight.count + 1
|
|
315
|
+
});
|
|
316
|
+
this.set({
|
|
317
|
+
[names.modelForm]: immerify(modelRef, defaultModel),
|
|
318
|
+
[names.model]: model,
|
|
319
|
+
[names.modelLoading]: false,
|
|
320
|
+
[namesOfSlice.modelList]: newModelList,
|
|
321
|
+
[namesOfSlice.modelInsight]: newModelInsight,
|
|
322
|
+
[names.modelViewAt]: /* @__PURE__ */ new Date(),
|
|
323
|
+
[names.modelModal]: modal ?? null,
|
|
324
|
+
...typeof path === "string" && path ? { [path]: model } : {}
|
|
325
|
+
});
|
|
326
|
+
await onSuccess?.(model);
|
|
327
|
+
},
|
|
328
|
+
[names.updateModelInForm]: async function({ path, modal, sliceName = names.model, onError, onSuccess } = {}) {
|
|
329
|
+
const SliceName = capitalize(sliceName);
|
|
330
|
+
const namesOfSlice = {
|
|
331
|
+
defaultModel: SliceName.replace(names.Model, names.defaultModel)
|
|
332
|
+
};
|
|
333
|
+
const currentState = this.get();
|
|
334
|
+
const model = currentState[names.model];
|
|
335
|
+
const modelForm = currentState[names.modelForm];
|
|
336
|
+
const defaultModel = currentState[namesOfSlice.defaultModel];
|
|
337
|
+
const modelInput = gql[names.purifyModel](modelForm);
|
|
338
|
+
if (!modelInput)
|
|
339
|
+
return;
|
|
340
|
+
if (model?.id === modelForm.id)
|
|
341
|
+
this.set({ [names.modelLoading]: modelForm.id });
|
|
342
|
+
const updatedModel = await gql[names.updateModel](modelForm.id, modelInput, {
|
|
343
|
+
onError
|
|
344
|
+
});
|
|
345
|
+
this.set({
|
|
346
|
+
...model?.id === updatedModel.id ? { [names.model]: updatedModel, [names.modelLoading]: false, [names.modelViewAt]: /* @__PURE__ */ new Date() } : {},
|
|
347
|
+
[names.modelForm]: immerify(modelRef, defaultModel),
|
|
348
|
+
[names.modelModal]: modal ?? null,
|
|
349
|
+
...typeof path === "string" && path ? { [path]: updatedModel } : {}
|
|
350
|
+
});
|
|
351
|
+
const updatedLightModel = gql[names.lightCrystalizeModel](updatedModel);
|
|
352
|
+
gql.slices.forEach(({ sliceName: sliceName2 }) => {
|
|
353
|
+
const namesOfSlice2 = {
|
|
354
|
+
modelList: sliceName2.replace(names.model, names.modelList),
|
|
355
|
+
modelListLoading: sliceName2.replace(names.model, names.modelListLoading)
|
|
356
|
+
};
|
|
357
|
+
const currentState2 = this.get();
|
|
358
|
+
const modelList = currentState2[namesOfSlice2.modelList];
|
|
359
|
+
const modelListLoading = currentState2[namesOfSlice2.modelListLoading];
|
|
360
|
+
if (modelListLoading || !modelList.has(updatedModel.id))
|
|
361
|
+
return;
|
|
362
|
+
const newModelList = new DataList(modelList).set(updatedLightModel);
|
|
363
|
+
this.set({ [namesOfSlice2.modelList]: newModelList });
|
|
364
|
+
});
|
|
365
|
+
await onSuccess?.(updatedModel);
|
|
366
|
+
},
|
|
367
|
+
[names.createModel]: async function(data, { idx, path, modal, sliceName = names.model, onError, onSuccess } = {}) {
|
|
368
|
+
const SliceName = capitalize(sliceName);
|
|
369
|
+
const namesOfSlice = {
|
|
370
|
+
defaultModel: SliceName.replace(names.Model, names.defaultModel),
|
|
371
|
+
modelList: sliceName.replace(names.model, names.modelList),
|
|
372
|
+
modelListLoading: sliceName.replace(names.model, names.modelListLoading),
|
|
373
|
+
modelInsight: sliceName.replace(names.model, names.modelInsight)
|
|
374
|
+
};
|
|
375
|
+
const currentState = this.get();
|
|
376
|
+
const modelList = currentState[namesOfSlice.modelList];
|
|
377
|
+
const modelListLoading = currentState[namesOfSlice.modelListLoading];
|
|
378
|
+
const modelInsight = currentState[namesOfSlice.modelInsight];
|
|
379
|
+
const modelInput = gql[names.purifyModel](data);
|
|
380
|
+
if (!modelInput)
|
|
381
|
+
return;
|
|
382
|
+
this.set({ [names.modelLoading]: true });
|
|
383
|
+
const model = await gql[names.createModel](modelInput, { onError });
|
|
384
|
+
const newModelList = modelListLoading ? modelList : new DataList([...modelList.slice(0, idx ?? 0), model, ...modelList.slice(idx ?? 0)]);
|
|
385
|
+
const newModelInsight = gql[names.crystalizeInsight]({
|
|
386
|
+
...modelInsight,
|
|
387
|
+
count: modelInsight.count + 1
|
|
388
|
+
});
|
|
389
|
+
this.set({
|
|
390
|
+
[names.model]: model,
|
|
391
|
+
[names.modelLoading]: false,
|
|
392
|
+
[namesOfSlice.modelList]: newModelList,
|
|
393
|
+
[namesOfSlice.modelInsight]: newModelInsight,
|
|
394
|
+
[names.modelViewAt]: /* @__PURE__ */ new Date(),
|
|
395
|
+
[names.modelModal]: modal ?? null,
|
|
396
|
+
...typeof path === "string" && path ? { [path]: model } : {}
|
|
397
|
+
});
|
|
398
|
+
await onSuccess?.(model);
|
|
399
|
+
},
|
|
400
|
+
[names.updateModel]: async function(id, data, { idx, path, modal, sliceName = names.model, onError, onSuccess } = {}) {
|
|
401
|
+
const currentState = this.get();
|
|
402
|
+
const model = currentState[names.model];
|
|
403
|
+
const modelInput = gql[names.purifyModel](data);
|
|
404
|
+
if (!modelInput)
|
|
405
|
+
return;
|
|
406
|
+
if (model?.id === id)
|
|
407
|
+
this.set({ [names.modelLoading]: id });
|
|
408
|
+
const updatedModel = await gql[names.updateModel](id, modelInput, { onError });
|
|
409
|
+
this.set({
|
|
410
|
+
...model?.id === updatedModel.id ? { [names.model]: updatedModel, [names.modelLoading]: false, [names.modelViewAt]: /* @__PURE__ */ new Date() } : {},
|
|
411
|
+
[names.modelModal]: modal ?? null,
|
|
412
|
+
...typeof path === "string" && path ? { [path]: updatedModel } : {}
|
|
413
|
+
});
|
|
414
|
+
const updatedLightModel = gql[names.lightCrystalizeModel](updatedModel);
|
|
415
|
+
gql.slices.forEach(({ sliceName: sliceName2 }) => {
|
|
416
|
+
const namesOfSlice = {
|
|
417
|
+
modelList: sliceName2.replace(names.model, names.modelList),
|
|
418
|
+
modelListLoading: sliceName2.replace(names.model, names.modelListLoading)
|
|
419
|
+
};
|
|
420
|
+
const currentState2 = this.get();
|
|
421
|
+
const modelList = currentState2[namesOfSlice.modelList];
|
|
422
|
+
const modelListLoading = currentState2[namesOfSlice.modelListLoading];
|
|
423
|
+
if (modelListLoading || !modelList.has(updatedModel.id))
|
|
424
|
+
return;
|
|
425
|
+
const newModelList = new DataList(modelList).set(updatedLightModel);
|
|
426
|
+
this.set({ [namesOfSlice.modelList]: newModelList });
|
|
427
|
+
});
|
|
428
|
+
await onSuccess?.(updatedModel);
|
|
429
|
+
},
|
|
430
|
+
[names.removeModel]: async function(id, options) {
|
|
431
|
+
const { modal, ...fetchPolicyOptions } = options ?? {};
|
|
432
|
+
const model = await gql[names.removeModel](
|
|
433
|
+
id,
|
|
434
|
+
fetchPolicyOptions
|
|
435
|
+
);
|
|
436
|
+
const lightModel = gql[names.lightCrystalizeModel](model);
|
|
437
|
+
gql.slices.forEach(({ sliceName }) => {
|
|
438
|
+
const namesOfSlice = {
|
|
439
|
+
modelList: sliceName.replace(names.model, names.modelList),
|
|
440
|
+
modelListLoading: sliceName.replace(names.model, names.modelListLoading),
|
|
441
|
+
modelSelection: sliceName.replace(names.model, names.modelSelection),
|
|
442
|
+
modelInsight: sliceName.replace(names.model, names.modelInsight)
|
|
443
|
+
};
|
|
444
|
+
const currentState = this.get();
|
|
445
|
+
const modelList = currentState[namesOfSlice.modelList];
|
|
446
|
+
const modelListLoading = currentState[namesOfSlice.modelListLoading];
|
|
447
|
+
const modelSelection = currentState[namesOfSlice.modelSelection];
|
|
448
|
+
const modelInsight = currentState[namesOfSlice.modelInsight];
|
|
449
|
+
if (modelListLoading || !modelList.has(model.id))
|
|
450
|
+
return;
|
|
451
|
+
const newModelList = new DataList(modelList);
|
|
452
|
+
if (model.removedAt) {
|
|
453
|
+
newModelList.delete(id);
|
|
454
|
+
const newModelInsight = gql[names.crystalizeInsight]({
|
|
455
|
+
...modelInsight,
|
|
456
|
+
count: modelInsight.count - 1
|
|
457
|
+
});
|
|
458
|
+
const newModelSelection = new DataList(modelSelection);
|
|
459
|
+
newModelSelection.delete(id);
|
|
460
|
+
this.set({
|
|
461
|
+
[namesOfSlice.modelList]: newModelList,
|
|
462
|
+
[namesOfSlice.modelInsight]: newModelInsight,
|
|
463
|
+
...modelSelection.has(model.id) ? { [namesOfSlice.modelSelection]: newModelSelection } : {},
|
|
464
|
+
...modal !== void 0 ? { [names.modelModal]: modal } : {}
|
|
465
|
+
});
|
|
466
|
+
} else {
|
|
467
|
+
newModelList.set(lightModel);
|
|
468
|
+
this.set({
|
|
469
|
+
[namesOfSlice.modelList]: newModelList,
|
|
470
|
+
...modal !== void 0 ? { [names.modelModal]: modal } : {}
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
},
|
|
475
|
+
[names.checkModelSubmitable]: function(disabled) {
|
|
476
|
+
const currentState = this.get();
|
|
477
|
+
const modelForm = currentState[names.modelForm];
|
|
478
|
+
const modelSubmit = currentState[names.modelSubmit];
|
|
479
|
+
const modelInput = gql[names.purifyModel](modelForm);
|
|
480
|
+
this.set({ [names.modelSubmit]: { ...modelSubmit, disabled: !modelInput || disabled } });
|
|
481
|
+
},
|
|
482
|
+
[names.submitModel]: async function(option) {
|
|
483
|
+
const currentState = this.get();
|
|
484
|
+
const modelForm = currentState[names.modelForm];
|
|
485
|
+
const modelSubmit = currentState[names.modelSubmit];
|
|
486
|
+
this.set({ [names.modelSubmit]: { ...modelSubmit, loading: true } });
|
|
487
|
+
if (modelForm.id)
|
|
488
|
+
await this[names.updateModelInForm](option);
|
|
489
|
+
else
|
|
490
|
+
await this[names.createModelInForm](option);
|
|
491
|
+
this.set({ [names.modelSubmit]: { ...modelSubmit, loading: false, times: modelSubmit.times + 1 } });
|
|
492
|
+
},
|
|
493
|
+
[names.newModel]: function(partial = {}, { modal, setDefault, sliceName = names.model } = {}) {
|
|
494
|
+
const SliceName = capitalize(sliceName);
|
|
495
|
+
const namesOfSlice = {
|
|
496
|
+
defaultModel: SliceName.replace(names.Model, names.defaultModel)
|
|
497
|
+
};
|
|
498
|
+
const currentState = this.get();
|
|
499
|
+
const defaultModel = currentState[namesOfSlice.defaultModel];
|
|
500
|
+
this.set({
|
|
501
|
+
[names.modelForm]: immerify(modelRef, { ...defaultModel, ...partial }),
|
|
502
|
+
[namesOfSlice.defaultModel]: setDefault ? immerify(modelRef, { ...defaultModel, ...partial }) : defaultModel,
|
|
503
|
+
[names.model]: null,
|
|
504
|
+
[names.modelModal]: modal ?? "edit",
|
|
505
|
+
[names.modelFormLoading]: false
|
|
506
|
+
});
|
|
507
|
+
},
|
|
508
|
+
[names.editModel]: async function(modelOrId, { modal, onError } = {}) {
|
|
509
|
+
const id = typeof modelOrId === "string" ? modelOrId : modelOrId.id;
|
|
510
|
+
this.set({ [names.modelFormLoading]: id, [names.modelModal]: modal ?? "edit" });
|
|
511
|
+
this.set((state) => {
|
|
512
|
+
state[names.modelForm].id = id;
|
|
513
|
+
});
|
|
514
|
+
const model = await gql[names.model](id, { onError });
|
|
515
|
+
const modelForm = deepObjectify(model);
|
|
516
|
+
this.set({
|
|
517
|
+
[names.model]: model,
|
|
518
|
+
[names.modelFormLoading]: false,
|
|
519
|
+
[names.modelViewAt]: /* @__PURE__ */ new Date(),
|
|
520
|
+
[names.modelForm]: modelForm
|
|
521
|
+
});
|
|
522
|
+
},
|
|
523
|
+
[names.mergeModel]: async function(modelOrId, data, options) {
|
|
524
|
+
const id = typeof modelOrId === "string" ? modelOrId : modelOrId.id;
|
|
525
|
+
const currentState = this.get();
|
|
526
|
+
const model = currentState[names.model];
|
|
527
|
+
if (id === model?.id)
|
|
528
|
+
this.set({ modelLoading: id });
|
|
529
|
+
const updatedModel = await gql[names.mergeModel](modelOrId, data, options);
|
|
530
|
+
this.set({
|
|
531
|
+
[names.model]: id === model?.id ? updatedModel : model,
|
|
532
|
+
[names.modelLoading]: false
|
|
533
|
+
});
|
|
534
|
+
const updatedLightModel = gql[names.lightCrystalizeModel](updatedModel);
|
|
535
|
+
gql.slices.forEach(({ sliceName }) => {
|
|
536
|
+
const namesOfSlice = {
|
|
537
|
+
modelList: sliceName.replace(names.model, names.modelList),
|
|
538
|
+
modelListLoading: sliceName.replace(names.model, names.modelListLoading)
|
|
539
|
+
};
|
|
540
|
+
const currentState2 = this.get();
|
|
541
|
+
const modelList = currentState2[namesOfSlice.modelList];
|
|
542
|
+
const modelListLoading = currentState2[namesOfSlice.modelListLoading];
|
|
543
|
+
if (modelListLoading || !modelList.has(updatedModel.id))
|
|
544
|
+
return;
|
|
545
|
+
const newModelList = new DataList(modelList).set(updatedLightModel);
|
|
546
|
+
this.set({ [namesOfSlice.modelList]: newModelList });
|
|
547
|
+
});
|
|
548
|
+
},
|
|
549
|
+
[names.viewModel]: async function(modelOrId, { modal, onError } = {}) {
|
|
550
|
+
const id = typeof modelOrId === "string" ? modelOrId : modelOrId.id;
|
|
551
|
+
this.set({ [names.modelModal]: modal ?? "view", [names.modelLoading]: id });
|
|
552
|
+
const model = await gql[names.model](id, { onError });
|
|
553
|
+
this.set({ [names.model]: model, [names.modelViewAt]: /* @__PURE__ */ new Date(), [names.modelLoading]: false });
|
|
554
|
+
},
|
|
555
|
+
[names.setModel]: function(fullOrLightModel) {
|
|
556
|
+
const currentState = this.get();
|
|
557
|
+
const model = currentState[names.model];
|
|
558
|
+
const isFull = fullOrLightModel instanceof modelRef;
|
|
559
|
+
if (isFull) {
|
|
560
|
+
const crystalizedModel = gql[names.crystalizeModel](fullOrLightModel);
|
|
561
|
+
this.set({ [names.model]: crystalizedModel });
|
|
562
|
+
} else if (model?.id === fullOrLightModel.id) {
|
|
563
|
+
const crystalizedModel = gql[names.crystalizeModel]({ ...model, ...fullOrLightModel });
|
|
564
|
+
this.set({ [names.model]: crystalizedModel });
|
|
565
|
+
}
|
|
566
|
+
const lightModel = gql[names.lightCrystalizeModel](fullOrLightModel);
|
|
567
|
+
gql.slices.forEach(({ sliceName }) => {
|
|
568
|
+
const namesOfSlice = {
|
|
569
|
+
modelList: sliceName.replace(names.model, names.modelList),
|
|
570
|
+
modelListLoading: sliceName.replace(names.model, names.modelListLoading)
|
|
571
|
+
};
|
|
572
|
+
const modelList = currentState[namesOfSlice.modelList];
|
|
573
|
+
const modelListLoading = currentState[namesOfSlice.modelListLoading];
|
|
574
|
+
if (modelListLoading || !modelList.has(lightModel.id))
|
|
575
|
+
return;
|
|
576
|
+
this.set({ [namesOfSlice.modelList]: modelList.set(lightModel).save() });
|
|
577
|
+
});
|
|
578
|
+
},
|
|
579
|
+
[names.resetModel]: function(model) {
|
|
580
|
+
const currentState = this.get();
|
|
581
|
+
const defaultModel = currentState[names.defaultModel];
|
|
582
|
+
this.set({
|
|
583
|
+
[names.model]: model ?? null,
|
|
584
|
+
[names.modelViewAt]: /* @__PURE__ */ new Date(0),
|
|
585
|
+
[names.modelForm]: immerify(modelRef, defaultModel),
|
|
586
|
+
[names.modelModal]: null
|
|
587
|
+
});
|
|
588
|
+
return model ?? null;
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
const sliceAction = gql.slices.reduce((acc, { sliceName, argLength }) => {
|
|
592
|
+
const SliceName = capitalize(sliceName);
|
|
593
|
+
const namesOfSlice = {
|
|
594
|
+
defaultModel: SliceName.replace(names.Model, names.defaultModel),
|
|
595
|
+
modelInsight: sliceName.replace(names.model, names.modelInsight),
|
|
596
|
+
modelList: sliceName.replace(names.model, names.modelList),
|
|
597
|
+
modelListLoading: sliceName.replace(names.model, names.modelListLoading),
|
|
598
|
+
initModel: SliceName.replace(names.Model, names.initModel),
|
|
599
|
+
modelInitList: SliceName.replace(names.Model, names.modelInitList),
|
|
600
|
+
modelInitAt: SliceName.replace(names.Model, names.modelInitAt),
|
|
601
|
+
refreshModel: SliceName.replace(names.Model, names.refreshModel),
|
|
602
|
+
selectModel: SliceName.replace(names.Model, names.selectModel),
|
|
603
|
+
setPageOfModel: SliceName.replace(names.Model, names.setPageOfModel),
|
|
604
|
+
addPageOfModel: SliceName.replace(names.Model, names.addPageOfModel),
|
|
605
|
+
setLimitOfModel: SliceName.replace(names.Model, names.setLimitOfModel),
|
|
606
|
+
setQueryArgsOfModel: SliceName.replace(names.Model, names.setQueryArgsOfModel),
|
|
607
|
+
setSortOfModel: SliceName.replace(names.Model, names.setSortOfModel),
|
|
608
|
+
lastPageOfModel: SliceName.replace(names.Model, names.lastPageOfModel),
|
|
609
|
+
pageOfModel: SliceName.replace(names.Model, names.pageOfModel),
|
|
610
|
+
limitOfModel: SliceName.replace(names.Model, names.limitOfModel),
|
|
611
|
+
queryArgsOfModel: SliceName.replace(names.Model, names.queryArgsOfModel),
|
|
612
|
+
sortOfModel: SliceName.replace(names.Model, names.sortOfModel),
|
|
613
|
+
modelSelection: SliceName.replace(names.Model, names.modelSelection)
|
|
614
|
+
};
|
|
615
|
+
const singleSliceAction = {
|
|
616
|
+
[namesOfSlice.initModel]: async function(...args) {
|
|
617
|
+
const initArgLength = Math.min(args.length, argLength);
|
|
618
|
+
const initForm = { invalidate: false, ...args[argLength] ?? {} };
|
|
619
|
+
const queryArgs = new Array(initArgLength).fill(null).map((_, i) => args[i]);
|
|
620
|
+
const defaultModel = immerify(modelRef, { ...gql[names.defaultModel], ...initForm.default ?? {} });
|
|
621
|
+
this.set({ [names.defaultModel]: defaultModel });
|
|
622
|
+
await this[namesOfSlice.refreshModel](
|
|
623
|
+
...initArgLength === argLength ? [...queryArgs, initForm] : queryArgs
|
|
624
|
+
);
|
|
625
|
+
},
|
|
626
|
+
[namesOfSlice.refreshModel]: async function(...args) {
|
|
627
|
+
const refreshArgLength = Math.min(args.length, argLength);
|
|
628
|
+
const currentState = this.get();
|
|
629
|
+
const existingQueryArgs = currentState[namesOfSlice.queryArgsOfModel];
|
|
630
|
+
const queryArgs = [
|
|
631
|
+
...new Array(refreshArgLength).fill(null).map((_, i) => args[i]),
|
|
632
|
+
...existingQueryArgs.slice(refreshArgLength, argLength)
|
|
633
|
+
];
|
|
634
|
+
const initForm = args[argLength] ?? {};
|
|
635
|
+
const {
|
|
636
|
+
page = currentState[namesOfSlice.pageOfModel],
|
|
637
|
+
limit = currentState[namesOfSlice.limitOfModel],
|
|
638
|
+
sort = currentState[namesOfSlice.sortOfModel],
|
|
639
|
+
invalidate = true
|
|
640
|
+
} = initForm;
|
|
641
|
+
const modelOperation = currentState[names.modelOperation];
|
|
642
|
+
const queryArgsOfModel = currentState[namesOfSlice.queryArgsOfModel];
|
|
643
|
+
const pageOfModel = currentState[namesOfSlice.pageOfModel];
|
|
644
|
+
const limitOfModel = currentState[namesOfSlice.limitOfModel];
|
|
645
|
+
const sortOfModel = currentState[namesOfSlice.sortOfModel];
|
|
646
|
+
if (!invalidate && !["sleep", "reset"].includes(modelOperation) && isQueryEqual(queryArgs, queryArgsOfModel) && page === pageOfModel && limit === limitOfModel && isQueryEqual(sort, sortOfModel))
|
|
647
|
+
return;
|
|
648
|
+
else
|
|
649
|
+
this.set({ [namesOfSlice.modelListLoading]: true });
|
|
650
|
+
const [modelDataList, modelInsight] = await Promise.all([
|
|
651
|
+
gql[namesOfSlice.modelList](
|
|
652
|
+
...queryArgs,
|
|
653
|
+
(page - 1) * limit,
|
|
654
|
+
limit,
|
|
655
|
+
sort,
|
|
656
|
+
{ onError: initForm.onError }
|
|
657
|
+
),
|
|
658
|
+
gql[namesOfSlice.modelInsight](...queryArgs, {
|
|
659
|
+
onError: initForm.onError
|
|
660
|
+
})
|
|
661
|
+
]);
|
|
662
|
+
const modelList = new DataList(modelDataList);
|
|
663
|
+
this.set({
|
|
664
|
+
[namesOfSlice.modelList]: modelList,
|
|
665
|
+
[namesOfSlice.modelListLoading]: false,
|
|
666
|
+
[namesOfSlice.modelInsight]: modelInsight,
|
|
667
|
+
[namesOfSlice.modelInitList]: modelList,
|
|
668
|
+
[namesOfSlice.modelInitAt]: /* @__PURE__ */ new Date(),
|
|
669
|
+
[namesOfSlice.lastPageOfModel]: Math.max(Math.floor((modelInsight.count - 1) / limit) + 1, 1),
|
|
670
|
+
[namesOfSlice.limitOfModel]: limit,
|
|
671
|
+
[namesOfSlice.queryArgsOfModel]: queryArgs,
|
|
672
|
+
[namesOfSlice.sortOfModel]: sort,
|
|
673
|
+
[namesOfSlice.pageOfModel]: page,
|
|
674
|
+
[names.modelOperation]: "idle"
|
|
675
|
+
});
|
|
676
|
+
},
|
|
677
|
+
[namesOfSlice.selectModel]: function(model, { refresh, remove } = {}) {
|
|
678
|
+
const models = Array.isArray(model) ? model : [model];
|
|
679
|
+
const currentState = this.get();
|
|
680
|
+
const modelSelection = currentState[namesOfSlice.modelSelection];
|
|
681
|
+
if (refresh)
|
|
682
|
+
this.set({ [namesOfSlice.modelSelection]: new DataList(models) });
|
|
683
|
+
else if (remove) {
|
|
684
|
+
const newModelSelection = new DataList(modelSelection);
|
|
685
|
+
models.map((model2) => newModelSelection.delete(model2.id));
|
|
686
|
+
this.set({ [namesOfSlice.modelSelection]: newModelSelection });
|
|
687
|
+
} else {
|
|
688
|
+
this.set({ [namesOfSlice.modelSelection]: new DataList([...modelSelection.values, ...models]) });
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
[namesOfSlice.setPageOfModel]: async function(page, options) {
|
|
692
|
+
const currentState = this.get();
|
|
693
|
+
const queryArgsOfModel = currentState[namesOfSlice.queryArgsOfModel];
|
|
694
|
+
const pageOfModel = currentState[namesOfSlice.pageOfModel];
|
|
695
|
+
const limitOfModel = currentState[namesOfSlice.limitOfModel];
|
|
696
|
+
const sortOfModel = currentState[namesOfSlice.sortOfModel];
|
|
697
|
+
if (pageOfModel === page)
|
|
698
|
+
return;
|
|
699
|
+
this.set({ [namesOfSlice.modelListLoading]: true });
|
|
700
|
+
const modelDataList = await gql[namesOfSlice.modelList](
|
|
701
|
+
...queryArgsOfModel,
|
|
702
|
+
(page - 1) * limitOfModel,
|
|
703
|
+
limitOfModel,
|
|
704
|
+
sortOfModel,
|
|
705
|
+
options
|
|
706
|
+
);
|
|
707
|
+
const modelList = new DataList(modelDataList);
|
|
708
|
+
this.set({
|
|
709
|
+
[namesOfSlice.modelList]: modelList,
|
|
710
|
+
[namesOfSlice.pageOfModel]: page,
|
|
711
|
+
[namesOfSlice.modelListLoading]: false
|
|
712
|
+
});
|
|
713
|
+
},
|
|
714
|
+
[namesOfSlice.addPageOfModel]: async function(page, options) {
|
|
715
|
+
const currentState = this.get();
|
|
716
|
+
const modelList = currentState[namesOfSlice.modelList];
|
|
717
|
+
const queryArgsOfModel = currentState[namesOfSlice.queryArgsOfModel];
|
|
718
|
+
const pageOfModel = currentState[namesOfSlice.pageOfModel];
|
|
719
|
+
const limitOfModel = currentState[namesOfSlice.limitOfModel];
|
|
720
|
+
const sortOfModel = currentState[namesOfSlice.sortOfModel];
|
|
721
|
+
if (pageOfModel === page)
|
|
722
|
+
return;
|
|
723
|
+
const addFront = page < pageOfModel;
|
|
724
|
+
const modelDataList = await gql[namesOfSlice.modelList](
|
|
725
|
+
...queryArgsOfModel,
|
|
726
|
+
(page - 1) * limitOfModel,
|
|
727
|
+
limitOfModel,
|
|
728
|
+
sortOfModel,
|
|
729
|
+
options
|
|
730
|
+
);
|
|
731
|
+
const newModelList = new DataList(
|
|
732
|
+
addFront ? [...modelDataList, ...modelList] : [...modelList, ...modelDataList]
|
|
733
|
+
);
|
|
734
|
+
this.set({ [namesOfSlice.modelList]: newModelList, [namesOfSlice.pageOfModel]: page });
|
|
735
|
+
},
|
|
736
|
+
[namesOfSlice.setLimitOfModel]: async function(limit, options) {
|
|
737
|
+
const currentState = this.get();
|
|
738
|
+
const modelInsight = currentState[namesOfSlice.modelInsight];
|
|
739
|
+
const queryArgsOfModel = currentState[namesOfSlice.queryArgsOfModel];
|
|
740
|
+
const pageOfModel = currentState[namesOfSlice.pageOfModel];
|
|
741
|
+
const limitOfModel = currentState[namesOfSlice.limitOfModel];
|
|
742
|
+
const sortOfModel = currentState[namesOfSlice.sortOfModel];
|
|
743
|
+
if (limitOfModel === limit)
|
|
744
|
+
return;
|
|
745
|
+
const skip = (pageOfModel - 1) * limitOfModel;
|
|
746
|
+
const page = Math.max(Math.floor((skip - 1) / limit) + 1, 1);
|
|
747
|
+
const modelDataList = await gql[namesOfSlice.modelList](
|
|
748
|
+
...queryArgsOfModel,
|
|
749
|
+
(page - 1) * limit,
|
|
750
|
+
limit,
|
|
751
|
+
sortOfModel,
|
|
752
|
+
options
|
|
753
|
+
);
|
|
754
|
+
const modelList = new DataList(modelDataList);
|
|
755
|
+
this.set({
|
|
756
|
+
[namesOfSlice.modelList]: modelList,
|
|
757
|
+
[namesOfSlice.lastPageOfModel]: Math.max(Math.floor((modelInsight.count - 1) / limit) + 1, 1),
|
|
758
|
+
[namesOfSlice.limitOfModel]: limit,
|
|
759
|
+
[namesOfSlice.pageOfModel]: page
|
|
760
|
+
});
|
|
761
|
+
},
|
|
762
|
+
[namesOfSlice.setQueryArgsOfModel]: async function(...args) {
|
|
763
|
+
const queryArgs = new Array(argLength).fill(null).map((_, i) => args[i]);
|
|
764
|
+
const options = args[argLength];
|
|
765
|
+
const currentState = this.get();
|
|
766
|
+
const queryArgsOfModel = currentState[namesOfSlice.queryArgsOfModel];
|
|
767
|
+
const limitOfModel = currentState[namesOfSlice.limitOfModel];
|
|
768
|
+
const sortOfModel = currentState[namesOfSlice.sortOfModel];
|
|
769
|
+
if (isQueryEqual(queryArgsOfModel, queryArgs)) {
|
|
770
|
+
Logger.trace(`${namesOfSlice.queryArgsOfModel} store-level cache hit`);
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
this.set({ [namesOfSlice.modelListLoading]: true });
|
|
774
|
+
const [modelDataList, modelInsight] = await Promise.all([
|
|
775
|
+
gql[namesOfSlice.modelList](
|
|
776
|
+
...queryArgs,
|
|
777
|
+
0,
|
|
778
|
+
limitOfModel,
|
|
779
|
+
sortOfModel,
|
|
780
|
+
options
|
|
781
|
+
),
|
|
782
|
+
gql[namesOfSlice.modelInsight](...queryArgs, options)
|
|
783
|
+
]);
|
|
784
|
+
const modelList = new DataList(modelDataList);
|
|
785
|
+
this.set({
|
|
786
|
+
[namesOfSlice.queryArgsOfModel]: queryArgs,
|
|
787
|
+
[namesOfSlice.modelList]: modelList,
|
|
788
|
+
[namesOfSlice.modelInsight]: modelInsight,
|
|
789
|
+
[namesOfSlice.lastPageOfModel]: Math.max(Math.floor((modelInsight.count - 1) / limitOfModel) + 1, 1),
|
|
790
|
+
[namesOfSlice.pageOfModel]: 1,
|
|
791
|
+
[namesOfSlice.modelSelection]: /* @__PURE__ */ new Map(),
|
|
792
|
+
[namesOfSlice.modelListLoading]: false
|
|
793
|
+
});
|
|
794
|
+
},
|
|
795
|
+
[namesOfSlice.setSortOfModel]: async function(sort, options) {
|
|
796
|
+
const currentState = this.get();
|
|
797
|
+
const queryArgsOfModel = currentState[namesOfSlice.queryArgsOfModel];
|
|
798
|
+
const limitOfModel = currentState[namesOfSlice.limitOfModel];
|
|
799
|
+
const sortOfModel = currentState[namesOfSlice.sortOfModel];
|
|
800
|
+
if (sortOfModel === sort)
|
|
801
|
+
return;
|
|
802
|
+
this.set({ [namesOfSlice.modelListLoading]: true });
|
|
803
|
+
const modelDataList = await gql[namesOfSlice.modelList](
|
|
804
|
+
...queryArgsOfModel,
|
|
805
|
+
0,
|
|
806
|
+
limitOfModel,
|
|
807
|
+
sort,
|
|
808
|
+
options
|
|
809
|
+
);
|
|
810
|
+
const modelList = new DataList(modelDataList);
|
|
811
|
+
this.set({
|
|
812
|
+
[namesOfSlice.modelList]: modelList,
|
|
813
|
+
[namesOfSlice.sortOfModel]: sort,
|
|
814
|
+
[namesOfSlice.pageOfModel]: 1,
|
|
815
|
+
[namesOfSlice.modelListLoading]: false
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
return Object.assign(acc, singleSliceAction);
|
|
820
|
+
}, {});
|
|
821
|
+
return { ...baseAction, ...sliceAction };
|
|
822
|
+
};
|
|
823
|
+
const stateOf = (gql, state) => {
|
|
824
|
+
const applyState = Object.assign(createState(gql), state);
|
|
825
|
+
const applyAction = createActions(gql);
|
|
826
|
+
setStoreMeta(gql.refName, {
|
|
827
|
+
refName: gql.refName,
|
|
828
|
+
useKeys: Object.keys(applyState),
|
|
829
|
+
doKeys: Object.keys(applyAction),
|
|
830
|
+
slices: gql.slices
|
|
831
|
+
});
|
|
832
|
+
const applyStore = { ...applyState, ...applyAction };
|
|
833
|
+
class StateStore {
|
|
834
|
+
get;
|
|
835
|
+
set;
|
|
836
|
+
pick;
|
|
837
|
+
}
|
|
838
|
+
Object.keys(applyStore).forEach(
|
|
839
|
+
(key) => Object.defineProperty(StateStore.prototype, key, { value: applyStore[key] })
|
|
840
|
+
);
|
|
841
|
+
return StateStore;
|
|
842
|
+
};
|
|
843
|
+
const scalarStateOf = (refName, state) => {
|
|
844
|
+
const applyState = state;
|
|
845
|
+
setStoreMeta(refName, { refName, useKeys: Object.keys(applyState), doKeys: [], slices: [] });
|
|
846
|
+
class StateStore {
|
|
847
|
+
get;
|
|
848
|
+
set;
|
|
849
|
+
pick;
|
|
850
|
+
}
|
|
851
|
+
Object.keys(applyState).forEach(
|
|
852
|
+
(key) => Object.defineProperty(StateStore.prototype, key, { value: applyState[key] })
|
|
853
|
+
);
|
|
854
|
+
return StateStore;
|
|
855
|
+
};
|
|
856
|
+
const Store = (returnsOrObj) => {
|
|
857
|
+
const refName = typeof returnsOrObj === "object" ? returnsOrObj.name : lowerlize(getClassMeta(returnsOrObj()).refName);
|
|
858
|
+
const storeMeta = getStoreMeta(refName);
|
|
859
|
+
return function(target) {
|
|
860
|
+
const customDoKeys = Object.getOwnPropertyNames(target.prototype).filter((key) => key !== "constructor");
|
|
861
|
+
setStoreMeta(refName, { ...storeMeta, doKeys: [...storeMeta.doKeys, ...customDoKeys] });
|
|
862
|
+
};
|
|
863
|
+
};
|
|
864
|
+
const createSelectors = (_store, store = {}) => {
|
|
865
|
+
store.get = _store.getState;
|
|
866
|
+
store.set = (s) => {
|
|
867
|
+
if (typeof s === "function")
|
|
868
|
+
_store.setState((st2) => {
|
|
869
|
+
s(st2);
|
|
870
|
+
});
|
|
871
|
+
else
|
|
872
|
+
_store.setState(s);
|
|
873
|
+
};
|
|
874
|
+
store.sel = (selectFn, equals) => _store(selectFn, equals);
|
|
875
|
+
const state = store.get();
|
|
876
|
+
store.sub = _store.subscribe;
|
|
877
|
+
const useReference = (selectFn) => {
|
|
878
|
+
const ref = useRef(selectFn(store.get()));
|
|
879
|
+
useEffect(() => {
|
|
880
|
+
return store.sub(selectFn, (val) => ref.current = val);
|
|
881
|
+
}, []);
|
|
882
|
+
return ref;
|
|
883
|
+
};
|
|
884
|
+
store.ref = useReference;
|
|
885
|
+
const existingUse = store.use;
|
|
886
|
+
const existingDo = store.do;
|
|
887
|
+
const existingSlice = store.slice;
|
|
888
|
+
if (!existingUse)
|
|
889
|
+
Object.assign(store, { use: {} });
|
|
890
|
+
if (!existingDo)
|
|
891
|
+
Object.assign(store, { do: {} });
|
|
892
|
+
if (!existingSlice)
|
|
893
|
+
Object.assign(store, { slice: {} });
|
|
894
|
+
for (const k of Object.keys(state)) {
|
|
895
|
+
if (typeof state[k] !== "function") {
|
|
896
|
+
store.use[k] = () => store.sel((s) => s[k]);
|
|
897
|
+
const setKey = `set${capitalize(k)}`;
|
|
898
|
+
if (!state[setKey])
|
|
899
|
+
store.do[setKey] = (value) => {
|
|
900
|
+
store.set({ [k]: value });
|
|
901
|
+
};
|
|
902
|
+
} else {
|
|
903
|
+
store.do[k] = async (...args) => {
|
|
904
|
+
try {
|
|
905
|
+
Logger.verbose(`${k} action loading...`);
|
|
906
|
+
const start = Date.now();
|
|
907
|
+
await state[k](...args);
|
|
908
|
+
const end = Date.now();
|
|
909
|
+
Logger.verbose(`=> ${k} action dispatched (${end - start}ms)`);
|
|
910
|
+
} catch (e) {
|
|
911
|
+
const errKey = typeof e === "string" ? e : e.message;
|
|
912
|
+
msg.error(errKey, { key: k });
|
|
913
|
+
throw e;
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
const storeNames = getStoreNames();
|
|
919
|
+
for (const storeName of storeNames) {
|
|
920
|
+
const [fieldName, className] = [lowerlize(storeName), capitalize(storeName)];
|
|
921
|
+
const names = {
|
|
922
|
+
model: fieldName,
|
|
923
|
+
Model: className,
|
|
924
|
+
defaultModel: `default${className}`,
|
|
925
|
+
modelInsight: `${fieldName}Insight`,
|
|
926
|
+
modelList: `${fieldName}List`,
|
|
927
|
+
modelListLoading: `${fieldName}ListLoading`,
|
|
928
|
+
modelInitList: `${fieldName}InitList`,
|
|
929
|
+
modelInitAt: `${fieldName}InitAt`,
|
|
930
|
+
pageOfModel: `pageOf${className}`,
|
|
931
|
+
limitOfModel: `limitOf${className}`,
|
|
932
|
+
queryArgsOfModel: `queryArgsOf${className}`,
|
|
933
|
+
sortOfModel: `sortOf${className}`,
|
|
934
|
+
modelSelection: `${fieldName}Selection`,
|
|
935
|
+
initModel: `init${className}`,
|
|
936
|
+
refreshModel: `refresh${className}`,
|
|
937
|
+
selectModel: `select${className}`,
|
|
938
|
+
setPageOfModel: `setPageOf${className}`,
|
|
939
|
+
addPageOfModel: `addPageOf${className}`,
|
|
940
|
+
setLimitOfModel: `setLimitOf${className}`,
|
|
941
|
+
setQueryArgsOfModel: `setQueryArgsOf${className}`,
|
|
942
|
+
setSortOfModel: `setSortOf${className}`,
|
|
943
|
+
lastPageOfModel: `lastPageOf${className}`
|
|
944
|
+
};
|
|
945
|
+
const storeMeta = getStoreMeta(storeName);
|
|
946
|
+
storeMeta.slices.forEach(({ sliceName, argLength, refName }) => {
|
|
947
|
+
const SliceName = capitalize(sliceName);
|
|
948
|
+
const namesOfSliceState = {
|
|
949
|
+
defaultModel: SliceName.replace(names.Model, names.defaultModel),
|
|
950
|
+
modelInitList: SliceName.replace(names.Model, names.modelInitList),
|
|
951
|
+
modelInsight: sliceName.replace(names.model, names.modelInsight),
|
|
952
|
+
modelList: sliceName.replace(names.model, names.modelList),
|
|
953
|
+
modelListLoading: sliceName.replace(names.model, names.modelListLoading),
|
|
954
|
+
modelInitAt: SliceName.replace(names.Model, names.modelInitAt),
|
|
955
|
+
lastPageOfModel: SliceName.replace(names.Model, names.lastPageOfModel),
|
|
956
|
+
pageOfModel: SliceName.replace(names.Model, names.pageOfModel),
|
|
957
|
+
limitOfModel: SliceName.replace(names.Model, names.limitOfModel),
|
|
958
|
+
queryArgsOfModel: SliceName.replace(names.Model, names.queryArgsOfModel),
|
|
959
|
+
sortOfModel: SliceName.replace(names.Model, names.sortOfModel),
|
|
960
|
+
modelSelection: SliceName.replace(names.Model, names.modelSelection)
|
|
961
|
+
};
|
|
962
|
+
const namesOfSliceAction = {
|
|
963
|
+
initModel: SliceName.replace(names.Model, names.initModel),
|
|
964
|
+
refreshModel: SliceName.replace(names.Model, names.refreshModel),
|
|
965
|
+
selectModel: SliceName.replace(names.Model, names.selectModel),
|
|
966
|
+
setPageOfModel: SliceName.replace(names.Model, names.setPageOfModel),
|
|
967
|
+
addPageOfModel: SliceName.replace(names.Model, names.addPageOfModel),
|
|
968
|
+
setLimitOfModel: SliceName.replace(names.Model, names.setLimitOfModel),
|
|
969
|
+
setQueryArgsOfModel: SliceName.replace(names.Model, names.setQueryArgsOfModel),
|
|
970
|
+
setSortOfModel: SliceName.replace(names.Model, names.setSortOfModel)
|
|
971
|
+
};
|
|
972
|
+
store.slice[sliceName] = { do: {}, use: {} };
|
|
973
|
+
const targetSlice = store.slice[sliceName];
|
|
974
|
+
Object.keys(namesOfSliceAction).forEach((key) => {
|
|
975
|
+
targetSlice.do[names[key]] = store.do[namesOfSliceAction[key]];
|
|
976
|
+
});
|
|
977
|
+
Object.keys(namesOfSliceState).map((key) => {
|
|
978
|
+
targetSlice.use[names[key]] = store.use[namesOfSliceState[key]];
|
|
979
|
+
targetSlice.do[`set${capitalize(names[key])}`] = store.do[`set${capitalize(namesOfSliceState[key])}`];
|
|
980
|
+
});
|
|
981
|
+
targetSlice.sliceName = sliceName;
|
|
982
|
+
targetSlice.refName = refName;
|
|
983
|
+
targetSlice.argLength = argLength;
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
return store;
|
|
987
|
+
};
|
|
988
|
+
const makePicker = (set, get) => (...fields) => {
|
|
989
|
+
const state = get();
|
|
990
|
+
const ret = {};
|
|
991
|
+
for (const field of fields) {
|
|
992
|
+
const val = state[field];
|
|
993
|
+
if (!val)
|
|
994
|
+
throw new Error(`Field ${field} is not ready`);
|
|
995
|
+
if (typeof val === "string" && val.length === 0)
|
|
996
|
+
throw new Error(`Field is empty string (${field})`);
|
|
997
|
+
else if (["self", "me"].includes(field) && !state[field].id?.length)
|
|
998
|
+
throw new Error("Self or Me Id is not defined");
|
|
999
|
+
ret[field] = val;
|
|
1000
|
+
}
|
|
1001
|
+
return ret;
|
|
1002
|
+
};
|
|
1003
|
+
const makeStore = (st2, storeRef, { library } = {}) => {
|
|
1004
|
+
if (library)
|
|
1005
|
+
return st2;
|
|
1006
|
+
const zustandStore = create(
|
|
1007
|
+
devtools(
|
|
1008
|
+
subscribeWithSelector(
|
|
1009
|
+
immer((set, get) => {
|
|
1010
|
+
const store = {};
|
|
1011
|
+
const pick = makePicker(set, get);
|
|
1012
|
+
Object.getOwnPropertyNames(storeRef.prototype).forEach((key) => {
|
|
1013
|
+
const descriptor = Object.getOwnPropertyDescriptor(storeRef.prototype, key);
|
|
1014
|
+
if (descriptor)
|
|
1015
|
+
store[key] = descriptor.value;
|
|
1016
|
+
});
|
|
1017
|
+
Object.assign(store, { set, get, pick });
|
|
1018
|
+
return store;
|
|
1019
|
+
})
|
|
1020
|
+
),
|
|
1021
|
+
{ name: "root", anonymousActionType: "root", type: "root" }
|
|
1022
|
+
)
|
|
1023
|
+
);
|
|
1024
|
+
return createSelectors(zustandStore, st2);
|
|
1025
|
+
};
|
|
1026
|
+
const MixStore = (s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, s21, s22, s23, s24, s25, s26, s27, s28, s29, s30) => {
|
|
1027
|
+
const stores = [
|
|
1028
|
+
s1,
|
|
1029
|
+
s2,
|
|
1030
|
+
s3,
|
|
1031
|
+
s4,
|
|
1032
|
+
s5,
|
|
1033
|
+
s6,
|
|
1034
|
+
s7,
|
|
1035
|
+
s8,
|
|
1036
|
+
s9,
|
|
1037
|
+
s10,
|
|
1038
|
+
s11,
|
|
1039
|
+
s12,
|
|
1040
|
+
s13,
|
|
1041
|
+
s14,
|
|
1042
|
+
s15,
|
|
1043
|
+
s16,
|
|
1044
|
+
s17,
|
|
1045
|
+
s18,
|
|
1046
|
+
s19,
|
|
1047
|
+
s20,
|
|
1048
|
+
s21,
|
|
1049
|
+
s22,
|
|
1050
|
+
s23,
|
|
1051
|
+
s24,
|
|
1052
|
+
s25,
|
|
1053
|
+
s26,
|
|
1054
|
+
s27,
|
|
1055
|
+
s28,
|
|
1056
|
+
s29,
|
|
1057
|
+
s30
|
|
1058
|
+
].filter((s) => !!s);
|
|
1059
|
+
class Mix {
|
|
1060
|
+
}
|
|
1061
|
+
applyMixins(Mix, stores);
|
|
1062
|
+
return Mix;
|
|
1063
|
+
};
|
|
1064
|
+
const rootStoreOf = (store) => {
|
|
1065
|
+
return Object.getPrototypeOf(store);
|
|
1066
|
+
};
|
|
1067
|
+
const Toast = ({ root, duration = 3 } = {}) => {
|
|
1068
|
+
return function(target, key, descriptor) {
|
|
1069
|
+
const originMethod = descriptor.value;
|
|
1070
|
+
descriptor.value = async function(...args) {
|
|
1071
|
+
try {
|
|
1072
|
+
msg.loading(`${root ? `${root}.` : ""}${key}-loading`, { key, duration });
|
|
1073
|
+
const result = await originMethod.apply(this, args);
|
|
1074
|
+
msg.success(`${root ? `${root}.` : ""}${key}-success`, { key, duration });
|
|
1075
|
+
return result;
|
|
1076
|
+
} catch (err) {
|
|
1077
|
+
const errKey = typeof err === "string" ? err : err.message;
|
|
1078
|
+
msg.error(errKey, { key, duration });
|
|
1079
|
+
Logger.error(`${key} action error return: ${err}`);
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
};
|
|
1083
|
+
};
|
|
1084
|
+
export {
|
|
1085
|
+
MixStore,
|
|
1086
|
+
Store,
|
|
1087
|
+
Toast,
|
|
1088
|
+
createActions,
|
|
1089
|
+
createState,
|
|
1090
|
+
makeStore,
|
|
1091
|
+
rootStoreOf,
|
|
1092
|
+
scalarStateOf,
|
|
1093
|
+
st,
|
|
1094
|
+
stateOf
|
|
1095
|
+
};
|
package/src/types.mjs
ADDED
|
File without changes
|