@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/mjs/app/CoreApp.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { NotificationAlign, NotificationMessageType } from
|
|
2
|
-
import { createClient } from
|
|
3
|
-
import { DataTypes, DateUtils, DomUtils, ExtendUtils, NumberUtils, Utils } from
|
|
4
|
-
import { AddressRegion } from
|
|
5
|
-
import { BridgeUtils } from
|
|
6
|
-
import { DataPrivacy } from
|
|
7
|
-
import { EntityStatus } from
|
|
8
|
-
import { ActionResultError } from
|
|
9
|
-
import { appFields } from
|
|
10
|
-
import { UserRole } from
|
|
11
|
-
import { AuthApi } from
|
|
1
|
+
import { NotificationAlign, NotificationMessageType } from "@etsoo/notificationbase";
|
|
2
|
+
import { createClient } from "@etsoo/restclient";
|
|
3
|
+
import { DataTypes, DateUtils, DomUtils, ExtendUtils, NumberUtils, Utils } from "@etsoo/shared";
|
|
4
|
+
import { AddressRegion } from "../address/AddressRegion";
|
|
5
|
+
import { BridgeUtils } from "../bridges/BridgeUtils";
|
|
6
|
+
import { DataPrivacy } from "../business/DataPrivacy";
|
|
7
|
+
import { EntityStatus } from "../business/EntityStatus";
|
|
8
|
+
import { ActionResultError } from "../result/ActionResultError";
|
|
9
|
+
import { appFields } from "./IApp";
|
|
10
|
+
import { UserRole } from "./UserRole";
|
|
11
|
+
import { AuthApi } from "../api/AuthApi";
|
|
12
12
|
let CJ;
|
|
13
|
-
const loadCrypto = () => import(
|
|
13
|
+
const loadCrypto = () => import("crypto-js");
|
|
14
14
|
// System API name
|
|
15
|
-
const systemApi =
|
|
15
|
+
const systemApi = "system";
|
|
16
16
|
/**
|
|
17
17
|
* Core application
|
|
18
18
|
*/
|
|
@@ -165,20 +165,20 @@ export class CoreApp {
|
|
|
165
165
|
/**
|
|
166
166
|
* Init call Api URL
|
|
167
167
|
*/
|
|
168
|
-
this.initCallApi =
|
|
168
|
+
this.initCallApi = "Auth/WebInitCall";
|
|
169
169
|
/**
|
|
170
170
|
* Passphrase for encryption
|
|
171
171
|
*/
|
|
172
|
-
this.passphrase =
|
|
172
|
+
this.passphrase = "";
|
|
173
173
|
this.apis = {};
|
|
174
174
|
this.tasks = [];
|
|
175
175
|
if (settings?.regions?.length === 0) {
|
|
176
|
-
throw new Error(
|
|
176
|
+
throw new Error("No regions defined");
|
|
177
177
|
}
|
|
178
178
|
this.settings = settings;
|
|
179
179
|
const region = AddressRegion.getById(settings.regions[0]);
|
|
180
180
|
if (region == null) {
|
|
181
|
-
throw new Error(
|
|
181
|
+
throw new Error("No default region defined");
|
|
182
182
|
}
|
|
183
183
|
this.defaultRegion = region;
|
|
184
184
|
// Current system refresh token
|
|
@@ -215,9 +215,9 @@ export class CoreApp {
|
|
|
215
215
|
this.name = name;
|
|
216
216
|
this.debug = debug;
|
|
217
217
|
// Fields, attach with the name identifier
|
|
218
|
-
this.fields = appFields.reduce((a, v) => ({ ...a, [v]:
|
|
218
|
+
this.fields = appFields.reduce((a, v) => ({ ...a, [v]: "smarterp-" + v + "-" + name }), {});
|
|
219
219
|
// Device id
|
|
220
|
-
this._deviceId = storage.getData(this.fields.deviceId,
|
|
220
|
+
this._deviceId = storage.getData(this.fields.deviceId, "");
|
|
221
221
|
// Embedded
|
|
222
222
|
this._embedded =
|
|
223
223
|
this.storage.getData(this.fields.embedded) ?? false;
|
|
@@ -227,7 +227,7 @@ export class CoreApp {
|
|
|
227
227
|
CJ = cj.default;
|
|
228
228
|
// Debug
|
|
229
229
|
if (this.debug) {
|
|
230
|
-
console.debug(
|
|
230
|
+
console.debug("CoreApp.constructor.ready", this._deviceId, this.fields, cj, currentCulture, currentRegion);
|
|
231
231
|
}
|
|
232
232
|
this.changeRegion(currentRegion);
|
|
233
233
|
this.setup();
|
|
@@ -242,7 +242,7 @@ export class CoreApp {
|
|
|
242
242
|
this.fields.headerToken,
|
|
243
243
|
this.fields.serversideDeviceId
|
|
244
244
|
], false);
|
|
245
|
-
this.passphrase =
|
|
245
|
+
this.passphrase = "";
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
248
248
|
* Add app name as identifier
|
|
@@ -250,7 +250,7 @@ export class CoreApp {
|
|
|
250
250
|
* @returns Result
|
|
251
251
|
*/
|
|
252
252
|
addIdentifier(field) {
|
|
253
|
-
return field +
|
|
253
|
+
return field + "-" + this.name;
|
|
254
254
|
}
|
|
255
255
|
/**
|
|
256
256
|
* Add root (homepage) to the URL
|
|
@@ -259,13 +259,13 @@ export class CoreApp {
|
|
|
259
259
|
*/
|
|
260
260
|
addRootUrl(url) {
|
|
261
261
|
const page = this.settings.homepage;
|
|
262
|
-
const endSlash = page.endsWith(
|
|
262
|
+
const endSlash = page.endsWith("/");
|
|
263
263
|
return (page +
|
|
264
264
|
(endSlash
|
|
265
|
-
? Utils.trimStart(url,
|
|
266
|
-
: url.startsWith(
|
|
265
|
+
? Utils.trimStart(url, "/")
|
|
266
|
+
: url.startsWith("/")
|
|
267
267
|
? url
|
|
268
|
-
:
|
|
268
|
+
: "/" + url));
|
|
269
269
|
}
|
|
270
270
|
/**
|
|
271
271
|
* Create Auth API
|
|
@@ -281,13 +281,13 @@ export class CoreApp {
|
|
|
281
281
|
async restore() {
|
|
282
282
|
// Devices
|
|
283
283
|
const devices = this.storage.getPersistedData(this.fields.devices, []);
|
|
284
|
-
if (this._deviceId ===
|
|
284
|
+
if (this._deviceId === "") {
|
|
285
285
|
// First vist, restore and keep the source
|
|
286
286
|
this.storage.copyFrom(this.persistedFields, false);
|
|
287
287
|
// Reset device id
|
|
288
|
-
this._deviceId = this.storage.getData(this.fields.deviceId,
|
|
288
|
+
this._deviceId = this.storage.getData(this.fields.deviceId, "");
|
|
289
289
|
// Totally new, no data restored
|
|
290
|
-
if (this._deviceId ===
|
|
290
|
+
if (this._deviceId === "")
|
|
291
291
|
return false;
|
|
292
292
|
}
|
|
293
293
|
// Device exists or not
|
|
@@ -391,7 +391,7 @@ export class CoreApp {
|
|
|
391
391
|
}
|
|
392
392
|
}
|
|
393
393
|
updateApi(nameOrData, token, seconds) {
|
|
394
|
-
const api = typeof nameOrData ===
|
|
394
|
+
const api = typeof nameOrData === "string" ? this.apis[nameOrData] : nameOrData;
|
|
395
395
|
if (api == null)
|
|
396
396
|
return;
|
|
397
397
|
// Consider the API call delay
|
|
@@ -436,7 +436,7 @@ export class CoreApp {
|
|
|
436
436
|
// Unauthorized
|
|
437
437
|
if (handlerFor401 === false)
|
|
438
438
|
return;
|
|
439
|
-
if (typeof handlerFor401 ===
|
|
439
|
+
if (typeof handlerFor401 === "function") {
|
|
440
440
|
handlerFor401();
|
|
441
441
|
}
|
|
442
442
|
else {
|
|
@@ -445,10 +445,10 @@ export class CoreApp {
|
|
|
445
445
|
return;
|
|
446
446
|
}
|
|
447
447
|
else if (error.response == null &&
|
|
448
|
-
(error.message ===
|
|
449
|
-
error.message ===
|
|
448
|
+
(error.message === "Network Error" ||
|
|
449
|
+
error.message === "Failed to fetch")) {
|
|
450
450
|
// Network error
|
|
451
|
-
this.notifier.alert(this.get(
|
|
451
|
+
this.notifier.alert(this.get("networkError") + ` [${this.name}]`);
|
|
452
452
|
return;
|
|
453
453
|
}
|
|
454
454
|
else {
|
|
@@ -497,10 +497,10 @@ export class CoreApp {
|
|
|
497
497
|
*/
|
|
498
498
|
setupLogging(action, preventDefault) {
|
|
499
499
|
action ?? (action = (data) => {
|
|
500
|
-
this.api.post(
|
|
500
|
+
this.api.post("Auth/LogFrontendError", data, {
|
|
501
501
|
onError: (error) => {
|
|
502
502
|
// Use 'debug' to avoid infinite loop
|
|
503
|
-
console.debug(
|
|
503
|
+
console.debug("Log front-end error", data, error);
|
|
504
504
|
// Prevent global error handler
|
|
505
505
|
return false;
|
|
506
506
|
}
|
|
@@ -522,8 +522,8 @@ export class CoreApp {
|
|
|
522
522
|
* @returns true means device is invalid
|
|
523
523
|
*/
|
|
524
524
|
checkDeviceResult(result) {
|
|
525
|
-
if (result.type ===
|
|
526
|
-
(result.type ===
|
|
525
|
+
if (result.type === "DataProcessingFailed" ||
|
|
526
|
+
(result.type === "NoValidData" && result.field === "Device"))
|
|
527
527
|
return true;
|
|
528
528
|
return false;
|
|
529
529
|
}
|
|
@@ -531,7 +531,7 @@ export class CoreApp {
|
|
|
531
531
|
* Clear device id
|
|
532
532
|
*/
|
|
533
533
|
clearDeviceId() {
|
|
534
|
-
this._deviceId =
|
|
534
|
+
this._deviceId = "";
|
|
535
535
|
this.storage.clear([this.fields.deviceId], false);
|
|
536
536
|
this.storage.clear([this.fields.deviceId], true);
|
|
537
537
|
}
|
|
@@ -572,7 +572,7 @@ export class CoreApp {
|
|
|
572
572
|
}
|
|
573
573
|
if (result.data == null) {
|
|
574
574
|
// Popup no data error
|
|
575
|
-
this.notifier.alert(this.get(
|
|
575
|
+
this.notifier.alert(this.get("noData"));
|
|
576
576
|
if (callback)
|
|
577
577
|
callback(false);
|
|
578
578
|
return;
|
|
@@ -580,10 +580,10 @@ export class CoreApp {
|
|
|
580
580
|
if (!result.ok) {
|
|
581
581
|
const seconds = result.data.seconds;
|
|
582
582
|
const validSeconds = result.data.validSeconds;
|
|
583
|
-
if (result.title ===
|
|
583
|
+
if (result.title === "timeDifferenceInvalid" &&
|
|
584
584
|
seconds != null &&
|
|
585
585
|
validSeconds != null) {
|
|
586
|
-
const title = this.get(
|
|
586
|
+
const title = this.get("timeDifferenceInvalid")?.format(seconds.toString(), validSeconds.toString());
|
|
587
587
|
this.notifier.alert(title);
|
|
588
588
|
}
|
|
589
589
|
else {
|
|
@@ -597,7 +597,7 @@ export class CoreApp {
|
|
|
597
597
|
}
|
|
598
598
|
const updateResult = await this.initCallUpdate(result.data, data.timestamp);
|
|
599
599
|
if (!updateResult) {
|
|
600
|
-
this.notifier.alert(this.get(
|
|
600
|
+
this.notifier.alert(this.get("noData") + "(Update)");
|
|
601
601
|
}
|
|
602
602
|
if (callback)
|
|
603
603
|
callback(updateResult);
|
|
@@ -616,14 +616,14 @@ export class CoreApp {
|
|
|
616
616
|
const fields = this.initCallEncryptedUpdateFields();
|
|
617
617
|
for (const field of fields) {
|
|
618
618
|
const currentValue = this.storage.getData(field);
|
|
619
|
-
if (currentValue == null || currentValue ===
|
|
619
|
+
if (currentValue == null || currentValue === "")
|
|
620
620
|
continue;
|
|
621
621
|
if (prev == null) {
|
|
622
622
|
// Reset the field
|
|
623
623
|
this.storage.setData(field, undefined);
|
|
624
624
|
continue;
|
|
625
625
|
}
|
|
626
|
-
const enhanced = currentValue.indexOf(
|
|
626
|
+
const enhanced = currentValue.indexOf("!") >= 8;
|
|
627
627
|
let newValueSource;
|
|
628
628
|
if (enhanced) {
|
|
629
629
|
newValueSource = this.decryptEnhanced(currentValue, prev, 12);
|
|
@@ -631,7 +631,7 @@ export class CoreApp {
|
|
|
631
631
|
else {
|
|
632
632
|
newValueSource = this.decrypt(currentValue, prev);
|
|
633
633
|
}
|
|
634
|
-
if (newValueSource == null || newValueSource ===
|
|
634
|
+
if (newValueSource == null || newValueSource === "") {
|
|
635
635
|
// Reset the field
|
|
636
636
|
this.storage.setData(field, undefined);
|
|
637
637
|
continue;
|
|
@@ -666,7 +666,7 @@ export class CoreApp {
|
|
|
666
666
|
// Previous passphrase
|
|
667
667
|
if (data.previousPassphrase) {
|
|
668
668
|
const prev = this.decrypt(data.previousPassphrase, timestamp.toString());
|
|
669
|
-
this.passphrase = prev ??
|
|
669
|
+
this.passphrase = prev ?? "";
|
|
670
670
|
}
|
|
671
671
|
// Update passphrase
|
|
672
672
|
this.updatePassphrase(passphrase);
|
|
@@ -680,7 +680,7 @@ export class CoreApp {
|
|
|
680
680
|
return [this.fields.headerToken];
|
|
681
681
|
}
|
|
682
682
|
alertResult(result, callback, forceToLocal) {
|
|
683
|
-
const message = typeof result ===
|
|
683
|
+
const message = typeof result === "string"
|
|
684
684
|
? result
|
|
685
685
|
: this.formatResult(result, forceToLocal);
|
|
686
686
|
this.notifier.alert(message, callback);
|
|
@@ -695,10 +695,10 @@ export class CoreApp {
|
|
|
695
695
|
// State, when token is null, means logout
|
|
696
696
|
const authorized = token != null;
|
|
697
697
|
// Token
|
|
698
|
-
schema ?? (schema =
|
|
698
|
+
schema ?? (schema = "Bearer");
|
|
699
699
|
this.api.authorize(schema, token);
|
|
700
700
|
// Overwrite the current value
|
|
701
|
-
if (refreshToken !==
|
|
701
|
+
if (refreshToken !== "") {
|
|
702
702
|
if (refreshToken != null)
|
|
703
703
|
refreshToken = this.encrypt(refreshToken);
|
|
704
704
|
this.storage.setData(this.fields.headerToken, refreshToken);
|
|
@@ -737,7 +737,7 @@ export class CoreApp {
|
|
|
737
737
|
// Get data
|
|
738
738
|
let regionId;
|
|
739
739
|
let regionItem;
|
|
740
|
-
if (typeof region ===
|
|
740
|
+
if (typeof region === "string") {
|
|
741
741
|
regionId = region;
|
|
742
742
|
regionItem = AddressRegion.getById(region);
|
|
743
743
|
}
|
|
@@ -770,7 +770,7 @@ export class CoreApp {
|
|
|
770
770
|
const { name } = culture;
|
|
771
771
|
// Same?
|
|
772
772
|
let resources = culture.resources;
|
|
773
|
-
if (this._culture === name && typeof resources ===
|
|
773
|
+
if (this._culture === name && typeof resources === "object")
|
|
774
774
|
return resources;
|
|
775
775
|
// Save the cultrue to local storage
|
|
776
776
|
this.storage.setPersistedData(DomUtils.CultureField, name);
|
|
@@ -781,7 +781,7 @@ export class CoreApp {
|
|
|
781
781
|
this._culture = name;
|
|
782
782
|
// Hold the current resources
|
|
783
783
|
this.settings.currentCulture = culture;
|
|
784
|
-
if (typeof resources !==
|
|
784
|
+
if (typeof resources !== "object") {
|
|
785
785
|
resources = await resources();
|
|
786
786
|
// Set static resources back
|
|
787
787
|
culture.resources = resources;
|
|
@@ -864,7 +864,7 @@ export class CoreApp {
|
|
|
864
864
|
*/
|
|
865
865
|
decryptEnhanced(messageEncrypted, passphrase, durationSeconds) {
|
|
866
866
|
// Timestamp splitter
|
|
867
|
-
const pos = messageEncrypted.indexOf(
|
|
867
|
+
const pos = messageEncrypted.indexOf("!");
|
|
868
868
|
// Miliseconds chars are longer than 8
|
|
869
869
|
if (pos < 8 || messageEncrypted.length <= 66)
|
|
870
870
|
return undefined;
|
|
@@ -875,10 +875,8 @@ export class CoreApp {
|
|
|
875
875
|
if (isNaN(milseconds) || milseconds < 1)
|
|
876
876
|
return undefined;
|
|
877
877
|
const timespan = new Date().substract(new Date(milseconds));
|
|
878
|
-
if ((durationSeconds <= 12 &&
|
|
879
|
-
timespan.
|
|
880
|
-
(durationSeconds > 12 &&
|
|
881
|
-
timespan.totalSeconds > durationSeconds))
|
|
878
|
+
if ((durationSeconds <= 12 && timespan.totalMonths > durationSeconds) ||
|
|
879
|
+
(durationSeconds > 12 && timespan.totalSeconds > durationSeconds))
|
|
882
880
|
return undefined;
|
|
883
881
|
}
|
|
884
882
|
const message = messageEncrypted.substring(pos + 1);
|
|
@@ -938,12 +936,12 @@ export class CoreApp {
|
|
|
938
936
|
callback(success);
|
|
939
937
|
}
|
|
940
938
|
else if (success)
|
|
941
|
-
this.notifier.message(NotificationMessageType.Success, this.get(
|
|
939
|
+
this.notifier.message(NotificationMessageType.Success, this.get("fileDownloaded"));
|
|
942
940
|
};
|
|
943
941
|
// https://developer.mozilla.org/en-US/docs/Web/API/UserActivation/isActive
|
|
944
|
-
if (
|
|
942
|
+
if ("userActivation" in navigator &&
|
|
945
943
|
!navigator.userActivation.isActive) {
|
|
946
|
-
this.notifier.alert(this.get(
|
|
944
|
+
this.notifier.alert(this.get("reactivateTip"), async () => {
|
|
947
945
|
await downloadFile();
|
|
948
946
|
});
|
|
949
947
|
}
|
|
@@ -970,7 +968,7 @@ export class CoreApp {
|
|
|
970
968
|
iterations: 1000 * iterations
|
|
971
969
|
});
|
|
972
970
|
const iv = lib.WordArray.random(bits);
|
|
973
|
-
return (iterations.toString().padStart(2,
|
|
971
|
+
return (iterations.toString().padStart(2, "0") +
|
|
974
972
|
salt.toString(enc.Hex) +
|
|
975
973
|
iv.toString(enc.Hex) +
|
|
976
974
|
AES.encrypt(message, key, {
|
|
@@ -992,7 +990,7 @@ export class CoreApp {
|
|
|
992
990
|
const timestamp = Utils.numberToChars(new Date().getTime());
|
|
993
991
|
passphrase = this.encryptionEnhance(passphrase ?? this.passphrase, timestamp);
|
|
994
992
|
const result = this.encrypt(message, passphrase, iterations);
|
|
995
|
-
return timestamp +
|
|
993
|
+
return timestamp + "!" + result;
|
|
996
994
|
}
|
|
997
995
|
/**
|
|
998
996
|
* Enchance secret passphrase
|
|
@@ -1013,8 +1011,8 @@ export class CoreApp {
|
|
|
1013
1011
|
* @returns Result
|
|
1014
1012
|
*/
|
|
1015
1013
|
formatAction(action, target, ...items) {
|
|
1016
|
-
let more = items.join(
|
|
1017
|
-
return `[${this.get(
|
|
1014
|
+
let more = items.join(", ");
|
|
1015
|
+
return `[${this.get("appName")}] ${action} - ${target}${more ? `, ${more}` : more}`;
|
|
1018
1016
|
}
|
|
1019
1017
|
/**
|
|
1020
1018
|
* Format date to string
|
|
@@ -1062,10 +1060,10 @@ export class CoreApp {
|
|
|
1062
1060
|
*/
|
|
1063
1061
|
formatFullName(familyName, givenName) {
|
|
1064
1062
|
if (!familyName)
|
|
1065
|
-
return givenName ??
|
|
1063
|
+
return givenName ?? "";
|
|
1066
1064
|
if (!givenName)
|
|
1067
|
-
return familyName ??
|
|
1068
|
-
const wf = givenName +
|
|
1065
|
+
return familyName ?? "";
|
|
1066
|
+
const wf = givenName + " " + familyName;
|
|
1069
1067
|
if (wf.containChinese() || wf.containJapanese() || wf.containKorean()) {
|
|
1070
1068
|
return familyName + givenName;
|
|
1071
1069
|
}
|
|
@@ -1083,18 +1081,16 @@ export class CoreApp {
|
|
|
1083
1081
|
// Destruct the result
|
|
1084
1082
|
const { title, type, field } = result;
|
|
1085
1083
|
const data = { title, type, field };
|
|
1086
|
-
if (type ===
|
|
1084
|
+
if (type === "ItemExists" && field) {
|
|
1087
1085
|
// Special case
|
|
1088
|
-
const fieldLabel = (typeof forceToLocal ===
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
result.title = this.get('itemExists')?.format(fieldLabel);
|
|
1086
|
+
const fieldLabel = (typeof forceToLocal === "function" ? forceToLocal(data) : undefined) ??
|
|
1087
|
+
this.getFieldLabel(field);
|
|
1088
|
+
result.title = this.get("itemExists")?.format(fieldLabel);
|
|
1092
1089
|
}
|
|
1093
|
-
else if (title?.includes(
|
|
1090
|
+
else if (title?.includes("{0}")) {
|
|
1094
1091
|
// When title contains {0}, replace with the field label
|
|
1095
|
-
const fieldLabel = (typeof forceToLocal ===
|
|
1096
|
-
?
|
|
1097
|
-
: undefined) ?? (field ? this.getFieldLabel(field) : '');
|
|
1092
|
+
const fieldLabel = (typeof forceToLocal === "function" ? forceToLocal(data) : undefined) ??
|
|
1093
|
+
(field ? this.getFieldLabel(field) : "");
|
|
1098
1094
|
result.title = title.format(fieldLabel);
|
|
1099
1095
|
}
|
|
1100
1096
|
else if (title && /^\w+$/.test(title)) {
|
|
@@ -1102,15 +1098,13 @@ export class CoreApp {
|
|
|
1102
1098
|
// Hold the original title in type when type is null
|
|
1103
1099
|
if (type == null)
|
|
1104
1100
|
result.type = title;
|
|
1105
|
-
const localTitle = (typeof forceToLocal ===
|
|
1106
|
-
|
|
1107
|
-
: undefined) ?? this.getFieldLabel(title);
|
|
1101
|
+
const localTitle = (typeof forceToLocal === "function" ? forceToLocal(data) : undefined) ??
|
|
1102
|
+
this.getFieldLabel(title);
|
|
1108
1103
|
result.title = localTitle;
|
|
1109
1104
|
}
|
|
1110
1105
|
else if ((title == null || forceToLocal) && type != null) {
|
|
1111
|
-
const localTitle = (typeof forceToLocal ===
|
|
1112
|
-
|
|
1113
|
-
: undefined) ?? this.getFieldLabel(type);
|
|
1106
|
+
const localTitle = (typeof forceToLocal === "function" ? forceToLocal(data) : undefined) ??
|
|
1107
|
+
this.getFieldLabel(type);
|
|
1114
1108
|
result.title = localTitle;
|
|
1115
1109
|
}
|
|
1116
1110
|
return ActionResultError.format(result);
|
|
@@ -1123,7 +1117,7 @@ export class CoreApp {
|
|
|
1123
1117
|
get(key) {
|
|
1124
1118
|
// Make sure the resource files are loaded first
|
|
1125
1119
|
const resources = this.settings.currentCulture.resources;
|
|
1126
|
-
const value = typeof resources ===
|
|
1120
|
+
const value = typeof resources === "object" ? resources[key] : undefined;
|
|
1127
1121
|
if (value == null)
|
|
1128
1122
|
return undefined;
|
|
1129
1123
|
// No strict type convertion here
|
|
@@ -1137,17 +1131,17 @@ export class CoreApp {
|
|
|
1137
1131
|
*/
|
|
1138
1132
|
getLabels(...keys) {
|
|
1139
1133
|
const init = {};
|
|
1140
|
-
return keys.reduce((a, v) => ({ ...a, [v]: this.get(v) ??
|
|
1134
|
+
return keys.reduce((a, v) => ({ ...a, [v]: this.get(v) ?? "" }), init);
|
|
1141
1135
|
}
|
|
1142
1136
|
/**
|
|
1143
1137
|
* Get bool items
|
|
1144
1138
|
* @returns Bool items
|
|
1145
1139
|
*/
|
|
1146
1140
|
getBools() {
|
|
1147
|
-
const { no =
|
|
1141
|
+
const { no = "No", yes = "Yes" } = this.getLabels("no", "yes");
|
|
1148
1142
|
return [
|
|
1149
|
-
{ id:
|
|
1150
|
-
{ id:
|
|
1143
|
+
{ id: "false", label: no },
|
|
1144
|
+
{ id: "true", label: yes }
|
|
1151
1145
|
];
|
|
1152
1146
|
}
|
|
1153
1147
|
/**
|
|
@@ -1162,7 +1156,7 @@ export class CoreApp {
|
|
|
1162
1156
|
* @returns Result
|
|
1163
1157
|
*/
|
|
1164
1158
|
getDataPrivacies() {
|
|
1165
|
-
return this.getEnumList(DataPrivacy,
|
|
1159
|
+
return this.getEnumList(DataPrivacy, "dataPrivacy");
|
|
1166
1160
|
}
|
|
1167
1161
|
/**
|
|
1168
1162
|
* Get enum item number id list
|
|
@@ -1173,12 +1167,10 @@ export class CoreApp {
|
|
|
1173
1167
|
*/
|
|
1174
1168
|
getEnumList(em, prefix, filter) {
|
|
1175
1169
|
const list = [];
|
|
1176
|
-
const getKey = typeof prefix ===
|
|
1177
|
-
? prefix
|
|
1178
|
-
: (key) => prefix + key;
|
|
1170
|
+
const getKey = typeof prefix === "function" ? prefix : (key) => prefix + key;
|
|
1179
1171
|
if (Array.isArray(filter)) {
|
|
1180
1172
|
filter.forEach((id) => {
|
|
1181
|
-
if (typeof id !==
|
|
1173
|
+
if (typeof id !== "number")
|
|
1182
1174
|
return;
|
|
1183
1175
|
const key = DataTypes.getEnumKey(em, id);
|
|
1184
1176
|
const label = this.get(getKey(key)) ?? key;
|
|
@@ -1195,7 +1187,7 @@ export class CoreApp {
|
|
|
1195
1187
|
continue;
|
|
1196
1188
|
id = fid;
|
|
1197
1189
|
}
|
|
1198
|
-
if (typeof id !==
|
|
1190
|
+
if (typeof id !== "number")
|
|
1199
1191
|
continue;
|
|
1200
1192
|
const label = this.get(getKey(key)) ?? key;
|
|
1201
1193
|
list.push({ id, label });
|
|
@@ -1212,9 +1204,7 @@ export class CoreApp {
|
|
|
1212
1204
|
*/
|
|
1213
1205
|
getEnumStrList(em, prefix, filter) {
|
|
1214
1206
|
const list = [];
|
|
1215
|
-
const getKey = typeof prefix ===
|
|
1216
|
-
? prefix
|
|
1217
|
-
: (key) => prefix + key;
|
|
1207
|
+
const getKey = typeof prefix === "function" ? prefix : (key) => prefix + key;
|
|
1218
1208
|
const keys = DataTypes.getEnumKeys(em);
|
|
1219
1209
|
for (const key of keys) {
|
|
1220
1210
|
let id = em[key];
|
|
@@ -1235,7 +1225,7 @@ export class CoreApp {
|
|
|
1235
1225
|
* @returns Label
|
|
1236
1226
|
*/
|
|
1237
1227
|
getRegionLabel(id) {
|
|
1238
|
-
return this.get(
|
|
1228
|
+
return this.get("region" + id) ?? id;
|
|
1239
1229
|
}
|
|
1240
1230
|
/**
|
|
1241
1231
|
* Get all regions
|
|
@@ -1251,7 +1241,7 @@ export class CoreApp {
|
|
|
1251
1241
|
* @param role Combination role value
|
|
1252
1242
|
*/
|
|
1253
1243
|
getRoles(role) {
|
|
1254
|
-
return this.getEnumList(UserRole,
|
|
1244
|
+
return this.getEnumList(UserRole, "role", (id, _key) => {
|
|
1255
1245
|
if ((id & role) > 0)
|
|
1256
1246
|
return id;
|
|
1257
1247
|
});
|
|
@@ -1262,7 +1252,7 @@ export class CoreApp {
|
|
|
1262
1252
|
* @returns list
|
|
1263
1253
|
*/
|
|
1264
1254
|
getStatusList(ids) {
|
|
1265
|
-
return this.getEnumList(EntityStatus,
|
|
1255
|
+
return this.getEnumList(EntityStatus, "status", ids);
|
|
1266
1256
|
}
|
|
1267
1257
|
/**
|
|
1268
1258
|
* Get status label
|
|
@@ -1270,9 +1260,9 @@ export class CoreApp {
|
|
|
1270
1260
|
*/
|
|
1271
1261
|
getStatusLabel(status) {
|
|
1272
1262
|
if (status == null)
|
|
1273
|
-
return
|
|
1263
|
+
return "";
|
|
1274
1264
|
const key = EntityStatus[status];
|
|
1275
|
-
return this.get(
|
|
1265
|
+
return this.get("status" + key) ?? key;
|
|
1276
1266
|
}
|
|
1277
1267
|
/**
|
|
1278
1268
|
* Get refresh token from response headers
|
|
@@ -1364,20 +1354,20 @@ export class CoreApp {
|
|
|
1364
1354
|
* @param options Options
|
|
1365
1355
|
*/
|
|
1366
1356
|
navigate(to, options) {
|
|
1367
|
-
if (typeof to ===
|
|
1357
|
+
if (typeof to === "number") {
|
|
1368
1358
|
globalThis.history.go(to);
|
|
1369
1359
|
}
|
|
1370
1360
|
else {
|
|
1371
1361
|
const { state, replace = false } = options ?? {};
|
|
1372
1362
|
if (replace) {
|
|
1373
1363
|
if (state)
|
|
1374
|
-
globalThis.history.replaceState(state,
|
|
1364
|
+
globalThis.history.replaceState(state, "", to);
|
|
1375
1365
|
else
|
|
1376
1366
|
globalThis.location.replace(to);
|
|
1377
1367
|
}
|
|
1378
1368
|
else {
|
|
1379
1369
|
if (state)
|
|
1380
|
-
globalThis.history.pushState(state,
|
|
1370
|
+
globalThis.history.pushState(state, "", to);
|
|
1381
1371
|
else
|
|
1382
1372
|
globalThis.location.assign(to);
|
|
1383
1373
|
}
|
|
@@ -1389,7 +1379,7 @@ export class CoreApp {
|
|
|
1389
1379
|
* @param message Success message
|
|
1390
1380
|
*/
|
|
1391
1381
|
ok(callback, message) {
|
|
1392
|
-
message ?? (message = this.get(
|
|
1382
|
+
message ?? (message = this.get("operationSucceeded"));
|
|
1393
1383
|
this.notifier.succeed(message, undefined, callback);
|
|
1394
1384
|
}
|
|
1395
1385
|
/**
|
|
@@ -1417,17 +1407,17 @@ export class CoreApp {
|
|
|
1417
1407
|
if (!token) {
|
|
1418
1408
|
data = {
|
|
1419
1409
|
ok: false,
|
|
1420
|
-
type:
|
|
1421
|
-
field:
|
|
1422
|
-
title: this.get(
|
|
1410
|
+
type: "noData",
|
|
1411
|
+
field: "token",
|
|
1412
|
+
title: this.get("noData")
|
|
1423
1413
|
};
|
|
1424
1414
|
}
|
|
1425
1415
|
else if (result.data == null) {
|
|
1426
1416
|
data = {
|
|
1427
1417
|
ok: false,
|
|
1428
|
-
type:
|
|
1429
|
-
field:
|
|
1430
|
-
title: this.get(
|
|
1418
|
+
type: "noData",
|
|
1419
|
+
field: "user",
|
|
1420
|
+
title: this.get("noData")
|
|
1431
1421
|
};
|
|
1432
1422
|
}
|
|
1433
1423
|
else {
|
|
@@ -1444,8 +1434,7 @@ export class CoreApp {
|
|
|
1444
1434
|
this.initCall((ir) => {
|
|
1445
1435
|
if (!ir)
|
|
1446
1436
|
return;
|
|
1447
|
-
this.notifier.alert(this.get(
|
|
1448
|
-
'Environment changed', () => {
|
|
1437
|
+
this.notifier.alert(this.get("environmentChanged") ?? "Environment changed", () => {
|
|
1449
1438
|
// Callback, return true to prevent the default reload action
|
|
1450
1439
|
if (callback == null || callback() !== true) {
|
|
1451
1440
|
// Reload the page
|
|
@@ -1462,8 +1451,7 @@ export class CoreApp {
|
|
|
1462
1451
|
r = data;
|
|
1463
1452
|
}
|
|
1464
1453
|
if (callback == null || callback(r) !== true) {
|
|
1465
|
-
|
|
1466
|
-
this.notifier.alert(message, () => {
|
|
1454
|
+
this.alertResult(r, () => {
|
|
1467
1455
|
if (callback)
|
|
1468
1456
|
callback(false);
|
|
1469
1457
|
});
|
|
@@ -1494,7 +1482,7 @@ export class CoreApp {
|
|
|
1494
1482
|
async exchangeToken(api, token) {
|
|
1495
1483
|
// Avoid to call the system API
|
|
1496
1484
|
if (api.name === systemApi) {
|
|
1497
|
-
throw new Error(
|
|
1485
|
+
throw new Error("System API is not allowed to exchange token");
|
|
1498
1486
|
}
|
|
1499
1487
|
// Call the API quietly, no loading bar and no error popup
|
|
1500
1488
|
const data = await this.createAuthApi().exchangeToken({ token }, {
|
|
@@ -1526,7 +1514,7 @@ export class CoreApp {
|
|
|
1526
1514
|
* @param coreName Core system's name, default is 'core'
|
|
1527
1515
|
*/
|
|
1528
1516
|
exchangeTokenAll(coreData, coreName) {
|
|
1529
|
-
coreName ?? (coreName =
|
|
1517
|
+
coreName ?? (coreName = "core");
|
|
1530
1518
|
for (const name in this.apis) {
|
|
1531
1519
|
// Ignore the system API as it has its own logic with refreshToken
|
|
1532
1520
|
if (name === systemApi)
|
|
@@ -1677,7 +1665,7 @@ export class CoreApp {
|
|
|
1677
1665
|
// Save the current URL
|
|
1678
1666
|
this.cachedUrl = removeUrl ? undefined : globalThis.location.href;
|
|
1679
1667
|
// URL with parameters
|
|
1680
|
-
const url =
|
|
1668
|
+
const url = "/".addUrlParams(params);
|
|
1681
1669
|
this.navigate(url);
|
|
1682
1670
|
}
|
|
1683
1671
|
/**
|
|
@@ -1738,7 +1726,7 @@ export class CoreApp {
|
|
|
1738
1726
|
* @param noTrigger No trigger for state change
|
|
1739
1727
|
*/
|
|
1740
1728
|
userLogout(clearToken = true, noTrigger = false) {
|
|
1741
|
-
this.authorize(undefined, undefined, clearToken ? undefined :
|
|
1729
|
+
this.authorize(undefined, undefined, clearToken ? undefined : "");
|
|
1742
1730
|
}
|
|
1743
1731
|
/**
|
|
1744
1732
|
* 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
|