@saltcorn/mobile-app 1.1.0-beta.2 → 1.1.0-beta.20

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.
Files changed (39) hide show
  1. package/.babelrc +3 -0
  2. package/build_scripts/modify_android_manifest.js +47 -0
  3. package/build_scripts/modify_gradle_cfg.js +34 -0
  4. package/package.json +20 -11
  5. package/src/.eslintrc +21 -0
  6. package/src/helpers/api.js +43 -0
  7. package/src/helpers/auth.js +191 -0
  8. package/src/helpers/common.js +175 -0
  9. package/{www/js/utils/table_utils.js → src/helpers/db_schema.js} +18 -40
  10. package/src/helpers/file_system.js +102 -0
  11. package/{www/js/utils/global_utils.js → src/helpers/navigation.js} +175 -335
  12. package/src/helpers/offline_mode.js +645 -0
  13. package/src/index.js +20 -0
  14. package/src/init.js +424 -0
  15. package/src/routing/index.js +98 -0
  16. package/{www/js → src/routing}/mocks/request.js +5 -5
  17. package/{www/js → src/routing}/mocks/response.js +1 -1
  18. package/{www/js → src/routing}/routes/api.js +10 -15
  19. package/{www/js → src/routing}/routes/auth.js +12 -6
  20. package/{www/js → src/routing}/routes/delete.js +9 -6
  21. package/{www/js → src/routing}/routes/edit.js +9 -6
  22. package/src/routing/routes/error.js +6 -0
  23. package/{www/js → src/routing}/routes/fields.js +7 -2
  24. package/{www/js → src/routing}/routes/page.js +14 -9
  25. package/{www/js → src/routing}/routes/sync.js +9 -5
  26. package/{www/js → src/routing}/routes/view.js +16 -11
  27. package/{www/js/routes/common.js → src/routing/utils.js} +15 -13
  28. package/webpack.config.js +31 -0
  29. package/www/data/encoded_site_logo.js +1 -0
  30. package/www/index.html +23 -493
  31. package/www/js/{utils/iframe_view_utils.js → iframe_view_utils.js} +187 -273
  32. package/config.xml +0 -27
  33. package/res/icon/android/icon.png +0 -0
  34. package/res/screen/android/splash-icon.png +0 -0
  35. package/res/screen/ios/Default@2x~universal~anyany.png +0 -0
  36. package/www/js/routes/error.js +0 -5
  37. package/www/js/routes/init.js +0 -76
  38. package/www/js/utils/file_helpers.js +0 -108
  39. package/www/js/utils/offline_mode_helper.js +0 -625
@@ -1,16 +1,19 @@
1
- /*global i18next, apiCall, saltcorn, offlineHelper*/
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, role_id } = state.mobileConfig;
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); //TODO call with user
13
- if (isOfflineMode) await offlineHelper.setHasOfflineData(true);
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",
@@ -0,0 +1,6 @@
1
+ import { MobileRequest } from "../mocks/request";
2
+ import { wrapContents } from "../utils";
3
+
4
+ export const getErrorView = async (context) => {
5
+ return wrapContents("", "Error", context, new MobileRequest());
6
+ };
@@ -1,6 +1,11 @@
1
- /*global saltcorn, apiCall, MobileRequest, MobileResponse, offlineHelper, parseQuery */
1
+ /*global saltcorn */
2
2
 
3
- const postShowCalculated = async (context) => {
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 window, MobileRequest, parseQuery, MobileResponse, wrapContents, saltcorn, loadFileAsText*/
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 state = saltcorn.data.state.getState();
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 (state.mobileConfig.role_id > page.min_role) {
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, wrapContents, MobileRequest, */
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: "closeModal(); deleteOfflineData()",
151
+ onClick:
152
+ "closeModal(); parent.saltcorn.mobileApp.offlineMode.deleteOfflineData()",
149
153
  },
150
154
  "Delete"
151
155
  )
@@ -1,11 +1,16 @@
1
- /*global MobileRequest, MobileResponse, parseQuery, wrapContents, saltcorn, offlineHelper, routingHistory*/
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 offlineHelper.setHasOfflineData(true);
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 { role_id, isOfflineMode } = state.mobileConfig;
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 offlineHelper.setHasOfflineData(true);
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, offlineHelper*/
1
+ /*global saltcorn */
2
2
 
3
- const getHeaders = () => {
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/utils/iframe_view_utils.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: `javascript:parent.gotoEntryView()`,
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.user_name;
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", offlineHelper.getOfflineMsg())
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 = "";