@saltcorn/mobile-app 1.5.0-beta.17 → 1.5.0-beta.19
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/optional_sources/notifications.js +2 -2
- package/package.json +1 -1
- package/src/helpers/auth.js +7 -7
- package/src/helpers/common.js +49 -27
- package/src/helpers/navigation.js +4 -4
- package/src/helpers/offline_mode.js +80 -23
- package/src/init.js +2 -2
- package/www/js/iframe_view_utils.js +21 -24
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { Capacitor } from "@capacitor/core";
|
|
4
4
|
import { apiCall } from "./api";
|
|
5
|
-
import {
|
|
5
|
+
import { showToasts } from "./common";
|
|
6
6
|
import { PushNotifications } from "@capacitor/push-notifications";
|
|
7
7
|
import { Device } from "@capacitor/device";
|
|
8
8
|
|
|
@@ -151,7 +151,7 @@ export function addPusNotifyHandler() {
|
|
|
151
151
|
const state = saltcorn.data.state.getState();
|
|
152
152
|
state.mobile_push_handler["push_notification"] = (notification) => {
|
|
153
153
|
console.log("Push notification received:", notification);
|
|
154
|
-
|
|
154
|
+
showToasts([
|
|
155
155
|
{
|
|
156
156
|
type: "info",
|
|
157
157
|
msg: notification.body,
|
package/package.json
CHANGED
package/src/helpers/auth.js
CHANGED
|
@@ -7,7 +7,7 @@ import { router } from "../routing/index";
|
|
|
7
7
|
import { getLastOfflineSession, deleteOfflineData, sync } from "./offline_mode";
|
|
8
8
|
import { addRoute, replaceIframe, clearHistory } from "../helpers/navigation";
|
|
9
9
|
import {
|
|
10
|
-
|
|
10
|
+
showToasts,
|
|
11
11
|
tryInitBackgroundSync,
|
|
12
12
|
tryInitPush,
|
|
13
13
|
tryStopBackgroundSync,
|
|
@@ -69,7 +69,7 @@ const initialSync = async (config) => {
|
|
|
69
69
|
const alerts = [];
|
|
70
70
|
const { offlineUser, hasOfflineData } = (await getLastOfflineSession()) || {};
|
|
71
71
|
if (!offlineUser || offlineUser === config.user.email) {
|
|
72
|
-
await sync(
|
|
72
|
+
await sync(true, true, alerts);
|
|
73
73
|
} else {
|
|
74
74
|
if (hasOfflineData)
|
|
75
75
|
alerts.push({
|
|
@@ -78,7 +78,7 @@ const initialSync = async (config) => {
|
|
|
78
78
|
});
|
|
79
79
|
else {
|
|
80
80
|
await deleteOfflineData(true);
|
|
81
|
-
await sync(
|
|
81
|
+
await sync(true, true, alerts);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
return alerts;
|
|
@@ -138,7 +138,7 @@ export async function login({ email, password, isSignup, token }) {
|
|
|
138
138
|
});
|
|
139
139
|
if (page.content) await replaceIframe(page.content, page.isFile);
|
|
140
140
|
} else if (loginResult?.alerts) {
|
|
141
|
-
|
|
141
|
+
showToasts(loginResult?.alerts);
|
|
142
142
|
} else {
|
|
143
143
|
throw new Error("The login failed.");
|
|
144
144
|
}
|
|
@@ -180,13 +180,13 @@ export async function publicLogin(entryPoint) {
|
|
|
180
180
|
});
|
|
181
181
|
if (page.content) await replaceIframe(page.content, page.isFile);
|
|
182
182
|
} else if (loginResult?.alerts) {
|
|
183
|
-
|
|
183
|
+
showToasts(loginResult?.alerts);
|
|
184
184
|
} else {
|
|
185
185
|
throw new Error("The login failed.");
|
|
186
186
|
}
|
|
187
187
|
} catch (error) {
|
|
188
188
|
console.error(error);
|
|
189
|
-
|
|
189
|
+
showToasts([
|
|
190
190
|
{
|
|
191
191
|
type: "error",
|
|
192
192
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -215,7 +215,7 @@ export async function logout() {
|
|
|
215
215
|
} else throw new Error("Unable to logout.");
|
|
216
216
|
} catch (error) {
|
|
217
217
|
console.error("unable to logout:", error);
|
|
218
|
-
|
|
218
|
+
showToasts([
|
|
219
219
|
{
|
|
220
220
|
type: "error",
|
|
221
221
|
msg: error.message ? error.message : "An error occured.",
|
package/src/helpers/common.js
CHANGED
|
@@ -8,22 +8,28 @@ import { addPushSyncHandler } from "./offline_mode";
|
|
|
8
8
|
|
|
9
9
|
const orientationChangeListeners = new Set();
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Make the toast area shown at the bottom empty
|
|
13
|
+
*/
|
|
14
|
+
export function clearToasts() {
|
|
12
15
|
const iframe = document.getElementById("content-iframe");
|
|
13
16
|
const alertsArea =
|
|
14
17
|
iframe.contentWindow.document.getElementById("toasts-area");
|
|
15
18
|
alertsArea.innerHTML = "";
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Show toasts in the toast area at the bottom
|
|
23
|
+
* @param toasts
|
|
24
|
+
* @returns
|
|
25
|
+
*/
|
|
26
|
+
export function showToasts(toasts) {
|
|
19
27
|
if (typeof saltcorn === "undefined") {
|
|
20
28
|
console.log("Not yet initalized.");
|
|
21
|
-
console.log(
|
|
29
|
+
console.log(toasts);
|
|
22
30
|
} else {
|
|
23
31
|
const iframe = document.getElementById("content-iframe");
|
|
24
|
-
let area = iframe.contentWindow.document.getElementById(
|
|
25
|
-
toast ? "toasts-area" : "top-alert"
|
|
26
|
-
);
|
|
32
|
+
let area = iframe.contentWindow.document.getElementById("toasts-area");
|
|
27
33
|
if (!area) {
|
|
28
34
|
const areaHtml = `<div class="container">
|
|
29
35
|
<div
|
|
@@ -37,18 +43,14 @@ export function showAlerts(alerts, toast = true) {
|
|
|
37
43
|
iframe.contentWindow.document
|
|
38
44
|
.getElementById("page-inner-content")
|
|
39
45
|
.insertAdjacentHTML("beforeend", areaHtml);
|
|
40
|
-
area = iframe.contentWindow.document.getElementById(
|
|
41
|
-
toast ? "toasts-area" : "top-alert"
|
|
42
|
-
);
|
|
46
|
+
area = iframe.contentWindow.document.getElementById("toasts-area");
|
|
43
47
|
}
|
|
44
48
|
const successIds = [];
|
|
45
49
|
area.innerHTML = "";
|
|
46
|
-
for (const { type, msg, title } of
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (type === "success") successIds.push(rndid);
|
|
51
|
-
} else area.innerHTML += saltcorn.markup.alert(type, msg);
|
|
50
|
+
for (const { type, msg, title } of toasts) {
|
|
51
|
+
const rndid = `tab${Math.floor(Math.random() * 16777215).toString(16)}`;
|
|
52
|
+
area.innerHTML += saltcorn.markup.toast(type, msg, rndid, title);
|
|
53
|
+
if (type === "success") successIds.push(rndid);
|
|
52
54
|
}
|
|
53
55
|
if (successIds.length > 0) {
|
|
54
56
|
setTimeout(() => {
|
|
@@ -62,6 +64,34 @@ export function showAlerts(alerts, toast = true) {
|
|
|
62
64
|
return true;
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Make the alert area at the top empty
|
|
69
|
+
*/
|
|
70
|
+
export function clearAlerts() {
|
|
71
|
+
const iframe = document.getElementById("content-iframe");
|
|
72
|
+
const area = iframe.contentWindow.document.getElementById("alerts-area");
|
|
73
|
+
if (area) area.innerHTML = "";
|
|
74
|
+
const topAlert = iframe.contentWindow.document.getElementById("top-alert");
|
|
75
|
+
if (topAlert) topAlert.innerHTML = "";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Show alerts in the alert area at the top
|
|
80
|
+
* @param alerts
|
|
81
|
+
*/
|
|
82
|
+
export function showAlerts(alerts) {
|
|
83
|
+
if (typeof saltcorn === "undefined") {
|
|
84
|
+
console.log("Not yet initalized.");
|
|
85
|
+
console.log(alerts);
|
|
86
|
+
} else {
|
|
87
|
+
for (const { type, msg, title } of alerts) {
|
|
88
|
+
const iframe = document.getElementById("content-iframe");
|
|
89
|
+
const area = iframe.contentWindow.document.getElementById("top-alert");
|
|
90
|
+
area.innerHTML += saltcorn.markup.alert(type, msg);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
65
95
|
export function showLoadSpinner() {
|
|
66
96
|
const iframe = document.getElementById("content-iframe");
|
|
67
97
|
if (iframe) iframe.contentWindow.showLoadSpinner();
|
|
@@ -72,17 +102,9 @@ export function removeLoadSpinner() {
|
|
|
72
102
|
if (iframe) iframe.contentWindow.removeLoadSpinner();
|
|
73
103
|
}
|
|
74
104
|
|
|
75
|
-
export function clearTopAlerts() {
|
|
76
|
-
const iframe = document.getElementById("content-iframe");
|
|
77
|
-
const area = iframe.contentWindow.document.getElementById("alerts-area");
|
|
78
|
-
if (area) area.innerHTML = "";
|
|
79
|
-
const topAlert = iframe.contentWindow.document.getElementById("top-alert");
|
|
80
|
-
if (topAlert) topAlert.innerHTML = "";
|
|
81
|
-
}
|
|
82
|
-
|
|
83
105
|
export function errorAlert(error) {
|
|
84
106
|
console.error(error);
|
|
85
|
-
|
|
107
|
+
showToasts([
|
|
86
108
|
{
|
|
87
109
|
type: "error",
|
|
88
110
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -110,7 +132,7 @@ export async function loadFileAsText(fileId) {
|
|
|
110
132
|
});
|
|
111
133
|
} catch (error) {
|
|
112
134
|
if (
|
|
113
|
-
!
|
|
135
|
+
!showToasts([
|
|
114
136
|
{
|
|
115
137
|
type: "error",
|
|
116
138
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -139,7 +161,7 @@ export async function loadEncodedFile(fileId) {
|
|
|
139
161
|
reader.readAsDataURL(response.data);
|
|
140
162
|
});
|
|
141
163
|
} catch (error) {
|
|
142
|
-
|
|
164
|
+
showToasts([
|
|
143
165
|
{
|
|
144
166
|
type: "error",
|
|
145
167
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -157,7 +179,7 @@ export async function takePhoto() {
|
|
|
157
179
|
});
|
|
158
180
|
return image.path;
|
|
159
181
|
} catch (error) {
|
|
160
|
-
|
|
182
|
+
showToasts([
|
|
161
183
|
{
|
|
162
184
|
type: "error",
|
|
163
185
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -3,7 +3,7 @@ import i18next from "i18next";
|
|
|
3
3
|
|
|
4
4
|
import { router } from "../routing/index";
|
|
5
5
|
import { startOfflineMode } from "./offline_mode";
|
|
6
|
-
import {
|
|
6
|
+
import { showToasts } from "./common";
|
|
7
7
|
|
|
8
8
|
export let routingHistory = [];
|
|
9
9
|
|
|
@@ -186,7 +186,7 @@ export async function handleRoute(route, query, files, data) {
|
|
|
186
186
|
await replaceIframeInnerContent(page.content);
|
|
187
187
|
else await replaceIframe(page.content, page.isFile);
|
|
188
188
|
} else {
|
|
189
|
-
|
|
189
|
+
showToasts([
|
|
190
190
|
{
|
|
191
191
|
type: "warning",
|
|
192
192
|
msg: i18next.t("%s finished without a result", {
|
|
@@ -199,7 +199,7 @@ export async function handleRoute(route, query, files, data) {
|
|
|
199
199
|
}
|
|
200
200
|
} catch (error) {
|
|
201
201
|
if (routeAdded) popRoute();
|
|
202
|
-
|
|
202
|
+
showToasts([
|
|
203
203
|
{
|
|
204
204
|
type: "error",
|
|
205
205
|
msg: `${i18next.t("In %s", {
|
|
@@ -253,7 +253,7 @@ export async function gotoEntryView() {
|
|
|
253
253
|
addRoute({ route: mobileConfig.entry_point, query: undefined });
|
|
254
254
|
await replaceIframeInnerContent(page.content);
|
|
255
255
|
} catch (error) {
|
|
256
|
-
|
|
256
|
+
showToasts([
|
|
257
257
|
{
|
|
258
258
|
type: "error",
|
|
259
259
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import { apiCall } from "./api";
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
showToasts,
|
|
6
|
+
clearToasts,
|
|
6
7
|
clearAlerts,
|
|
8
|
+
showAlerts,
|
|
7
9
|
errorAlert,
|
|
8
10
|
showLoadSpinner,
|
|
9
11
|
removeLoadSpinner,
|
|
@@ -318,12 +320,28 @@ const handleUniqueConflicts = async (uniqueConflicts, translatedIds) => {
|
|
|
318
320
|
}
|
|
319
321
|
};
|
|
320
322
|
|
|
321
|
-
|
|
323
|
+
/**
|
|
324
|
+
* If there was a field level data conflict, the server version is applied
|
|
325
|
+
* When it also was translated, change the untranslated row and translate it later the normal way
|
|
326
|
+
* @param {*} dataConflicts
|
|
327
|
+
* @param {*} translatedIds
|
|
328
|
+
* @param {*} alerts
|
|
329
|
+
*/
|
|
330
|
+
const handleUpdateConflicts = async (dataConflicts, translatedIds, alerts) => {
|
|
322
331
|
let hasConflicts = false;
|
|
323
332
|
for (const [tblName, updates] of Object.entries(dataConflicts)) {
|
|
324
333
|
const table = saltcorn.data.models.Table.findOne({ name: tblName });
|
|
325
334
|
const pkName = table.pk_name || "id";
|
|
335
|
+
const translations = translatedIds[tblName] || {};
|
|
326
336
|
for (const update of updates) {
|
|
337
|
+
// search a translation where the current row is the target
|
|
338
|
+
// and if found, make sure the untranslated row is updated
|
|
339
|
+
for (const [from, to] of Object.entries(translations)) {
|
|
340
|
+
if (to === update[pkName]) {
|
|
341
|
+
update[pkName] = from;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
327
345
|
const { [pkName]: _sc_pkValue, ...rest } = update;
|
|
328
346
|
await table.updateRow(rest, _sc_pkValue);
|
|
329
347
|
hasConflicts = true;
|
|
@@ -404,7 +422,7 @@ const syncOfflineData = async (synchedTables, syncTimestamp, alerts) => {
|
|
|
404
422
|
if (finished) {
|
|
405
423
|
if (error) throw new Error(error.message);
|
|
406
424
|
else {
|
|
407
|
-
await handleUpdateConflicts(dataConflicts, alerts);
|
|
425
|
+
await handleUpdateConflicts(dataConflicts, translatedIds, alerts);
|
|
408
426
|
await handleUniqueConflicts(uniqueConflicts, translatedIds);
|
|
409
427
|
await handleTranslatedIds(uniqueConflicts, translatedIds);
|
|
410
428
|
await updateSyncInfos(offlineChanges, translatedIds, syncTimestamp);
|
|
@@ -481,16 +499,26 @@ const setSpinnerText = () => {
|
|
|
481
499
|
|
|
482
500
|
let syncInProgress = false;
|
|
483
501
|
|
|
484
|
-
export
|
|
502
|
+
export function isSyncInProgress() {
|
|
485
503
|
return syncInProgress;
|
|
486
504
|
}
|
|
487
505
|
|
|
488
|
-
|
|
506
|
+
/**
|
|
507
|
+
*
|
|
508
|
+
* @param {boolean} withWakelock try request a wakelock and show a spinner during sync (propably not in background mode)
|
|
509
|
+
* @param {boolean} switchOnline end the offline mode and go online again after sync
|
|
510
|
+
* @param {string[]} alerts output alerts collected during sync
|
|
511
|
+
*/
|
|
512
|
+
export async function sync(
|
|
513
|
+
withWakelock = true,
|
|
514
|
+
switchOnline = true,
|
|
515
|
+
alerts = []
|
|
516
|
+
) {
|
|
489
517
|
if (syncInProgress)
|
|
490
518
|
throw new Error("A synchronization is already in progress.");
|
|
491
|
-
|
|
519
|
+
syncInProgress = true;
|
|
492
520
|
try {
|
|
493
|
-
if (
|
|
521
|
+
if (withWakelock) setSpinnerText();
|
|
494
522
|
const state = saltcorn.data.state.getState();
|
|
495
523
|
const { user } = state.mobileConfig;
|
|
496
524
|
const { offlineUser, hasOfflineData, uploadStarted, uploadStartTime } =
|
|
@@ -509,7 +537,7 @@ export async function sync(background = false, alerts = []) {
|
|
|
509
537
|
const syncTimestamp = await getServerTime();
|
|
510
538
|
await setUploadStarted(true, syncTimestamp);
|
|
511
539
|
let lock = null;
|
|
512
|
-
if (
|
|
540
|
+
if (withWakelock) {
|
|
513
541
|
try {
|
|
514
542
|
if (window.navigator?.wakeLock?.request)
|
|
515
543
|
lock = await window.navigator.wakeLock.request();
|
|
@@ -529,7 +557,7 @@ export async function sync(background = false, alerts = []) {
|
|
|
529
557
|
syncDir = await syncOfflineData(synchedTables, syncTimestamp, alerts);
|
|
530
558
|
await syncRemoteData(syncInfos, syncTimestamp);
|
|
531
559
|
await setLocalSyncTimestamp(syncTimestamp);
|
|
532
|
-
if (
|
|
560
|
+
if (switchOnline) await endOfflineMode(true);
|
|
533
561
|
await setUploadStarted(false);
|
|
534
562
|
await saltcorn.data.db.query("COMMIT");
|
|
535
563
|
transactionOpen = false;
|
|
@@ -626,21 +654,50 @@ export async function clearLocalData(inTransaction) {
|
|
|
626
654
|
}
|
|
627
655
|
}
|
|
628
656
|
|
|
629
|
-
export function networkChangeCallback(status) {
|
|
657
|
+
export async function networkChangeCallback(status) {
|
|
630
658
|
console.log("Network status changed", status);
|
|
631
659
|
const mobileConfig = saltcorn.data.state.getState().mobileConfig;
|
|
632
660
|
if (status.connectionType !== "none" && mobileConfig.isOfflineMode) {
|
|
633
661
|
const iframeWindow = $("#content-iframe")[0].contentWindow;
|
|
634
|
-
if (
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
)
|
|
643
|
-
|
|
662
|
+
if (mobileConfig.syncOnReconnect) {
|
|
663
|
+
if (isSyncInProgress()) {
|
|
664
|
+
console.log("Sync already in progress, skipping automatic sync");
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
console.log("Network restored, starting automatic sync");
|
|
668
|
+
const toasts = [];
|
|
669
|
+
try {
|
|
670
|
+
await sync(false, true, toasts);
|
|
671
|
+
if (iframeWindow) {
|
|
672
|
+
clearAlerts();
|
|
673
|
+
showAlerts([
|
|
674
|
+
{
|
|
675
|
+
type: "info",
|
|
676
|
+
msg: "You are online again.",
|
|
677
|
+
},
|
|
678
|
+
]);
|
|
679
|
+
}
|
|
680
|
+
toasts.push({
|
|
681
|
+
type: "info",
|
|
682
|
+
msg: "Synchronized your offline data.",
|
|
683
|
+
});
|
|
684
|
+
} catch (error) {
|
|
685
|
+
console.log("Error during push sync:", error);
|
|
686
|
+
}
|
|
687
|
+
if (toasts.length > 0) showToasts(toasts);
|
|
688
|
+
} else {
|
|
689
|
+
const iframeWindow = $("#content-iframe")[0].contentWindow;
|
|
690
|
+
if (iframeWindow) {
|
|
691
|
+
clearToasts();
|
|
692
|
+
iframeWindow.notifyAlert(
|
|
693
|
+
`An internet connection is available, to end the offline mode click ${saltcorn.markup.a(
|
|
694
|
+
{
|
|
695
|
+
href: "javascript:execLink('/sync/sync_settings')",
|
|
696
|
+
},
|
|
697
|
+
"here"
|
|
698
|
+
)}`
|
|
699
|
+
);
|
|
700
|
+
}
|
|
644
701
|
}
|
|
645
702
|
}
|
|
646
703
|
mobileConfig.networkState = status.connectionType;
|
|
@@ -680,7 +737,7 @@ export async function deleteOfflineData(noFeedback) {
|
|
|
680
737
|
await clearLocalData(false);
|
|
681
738
|
await setHasOfflineData(false);
|
|
682
739
|
if (!noFeedback)
|
|
683
|
-
|
|
740
|
+
showToasts([
|
|
684
741
|
{
|
|
685
742
|
type: "info",
|
|
686
743
|
msg: "Deleted your offline data.",
|
|
@@ -700,8 +757,8 @@ export function addPushSyncHandler() {
|
|
|
700
757
|
console.log("Push sync received:", notification);
|
|
701
758
|
const alerts = [];
|
|
702
759
|
try {
|
|
703
|
-
await sync(
|
|
704
|
-
if (alerts.length > 0)
|
|
760
|
+
await sync(false, false, alerts);
|
|
761
|
+
if (alerts.length > 0) showToasts(alerts);
|
|
705
762
|
} catch (error) {
|
|
706
763
|
console.log("Error during push sync:", error);
|
|
707
764
|
}
|
package/src/init.js
CHANGED
|
@@ -472,7 +472,7 @@ export async function init(mobileConfig) {
|
|
|
472
472
|
}
|
|
473
473
|
} else if (offlineUser) {
|
|
474
474
|
if (offlineUser === mobileConfig.user.email) {
|
|
475
|
-
await sync(
|
|
475
|
+
await sync(true, true, alerts);
|
|
476
476
|
alerts.push({
|
|
477
477
|
type: "info",
|
|
478
478
|
msg: "Synchronized your offline data.",
|
|
@@ -483,7 +483,7 @@ export async function init(mobileConfig) {
|
|
|
483
483
|
msg: `'${offlineUser}' has not yet uploaded offline data.`,
|
|
484
484
|
});
|
|
485
485
|
} else {
|
|
486
|
-
await sync(
|
|
486
|
+
await sync(true, true, alerts);
|
|
487
487
|
alerts.push({
|
|
488
488
|
type: "info",
|
|
489
489
|
msg: "Synchronized your offline data.",
|
|
@@ -192,7 +192,7 @@ async function inline_local_submit(e, opts1) {
|
|
|
192
192
|
});
|
|
193
193
|
inline_submit_success(e, form, opts);
|
|
194
194
|
} catch (error) {
|
|
195
|
-
parent.saltcorn.mobileApp.common.
|
|
195
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
196
196
|
{
|
|
197
197
|
type: "error",
|
|
198
198
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -565,7 +565,7 @@ async function mobile_modal(url, opts = {}) {
|
|
|
565
565
|
// onOpen onClose initialize_page?
|
|
566
566
|
}
|
|
567
567
|
} catch (error) {
|
|
568
|
-
parent.saltcorn.mobileApp.common.
|
|
568
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
569
569
|
{
|
|
570
570
|
type: "error",
|
|
571
571
|
msg: error.message ? error.message : "An error occured.",
|
|
@@ -665,7 +665,7 @@ async function make_unique_field(
|
|
|
665
665
|
);
|
|
666
666
|
}
|
|
667
667
|
} catch (error) {
|
|
668
|
-
parent.saltcorn.mobileApp.common.
|
|
668
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
669
669
|
{
|
|
670
670
|
type: "error",
|
|
671
671
|
msg: "unable to 'make_unique_field'",
|
|
@@ -835,16 +835,13 @@ async function switchNetworkMode() {
|
|
|
835
835
|
parent.saltcorn.mobileApp.navigation.addRoute({
|
|
836
836
|
route: "get/sync/sync_settings",
|
|
837
837
|
});
|
|
838
|
-
parent.saltcorn.mobileApp.common.showAlerts(
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
false
|
|
846
|
-
);
|
|
847
|
-
parent.saltcorn.mobileApp.common.clearAlerts();
|
|
838
|
+
parent.saltcorn.mobileApp.common.showAlerts([
|
|
839
|
+
{
|
|
840
|
+
type: "info",
|
|
841
|
+
msg: parent.saltcorn.mobileApp.offlineMode.getOfflineMsg(),
|
|
842
|
+
},
|
|
843
|
+
]);
|
|
844
|
+
parent.saltcorn.mobileApp.common.clearToasts();
|
|
848
845
|
} else {
|
|
849
846
|
if (networkState === "none")
|
|
850
847
|
throw new Error("No internet connection is available.");
|
|
@@ -854,16 +851,16 @@ async function switchNetworkMode() {
|
|
|
854
851
|
parent.saltcorn.mobileApp.navigation.addRoute({
|
|
855
852
|
route: "get/sync/sync_settings",
|
|
856
853
|
});
|
|
857
|
-
parent.saltcorn.mobileApp.common.
|
|
854
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
858
855
|
{
|
|
859
856
|
type: "info",
|
|
860
857
|
msg: "You are online again.",
|
|
861
858
|
},
|
|
862
859
|
]);
|
|
863
|
-
parent.saltcorn.mobileApp.common.
|
|
860
|
+
parent.saltcorn.mobileApp.common.clearAlerts();
|
|
864
861
|
}
|
|
865
862
|
} catch (error) {
|
|
866
|
-
parent.saltcorn.mobileApp.common.
|
|
863
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
867
864
|
{
|
|
868
865
|
type: "error",
|
|
869
866
|
msg: `Unable to change the network mode: ${
|
|
@@ -883,7 +880,7 @@ async function callSync() {
|
|
|
883
880
|
try {
|
|
884
881
|
const mobileConfig = parent.saltcorn.data.state.getState().mobileConfig;
|
|
885
882
|
if (mobileConfig.networkState === "none") {
|
|
886
|
-
parent.saltcorn.mobileApp.common.
|
|
883
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
887
884
|
{
|
|
888
885
|
type: "error",
|
|
889
886
|
msg: "You don't have an internet connection.",
|
|
@@ -893,14 +890,14 @@ async function callSync() {
|
|
|
893
890
|
const wasOffline = mobileConfig.isOfflineMode;
|
|
894
891
|
showLoadSpinner();
|
|
895
892
|
const alerts = [];
|
|
896
|
-
await parent.saltcorn.mobileApp.offlineMode.sync(
|
|
897
|
-
parent.saltcorn.mobileApp.common.
|
|
893
|
+
await parent.saltcorn.mobileApp.offlineMode.sync(true, true, alerts);
|
|
894
|
+
parent.saltcorn.mobileApp.common.clearToasts();
|
|
898
895
|
if (!wasOffline) {
|
|
899
896
|
alerts.push({
|
|
900
897
|
type: "info",
|
|
901
898
|
msg: "Synchronized your offline data.",
|
|
902
899
|
});
|
|
903
|
-
parent.saltcorn.mobileApp.common.
|
|
900
|
+
parent.saltcorn.mobileApp.common.showToasts(alerts);
|
|
904
901
|
} else {
|
|
905
902
|
setNetworSwitcherOn();
|
|
906
903
|
parent.saltcorn.mobileApp.navigation.clearHistory();
|
|
@@ -912,8 +909,8 @@ async function callSync() {
|
|
|
912
909
|
type: "info",
|
|
913
910
|
msg: "Synchronized your offline data, you are online again.",
|
|
914
911
|
});
|
|
915
|
-
parent.saltcorn.mobileApp.common.
|
|
916
|
-
parent.saltcorn.mobileApp.common.
|
|
912
|
+
parent.saltcorn.mobileApp.common.showToasts(alerts);
|
|
913
|
+
parent.saltcorn.mobileApp.common.clearAlerts();
|
|
917
914
|
}
|
|
918
915
|
}
|
|
919
916
|
} catch (error) {
|
|
@@ -929,14 +926,14 @@ async function deleteOfflineDataClicked() {
|
|
|
929
926
|
await parent.saltcorn.mobileApp.offlineMode.getLastOfflineSession();
|
|
930
927
|
const { user } = parent.saltcorn.data.state.getState().mobileConfig;
|
|
931
928
|
if (!lastOfflineSession?.offlineUser) {
|
|
932
|
-
parent.saltcorn.mobileApp.common.
|
|
929
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
933
930
|
{
|
|
934
931
|
type: "error",
|
|
935
932
|
msg: "You don't have any offline data.",
|
|
936
933
|
},
|
|
937
934
|
]);
|
|
938
935
|
} else if (lastOfflineSession.offlineUser !== user.email) {
|
|
939
|
-
parent.saltcorn.mobileApp.common.
|
|
936
|
+
parent.saltcorn.mobileApp.common.showToasts([
|
|
940
937
|
{
|
|
941
938
|
type: "error",
|
|
942
939
|
msg: `The offline data is owned by '${lastOfflineSession.offlineUser}'.`,
|