@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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@saltcorn/mobile-app",
3
3
  "displayName": "Saltcorn mobile app",
4
- "version": "0.8.8-beta.0",
4
+ "version": "0.8.8-beta.2",
5
5
  "description": "Apache Cordova application with @saltcorn/markup",
6
6
  "main": "index.js",
7
7
  "scripts": {
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, upload_started_at, upload_ended_at } =
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
- if (upload_started_at && !upload_ended_at) {
360
- alerts.push({
361
- type: "warning",
362
- msg: "Please check if your offline data is already online. An upload was started but did not finish.",
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 });
@@ -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
  }
@@ -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({
@@ -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
  });
@@ -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 && !(await offlineHelper.hasOfflineRows())) {
16
- await offlineHelper.setOfflineSession(null);
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
  }
@@ -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, user_name, role_id } =
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 && !(await offlineHelper.getLastOfflineSession()))
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",
@@ -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
- "Upload offline data"
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: "callUpload()",
67
+ onClick: "callSync()",
68
68
  },
69
69
  saltcorn.markup.i({ class: "fas fa-sync" })
70
70
  )
@@ -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 && !(await offlineHelper.getLastOfflineSession()))
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, user_name } = state.mobileConfig;
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 && !(await offlineHelper.getLastOfflineSession()))
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 req = new MobileRequest({ xhr: context.xhr, query });
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") return await gotoEntryView();
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"