@etsoo/appscript 1.4.97 → 1.4.98

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.
@@ -264,6 +264,30 @@ test('Tests for formatResult', () => {
264
264
  );
265
265
  });
266
266
 
267
+ test('Tests for formatResult with custom label', () => {
268
+ const result: IActionResult = {
269
+ ok: false,
270
+ type: 'ItemRequired',
271
+ title: '{0} is required.',
272
+ field: 'url'
273
+ };
274
+
275
+ const formatted = app.formatResult(result, () => 'Url');
276
+ expect(formatted).toBe('Url is required. (ItemRequired, url)');
277
+ });
278
+
279
+ test('Tests for formatResult with custom label', () => {
280
+ const result: IActionResult = {
281
+ ok: false,
282
+ type: 'ItemExists',
283
+ field: 'url'
284
+ };
285
+
286
+ const fieldLabel = '文章地址';
287
+ const formatted = app.formatResult(result, () => fieldLabel);
288
+ expect(formatted).toBe(`'${fieldLabel}'已经存在 (ItemExists, url)`);
289
+ });
290
+
267
291
  test('Tests for formatError', () => {
268
292
  const error: ApiDataError = {
269
293
  name: 'ApiDataError',
@@ -7,7 +7,7 @@ import { InitCallDto } from '../erp/dto/InitCallDto';
7
7
  import { InitCallResult, InitCallResultData } from '../result/InitCallResult';
8
8
  import { IUser } from '../state/User';
9
9
  import { IAppSettings } from './AppSettings';
10
- import { IApp, IAppFields, IDetectIPCallback, NavigateOptions, RefreshTokenProps, RefreshTokenResult } from './IApp';
10
+ import { FormatResultCustomCallback, IApp, IAppFields, IDetectIPCallback, NavigateOptions, RefreshTokenProps, RefreshTokenResult } from './IApp';
11
11
  import { UserRole } from './UserRole';
12
12
  /**
13
13
  * Core application interface
@@ -229,12 +229,19 @@ export declare abstract class CoreApp<U extends IUser, S extends IAppSettings, N
229
229
  * @returns Fields
230
230
  */
231
231
  protected initCallEncryptedUpdateFields(): string[];
232
+ /**
233
+ * Alert result
234
+ * @param result Result message
235
+ * @param callback Callback
236
+ */
237
+ alertResult(result: string, callback?: NotificationReturn<void>): void;
232
238
  /**
233
239
  * Alert action result
234
- * @param result Action result or message
240
+ * @param result Action result
235
241
  * @param callback Callback
242
+ * @param forceToLocal Force to local labels
236
243
  */
237
- alertResult(result: IActionResult | string, callback?: NotificationReturn<void>): void;
244
+ alertResult(result: IActionResult, callback?: NotificationReturn<void>, forceToLocal?: FormatResultCustomCallback): void;
238
245
  /**
239
246
  * Authorize
240
247
  * @param token New token
@@ -381,12 +388,13 @@ export declare abstract class CoreApp<U extends IUser, S extends IAppSettings, N
381
388
  * @returns Message
382
389
  */
383
390
  formatRefreshTokenResult(result: RefreshTokenResult): string | undefined;
391
+ private getFieldLabel;
384
392
  /**
385
393
  * Format result text
386
394
  * @param result Action result
387
395
  * @param forceToLocal Force to local labels
388
396
  */
389
- formatResult(result: IActionResult, forceToLocal?: boolean): string;
397
+ formatResult(result: IActionResult, forceToLocal?: FormatResultCustomCallback): string;
390
398
  /**
391
399
  * Get culture resource
392
400
  * @param key key
@@ -504,13 +504,10 @@ class CoreApp {
504
504
  initCallEncryptedUpdateFields() {
505
505
  return [this.fields.headerToken];
506
506
  }
507
- /**
508
- * Alert action result
509
- * @param result Action result or message
510
- * @param callback Callback
511
- */
512
- alertResult(result, callback) {
513
- const message = typeof result === 'string' ? result : this.formatResult(result);
507
+ alertResult(result, callback, forceToLocal) {
508
+ const message = typeof result === 'string'
509
+ ? result
510
+ : this.formatResult(result, forceToLocal);
514
511
  this.notifier.alert(message, callback);
515
512
  }
516
513
  /**
@@ -939,33 +936,47 @@ class CoreApp {
939
936
  ? ActionResultError_1.ActionResultError.format(result)
940
937
  : result;
941
938
  }
939
+ getFieldLabel(field) {
940
+ return this.get(field.formatInitial(false)) ?? field;
941
+ }
942
942
  /**
943
943
  * Format result text
944
944
  * @param result Action result
945
945
  * @param forceToLocal Force to local labels
946
946
  */
947
947
  formatResult(result, forceToLocal) {
948
- const title = result.title;
949
- if (title && /^\w+$/.test(title)) {
950
- const key = title.formatInitial(false);
951
- const localTitle = this.get(key);
952
- if (localTitle) {
953
- result.title = localTitle;
954
- // Hold the original title in type when type is null
955
- if (result.type == null)
956
- result.type = title;
957
- }
948
+ // Destruct the result
949
+ const { title, type, field } = result;
950
+ const data = { title, type, field };
951
+ if (type === 'ItemExists' && field) {
952
+ // Special case
953
+ const fieldLabel = (typeof forceToLocal === 'function'
954
+ ? forceToLocal(data)
955
+ : undefined) ?? this.getFieldLabel(field);
956
+ result.title = this.get('itemExists')?.format(fieldLabel);
957
+ }
958
+ else if (title?.includes('{0}')) {
959
+ // When title contains {0}, replace with the field label
960
+ const fieldLabel = (typeof forceToLocal === 'function'
961
+ ? forceToLocal(data)
962
+ : undefined) ?? (field ? this.getFieldLabel(field) : '');
963
+ result.title = title.format(fieldLabel);
958
964
  }
959
- else if ((title == null || forceToLocal) && result.type != null) {
960
- // Get label from type
961
- const key = result.type.formatInitial(false);
962
- result.title = this.get(key);
965
+ else if (title && /^\w+$/.test(title)) {
966
+ // When title is a single word
967
+ // Hold the original title in type when type is null
968
+ if (type == null)
969
+ result.type = title;
970
+ const localTitle = (typeof forceToLocal === 'function'
971
+ ? forceToLocal(data)
972
+ : undefined) ?? this.getFieldLabel(title);
973
+ result.title = localTitle;
963
974
  }
964
- // When title contains {0}, replace with the field label
965
- if (result.field && result.title?.includes('{0}')) {
966
- const fieldLabel = this.get(result.field.formatInitial(false));
967
- if (fieldLabel)
968
- result.title = result.title.format(fieldLabel);
975
+ else if ((title == null || forceToLocal) && type != null) {
976
+ const localTitle = (typeof forceToLocal === 'function'
977
+ ? forceToLocal(data)
978
+ : undefined) ?? this.getFieldLabel(type);
979
+ result.title = localTitle;
969
980
  }
970
981
  return ActionResultError_1.ActionResultError.format(result);
971
982
  }
@@ -26,6 +26,18 @@ export interface NavigateOptions {
26
26
  * other cases means failed with differnet message
27
27
  */
28
28
  export type RefreshTokenResult = boolean | string | ApiDataError | IActionResult;
29
+ /**
30
+ * Format result custom type
31
+ */
32
+ export type FormatResultCustom = {
33
+ title?: string;
34
+ type?: string;
35
+ field?: string;
36
+ };
37
+ /**
38
+ * Format result custom callback type
39
+ */
40
+ export type FormatResultCustomCallback = ((data: FormatResultCustom) => string | null | undefined) | boolean;
29
41
  /**
30
42
  * Refresh token props
31
43
  */
@@ -147,12 +159,19 @@ export interface IApp {
147
159
  * @returns Result
148
160
  */
149
161
  addRootUrl(url: string): string;
162
+ /**
163
+ * Alert result
164
+ * @param result Result message
165
+ * @param callback Callback
166
+ */
167
+ alertResult(result: string, callback?: NotificationReturn<void>): void;
150
168
  /**
151
169
  * Alert action result
152
- * @param result Action result or message
170
+ * @param result Action result
153
171
  * @param callback Callback
172
+ * @param forceToLocal Force to local labels
154
173
  */
155
- alertResult(result: IActionResult | string, callback?: NotificationReturn<void>): void;
174
+ alertResult(result: IActionResult, callback?: NotificationReturn<void>, forceToLocal?: FormatResultCustomCallback): void;
156
175
  /**
157
176
  * Authorize
158
177
  * @param token New token
@@ -298,7 +317,7 @@ export interface IApp {
298
317
  * @param forceToLocal Force to local labels
299
318
  * @returns Message
300
319
  */
301
- formatResult(result: IActionResult, forceToLocal?: boolean): string;
320
+ formatResult(result: IActionResult, forceToLocal?: FormatResultCustomCallback): string;
302
321
  /**
303
322
  * Fresh countdown UI
304
323
  * @param callback Callback
@@ -7,7 +7,7 @@ import { InitCallDto } from '../erp/dto/InitCallDto';
7
7
  import { InitCallResult, InitCallResultData } from '../result/InitCallResult';
8
8
  import { IUser } from '../state/User';
9
9
  import { IAppSettings } from './AppSettings';
10
- import { IApp, IAppFields, IDetectIPCallback, NavigateOptions, RefreshTokenProps, RefreshTokenResult } from './IApp';
10
+ import { FormatResultCustomCallback, IApp, IAppFields, IDetectIPCallback, NavigateOptions, RefreshTokenProps, RefreshTokenResult } from './IApp';
11
11
  import { UserRole } from './UserRole';
12
12
  /**
13
13
  * Core application interface
@@ -229,12 +229,19 @@ export declare abstract class CoreApp<U extends IUser, S extends IAppSettings, N
229
229
  * @returns Fields
230
230
  */
231
231
  protected initCallEncryptedUpdateFields(): string[];
232
+ /**
233
+ * Alert result
234
+ * @param result Result message
235
+ * @param callback Callback
236
+ */
237
+ alertResult(result: string, callback?: NotificationReturn<void>): void;
232
238
  /**
233
239
  * Alert action result
234
- * @param result Action result or message
240
+ * @param result Action result
235
241
  * @param callback Callback
242
+ * @param forceToLocal Force to local labels
236
243
  */
237
- alertResult(result: IActionResult | string, callback?: NotificationReturn<void>): void;
244
+ alertResult(result: IActionResult, callback?: NotificationReturn<void>, forceToLocal?: FormatResultCustomCallback): void;
238
245
  /**
239
246
  * Authorize
240
247
  * @param token New token
@@ -381,12 +388,13 @@ export declare abstract class CoreApp<U extends IUser, S extends IAppSettings, N
381
388
  * @returns Message
382
389
  */
383
390
  formatRefreshTokenResult(result: RefreshTokenResult): string | undefined;
391
+ private getFieldLabel;
384
392
  /**
385
393
  * Format result text
386
394
  * @param result Action result
387
395
  * @param forceToLocal Force to local labels
388
396
  */
389
- formatResult(result: IActionResult, forceToLocal?: boolean): string;
397
+ formatResult(result: IActionResult, forceToLocal?: FormatResultCustomCallback): string;
390
398
  /**
391
399
  * Get culture resource
392
400
  * @param key key
@@ -501,13 +501,10 @@ export class CoreApp {
501
501
  initCallEncryptedUpdateFields() {
502
502
  return [this.fields.headerToken];
503
503
  }
504
- /**
505
- * Alert action result
506
- * @param result Action result or message
507
- * @param callback Callback
508
- */
509
- alertResult(result, callback) {
510
- const message = typeof result === 'string' ? result : this.formatResult(result);
504
+ alertResult(result, callback, forceToLocal) {
505
+ const message = typeof result === 'string'
506
+ ? result
507
+ : this.formatResult(result, forceToLocal);
511
508
  this.notifier.alert(message, callback);
512
509
  }
513
510
  /**
@@ -936,33 +933,47 @@ export class CoreApp {
936
933
  ? ActionResultError.format(result)
937
934
  : result;
938
935
  }
936
+ getFieldLabel(field) {
937
+ return this.get(field.formatInitial(false)) ?? field;
938
+ }
939
939
  /**
940
940
  * Format result text
941
941
  * @param result Action result
942
942
  * @param forceToLocal Force to local labels
943
943
  */
944
944
  formatResult(result, forceToLocal) {
945
- const title = result.title;
946
- if (title && /^\w+$/.test(title)) {
947
- const key = title.formatInitial(false);
948
- const localTitle = this.get(key);
949
- if (localTitle) {
950
- result.title = localTitle;
951
- // Hold the original title in type when type is null
952
- if (result.type == null)
953
- result.type = title;
954
- }
945
+ // Destruct the result
946
+ const { title, type, field } = result;
947
+ const data = { title, type, field };
948
+ if (type === 'ItemExists' && field) {
949
+ // Special case
950
+ const fieldLabel = (typeof forceToLocal === 'function'
951
+ ? forceToLocal(data)
952
+ : undefined) ?? this.getFieldLabel(field);
953
+ result.title = this.get('itemExists')?.format(fieldLabel);
954
+ }
955
+ else if (title?.includes('{0}')) {
956
+ // When title contains {0}, replace with the field label
957
+ const fieldLabel = (typeof forceToLocal === 'function'
958
+ ? forceToLocal(data)
959
+ : undefined) ?? (field ? this.getFieldLabel(field) : '');
960
+ result.title = title.format(fieldLabel);
955
961
  }
956
- else if ((title == null || forceToLocal) && result.type != null) {
957
- // Get label from type
958
- const key = result.type.formatInitial(false);
959
- result.title = this.get(key);
962
+ else if (title && /^\w+$/.test(title)) {
963
+ // When title is a single word
964
+ // Hold the original title in type when type is null
965
+ if (type == null)
966
+ result.type = title;
967
+ const localTitle = (typeof forceToLocal === 'function'
968
+ ? forceToLocal(data)
969
+ : undefined) ?? this.getFieldLabel(title);
970
+ result.title = localTitle;
960
971
  }
961
- // When title contains {0}, replace with the field label
962
- if (result.field && result.title?.includes('{0}')) {
963
- const fieldLabel = this.get(result.field.formatInitial(false));
964
- if (fieldLabel)
965
- result.title = result.title.format(fieldLabel);
972
+ else if ((title == null || forceToLocal) && type != null) {
973
+ const localTitle = (typeof forceToLocal === 'function'
974
+ ? forceToLocal(data)
975
+ : undefined) ?? this.getFieldLabel(type);
976
+ result.title = localTitle;
966
977
  }
967
978
  return ActionResultError.format(result);
968
979
  }
@@ -26,6 +26,18 @@ export interface NavigateOptions {
26
26
  * other cases means failed with differnet message
27
27
  */
28
28
  export type RefreshTokenResult = boolean | string | ApiDataError | IActionResult;
29
+ /**
30
+ * Format result custom type
31
+ */
32
+ export type FormatResultCustom = {
33
+ title?: string;
34
+ type?: string;
35
+ field?: string;
36
+ };
37
+ /**
38
+ * Format result custom callback type
39
+ */
40
+ export type FormatResultCustomCallback = ((data: FormatResultCustom) => string | null | undefined) | boolean;
29
41
  /**
30
42
  * Refresh token props
31
43
  */
@@ -147,12 +159,19 @@ export interface IApp {
147
159
  * @returns Result
148
160
  */
149
161
  addRootUrl(url: string): string;
162
+ /**
163
+ * Alert result
164
+ * @param result Result message
165
+ * @param callback Callback
166
+ */
167
+ alertResult(result: string, callback?: NotificationReturn<void>): void;
150
168
  /**
151
169
  * Alert action result
152
- * @param result Action result or message
170
+ * @param result Action result
153
171
  * @param callback Callback
172
+ * @param forceToLocal Force to local labels
154
173
  */
155
- alertResult(result: IActionResult | string, callback?: NotificationReturn<void>): void;
174
+ alertResult(result: IActionResult, callback?: NotificationReturn<void>, forceToLocal?: FormatResultCustomCallback): void;
156
175
  /**
157
176
  * Authorize
158
177
  * @param token New token
@@ -298,7 +317,7 @@ export interface IApp {
298
317
  * @param forceToLocal Force to local labels
299
318
  * @returns Message
300
319
  */
301
- formatResult(result: IActionResult, forceToLocal?: boolean): string;
320
+ formatResult(result: IActionResult, forceToLocal?: FormatResultCustomCallback): string;
302
321
  /**
303
322
  * Fresh countdown UI
304
323
  * @param callback Callback
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/appscript",
3
- "version": "1.4.97",
3
+ "version": "1.4.98",
4
4
  "description": "Applications shared TypeScript framework",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -32,6 +32,7 @@ import { IUser } from '../state/User';
32
32
  import { IAppSettings } from './AppSettings';
33
33
  import {
34
34
  appFields,
35
+ FormatResultCustomCallback,
35
36
  IApp,
36
37
  IAppFields,
37
38
  IDetectIPCallback,
@@ -752,17 +753,34 @@ export abstract class CoreApp<
752
753
  return [this.fields.headerToken];
753
754
  }
754
755
 
756
+ /**
757
+ * Alert result
758
+ * @param result Result message
759
+ * @param callback Callback
760
+ */
761
+ alertResult(result: string, callback?: NotificationReturn<void>): void;
762
+
755
763
  /**
756
764
  * Alert action result
757
- * @param result Action result or message
765
+ * @param result Action result
758
766
  * @param callback Callback
767
+ * @param forceToLocal Force to local labels
759
768
  */
769
+ alertResult(
770
+ result: IActionResult,
771
+ callback?: NotificationReturn<void>,
772
+ forceToLocal?: FormatResultCustomCallback
773
+ ): void;
774
+
760
775
  alertResult(
761
776
  result: IActionResult | string,
762
- callback?: NotificationReturn<void>
777
+ callback?: NotificationReturn<void>,
778
+ forceToLocal?: FormatResultCustomCallback
763
779
  ) {
764
780
  const message =
765
- typeof result === 'string' ? result : this.formatResult(result);
781
+ typeof result === 'string'
782
+ ? result
783
+ : this.formatResult(result, forceToLocal);
766
784
  this.notifier.alert(message, callback);
767
785
  }
768
786
 
@@ -1307,32 +1325,53 @@ export abstract class CoreApp<
1307
1325
  : result;
1308
1326
  }
1309
1327
 
1328
+ private getFieldLabel(field: string) {
1329
+ return this.get(field.formatInitial(false)) ?? field;
1330
+ }
1331
+
1310
1332
  /**
1311
1333
  * Format result text
1312
1334
  * @param result Action result
1313
1335
  * @param forceToLocal Force to local labels
1314
1336
  */
1315
- formatResult(result: IActionResult, forceToLocal?: boolean) {
1316
- const title = result.title;
1317
- if (title && /^\w+$/.test(title)) {
1318
- const key = title.formatInitial(false);
1319
- const localTitle = this.get(key);
1320
- if (localTitle) {
1321
- result.title = localTitle;
1322
-
1323
- // Hold the original title in type when type is null
1324
- if (result.type == null) result.type = title;
1325
- }
1326
- } else if ((title == null || forceToLocal) && result.type != null) {
1327
- // Get label from type
1328
- const key = result.type.formatInitial(false);
1329
- result.title = this.get(key);
1330
- }
1331
-
1332
- // When title contains {0}, replace with the field label
1333
- if (result.field && result.title?.includes('{0}')) {
1334
- const fieldLabel = this.get(result.field.formatInitial(false));
1335
- if (fieldLabel) result.title = result.title.format(fieldLabel);
1337
+ formatResult(
1338
+ result: IActionResult,
1339
+ forceToLocal?: FormatResultCustomCallback
1340
+ ) {
1341
+ // Destruct the result
1342
+ const { title, type, field } = result;
1343
+ const data = { title, type, field };
1344
+
1345
+ if (type === 'ItemExists' && field) {
1346
+ // Special case
1347
+ const fieldLabel =
1348
+ (typeof forceToLocal === 'function'
1349
+ ? forceToLocal(data)
1350
+ : undefined) ?? this.getFieldLabel(field);
1351
+ result.title = this.get('itemExists')?.format(fieldLabel);
1352
+ } else if (title?.includes('{0}')) {
1353
+ // When title contains {0}, replace with the field label
1354
+ const fieldLabel =
1355
+ (typeof forceToLocal === 'function'
1356
+ ? forceToLocal(data)
1357
+ : undefined) ?? (field ? this.getFieldLabel(field) : '');
1358
+
1359
+ result.title = title.format(fieldLabel);
1360
+ } else if (title && /^\w+$/.test(title)) {
1361
+ // When title is a single word
1362
+ // Hold the original title in type when type is null
1363
+ if (type == null) result.type = title;
1364
+ const localTitle =
1365
+ (typeof forceToLocal === 'function'
1366
+ ? forceToLocal(data)
1367
+ : undefined) ?? this.getFieldLabel(title);
1368
+ result.title = localTitle;
1369
+ } else if ((title == null || forceToLocal) && type != null) {
1370
+ const localTitle =
1371
+ (typeof forceToLocal === 'function'
1372
+ ? forceToLocal(data)
1373
+ : undefined) ?? this.getFieldLabel(type);
1374
+ result.title = localTitle;
1336
1375
  }
1337
1376
 
1338
1377
  return ActionResultError.format(result);
package/src/app/IApp.ts CHANGED
@@ -49,6 +49,22 @@ export type RefreshTokenResult =
49
49
  | ApiDataError
50
50
  | IActionResult;
51
51
 
52
+ /**
53
+ * Format result custom type
54
+ */
55
+ export type FormatResultCustom = {
56
+ title?: string;
57
+ type?: string;
58
+ field?: string;
59
+ };
60
+
61
+ /**
62
+ * Format result custom callback type
63
+ */
64
+ export type FormatResultCustomCallback =
65
+ | ((data: FormatResultCustom) => string | null | undefined)
66
+ | boolean;
67
+
52
68
  /**
53
69
  * Refresh token props
54
70
  */
@@ -201,14 +217,23 @@ export interface IApp {
201
217
  */
202
218
  addRootUrl(url: string): string;
203
219
 
220
+ /**
221
+ * Alert result
222
+ * @param result Result message
223
+ * @param callback Callback
224
+ */
225
+ alertResult(result: string, callback?: NotificationReturn<void>): void;
226
+
204
227
  /**
205
228
  * Alert action result
206
- * @param result Action result or message
229
+ * @param result Action result
207
230
  * @param callback Callback
231
+ * @param forceToLocal Force to local labels
208
232
  */
209
233
  alertResult(
210
- result: IActionResult | string,
211
- callback?: NotificationReturn<void>
234
+ result: IActionResult,
235
+ callback?: NotificationReturn<void>,
236
+ forceToLocal?: FormatResultCustomCallback
212
237
  ): void;
213
238
 
214
239
  /**
@@ -410,7 +435,10 @@ export interface IApp {
410
435
  * @param forceToLocal Force to local labels
411
436
  * @returns Message
412
437
  */
413
- formatResult(result: IActionResult, forceToLocal?: boolean): string;
438
+ formatResult(
439
+ result: IActionResult,
440
+ forceToLocal?: FormatResultCustomCallback
441
+ ): string;
414
442
 
415
443
  /**
416
444
  * Fresh countdown UI