@saltcorn/mobile-app 0.8.8-beta.0 → 0.8.8-beta.2
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 +13 -12
- package/www/js/mocks/request.js +13 -2
- package/www/js/routes/api.js +2 -14
- package/www/js/routes/common.js +3 -0
- package/www/js/routes/delete.js +5 -3
- package/www/js/routes/edit.js +2 -4
- package/www/js/routes/sync.js +2 -2
- package/www/js/routes/view.js +9 -7
- package/www/js/utils/global_utils.js +12 -1
- package/www/js/utils/iframe_view_utils.js +257 -201
- package/www/js/utils/offline_mode_helper.js +479 -54
- package/www/js/utils/table_utils.js +19 -0
package/package.json
CHANGED
package/www/index.html
CHANGED
|
@@ -300,6 +300,7 @@
|
|
|
300
300
|
if (updateNeeded) {
|
|
301
301
|
await updateDb(tablesJSON);
|
|
302
302
|
}
|
|
303
|
+
await createSyncInfoTables(config.synchedTables);
|
|
303
304
|
await initJwt();
|
|
304
305
|
await state.refresh_tables();
|
|
305
306
|
await state.refresh_views();
|
|
@@ -340,7 +341,7 @@
|
|
|
340
341
|
mobileConfig.isPublicUser = false;
|
|
341
342
|
await i18next.changeLanguage(mobileConfig.language);
|
|
342
343
|
if (mobileConfig.allowOfflineMode) {
|
|
343
|
-
const { offlineUser
|
|
344
|
+
const { offlineUser } =
|
|
344
345
|
(await offlineHelper.getLastOfflineSession()) || {};
|
|
345
346
|
if (networkDisabled) {
|
|
346
347
|
if (offlineUser && offlineUser !== mobileConfig.user_name)
|
|
@@ -356,22 +357,22 @@
|
|
|
356
357
|
}
|
|
357
358
|
} else if (offlineUser) {
|
|
358
359
|
if (offlineUser === mobileConfig.user_name) {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
} else {
|
|
365
|
-
alerts.push({
|
|
366
|
-
type: "info",
|
|
367
|
-
msg: "You have offline data, to handle it open the Network menu.",
|
|
368
|
-
});
|
|
369
|
-
}
|
|
360
|
+
await offlineHelper.sync();
|
|
361
|
+
alerts.push({
|
|
362
|
+
type: "info",
|
|
363
|
+
msg: "Synchronized your offline data.",
|
|
364
|
+
});
|
|
370
365
|
} else
|
|
371
366
|
alerts.push({
|
|
372
367
|
type: "warning",
|
|
373
368
|
msg: `'${offlineUser}' has not yet uploaded offline data.`,
|
|
374
369
|
});
|
|
370
|
+
} else {
|
|
371
|
+
await offlineHelper.sync();
|
|
372
|
+
alerts.push({
|
|
373
|
+
type: "info",
|
|
374
|
+
msg: "Synchronized your offline data.",
|
|
375
|
+
});
|
|
375
376
|
}
|
|
376
377
|
}
|
|
377
378
|
addRoute({ route: entryPoint, query: undefined });
|
package/www/js/mocks/request.js
CHANGED
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
/*global i18next, saltcorn*/
|
|
1
|
+
/*global i18next, saltcorn, currentLocation*/
|
|
2
2
|
|
|
3
3
|
function MobileRequest({
|
|
4
4
|
xhr = false,
|
|
5
5
|
files = undefined,
|
|
6
6
|
query = undefined,
|
|
7
|
+
refererRoute = undefined,
|
|
7
8
|
} = {}) {
|
|
8
9
|
const cfg = saltcorn.data.state.getState().mobileConfig;
|
|
9
10
|
const roleId = cfg.role_id ? cfg.role_id : 100;
|
|
10
11
|
const userId = cfg.user_id ? cfg.user_id : undefined;
|
|
11
12
|
const flashMessages = [];
|
|
12
|
-
|
|
13
|
+
const refererPath = refererRoute ? refererRoute.route : undefined;
|
|
14
|
+
const referQuery =
|
|
15
|
+
refererPath && refererRoute.query
|
|
16
|
+
? refererRoute.query.startsWith("?")
|
|
17
|
+
? refererRoute.query
|
|
18
|
+
: `?${refererRoute.query}`
|
|
19
|
+
: "";
|
|
20
|
+
const referer = refererPath ? `${refererPath}${referQuery}` : undefined;
|
|
13
21
|
return {
|
|
14
22
|
__: (s, ...params) =>
|
|
15
23
|
i18next.t(s, {
|
|
@@ -41,5 +49,8 @@ function MobileRequest({
|
|
|
41
49
|
xhr,
|
|
42
50
|
files,
|
|
43
51
|
query,
|
|
52
|
+
headers: {
|
|
53
|
+
referer: referer,
|
|
54
|
+
},
|
|
44
55
|
};
|
|
45
56
|
}
|
package/www/js/routes/api.js
CHANGED
|
@@ -27,13 +27,7 @@ const updateTableRow = async (context) => {
|
|
|
27
27
|
const ins_res = await table.tryUpdateRow(row, id, user);
|
|
28
28
|
if (ins_res.error)
|
|
29
29
|
throw new Error(`Update '${table.name}' error: ${ins_res.error}`);
|
|
30
|
-
if (
|
|
31
|
-
mobileConfig.isOfflineMode &&
|
|
32
|
-
!(await offlineHelper.getLastOfflineSession())
|
|
33
|
-
)
|
|
34
|
-
await offlineHelper.setOfflineSession({
|
|
35
|
-
offlineUser: mobileConfig.user_name,
|
|
36
|
-
});
|
|
30
|
+
if (mobileConfig.isOfflineMode) await offlineHelper.setHasOfflineData(true);
|
|
37
31
|
return ins_res;
|
|
38
32
|
} else {
|
|
39
33
|
const response = await apiCall({
|
|
@@ -72,13 +66,7 @@ const insertTableRow = async (context) => {
|
|
|
72
66
|
if (ins_res.error) {
|
|
73
67
|
throw new Error(`Insert '${table.name}' error: ${ins_res.error}`);
|
|
74
68
|
}
|
|
75
|
-
if (
|
|
76
|
-
mobileConfig.isOfflineMode &&
|
|
77
|
-
!(await offlineHelper.getLastOfflineSession())
|
|
78
|
-
)
|
|
79
|
-
await offlineHelper.setOfflineSession({
|
|
80
|
-
offlineUser: mobileConfig.user_name,
|
|
81
|
-
});
|
|
69
|
+
if (mobileConfig.isOfflineMode) await offlineHelper.setHasOfflineData(true);
|
|
82
70
|
return ins_res;
|
|
83
71
|
} else {
|
|
84
72
|
const response = await apiCall({
|
package/www/js/routes/common.js
CHANGED
|
@@ -6,6 +6,7 @@ const getHeaders = () => {
|
|
|
6
6
|
const stdHeaders = [
|
|
7
7
|
{ css: `static_assets/${versionTag}/saltcorn.css` },
|
|
8
8
|
{ script: `static_assets/${versionTag}/saltcorn-common.js` },
|
|
9
|
+
{ script: `static_assets/${versionTag}/dayjs.min.js` },
|
|
9
10
|
{ script: "js/utils/iframe_view_utils.js" },
|
|
10
11
|
];
|
|
11
12
|
return [...stdHeaders, ...config.pluginHeaders];
|
|
@@ -130,6 +131,7 @@ const wrapContents = (contents, title, context, req) => {
|
|
|
130
131
|
alerts: prepareAlerts(context, req),
|
|
131
132
|
role: state.mobileConfig.role_id,
|
|
132
133
|
menu: getMenu(req),
|
|
134
|
+
req,
|
|
133
135
|
headers: getHeaders(),
|
|
134
136
|
brand: {
|
|
135
137
|
name: state.getConfig("site_name") || "Saltcorn",
|
|
@@ -141,6 +143,7 @@ const wrapContents = (contents, title, context, req) => {
|
|
|
141
143
|
: layout().renderBody({
|
|
142
144
|
title: title,
|
|
143
145
|
body: { above: [contents] },
|
|
146
|
+
req,
|
|
144
147
|
alerts: prepareAlerts(context, req),
|
|
145
148
|
role: state.mobileConfig.role_id,
|
|
146
149
|
});
|
package/www/js/routes/delete.js
CHANGED
|
@@ -12,9 +12,11 @@ const deleteRows = async (context) => {
|
|
|
12
12
|
// TODO 'table.is_owner' check?
|
|
13
13
|
} else
|
|
14
14
|
throw new saltcorn.data.utils.NotAuthorized(i18next.t("Not authorized"));
|
|
15
|
-
if (isOfflineMode &&
|
|
16
|
-
await offlineHelper.
|
|
17
|
-
|
|
15
|
+
if (isOfflineMode && (await offlineHelper.hasOfflineRows()))
|
|
16
|
+
await offlineHelper.setHasOfflineData(true);
|
|
17
|
+
// if (isOfflineMode && !(await offlineHelper.hasOfflineRows())) {
|
|
18
|
+
// await offlineHelper.setOfflineSession(null);
|
|
19
|
+
// }
|
|
18
20
|
} else {
|
|
19
21
|
await apiCall({ method: "POST", path: `/delete/${name}/${id}` });
|
|
20
22
|
}
|
package/www/js/routes/edit.js
CHANGED
|
@@ -5,14 +5,12 @@ 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
7
|
const state = saltcorn.data.state.getState();
|
|
8
|
-
const { isOfflineMode, localTableIds,
|
|
9
|
-
state.mobileConfig;
|
|
8
|
+
const { isOfflineMode, localTableIds, role_id } = state.mobileConfig;
|
|
10
9
|
if (isOfflineMode || localTableIds.indexOf(table.id) >= 0) {
|
|
11
10
|
if (role_id > table.min_role_write)
|
|
12
11
|
throw new saltcorn.data.utils.NotAuthorized(i18next.t("Not authorized"));
|
|
13
12
|
await table.toggleBool(+id, field_name); //TODO call with user
|
|
14
|
-
if (isOfflineMode
|
|
15
|
-
await offlineHelper.setOfflineSession({ offlineUser: user_name });
|
|
13
|
+
if (isOfflineMode) await offlineHelper.setHasOfflineData(true);
|
|
16
14
|
} else {
|
|
17
15
|
await apiCall({
|
|
18
16
|
method: "POST",
|
package/www/js/routes/sync.js
CHANGED
|
@@ -54,7 +54,7 @@ const getSyncSettingsView = (context) => {
|
|
|
54
54
|
{ class: "col-9" },
|
|
55
55
|
saltcorn.markup.div(
|
|
56
56
|
{ class: "fs-6 fw-bold text-decoration-underline" },
|
|
57
|
-
"
|
|
57
|
+
"Sync offline data"
|
|
58
58
|
),
|
|
59
59
|
saltcorn.markup.div("Upload the data from your last offline session.")
|
|
60
60
|
),
|
|
@@ -64,7 +64,7 @@ const getSyncSettingsView = (context) => {
|
|
|
64
64
|
{
|
|
65
65
|
class: "btn btn-primary",
|
|
66
66
|
type: "button",
|
|
67
|
-
onClick: "
|
|
67
|
+
onClick: "callSync()",
|
|
68
68
|
},
|
|
69
69
|
saltcorn.markup.i({ class: "fas fa-sync" })
|
|
70
70
|
)
|
package/www/js/routes/view.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*global MobileRequest, MobileResponse, parseQuery, wrapContents, saltcorn, offlineHelper*/
|
|
1
|
+
/*global MobileRequest, MobileResponse, parseQuery, wrapContents, saltcorn, offlineHelper, routingHistory*/
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
*
|
|
@@ -35,8 +35,7 @@ const postView = async (context) => {
|
|
|
35
35
|
},
|
|
36
36
|
view.isRemoteTable()
|
|
37
37
|
);
|
|
38
|
-
if (mobileCfg.isOfflineMode
|
|
39
|
-
await offlineHelper.setOfflineSession({ offlineUser: mobileCfg.user_name });
|
|
38
|
+
if (mobileCfg.isOfflineMode) await offlineHelper.setHasOfflineData(true);
|
|
40
39
|
return res.getJson();
|
|
41
40
|
};
|
|
42
41
|
|
|
@@ -51,7 +50,7 @@ const postViewRoute = async (context) => {
|
|
|
51
50
|
const req = new MobileRequest({ xhr: context.xhr });
|
|
52
51
|
const res = new MobileResponse();
|
|
53
52
|
const state = saltcorn.data.state.getState();
|
|
54
|
-
const { role_id, isOfflineMode
|
|
53
|
+
const { role_id, isOfflineMode } = state.mobileConfig;
|
|
55
54
|
if (role_id > view.min_role)
|
|
56
55
|
throw new saltcorn.data.utils.NotAuthorized(req.__("Not authorized"));
|
|
57
56
|
await view.runRoute(
|
|
@@ -61,8 +60,7 @@ const postViewRoute = async (context) => {
|
|
|
61
60
|
{ req, res },
|
|
62
61
|
view.isRemoteTable()
|
|
63
62
|
);
|
|
64
|
-
if (isOfflineMode
|
|
65
|
-
await offlineHelper.setOfflineSession({ offlineUser: user_name });
|
|
63
|
+
if (isOfflineMode) await offlineHelper.setHasOfflineData(true);
|
|
66
64
|
return res.getJson();
|
|
67
65
|
};
|
|
68
66
|
|
|
@@ -76,7 +74,11 @@ const getView = async (context) => {
|
|
|
76
74
|
const query = parseQuery(context.query);
|
|
77
75
|
const { viewname } = context.params;
|
|
78
76
|
const view = saltcorn.data.models.View.findOne({ name: viewname });
|
|
79
|
-
const
|
|
77
|
+
const refererRoute =
|
|
78
|
+
routingHistory?.length > 1
|
|
79
|
+
? routingHistory[routingHistory.length - 2]
|
|
80
|
+
: undefined;
|
|
81
|
+
const req = new MobileRequest({ xhr: context.xhr, query, refererRoute });
|
|
80
82
|
if (
|
|
81
83
|
state.mobileConfig.role_id > view.min_role &&
|
|
82
84
|
!(await view.authorise_get({ query, req, ...view }))
|
|
@@ -189,6 +189,15 @@ async function gotoEntryView() {
|
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
function handleOpenModal() {
|
|
193
|
+
const iframe = document.getElementById("content-iframe");
|
|
194
|
+
if (!iframe) return false;
|
|
195
|
+
const openModal = iframe.contentWindow.$("#scmodal.modal.show");
|
|
196
|
+
if (openModal.length === 0) return;
|
|
197
|
+
iframe.contentWindow.bootstrap.Modal.getInstance(openModal[0]).hide();
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
192
201
|
async function handleRoute(route, query, files) {
|
|
193
202
|
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
194
203
|
try {
|
|
@@ -201,7 +210,8 @@ async function handleRoute(route, query, files) {
|
|
|
201
210
|
clearHistory();
|
|
202
211
|
await gotoEntryView();
|
|
203
212
|
} else {
|
|
204
|
-
if (route === "/" || route === "get"
|
|
213
|
+
if (route === "/" || route === "get" || route === "get/")
|
|
214
|
+
return await gotoEntryView();
|
|
205
215
|
const safeRoute = route ? route : currentLocation();
|
|
206
216
|
addRoute({ route: safeRoute, query });
|
|
207
217
|
const page = await router.resolve({
|
|
@@ -218,6 +228,7 @@ async function handleRoute(route, query, files) {
|
|
|
218
228
|
: [],
|
|
219
229
|
});
|
|
220
230
|
if (page.redirect) {
|
|
231
|
+
if (handleOpenModal()) return;
|
|
221
232
|
if (
|
|
222
233
|
page.redirect.startsWith("http://localhost") ||
|
|
223
234
|
page.redirect === "undefined"
|