@saltcorn/mobile-app 0.8.6-beta.1 → 0.8.6-beta.11
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/package.json +1 -1
- package/www/index.html +98 -21
- package/www/js/mocks/request.js +9 -4
- package/www/js/routes/api.js +39 -0
- package/www/js/routes/auth.js +11 -6
- package/www/js/routes/common.js +74 -40
- package/www/js/routes/delete.js +9 -9
- package/www/js/routes/edit.js +8 -4
- package/www/js/routes/error.js +2 -15
- package/www/js/routes/init.js +18 -1
- package/www/js/routes/sync.js +154 -0
- package/www/js/routes/view.js +10 -7
- package/www/js/utils/global_utils.js +104 -24
- package/www/js/utils/iframe_view_utils.js +311 -21
- package/www/js/utils/offline_mode_helper.js +131 -0
- package/www/js/utils/table_utils.js +25 -4
package/package.json
CHANGED
package/www/index.html
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
<script src="js/utils/iframe_view_utils.js"></script>
|
|
11
11
|
<script src="js/utils/file_helpers.js"></script>
|
|
12
12
|
<script src="js/utils/table_utils.js"></script>
|
|
13
|
+
<script src="js/utils/offline_mode_helper.js"></script>
|
|
13
14
|
|
|
14
15
|
<script src="js/mocks/request.js"></script>
|
|
15
16
|
<script src="js/mocks/response.js"></script>
|
|
@@ -17,9 +18,11 @@
|
|
|
17
18
|
<script src="js/routes/auth.js"></script>
|
|
18
19
|
<script src="js/routes/delete.js"></script>
|
|
19
20
|
<script src="js/routes/edit.js"></script>
|
|
21
|
+
<script src="js/routes/api.js"></script>
|
|
20
22
|
<script src="js/routes/error.js"></script>
|
|
21
23
|
<script src="js/routes/page.js"></script>
|
|
22
24
|
<script src="js/routes/view.js"></script>
|
|
25
|
+
<script src="js/routes/sync.js"></script>
|
|
23
26
|
<script src="js/routes/init.js"></script>
|
|
24
27
|
|
|
25
28
|
<script src="js/mocks/response.js"></script>
|
|
@@ -124,7 +127,7 @@
|
|
|
124
127
|
config.pluginHeaders.push(prepareHeader(header));
|
|
125
128
|
}
|
|
126
129
|
else if (typeof pluginHeaders === "function") {
|
|
127
|
-
const headerResult = pluginHeaders(row.configuration);
|
|
130
|
+
const headerResult = pluginHeaders(row.configuration || {});
|
|
128
131
|
if (Array.isArray(headerResult)) {
|
|
129
132
|
for (const header of headerResult)
|
|
130
133
|
config.pluginHeaders.push(prepareHeader(header));
|
|
@@ -146,29 +149,15 @@
|
|
|
146
149
|
const initJwt = async () => {
|
|
147
150
|
if (!(await saltcorn.data.db.tableExists("jwt_table"))) {
|
|
148
151
|
await createJwtTable();
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
152
|
+
} else {
|
|
151
153
|
const jwt = await getJwt();
|
|
152
|
-
if(jwt) {
|
|
154
|
+
if (jwt) {
|
|
153
155
|
const state = saltcorn.data.state.getState();
|
|
154
156
|
state.mobileConfig.jwt = jwt;
|
|
155
157
|
}
|
|
156
158
|
}
|
|
157
159
|
};
|
|
158
160
|
|
|
159
|
-
const checkJWT = async () => {
|
|
160
|
-
const state = saltcorn.data.state.getState();
|
|
161
|
-
const jwt = state.mobileConfig.jwt;
|
|
162
|
-
if(jwt && jwt !== "undefined") {
|
|
163
|
-
const response = await apiCall({
|
|
164
|
-
method: "GET",
|
|
165
|
-
path: "/auth/authenticated",
|
|
166
|
-
});
|
|
167
|
-
return response.data.authenticated;
|
|
168
|
-
}
|
|
169
|
-
else return false;
|
|
170
|
-
};
|
|
171
|
-
|
|
172
161
|
const initI18Next = async () => {
|
|
173
162
|
const resources = {};
|
|
174
163
|
for (const key of Object.keys(
|
|
@@ -188,8 +177,43 @@
|
|
|
188
177
|
});
|
|
189
178
|
};
|
|
190
179
|
|
|
180
|
+
// the app comes back from background
|
|
181
|
+
const onResume = async () => {
|
|
182
|
+
const state = saltcorn.data.state.getState();
|
|
183
|
+
const mobileConfig = state.mobileConfig;
|
|
184
|
+
if (mobileConfig?.allowOfflineMode) {
|
|
185
|
+
mobileConfig.networkState = navigator.connection.type;
|
|
186
|
+
if (
|
|
187
|
+
mobileConfig.networkState === "none" &&
|
|
188
|
+
!mobileConfig.isOfflineMode &&
|
|
189
|
+
mobileConfig.jwt
|
|
190
|
+
) {
|
|
191
|
+
await offlineHelper.startOfflineMode();
|
|
192
|
+
clearHistory();
|
|
193
|
+
if (mobileConfig.user_id) await gotoEntryView();
|
|
194
|
+
else {
|
|
195
|
+
const decodedJwt = jwt_decode(mobileConfig.jwt);
|
|
196
|
+
mobileConfig.role_id = decodedJwt.user.role_id
|
|
197
|
+
? decodedJwt.user.role_id
|
|
198
|
+
: 100;
|
|
199
|
+
mobileConfig.user_id = decodedJwt.user.id;
|
|
200
|
+
mobileConfig.user_name = decodedJwt.user.email;
|
|
201
|
+
mobileConfig.language = decodedJwt.user.language;
|
|
202
|
+
mobileConfig.isPublicUser = false;
|
|
203
|
+
}
|
|
204
|
+
addRoute({ route: entryPoint, query: undefined });
|
|
205
|
+
const page = await router.resolve({
|
|
206
|
+
pathname: mobileConfig.entry_point,
|
|
207
|
+
fullWrap: true,
|
|
208
|
+
alerts: [],
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
191
214
|
// device is ready
|
|
192
215
|
const init = async () => {
|
|
216
|
+
document.addEventListener("resume", onResume, false);
|
|
193
217
|
const config = await readJSON(
|
|
194
218
|
"config",
|
|
195
219
|
`${cordova.file.applicationDirectory}www`
|
|
@@ -227,32 +251,86 @@
|
|
|
227
251
|
setVersionTtag();
|
|
228
252
|
const entryPoint = config.entry_point;
|
|
229
253
|
await initI18Next();
|
|
254
|
+
state.mobileConfig.networkState = navigator.connection.type;
|
|
255
|
+
document.addEventListener(
|
|
256
|
+
"offline",
|
|
257
|
+
offlineHelper.offlineCallback,
|
|
258
|
+
false
|
|
259
|
+
);
|
|
260
|
+
document.addEventListener(
|
|
261
|
+
"online",
|
|
262
|
+
offlineHelper.onlineCallback,
|
|
263
|
+
false
|
|
264
|
+
);
|
|
265
|
+
const networkDisabled = state.mobileConfig.networkState === "none";
|
|
266
|
+
const jwt = state.mobileConfig.jwt;
|
|
230
267
|
try {
|
|
231
|
-
|
|
268
|
+
const alerts = [];
|
|
269
|
+
if ((networkDisabled && jwt) || (await checkJWT(jwt))) {
|
|
232
270
|
const mobileConfig = state.mobileConfig;
|
|
233
271
|
const decodedJwt = jwt_decode(mobileConfig.jwt);
|
|
234
272
|
mobileConfig.role_id = decodedJwt.user.role_id
|
|
235
273
|
? decodedJwt.user.role_id
|
|
236
|
-
:
|
|
274
|
+
: 100;
|
|
275
|
+
mobileConfig.user_id = decodedJwt.user.id;
|
|
237
276
|
mobileConfig.user_name = decodedJwt.user.email;
|
|
238
277
|
mobileConfig.language = decodedJwt.user.language;
|
|
239
278
|
mobileConfig.isPublicUser = false;
|
|
240
279
|
await i18next.changeLanguage(mobileConfig.language);
|
|
280
|
+
if (mobileConfig.allowOfflineMode) {
|
|
281
|
+
const { offlineUser, upload_started_at, upload_ended_at } =
|
|
282
|
+
(await offlineHelper.getLastOfflineSession()) || {};
|
|
283
|
+
if (networkDisabled) {
|
|
284
|
+
if (offlineUser && offlineUser !== mobileConfig.user_name)
|
|
285
|
+
throw new Error(
|
|
286
|
+
`The offline mode is not available, '${offlineUser}' has not yet uploaded offline data.`
|
|
287
|
+
);
|
|
288
|
+
else {
|
|
289
|
+
await offlineHelper.startOfflineMode();
|
|
290
|
+
alerts.push({
|
|
291
|
+
type: "info",
|
|
292
|
+
msg: offlineHelper.getOfflineMsg(),
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
} else if (offlineUser) {
|
|
296
|
+
if (offlineUser === mobileConfig.user_name) {
|
|
297
|
+
if (upload_started_at && !upload_ended_at) {
|
|
298
|
+
alerts.push({
|
|
299
|
+
type: "warning",
|
|
300
|
+
msg: "Please check if your offline data is already online. An upload was started but did not finish.",
|
|
301
|
+
});
|
|
302
|
+
} else {
|
|
303
|
+
alerts.push({
|
|
304
|
+
type: "info",
|
|
305
|
+
msg: "You have offline data, to handle it open the Network menu.",
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
} else
|
|
309
|
+
alerts.push({
|
|
310
|
+
type: "warning",
|
|
311
|
+
msg: `'${offlineUser}' has not yet uploaded offline data.`,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
241
315
|
addRoute({ route: entryPoint, query: undefined });
|
|
242
316
|
const page = await router.resolve({
|
|
243
317
|
pathname: entryPoint,
|
|
244
318
|
fullWrap: true,
|
|
319
|
+
alerts,
|
|
245
320
|
});
|
|
246
321
|
await replaceIframe(page.content);
|
|
247
322
|
} else {
|
|
248
323
|
const page = await router.resolve({
|
|
249
324
|
pathname: "get/auth/login",
|
|
325
|
+
alerts,
|
|
250
326
|
});
|
|
251
|
-
replaceIframe(page.content);
|
|
327
|
+
await replaceIframe(page.content);
|
|
252
328
|
}
|
|
253
329
|
} catch (error) {
|
|
330
|
+
state.mobileConfig.inErrorState = true;
|
|
254
331
|
const page = await router.resolve({
|
|
255
332
|
pathname: "get/error_page",
|
|
333
|
+
fullWrap: true,
|
|
256
334
|
alerts: [
|
|
257
335
|
{
|
|
258
336
|
type: "error",
|
|
@@ -261,7 +339,6 @@
|
|
|
261
339
|
],
|
|
262
340
|
});
|
|
263
341
|
await replaceIframe(page.content);
|
|
264
|
-
console.error(error);
|
|
265
342
|
}
|
|
266
343
|
};
|
|
267
344
|
|
package/www/js/mocks/request.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/*global i18next, saltcorn*/
|
|
2
2
|
|
|
3
|
-
function MobileRequest({
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
function MobileRequest({
|
|
4
|
+
xhr = false,
|
|
5
|
+
files = undefined,
|
|
6
|
+
query = undefined,
|
|
7
|
+
} = {}) {
|
|
8
|
+
const cfg = saltcorn.data.state.getState().mobileConfig;
|
|
9
|
+
const roleId = cfg.role_id ? cfg.role_id : 100;
|
|
10
|
+
const userId = cfg.user_id ? cfg.user_id : undefined;
|
|
7
11
|
const flashMessages = [];
|
|
8
12
|
|
|
9
13
|
return {
|
|
@@ -21,6 +25,7 @@ function MobileRequest({ xhr = false, files = undefined, query = undefined }) {
|
|
|
21
25
|
return mobileCfg?.language ? mobileCfg.language : "en";
|
|
22
26
|
},
|
|
23
27
|
user: {
|
|
28
|
+
id: userId,
|
|
24
29
|
role_id: roleId,
|
|
25
30
|
},
|
|
26
31
|
flash: (type, msg) => {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*global saltcorn, apiCall*/
|
|
2
|
+
|
|
3
|
+
// post/api/:tableName/:id
|
|
4
|
+
const updateTableRow = async (context) => {
|
|
5
|
+
const { tableName, id } = context.params;
|
|
6
|
+
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
7
|
+
const user = {
|
|
8
|
+
id: mobileConfig.user_id,
|
|
9
|
+
role_id: mobileConfig.role_id || 100,
|
|
10
|
+
};
|
|
11
|
+
const table = saltcorn.data.models.Table.findOne({ name: tableName });
|
|
12
|
+
if (!table) throw new Error(`The table '${tableName}' does not exist.`);
|
|
13
|
+
if (
|
|
14
|
+
mobileConfig.isOfflineMode ||
|
|
15
|
+
mobileConfig.localTableIds.indexOf(table.id) >= 0
|
|
16
|
+
) {
|
|
17
|
+
const row = {};
|
|
18
|
+
for (const [k, v] of new URLSearchParams(context.query).entries()) {
|
|
19
|
+
row[k] = v;
|
|
20
|
+
}
|
|
21
|
+
const errors = await saltcorn.data.web_mobile_commons.prepare_update_row(
|
|
22
|
+
table,
|
|
23
|
+
row,
|
|
24
|
+
id
|
|
25
|
+
);
|
|
26
|
+
if (errors.length > 0) throw new Error(errors.join(", "));
|
|
27
|
+
const ins_res = await table.tryUpdateRow(row, id, user);
|
|
28
|
+
if (ins_res.error)
|
|
29
|
+
throw new Error(`Update ${table.name} error: ${ins_res.error}`);
|
|
30
|
+
return { ins_res };
|
|
31
|
+
} else {
|
|
32
|
+
const response = await apiCall({
|
|
33
|
+
method: "POST",
|
|
34
|
+
path: `/api/${tableName}/${id}`,
|
|
35
|
+
body: context.query,
|
|
36
|
+
});
|
|
37
|
+
return response.data;
|
|
38
|
+
}
|
|
39
|
+
};
|
package/www/js/routes/auth.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*global sbAdmin2Layout, apiCall, removeJwt, saltcorn*/
|
|
1
|
+
/*global sbAdmin2Layout, apiCall, removeJwt, saltcorn, clearHistory*/
|
|
2
2
|
|
|
3
3
|
const prepareAuthForm = () => {
|
|
4
4
|
return new saltcorn.data.models.Form({
|
|
@@ -35,7 +35,7 @@ const getAuthLinks = (current, entryPoint) => {
|
|
|
35
35
|
return links;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
const renderLoginView = (entryPoint, versionTag) => {
|
|
38
|
+
const renderLoginView = (entryPoint, versionTag, alerts = []) => {
|
|
39
39
|
const form = prepareAuthForm(entryPoint);
|
|
40
40
|
form.onSubmit = `javascript:loginFormSubmit(this, '${entryPoint}')`;
|
|
41
41
|
form.submitLabel = "Login";
|
|
@@ -43,7 +43,7 @@ const renderLoginView = (entryPoint, versionTag) => {
|
|
|
43
43
|
title: "login",
|
|
44
44
|
form: form,
|
|
45
45
|
authLinks: getAuthLinks("login", entryPoint),
|
|
46
|
-
alerts
|
|
46
|
+
alerts,
|
|
47
47
|
headers: [
|
|
48
48
|
{ css: `static_assets/${versionTag}/saltcorn.css` },
|
|
49
49
|
{ script: "js/utils/iframe_view_utils.js" },
|
|
@@ -69,10 +69,14 @@ const renderSignupView = (entryPoint, versionTag) => {
|
|
|
69
69
|
});
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
const getLoginView = async () => {
|
|
73
|
-
const
|
|
72
|
+
const getLoginView = async (context) => {
|
|
73
|
+
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
74
74
|
return {
|
|
75
|
-
content: renderLoginView(
|
|
75
|
+
content: renderLoginView(
|
|
76
|
+
mobileConfig.entry_point,
|
|
77
|
+
mobileConfig.version_tag,
|
|
78
|
+
context.alerts ? context.alerts : []
|
|
79
|
+
),
|
|
76
80
|
replaceIframe: true,
|
|
77
81
|
};
|
|
78
82
|
};
|
|
@@ -90,6 +94,7 @@ const logoutAction = async () => {
|
|
|
90
94
|
const response = await apiCall({ method: "GET", path: "/auth/logout" });
|
|
91
95
|
if (response.data.success) {
|
|
92
96
|
await removeJwt();
|
|
97
|
+
clearHistory();
|
|
93
98
|
config.jwt = undefined;
|
|
94
99
|
return {
|
|
95
100
|
content: renderLoginView(config.entry_point, config.version_tag),
|
package/www/js/routes/common.js
CHANGED
|
@@ -25,7 +25,7 @@ const parseQuery = (queryStr) => {
|
|
|
25
25
|
|
|
26
26
|
const layout = () => {
|
|
27
27
|
const state = saltcorn.data.state.getState();
|
|
28
|
-
return state.getLayout({ role_id: state.mobileConfig.role_id });
|
|
28
|
+
return state.getLayout({ role_id: state.mobileConfig.role_id || 100 });
|
|
29
29
|
};
|
|
30
30
|
|
|
31
31
|
const sbAdmin2Layout = () => {
|
|
@@ -34,53 +34,87 @@ const sbAdmin2Layout = () => {
|
|
|
34
34
|
|
|
35
35
|
const getMenu = (req) => {
|
|
36
36
|
const state = saltcorn.data.state.getState();
|
|
37
|
-
const mobileCfg =
|
|
38
|
-
const role = mobileCfg.role_id ||
|
|
37
|
+
const mobileCfg = state.mobileConfig;
|
|
38
|
+
const role = mobileCfg.role_id || 100;
|
|
39
39
|
const extraMenu = saltcorn.data.web_mobile_commons.get_extra_menu(
|
|
40
40
|
role,
|
|
41
41
|
req.__
|
|
42
42
|
);
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
if (mobileCfg.inErrorState) {
|
|
44
|
+
const entryLink = mobileCfg.entry_point?.startsWith("get")
|
|
45
|
+
? mobileCfg.entry_point.substr(3)
|
|
46
|
+
: null;
|
|
47
|
+
return entryLink
|
|
48
|
+
? [
|
|
49
|
+
{
|
|
50
|
+
section: "Reload",
|
|
51
|
+
items: [
|
|
50
52
|
{
|
|
51
|
-
link:
|
|
52
|
-
|
|
53
|
+
link: `javascript:parent.gotoEntryView()`,
|
|
54
|
+
icon: "fas fa-sync",
|
|
55
|
+
label: "Reload",
|
|
53
56
|
},
|
|
54
|
-
]
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
]
|
|
60
|
+
: [];
|
|
61
|
+
} else {
|
|
62
|
+
const allowSignup = state.getConfig("allow_signup");
|
|
63
|
+
const userName = mobileCfg.user_name;
|
|
64
|
+
const authItems = mobileCfg.isPublicUser
|
|
65
|
+
? [
|
|
66
|
+
{
|
|
67
|
+
link: "javascript:execNavbarLink('/auth/login')",
|
|
68
|
+
label: req.__("Login"),
|
|
69
|
+
},
|
|
70
|
+
...(allowSignup
|
|
71
|
+
? [
|
|
72
|
+
{
|
|
73
|
+
link: "javascript:execNavbarLink('/auth/signup')",
|
|
74
|
+
label: req.__("Sign up"),
|
|
75
|
+
},
|
|
76
|
+
]
|
|
77
|
+
: []),
|
|
78
|
+
]
|
|
79
|
+
: [
|
|
80
|
+
{
|
|
81
|
+
label: req.__("User"),
|
|
82
|
+
icon: "far fa-user",
|
|
83
|
+
isUser: true,
|
|
84
|
+
subitems: [
|
|
85
|
+
{ label: userName },
|
|
86
|
+
{
|
|
87
|
+
link: `javascript:logout();`,
|
|
88
|
+
icon: "fas fa-sign-out-alt",
|
|
89
|
+
label: "Logout",
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
const result = [];
|
|
95
|
+
if (extraMenu.length > 0)
|
|
96
|
+
result.push({
|
|
97
|
+
section: req.__("Menu"),
|
|
98
|
+
items: extraMenu,
|
|
99
|
+
});
|
|
74
100
|
result.push({
|
|
75
|
-
section: req.__("
|
|
76
|
-
|
|
101
|
+
section: req.__("User"),
|
|
102
|
+
isUser: true,
|
|
103
|
+
items: authItems,
|
|
77
104
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
105
|
+
if (mobileCfg.allowOfflineMode)
|
|
106
|
+
result.push({
|
|
107
|
+
section: "Network",
|
|
108
|
+
items: [
|
|
109
|
+
{
|
|
110
|
+
link: "javascript:execNavbarLink('/sync/sync_settings')",
|
|
111
|
+
icon: "fas fa-sync",
|
|
112
|
+
label: "Network",
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
});
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
84
118
|
};
|
|
85
119
|
|
|
86
120
|
const prepareAlerts = (context, req) => {
|
package/www/js/routes/delete.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
/*global i18next, apiCall, saltcorn*/
|
|
1
|
+
/*global i18next, apiCall, saltcorn, offlineHelper*/
|
|
2
2
|
|
|
3
3
|
// post/delete/:name/:id
|
|
4
4
|
const deleteRows = async (context) => {
|
|
5
5
|
const { name, id } = context.params;
|
|
6
6
|
const table = await saltcorn.data.models.Table.findOne({ name });
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
if (
|
|
10
|
-
if (
|
|
7
|
+
const { isOfflineMode, localTableIds, role_id } =
|
|
8
|
+
saltcorn.data.state.getState().mobileConfig;
|
|
9
|
+
if (isOfflineMode || localTableIds.indexOf(table.id) >= 0) {
|
|
10
|
+
if (role_id <= table.min_role_write) {
|
|
11
11
|
await table.deleteRows({ id });
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
// TODO 'table.is_owner' check?
|
|
13
|
+
} else throw new Error(i18next.t("Not authorized"));
|
|
14
|
+
if (isOfflineMode && !(await offlineHelper.hasOfflineRows())) {
|
|
15
|
+
await offlineHelper.setOfflineSession(null);
|
|
16
16
|
}
|
|
17
17
|
} else {
|
|
18
18
|
await apiCall({ method: "POST", path: `/delete/${name}/${id}` });
|
package/www/js/routes/edit.js
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
/*global i18next, apiCall, saltcorn*/
|
|
1
|
+
/*global i18next, apiCall, saltcorn, offlineHelper*/
|
|
2
2
|
|
|
3
3
|
// /toggle/:name/:id/:field_name
|
|
4
4
|
const postToggleField = async (context) => {
|
|
5
5
|
const { name, id, field_name } = context.params;
|
|
6
6
|
const table = await saltcorn.data.models.Table.findOne({ name });
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const state = saltcorn.data.state.getState();
|
|
8
|
+
const { isOfflineMode, localTableIds, user_name, role_id } =
|
|
9
|
+
state.mobileConfig;
|
|
10
|
+
if (isOfflineMode || localTableIds.indexOf(table.id) >= 0) {
|
|
11
|
+
if (role_id > table.min_role_write)
|
|
10
12
|
throw new Error(i18next.t("Not authorized"));
|
|
11
13
|
await table.toggleBool(+id, field_name);
|
|
14
|
+
if (isOfflineMode && !(await offlineHelper.getLastOfflineSession()))
|
|
15
|
+
await offlineHelper.setOfflineSession({ offlineUser: user_name });
|
|
12
16
|
} else {
|
|
13
17
|
await apiCall({
|
|
14
18
|
method: "POST",
|
package/www/js/routes/error.js
CHANGED
|
@@ -1,18 +1,5 @@
|
|
|
1
|
-
/*global
|
|
1
|
+
/*global wrapContents, MobileRequest */
|
|
2
2
|
|
|
3
3
|
const getErrorView = async (context) => {
|
|
4
|
-
|
|
5
|
-
const wrappedContent = layout().wrap({
|
|
6
|
-
title: "Error",
|
|
7
|
-
body: { above: [""] },
|
|
8
|
-
alerts: context.alerts ,
|
|
9
|
-
role: state.mobileConfig.role_id,
|
|
10
|
-
headers: getHeaders(),
|
|
11
|
-
menu: [],
|
|
12
|
-
bodyClass: "",
|
|
13
|
-
currentUrl: "",
|
|
14
|
-
brand: {},
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
return { content: wrappedContent, title: "Error" };
|
|
4
|
+
return wrapContents("", "Error", context, new MobileRequest());
|
|
18
5
|
};
|
package/www/js/routes/init.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
/*global postView, postViewRoute, getView, postToggleField, deleteRows, postPageAction, getPage, getLoginView, logoutAction, getSignupView, getErrorView, window*/
|
|
1
|
+
/*global postView, postViewRoute, getView, postToggleField, deleteRows, postPageAction, getPage, getLoginView, logoutAction, getSignupView, getErrorView, window, getSyncSettingsView, getAskDeleteOfflineData, getAskUploadNotEnded, updateTableRow */
|
|
2
|
+
// TODO module namespacese
|
|
2
3
|
|
|
3
4
|
const initRoutes = async () => {
|
|
4
5
|
const routes = [
|
|
@@ -14,6 +15,10 @@ const initRoutes = async () => {
|
|
|
14
15
|
path: "get/view/:viewname",
|
|
15
16
|
action: getView,
|
|
16
17
|
},
|
|
18
|
+
{
|
|
19
|
+
path: "post/api/:tableName/:id",
|
|
20
|
+
action: updateTableRow,
|
|
21
|
+
},
|
|
17
22
|
{
|
|
18
23
|
path: "post/edit/toggle/:name/:id/:field_name",
|
|
19
24
|
action: postToggleField,
|
|
@@ -46,6 +51,18 @@ const initRoutes = async () => {
|
|
|
46
51
|
path: "get/error_page",
|
|
47
52
|
action: getErrorView,
|
|
48
53
|
},
|
|
54
|
+
{
|
|
55
|
+
path: "get/sync/sync_settings",
|
|
56
|
+
action: getSyncSettingsView,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
path: "get/sync/ask_upload_not_ended",
|
|
60
|
+
action: getAskUploadNotEnded,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
path: "get/sync/ask_delete_offline_data",
|
|
64
|
+
action: getAskDeleteOfflineData,
|
|
65
|
+
},
|
|
49
66
|
];
|
|
50
67
|
window.router = new window.UniversalRouter(routes);
|
|
51
68
|
};
|