emilsoftware-utilities 2.0.0-dev.40 → 2.0.0-dev.41
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/dist/accessi-module/Console/accessiFetch.d.ts +9 -0
- package/dist/accessi-module/Console/accessiFetch.js +31 -3
- package/dist/accessi-module/Console/accessiFetch.js.map +1 -1
- package/dist/accessi-module/Console/console.css +8 -3
- package/dist/accessi-module/Console/console.js +85 -22
- package/dist/accessi-module/Console/console.js.map +1 -1
- package/dist/accessi-module/Console/wiki.js +1 -0
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.d.ts +2 -1
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.js +35 -4
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.js.map +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.41.tgz +0 -0
- package/package.json +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.40.tgz +0 -0
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/** Emesso quando una richiesta autenticata riceve 401: la console deve riportare al login. */
|
|
2
|
+
export declare const ACCESSI_UNAUTHORIZED_EVENT = "accessi-console-unauthorized";
|
|
3
|
+
/** Errore del client console: conserva status, codice stabile Accessi e dettagli di validazione. */
|
|
4
|
+
export declare class AccessiRequestError extends Error {
|
|
5
|
+
readonly status: number;
|
|
6
|
+
readonly code?: string | undefined;
|
|
7
|
+
readonly details?: string[] | undefined;
|
|
8
|
+
constructor(message: string, status: number, code?: string | undefined, details?: string[] | undefined);
|
|
9
|
+
}
|
|
1
10
|
/** Imposta il JWT usato da tutte le funzioni generate da Orval. */
|
|
2
11
|
export declare function setAccessiConsoleToken(token: string | null): void;
|
|
3
12
|
/**
|
|
@@ -9,10 +9,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AccessiRequestError = exports.ACCESSI_UNAUTHORIZED_EVENT = void 0;
|
|
12
13
|
exports.setAccessiConsoleToken = setAccessiConsoleToken;
|
|
13
14
|
exports.accessiFetch = accessiFetch;
|
|
14
15
|
let accessToken = null;
|
|
15
16
|
const loadingEventName = 'accessi-console-network';
|
|
17
|
+
/** Emesso quando una richiesta autenticata riceve 401: la console deve riportare al login. */
|
|
18
|
+
exports.ACCESSI_UNAUTHORIZED_EVENT = 'accessi-console-unauthorized';
|
|
19
|
+
/** Errore del client console: conserva status, codice stabile Accessi e dettagli di validazione. */
|
|
20
|
+
class AccessiRequestError extends Error {
|
|
21
|
+
constructor(message, status, code, details) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.status = status;
|
|
24
|
+
this.code = code;
|
|
25
|
+
this.details = details;
|
|
26
|
+
this.name = 'AccessiRequestError';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.AccessiRequestError = AccessiRequestError;
|
|
16
30
|
/** Notifies the browser shell without coupling generated Orval calls to the UI implementation. */
|
|
17
31
|
function notifyNetworkActivity(active) {
|
|
18
32
|
if (typeof window !== 'undefined') {
|
|
@@ -23,18 +37,26 @@ function notifyNetworkActivity(active) {
|
|
|
23
37
|
function setAccessiConsoleToken(token) {
|
|
24
38
|
accessToken = token;
|
|
25
39
|
}
|
|
40
|
+
/** Legge una stringa non vuota dal payload di errore Accessi, ignorando tipi inattesi. */
|
|
41
|
+
function payloadString(payload, key) {
|
|
42
|
+
if (!payload || typeof payload !== 'object')
|
|
43
|
+
return undefined;
|
|
44
|
+
const value = payload[key];
|
|
45
|
+
return typeof value === 'string' && value.length > 0 ? value : undefined;
|
|
46
|
+
}
|
|
26
47
|
/**
|
|
27
48
|
* Trasporto comune del client Orval: aggiunge il Bearer token e converte le
|
|
28
49
|
* risposte di errore Accessi in Error JavaScript leggibili dalla console.
|
|
29
50
|
*/
|
|
30
51
|
function accessiFetch(url, options) {
|
|
31
52
|
return __awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
var _a, _b;
|
|
53
|
+
var _a, _b, _c;
|
|
33
54
|
const headers = new Headers(options.headers);
|
|
34
55
|
headers.set('Accept', 'application/json');
|
|
35
56
|
if (options.body !== undefined && !headers.has('Content-Type')) {
|
|
36
57
|
headers.set('Content-Type', 'application/json');
|
|
37
58
|
}
|
|
59
|
+
const authenticatedRequest = accessToken !== null;
|
|
38
60
|
if (accessToken)
|
|
39
61
|
headers.set('Authorization', `Bearer ${accessToken}`);
|
|
40
62
|
notifyNetworkActivity(true);
|
|
@@ -42,8 +64,14 @@ function accessiFetch(url, options) {
|
|
|
42
64
|
const response = yield fetch(url, Object.assign(Object.assign({}, options), { headers }));
|
|
43
65
|
const payload = yield response.json().catch(() => undefined);
|
|
44
66
|
if (!response.ok) {
|
|
45
|
-
const message = (_b = (_a = payload
|
|
46
|
-
|
|
67
|
+
const message = (_b = (_a = payloadString(payload, 'message')) !== null && _a !== void 0 ? _a : payloadString(payload, 'error')) !== null && _b !== void 0 ? _b : `Errore HTTP ${response.status}`;
|
|
68
|
+
const rawDetails = payload && typeof payload === 'object' ? payload.details : undefined;
|
|
69
|
+
const details = Array.isArray(rawDetails) ? rawDetails.map((item) => String(item)) : undefined;
|
|
70
|
+
// Un 401 su una richiesta autenticata significa sessione scaduta/revocata: il token non e piu valido.
|
|
71
|
+
if (response.status === 401 && authenticatedRequest && typeof window !== 'undefined') {
|
|
72
|
+
window.dispatchEvent(new CustomEvent(exports.ACCESSI_UNAUTHORIZED_EVENT));
|
|
73
|
+
}
|
|
74
|
+
throw new AccessiRequestError(message, response.status, (_c = payloadString(payload, 'code')) !== null && _c !== void 0 ? _c : payloadString(payload, 'error'), details);
|
|
47
75
|
}
|
|
48
76
|
return {
|
|
49
77
|
data: payload,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accessiFetch.js","sourceRoot":"","sources":["../../../src/accessi-module/Console/accessiFetch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"accessiFetch.js","sourceRoot":"","sources":["../../../src/accessi-module/Console/accessiFetch.ts"],"names":[],"mappings":"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","sourcesContent":["let accessToken: string | null = null;\n\nconst loadingEventName = 'accessi-console-network';\n/** Emesso quando una richiesta autenticata riceve 401: la console deve riportare al login. */\nexport const ACCESSI_UNAUTHORIZED_EVENT = 'accessi-console-unauthorized';\n\n/** Errore del client console: conserva status, codice stabile Accessi e dettagli di validazione. */\nexport class AccessiRequestError extends Error {\n constructor(message: string, readonly status: number, readonly code?: string, readonly details?: string[]) {\n super(message);\n this.name = 'AccessiRequestError';\n }\n}\n\n/** Notifies the browser shell without coupling generated Orval calls to the UI implementation. */\nfunction notifyNetworkActivity(active: boolean): void {\n if (typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent(loadingEventName, { detail: { active } }));\n }\n}\n\n/** Imposta il JWT usato da tutte le funzioni generate da Orval. */\nexport function setAccessiConsoleToken(token: string | null): void {\n accessToken = token;\n}\n\n/** Legge una stringa non vuota dal payload di errore Accessi, ignorando tipi inattesi. */\nfunction payloadString(payload: unknown, key: string): string | undefined {\n if (!payload || typeof payload !== 'object') return undefined;\n const value = (payload as Record<string, unknown>)[key];\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\n/**\n * Trasporto comune del client Orval: aggiunge il Bearer token e converte le\n * risposte di errore Accessi in Error JavaScript leggibili dalla console.\n */\nexport async function accessiFetch<T>(url: string, options: RequestInit): Promise<T> {\n const headers = new Headers(options.headers);\n headers.set('Accept', 'application/json');\n if (options.body !== undefined && !headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json');\n }\n const authenticatedRequest = accessToken !== null;\n if (accessToken) headers.set('Authorization', `Bearer ${accessToken}`);\n\n notifyNetworkActivity(true);\n try {\n const response = await fetch(url, { ...options, headers });\n const payload = await response.json().catch(() => undefined);\n if (!response.ok) {\n const message = payloadString(payload, 'message') ?? payloadString(payload, 'error') ?? `Errore HTTP ${response.status}`;\n const rawDetails = payload && typeof payload === 'object' ? (payload as { details?: unknown }).details : undefined;\n const details = Array.isArray(rawDetails) ? rawDetails.map((item) => String(item)) : undefined;\n // Un 401 su una richiesta autenticata significa sessione scaduta/revocata: il token non e piu valido.\n if (response.status === 401 && authenticatedRequest && typeof window !== 'undefined') {\n window.dispatchEvent(new CustomEvent(ACCESSI_UNAUTHORIZED_EVENT));\n }\n throw new AccessiRequestError(message, response.status, payloadString(payload, 'code') ?? payloadString(payload, 'error'), details);\n }\n return {\n data: payload,\n status: response.status,\n headers: response.headers,\n } as T;\n } finally {\n notifyNetworkActivity(false);\n }\n}\n"]}
|
|
@@ -263,9 +263,14 @@ legend { padding: 0 var(--s2); color: var(--ink-2); font-weight: 650; font-size:
|
|
|
263
263
|
.error { color: var(--danger); }
|
|
264
264
|
|
|
265
265
|
#notice { min-height: 0; }
|
|
266
|
-
#notice:not(:empty) { margin: 0
|
|
267
|
-
|
|
268
|
-
|
|
266
|
+
#notice:not(:empty) { margin: 0 0 var(--s4); }
|
|
267
|
+
.notice { display: flex; align-items: flex-start; gap: var(--s3); padding: var(--s3) var(--s4); border: 1px solid var(--brand-line); border-radius: var(--r-md); color: var(--brand-strong); background: var(--brand-soft); }
|
|
268
|
+
.notice-error { border-color: var(--danger-line); color: var(--danger); background: var(--danger-soft); }
|
|
269
|
+
.notice-icon { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 1.3rem; height: 1.3rem; border-radius: 50%; color: #fff; background: var(--brand-strong); font-weight: 700; font-size: .82rem; }
|
|
270
|
+
.notice-error .notice-icon { background: var(--danger); }
|
|
271
|
+
.notice-text { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
|
|
272
|
+
.notice-close { flex: 0 0 auto; padding: 0 .2rem; border: 0; background: none; color: inherit; font-size: 1.15rem; line-height: 1; cursor: pointer; opacity: .7; }
|
|
273
|
+
.notice-close:hover, .notice-close:focus-visible { opacity: 1; }
|
|
269
274
|
|
|
270
275
|
.page-header { display: flex; align-items: end; justify-content: space-between; gap: var(--s4); margin: 0 0 var(--s5); padding-bottom: var(--s4); border-bottom: 1px solid var(--line); }
|
|
271
276
|
.page-header h2 { margin: 0; }
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
// src/accessi-module/Console/accessiFetch.ts
|
|
2
2
|
var accessToken = null;
|
|
3
3
|
var loadingEventName = "accessi-console-network";
|
|
4
|
+
var ACCESSI_UNAUTHORIZED_EVENT = "accessi-console-unauthorized";
|
|
5
|
+
var AccessiRequestError = class extends Error {
|
|
6
|
+
constructor(message, status, code3, details) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.code = code3;
|
|
10
|
+
this.details = details;
|
|
11
|
+
this.name = "AccessiRequestError";
|
|
12
|
+
}
|
|
13
|
+
};
|
|
4
14
|
function notifyNetworkActivity(active) {
|
|
5
15
|
if (typeof window !== "undefined") {
|
|
6
16
|
window.dispatchEvent(new CustomEvent(loadingEventName, { detail: { active } }));
|
|
@@ -9,20 +19,31 @@ function notifyNetworkActivity(active) {
|
|
|
9
19
|
function setAccessiConsoleToken(token2) {
|
|
10
20
|
accessToken = token2;
|
|
11
21
|
}
|
|
22
|
+
function payloadString(payload, key) {
|
|
23
|
+
if (!payload || typeof payload !== "object") return void 0;
|
|
24
|
+
const value = payload[key];
|
|
25
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
26
|
+
}
|
|
12
27
|
async function accessiFetch(url, options) {
|
|
13
28
|
const headers = new Headers(options.headers);
|
|
14
29
|
headers.set("Accept", "application/json");
|
|
15
30
|
if (options.body !== void 0 && !headers.has("Content-Type")) {
|
|
16
31
|
headers.set("Content-Type", "application/json");
|
|
17
32
|
}
|
|
33
|
+
const authenticatedRequest = accessToken !== null;
|
|
18
34
|
if (accessToken) headers.set("Authorization", `Bearer ${accessToken}`);
|
|
19
35
|
notifyNetworkActivity(true);
|
|
20
36
|
try {
|
|
21
37
|
const response = await fetch(url, { ...options, headers });
|
|
22
38
|
const payload = await response.json().catch(() => void 0);
|
|
23
39
|
if (!response.ok) {
|
|
24
|
-
const message = payload
|
|
25
|
-
|
|
40
|
+
const message = payloadString(payload, "message") ?? payloadString(payload, "error") ?? `Errore HTTP ${response.status}`;
|
|
41
|
+
const rawDetails = payload && typeof payload === "object" ? payload.details : void 0;
|
|
42
|
+
const details = Array.isArray(rawDetails) ? rawDetails.map((item) => String(item)) : void 0;
|
|
43
|
+
if (response.status === 401 && authenticatedRequest && typeof window !== "undefined") {
|
|
44
|
+
window.dispatchEvent(new CustomEvent(ACCESSI_UNAUTHORIZED_EVENT));
|
|
45
|
+
}
|
|
46
|
+
throw new AccessiRequestError(message, response.status, payloadString(payload, "code") ?? payloadString(payload, "error"), details);
|
|
26
47
|
}
|
|
27
48
|
return {
|
|
28
49
|
data: payload,
|
|
@@ -959,7 +980,8 @@ var WIKI_SECTIONS = [
|
|
|
959
980
|
]),
|
|
960
981
|
code("bash", `npm run db:update:accessi # riconcilia lo schema
|
|
961
982
|
npm run db:check:accessi # verifica senza modificare`, "CLI schema"),
|
|
962
|
-
note("warn", `Versioni`, `La libreria richiede uno schema compatibile con la versione corrente (ACCESSI_SCHEMA_VERSION). Se la verifica fallisce, leggi il codice errore ACCESSI_DATABASE_SCHEMA_OUTDATED ed esegui db:update:accessi.`)
|
|
983
|
+
note("warn", `Versioni`, `La libreria richiede uno schema compatibile con la versione corrente (ACCESSI_SCHEMA_VERSION). Se la verifica fallisce, leggi il codice errore ACCESSI_DATABASE_SCHEMA_OUTDATED ed esegui db:update:accessi.`),
|
|
984
|
+
note("info", `Schema esatto`, `La riconciliazione allinea le tabelle Accessi a "niente in piu, niente in meno": le colonne non previste vengono segnalate come incompatibili e rimosse automaticamente (dopo rename e copie dei dati legacy). Gli indici, i trigger e i CHECK extra non previsti non vengono tolti, ma un indice non previsto su una tabella Accessi viene riportato come avviso senza bloccare l'avvio.`)
|
|
963
985
|
]
|
|
964
986
|
},
|
|
965
987
|
// -------------------------------------------------------------------------
|
|
@@ -1950,8 +1972,24 @@ function result(response) {
|
|
|
1950
1972
|
if (body.Result === void 0) throw new Error(body.message ?? "Risposta Accessi priva di dati.");
|
|
1951
1973
|
return body.Result;
|
|
1952
1974
|
}
|
|
1975
|
+
var noticeTimer;
|
|
1953
1976
|
function showNotice(message, isError = false) {
|
|
1954
|
-
|
|
1977
|
+
const container = byId("notice");
|
|
1978
|
+
if (noticeTimer !== void 0) {
|
|
1979
|
+
window.clearTimeout(noticeTimer);
|
|
1980
|
+
noticeTimer = void 0;
|
|
1981
|
+
}
|
|
1982
|
+
if (!message) {
|
|
1983
|
+
container.innerHTML = "";
|
|
1984
|
+
return;
|
|
1985
|
+
}
|
|
1986
|
+
const kind = isError ? "error" : "success";
|
|
1987
|
+
const icon = isError ? "!" : "\u2713";
|
|
1988
|
+
container.innerHTML = `<div class="notice notice-${kind}${isError ? " error" : ""}" role="alert"><span class="notice-icon" aria-hidden="true">${icon}</span><span class="notice-text">${escapeHtml(message)}</span><button type="button" class="notice-close" aria-label="Chiudi il messaggio">×</button></div>`;
|
|
1989
|
+
container.querySelector(".notice-close")?.addEventListener("click", () => showNotice(""));
|
|
1990
|
+
if (!isError) {
|
|
1991
|
+
noticeTimer = window.setTimeout(() => showNotice(""), 6e3);
|
|
1992
|
+
}
|
|
1955
1993
|
}
|
|
1956
1994
|
function menuMetadata(menu) {
|
|
1957
1995
|
const details = [
|
|
@@ -2074,7 +2112,13 @@ function finishBoot(view) {
|
|
|
2074
2112
|
byId("console").hidden = view !== "console";
|
|
2075
2113
|
}
|
|
2076
2114
|
function errorMessage(error) {
|
|
2077
|
-
|
|
2115
|
+
if (!(error instanceof Error)) return "Operazione non riuscita.";
|
|
2116
|
+
const extra = error;
|
|
2117
|
+
const code3 = typeof extra.code === "string" ? extra.code : void 0;
|
|
2118
|
+
const details = Array.isArray(extra.details) ? extra.details.map((item) => String(item)) : [];
|
|
2119
|
+
const detailSuffix = details.length ? ` (${details.join("; ")})` : "";
|
|
2120
|
+
const message = code3 && !error.message.startsWith(`${code3}:`) ? `${code3}: ${error.message}` : error.message;
|
|
2121
|
+
return `${message}${detailSuffix}`;
|
|
2078
2122
|
}
|
|
2079
2123
|
function handleAction(action) {
|
|
2080
2124
|
void action().catch((error) => showNotice(errorMessage(error), true));
|
|
@@ -2612,12 +2656,14 @@ async function showUser(rawCode) {
|
|
|
2612
2656
|
handleAction(async () => {
|
|
2613
2657
|
const values = formValues(eventForm(event));
|
|
2614
2658
|
await linkFederatedIdentity(codiceUtente, { provider: values.provider ?? "", subject: values.subject ?? "", note: values.note || void 0 });
|
|
2659
|
+
showNotice("Collegamento SSO registrato.");
|
|
2615
2660
|
await showUser(String(codiceUtente));
|
|
2616
2661
|
});
|
|
2617
2662
|
};
|
|
2618
2663
|
document.querySelectorAll("[data-identity-toggle]").forEach((button) => {
|
|
2619
2664
|
button.onclick = () => handleAction(async () => {
|
|
2620
2665
|
await updateFederatedIdentity(button.dataset.identityToggle ?? "", { active: button.dataset.active === "true" });
|
|
2666
|
+
showNotice("Collegamento SSO aggiornato.");
|
|
2621
2667
|
await showUser(String(codiceUtente));
|
|
2622
2668
|
});
|
|
2623
2669
|
});
|
|
@@ -2659,14 +2705,17 @@ async function showRoles() {
|
|
|
2659
2705
|
};
|
|
2660
2706
|
});
|
|
2661
2707
|
const roleFormElement = document.getElementById("role-form");
|
|
2662
|
-
if (roleFormElement) roleFormElement.onsubmit =
|
|
2708
|
+
if (roleFormElement) roleFormElement.onsubmit = (event) => {
|
|
2663
2709
|
event.preventDefault();
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2710
|
+
handleAction(async () => {
|
|
2711
|
+
const form = eventForm(event);
|
|
2712
|
+
const data = new FormData(form);
|
|
2713
|
+
const request = { descrizioneRuolo: formValues(form).descrizione ?? "", menu: Array.from(data.getAll("menu"), (codiceMenu) => ({ codiceMenu: String(codiceMenu), tipoAbilitazione: Number(data.get(`menu-level:${codiceMenu}`) ?? 10) })) };
|
|
2714
|
+
if (role?.codiceRuolo) await updateRole(role.codiceRuolo, request);
|
|
2715
|
+
else await createRole(request);
|
|
2716
|
+
showNotice(role?.codiceRuolo ? "Ruolo aggiornato." : "Ruolo creato.");
|
|
2717
|
+
await show("roles");
|
|
2718
|
+
});
|
|
2670
2719
|
};
|
|
2671
2720
|
};
|
|
2672
2721
|
byId("new-role").onclick = () => roleForm();
|
|
@@ -2879,19 +2928,22 @@ async function showFilters() {
|
|
|
2879
2928
|
const users = await loadUsers();
|
|
2880
2929
|
render(`<h2>Filtri utente</h2><p class="form-help">Filtri applicativi salvati per singolo utente.</p><form id="filters"><label>Utente ${helpDot("filters-user")}<select name="codUte">${users.map(({ utente }) => `<option value="${utente.codiceUtente}">${escapeHtml(utente.email)}</option>`).join("")}</select><span class="form-help">Salvati per l'utente selezionato.</span></label><label>Filtro JSON ${helpDot("filters-json")}<textarea name="json" rows="12">{}</textarea><span class="form-help">Usa Carica per partire dalla struttura esistente.</span></label><button name="action" value="load">Carica</button><button name="action" value="save">Salva</button></form>`);
|
|
2881
2930
|
const filtersForm = document.getElementById("filters");
|
|
2882
|
-
if (filtersForm) filtersForm.onsubmit =
|
|
2931
|
+
if (filtersForm) filtersForm.onsubmit = (event) => {
|
|
2883
2932
|
event.preventDefault();
|
|
2884
2933
|
const form = eventForm(event);
|
|
2885
2934
|
const action = event.submitter?.value;
|
|
2886
2935
|
const code3 = Number(formValues(form).codUte);
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2936
|
+
handleAction(async () => {
|
|
2937
|
+
if (action === "load") {
|
|
2938
|
+
const filters = result(await getFiltriUtente({ codUte: code3 }));
|
|
2939
|
+
form.elements.namedItem("json").value = JSON.stringify(filters[0] ?? { codUte: code3 }, null, 2);
|
|
2940
|
+
showNotice("Filtri caricati.");
|
|
2941
|
+
} else {
|
|
2942
|
+
const parsed = JSON.parse(formValues(form).json ?? "{}");
|
|
2943
|
+
await saveFiltriUtente({ ...parsed, codUte: code3 });
|
|
2944
|
+
showNotice("Filtri salvati.");
|
|
2945
|
+
}
|
|
2946
|
+
});
|
|
2895
2947
|
};
|
|
2896
2948
|
}
|
|
2897
2949
|
async function showFilterTypes() {
|
|
@@ -2972,6 +3024,7 @@ async function showServiceTokens(includeRevoked = false) {
|
|
|
2972
3024
|
document.querySelectorAll("[data-rotate]").forEach((button) => {
|
|
2973
3025
|
button.onclick = () => handleAction(async () => {
|
|
2974
3026
|
const issued = result(await rotateServiceToken(button.dataset.rotate ?? ""));
|
|
3027
|
+
showNotice("Token di servizio ruotato.");
|
|
2975
3028
|
showIssuedServiceToken(issued);
|
|
2976
3029
|
});
|
|
2977
3030
|
});
|
|
@@ -2991,6 +3044,7 @@ function showServiceTokenForm() {
|
|
|
2991
3044
|
scopes: scopes.length ? scopes : void 0,
|
|
2992
3045
|
ttlDays: Number.isFinite(ttlDays) ? ttlDays : void 0
|
|
2993
3046
|
}));
|
|
3047
|
+
showNotice("Token di servizio creato.");
|
|
2994
3048
|
showIssuedServiceToken(issued);
|
|
2995
3049
|
});
|
|
2996
3050
|
};
|
|
@@ -3219,7 +3273,6 @@ async function showSql() {
|
|
|
3219
3273
|
}
|
|
3220
3274
|
async function show(view) {
|
|
3221
3275
|
try {
|
|
3222
|
-
showNotice("");
|
|
3223
3276
|
const views = {
|
|
3224
3277
|
users: showUsers,
|
|
3225
3278
|
roles: showRoles,
|
|
@@ -3310,6 +3363,16 @@ byId("nav").onclick = (event) => {
|
|
|
3310
3363
|
window.addEventListener("popstate", () => {
|
|
3311
3364
|
if (token && currentUser) handleAction(() => show(viewFromLocation()));
|
|
3312
3365
|
});
|
|
3366
|
+
window.addEventListener(ACCESSI_UNAUTHORIZED_EVENT, () => {
|
|
3367
|
+
if (!token) return;
|
|
3368
|
+
token = null;
|
|
3369
|
+
currentUser = null;
|
|
3370
|
+
setAccessiConsoleToken(null);
|
|
3371
|
+
sessionStorage.removeItem("accessi-console-token");
|
|
3372
|
+
finishBoot("login");
|
|
3373
|
+
resetLogin();
|
|
3374
|
+
byId("login-error").textContent = "Sessione scaduta o non piu valida. Accedi di nuovo.";
|
|
3375
|
+
});
|
|
3313
3376
|
window.addEventListener("accessi-console-network", (event) => {
|
|
3314
3377
|
updateLoadingState(event.detail.active);
|
|
3315
3378
|
});
|