@saltcorn/mobile-app 1.1.0-beta.9 → 1.1.1-beta.0
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 +21 -0
- package/package.json +21 -12
- package/src/.eslintrc +21 -0
- package/src/helpers/api.js +43 -0
- package/src/helpers/auth.js +191 -0
- package/src/helpers/common.js +189 -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} +189 -332
- 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 +15 -10
- package/{www/js → src/routing}/routes/sync.js +17 -8
- package/{www/js → src/routing}/routes/view.js +20 -15
- package/{www/js/routes/common.js → src/routing/utils.js} +18 -13
- package/unsecure-default-key.jks +0 -0
- package/webpack.config.js +31 -0
- package/www/data/encoded_site_logo.js +1 -0
- package/www/index.html +23 -493
- package/www/js/{utils/iframe_view_utils.js → iframe_view_utils.js} +193 -274
- 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,13 +1,16 @@
|
|
|
1
|
-
/*global
|
|
1
|
+
/*global saltcorn */
|
|
2
2
|
|
|
3
3
|
const historyFile = "update_history";
|
|
4
4
|
const jwtTableName = "jwt_table";
|
|
5
5
|
|
|
6
|
+
import { readFile, fileExists, writeJSON } from "./file_system";
|
|
7
|
+
import { Directory } from "@capacitor/filesystem";
|
|
8
|
+
|
|
6
9
|
/**
|
|
7
10
|
* drop tables that are no longer in the 'tables.json' file
|
|
8
11
|
* the server db uses a serial (with postgres), so checking ids should suffice
|
|
9
12
|
*/
|
|
10
|
-
async function dropDeletedTables(incomingTables) {
|
|
13
|
+
export async function dropDeletedTables(incomingTables) {
|
|
11
14
|
const existingTables = await saltcorn.data.models.Table.find();
|
|
12
15
|
for (const table of existingTables) {
|
|
13
16
|
if (
|
|
@@ -27,7 +30,7 @@ async function dropDeletedTables(incomingTables) {
|
|
|
27
30
|
* @param {*} rows
|
|
28
31
|
* @returns
|
|
29
32
|
*/
|
|
30
|
-
async function safeRows(table, rows) {
|
|
33
|
+
export async function safeRows(table, rows) {
|
|
31
34
|
const existingFields = (
|
|
32
35
|
await saltcorn.data.db.query(
|
|
33
36
|
`PRAGMA table_info('${saltcorn.data.db.sqlsanitize(table)}')`
|
|
@@ -45,7 +48,7 @@ async function safeRows(table, rows) {
|
|
|
45
48
|
});
|
|
46
49
|
}
|
|
47
50
|
|
|
48
|
-
async function updateScTables(tablesJSON, skipScPlugins = true) {
|
|
51
|
+
export async function updateScTables(tablesJSON, skipScPlugins = true) {
|
|
49
52
|
await saltcorn.data.db.query("PRAGMA foreign_keys = OFF;");
|
|
50
53
|
for (const { table, rows } of tablesJSON.sc_tables) {
|
|
51
54
|
if (skipScPlugins && table === "_sc_plugins") continue;
|
|
@@ -56,7 +59,7 @@ async function updateScTables(tablesJSON, skipScPlugins = true) {
|
|
|
56
59
|
await saltcorn.data.db.query("PRAGMA foreign_keys = ON;");
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
async function updateScPlugins(tablesJSON) {
|
|
62
|
+
export async function updateScPlugins(tablesJSON) {
|
|
60
63
|
const { table, rows } = tablesJSON.sc_tables.find(
|
|
61
64
|
({ table }) => table === "_sc_plugins"
|
|
62
65
|
);
|
|
@@ -66,7 +69,7 @@ async function updateScPlugins(tablesJSON) {
|
|
|
66
69
|
}
|
|
67
70
|
}
|
|
68
71
|
|
|
69
|
-
async function updateUserDefinedTables() {
|
|
72
|
+
export async function updateUserDefinedTables() {
|
|
70
73
|
const existingTables = await saltcorn.data.db.listUserDefinedTables();
|
|
71
74
|
const tables = await saltcorn.data.models.Table.find();
|
|
72
75
|
for (const table of tables) {
|
|
@@ -92,7 +95,7 @@ async function updateUserDefinedTables() {
|
|
|
92
95
|
}
|
|
93
96
|
}
|
|
94
97
|
|
|
95
|
-
async function createSyncInfoTables(synchTbls) {
|
|
98
|
+
export async function createSyncInfoTables(synchTbls) {
|
|
96
99
|
const infoTbls = (await saltcorn.data.db.listTables()).filter(({ name }) => {
|
|
97
100
|
name.endsWith("_sync_info");
|
|
98
101
|
});
|
|
@@ -139,11 +142,8 @@ async function createSyncInfoTables(synchTbls) {
|
|
|
139
142
|
}
|
|
140
143
|
}
|
|
141
144
|
|
|
142
|
-
async function tablesUptodate(createdAt, historyFile) {
|
|
143
|
-
const { updated_at } = await
|
|
144
|
-
historyFile,
|
|
145
|
-
cordova.file.dataDirectory
|
|
146
|
-
);
|
|
145
|
+
export async function tablesUptodate(createdAt, historyFile) {
|
|
146
|
+
const { updated_at } = await readFile(historyFile, Directory.Data);
|
|
147
147
|
if (!updated_at) {
|
|
148
148
|
console.log("No updated_at in history file");
|
|
149
149
|
return false;
|
|
@@ -155,52 +155,30 @@ async function tablesUptodate(createdAt, historyFile) {
|
|
|
155
155
|
* Do a table update when the history file doesn't exist or is older than createdAt
|
|
156
156
|
* @param {number} createdAt UTC Date number when the tables.json file was created on the server
|
|
157
157
|
*/
|
|
158
|
-
async function dbUpdateNeeded(createdAt) {
|
|
158
|
+
export async function dbUpdateNeeded(createdAt) {
|
|
159
159
|
return (
|
|
160
|
-
!(await fileExists(
|
|
160
|
+
!(await fileExists(historyFile, Directory.Data)) ||
|
|
161
161
|
!(await tablesUptodate(createdAt, historyFile))
|
|
162
162
|
);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
async function updateDb(tablesJSON) {
|
|
165
|
+
export async function updateDb(tablesJSON) {
|
|
166
166
|
await updateScTables(tablesJSON);
|
|
167
167
|
await saltcorn.data.state.getState().refresh_tables();
|
|
168
168
|
await updateUserDefinedTables();
|
|
169
|
-
await writeJSON(historyFile,
|
|
169
|
+
await writeJSON(historyFile, Directory.Data, {
|
|
170
170
|
updated_at: new Date().valueOf(),
|
|
171
171
|
});
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
async function getTableIds(tableNames) {
|
|
174
|
+
export async function getTableIds(tableNames) {
|
|
175
175
|
return (await saltcorn.data.models.Table.find())
|
|
176
176
|
.filter((table) => tableNames.indexOf(table.name) > -1)
|
|
177
177
|
.map((table) => table.id);
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
async function createJwtTable() {
|
|
180
|
+
export async function createJwtTable() {
|
|
181
181
|
await saltcorn.data.db.query(`CREATE TABLE IF NOT EXISTS ${jwtTableName} (
|
|
182
182
|
jwt VARCHAR(500)
|
|
183
183
|
)`);
|
|
184
184
|
}
|
|
185
|
-
|
|
186
|
-
async function getJwt() {
|
|
187
|
-
const rows = await saltcorn.data.db.select(jwtTableName);
|
|
188
|
-
return rows?.length > 0 ? rows[0].jwt : null;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async function removeJwt() {
|
|
192
|
-
await saltcorn.data.db.deleteWhere(jwtTableName);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async function setJwt(jwt) {
|
|
196
|
-
await removeJwt();
|
|
197
|
-
await saltcorn.data.db.insert(jwtTableName, { jwt: jwt });
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async function insertUser({ id, email, role_id, language }) {
|
|
201
|
-
await saltcorn.data.db.insert(
|
|
202
|
-
"users",
|
|
203
|
-
{ id, email, role_id, language },
|
|
204
|
-
{ ignoreExisting: true }
|
|
205
|
-
);
|
|
206
|
-
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { Filesystem, Encoding, Directory } from "@capacitor/filesystem";
|
|
2
|
+
|
|
3
|
+
export async function writeFile(name, directory, content) {
|
|
4
|
+
try {
|
|
5
|
+
await Filesystem.writeFile({
|
|
6
|
+
path: name,
|
|
7
|
+
data: content,
|
|
8
|
+
directory: directory,
|
|
9
|
+
encoding: Encoding.UTF8,
|
|
10
|
+
});
|
|
11
|
+
} catch (error) {
|
|
12
|
+
console.log("Unable to write file", error);
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function readFile(name, directory) {
|
|
18
|
+
try {
|
|
19
|
+
const contents = await Filesystem.readFile({
|
|
20
|
+
path: name,
|
|
21
|
+
directory: directory,
|
|
22
|
+
encoding: Encoding.UTF8,
|
|
23
|
+
});
|
|
24
|
+
return contents.data;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.log("Unable to read file", error);
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function fileExists(name, directory) {
|
|
32
|
+
try {
|
|
33
|
+
await Filesystem.stat({ path: name, directory: directory });
|
|
34
|
+
return true;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function writeJSON(name, directory, json) {
|
|
41
|
+
const contents = JSON.stringify(json);
|
|
42
|
+
await writeFile(name, directory, contents);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getDirEntryCordova(directory) {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
window.resolveLocalFileSystemURL(
|
|
48
|
+
directory,
|
|
49
|
+
function (fs) {
|
|
50
|
+
resolve(fs);
|
|
51
|
+
},
|
|
52
|
+
function (error) {
|
|
53
|
+
reject(error);
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function readBinaryCordova(fileName, dirName) {
|
|
60
|
+
const dirEntry = await getDirEntryCordova(dirName);
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
dirEntry.getFile(
|
|
63
|
+
fileName,
|
|
64
|
+
{ create: false, exclusive: false },
|
|
65
|
+
function (fileEntry) {
|
|
66
|
+
fileEntry.file(function (file) {
|
|
67
|
+
let reader = new FileReader();
|
|
68
|
+
reader.onloadend = function (e) {
|
|
69
|
+
resolve({ buffer: this.result, file: file });
|
|
70
|
+
};
|
|
71
|
+
reader.readAsArrayBuffer(file);
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
function (err) {
|
|
75
|
+
console.log(`unable to read ${fileName}`);
|
|
76
|
+
console.log(err);
|
|
77
|
+
reject(err);
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// TODO get this working
|
|
84
|
+
// export function normalizeFilePath(filePath) {
|
|
85
|
+
// if (filePath.startsWith("file:///")) {
|
|
86
|
+
// return filePath.replace("file:///storage/emulated/0/", "");
|
|
87
|
+
// }
|
|
88
|
+
// return filePath;
|
|
89
|
+
// }
|
|
90
|
+
|
|
91
|
+
// export async function readBinary(name, directory) {
|
|
92
|
+
// try {
|
|
93
|
+
// const file = await Filesystem.readFile({
|
|
94
|
+
// path: normalizeFilePath(`${directory}/${name}`),
|
|
95
|
+
// directory: Directory.ExternalStorage,
|
|
96
|
+
// });
|
|
97
|
+
// return Uint8Array.from(file.data, (char) => char.charCodeAt(0));
|
|
98
|
+
// } catch (error) {
|
|
99
|
+
// console.log("Unable to read file", error);
|
|
100
|
+
// throw error;
|
|
101
|
+
// }
|
|
102
|
+
// }
|