@quanticdigit/web-errors 1.0.1 → 1.0.3
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/README.md
CHANGED
|
@@ -1,64 +1,87 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @quanticdigit/web-errors
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Error collection and presentation: level aggregation, a localized dialog in 31 languages, pluggable
|
|
4
|
+
presenter.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
This is the implementation of `IErrorInfoAppender`, which `@quanticdigit/web-services` declares and
|
|
7
|
+
does not provide. The service layer knows **that** something went wrong; this knows **how to say it**.
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
## Install
|
|
8
10
|
|
|
9
11
|
```bash
|
|
10
|
-
|
|
12
|
+
npm install @quanticdigit/web-errors @quanticdigit/web-services
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
Peer dependencies: `@angular/core`, `devextreme`, `@quanticdigit/web-services`,
|
|
16
|
+
`@quanticdigit/web-logging`.
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
ng generate --help
|
|
17
|
-
```
|
|
18
|
+
## Use it
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
`ErrorCollector` is `providedIn: 'root'`. Hand it to any service call:
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
```ts
|
|
23
|
+
export class UserPage {
|
|
24
|
+
private readonly errors = inject(ErrorCollector);
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
load(): void {
|
|
27
|
+
this.users.byId(7, this.errors).subscribe((user) => …);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
25
30
|
```
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
Errors raised in the same turn are gathered into **one** dialog. Three failing calls produce three
|
|
33
|
+
lines, not three windows the user closes without reading.
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
## It already speaks your language
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
The texts ship with the package in the same 31 languages DevExtreme covers, so the dialog does not
|
|
38
|
+
come out in English surrounded by translated components. Nothing to configure.
|
|
32
39
|
|
|
33
|
-
|
|
40
|
+
## Three levels of customization
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
cd dist/web-errors
|
|
37
|
-
```
|
|
42
|
+
Nothing is mandatory. In order of weight:
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
npm publish
|
|
42
|
-
```
|
|
44
|
+
**One text.** Load that key into your own DevExtreme catalogue; it wins over the built-in one, and
|
|
45
|
+
the other seven stay as they are.
|
|
43
46
|
|
|
44
|
-
|
|
47
|
+
```ts
|
|
48
|
+
loadMessages({ it: { dialogTitleError: 'Ops' } });
|
|
49
|
+
```
|
|
45
50
|
|
|
46
|
-
|
|
51
|
+
**The window.** Declare `ERROR_PRESENTER` and ours is never even built.
|
|
47
52
|
|
|
48
|
-
```
|
|
49
|
-
|
|
53
|
+
```ts
|
|
54
|
+
{ provide: ERROR_PRESENTER, useValue: (p) => myDialog(p.title, p.message, p.errors) }
|
|
50
55
|
```
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
For end-to-end (e2e) testing, run:
|
|
57
|
+
To keep the default and add to it, wrap the exported one:
|
|
55
58
|
|
|
56
|
-
```
|
|
57
|
-
|
|
59
|
+
```ts
|
|
60
|
+
{ provide: ERROR_PRESENTER, useValue: (p) => { telemetry(p); devExtremeDialogPresenter(p); } }
|
|
58
61
|
```
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
**Everything.** Implement `IErrorInfoAppender` yourself and this package is not needed.
|
|
64
|
+
|
|
65
|
+
## A note on messages
|
|
66
|
+
|
|
67
|
+
`IErrorInfoModel.message` carries whatever the server put there. In products that resolve errors
|
|
68
|
+
through a copy catalogue it is a **key**, not a sentence: resolve it before handing it over, or the
|
|
69
|
+
key is what the user reads.
|
|
70
|
+
|
|
71
|
+
## It logs what it shows
|
|
72
|
+
|
|
73
|
+
`ErrorCollector` is wired to `@quanticdigit/web-logging`. Declare `APPLICATION_LOG_WRITER` and every
|
|
74
|
+
error it receives is also written under `errors.http`, with the level it came in at, the call that
|
|
75
|
+
produced it and the body that was posted.
|
|
76
|
+
|
|
77
|
+
An error shown to a user is one somebody will want to reconstruct later, when neither the dialog nor
|
|
78
|
+
the person who was looking at it is around.
|
|
79
|
+
|
|
80
|
+
## The family
|
|
81
|
+
|
|
82
|
+
`web-utils`, `web-model`, `web-services`, `web-component`, `web-errors` and `web-logging` are released
|
|
83
|
+
together and always share the same version. Install them at the same version.
|
|
61
84
|
|
|
62
|
-
##
|
|
85
|
+
## License
|
|
63
86
|
|
|
64
|
-
|
|
87
|
+
Commercial. See `LICENSE.txt` in the package.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, inject, Injectable } from '@angular/core';
|
|
3
|
+
import { ApplicationLogger, APPLICATION_LOG_WRITER, safeValue } from '@quanticdigit/web-logging';
|
|
3
4
|
import { custom } from 'devextreme/ui/dialog';
|
|
4
5
|
import { formatMessage, locale } from 'devextreme/localization';
|
|
5
6
|
import { LogLevel } from '@quanticdigit/web-services';
|
|
@@ -27,7 +28,7 @@ const ErrorCopyKeys = {
|
|
|
27
28
|
buttonClose: 'dialogLabelbtnClose',
|
|
28
29
|
};
|
|
29
30
|
/** Comodita' interna: compone le otto voci di una lingua nell'ordine dichiarato. */
|
|
30
|
-
const
|
|
31
|
+
const entries = (titleInfo, titleWarning, titleError, titleFatal, messageWarning, messageError, messageFatal, buttonClose) => ({
|
|
31
32
|
[ErrorCopyKeys.titleInfo]: titleInfo,
|
|
32
33
|
[ErrorCopyKeys.titleWarning]: titleWarning,
|
|
33
34
|
[ErrorCopyKeys.titleError]: titleError,
|
|
@@ -67,37 +68,37 @@ const voci = (titleInfo, titleWarning, titleError, titleFatal, messageWarning, m
|
|
|
67
68
|
* professionale, e vanno riviste da chi la lingua la parla prima di distribuire in quel mercato.
|
|
68
69
|
*/
|
|
69
70
|
const DEFAULT_ERROR_MESSAGES = {
|
|
70
|
-
ar:
|
|
71
|
-
bg:
|
|
72
|
-
ca:
|
|
73
|
-
cs:
|
|
74
|
-
da:
|
|
75
|
-
de:
|
|
76
|
-
el:
|
|
77
|
-
en:
|
|
78
|
-
es:
|
|
79
|
-
fa:
|
|
80
|
-
fi:
|
|
81
|
-
fr:
|
|
82
|
-
hu:
|
|
83
|
-
it:
|
|
84
|
-
ja:
|
|
85
|
-
ko:
|
|
86
|
-
lt:
|
|
87
|
-
lv:
|
|
88
|
-
nb:
|
|
89
|
-
nl:
|
|
90
|
-
pl:
|
|
91
|
-
pt:
|
|
92
|
-
ro:
|
|
93
|
-
ru:
|
|
94
|
-
sl:
|
|
95
|
-
sv:
|
|
96
|
-
tr:
|
|
97
|
-
uk:
|
|
98
|
-
vi:
|
|
99
|
-
zh:
|
|
100
|
-
'zh-tw':
|
|
71
|
+
ar: entries('معلومات', 'تحذير', 'خطأ', 'خطأ في التطبيق', 'يرجى مراجعة التحذيرات التالية.', 'لم تكتمل العملية.', 'حدث خطأ غير متوقع.', 'إغلاق'),
|
|
72
|
+
bg: entries('Информация', 'Предупреждение', 'Грешка', 'Грешка в приложението', 'Моля, прегледайте следните предупреждения.', 'Операцията не беше завършена.', 'Възникна неочаквана грешка.', 'Затвори'),
|
|
73
|
+
ca: entries('Informació', 'Avís', 'Error', 'Error d’aplicació', 'Reviseu els avisos següents.', 'L’operació no s’ha completat.', 'S’ha produït un error inesperat.', 'Tanca'),
|
|
74
|
+
cs: entries('Informace', 'Upozornění', 'Chyba', 'Chyba aplikace', 'Zkontrolujte následující upozornění.', 'Operace nebyla dokončena.', 'Došlo k neočekávané chybě.', 'Zavřít'),
|
|
75
|
+
da: entries('Information', 'Advarsel', 'Fejl', 'Programfejl', 'Genentrygå følgende advarsler.', 'Handlingen blev ikke genentryført.', 'Der opstod en uventet fejl.', 'Luk'),
|
|
76
|
+
de: entries('Information', 'Warnung', 'Fehler', 'Anwendungsfehler', 'Bitte beachten Sie die folgenden Warnungen.', 'Der Vorgang wurde nicht abgeschlossen.', 'Ein unerwarteter Fehler ist aufgetreten.', 'Schließen'),
|
|
77
|
+
el: entries('Πληροφορίες', 'Προειδοποίηση', 'Σφάλμα', 'Σφάλμα εφαρμογής', 'Ελέγξτε τις παρακάτω προειδοποιήσεις.', 'Η ενέργεια δεν ολοκληρώθηκε.', 'Παρουσιάστηκε απροσδόκητο σφάλμα.', 'Κλείσιμο'),
|
|
78
|
+
en: entries('Information', 'Warning', 'Error', 'Application error', 'Please review the following warnings.', 'The operation was not completed.', 'An unexpected error occurred.', 'Close'),
|
|
79
|
+
es: entries('Información', 'Aviso', 'Error', 'Error de aplicación', 'Revise las siguientes advertencias.', 'La operación no se ha completado.', 'Se ha producido un error inesperado.', 'Cerrar'),
|
|
80
|
+
fa: entries('اطلاعات', 'هشدار', 'خطا', 'خطای برنامه', 'لطفاً هشدارهای زیر را بررسی کنید.', 'عملیات کامل نشد.', 'خطای غیرمنتظرهای رخ داد.', 'بستن'),
|
|
81
|
+
fi: entries('Tiedot', 'Varoitus', 'Virhe', 'Sovellusvirhe', 'Tarkista seuraavat varoitukset.', 'Toimintoa ei suoritettu loppuun.', 'Tapahtui odottamaton virhe.', 'Sulje'),
|
|
82
|
+
fr: entries('Informations', 'Avertissement', 'Erreur', 'Erreur applicative', 'Veuillez prendre connaissance des avertissements suivants.', 'L’opération n’a pas été effectuée.', 'Une erreur inattendue est survenue.', 'Fermer'),
|
|
83
|
+
hu: entries('Információ', 'Figyelmeztetés', 'Hiba', 'Alkalmazáshiba', 'Tekintse át az alábbi figyelmeztetéseket.', 'A művelet entry fejeződött be.', 'Váratlan hiba történt.', 'Bezárás'),
|
|
84
|
+
it: entries('Informazioni', 'Avviso', 'Errore', 'Errore applicativo', 'Prendere visione dei seguenti avvisi.', 'L’operazione non è stata completata.', 'Si è verificato un errore imprevisto.', 'Chiudi'),
|
|
85
|
+
ja: entries('情報', '警告', 'エラー', 'アプリケーションエラー', '次の警告をご確認ください。', '操作は完了しませんでした。', '予期しないエラーが発生しました。', '閉じる'),
|
|
86
|
+
ko: entries('정보', '경고', '오류', '애플리케이션 오류', '다음 경고를 확인하십시오.', '작업이 완료되지 않았습니다.', '예기치 않은 오류가 발생했습니다.', '닫기'),
|
|
87
|
+
lt: entries('Informacija', 'Įspėjimas', 'Klaida', 'Programos klaida', 'Peržiūrėkite šiuos įspėjimus.', 'Operacija nebuvo baigta.', 'Įvyko netikėta klaida.', 'Uždaryti'),
|
|
88
|
+
lv: entries('Informācija', 'Brīdinājums', 'Kļūda', 'Lietojumprogrammas kļūda', 'Lūdzu, pārskatiet tālāk norādītos brīdinājumus.', 'Darbība netika pabeigta.', 'Radās neparedzēta kļūda.', 'Aizvērt'),
|
|
89
|
+
nb: entries('Informasjon', 'Advarsel', 'Feil', 'Programfeil', 'Se gjennom følgende advarsler.', 'Handlingen ble ikke fullført.', 'Det oppstod en uventet feil.', 'Lukk'),
|
|
90
|
+
nl: entries('Informatie', 'Waarschuwing', 'Fout', 'Toepassingsfout', 'Bekijk de volgende waarschuwingen.', 'De bewerking is niet voltooid.', 'Er is een onverwachte fout opgetreden.', 'Sluiten'),
|
|
91
|
+
pl: entries('Informacja', 'Ostrzeżenie', 'Błąd', 'Błąd aplikacji', 'Zapoznaj się z poniższymi ostrzeżeniami.', 'Operacja nie została ukończona.', 'Wystąpił nieoczekiwany błąd.', 'Zamknij'),
|
|
92
|
+
pt: entries('Informação', 'Aviso', 'Erro', 'Erro da aplicação', 'Consulte os avisos seguintes.', 'A operação não foi concluída.', 'Ocorreu um erro inesperado.', 'Fechar'),
|
|
93
|
+
ro: entries('Informații', 'Avertisment', 'Eroare', 'Eroare de aplicație', 'Consultați următoarele avertismente.', 'Operațiunea nu a fost finalizată.', 'A apărut o eroare neașteptată.', 'Închide'),
|
|
94
|
+
ru: entries('Информация', 'Предупреждение', 'Ошибка', 'Ошибка приложения', 'Ознакомьтесь со следующими предупреждениями.', 'Операция не была завершена.', 'Произошла непредвиденная ошибка.', 'Закрыть'),
|
|
95
|
+
sl: entries('Informacije', 'Opozorilo', 'Napaka', 'Napaka aplikacije', 'Preglejte naslednja opozorila.', 'Dejanje ni bilo dokončano.', 'Prišlo je do nepričakovane napake.', 'Zapri'),
|
|
96
|
+
sv: entries('Information', 'Varning', 'Fel', 'Programfel', 'Granska följande varningar.', 'Åtgärden slutfördes inte.', 'Ett oväntat fel inträffade.', 'Stäng'),
|
|
97
|
+
tr: entries('Bilgi', 'Uyarı', 'Hata', 'Uygulama hatası', 'Lütfen aşağıdaki uyarıları inceleyin.', 'İşlem tamamlanmadı.', 'Beklenmeyen bir hata oluştu.', 'Kapat'),
|
|
98
|
+
uk: entries('Інформація', 'Попередження', 'Помилка', 'Помилка застосунку', 'Перегляньте наведені нижче попередження.', 'Операцію не завершено.', 'Сталася неочікувана помилка.', 'Закрити'),
|
|
99
|
+
vi: entries('Thông tin', 'Cảnh báo', 'Lỗi', 'Lỗi ứng dụng', 'Vui lòng xem các cảnh báo sau.', 'Thao tác chưa được hoàn tất.', 'Đã xảy ra lỗi không mong muốn.', 'Đóng'),
|
|
100
|
+
zh: entries('信息', '警告', '错误', '应用程序错误', '请查看以下警告。', '操作未完成。', '发生意外错误。', '关闭'),
|
|
101
|
+
'zh-tw': entries('資訊', '警告', '錯誤', '應用程式錯誤', '請檢視下列警告。', '作業未完成。', '發生未預期的錯誤。', '關閉'),
|
|
101
102
|
};
|
|
102
103
|
/** La lingua di ripiego quando quella corrente non e' fra quelle previste. */
|
|
103
104
|
const FALLBACK_LANGUAGE = 'en';
|
|
@@ -139,18 +140,18 @@ function manageFormCssClassIcons(level) {
|
|
|
139
140
|
* mancanza che si nota.
|
|
140
141
|
*/
|
|
141
142
|
function resolve(key) {
|
|
142
|
-
const
|
|
143
|
-
if (
|
|
144
|
-
return
|
|
143
|
+
const fromProduct = formatMessage(key);
|
|
144
|
+
if (fromProduct != null && fromProduct !== '') {
|
|
145
|
+
return fromProduct;
|
|
145
146
|
}
|
|
146
147
|
// Prima la lingua COMPLETA, poi la sola parte di lingua. L'ordine conta: `zh-tw` e `zh` sono
|
|
147
148
|
// due dizionari diversi — cinese tradizionale e semplificato — e guardare subito la sola parte di
|
|
148
149
|
// lingua renderebbe il primo irraggiungibile. `it-IT` invece non ha un dizionario proprio e
|
|
149
150
|
// ricade su `it`, che e' il comportamento voluto.
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
return (DEFAULT_ERROR_MESSAGES[
|
|
153
|
-
DEFAULT_ERROR_MESSAGES[
|
|
151
|
+
const fullLanguage = (locale() ?? FALLBACK_LANGUAGE).toLowerCase();
|
|
152
|
+
const languageOnly = fullLanguage.split('-')[0];
|
|
153
|
+
return (DEFAULT_ERROR_MESSAGES[fullLanguage]?.[key] ??
|
|
154
|
+
DEFAULT_ERROR_MESSAGES[languageOnly]?.[key] ??
|
|
154
155
|
DEFAULT_ERROR_MESSAGES[FALLBACK_LANGUAGE]?.[key] ??
|
|
155
156
|
key);
|
|
156
157
|
}
|
|
@@ -237,15 +238,15 @@ function buttonText(key) {
|
|
|
237
238
|
* ```
|
|
238
239
|
*/
|
|
239
240
|
const devExtremeDialogPresenter = (presentation) => {
|
|
240
|
-
const
|
|
241
|
-
.map((e) => `<li class="${manageFormCssClassIcons(e.level)}">${
|
|
241
|
+
const lines = presentation.errors
|
|
242
|
+
.map((e) => `<li class="${manageFormCssClassIcons(e.level)}">${text(e.message, e.id)}</li>`)
|
|
242
243
|
.join('');
|
|
243
|
-
const
|
|
244
|
+
const dialog = custom({
|
|
244
245
|
title: presentation.title,
|
|
245
|
-
messageHtml: `<p>${presentation.message}</p><ul>${
|
|
246
|
+
messageHtml: `<p>${presentation.message}</p><ul>${lines}</ul>`,
|
|
246
247
|
buttons: [{ text: buttonText(ErrorCopyKeys.buttonClose) }],
|
|
247
248
|
});
|
|
248
|
-
void
|
|
249
|
+
void dialog.show();
|
|
249
250
|
};
|
|
250
251
|
/**
|
|
251
252
|
* Il testo di una riga.
|
|
@@ -256,11 +257,15 @@ const devExtremeDialogPresenter = (presentation) => {
|
|
|
256
257
|
* oppure mostrera' la chiave. La chiave mostrata e' una mancanza visibile, preferibile a un testo
|
|
257
258
|
* inventato dal pacchetto.
|
|
258
259
|
*/
|
|
259
|
-
function
|
|
260
|
-
const
|
|
261
|
-
return `${message ?? ''}${
|
|
260
|
+
function text(message, id) {
|
|
261
|
+
const identifier = id != null && id !== 0 ? ` [${id}]` : '';
|
|
262
|
+
return `${message ?? ''}${identifier}`;
|
|
262
263
|
}
|
|
263
264
|
|
|
265
|
+
/** I tre caratteri dell'envelope sono gia' codici di livello: tutto il resto e' un errore. */
|
|
266
|
+
function logLevelOf(type) {
|
|
267
|
+
return type === 'W' || type === 'E' || type === 'F' ? type : 'E';
|
|
268
|
+
}
|
|
264
269
|
/**
|
|
265
270
|
* Raccoglie gli errori di una chiamata e li mostra all'utente.
|
|
266
271
|
*
|
|
@@ -280,7 +285,7 @@ function testo(message, id) {
|
|
|
280
285
|
*/
|
|
281
286
|
class ErrorCollector {
|
|
282
287
|
/** Quanto si aspetta prima di mostrare, per raccogliere cio' che arriva nello stesso giro. */
|
|
283
|
-
static
|
|
288
|
+
static WAIT_MS = 0;
|
|
284
289
|
/**
|
|
285
290
|
* Come mostrare, quando il modo base non va bene.
|
|
286
291
|
*
|
|
@@ -290,12 +295,21 @@ class ErrorCollector {
|
|
|
290
295
|
* quel caso la nostra non viene nemmeno costruita.
|
|
291
296
|
*/
|
|
292
297
|
presenter = inject(ERROR_PRESENTER, { optional: true });
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
298
|
+
/**
|
|
299
|
+
* Il log applicativo, sotto `errors`.
|
|
300
|
+
*
|
|
301
|
+
* @remarks
|
|
302
|
+
* Un errore mostrato all'utente e' un errore che qualcuno vorra' ricostruire dopo, quando la
|
|
303
|
+
* finestra e la persona che la stava guardando non ci sono piu'. Senza writer dichiarato non
|
|
304
|
+
* accade nulla, come ovunque nel resto della famiglia.
|
|
305
|
+
*/
|
|
306
|
+
appLogger = new ApplicationLogger(inject(APPLICATION_LOG_WRITER, { optional: true }), 'errors');
|
|
307
|
+
collected = [];
|
|
308
|
+
level = LogLevel.Info;
|
|
309
|
+
scheduled = false;
|
|
296
310
|
/** Gli errori non ancora mostrati. */
|
|
297
311
|
get messages() {
|
|
298
|
-
return this.
|
|
312
|
+
return this.collected;
|
|
299
313
|
}
|
|
300
314
|
/**
|
|
301
315
|
* Prende in carico gli errori di una chiamata.
|
|
@@ -309,19 +323,20 @@ class ErrorCollector {
|
|
|
309
323
|
if (errors == null || errors.length === 0) {
|
|
310
324
|
return;
|
|
311
325
|
}
|
|
312
|
-
const
|
|
313
|
-
if (
|
|
314
|
-
this.
|
|
326
|
+
const level = levelOf(type);
|
|
327
|
+
if (level > this.level) {
|
|
328
|
+
this.level = level;
|
|
315
329
|
}
|
|
316
|
-
for (const
|
|
317
|
-
this.
|
|
330
|
+
for (const error of errors) {
|
|
331
|
+
this.collected.push(error);
|
|
332
|
+
this.appLogger.log(logLevelOf(type), 'http', error.message, { id: error.id, level: error.level, isBusiness: error.isBusiness, url, post: safeValue(post) }, error.trace);
|
|
318
333
|
}
|
|
319
|
-
this.
|
|
334
|
+
this.schedule();
|
|
320
335
|
};
|
|
321
336
|
/** Dimentica cio' che non e' stato mostrato. */
|
|
322
337
|
clear() {
|
|
323
|
-
this.
|
|
324
|
-
this.
|
|
338
|
+
this.collected.length = 0;
|
|
339
|
+
this.level = LogLevel.Info;
|
|
325
340
|
}
|
|
326
341
|
/**
|
|
327
342
|
* Programma la presentazione per la fine del giro corrente.
|
|
@@ -329,33 +344,33 @@ class ErrorCollector {
|
|
|
329
344
|
* Tre chiamate fallite nello stesso istante producono una finestra sola con tre righe, non tre
|
|
330
345
|
* finestre: e' la ragione per cui la presentazione non e' immediata.
|
|
331
346
|
*/
|
|
332
|
-
|
|
333
|
-
if (this.
|
|
347
|
+
schedule() {
|
|
348
|
+
if (this.scheduled) {
|
|
334
349
|
return;
|
|
335
350
|
}
|
|
336
|
-
this.
|
|
337
|
-
setTimeout(() => this.
|
|
351
|
+
this.scheduled = true;
|
|
352
|
+
setTimeout(() => this.present(), ErrorCollector.WAIT_MS);
|
|
338
353
|
}
|
|
339
354
|
/** Mostra quanto accumulato e svuota. */
|
|
340
|
-
|
|
341
|
-
this.
|
|
342
|
-
if (this.
|
|
355
|
+
present() {
|
|
356
|
+
this.scheduled = false;
|
|
357
|
+
if (this.collected.length === 0) {
|
|
343
358
|
return;
|
|
344
359
|
}
|
|
345
|
-
const
|
|
346
|
-
level: this.
|
|
347
|
-
title: levelTitle(this.
|
|
348
|
-
message: levelMessage(this.
|
|
360
|
+
const presentation = {
|
|
361
|
+
level: this.level,
|
|
362
|
+
title: levelTitle(this.level),
|
|
363
|
+
message: levelMessage(this.level),
|
|
349
364
|
// Una copia: si svuota subito dopo, e chi presenta deve poter leggere con calma.
|
|
350
|
-
errors: [...this.
|
|
365
|
+
errors: [...this.collected],
|
|
351
366
|
};
|
|
352
367
|
this.clear();
|
|
353
368
|
// Se qualcuno ha dichiarato come mostrare, la nostra finestra non viene nemmeno costruita.
|
|
354
369
|
if (this.presenter != null) {
|
|
355
|
-
this.presenter(
|
|
370
|
+
this.presenter(presentation);
|
|
356
371
|
return;
|
|
357
372
|
}
|
|
358
|
-
devExtremeDialogPresenter(
|
|
373
|
+
devExtremeDialogPresenter(presentation);
|
|
359
374
|
}
|
|
360
375
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: ErrorCollector, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
361
376
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: ErrorCollector, providedIn: 'root' });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quanticdigit-web-errors.mjs","sources":["../../../projects/web-errors/src/lib/error-messages.ts","../../../projects/web-errors/src/lib/error-presentation.ts","../../../projects/web-errors/src/lib/error-dialog.ts","../../../projects/web-errors/src/lib/error-collector.ts","../../../projects/web-errors/src/public-api.ts","../../../projects/web-errors/src/quanticdigit-web-errors.ts"],"sourcesContent":["/**\n * Le chiavi di testo che questo pacchetto usa.\n *\n * @remarks\n * <b>Sono il contratto.</b> Il pacchetto porta con se' i testi predefiniti in piu' lingue — vedi\n * {@link DEFAULT_ERROR_MESSAGES} — e un prodotto ne sovrascrive una qualsiasi caricandola nel\n * proprio catalogo di DevExtreme con `loadMessages`: quello del prodotto vince sempre.\n *\n * Stanno qui e non accanto a chi le risolve per rompere un ciclo fra moduli: i testi hanno bisogno\n * delle chiavi, e chi risolve ha bisogno di entrambi.\n */\nexport const ErrorCopyKeys = {\n titleInfo: 'dialogTitleInfo',\n titleWarning: 'dialogTitleWarning',\n titleError: 'dialogTitleError',\n titleFatal: 'dialogTitleFatal',\n messageWarning: 'dialogMessageWarning',\n messageError: 'dialogMessageError',\n messageFatal: 'dialogMessageFatal',\n buttonClose: 'dialogLabelbtnClose',\n} as const;\n\n/** Comodita' interna: compone le otto voci di una lingua nell'ordine dichiarato. */\nconst voci = (\n titleInfo: string,\n titleWarning: string,\n titleError: string,\n titleFatal: string,\n messageWarning: string,\n messageError: string,\n messageFatal: string,\n buttonClose: string,\n): Readonly<Record<string, string>> => ({\n [ErrorCopyKeys.titleInfo]: titleInfo,\n [ErrorCopyKeys.titleWarning]: titleWarning,\n [ErrorCopyKeys.titleError]: titleError,\n [ErrorCopyKeys.titleFatal]: titleFatal,\n [ErrorCopyKeys.messageWarning]: messageWarning,\n [ErrorCopyKeys.messageError]: messageError,\n [ErrorCopyKeys.messageFatal]: messageFatal,\n [ErrorCopyKeys.buttonClose]: buttonClose,\n});\n\n/**\n * I testi predefiniti della finestra degli errori.\n *\n * @remarks\n * <b>Perche' stanno nel pacchetto.</b> E' il modello dei componenti DevExtreme: un calendario porta\n * dentro di se' i nomi dei mesi in tutte le lingue, e chi non li vuole si rifa' il componente con un\n * template. Qui e' lo stesso — se questi testi non vanno bene si dichiara `ERROR_PRESENTER` e la\n * finestra la disegna il prodotto.\n *\n * <b>Perche' non si caricano nel catalogo di DevExtreme.</b> Caricarli con `loadMessages` sarebbe\n * scrivere in uno stato globale, e l'esito dipenderebbe da chi scrive per ultimo: se un prodotto\n * carica i propri testi all'avvio e noi carichiamo i nostri dopo, i suoi sparirebbero. Restando qui,\n * l'ordine di risoluzione e' fisso e non dipende da nessuna sequenza:\n *\n * 1. il catalogo del prodotto, se ha la chiave;\n * 2. questi testi, per la lingua completa (`zh-tw`);\n * 3. questi testi, per la sola lingua (`zh`);\n * 4. questi testi in inglese;\n * 5. la chiave stessa.\n *\n * Un prodotto sovrascrive quindi <b>una singola voce</b> caricandola nel proprio catalogo, senza\n * dover ridichiarare le altre sette.\n *\n * <b>Le lingue sono le stesse trentuno di DevExtreme</b>, cosi' che i testi della finestra non\n * risultino in una lingua diversa da quella dei componenti che la circondano. Delle trentuno, le\n * cinque che i prodotti dichiarano davvero — `de`, `en`, `es`, `fr`, `it` — sono quelle su cui vale\n * la pena investire una revisione; le altre ventisei sono un ripiego utile, non una traduzione\n * professionale, e vanno riviste da chi la lingua la parla prima di distribuire in quel mercato.\n */\nexport const DEFAULT_ERROR_MESSAGES: Readonly<Record<string, Readonly<Record<string, string>>>> = {\n ar: voci(\n 'معلومات',\n 'تحذير',\n 'خطأ',\n 'خطأ في التطبيق',\n 'يرجى مراجعة التحذيرات التالية.',\n 'لم تكتمل العملية.',\n 'حدث خطأ غير متوقع.',\n 'إغلاق',\n ),\n bg: voci(\n 'Информация',\n 'Предупреждение',\n 'Грешка',\n 'Грешка в приложението',\n 'Моля, прегледайте следните предупреждения.',\n 'Операцията не беше завършена.',\n 'Възникна неочаквана грешка.',\n 'Затвори',\n ),\n ca: voci(\n 'Informació',\n 'Avís',\n 'Error',\n 'Error d’aplicació',\n 'Reviseu els avisos següents.',\n 'L’operació no s’ha completat.',\n 'S’ha produït un error inesperat.',\n 'Tanca',\n ),\n cs: voci(\n 'Informace',\n 'Upozornění',\n 'Chyba',\n 'Chyba aplikace',\n 'Zkontrolujte následující upozornění.',\n 'Operace nebyla dokončena.',\n 'Došlo k neočekávané chybě.',\n 'Zavřít',\n ),\n da: voci(\n 'Information',\n 'Advarsel',\n 'Fejl',\n 'Programfejl',\n 'Gennemgå følgende advarsler.',\n 'Handlingen blev ikke gennemført.',\n 'Der opstod en uventet fejl.',\n 'Luk',\n ),\n de: voci(\n 'Information',\n 'Warnung',\n 'Fehler',\n 'Anwendungsfehler',\n 'Bitte beachten Sie die folgenden Warnungen.',\n 'Der Vorgang wurde nicht abgeschlossen.',\n 'Ein unerwarteter Fehler ist aufgetreten.',\n 'Schließen',\n ),\n el: voci(\n 'Πληροφορίες',\n 'Προειδοποίηση',\n 'Σφάλμα',\n 'Σφάλμα εφαρμογής',\n 'Ελέγξτε τις παρακάτω προειδοποιήσεις.',\n 'Η ενέργεια δεν ολοκληρώθηκε.',\n 'Παρουσιάστηκε απροσδόκητο σφάλμα.',\n 'Κλείσιμο',\n ),\n en: voci(\n 'Information',\n 'Warning',\n 'Error',\n 'Application error',\n 'Please review the following warnings.',\n 'The operation was not completed.',\n 'An unexpected error occurred.',\n 'Close',\n ),\n es: voci(\n 'Información',\n 'Aviso',\n 'Error',\n 'Error de aplicación',\n 'Revise las siguientes advertencias.',\n 'La operación no se ha completado.',\n 'Se ha producido un error inesperado.',\n 'Cerrar',\n ),\n fa: voci(\n 'اطلاعات',\n 'هشدار',\n 'خطا',\n 'خطای برنامه',\n 'لطفاً هشدارهای زیر را بررسی کنید.',\n 'عملیات کامل نشد.',\n 'خطای غیرمنتظرهای رخ داد.',\n 'بستن',\n ),\n fi: voci(\n 'Tiedot',\n 'Varoitus',\n 'Virhe',\n 'Sovellusvirhe',\n 'Tarkista seuraavat varoitukset.',\n 'Toimintoa ei suoritettu loppuun.',\n 'Tapahtui odottamaton virhe.',\n 'Sulje',\n ),\n fr: voci(\n 'Informations',\n 'Avertissement',\n 'Erreur',\n 'Erreur applicative',\n 'Veuillez prendre connaissance des avertissements suivants.',\n 'L’opération n’a pas été effectuée.',\n 'Une erreur inattendue est survenue.',\n 'Fermer',\n ),\n hu: voci(\n 'Információ',\n 'Figyelmeztetés',\n 'Hiba',\n 'Alkalmazáshiba',\n 'Tekintse át az alábbi figyelmeztetéseket.',\n 'A művelet nem fejeződött be.',\n 'Váratlan hiba történt.',\n 'Bezárás',\n ),\n it: voci(\n 'Informazioni',\n 'Avviso',\n 'Errore',\n 'Errore applicativo',\n 'Prendere visione dei seguenti avvisi.',\n 'L’operazione non è stata completata.',\n 'Si è verificato un errore imprevisto.',\n 'Chiudi',\n ),\n ja: voci(\n '情報',\n '警告',\n 'エラー',\n 'アプリケーションエラー',\n '次の警告をご確認ください。',\n '操作は完了しませんでした。',\n '予期しないエラーが発生しました。',\n '閉じる',\n ),\n ko: voci(\n '정보',\n '경고',\n '오류',\n '애플리케이션 오류',\n '다음 경고를 확인하십시오.',\n '작업이 완료되지 않았습니다.',\n '예기치 않은 오류가 발생했습니다.',\n '닫기',\n ),\n lt: voci(\n 'Informacija',\n 'Įspėjimas',\n 'Klaida',\n 'Programos klaida',\n 'Peržiūrėkite šiuos įspėjimus.',\n 'Operacija nebuvo baigta.',\n 'Įvyko netikėta klaida.',\n 'Uždaryti',\n ),\n lv: voci(\n 'Informācija',\n 'Brīdinājums',\n 'Kļūda',\n 'Lietojumprogrammas kļūda',\n 'Lūdzu, pārskatiet tālāk norādītos brīdinājumus.',\n 'Darbība netika pabeigta.',\n 'Radās neparedzēta kļūda.',\n 'Aizvērt',\n ),\n nb: voci(\n 'Informasjon',\n 'Advarsel',\n 'Feil',\n 'Programfeil',\n 'Se gjennom følgende advarsler.',\n 'Handlingen ble ikke fullført.',\n 'Det oppstod en uventet feil.',\n 'Lukk',\n ),\n nl: voci(\n 'Informatie',\n 'Waarschuwing',\n 'Fout',\n 'Toepassingsfout',\n 'Bekijk de volgende waarschuwingen.',\n 'De bewerking is niet voltooid.',\n 'Er is een onverwachte fout opgetreden.',\n 'Sluiten',\n ),\n pl: voci(\n 'Informacja',\n 'Ostrzeżenie',\n 'Błąd',\n 'Błąd aplikacji',\n 'Zapoznaj się z poniższymi ostrzeżeniami.',\n 'Operacja nie została ukończona.',\n 'Wystąpił nieoczekiwany błąd.',\n 'Zamknij',\n ),\n pt: voci(\n 'Informação',\n 'Aviso',\n 'Erro',\n 'Erro da aplicação',\n 'Consulte os avisos seguintes.',\n 'A operação não foi concluída.',\n 'Ocorreu um erro inesperado.',\n 'Fechar',\n ),\n ro: voci(\n 'Informații',\n 'Avertisment',\n 'Eroare',\n 'Eroare de aplicație',\n 'Consultați următoarele avertismente.',\n 'Operațiunea nu a fost finalizată.',\n 'A apărut o eroare neașteptată.',\n 'Închide',\n ),\n ru: voci(\n 'Информация',\n 'Предупреждение',\n 'Ошибка',\n 'Ошибка приложения',\n 'Ознакомьтесь со следующими предупреждениями.',\n 'Операция не была завершена.',\n 'Произошла непредвиденная ошибка.',\n 'Закрыть',\n ),\n sl: voci(\n 'Informacije',\n 'Opozorilo',\n 'Napaka',\n 'Napaka aplikacije',\n 'Preglejte naslednja opozorila.',\n 'Dejanje ni bilo dokončano.',\n 'Prišlo je do nepričakovane napake.',\n 'Zapri',\n ),\n sv: voci(\n 'Information',\n 'Varning',\n 'Fel',\n 'Programfel',\n 'Granska följande varningar.',\n 'Åtgärden slutfördes inte.',\n 'Ett oväntat fel inträffade.',\n 'Stäng',\n ),\n tr: voci(\n 'Bilgi',\n 'Uyarı',\n 'Hata',\n 'Uygulama hatası',\n 'Lütfen aşağıdaki uyarıları inceleyin.',\n 'İşlem tamamlanmadı.',\n 'Beklenmeyen bir hata oluştu.',\n 'Kapat',\n ),\n uk: voci(\n 'Інформація',\n 'Попередження',\n 'Помилка',\n 'Помилка застосунку',\n 'Перегляньте наведені нижче попередження.',\n 'Операцію не завершено.',\n 'Сталася неочікувана помилка.',\n 'Закрити',\n ),\n vi: voci(\n 'Thông tin',\n 'Cảnh báo',\n 'Lỗi',\n 'Lỗi ứng dụng',\n 'Vui lòng xem các cảnh báo sau.',\n 'Thao tác chưa được hoàn tất.',\n 'Đã xảy ra lỗi không mong muốn.',\n 'Đóng',\n ),\n zh: voci(\n '信息',\n '警告',\n '错误',\n '应用程序错误',\n '请查看以下警告。',\n '操作未完成。',\n '发生意外错误。',\n '关闭',\n ),\n 'zh-tw': voci(\n '資訊',\n '警告',\n '錯誤',\n '應用程式錯誤',\n '請檢視下列警告。',\n '作業未完成。',\n '發生未預期的錯誤。',\n '關閉',\n ),\n};\n\n/** La lingua di ripiego quando quella corrente non e' fra quelle previste. */\nexport const FALLBACK_LANGUAGE = 'en';\n","import { InjectionToken } from '@angular/core';\nimport { formatMessage, locale } from 'devextreme/localization';\nimport { DEFAULT_ERROR_MESSAGES, ErrorCopyKeys, FALLBACK_LANGUAGE } from './error-messages';\nimport { IErrorInfoModel, LogLevel } from '@quanticdigit/web-services';\n\n// L'enum della gravita' vive nel contratto, non nella presentazione: si riesporta perche' chi lo\n// prendeva da questo pacchetto continui a poterlo fare.\nexport { LogLevel } from '@quanticdigit/web-services';\n\n// Le chiavi vivono accanto ai testi: si riesportano perche' chi le prendeva da qui continui a farlo.\nexport { ErrorCopyKeys } from './error-messages';\n\n/**\n * L'icona che accompagna un livello.\n *\n * Portata da `global-functions.ts` di Jupiter con lo stesso nome e lo stesso esito: i fogli di stile\n * che vi si appoggiano non cambiano.\n */\nexport function manageFormCssClassIcons(level: number): string {\n switch (level) {\n case LogLevel.Info:\n return 'dx-icon-info';\n case LogLevel.Warning:\n return 'dx-icon-warning';\n case LogLevel.Error:\n return 'dx-icon-clear';\n default:\n return 'dx-icon-warning';\n }\n}\n\n/**\n * Risolve una chiave, in quattro passi.\n *\n * @remarks\n * L'ordine e' fisso e non dipende da chi ha caricato cosa per primo:\n *\n * 1. il <b>catalogo del prodotto</b>, se ha la chiave — cosi' sovrascrivere una singola voce e'\n * sufficiente a farla vincere, senza ridichiarare le altre;\n * 2. i testi del pacchetto per la <b>lingua completa</b> (`zh-tw`);\n * 3. i testi del pacchetto per la <b>sola lingua</b> (`zh`, e quindi anche `it-IT` su `it`);\n * 4. gli stessi in inglese, per le lingue che non abbiamo previsto;\n * 5. la <b>chiave</b>, come ultima risorsa.\n *\n * Il quarto passo esiste perche' `formatMessage` restituisce la <b>stringa vuota</b> su una chiave\n * assente, non la chiave: lasciarlo passare produceva una finestra con titolo e testo vuoti — e'\n * andato storto qualcosa e non c'e' scritto niente da nessuna parte. Una chiave visibile e' una\n * mancanza che si nota.\n */\nfunction resolve(key: string): string {\n const dalProdotto = formatMessage(key);\n if (dalProdotto != null && dalProdotto !== '') {\n return dalProdotto;\n }\n\n // Prima la lingua COMPLETA, poi la sola parte di lingua. L'ordine conta: `zh-tw` e `zh` sono\n // due dizionari diversi — cinese tradizionale e semplificato — e guardare subito la sola parte di\n // lingua renderebbe il primo irraggiungibile. `it-IT` invece non ha un dizionario proprio e\n // ricade su `it`, che e' il comportamento voluto.\n const completa = (locale() ?? FALLBACK_LANGUAGE).toLowerCase();\n const lingua = completa.split('-')[0];\n\n return (\n DEFAULT_ERROR_MESSAGES[completa]?.[key] ??\n DEFAULT_ERROR_MESSAGES[lingua]?.[key] ??\n DEFAULT_ERROR_MESSAGES[FALLBACK_LANGUAGE]?.[key] ??\n key\n );\n}\n\n/** Il titolo della finestra per un livello, risolto sul catalogo del prodotto. */\nexport function levelTitle(level: number): string {\n switch (level) {\n case LogLevel.Info:\n return resolve(ErrorCopyKeys.titleInfo);\n case LogLevel.Warning:\n return resolve(ErrorCopyKeys.titleWarning);\n case LogLevel.Error:\n return resolve(ErrorCopyKeys.titleError);\n case LogLevel.Fatal:\n return resolve(ErrorCopyKeys.titleFatal);\n default:\n return resolve(ErrorCopyKeys.titleInfo);\n }\n}\n\n/** L'introduzione della finestra per un livello, risolta sul catalogo del prodotto. */\nexport function levelMessage(level: number): string {\n switch (level) {\n case LogLevel.Warning:\n return resolve(ErrorCopyKeys.messageWarning);\n case LogLevel.Error:\n return resolve(ErrorCopyKeys.messageError);\n case LogLevel.Fatal:\n return resolve(ErrorCopyKeys.messageFatal);\n default:\n return resolve(ErrorCopyKeys.titleInfo);\n }\n}\n\n/**\n * Traduce il tipo dichiarato da `IErrorInfoAppender` nel livello corrispondente.\n *\n * I quattro caratteri sono quelli dell'envelope: `W` avviso, `E` rifiuto di dominio, `F` guasto.\n */\nexport function levelOf(type: string): LogLevel {\n switch (type) {\n case 'W':\n return LogLevel.Warning;\n case 'E':\n return LogLevel.Error;\n case 'F':\n return LogLevel.Fatal;\n default:\n return LogLevel.Info;\n }\n}\n\n/**\n * Cio' che va mostrato all'utente: gia' aggregato, con il livello massimo e i testi risolti.\n *\n * @remarks\n * I testi arrivano gia' risolti perche' il caso comune sia banale. Chi vuole ricalcolarli ha\n * {@link levelTitle}, {@link levelMessage} e {@link manageFormCssClassIcons}, che restano pubbliche.\n */\nexport interface ErrorPresentation {\n readonly level: LogLevel;\n readonly title: string;\n readonly message: string;\n readonly errors: readonly IErrorInfoModel[];\n}\n\n/** Chi mostra gli errori raccolti. */\nexport type ErrorPresenter = (presentation: ErrorPresentation) => void;\n\n/**\n * Come mostrare gli errori, quando la finestra predefinita non va bene.\n *\n * @remarks\n * <b>Non ha una fabbrica predefinita, e non e' una dimenticanza.</b> Assente — o fornito come\n * `null` — significa «va bene il modo base», e {@link ErrorCollector} apre la propria finestra\n * DevExtreme. Si dichiara soltanto quando si vuole qualcos'altro:\n *\n * ```ts\n * { provide: ERROR_PRESENTER, useValue: (p) => miaFinestra(p.title, p.message, p.errors) }\n * ```\n *\n * Chi vuole tenere la finestra e aggiungerci qualcosa avvolge {@link devExtremeDialogPresenter},\n * che e' esportata apposta.\n */\nexport const ERROR_PRESENTER = new InjectionToken<ErrorPresenter>('QuanticDigit.ErrorPresenter');\n\n/**\n * Risolve una chiave qualsiasi con lo stesso ripiego dei titoli.\n *\n * Serve a chi realizza una finestra propria e vuole le stesse regole di risoluzione.\n */\nexport function buttonText(key: string): string {\n return resolve(key);\n}\n","import { custom } from 'devextreme/ui/dialog';\nimport {\n ErrorCopyKeys,\n ErrorPresentation,\n ErrorPresenter,\n buttonText,\n manageFormCssClassIcons,\n} from './error-presentation';\n\n/**\n * La finestra predefinita: un elenco degli errori raccolti, con l'icona del proprio livello.\n *\n * @remarks\n * E' cio' che {@link ErrorCollector} apre quando nessuno ha dichiarato `ERROR_PRESENTER`. E'\n * esportata perche' chi ne vuole una diversa possa comunque riusarla — per esempio per mandare\n * l'errore alla telemetria e poi mostrarlo come prima:\n *\n * ```ts\n * { provide: ERROR_PRESENTER, useValue: (p) => { telemetria(p); devExtremeDialogPresenter(p); } }\n * ```\n */\nexport const devExtremeDialogPresenter: ErrorPresenter = (presentation: ErrorPresentation): void => {\n const righe = presentation.errors\n .map((e) => `<li class=\"${manageFormCssClassIcons(e.level)}\">${testo(e.message, e.id)}</li>`)\n .join('');\n\n const finestra = custom({\n title: presentation.title,\n messageHtml: `<p>${presentation.message}</p><ul>${righe}</ul>`,\n buttons: [{ text: buttonText(ErrorCopyKeys.buttonClose) }],\n });\n\n void finestra.show();\n};\n\n/**\n * Il testo di una riga.\n *\n * @remarks\n * `message` porta cio' che il server ha messo. In DeepWood e' una <b>chiave di copy</b> del catalogo\n * (`error.<mnemonico>`), non un testo: quel prodotto deve risolverla prima di consegnarla qui,\n * oppure mostrera' la chiave. La chiave mostrata e' una mancanza visibile, preferibile a un testo\n * inventato dal pacchetto.\n */\nfunction testo(message: string, id: number): string {\n const identificativo = id != null && id !== 0 ? ` [${id}]` : '';\n return `${message ?? ''}${identificativo}`;\n}\n","import { Injectable, inject } from '@angular/core';\nimport { IErrorInfoAppender, IErrorInfoModel } from '@quanticdigit/web-services';\nimport { devExtremeDialogPresenter } from './error-dialog';\nimport { ERROR_PRESENTER, ErrorPresentation, LogLevel, levelMessage, levelOf, levelTitle } from './error-presentation';\n\n/**\n * Raccoglie gli errori di una chiamata e li mostra all'utente.\n *\n * @remarks\n * <b>E' la realizzazione di `IErrorInfoAppender`</b> che `@quanticdigit/web-services` dichiara e non\n * fornisce. La separazione e' voluta: il livello di servizio sa <i>che</i> qualcosa e' andato storto,\n * questo sa <i>come</i> dirlo, e un'applicazione senza interfaccia grafica sostituisce il secondo\n * senza toccare il primo.\n *\n * <b>Non e' un portaggio.</b> In Jupiter questo lavoro sta dentro `LogService`, 376 righe che sono\n * insieme accumulatore, presentatore, registro e client HTTP verso una WebApi: quel file non e'\n * separabile senza riscriverlo. Qui c'e' la sola presentazione, e cio' che manca — spedire l'evento\n * di errore al proprio backend — resta al prodotto, che lo fa con i propri servizi.\n *\n * <b>Gli errori si accumulano.</b> Una schermata che ne produce tre in sequenza deve mostrarne una\n * finestra sola: aprirne tre significa che l'utente chiude le prime due senza leggerle.\n */\n@Injectable({ providedIn: 'root' })\nexport class ErrorCollector implements IErrorInfoAppender {\n /** Quanto si aspetta prima di mostrare, per raccogliere cio' che arriva nello stesso giro. */\n private static readonly ATTESA_MS = 0;\n\n /**\n * Come mostrare, quando il modo base non va bene.\n *\n * @remarks\n * Assente significa <b>va bene il modo base</b>: si apre la finestra di\n * {@link devExtremeDialogPresenter}. `ERROR_PRESENTER` si dichiara soltanto per sostituirla, e in\n * quel caso la nostra non viene nemmeno costruita.\n */\n private readonly presenter = inject(ERROR_PRESENTER, { optional: true });\n\n private readonly accumulati: IErrorInfoModel[] = [];\n private livello: LogLevel = LogLevel.Info;\n private programmata = false;\n\n /** Gli errori non ancora mostrati. */\n get messages(): readonly IErrorInfoModel[] {\n return this.accumulati;\n }\n\n /**\n * Prende in carico gli errori di una chiamata.\n *\n * @remarks\n * E' scritta come proprieta' di tipo funzione, ma ora e' una scelta e non un obbligo:\n * `BaseService` chiama attraverso l'oggetto, quindi anche un metodo normale funzionerebbe. Resta\n * cosi' perche' regge anche se qualcuno la consegna come riferimento a un altro raccoglitore.\n */\n appendErrorInfo = (errors: IErrorInfoModel[], type: string, url: string, post: unknown): void => {\n if (errors == null || errors.length === 0) {\n return;\n }\n\n const livello = levelOf(type);\n if (livello > this.livello) {\n this.livello = livello;\n }\n\n for (const errore of errors) {\n this.accumulati.push(errore);\n }\n\n this.programma();\n };\n\n /** Dimentica cio' che non e' stato mostrato. */\n clear(): void {\n this.accumulati.length = 0;\n this.livello = LogLevel.Info;\n }\n\n /**\n * Programma la presentazione per la fine del giro corrente.\n *\n * Tre chiamate fallite nello stesso istante producono una finestra sola con tre righe, non tre\n * finestre: e' la ragione per cui la presentazione non e' immediata.\n */\n private programma(): void {\n if (this.programmata) {\n return;\n }\n this.programmata = true;\n setTimeout(() => this.mostra(), ErrorCollector.ATTESA_MS);\n }\n\n /** Mostra quanto accumulato e svuota. */\n private mostra(): void {\n this.programmata = false;\n\n if (this.accumulati.length === 0) {\n return;\n }\n\n const presentazione: ErrorPresentation = {\n level: this.livello,\n title: levelTitle(this.livello),\n message: levelMessage(this.livello),\n // Una copia: si svuota subito dopo, e chi presenta deve poter leggere con calma.\n errors: [...this.accumulati],\n };\n\n this.clear();\n\n // Se qualcuno ha dichiarato come mostrare, la nostra finestra non viene nemmeno costruita.\n if (this.presenter != null) {\n this.presenter(presentazione);\n return;\n }\n\n devExtremeDialogPresenter(presentazione);\n }\n}\n","/**\n * Superficie pubblica di `@quanticdigit/web-errors`.\n *\n * Raccoglie gli errori che il livello di servizio consegna e li mostra: accumulo per livello, icone,\n * una finestra sola per giro, e i testi gia' dentro nelle lingue principali.\n *\n * E' la realizzazione di `IErrorInfoAppender`, che `@quanticdigit/web-services` dichiara e non\n * fornisce: chi non vuole una finestra sostituisce questo pacchetto e non tocca quello.\n *\n * Tre livelli di personalizzazione, dal piu' leggero al piu' invasivo. Nessuno e' obbligatorio: senza\n * fare niente si ha una finestra che parla la lingua corrente.\n *\n * 1. **un testo** — si carica quella chiave di `ErrorCopyKeys` nel catalogo di DevExtreme, e vince\n * sul testo predefinito senza doverne ridichiarare altri;\n * 2. **la finestra** — si dichiara `ERROR_PRESENTER`; senza, resta quella predefinita;\n * 3. **tutto** — si realizza `IErrorInfoAppender` per conto proprio e questo pacchetto non serve.\n */\n\nexport * from './lib/error-collector';\nexport * from './lib/error-dialog';\nexport * from './lib/error-messages';\nexport * from './lib/error-presentation';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"quanticdigit-web-errors.mjs","sources":["../../../projects/web-errors/src/lib/error-messages.ts","../../../projects/web-errors/src/lib/error-presentation.ts","../../../projects/web-errors/src/lib/error-dialog.ts","../../../projects/web-errors/src/lib/error-collector.ts","../../../projects/web-errors/src/public-api.ts","../../../projects/web-errors/src/quanticdigit-web-errors.ts"],"sourcesContent":["/**\n * Le chiavi di testo che questo pacchetto usa.\n *\n * @remarks\n * <b>Sono il contratto.</b> Il pacchetto porta con se' i testi predefiniti in piu' lingue — vedi\n * {@link DEFAULT_ERROR_MESSAGES} — e un prodotto ne sovrascrive una qualsiasi caricandola nel\n * proprio catalogo di DevExtreme con `loadMessages`: quello del prodotto vince sempre.\n *\n * Stanno qui e non accanto a chi le risolve per rompere un ciclo fra moduli: i testi hanno bisogno\n * delle chiavi, e chi risolve ha bisogno di entrambi.\n */\nexport const ErrorCopyKeys = {\n titleInfo: 'dialogTitleInfo',\n titleWarning: 'dialogTitleWarning',\n titleError: 'dialogTitleError',\n titleFatal: 'dialogTitleFatal',\n messageWarning: 'dialogMessageWarning',\n messageError: 'dialogMessageError',\n messageFatal: 'dialogMessageFatal',\n buttonClose: 'dialogLabelbtnClose',\n} as const;\n\n/** Comodita' interna: compone le otto voci di una lingua nell'ordine dichiarato. */\nconst entries = (\n titleInfo: string,\n titleWarning: string,\n titleError: string,\n titleFatal: string,\n messageWarning: string,\n messageError: string,\n messageFatal: string,\n buttonClose: string,\n): Readonly<Record<string, string>> => ({\n [ErrorCopyKeys.titleInfo]: titleInfo,\n [ErrorCopyKeys.titleWarning]: titleWarning,\n [ErrorCopyKeys.titleError]: titleError,\n [ErrorCopyKeys.titleFatal]: titleFatal,\n [ErrorCopyKeys.messageWarning]: messageWarning,\n [ErrorCopyKeys.messageError]: messageError,\n [ErrorCopyKeys.messageFatal]: messageFatal,\n [ErrorCopyKeys.buttonClose]: buttonClose,\n});\n\n/**\n * I testi predefiniti della finestra degli errori.\n *\n * @remarks\n * <b>Perche' stanno nel pacchetto.</b> E' il modello dei componenti DevExtreme: un calendario porta\n * dentro di se' i nomi dei mesi in tutte le lingue, e chi non li vuole si rifa' il componente con un\n * template. Qui e' lo stesso — se questi testi non vanno bene si dichiara `ERROR_PRESENTER` e la\n * finestra la disegna il prodotto.\n *\n * <b>Perche' non si caricano nel catalogo di DevExtreme.</b> Caricarli con `loadMessages` sarebbe\n * scrivere in uno stato globale, e l'esito dipenderebbe da chi scrive per ultimo: se un prodotto\n * carica i propri testi all'avvio e noi carichiamo i nostri dopo, i suoi sparirebbero. Restando qui,\n * l'ordine di risoluzione e' fisso e non dipende da nessuna sequenza:\n *\n * 1. il catalogo del prodotto, se ha la chiave;\n * 2. questi testi, per la lingua completa (`zh-tw`);\n * 3. questi testi, per la sola lingua (`zh`);\n * 4. questi testi in inglese;\n * 5. la chiave stessa.\n *\n * Un prodotto sovrascrive quindi <b>una singola voce</b> caricandola nel proprio catalogo, senza\n * dover ridichiarare le altre sette.\n *\n * <b>Le lingue sono le stesse trentuno di DevExtreme</b>, cosi' che i testi della finestra non\n * risultino in una lingua diversa da quella dei componenti che la circondano. Delle trentuno, le\n * cinque che i prodotti dichiarano davvero — `de`, `en`, `es`, `fr`, `it` — sono quelle su cui vale\n * la pena investire una revisione; le altre ventisei sono un ripiego utile, non una traduzione\n * professionale, e vanno riviste da chi la lingua la parla prima di distribuire in quel mercato.\n */\nexport const DEFAULT_ERROR_MESSAGES: Readonly<Record<string, Readonly<Record<string, string>>>> = {\n ar: entries(\n 'معلومات',\n 'تحذير',\n 'خطأ',\n 'خطأ في التطبيق',\n 'يرجى مراجعة التحذيرات التالية.',\n 'لم تكتمل العملية.',\n 'حدث خطأ غير متوقع.',\n 'إغلاق',\n ),\n bg: entries(\n 'Информация',\n 'Предупреждение',\n 'Грешка',\n 'Грешка в приложението',\n 'Моля, прегледайте следните предупреждения.',\n 'Операцията не беше завършена.',\n 'Възникна неочаквана грешка.',\n 'Затвори',\n ),\n ca: entries(\n 'Informació',\n 'Avís',\n 'Error',\n 'Error d’aplicació',\n 'Reviseu els avisos següents.',\n 'L’operació no s’ha completat.',\n 'S’ha produït un error inesperat.',\n 'Tanca',\n ),\n cs: entries(\n 'Informace',\n 'Upozornění',\n 'Chyba',\n 'Chyba aplikace',\n 'Zkontrolujte následující upozornění.',\n 'Operace nebyla dokončena.',\n 'Došlo k neočekávané chybě.',\n 'Zavřít',\n ),\n da: entries(\n 'Information',\n 'Advarsel',\n 'Fejl',\n 'Programfejl',\n 'Genentrygå følgende advarsler.',\n 'Handlingen blev ikke genentryført.',\n 'Der opstod en uventet fejl.',\n 'Luk',\n ),\n de: entries(\n 'Information',\n 'Warnung',\n 'Fehler',\n 'Anwendungsfehler',\n 'Bitte beachten Sie die folgenden Warnungen.',\n 'Der Vorgang wurde nicht abgeschlossen.',\n 'Ein unerwarteter Fehler ist aufgetreten.',\n 'Schließen',\n ),\n el: entries(\n 'Πληροφορίες',\n 'Προειδοποίηση',\n 'Σφάλμα',\n 'Σφάλμα εφαρμογής',\n 'Ελέγξτε τις παρακάτω προειδοποιήσεις.',\n 'Η ενέργεια δεν ολοκληρώθηκε.',\n 'Παρουσιάστηκε απροσδόκητο σφάλμα.',\n 'Κλείσιμο',\n ),\n en: entries(\n 'Information',\n 'Warning',\n 'Error',\n 'Application error',\n 'Please review the following warnings.',\n 'The operation was not completed.',\n 'An unexpected error occurred.',\n 'Close',\n ),\n es: entries(\n 'Información',\n 'Aviso',\n 'Error',\n 'Error de aplicación',\n 'Revise las siguientes advertencias.',\n 'La operación no se ha completado.',\n 'Se ha producido un error inesperado.',\n 'Cerrar',\n ),\n fa: entries(\n 'اطلاعات',\n 'هشدار',\n 'خطا',\n 'خطای برنامه',\n 'لطفاً هشدارهای زیر را بررسی کنید.',\n 'عملیات کامل نشد.',\n 'خطای غیرمنتظرهای رخ داد.',\n 'بستن',\n ),\n fi: entries(\n 'Tiedot',\n 'Varoitus',\n 'Virhe',\n 'Sovellusvirhe',\n 'Tarkista seuraavat varoitukset.',\n 'Toimintoa ei suoritettu loppuun.',\n 'Tapahtui odottamaton virhe.',\n 'Sulje',\n ),\n fr: entries(\n 'Informations',\n 'Avertissement',\n 'Erreur',\n 'Erreur applicative',\n 'Veuillez prendre connaissance des avertissements suivants.',\n 'L’opération n’a pas été effectuée.',\n 'Une erreur inattendue est survenue.',\n 'Fermer',\n ),\n hu: entries(\n 'Információ',\n 'Figyelmeztetés',\n 'Hiba',\n 'Alkalmazáshiba',\n 'Tekintse át az alábbi figyelmeztetéseket.',\n 'A művelet entry fejeződött be.',\n 'Váratlan hiba történt.',\n 'Bezárás',\n ),\n it: entries(\n 'Informazioni',\n 'Avviso',\n 'Errore',\n 'Errore applicativo',\n 'Prendere visione dei seguenti avvisi.',\n 'L’operazione non è stata completata.',\n 'Si è verificato un errore imprevisto.',\n 'Chiudi',\n ),\n ja: entries(\n '情報',\n '警告',\n 'エラー',\n 'アプリケーションエラー',\n '次の警告をご確認ください。',\n '操作は完了しませんでした。',\n '予期しないエラーが発生しました。',\n '閉じる',\n ),\n ko: entries(\n '정보',\n '경고',\n '오류',\n '애플리케이션 오류',\n '다음 경고를 확인하십시오.',\n '작업이 완료되지 않았습니다.',\n '예기치 않은 오류가 발생했습니다.',\n '닫기',\n ),\n lt: entries(\n 'Informacija',\n 'Įspėjimas',\n 'Klaida',\n 'Programos klaida',\n 'Peržiūrėkite šiuos įspėjimus.',\n 'Operacija nebuvo baigta.',\n 'Įvyko netikėta klaida.',\n 'Uždaryti',\n ),\n lv: entries(\n 'Informācija',\n 'Brīdinājums',\n 'Kļūda',\n 'Lietojumprogrammas kļūda',\n 'Lūdzu, pārskatiet tālāk norādītos brīdinājumus.',\n 'Darbība netika pabeigta.',\n 'Radās neparedzēta kļūda.',\n 'Aizvērt',\n ),\n nb: entries(\n 'Informasjon',\n 'Advarsel',\n 'Feil',\n 'Programfeil',\n 'Se gjennom følgende advarsler.',\n 'Handlingen ble ikke fullført.',\n 'Det oppstod en uventet feil.',\n 'Lukk',\n ),\n nl: entries(\n 'Informatie',\n 'Waarschuwing',\n 'Fout',\n 'Toepassingsfout',\n 'Bekijk de volgende waarschuwingen.',\n 'De bewerking is niet voltooid.',\n 'Er is een onverwachte fout opgetreden.',\n 'Sluiten',\n ),\n pl: entries(\n 'Informacja',\n 'Ostrzeżenie',\n 'Błąd',\n 'Błąd aplikacji',\n 'Zapoznaj się z poniższymi ostrzeżeniami.',\n 'Operacja nie została ukończona.',\n 'Wystąpił nieoczekiwany błąd.',\n 'Zamknij',\n ),\n pt: entries(\n 'Informação',\n 'Aviso',\n 'Erro',\n 'Erro da aplicação',\n 'Consulte os avisos seguintes.',\n 'A operação não foi concluída.',\n 'Ocorreu um erro inesperado.',\n 'Fechar',\n ),\n ro: entries(\n 'Informații',\n 'Avertisment',\n 'Eroare',\n 'Eroare de aplicație',\n 'Consultați următoarele avertismente.',\n 'Operațiunea nu a fost finalizată.',\n 'A apărut o eroare neașteptată.',\n 'Închide',\n ),\n ru: entries(\n 'Информация',\n 'Предупреждение',\n 'Ошибка',\n 'Ошибка приложения',\n 'Ознакомьтесь со следующими предупреждениями.',\n 'Операция не была завершена.',\n 'Произошла непредвиденная ошибка.',\n 'Закрыть',\n ),\n sl: entries(\n 'Informacije',\n 'Opozorilo',\n 'Napaka',\n 'Napaka aplikacije',\n 'Preglejte naslednja opozorila.',\n 'Dejanje ni bilo dokončano.',\n 'Prišlo je do nepričakovane napake.',\n 'Zapri',\n ),\n sv: entries(\n 'Information',\n 'Varning',\n 'Fel',\n 'Programfel',\n 'Granska följande varningar.',\n 'Åtgärden slutfördes inte.',\n 'Ett oväntat fel inträffade.',\n 'Stäng',\n ),\n tr: entries(\n 'Bilgi',\n 'Uyarı',\n 'Hata',\n 'Uygulama hatası',\n 'Lütfen aşağıdaki uyarıları inceleyin.',\n 'İşlem tamamlanmadı.',\n 'Beklenmeyen bir hata oluştu.',\n 'Kapat',\n ),\n uk: entries(\n 'Інформація',\n 'Попередження',\n 'Помилка',\n 'Помилка застосунку',\n 'Перегляньте наведені нижче попередження.',\n 'Операцію не завершено.',\n 'Сталася неочікувана помилка.',\n 'Закрити',\n ),\n vi: entries(\n 'Thông tin',\n 'Cảnh báo',\n 'Lỗi',\n 'Lỗi ứng dụng',\n 'Vui lòng xem các cảnh báo sau.',\n 'Thao tác chưa được hoàn tất.',\n 'Đã xảy ra lỗi không mong muốn.',\n 'Đóng',\n ),\n zh: entries(\n '信息',\n '警告',\n '错误',\n '应用程序错误',\n '请查看以下警告。',\n '操作未完成。',\n '发生意外错误。',\n '关闭',\n ),\n 'zh-tw': entries(\n '資訊',\n '警告',\n '錯誤',\n '應用程式錯誤',\n '請檢視下列警告。',\n '作業未完成。',\n '發生未預期的錯誤。',\n '關閉',\n ),\n};\n\n/** La lingua di ripiego quando quella corrente non e' fra quelle previste. */\nexport const FALLBACK_LANGUAGE = 'en';\n","import { InjectionToken } from '@angular/core';\nimport { formatMessage, locale } from 'devextreme/localization';\nimport { DEFAULT_ERROR_MESSAGES, ErrorCopyKeys, FALLBACK_LANGUAGE } from './error-messages';\nimport { IErrorInfoModel, LogLevel } from '@quanticdigit/web-services';\n\n// L'enum della gravita' vive nel contratto, non nella presentazione: si riesporta perche' chi lo\n// prendeva da questo pacchetto continui a poterlo fare.\nexport { LogLevel } from '@quanticdigit/web-services';\n\n// Le chiavi vivono accanto ai testi: si riesportano perche' chi le prendeva da qui continui a farlo.\nexport { ErrorCopyKeys } from './error-messages';\n\n/**\n * L'icona che accompagna un livello.\n *\n * Portata da `global-functions.ts` di Jupiter con lo stesso nome e lo stesso esito: i fogli di stile\n * che vi si appoggiano non cambiano.\n */\nexport function manageFormCssClassIcons(level: number): string {\n switch (level) {\n case LogLevel.Info:\n return 'dx-icon-info';\n case LogLevel.Warning:\n return 'dx-icon-warning';\n case LogLevel.Error:\n return 'dx-icon-clear';\n default:\n return 'dx-icon-warning';\n }\n}\n\n/**\n * Risolve una chiave, in quattro passi.\n *\n * @remarks\n * L'ordine e' fisso e non dipende da chi ha caricato cosa per primo:\n *\n * 1. il <b>catalogo del prodotto</b>, se ha la chiave — cosi' sovrascrivere una singola voce e'\n * sufficiente a farla vincere, senza ridichiarare le altre;\n * 2. i testi del pacchetto per la <b>lingua completa</b> (`zh-tw`);\n * 3. i testi del pacchetto per la <b>sola lingua</b> (`zh`, e quindi anche `it-IT` su `it`);\n * 4. gli stessi in inglese, per le lingue che non abbiamo previsto;\n * 5. la <b>chiave</b>, come ultima risorsa.\n *\n * Il quarto passo esiste perche' `formatMessage` restituisce la <b>stringa vuota</b> su una chiave\n * assente, non la chiave: lasciarlo passare produceva una finestra con titolo e testo vuoti — e'\n * andato storto qualcosa e non c'e' scritto niente da nessuna parte. Una chiave visibile e' una\n * mancanza che si nota.\n */\nfunction resolve(key: string): string {\n const fromProduct = formatMessage(key);\n if (fromProduct != null && fromProduct !== '') {\n return fromProduct;\n }\n\n // Prima la lingua COMPLETA, poi la sola parte di lingua. L'ordine conta: `zh-tw` e `zh` sono\n // due dizionari diversi — cinese tradizionale e semplificato — e guardare subito la sola parte di\n // lingua renderebbe il primo irraggiungibile. `it-IT` invece non ha un dizionario proprio e\n // ricade su `it`, che e' il comportamento voluto.\n const fullLanguage = (locale() ?? FALLBACK_LANGUAGE).toLowerCase();\n const languageOnly = fullLanguage.split('-')[0];\n\n return (\n DEFAULT_ERROR_MESSAGES[fullLanguage]?.[key] ??\n DEFAULT_ERROR_MESSAGES[languageOnly]?.[key] ??\n DEFAULT_ERROR_MESSAGES[FALLBACK_LANGUAGE]?.[key] ??\n key\n );\n}\n\n/** Il titolo della finestra per un livello, risolto sul catalogo del prodotto. */\nexport function levelTitle(level: number): string {\n switch (level) {\n case LogLevel.Info:\n return resolve(ErrorCopyKeys.titleInfo);\n case LogLevel.Warning:\n return resolve(ErrorCopyKeys.titleWarning);\n case LogLevel.Error:\n return resolve(ErrorCopyKeys.titleError);\n case LogLevel.Fatal:\n return resolve(ErrorCopyKeys.titleFatal);\n default:\n return resolve(ErrorCopyKeys.titleInfo);\n }\n}\n\n/** L'introduzione della finestra per un livello, risolta sul catalogo del prodotto. */\nexport function levelMessage(level: number): string {\n switch (level) {\n case LogLevel.Warning:\n return resolve(ErrorCopyKeys.messageWarning);\n case LogLevel.Error:\n return resolve(ErrorCopyKeys.messageError);\n case LogLevel.Fatal:\n return resolve(ErrorCopyKeys.messageFatal);\n default:\n return resolve(ErrorCopyKeys.titleInfo);\n }\n}\n\n/**\n * Traduce il tipo dichiarato da `IErrorInfoAppender` nel livello corrispondente.\n *\n * I quattro caratteri sono quelli dell'envelope: `W` avviso, `E` rifiuto di dominio, `F` guasto.\n */\nexport function levelOf(type: string): LogLevel {\n switch (type) {\n case 'W':\n return LogLevel.Warning;\n case 'E':\n return LogLevel.Error;\n case 'F':\n return LogLevel.Fatal;\n default:\n return LogLevel.Info;\n }\n}\n\n/**\n * Cio' che va mostrato all'utente: gia' aggregato, con il livello massimo e i testi risolti.\n *\n * @remarks\n * I testi arrivano gia' risolti perche' il caso comune sia banale. Chi vuole ricalcolarli ha\n * {@link levelTitle}, {@link levelMessage} e {@link manageFormCssClassIcons}, che restano pubbliche.\n */\nexport interface ErrorPresentation {\n readonly level: LogLevel;\n readonly title: string;\n readonly message: string;\n readonly errors: readonly IErrorInfoModel[];\n}\n\n/** Chi mostra gli errori raccolti. */\nexport type ErrorPresenter = (presentation: ErrorPresentation) => void;\n\n/**\n * Come mostrare gli errori, quando la finestra predefinita non va bene.\n *\n * @remarks\n * <b>Non ha una fabbrica predefinita, e non e' una dimenticanza.</b> Assente — o fornito come\n * `null` — significa «va bene il modo base», e {@link ErrorCollector} apre la propria finestra\n * DevExtreme. Si dichiara soltanto quando si vuole qualcos'altro:\n *\n * ```ts\n * { provide: ERROR_PRESENTER, useValue: (p) => miaFinestra(p.title, p.message, p.errors) }\n * ```\n *\n * Chi vuole tenere la finestra e aggiungerci qualcosa avvolge {@link devExtremeDialogPresenter},\n * che e' esportata apposta.\n */\nexport const ERROR_PRESENTER = new InjectionToken<ErrorPresenter>('QuanticDigit.ErrorPresenter');\n\n/**\n * Risolve una chiave qualsiasi con lo stesso ripiego dei titoli.\n *\n * Serve a chi realizza una finestra propria e vuole le stesse regole di risoluzione.\n */\nexport function buttonText(key: string): string {\n return resolve(key);\n}\n","import { custom } from 'devextreme/ui/dialog';\nimport {\n ErrorCopyKeys,\n ErrorPresentation,\n ErrorPresenter,\n buttonText,\n manageFormCssClassIcons,\n} from './error-presentation';\n\n/**\n * La finestra predefinita: un elenco degli errori raccolti, con l'icona del proprio livello.\n *\n * @remarks\n * E' cio' che {@link ErrorCollector} apre quando nessuno ha dichiarato `ERROR_PRESENTER`. E'\n * esportata perche' chi ne vuole una diversa possa comunque riusarla — per esempio per mandare\n * l'errore alla telemetria e poi mostrarlo come prima:\n *\n * ```ts\n * { provide: ERROR_PRESENTER, useValue: (p) => { telemetria(p); devExtremeDialogPresenter(p); } }\n * ```\n */\nexport const devExtremeDialogPresenter: ErrorPresenter = (presentation: ErrorPresentation): void => {\n const lines = presentation.errors\n .map((e) => `<li class=\"${manageFormCssClassIcons(e.level)}\">${text(e.message, e.id)}</li>`)\n .join('');\n\n const dialog = custom({\n title: presentation.title,\n messageHtml: `<p>${presentation.message}</p><ul>${lines}</ul>`,\n buttons: [{ text: buttonText(ErrorCopyKeys.buttonClose) }],\n });\n\n void dialog.show();\n};\n\n/**\n * Il testo di una riga.\n *\n * @remarks\n * `message` porta cio' che il server ha messo. In DeepWood e' una <b>chiave di copy</b> del catalogo\n * (`error.<mnemonico>`), non un testo: quel prodotto deve risolverla prima di consegnarla qui,\n * oppure mostrera' la chiave. La chiave mostrata e' una mancanza visibile, preferibile a un testo\n * inventato dal pacchetto.\n */\nfunction text(message: string, id: number): string {\n const identifier = id != null && id !== 0 ? ` [${id}]` : '';\n return `${message ?? ''}${identifier}`;\n}\n","import { Injectable, inject } from '@angular/core';\nimport { IErrorInfoAppender, IErrorInfoModel } from '@quanticdigit/web-services';\nimport { APPLICATION_LOG_WRITER, AppLogLevelCode, ApplicationLogger, safeValue } from '@quanticdigit/web-logging';\nimport { devExtremeDialogPresenter } from './error-dialog';\nimport { ERROR_PRESENTER, ErrorPresentation, LogLevel, levelMessage, levelOf, levelTitle } from './error-presentation';\n\n/** I tre caratteri dell'envelope sono gia' codici di livello: tutto il resto e' un errore. */\nfunction logLevelOf(type: string): AppLogLevelCode {\n return type === 'W' || type === 'E' || type === 'F' ? type : 'E';\n}\n\n/**\n * Raccoglie gli errori di una chiamata e li mostra all'utente.\n *\n * @remarks\n * <b>E' la realizzazione di `IErrorInfoAppender`</b> che `@quanticdigit/web-services` dichiara e non\n * fornisce. La separazione e' voluta: il livello di servizio sa <i>che</i> qualcosa e' andato storto,\n * questo sa <i>come</i> dirlo, e un'applicazione senza interfaccia grafica sostituisce il secondo\n * senza toccare il primo.\n *\n * <b>Non e' un portaggio.</b> In Jupiter questo lavoro sta dentro `LogService`, 376 righe che sono\n * insieme accumulatore, presentatore, registro e client HTTP verso una WebApi: quel file non e'\n * separabile senza riscriverlo. Qui c'e' la sola presentazione, e cio' che manca — spedire l'evento\n * di errore al proprio backend — resta al prodotto, che lo fa con i propri servizi.\n *\n * <b>Gli errori si accumulano.</b> Una schermata che ne produce tre in sequenza deve mostrarne una\n * finestra sola: aprirne tre significa che l'utente chiude le prime due senza leggerle.\n */\n@Injectable({ providedIn: 'root' })\nexport class ErrorCollector implements IErrorInfoAppender {\n /** Quanto si aspetta prima di mostrare, per raccogliere cio' che arriva nello stesso giro. */\n private static readonly WAIT_MS = 0;\n\n /**\n * Come mostrare, quando il modo base non va bene.\n *\n * @remarks\n * Assente significa <b>va bene il modo base</b>: si apre la finestra di\n * {@link devExtremeDialogPresenter}. `ERROR_PRESENTER` si dichiara soltanto per sostituirla, e in\n * quel caso la nostra non viene nemmeno costruita.\n */\n private readonly presenter = inject(ERROR_PRESENTER, { optional: true });\n\n /**\n * Il log applicativo, sotto `errors`.\n *\n * @remarks\n * Un errore mostrato all'utente e' un errore che qualcuno vorra' ricostruire dopo, quando la\n * finestra e la persona che la stava guardando non ci sono piu'. Senza writer dichiarato non\n * accade nulla, come ovunque nel resto della famiglia.\n */\n private readonly appLogger = new ApplicationLogger(inject(APPLICATION_LOG_WRITER, { optional: true }), 'errors');\n\n private readonly collected: IErrorInfoModel[] = [];\n private level: LogLevel = LogLevel.Info;\n private scheduled = false;\n\n /** Gli errori non ancora mostrati. */\n get messages(): readonly IErrorInfoModel[] {\n return this.collected;\n }\n\n /**\n * Prende in carico gli errori di una chiamata.\n *\n * @remarks\n * E' scritta come proprieta' di tipo funzione, ma ora e' una scelta e non un obbligo:\n * `BaseService` chiama attraverso l'oggetto, quindi anche un metodo normale funzionerebbe. Resta\n * cosi' perche' regge anche se qualcuno la consegna come riferimento a un altro raccoglitore.\n */\n appendErrorInfo = (errors: IErrorInfoModel[], type: string, url: string, post: unknown): void => {\n if (errors == null || errors.length === 0) {\n return;\n }\n\n const level = levelOf(type);\n if (level > this.level) {\n this.level = level;\n }\n\n for (const error of errors) {\n this.collected.push(error);\n this.appLogger.log(logLevelOf(type), 'http', error.message, { id: error.id, level: error.level, isBusiness: error.isBusiness, url, post: safeValue(post) }, error.trace);\n }\n\n this.schedule();\n };\n\n /** Dimentica cio' che non e' stato mostrato. */\n clear(): void {\n this.collected.length = 0;\n this.level = LogLevel.Info;\n }\n\n /**\n * Programma la presentazione per la fine del giro corrente.\n *\n * Tre chiamate fallite nello stesso istante producono una finestra sola con tre righe, non tre\n * finestre: e' la ragione per cui la presentazione non e' immediata.\n */\n private schedule(): void {\n if (this.scheduled) {\n return;\n }\n this.scheduled = true;\n setTimeout(() => this.present(), ErrorCollector.WAIT_MS);\n }\n\n /** Mostra quanto accumulato e svuota. */\n private present(): void {\n this.scheduled = false;\n\n if (this.collected.length === 0) {\n return;\n }\n\n const presentation: ErrorPresentation = {\n level: this.level,\n title: levelTitle(this.level),\n message: levelMessage(this.level),\n // Una copia: si svuota subito dopo, e chi presenta deve poter leggere con calma.\n errors: [...this.collected],\n };\n\n this.clear();\n\n // Se qualcuno ha dichiarato come mostrare, la nostra finestra non viene nemmeno costruita.\n if (this.presenter != null) {\n this.presenter(presentation);\n return;\n }\n\n devExtremeDialogPresenter(presentation);\n }\n}\n","/**\n * Superficie pubblica di `@quanticdigit/web-errors`.\n *\n * Raccoglie gli errori che il livello di servizio consegna e li mostra: accumulo per livello, icone,\n * una finestra sola per giro, e i testi gia' dentro nelle lingue principali.\n *\n * E' la realizzazione di `IErrorInfoAppender`, che `@quanticdigit/web-services` dichiara e non\n * fornisce: chi non vuole una finestra sostituisce questo pacchetto e non tocca quello.\n *\n * Tre livelli di personalizzazione, dal piu' leggero al piu' invasivo. Nessuno e' obbligatorio: senza\n * fare niente si ha una finestra che parla la lingua corrente.\n *\n * 1. **un testo** — si carica quella chiave di `ErrorCopyKeys` nel catalogo di DevExtreme, e vince\n * sul testo predefinito senza doverne ridichiarare altri;\n * 2. **la finestra** — si dichiara `ERROR_PRESENTER`; senza, resta quella predefinita;\n * 3. **tutto** — si realizza `IErrorInfoAppender` per conto proprio e questo pacchetto non serve.\n */\n\nexport * from './lib/error-collector';\nexport * from './lib/error-dialog';\nexport * from './lib/error-messages';\nexport * from './lib/error-presentation';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quanticdigit/web-errors",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "Error collection and presentation: level aggregation, a localized dialog in 31 languages, pluggable presenter.",
|
|
5
5
|
"author": "Quantic Digit S.R.L.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
7
7
|
"homepage": "https://www.quanticdigit.it/",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"peerDependencies": {
|
|
14
14
|
"@angular/core": "^21.2.0",
|
|
15
15
|
"devextreme": "^25.1.3",
|
|
16
|
-
"@quanticdigit/web-services": "1.0.
|
|
16
|
+
"@quanticdigit/web-services": "1.0.3",
|
|
17
|
+
"@quanticdigit/web-logging": "1.0.3"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
20
|
"tslib": "^2.3.0"
|
|
@@ -22,7 +22,7 @@ import { InjectionToken } from '@angular/core';
|
|
|
22
22
|
*/
|
|
23
23
|
declare class ErrorCollector implements IErrorInfoAppender {
|
|
24
24
|
/** Quanto si aspetta prima di mostrare, per raccogliere cio' che arriva nello stesso giro. */
|
|
25
|
-
private static readonly
|
|
25
|
+
private static readonly WAIT_MS;
|
|
26
26
|
/**
|
|
27
27
|
* Come mostrare, quando il modo base non va bene.
|
|
28
28
|
*
|
|
@@ -32,9 +32,18 @@ declare class ErrorCollector implements IErrorInfoAppender {
|
|
|
32
32
|
* quel caso la nostra non viene nemmeno costruita.
|
|
33
33
|
*/
|
|
34
34
|
private readonly presenter;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Il log applicativo, sotto `errors`.
|
|
37
|
+
*
|
|
38
|
+
* @remarks
|
|
39
|
+
* Un errore mostrato all'utente e' un errore che qualcuno vorra' ricostruire dopo, quando la
|
|
40
|
+
* finestra e la persona che la stava guardando non ci sono piu'. Senza writer dichiarato non
|
|
41
|
+
* accade nulla, come ovunque nel resto della famiglia.
|
|
42
|
+
*/
|
|
43
|
+
private readonly appLogger;
|
|
44
|
+
private readonly collected;
|
|
45
|
+
private level;
|
|
46
|
+
private scheduled;
|
|
38
47
|
/** Gli errori non ancora mostrati. */
|
|
39
48
|
get messages(): readonly IErrorInfoModel[];
|
|
40
49
|
/**
|
|
@@ -54,9 +63,9 @@ declare class ErrorCollector implements IErrorInfoAppender {
|
|
|
54
63
|
* Tre chiamate fallite nello stesso istante producono una finestra sola con tre righe, non tre
|
|
55
64
|
* finestre: e' la ragione per cui la presentazione non e' immediata.
|
|
56
65
|
*/
|
|
57
|
-
private
|
|
66
|
+
private schedule;
|
|
58
67
|
/** Mostra quanto accumulato e svuota. */
|
|
59
|
-
private
|
|
68
|
+
private present;
|
|
60
69
|
static ɵfac: i0.ɵɵFactoryDeclaration<ErrorCollector, never>;
|
|
61
70
|
static ɵprov: i0.ɵɵInjectableDeclaration<ErrorCollector>;
|
|
62
71
|
}
|