@saltcorn/mobile-app 0.8.7-beta.0 → 0.8.7-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.7-beta.0",
4
+ "version": "0.8.7-beta.2",
5
5
  "description": "Apache Cordova application with @saltcorn/markup",
6
6
  "main": "index.js",
7
7
  "scripts": {
package/www/index.html CHANGED
@@ -177,6 +177,22 @@
177
177
  });
178
178
  };
179
179
 
180
+ const readSiteLogo = async (state) => {
181
+ try {
182
+ const base64 = await readText(
183
+ "encoded_site_logo.txt",
184
+ `${cordova.file.applicationDirectory}www`
185
+ );
186
+ state.mobileConfig.encodedSiteLogo = base64;
187
+ } catch (error) {
188
+ console.log(
189
+ `Unable to read the site logo file: ${
190
+ error.message ? error.message : "Unknown error"
191
+ }`
192
+ );
193
+ }
194
+ };
195
+
180
196
  // the app comes back from background
181
197
  const onResume = async () => {
182
198
  if (typeof saltcorn === "undefined") return;
@@ -212,6 +228,21 @@
212
228
  }
213
229
  };
214
230
 
231
+ const isPublicJwt = (jwt) => {
232
+ try {
233
+ if (!jwt) return false;
234
+ const decoded = jwt_decode(jwt);
235
+ return decoded.sub === "public";
236
+ } catch (error) {
237
+ console.log(
238
+ `Unable to inspect '${jwt}': ${
239
+ error.message ? error.message : "Unknown error"
240
+ }`
241
+ );
242
+ return false;
243
+ }
244
+ };
245
+
215
246
  // device is ready
216
247
  const init = async () => {
217
248
  document.addEventListener("resume", onResume, false);
@@ -252,6 +283,7 @@
252
283
  setVersionTtag();
253
284
  const entryPoint = config.entry_point;
254
285
  await initI18Next();
286
+ await readSiteLogo(state);
255
287
  state.mobileConfig.networkState = navigator.connection.type;
256
288
  document.addEventListener(
257
289
  "offline",
@@ -320,6 +352,20 @@
320
352
  alerts,
321
353
  });
322
354
  await replaceIframe(page.content);
