@etsoo/appscript 1.5.67 → 1.5.69
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/__tests__/app/CoreApp.ts +12 -0
- package/lib/cjs/app/CoreApp.d.ts +15 -15
- package/lib/cjs/app/CoreApp.js +97 -109
- package/lib/cjs/app/ExternalSettings.d.ts +1 -1
- package/lib/cjs/app/ExternalSettings.js +8 -8
- package/lib/cjs/app/IApp.d.ts +12 -12
- package/lib/cjs/app/IApp.js +8 -8
- package/lib/cjs/bridges/BridgeUtils.d.ts +2 -2
- package/lib/cjs/bridges/BridgeUtils.js +2 -2
- package/lib/cjs/i18n/en.json +1 -0
- package/lib/cjs/i18n/zh-Hans.json +1 -0
- package/lib/cjs/i18n/zh-Hant.json +1 -0
- package/lib/mjs/app/CoreApp.d.ts +15 -15
- package/lib/mjs/app/CoreApp.js +108 -120
- package/lib/mjs/app/ExternalSettings.d.ts +1 -1
- package/lib/mjs/app/ExternalSettings.js +8 -8
- package/lib/mjs/app/IApp.d.ts +12 -12
- package/lib/mjs/app/IApp.js +8 -8
- package/lib/mjs/bridges/BridgeUtils.d.ts +2 -2
- package/lib/mjs/bridges/BridgeUtils.js +3 -3
- package/lib/mjs/i18n/en.json +1 -0
- package/lib/mjs/i18n/zh-Hans.json +1 -0
- package/lib/mjs/i18n/zh-Hant.json +1 -0
- package/package.json +4 -4
- package/src/app/CoreApp.ts +2246 -2303
- package/src/app/ExternalSettings.ts +61 -61
- package/src/app/IApp.ts +760 -766
- package/src/bridges/BridgeUtils.ts +12 -12
- package/src/i18n/en.json +1 -0
- package/src/i18n/zh-Hans.json +1 -0
- package/src/i18n/zh-Hant.json +1 -0
package/lib/cjs/app/CoreApp.js
CHANGED
|
@@ -13,9 +13,9 @@ const IApp_1 = require("./IApp");
|
|
|
13
13
|
const UserRole_1 = require("./UserRole");
|
|
14
14
|
const AuthApi_1 = require("../api/AuthApi");
|
|
15
15
|
let CJ;
|
|
16
|
-
const loadCrypto = () => import(
|
|
16
|
+
const loadCrypto = () => import("crypto-js");
|
|
17
17
|
// System API name
|
|
18
|
-
const systemApi =
|
|
18
|
+
const systemApi = "system";
|
|
19
19
|
/**
|
|
20
20
|
* Core application
|
|
21
21
|
*/
|
|
@@ -168,20 +168,20 @@ class CoreApp {
|
|
|
168
168
|
/**
|
|
169
169
|
* Init call Api URL
|
|
170
170
|
*/
|
|
171
|
-
this.initCallApi =
|
|
171
|
+
this.initCallApi = "Auth/WebInitCall";
|
|
172
172
|
/**
|
|
173
173
|
* Passphrase for encryption
|
|
174
174
|
*/
|
|
175
|
-
this.passphrase =
|
|
175
|
+
this.passphrase = "";
|
|
176
176
|
this.apis = {};
|
|
177
177
|
this.tasks = [];
|
|
178
178
|
if (settings?.regions?.length === 0) {
|
|
179
|
-
throw new Error(
|
|
179
|
+
throw new Error("No regions defined");
|
|
180
180
|
}
|
|
181
181
|
this.settings = settings;
|
|
182
182
|
const region = AddressRegion_1.AddressRegion.getById(settings.regions[0]);
|
|
183
183
|
if (region == null) {
|
|
184
|
-
throw new Error(
|
|
184
|
+
throw new Error("No default region defined");
|
|
185
185
|
}
|
|
186
186
|
this.defaultRegion = region;
|
|
187
187
|
// Current system refresh token
|
|
@@ -218,9 +218,9 @@ class CoreApp {
|
|
|
218
218
|
this.name = name;
|
|
219
219
|
this.debug = debug;
|
|
220
220
|
// Fields, attach with the name identifier
|
|
221
|
-
this.fields = IApp_1.appFields.reduce((a, v) => ({ ...a, [v]:
|
|
221
|
+
this.fields = IApp_1.appFields.reduce((a, v) => ({ ...a, [v]: "smarterp-" + v + "-" + name }), {});
|
|
222
222
|
// Device id
|
|
223
|
-
this._deviceId = storage.getData(this.fields.deviceId,
|
|
223
|
+
this._deviceId = storage.getData(this.fields.deviceId, "");
|
|
224
224
|
// Embedded
|
|
225
225
|
this._embedded =
|
|
226
226
|
this.storage.getData(this.fields.embedded) ?? false;
|
|
@@ -230,7 +230,7 @@ class CoreApp {
|
|
|
230
230
|
CJ = cj.default;
|
|
231
231
|
// Debug
|
|
232
232
|
if (this.debug) {
|
|
233
|
-
console.debug(
|
|
233
|
+
console.debug("CoreApp.constructor.ready", this._deviceId, this.fields, cj, currentCulture, currentRegion);
|
|
234
234
|
}
|
|
235
235
|
this.changeRegion(currentRegion);
|
|
236
236
|
this.setup();
|
|
@@ -245,7 +245,7 @@ class CoreApp {
|
|
|
245
245
|
this.fields.headerToken,
|
|
246
246
|
this.fields.serversideDeviceId
|
|
247
247
|
], false);
|
|
248
|
-
this.passphrase =
|
|
248
|
+
this.passphrase = "";
|
|
249
249
|
}
|
|
250
250
|
/**
|
|
251
251
|
* Add app name as identifier
|
|
@@ -253,7 +253,7 @@ class CoreApp {
|
|
|
253
253
|
* @returns Result
|
|
254
254
|
*/
|
|
255
255
|
addIdentifier(field) {
|
|
256
|
-
return field +
|
|
256
|
+
return field + "-" + this.name;
|
|
257
257
|
}
|
|
258
258
|
/**
|
|
259
259
|
* Add root (homepage) to the URL
|
|
@@ -262,13 +262,13 @@ class CoreApp {
|
|
|
262
262
|
*/
|
|
263
263
|
addRootUrl(url) {
|
|
264
264
|
const page = this.settings.homepage;
|
|
265
|
-
const endSlash = page.endsWith(
|
|
265
|
+
const endSlash = page.endsWith("/");
|
|
266
266
|
return (page +
|
|
267
267
|
(endSlash
|
|
268
|
-
? shared_1.Utils.trimStart(url,
|
|
269
|
-
: url.startsWith(
|
|
268
|
+
? shared_1.Utils.trimStart(url, "/")
|
|
269
|
+
: url.startsWith("/")
|
|
270
270
|
? url
|
|
271
|
-
:
|
|
271
|
+
: "/" + url));
|
|
272
272
|
}
|
|
273
273
|
/**
|
|
274
274
|
* Create Auth API
|
|
@@ -284,13 +284,13 @@ class CoreApp {
|
|
|
284
284
|
async restore() {
|
|
285
285
|
// Devices
|
|
286
286
|
const devices = this.storage.getPersistedData(this.fields.devices, []);
|
|
287
|
-
if (this._deviceId ===
|
|
287
|
+
if (this._deviceId === "") {
|
|
288
288
|
// First vist, restore and keep the source
|
|
289
289
|
this.storage.copyFrom(this.persistedFields, false);
|
|
290
290
|
// Reset device id
|
|
291
|
-
this._deviceId = this.storage.getData(this.fields.deviceId,
|
|
291
|
+
this._deviceId = this.storage.getData(this.fields.deviceId, "");
|
|
292
292
|
// Totally new, no data restored
|
|
293
|
-
if (this._deviceId ===
|
|
293
|
+
if (this._deviceId === "")
|
|
294
294
|
return false;
|
|
295
295
|
}
|
|
296
296
|
// Device exists or not
|
|
@@ -394,7 +394,7 @@ class CoreApp {
|
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
updateApi(nameOrData, token, seconds) {
|
|
397
|
-
const api = typeof nameOrData ===
|
|
397
|
+
const api = typeof nameOrData === "string" ? this.apis[nameOrData] : nameOrData;
|
|
398
398
|
if (api == null)
|
|
399
399
|
return;
|
|
400
400
|
// Consider the API call delay
|
|
@@ -439,7 +439,7 @@ class CoreApp {
|
|
|
439
439
|
// Unauthorized
|
|
440
440
|
if (handlerFor401 === false)
|
|
441
441
|
return;
|
|
442
|
-
if (typeof handlerFor401 ===
|
|
442
|
+
if (typeof handlerFor401 === "function") {
|
|
443
443
|
handlerFor401();
|
|
444
444
|
}
|
|
445
445
|
else {
|
|
@@ -448,10 +448,10 @@ class CoreApp {
|
|
|
448
448
|
return;
|
|
449
449
|
}
|
|
450
450
|
else if (error.response == null &&
|
|
451
|
-
(error.message ===
|
|
452
|
-
error.message ===
|
|
451
|
+
(error.message === "Network Error" ||
|
|
452
|
+
error.message === "Failed to fetch")) {
|
|
453
453
|
// Network error
|
|
454
|
-
this.notifier.alert(this.get(
|
|
454
|
+
this.notifier.alert(this.get("networkError") + ` [${this.name}]`);
|
|
455
455
|
return;
|
|
456
456
|
}
|
|
457
457
|
else {
|
|
@@ -500,10 +500,10 @@ class CoreApp {
|
|
|
500
500
|
*/
|
|
501
501
|
setupLogging(action, preventDefault) {
|
|
502
502
|
action ?? (action = (data) => {
|
|
503
|
-
this.api.post(
|
|
503
|
+
this.api.post("Auth/LogFrontendError", data, {
|
|
504
504
|
onError: (error) => {
|
|
505
505
|
// Use 'debug' to avoid infinite loop
|
|
506
|
-
console.debug(
|
|
506
|
+
console.debug("Log front-end error", data, error);
|
|
507
507
|
// Prevent global error handler
|
|
508
508
|
return false;
|
|
509
509
|
}
|
|
@@ -525,8 +525,8 @@ class CoreApp {
|
|
|
525
525
|
* @returns true means device is invalid
|
|
526
526
|
*/
|
|
527
527
|
checkDeviceResult(result) {
|
|
528
|
-
if (result.type ===
|
|
529
|
-
(result.type ===
|
|
528
|
+
if (result.type === "DataProcessingFailed" ||
|
|
529
|
+
(result.type === "NoValidData" && result.field === "Device"))
|
|
530
530
|
return true;
|
|
531
531
|
return false;
|
|
532
532
|
}
|
|
@@ -534,7 +534,7 @@ class CoreApp {
|
|
|
534
534
|
* Clear device id
|
|
535
535
|
*/
|
|
536
536
|
clearDeviceId() {
|
|
537
|
-
this._deviceId =
|
|
537
|
+
this._deviceId = "";
|
|
538
538
|
this.storage.clear([this.fields.deviceId], false);
|
|
539
539
|
this.storage.clear([this.fields.deviceId], true);
|
|
540
540
|
}
|
|
@@ -575,7 +575,7 @@ class CoreApp {
|
|
|
575
575
|
}
|
|
576
576
|
if (result.data == null) {
|
|
577
577
|
// Popup no data error
|
|
578
|
-
this.notifier.alert(this.get(
|
|
578
|
+
this.notifier.alert(this.get("noData"));
|
|
579
579
|
if (callback)
|
|
580
580
|
callback(false);
|
|
581
581
|
return;
|
|
@@ -583,10 +583,10 @@ class CoreApp {
|
|
|
583
583
|
if (!result.ok) {
|
|
584
584
|
const seconds = result.data.seconds;
|
|
585
585
|
const validSeconds = result.data.validSeconds;
|
|
586
|
-
if (result.title ===
|
|
586
|
+
if (result.title === "timeDifferenceInvalid" &&
|
|
587
587
|
seconds != null &&
|
|
588
588
|
validSeconds != null) {
|
|
589
|
-
const title = this.get(
|
|
589
|
+
const title = this.get("timeDifferenceInvalid")?.format(seconds.toString(), validSeconds.toString());
|
|
590
590
|
this.notifier.alert(title);
|
|
591
591
|
}
|
|
592
592
|
else {
|
|
@@ -600,7 +600,7 @@ class CoreApp {
|
|
|
600
600
|
}
|
|
601
601
|
const updateResult = await this.initCallUpdate(result.data, data.timestamp);
|
|
602
602
|
if (!updateResult) {
|
|
603
|
-
this.notifier.alert(this.get(
|
|
603
|
+
this.notifier.alert(this.get("noData") + "(Update)");
|
|
604
604
|
}
|
|
605
605
|
if (callback)
|
|
606
606
|
callback(updateResult);
|
|
@@ -619,14 +619,14 @@ class CoreApp {
|
|
|
619
619
|
const fields = this.initCallEncryptedUpdateFields();
|
|
620
620
|
for (const field of fields) {
|
|
621
621
|
const currentValue = this.storage.getData(field);
|
|
622
|
-
if (currentValue == null || currentValue ===
|
|
622
|
+
if (currentValue == null || currentValue === "")
|
|
623
623
|
continue;
|
|
624
624
|
if (prev == null) {
|
|
625
625
|
// Reset the field
|
|
626
626
|
this.storage.setData(field, undefined);
|
|
627
627
|
continue;
|
|
628
628
|
}
|
|
629
|
-
const enhanced = currentValue.indexOf(
|
|
629
|
+
const enhanced = currentValue.indexOf("!") >= 8;
|
|
630
630
|
let newValueSource;
|
|
631
631
|
if (enhanced) {
|
|
632
632
|
newValueSource = this.decryptEnhanced(currentValue, prev, 12);
|
|
@@ -634,7 +634,7 @@ class CoreApp {
|
|
|
634
634
|
else {
|
|
635
635
|
newValueSource = this.decrypt(currentValue, prev);
|
|
636
636
|
}
|
|
637
|
-
if (newValueSource == null || newValueSource ===
|
|
637
|
+
if (newValueSource == null || newValueSource === "") {
|
|
638
638
|
// Reset the field
|
|
639
639
|
this.storage.setData(field, undefined);
|
|
640
640
|
continue;
|
|
@@ -669,7 +669,7 @@ class CoreApp {
|
|
|
669
669
|
// Previous passphrase
|
|
670
670
|
if (data.previousPassphrase) {
|
|
671
671
|
const prev = this.decrypt(data.previousPassphrase, timestamp.toString());
|
|
672
|
-
this.passphrase = prev ??
|
|
672
|
+
this.passphrase = prev ?? "";
|
|
673
673
|
}
|
|
674
674
|
// Update passphrase
|
|
675
675
|
this.updatePassphrase(passphrase);
|
|
@@ -683,7 +683,7 @@ class CoreApp {
|
|
|
683
683
|
return [this.fields.headerToken];
|
|
684
684
|
}
|
|
685
685
|
alertResult(result, callback, forceToLocal) {
|
|
686
|
-
const message = typeof result ===
|
|
686
|
+
const message = typeof result === "string"
|
|
687
687
|
? result
|
|
688
688
|
: this.formatResult(result, forceToLocal);
|
|
689
689
|
this.notifier.alert(message, callback);
|
|
@@ -698,10 +698,10 @@ class CoreApp {
|
|
|
698
698
|
// State, when token is null, means logout
|
|
699
699
|
const authorized = token != null;
|
|
700
700
|
// Token
|
|
701
|
-
schema ?? (schema =
|
|
701
|
+
schema ?? (schema = "Bearer");
|
|
702
702
|
this.api.authorize(schema, token);
|
|
703
703
|
// Overwrite the current value
|
|
704
|
-
if (refreshToken !==
|
|
704
|
+
if (refreshToken !== "") {
|
|
705
705
|
if (refreshToken != null)
|
|
706
706
|
refreshToken = this.encrypt(refreshToken);
|
|
707
707
|
this.storage.setData(this.fields.headerToken, refreshToken);
|
|
@@ -740,7 +740,7 @@ class CoreApp {
|
|
|
740
740
|
// Get data
|
|
741
741
|
let regionId;
|
|
742
742
|
let regionItem;
|
|
743
|
-
if (typeof region ===
|
|
743
|
+
if (typeof region === "string") {
|
|
744
744
|
regionId = region;
|
|
745
745
|
regionItem = AddressRegion_1.AddressRegion.getById(region);
|
|
746
746
|
}
|
|
@@ -773,7 +773,7 @@ class CoreApp {
|
|
|
773
773
|
const { name } = culture;
|
|
774
774
|
// Same?
|
|
775
775
|
let resources = culture.resources;
|
|
776
|
-
if (this._culture === name && typeof resources ===
|
|
776
|
+
if (this._culture === name && typeof resources === "object")
|
|
777
777
|
return resources;
|
|
778
778
|
// Save the cultrue to local storage
|
|
779
779
|
this.storage.setPersistedData(shared_1.DomUtils.CultureField, name);
|
|
@@ -784,7 +784,7 @@ class CoreApp {
|
|
|
784
784
|
this._culture = name;
|
|
785
785
|
// Hold the current resources
|
|
786
786
|
this.settings.currentCulture = culture;
|
|
787
|
-
if (typeof resources !==
|
|
787
|
+
if (typeof resources !== "object") {
|
|
788
788
|
resources = await resources();
|
|
789
789
|
// Set static resources back
|
|
790
790
|
culture.resources = resources;
|
|
@@ -867,7 +867,7 @@ class CoreApp {
|
|
|
867
867
|
*/
|
|
868
868
|
decryptEnhanced(messageEncrypted, passphrase, durationSeconds) {
|
|
869
869
|
// Timestamp splitter
|
|
870
|
-
const pos = messageEncrypted.indexOf(
|
|
870
|
+
const pos = messageEncrypted.indexOf("!");
|
|
871
871
|
// Miliseconds chars are longer than 8
|
|
872
872
|
if (pos < 8 || messageEncrypted.length <= 66)
|
|
873
873
|
return undefined;
|
|
@@ -878,10 +878,8 @@ class CoreApp {
|
|
|
878
878
|
if (isNaN(milseconds) || milseconds < 1)
|
|
879
879
|
return undefined;
|
|
880
880
|
const timespan = new Date().substract(new Date(milseconds));
|
|
881
|
-
if ((durationSeconds <= 12 &&
|
|
882
|
-
timespan.
|
|
883
|
-
(durationSeconds > 12 &&
|
|
884
|
-
timespan.totalSeconds > durationSeconds))
|
|
881
|
+
if ((durationSeconds <= 12 && timespan.totalMonths > durationSeconds) ||
|
|
882
|
+
(durationSeconds > 12 && timespan.totalSeconds > durationSeconds))
|
|
885
883
|
return undefined;
|
|
886
884
|
}
|
|
887
885
|
const message = messageEncrypted.substring(pos + 1);
|
|
@@ -941,12 +939,12 @@ class CoreApp {
|
|
|
941
939
|
callback(success);
|
|
942
940
|
}
|
|
943
941
|
else if (success)
|
|
944
|
-
this.notifier.message(notificationbase_1.NotificationMessageType.Success, this.get(
|
|
942
|
+
this.notifier.message(notificationbase_1.NotificationMessageType.Success, this.get("fileDownloaded"));
|
|
945
943
|
};
|
|
946
944
|
// https://developer.mozilla.org/en-US/docs/Web/API/UserActivation/isActive
|
|
947
|
-
if (
|
|
945
|
+
if ("userActivation" in navigator &&
|
|
948
946
|
!navigator.userActivation.isActive) {
|
|
949
|
-
this.notifier.alert(this.get(
|
|
947
|
+
this.notifier.alert(this.get("reactivateTip"), async () => {
|
|
950
948
|
await downloadFile();
|
|
951
949
|
});
|
|
952
950
|
}
|
|
@@ -973,7 +971,7 @@ class CoreApp {
|
|
|
973
971
|
iterations: 1000 * iterations
|
|
974
972
|
});
|
|
975
973
|
const iv = lib.WordArray.random(bits);
|
|
976
|
-
return (iterations.toString().padStart(2,
|
|
974
|
+
return (iterations.toString().padStart(2, "0") +
|
|
977
975
|
salt.toString(enc.Hex) +
|
|
978
976
|
iv.toString(enc.Hex) +
|
|
979
977
|
AES.encrypt(message, key, {
|
|
@@ -995,7 +993,7 @@ class CoreApp {
|
|
|
995
993
|
const timestamp = shared_1.Utils.numberToChars(new Date().getTime());
|
|
996
994
|
passphrase = this.encryptionEnhance(passphrase ?? this.passphrase, timestamp);
|
|
997
995
|
const result = this.encrypt(message, passphrase, iterations);
|
|
998
|
-
return timestamp +
|
|
996
|
+
return timestamp + "!" + result;
|
|
999
997
|
}
|
|
1000
998
|
/**
|
|
1001
999
|
* Enchance secret passphrase
|
|
@@ -1016,8 +1014,8 @@ class CoreApp {
|
|
|
1016
1014
|
* @returns Result
|
|
1017
1015
|
*/
|
|
1018
1016
|
formatAction(action, target, ...items) {
|
|
1019
|
-
let more = items.join(
|
|
1020
|
-
return `[${this.get(
|
|
1017
|
+
let more = items.join(", ");
|
|
1018
|
+
return `[${this.get("appName")}] ${action} - ${target}${more ? `, ${more}` : more}`;
|
|
1021
1019
|
}
|
|
1022
1020
|
/**
|
|
1023
1021
|
* Format date to string
|
|
@@ -1065,10 +1063,10 @@ class CoreApp {
|
|
|
1065
1063
|
*/
|
|
1066
1064
|
formatFullName(familyName, givenName) {
|
|
1067
1065
|
if (!familyName)
|
|
1068
|
-
return givenName ??
|
|
1066
|
+
return givenName ?? "";
|
|
1069
1067
|
if (!givenName)
|
|
1070
|
-
return familyName ??
|
|
1071
|
-
const wf = givenName +
|
|
1068
|
+
return familyName ?? "";
|
|
1069
|
+
const wf = givenName + " " + familyName;
|
|
1072
1070
|
if (wf.containChinese() || wf.containJapanese() || wf.containKorean()) {
|
|
1073
1071
|
return familyName + givenName;
|
|
1074
1072
|
}
|
|
@@ -1086,18 +1084,16 @@ class CoreApp {
|
|
|
1086
1084
|
// Destruct the result
|
|
1087
1085
|
const { title, type, field } = result;
|
|
1088
1086
|
const data = { title, type, field };
|
|
1089
|
-
if (type ===
|
|
1087
|
+
if (type === "ItemExists" && field) {
|
|
1090
1088
|
// Special case
|
|
1091
|
-
const fieldLabel = (typeof forceToLocal ===
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
result.title = this.get('itemExists')?.format(fieldLabel);
|
|
1089
|
+
const fieldLabel = (typeof forceToLocal === "function" ? forceToLocal(data) : undefined) ??
|
|
1090
|
+
this.getFieldLabel(field);
|
|
1091
|
+
result.title = this.get("itemExists")?.format(fieldLabel);
|
|
1095
1092
|
}
|
|
1096
|
-
else if (title?.includes(
|
|
1093
|
+
else if (title?.includes("{0}")) {
|
|
1097
1094
|
// When title contains {0}, replace with the field label
|
|
1098
|
-
const fieldLabel = (typeof forceToLocal ===
|
|
1099
|
-
?
|
|
1100
|
-
: undefined) ?? (field ? this.getFieldLabel(field) : '');
|
|
1095
|
+
const fieldLabel = (typeof forceToLocal === "function" ? forceToLocal(data) : undefined) ??
|
|
1096
|
+
(field ? this.getFieldLabel(field) : "");
|
|
1101
1097
|
result.title = title.format(fieldLabel);
|
|
1102
1098
|
}
|
|
1103
1099
|
else if (title && /^\w+$/.test(title)) {
|
|
@@ -1105,15 +1101,13 @@ class CoreApp {
|
|
|
1105
1101
|
// Hold the original title in type when type is null
|
|
1106
1102
|
if (type == null)
|
|
1107
1103
|
result.type = title;
|
|
1108
|
-
const localTitle = (typeof forceToLocal ===
|
|
1109
|
-
|
|
1110
|
-
: undefined) ?? this.getFieldLabel(title);
|
|
1104
|
+
const localTitle = (typeof forceToLocal === "function" ? forceToLocal(data) : undefined) ??
|
|
1105
|
+
this.getFieldLabel(title);
|
|
1111
1106
|
result.title = localTitle;
|
|
1112
1107
|
}
|
|
1113
1108
|
else if ((title == null || forceToLocal) && type != null) {
|
|
1114
|
-
const localTitle = (typeof forceToLocal ===
|
|
1115
|
-
|
|
1116
|
-
: undefined) ?? this.getFieldLabel(type);
|
|
1109
|
+
const localTitle = (typeof forceToLocal === "function" ? forceToLocal(data) : undefined) ??
|
|
1110
|
+
this.getFieldLabel(type);
|
|
1117
1111
|
result.title = localTitle;
|
|
1118
1112
|
}
|
|
1119
1113
|
return ActionResultError_1.ActionResultError.format(result);
|
|
@@ -1126,7 +1120,7 @@ class CoreApp {
|
|
|
1126
1120
|
get(key) {
|
|
1127
1121
|
// Make sure the resource files are loaded first
|
|
1128
1122
|
const resources = this.settings.currentCulture.resources;
|
|
1129
|
-
const value = typeof resources ===
|
|
1123
|
+
const value = typeof resources === "object" ? resources[key] : undefined;
|
|
1130
1124
|
if (value == null)
|
|
1131
1125
|
return undefined;
|
|
1132
1126
|
// No strict type convertion here
|
|
@@ -1140,17 +1134,17 @@ class CoreApp {
|
|
|
1140
1134
|
*/
|
|
1141
1135
|
getLabels(...keys) {
|
|
1142
1136
|
const init = {};
|
|
1143
|
-
return keys.reduce((a, v) => ({ ...a, [v]: this.get(v) ??
|
|
1137
|
+
return keys.reduce((a, v) => ({ ...a, [v]: this.get(v) ?? "" }), init);
|
|
1144
1138
|
}
|
|
1145
1139
|
/**
|
|
1146
1140
|
* Get bool items
|
|
1147
1141
|
* @returns Bool items
|
|
1148
1142
|
*/
|
|
1149
1143
|
getBools() {
|
|
1150
|
-
const { no =
|
|
1144
|
+
const { no = "No", yes = "Yes" } = this.getLabels("no", "yes");
|
|
1151
1145
|
return [
|
|
1152
|
-
{ id:
|
|
1153
|
-
{ id:
|
|
1146
|
+
{ id: "false", label: no },
|
|
1147
|
+
{ id: "true", label: yes }
|
|
1154
1148
|
];
|
|
1155
1149
|
}
|
|
1156
1150
|
/**
|
|
@@ -1165,7 +1159,7 @@ class CoreApp {
|
|
|
1165
1159
|
* @returns Result
|
|
1166
1160
|
*/
|
|
1167
1161
|
getDataPrivacies() {
|
|
1168
|
-
return this.getEnumList(DataPrivacy_1.DataPrivacy,
|
|
1162
|
+
return this.getEnumList(DataPrivacy_1.DataPrivacy, "dataPrivacy");
|
|
1169
1163
|
}
|
|
1170
1164
|
/**
|
|
1171
1165
|
* Get enum item number id list
|
|
@@ -1176,12 +1170,10 @@ class CoreApp {
|
|
|
1176
1170
|
*/
|
|
1177
1171
|
getEnumList(em, prefix, filter) {
|
|
1178
1172
|
const list = [];
|
|
1179
|
-
const getKey = typeof prefix ===
|
|
1180
|
-
? prefix
|
|
1181
|
-
: (key) => prefix + key;
|
|
1173
|
+
const getKey = typeof prefix === "function" ? prefix : (key) => prefix + key;
|
|
1182
1174
|
if (Array.isArray(filter)) {
|
|
1183
1175
|
filter.forEach((id) => {
|
|
1184
|
-
if (typeof id !==
|
|
1176
|
+
if (typeof id !== "number")
|
|
1185
1177
|
return;
|
|
1186
1178
|
const key = shared_1.DataTypes.getEnumKey(em, id);
|
|
1187
1179
|
const label = this.get(getKey(key)) ?? key;
|
|
@@ -1198,7 +1190,7 @@ class CoreApp {
|
|
|
1198
1190
|
continue;
|
|
1199
1191
|
id = fid;
|
|
1200
1192
|
}
|
|
1201
|
-
if (typeof id !==
|
|
1193
|
+
if (typeof id !== "number")
|
|
1202
1194
|
continue;
|
|
1203
1195
|
const label = this.get(getKey(key)) ?? key;
|
|
1204
1196
|
list.push({ id, label });
|
|
@@ -1215,9 +1207,7 @@ class CoreApp {
|
|
|
1215
1207
|
*/
|
|
1216
1208
|
getEnumStrList(em, prefix, filter) {
|
|
1217
1209
|
const list = [];
|
|
1218
|
-
const getKey = typeof prefix ===
|
|
1219
|
-
? prefix
|
|
1220
|
-
: (key) => prefix + key;
|
|
1210
|
+
const getKey = typeof prefix === "function" ? prefix : (key) => prefix + key;
|
|
1221
1211
|
const keys = shared_1.DataTypes.getEnumKeys(em);
|
|
1222
1212
|
for (const key of keys) {
|
|
1223
1213
|
let id = em[key];
|
|
@@ -1238,7 +1228,7 @@ class CoreApp {
|
|
|
1238
1228
|
* @returns Label
|
|
1239
1229
|
*/
|
|
1240
1230
|
getRegionLabel(id) {
|
|
1241
|
-
return this.get(
|
|
1231
|
+
return this.get("region" + id) ?? id;
|
|
1242
1232
|
}
|
|
1243
1233
|
/**
|
|
1244
1234
|
* Get all regions
|
|
@@ -1254,7 +1244,7 @@ class CoreApp {
|
|
|
1254
1244
|
* @param role Combination role value
|
|
1255
1245
|
*/
|
|
1256
1246
|
getRoles(role) {
|
|
1257
|
-
return this.getEnumList(UserRole_1.UserRole,
|
|
1247
|
+
return this.getEnumList(UserRole_1.UserRole, "role", (id, _key) => {
|
|
1258
1248
|
if ((id & role) > 0)
|
|
1259
1249
|
return id;
|
|
1260
1250
|
});
|
|
@@ -1265,7 +1255,7 @@ class CoreApp {
|
|
|
1265
1255
|
* @returns list
|
|
1266
1256
|
*/
|
|
1267
1257
|
getStatusList(ids) {
|
|
1268
|
-
return this.getEnumList(EntityStatus_1.EntityStatus,
|
|
1258
|
+
return this.getEnumList(EntityStatus_1.EntityStatus, "status", ids);
|
|
1269
1259
|
}
|
|
1270
1260
|
/**
|
|
1271
1261
|
* Get status label
|
|
@@ -1273,9 +1263,9 @@ class CoreApp {
|
|
|
1273
1263
|
*/
|
|
1274
1264
|
getStatusLabel(status) {
|
|
1275
1265
|
if (status == null)
|
|
1276
|
-
return
|
|
1266
|
+
return "";
|
|
1277
1267
|
const key = EntityStatus_1.EntityStatus[status];
|
|
1278
|
-
return this.get(
|
|
1268
|
+
return this.get("status" + key) ?? key;
|
|
1279
1269
|
}
|
|
1280
1270
|
/**
|
|
1281
1271
|
* Get refresh token from response headers
|
|
@@ -1367,20 +1357,20 @@ class CoreApp {
|
|
|
1367
1357
|
* @param options Options
|
|
1368
1358
|
*/
|
|
1369
1359
|
navigate(to, options) {
|
|
1370
|
-
if (typeof to ===
|
|
1360
|
+
if (typeof to === "number") {
|
|
1371
1361
|
globalThis.history.go(to);
|
|
1372
1362
|
}
|
|
1373
1363
|
else {
|
|
1374
1364
|
const { state, replace = false } = options ?? {};
|
|
1375
1365
|
if (replace) {
|
|
1376
1366
|
if (state)
|
|
1377
|
-
globalThis.history.replaceState(state,
|
|
1367
|
+
globalThis.history.replaceState(state, "", to);
|
|
1378
1368
|
else
|
|
1379
1369
|
globalThis.location.replace(to);
|
|
1380
1370
|
}
|
|
1381
1371
|
else {
|
|
1382
1372
|
if (state)
|
|
1383
|
-
globalThis.history.pushState(state,
|
|
1373
|
+
globalThis.history.pushState(state, "", to);
|
|
1384
1374
|
else
|
|
1385
1375
|
globalThis.location.assign(to);
|
|
1386
1376
|
}
|
|
@@ -1392,7 +1382,7 @@ class CoreApp {
|
|
|
1392
1382
|
* @param message Success message
|
|
1393
1383
|
*/
|
|
1394
1384
|
ok(callback, message) {
|
|
1395
|
-
message ?? (message = this.get(
|
|
1385
|
+
message ?? (message = this.get("operationSucceeded"));
|
|
1396
1386
|
this.notifier.succeed(message, undefined, callback);
|
|
1397
1387
|
}
|
|
1398
1388
|
/**
|
|
@@ -1420,17 +1410,17 @@ class CoreApp {
|
|
|
1420
1410
|
if (!token) {
|
|
1421
1411
|
data = {
|
|
1422
1412
|
ok: false,
|
|
1423
|
-
type:
|
|
1424
|
-
field:
|
|
1425
|
-
title: this.get(
|
|
1413
|
+
type: "noData",
|
|
1414
|
+
field: "token",
|
|
1415
|
+
title: this.get("noData")
|
|
1426
1416
|
};
|
|
1427
1417
|
}
|
|
1428
1418
|
else if (result.data == null) {
|
|
1429
1419
|
data = {
|
|
1430
1420
|
ok: false,
|
|
1431
|
-
type:
|
|
1432
|
-
field:
|
|
1433
|
-
title: this.get(
|
|
1421
|
+
type: "noData",
|
|
1422
|
+
field: "user",
|
|
1423
|
+
title: this.get("noData")
|
|
1434
1424
|
};
|
|
1435
1425
|
}
|
|
1436
1426
|
else {
|
|
@@ -1447,8 +1437,7 @@ class CoreApp {
|
|
|
1447
1437
|
this.initCall((ir) => {
|
|
1448
1438
|
if (!ir)
|
|
1449
1439
|
return;
|
|
1450
|
-
this.notifier.alert(this.get(
|
|
1451
|
-
'Environment changed', () => {
|
|
1440
|
+
this.notifier.alert(this.get("environmentChanged") ?? "Environment changed", () => {
|
|
1452
1441
|
// Callback, return true to prevent the default reload action
|
|
1453
1442
|
if (callback == null || callback() !== true) {
|
|
1454
1443
|
// Reload the page
|
|
@@ -1465,8 +1454,7 @@ class CoreApp {
|
|
|
1465
1454
|
r = data;
|
|
1466
1455
|
}
|
|
1467
1456
|
if (callback == null || callback(r) !== true) {
|
|
1468
|
-
|
|
1469
|
-
this.notifier.alert(message, () => {
|
|
1457
|
+
this.alertResult(r, () => {
|
|
1470
1458
|
if (callback)
|
|
1471
1459
|
callback(false);
|
|
1472
1460
|
});
|
|
@@ -1497,7 +1485,7 @@ class CoreApp {
|
|
|
1497
1485
|
async exchangeToken(api, token) {
|
|
1498
1486
|
// Avoid to call the system API
|
|
1499
1487
|
if (api.name === systemApi) {
|
|
1500
|
-
throw new Error(
|
|
1488
|
+
throw new Error("System API is not allowed to exchange token");
|
|
1501
1489
|
}
|
|
1502
1490
|
// Call the API quietly, no loading bar and no error popup
|
|
1503
1491
|
const data = await this.createAuthApi().exchangeToken({ token }, {
|
|
@@ -1529,7 +1517,7 @@ class CoreApp {
|
|
|
1529
1517
|
* @param coreName Core system's name, default is 'core'
|
|
1530
1518
|
*/
|
|
1531
1519
|
exchangeTokenAll(coreData, coreName) {
|
|
1532
|
-
coreName ?? (coreName =
|
|
1520
|
+
coreName ?? (coreName = "core");
|
|
1533
1521
|
for (const name in this.apis) {
|
|
1534
1522
|
// Ignore the system API as it has its own logic with refreshToken
|
|
1535
1523
|
if (name === systemApi)
|
|
@@ -1680,7 +1668,7 @@ class CoreApp {
|
|
|
1680
1668
|
// Save the current URL
|
|
1681
1669
|
this.cachedUrl = removeUrl ? undefined : globalThis.location.href;
|
|
1682
1670
|
// URL with parameters
|
|
1683
|
-
const url =
|
|
1671
|
+
const url = "/".addUrlParams(params);
|
|
1684
1672
|
this.navigate(url);
|
|
1685
1673
|
}
|
|
1686
1674
|
/**
|
|
@@ -1741,7 +1729,7 @@ class CoreApp {
|
|
|
1741
1729
|
* @param noTrigger No trigger for state change
|
|
1742
1730
|
*/
|
|
1743
1731
|
userLogout(clearToken = true, noTrigger = false) {
|
|
1744
|
-
this.authorize(undefined, undefined, clearToken ? undefined :
|
|
1732
|
+
this.authorize(undefined, undefined, clearToken ? undefined : "");
|
|
1745
1733
|
}
|
|
1746
1734
|
/**
|
|
1747
1735
|
* User unauthorized
|
|
@@ -31,7 +31,7 @@ export interface IExternalSettings extends ExternalEndpoint {
|
|
|
31
31
|
/**
|
|
32
32
|
* Endpoints to other services
|
|
33
33
|
*/
|
|
34
|
-
readonly endpoints?: Record<
|
|
34
|
+
readonly endpoints?: Record<"core" | "accounting" | "crm" | "calandar" | "task" | string, ExternalEndpoint>;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* External settings namespace
|