@saltcorn/mobile-app 1.1.0-beta.11 → 1.1.0-beta.12
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/.babelrc +3 -0
- package/build_scripts/modify_android_manifest.js +47 -0
- package/build_scripts/modify_gradle_cfg.js +34 -0
- package/package.json +20 -11
- package/src/.eslintrc +21 -0
- package/src/helpers/api.js +41 -0
- package/src/helpers/auth.js +191 -0
- package/src/helpers/common.js +175 -0
- package/{www/js/utils/table_utils.js → src/helpers/db_schema.js} +18 -40
- package/src/helpers/file_system.js +102 -0
- package/{www/js/utils/global_utils.js → src/helpers/navigation.js} +169 -335
- package/src/helpers/offline_mode.js +645 -0
- package/src/index.js +20 -0
- package/src/init.js +424 -0
- package/src/routing/index.js +98 -0
- package/{www/js → src/routing}/mocks/request.js +5 -5
- package/{www/js → src/routing}/mocks/response.js +1 -1
- package/{www/js → src/routing}/routes/api.js +10 -15
- package/{www/js → src/routing}/routes/auth.js +12 -6
- package/{www/js → src/routing}/routes/delete.js +9 -6
- package/{www/js → src/routing}/routes/edit.js +9 -6
- package/src/routing/routes/error.js +6 -0
- package/{www/js → src/routing}/routes/fields.js +7 -2
- package/{www/js → src/routing}/routes/page.js +14 -9
- package/{www/js → src/routing}/routes/sync.js +9 -5
- package/{www/js → src/routing}/routes/view.js +16 -11
- package/{www/js/routes/common.js → src/routing/utils.js} +15 -13
- package/webpack.config.js +31 -0
- package/www/data/encoded_site_logo.js +1 -0
- package/www/index.html +23 -491
- package/www/js/{utils/iframe_view_utils.js → iframe_view_utils.js} +137 -269
- package/config.xml +0 -27
- package/res/icon/android/icon.png +0 -0
- package/res/screen/android/splash-icon.png +0 -0
- package/res/screen/ios/Default@2x~universal~anyany.png +0 -0
- package/www/js/routes/error.js +0 -5
- package/www/js/routes/init.js +0 -76
- package/www/js/utils/file_helpers.js +0 -108
- package/www/js/utils/offline_mode_helper.js +0 -625
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
/*global
|
|
1
|
+
/*global saltcorn */
|
|
2
|
+
import { apiCall } from "../../helpers/api";
|
|
3
|
+
import { setHasOfflineData } from "../../helpers/offline_mode";
|
|
4
|
+
import i18next from "i18next";
|
|
2
5
|
|
|
3
6
|
// /toggle/:name/:id/:field_name
|
|
4
|
-
const postToggleField = async (context) => {
|
|
7
|
+
export const postToggleField = async (context) => {
|
|
5
8
|
const { name, id, field_name } = context.params;
|
|
6
9
|
const table = await saltcorn.data.models.Table.findOne({ name });
|
|
7
10
|
const state = saltcorn.data.state.getState();
|
|
8
|
-
const { isOfflineMode, localTableIds,
|
|
11
|
+
const { isOfflineMode, localTableIds, user } = state.mobileConfig;
|
|
9
12
|
if (isOfflineMode || localTableIds.indexOf(table.id) >= 0) {
|
|
10
|
-
if (role_id > table.min_role_write)
|
|
13
|
+
if (user.role_id > table.min_role_write)
|
|
11
14
|
throw new saltcorn.data.utils.NotAuthorized(i18next.t("Not authorized"));
|
|
12
|
-
await table.toggleBool(+id, field_name);
|
|
13
|
-
if (isOfflineMode) await
|
|
15
|
+
await table.toggleBool(+id, field_name, user);
|
|
16
|
+
if (isOfflineMode) await setHasOfflineData(true);
|
|
14
17
|
} else {
|
|
15
18
|
await apiCall({
|
|
16
19
|
method: "POST",
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
/*global saltcorn
|
|
1
|
+
/*global saltcorn */
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { MobileRequest } from "../mocks/request";
|
|
4
|
+
import { MobileResponse } from "../mocks/response";
|
|
5
|
+
import { parseQuery } from "../utils";
|
|
6
|
+
import { apiCall } from "../../helpers/api";
|
|
7
|
+
|
|
8
|
+
export const postShowCalculated = async (context) => {
|
|
4
9
|
const { tableName, fieldName, fieldview } = context.params;
|
|
5
10
|
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
6
11
|
const table = saltcorn.data.models.Table.findOne({ name: tableName });
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
/*global
|
|
1
|
+
/*global saltcorn */
|
|
2
|
+
|
|
3
|
+
import { MobileRequest } from "../mocks/request";
|
|
4
|
+
import { MobileResponse } from "../mocks/response";
|
|
5
|
+
import { parseQuery, wrapContents } from "../utils";
|
|
6
|
+
import { loadFileAsText } from "../../helpers/common";
|
|
2
7
|
|
|
3
8
|
// post/page/:pagename/action/:rndid
|
|
4
|
-
const postPageAction = async (context) => {
|
|
5
|
-
const
|
|
9
|
+
export const postPageAction = async (context) => {
|
|
10
|
+
const { user } = saltcorn.data.state.getState().mobileConfig;
|
|
6
11
|
const req = new MobileRequest({ xhr: context.xhr });
|
|
7
12
|
const { page_name, rndid } = context.params;
|
|
8
13
|
const page = await saltcorn.data.models.Page.findOne({ name: page_name });
|
|
9
14
|
if (!page) throw new Error(req.__("Page %s not found", page_name));
|
|
10
|
-
if (
|
|
15
|
+
if (user.role_id > page.min_role) {
|
|
11
16
|
throw new saltcorn.data.utils.NotAuthorized(req.__("Not authorized"));
|
|
12
17
|
}
|
|
13
18
|
let col;
|
|
@@ -37,8 +42,8 @@ const findPageOrGroup = (pagename) => {
|
|
|
37
42
|
};
|
|
38
43
|
|
|
39
44
|
const runPage = async (page, state, context, { req, res }) => {
|
|
40
|
-
if (state.mobileConfig.role_id > page.min_role) {
|
|
41
|
-
const additionalInfos = `: your role: ${state.mobileConfig.role_id}, page min_role: ${page.min_role}`;
|
|
45
|
+
if (state.mobileConfig.user.role_id > page.min_role) {
|
|
46
|
+
const additionalInfos = `: your role: ${state.mobileConfig.user.role_id}, page min_role: ${page.min_role}`;
|
|
42
47
|
throw new saltcorn.data.utils.NotAuthorized(
|
|
43
48
|
req.__("Not authorized") + additionalInfos
|
|
44
49
|
);
|
|
@@ -65,8 +70,8 @@ const getEligiblePage = async (pageGroup, req) => {
|
|
|
65
70
|
};
|
|
66
71
|
|
|
67
72
|
const runPageGroup = async (pageGroup, state, context, { req, res }) => {
|
|
68
|
-
if (state.mobileConfig.role_id > pageGroup.min_role) {
|
|
69
|
-
const additionalInfos = `: your role: ${state.mobileConfig.role_id}, pagegroup min_role: ${pageGroup.min_role}`;
|
|
73
|
+
if (state.mobileConfig.user.role_id > pageGroup.min_role) {
|
|
74
|
+
const additionalInfos = `: your role: ${state.mobileConfig.user.role_id}, pagegroup min_role: ${pageGroup.min_role}`;
|
|
70
75
|
throw new saltcorn.data.utils.NotAuthorized(
|
|
71
76
|
req.__("Not authorized") + additionalInfos
|
|
72
77
|
);
|
|
@@ -79,7 +84,7 @@ const runPageGroup = async (pageGroup, state, context, { req, res }) => {
|
|
|
79
84
|
};
|
|
80
85
|
|
|
81
86
|
// get/page/pagename
|
|
82
|
-
const getPage = async (context) => {
|
|
87
|
+
export const getPage = async (context) => {
|
|
83
88
|
const state = saltcorn.data.state.getState();
|
|
84
89
|
const query = context.query ? parseQuery(context.query) : {};
|
|
85
90
|
const req = new MobileRequest({ xhr: context.xhr, query: query });
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
/*global saltcorn
|
|
1
|
+
/*global saltcorn */
|
|
2
|
+
|
|
3
|
+
import { MobileRequest } from "../mocks/request";
|
|
4
|
+
import { wrapContents } from "../utils";
|
|
2
5
|
|
|
3
6
|
// get/sync/sync_settings
|
|
4
|
-
const getSyncSettingsView = (context) => {
|
|
7
|
+
export const getSyncSettingsView = (context) => {
|
|
5
8
|
const state = saltcorn.data.state.getState();
|
|
6
9
|
const { isOfflineMode } = state.mobileConfig;
|
|
7
10
|
const content = saltcorn.markup.div(
|
|
@@ -99,7 +102,7 @@ const getSyncSettingsView = (context) => {
|
|
|
99
102
|
};
|
|
100
103
|
|
|
101
104
|
// get/sync/ask_upload_not_ended
|
|
102
|
-
const getAskUploadNotEnded = (context) => {
|
|
105
|
+
export const getAskUploadNotEnded = (context) => {
|
|
103
106
|
const content = saltcorn.markup.div(
|
|
104
107
|
saltcorn.markup.div(
|
|
105
108
|
{ class: "mb-3 h6" },
|
|
@@ -127,7 +130,7 @@ const getAskUploadNotEnded = (context) => {
|
|
|
127
130
|
};
|
|
128
131
|
|
|
129
132
|
// get/sync/ask_delete_offline_data
|
|
130
|
-
const getAskDeleteOfflineData = (context) => {
|
|
133
|
+
export const getAskDeleteOfflineData = (context) => {
|
|
131
134
|
const content = saltcorn.markup.div(
|
|
132
135
|
saltcorn.markup.div(
|
|
133
136
|
{ class: "mb-3 h6" },
|
|
@@ -145,7 +148,8 @@ const getAskDeleteOfflineData = (context) => {
|
|
|
145
148
|
{
|
|
146
149
|
class: "btn btn-primary close",
|
|
147
150
|
type: "button",
|
|
148
|
-
onClick:
|
|
151
|
+
onClick:
|
|
152
|
+
"closeModal(); parent.saltcorn.mobileApp.offlineMode.deleteOfflineData()",
|
|
149
153
|
},
|
|
150
154
|
"Delete"
|
|
151
155
|
)
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
/*global
|
|
1
|
+
/*global saltcorn */
|
|
2
2
|
|
|
3
|
+
import { MobileRequest } from "../mocks/request";
|
|
4
|
+
import { MobileResponse } from "../mocks/response";
|
|
5
|
+
import { parseQuery, wrapContents } from "../utils";
|
|
6
|
+
import { setHasOfflineData } from "../../helpers/offline_mode";
|
|
7
|
+
import { routingHistory } from "../../helpers/navigation";
|
|
3
8
|
/**
|
|
4
9
|
*
|
|
5
10
|
* @param {*} context
|
|
6
11
|
* @returns
|
|
7
12
|
*/
|
|
8
|
-
const postView = async (context) => {
|
|
13
|
+
export const postView = async (context) => {
|
|
9
14
|
let body = {};
|
|
10
15
|
let redirect = undefined;
|
|
11
16
|
for (const [k, v] of new URLSearchParams(context.query).entries()) {
|
|
@@ -30,7 +35,7 @@ const postView = async (context) => {
|
|
|
30
35
|
const state = saltcorn.data.state.getState();
|
|
31
36
|
const mobileCfg = state.mobileConfig;
|
|
32
37
|
if (
|
|
33
|
-
mobileCfg.role_id > view.min_role &&
|
|
38
|
+
mobileCfg.user.role_id > view.min_role &&
|
|
34
39
|
!(await view.authorise_post({ body, req, ...view }))
|
|
35
40
|
) {
|
|
36
41
|
throw new saltcorn.data.utils.NotAuthorized(req.__("Not authorized"));
|
|
@@ -45,7 +50,7 @@ const postView = async (context) => {
|
|
|
45
50
|
},
|
|
46
51
|
view.isRemoteTable()
|
|
47
52
|
);
|
|
48
|
-
if (mobileCfg.isOfflineMode) await
|
|
53
|
+
if (mobileCfg.isOfflineMode) await setHasOfflineData(true);
|
|
49
54
|
const wrapped = res.getWrapHtml();
|
|
50
55
|
if (wrapped) {
|
|
51
56
|
return wrapContents(
|
|
@@ -64,7 +69,7 @@ const postView = async (context) => {
|
|
|
64
69
|
*
|
|
65
70
|
* @param {*} context
|
|
66
71
|
*/
|
|
67
|
-
const postViewRoute = async (context) => {
|
|
72
|
+
export const postViewRoute = async (context) => {
|
|
68
73
|
const query = context.query ? parseQuery(context.query) : {};
|
|
69
74
|
const refererRoute =
|
|
70
75
|
routingHistory?.length > 1
|
|
@@ -82,8 +87,8 @@ const postViewRoute = async (context) => {
|
|
|
82
87
|
throw new Error(req.__("No such view: %s", context.params.viewname));
|
|
83
88
|
const res = new MobileResponse();
|
|
84
89
|
const state = saltcorn.data.state.getState();
|
|
85
|
-
const {
|
|
86
|
-
if (role_id > view.min_role)
|
|
90
|
+
const { user, isOfflineMode } = state.mobileConfig;
|
|
91
|
+
if (user.role_id > view.min_role)
|
|
87
92
|
throw new saltcorn.data.utils.NotAuthorized(req.__("Not authorized"));
|
|
88
93
|
await view.runRoute(
|
|
89
94
|
context.params.route,
|
|
@@ -92,7 +97,7 @@ const postViewRoute = async (context) => {
|
|
|
92
97
|
{ req, res },
|
|
93
98
|
view.isRemoteTable()
|
|
94
99
|
);
|
|
95
|
-
if (isOfflineMode) await
|
|
100
|
+
if (isOfflineMode) await setHasOfflineData(true);
|
|
96
101
|
const wrapped = res.getWrapHtml();
|
|
97
102
|
if (wrapped)
|
|
98
103
|
return wrapContents(
|
|
@@ -116,7 +121,7 @@ const postViewRoute = async (context) => {
|
|
|
116
121
|
* @param {*} context
|
|
117
122
|
* @returns
|
|
118
123
|
*/
|
|
119
|
-
const getView = async (context) => {
|
|
124
|
+
export const getView = async (context) => {
|
|
120
125
|
const state = saltcorn.data.state.getState();
|
|
121
126
|
const query = context.query ? parseQuery(context.query) : {};
|
|
122
127
|
const refererRoute =
|
|
@@ -129,10 +134,10 @@ const getView = async (context) => {
|
|
|
129
134
|
if (!view) throw new Error(req.__("No such view: %s", viewname));
|
|
130
135
|
const res = new MobileResponse();
|
|
131
136
|
if (
|
|
132
|
-
state.mobileConfig.role_id > view.min_role &&
|
|
137
|
+
state.mobileConfig.user.role_id > view.min_role &&
|
|
133
138
|
!(await view.authorise_get({ query, req, ...view }))
|
|
134
139
|
) {
|
|
135
|
-
const additionalInfos = `: your role: ${state.mobileConfig.role_id}, view min_role: ${view.min_role}`;
|
|
140
|
+
const additionalInfos = `: your role: ${state.mobileConfig.user.role_id}, view min_role: ${view.min_role}`;
|
|
136
141
|
throw new saltcorn.data.utils.NotAuthorized(
|
|
137
142
|
req.__("Not authorized") + additionalInfos
|
|
138
143
|
);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
/*global saltcorn
|
|
1
|
+
/*global saltcorn */
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import { getOfflineMsg } from "../helpers/offline_mode";
|
|
4
|
+
|
|
5
|
+
export const getHeaders = () => {
|
|
4
6
|
const state = saltcorn.data.state.getState();
|
|
5
7
|
const config = state.mobileConfig;
|
|
6
8
|
const versionTag = config.version_tag;
|
|
@@ -8,7 +10,7 @@ const getHeaders = () => {
|
|
|
8
10
|
{ css: `static_assets/${versionTag}/saltcorn.css` },
|
|
9
11
|
{ script: `static_assets/${versionTag}/saltcorn-common.js` },
|
|
10
12
|
{ script: `static_assets/${versionTag}/dayjs.min.js` },
|
|
11
|
-
{ script: "js/
|
|
13
|
+
{ script: "js/iframe_view_utils.js" },
|
|
12
14
|
];
|
|
13
15
|
|
|
14
16
|
let from_cfg = [];
|
|
@@ -19,7 +21,7 @@ const getHeaders = () => {
|
|
|
19
21
|
return [...stdHeaders, ...config.pluginHeaders, ...from_cfg];
|
|
20
22
|
};
|
|
21
23
|
|
|
22
|
-
const parseQuery = (queryStr) => {
|
|
24
|
+
export const parseQuery = (queryStr) => {
|
|
23
25
|
let result = {};
|
|
24
26
|
const parsedQuery =
|
|
25
27
|
typeof queryStr === "string" ? new URLSearchParams(queryStr) : undefined;
|
|
@@ -33,17 +35,17 @@ const parseQuery = (queryStr) => {
|
|
|
33
35
|
|
|
34
36
|
const layout = () => {
|
|
35
37
|
const state = saltcorn.data.state.getState();
|
|
36
|
-
return state.getLayout({ role_id: state.mobileConfig.role_id || 100 });
|
|
38
|
+
return state.getLayout({ role_id: state.mobileConfig.user.role_id || 100 });
|
|
37
39
|
};
|
|
38
40
|
|
|
39
|
-
const sbAdmin2Layout = () => {
|
|
41
|
+
export const sbAdmin2Layout = () => {
|
|
40
42
|
return saltcorn.data.state.getState().layouts["sbadmin2"];
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
const getMenu = (req) => {
|
|
44
46
|
const state = saltcorn.data.state.getState();
|
|
45
47
|
const mobileCfg = state.mobileConfig;
|
|
46
|
-
const role = mobileCfg.role_id || 100;
|
|
48
|
+
const role = mobileCfg.user.role_id || 100;
|
|
47
49
|
const extraMenu = saltcorn.data.web_mobile_commons.get_extra_menu(
|
|
48
50
|
role,
|
|
49
51
|
req.__
|
|
@@ -58,7 +60,7 @@ const getMenu = (req) => {
|
|
|
58
60
|
section: "Reload",
|
|
59
61
|
items: [
|
|
60
62
|
{
|
|
61
|
-
link:
|
|
63
|
+
link: "javascript:parent.saltcorn.mobileApp.navigation.gotoEntryView()",
|
|
62
64
|
icon: "fas fa-sync",
|
|
63
65
|
label: "Reload",
|
|
64
66
|
},
|
|
@@ -68,7 +70,7 @@ const getMenu = (req) => {
|
|
|
68
70
|
: [];
|
|
69
71
|
} else {
|
|
70
72
|
const allowSignup = state.getConfig("allow_signup");
|
|
71
|
-
const userName = mobileCfg.
|
|
73
|
+
const userName = mobileCfg.user.email;
|
|
72
74
|
const authItems = mobileCfg.isPublicUser
|
|
73
75
|
? [
|
|
74
76
|
{
|
|
@@ -129,14 +131,14 @@ const prepareAlerts = (context, req) => {
|
|
|
129
131
|
return [...(context.alerts || []), ...req.flashMessages()];
|
|
130
132
|
};
|
|
131
133
|
|
|
132
|
-
const wrapContents = (contents, title, context, req) => {
|
|
134
|
+
export const wrapContents = (contents, title, context, req) => {
|
|
133
135
|
const state = saltcorn.data.state.getState();
|
|
134
136
|
const body = {
|
|
135
137
|
above: [
|
|
136
138
|
saltcorn.markup.div(
|
|
137
139
|
{ id: "top-alert" },
|
|
138
140
|
state.mobileConfig.isOfflineMode
|
|
139
|
-
? saltcorn.markup.alert("info",
|
|
141
|
+
? saltcorn.markup.alert("info", getOfflineMsg())
|
|
140
142
|
: ""
|
|
141
143
|
),
|
|
142
144
|
contents,
|
|
@@ -147,7 +149,7 @@ const wrapContents = (contents, title, context, req) => {
|
|
|
147
149
|
title: title,
|
|
148
150
|
body,
|
|
149
151
|
alerts: prepareAlerts(context, req),
|
|
150
|
-
role: state.mobileConfig.role_id,
|
|
152
|
+
role: state.mobileConfig.user.role_id || 100,
|
|
151
153
|
menu: getMenu(req),
|
|
152
154
|
req,
|
|
153
155
|
headers: getHeaders(),
|
|
@@ -163,7 +165,7 @@ const wrapContents = (contents, title, context, req) => {
|
|
|
163
165
|
body,
|
|
164
166
|
req,
|
|
165
167
|
alerts: prepareAlerts(context, req),
|
|
166
|
-
role: state.mobileConfig.role_id,
|
|
168
|
+
role: state.mobileConfig.user.role_id || 100,
|
|
167
169
|
});
|
|
168
170
|
return {
|
|
169
171
|
content: wrappedContent,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const path = require("path");
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
entry: "./src/index.js",
|
|
5
|
+
output: {
|
|
6
|
+
path: path.resolve(__dirname, "www/dist"),
|
|
7
|
+
filename: "bundle.js",
|
|
8
|
+
library: {
|
|
9
|
+
type: "module",
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
experiments: {
|
|
13
|
+
outputModule: true,
|
|
14
|
+
},
|
|
15
|
+
module: {
|
|
16
|
+
rules: [
|
|
17
|
+
{
|
|
18
|
+
test: /\.js$/,
|
|
19
|
+
exclude: /node_modules/,
|
|
20
|
+
use: {
|
|
21
|
+
loader: "babel-loader",
|
|
22
|
+
options: {
|
|
23
|
+
presets: ["@babel/preset-env"],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
target: "web", // Use web target for browser compatibility
|
|
30
|
+
mode: "development",
|
|
31
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var _sc_site_logo = "";
|