355
+ } else if (isPublicJwt(jwt)) {
356
+ const config = state.mobileConfig;
357
+ config.role_id = 100;
358
+ config.user_name = "public";
359
+ config.language = "en";
360
+ config.isPublicUser = true;
361
+ i18next.changeLanguage(config.language);
362
+ addRoute({ route: entryPoint, query: undefined });
363
+ const page = await router.resolve({
364
+ pathname: entryPoint,
365
+ fullWrap: true,
366
+ alerts,
367
+ });
368
+ await replaceIframe(page.content);
323
369
  } else {
324
370
  const page = await router.resolve({
325
371
  pathname: "get/auth/login",
@@ -19,7 +19,7 @@ function MobileResponse() {
19
19
  }
20
20
 
21
21
  function getSendData() {
22
- return getSendData;
22
+ return sendData;
23
23
  }
24
24
 
25
25
  return {
@@ -1,4 +1,4 @@
1
- /*global saltcorn, apiCall*/
1
+ /*global saltcorn, apiCall, MobileRequest, offlineHelper*/
2
2
 
3
3
  // post/api/:tableName/:id
4
4
  const updateTableRow = async (context) => {
@@ -26,8 +26,15 @@ const updateTableRow = async (context) => {
26
26
  if (errors.length > 0) throw new Error(errors.join(", "));
27
27
  const ins_res = await table.tryUpdateRow(row, id, user);
28
28
  if (ins_res.error)
29
- throw new Error(`Update ${table.name} error: ${ins_res.error}`);
30
- return { ins_res };
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
+ });
37
+ return ins_res;
31
38
  } else {
32
39
  const response = await apiCall({
33
40
  method: "POST",
@@ -37,3 +44,48 @@ const updateTableRow = async (context) => {
37
44
  return response.data;
38
45
  }
39
46
  };
47
+
48
+ // post/api/:tableName
49
+ const insertTableRow = async (context) => {
50
+ const { tableName } = context.params;
51
+ const table = saltcorn.data.models.Table.findOne({ name: tableName });
52
+ const mobileConfig = saltcorn.data.state.getState().mobileConfig;
53
+ const user = {
54
+ id: mobileConfig.user_id,
55
+ role_id: mobileConfig.role_id || 100,
56
+ };
57
+ if (!table) throw new Error(`The table '${tableName}' does not exist.`);
58
+ if (
59
+ mobileConfig.isOfflineMode ||
60
+ mobileConfig.localTableIds.indexOf(table.id) >= 0
61
+ ) {
62
+ const row = {};
63
+ for (const [k, v] of new URLSearchParams(context.query).entries()) {
64
+ row[k] = v;
65
+ }
66
+ const errors = await saltcorn.data.web_mobile_commons.prepare_insert_row(
67
+ row,
68
+ table.getFields()
69
+ );
70
+ if (errors.length > 0) throw new Error(errors.join(", "));
71
+ const ins_res = await table.tryInsertRow(row, user);
72
+ if (ins_res.error) {
73
+ throw new Error(`Insert '${table.name}' error: ${ins_res.error}`);
74
+ }
75
+ if (
76
+ mobileConfig.isOfflineMode &&
77
+ !(await offlineHelper.getLastOfflineSession())
78
+ )
79
+ await offlineHelper.setOfflineSession({
80
+ offlineUser: mobileConfig.user_name,
81
+ });
82
+ return ins_res;
83
+ } else {
84
+ const response = await apiCall({
85
+ method: "POST",
86
+ path: `/api/${tableName}`,
87
+ body: context.query,
88
+ });
89
+ return response.data;
90
+ }
91
+ };
@@ -131,8 +131,10 @@ const wrapContents = (contents, title, context, req) => {
131
131
  role: state.mobileConfig.role_id,
132
132
  menu: getMenu(req),
133
133
  headers: getHeaders(),
134
- // TODO logo as BASE 64 image
135
- brand: { name: state.getConfig("site_name") || "Saltcorn" },
134
+ brand: {
135
+ name: state.getConfig("site_name") || "Saltcorn",
136
+ logo: state.mobileConfig.encodedSiteLogo,
137
+ },
136
138
  bodyClass: "",
137
139
  currentUrl: "",
138
140
  })
@@ -1,4 +1,4 @@
1
- /*global postView, postViewRoute, getView, postToggleField, deleteRows, postPageAction, getPage, getLoginView, logoutAction, getSignupView, getErrorView, window, getSyncSettingsView, getAskDeleteOfflineData, getAskUploadNotEnded, updateTableRow */
1
+ /*global postView, postViewRoute, getView, postToggleField, deleteRows, postPageAction, getPage, getLoginView, logoutAction, getSignupView, getErrorView, window, getSyncSettingsView, getAskDeleteOfflineData, getAskUploadNotEnded, updateTableRow, insertTableRow */
2
2
  // TODO module namespacese
3
3
 
4
4
  const initRoutes = async () => {
@@ -19,6 +19,10 @@ const initRoutes = async () => {
19
19
  path: "post/api/:tableName/:id",
20
20
  action: updateTableRow,
21
21
  },
22
+ {
23
+ path: "post/api/:tableName/",
24
+ action: insertTableRow,
25
+ },
22
26
  {
23
27
  path: "post/edit/toggle/:name/:id/:field_name",
24
28
  action: postToggleField,
@@ -24,6 +24,11 @@ function getDirEntry(directory) {
24
24
  }
25
25
 
26
26
  async function readJSON(fileName, dirName) {
27
+ const text = await readText(fileName, dirName);
28
+ return JSON.parse(text);
29
+ }
30
+
31
+ async function readText(fileName, dirName) {
27
32
  const dirEntry = await getDirEntry(dirName);
28
33
  return new Promise((resolve, reject) => {
29
34
  dirEntry.getFile(
@@ -33,7 +38,7 @@ async function readJSON(fileName, dirName) {
33
38
  fileEntry.file(function (file) {
34
39
  let reader = new FileReader();
35
40
  reader.onloadend = function (e) {
36
- resolve(JSON.parse(this.result));
41
+ resolve(this.result);
37
42
  };
38
43
  reader.readAsText(file);
39
44
  });
@@ -201,7 +201,7 @@ async function handleRoute(route, query, files) {
201
201
  clearHistory();
202
202
  await gotoEntryView();
203
203
  } else {
204
- if (route === "/") return await gotoEntryView();
204
+ if (route === "/" || route === "get") return await gotoEntryView();
205
205
  const safeRoute = route ? route : currentLocation();
206
206
  addRoute({ route: safeRoute, query });
207
207
  const page = await router.resolve({
@@ -213,6 +213,7 @@ async function publicLogin(entryPoint) {
213
213
  await parent.setJwt(loginResult);
214
214
  config.jwt = loginResult;
215
215
  parent.i18next.changeLanguage(config.language);
216
+ parent.addRoute({ route: entryPoint, query: undefined });
216
217
  const page = await parent.router.resolve({
217
218
  pathname: entryPoint,
218
219
  fullWrap: true,
@@ -530,19 +531,6 @@ async function make_unique_field(
530
531
  }
531
532
  }
532
533
 
533
- async function buildEncodedImage(fileId, elementId) {
534
- const base64Encoded = await parent.loadEncodedFile(fileId);
535
- document.getElementById(elementId).src = base64Encoded;
536
- }
537
-
538
- async function buildEncodedBgImage(fileId, elementId) {
539
- const base64Encoded = await parent.loadEncodedFile(fileId);
540
- // ensure that not unique IDs work, but should not happen
541
- $(`#${elementId}`).each(function () {
542
- $(this).prev()[0].style.backgroundImage = `url("${base64Encoded}")`;
543
- });
544
- }
545
-
546
534
  function openFile(fileId) {
547
535
  // TODO fileIds with whitespaces do not work
548
536
  const config = parent.saltcorn.data.state.getState().mobileConfig;
@@ -574,14 +562,31 @@ async function clear_state() {
574
562
  }
575
563
 
576
564
  async function view_post(viewname, route, data, onDone) {
565
+ const mobileConfig = parent.saltcorn.data.state.getState().mobileConfig;
566
+ const view = parent.saltcorn.data.models.View.findOne({ name: viewname });
577
567
  try {
578
- const response = await parent.apiCall({
579
- method: "POST",
580
- path: "/view/" + viewname + "/" + route,
581
- body: data,
582
- });
583
- if (onDone) onDone(response.data);
584
- common_done(response.data);
568
+ let respData = undefined;
569
+ if (
570
+ mobileConfig.isOfflineMode ||
571
+ (view?.table_id && mobileConfig.localTableIds.indexOf(view.table_id) >= 0)
572
+ ) {
573
+ respData = await parent.router.resolve({
574
+ pathname: `post/view/${viewname}/${route}`,
575
+ data,
576
+ });
577
+ } else {
578
+ const response = await parent.apiCall({
579
+ method: "POST",
580
+ path: "/view/" + viewname + "/" + route,
581
+ body: data,
582
+ });
583
+ if (response) respData = response.data;
584
+ }
585
+
586
+ if (!respData)
587
+ throw new Error(`The response of '${viewname}/${route}' is ${respData}`);
588
+ if (onDone) onDone(respData);
589
+ common_done(respData);
585
590
  } catch (error) {
586
591
  parent.errorAlert(error);
587
592
  }