diff --git a/Tool/config.py b/Tool/config.py index bb7a66e..9d8b5ab 100644 --- a/Tool/config.py +++ b/Tool/config.py @@ -11,8 +11,8 @@ REPORTS_DIR = Path(__file__).resolve().parent.parent load_dotenv(REPORTS_DIR / '.env') TMPL_DIR = REPORTS_DIR / "templates" -CSS_PATH = REPORTS_DIR / "static" / "style.css" -PAGES_CSS_DIR = REPORTS_DIR / "static" / "pages" +CSS_PATH = REPORTS_DIR / "static" / "css" / "style.css" +PAGES_CSS_DIR = REPORTS_DIR / "static" / "css" JS_DIR = REPORTS_DIR / "static" / "js" class DbType(StrEnum): diff --git a/Tool/queries/api_iscrizioni.py b/Tool/queries/api_iscrizioni.py index 37cef7b..6876a7f 100644 --- a/Tool/queries/api_iscrizioni.py +++ b/Tool/queries/api_iscrizioni.py @@ -20,6 +20,7 @@ def get_iscrizioni(db_path: str) -> list: i.updated_at FROM rpa_intra_api_iscrizione i LEFT JOIN rpa_mapping_aziende m ON m.id = i.azienda_sorgente_id + WHERE date(i.created_at) >= date('now', '-10 days') ORDER BY i.id DESC LIMIT 500 """) diff --git a/Tool/queries/db.py b/Tool/queries/db.py index d9b0c45..a171c70 100644 --- a/Tool/queries/db.py +++ b/Tool/queries/db.py @@ -20,6 +20,11 @@ def count(db_path: str, sql: str) -> int: return rows[0]['n'] if rows else 0 +def count_q(db_path: str, sql: str, params: tuple = ()) -> int: + rows = query(db_path, sql, params) + return rows[0]['n'] if rows else 0 + + # ------------------------------------------------------------------ HTML utils def e(v) -> str: diff --git a/Tool/queries/email.py b/Tool/queries/email.py index 12ef7da..69bbb9f 100644 --- a/Tool/queries/email.py +++ b/Tool/queries/email.py @@ -1,6 +1,6 @@ """queries/email.py — rpa_intra_email_queue (Intraz)""" -from .db import query, count, e, dt, badge +from .db import query, count, count_q, e, dt, badge def get_email(db_path: str) -> list: @@ -8,16 +8,23 @@ def get_email(db_path: str) -> list: "SELECT id, iscrizione_id, recipient, subject, attachment_path, " "inviata, inviata_at, errore, created_at " "FROM rpa_intra_email_queue " + "WHERE date(created_at) >= date('now', '-10 days') " "ORDER BY created_at DESC LIMIT 200" ) -def get_stats(db_path: str) -> dict: +def get_stats(db_path: str, date_from: str = None, date_to: str = None) -> dict: + conds, params = [], [] + if date_from: conds.append("date(created_at) >= ?"); params.append(date_from) + if date_to: conds.append("date(created_at) <= ?"); params.append(date_to) + where = (" WHERE " + " AND ".join(conds)) if conds else "" + and_pfx = (" AND" if conds else " WHERE") + t = tuple(params) return { - 'email_total': count(db_path, "SELECT COUNT(*) as n FROM rpa_intra_email_queue"), - 'email_inviata': count(db_path, "SELECT COUNT(*) as n FROM rpa_intra_email_queue WHERE inviata=1"), - 'email_errore': count(db_path, "SELECT COUNT(*) as n FROM rpa_intra_email_queue WHERE inviata=0 AND errore IS NOT NULL"), - 'email_pending': count(db_path, "SELECT COUNT(*) as n FROM rpa_intra_email_queue WHERE inviata=0 AND errore IS NULL"), + 'email_total': count_q(db_path, f"SELECT COUNT(*) as n FROM rpa_intra_email_queue{where}", t), + 'email_inviata': count_q(db_path, f"SELECT COUNT(*) as n FROM rpa_intra_email_queue{where}{and_pfx} inviata=1", t), + 'email_errore': count_q(db_path, f"SELECT COUNT(*) as n FROM rpa_intra_email_queue{where}{and_pfx} inviata=0 AND errore IS NOT NULL", t), + 'email_pending': count_q(db_path, f"SELECT COUNT(*) as n FROM rpa_intra_email_queue{where}{and_pfx} inviata=0 AND errore IS NULL", t), } diff --git a/Tool/queries/iscrizioni.py b/Tool/queries/iscrizioni.py index 4803cf2..52e43e0 100644 --- a/Tool/queries/iscrizioni.py +++ b/Tool/queries/iscrizioni.py @@ -42,6 +42,7 @@ def get_corsi(db_path: str) -> list: LEFT JOIN rpa_mapping_aziende m ON m.company_code = f.company_code LEFT JOIN rpa_intra_steps_status s ON s.rpa_intra_ftp_json_id = f.id LEFT JOIN rpa_intra_bc_check bc ON bc.rpa_intra_ftp_json_id = f.id + WHERE date(f.created_at) >= date('now', '-10 days') ORDER BY f.id DESC """) @@ -67,8 +68,18 @@ def _step_cell(step_val, err_val) -> str: return badge_html -def get_stats(db_path: str) -> dict: - rows = get_corsi(db_path) +def get_stats(db_path: str, date_from: str = None, date_to: str = None) -> dict: + conds, params = [], [] + if date_from: conds.append("date(f.created_at) >= ?"); params.append(date_from) + if date_to: conds.append("date(f.created_at) <= ?"); params.append(date_to) + where = (" WHERE " + " AND ".join(conds)) if conds else "" + rows = query(db_path, f""" + SELECT s.step_ftp, s.step_bc, s.step_iscrizione, s.step_odv, + s.step_sharepoint, s.step_report, s.step_email + FROM rpa_intra_ftp_json f + LEFT JOIN rpa_intra_steps_status s ON s.rpa_intra_ftp_json_id = f.id + {where} + """, tuple(params)) return { 'isc_total': len(rows), 'isc_ok': sum(1 for r in rows if all(r.get(s) in ('done', 'skipped') for s in _ALL_STEPS)), diff --git a/Tool/queries/logs.py b/Tool/queries/logs.py index a370d8f..b8c3ac4 100644 --- a/Tool/queries/logs.py +++ b/Tool/queries/logs.py @@ -1,6 +1,6 @@ """queries/logs.py — rpa_logs""" -from .db import query, count, e, dt, badge +from .db import query, count, count_q, e, dt, badge def get_logs(db_path: str) -> list: @@ -8,6 +8,7 @@ def get_logs(db_path: str) -> list: "SELECT l.*, COALESCE(p.process_name, 'unknown') AS process_name " "FROM rpa_logs l " "LEFT JOIN rpa_process p ON p.id = l.rpa_process_id " + "WHERE date(l.date_log) >= date('now', '-10 days') " "ORDER BY l.date_log DESC LIMIT 500") @@ -19,6 +20,7 @@ def get_last_run_ids(db_path: str, n: int = 20) -> list: "FROM rpa_logs l " "LEFT JOIN rpa_process p ON p.id = l.rpa_process_id " "WHERE l.rpa_process_id IS NOT NULL " + "AND date(l.date_log) >= date('now', '-10 days') " "GROUP BY l.rpa_process_id ORDER BY l.rpa_process_id DESC LIMIT ?", (n,)) @@ -30,10 +32,16 @@ def get_logs_by_run(db_path: str, run_id: int) -> list: "WHERE l.rpa_process_id=? ORDER BY l.date_log DESC", (run_id,)) -def get_stats(db_path: str) -> dict: +def get_stats(db_path: str, date_from: str = None, date_to: str = None) -> dict: + conds, params = [], [] + if date_from: conds.append("date(date_log) >= ?"); params.append(date_from) + if date_to: conds.append("date(date_log) <= ?"); params.append(date_to) + where = (" WHERE " + " AND ".join(conds)) if conds else "" + and_pfx = (" AND" if conds else " WHERE") + t = tuple(params) return { - 'log_errors': count(db_path, "SELECT COUNT(*) as n FROM rpa_logs WHERE type='error'"), - 'log_warnings': count(db_path, "SELECT COUNT(*) as n FROM rpa_logs WHERE type='warning'"), + 'log_errors': count_q(db_path, f"SELECT COUNT(*) as n FROM rpa_logs{where}{and_pfx} type='error'", t), + 'log_warnings': count_q(db_path, f"SELECT COUNT(*) as n FROM rpa_logs{where}{and_pfx} type='warning'", t), } diff --git a/Tool/queries/pec.py b/Tool/queries/pec.py index a8866b0..1a68318 100644 --- a/Tool/queries/pec.py +++ b/Tool/queries/pec.py @@ -1,6 +1,6 @@ """queries/pec.py — pec_comunicazioni""" -from .db import query, count, e, dt, badge +from .db import query, count, count_q, e, dt, badge _PEC_JOIN = """ SELECT @@ -16,15 +16,21 @@ _PEC_JOIN = """ def get_pec(db_path: str) -> list: - return query(db_path, _PEC_JOIN + "ORDER BY p.created_at DESC LIMIT 200") + return query(db_path, _PEC_JOIN + "WHERE date(p.created_at) >= date('now', '-10 days') ORDER BY p.created_at DESC LIMIT 200") -def get_stats(db_path: str) -> dict: +def get_stats(db_path: str, date_from: str = None, date_to: str = None) -> dict: + conds, params = [], [] + if date_from: conds.append("date(created_at) >= ?"); params.append(date_from) + if date_to: conds.append("date(created_at) <= ?"); params.append(date_to) + where = (" WHERE " + " AND ".join(conds)) if conds else "" + and_pfx = (" AND" if conds else " WHERE") + t = tuple(params) return { - 'total_pec': count(db_path, "SELECT COUNT(*) as n FROM pec_comunicazioni"), - 'pec_inviato': count(db_path, "SELECT COUNT(*) as n FROM pec_comunicazioni WHERE stato_invio='inviata'"), - 'pec_errore': count(db_path, "SELECT COUNT(*) as n FROM pec_comunicazioni WHERE stato_invio='errore'"), - 'pec_pending': count(db_path, "SELECT COUNT(*) as n FROM pec_comunicazioni WHERE stato_invio='pending'"), + 'total_pec': count_q(db_path, f"SELECT COUNT(*) as n FROM pec_comunicazioni{where}", t), + 'pec_inviato': count_q(db_path, f"SELECT COUNT(*) as n FROM pec_comunicazioni{where}{and_pfx} stato_invio='inviata'", t), + 'pec_errore': count_q(db_path, f"SELECT COUNT(*) as n FROM pec_comunicazioni{where}{and_pfx} stato_invio='errore'", t), + 'pec_pending': count_q(db_path, f"SELECT COUNT(*) as n FROM pec_comunicazioni{where}{and_pfx} stato_invio='pending'", t), } diff --git a/Tool/queries/processes.py b/Tool/queries/processes.py index 37c1884..95a67eb 100644 --- a/Tool/queries/processes.py +++ b/Tool/queries/processes.py @@ -1,18 +1,27 @@ """queries/processes.py — rpa_process""" -from .db import query, count, e, dt, dur, badge +from .db import query, count, count_q, e, dt, dur, badge def get_processes(db_path: str) -> list: - return query(db_path, "SELECT id, process_name, note, completed, start_run, finish_run FROM rpa_process ORDER BY id DESC LIMIT 50") + return query(db_path, + "SELECT id, process_name, note, completed, start_run, finish_run FROM rpa_process " + "WHERE date(start_run) >= date('now', '-10 days') " + "ORDER BY id DESC LIMIT 50") -def get_stats(db_path: str) -> dict: - total = count(db_path, "SELECT COUNT(*) as n FROM rpa_process") - completed = count(db_path, "SELECT COUNT(*) as n FROM rpa_process WHERE completed = 1") +def get_stats(db_path: str, date_from: str = None, date_to: str = None) -> dict: + conds, params = [], [] + if date_from: conds.append("date(start_run) >= ?"); params.append(date_from) + if date_to: conds.append("date(start_run) <= ?"); params.append(date_to) + where = (" WHERE " + " AND ".join(conds)) if conds else "" + and_pfx = (" AND" if conds else " WHERE") + t = tuple(params) + total = count_q(db_path, f"SELECT COUNT(*) as n FROM rpa_process{where}", t) + completed = count_q(db_path, f"SELECT COUNT(*) as n FROM rpa_process{where}{and_pfx} completed=1", t) return { - 'total_runs': total, - 'completed_runs': completed, + 'total_runs': total, + 'completed_runs': completed, 'incomplete_runs': total - completed, } diff --git a/Tool/queries/report.py b/Tool/queries/report.py index ab4a3e0..85d2ff6 100644 --- a/Tool/queries/report.py +++ b/Tool/queries/report.py @@ -17,7 +17,9 @@ def get_report(db_path: str, da_data: str = None, a_data: str = None) -> list: where.append("sc.rilevato_at <= ?") params.append(a_data + " 23:59:59") - where_sql = ("WHERE " + " AND ".join(where)) if where else "" + if not where: + where.append("date(sc.rilevato_at) >= date('now', '-10 days')") + where_sql = "WHERE " + " AND ".join(where) sql = f""" SELECT diff --git a/Tool/queries/sharepoint.py b/Tool/queries/sharepoint.py index f9daccf..3a837ef 100644 --- a/Tool/queries/sharepoint.py +++ b/Tool/queries/sharepoint.py @@ -14,6 +14,7 @@ def get_sharepoint(db_path: str) -> list: json_extract(f.azienda, '$.ragione_sociale') AS azienda_nome FROM rpa_intra_sharepoint sp LEFT JOIN rpa_intra_ftp_json f ON f.id = sp.rpa_intra_ftp_json_id + WHERE date(sp.created_at) >= date('now', '-10 days') ORDER BY sp.id DESC LIMIT 500 """) diff --git a/Tool/renderer.py b/Tool/renderer.py index 08bab03..1cc43a2 100644 --- a/Tool/renderer.py +++ b/Tool/renderer.py @@ -10,29 +10,37 @@ def _css() -> str: return CSS_PATH.read_text(encoding='utf-8') +def _page_subdirs(base: Path) -> list: + """Return direct subdirectories of base, excluding 'shared'.""" + return [d for d in sorted(base.iterdir()) if d.is_dir() and d.name != 'shared'] + + def _page_css(name: str) -> str: parts = [] shared = PAGES_CSS_DIR / 'filters.css' if shared.exists(): parts.append(shared.read_text(encoding='utf-8')) - main = PAGES_CSS_DIR / f'{name}.css' - if main.exists(): - parts.append(main.read_text(encoding='utf-8')) - for f in sorted(PAGES_CSS_DIR.glob(f'{name}_*.css')): - parts.append(f.read_text(encoding='utf-8')) + for search_dir in [PAGES_CSS_DIR] + _page_subdirs(PAGES_CSS_DIR): + main = search_dir / f'{name}.css' + if main.exists(): + parts.append(main.read_text(encoding='utf-8')) + for f in sorted(search_dir.glob(f'{name}_*.css')): + parts.append(f.read_text(encoding='utf-8')) return '\n'.join(parts) def _page_js(name: str) -> str: parts = [] - shared = JS_DIR / 'filters.js' - if shared.exists(): - parts.append(shared.read_text(encoding='utf-8')) - main = JS_DIR / f'{name}.js' - if main.exists(): - parts.append(main.read_text(encoding='utf-8')) - for f in sorted(JS_DIR.glob(f'{name}_*.js')): - parts.append(f.read_text(encoding='utf-8')) + shared_dir = JS_DIR / 'shared' + if shared_dir.exists(): + for f in sorted(shared_dir.glob('*.js')): + parts.append(f.read_text(encoding='utf-8')) + for search_dir in [JS_DIR] + _page_subdirs(JS_DIR): + main = search_dir / f'page_{name}.js' + if main.exists(): + parts.append(main.read_text(encoding='utf-8')) + for f in sorted(search_dir.glob(f'page_{name}_*.js')): + parts.append(f.read_text(encoding='utf-8')) return '\n'.join(parts) diff --git a/static/pages/api_iscrizioni.css b/static/css/RPA_Intraz/api_iscrizioni.css similarity index 100% rename from static/pages/api_iscrizioni.css rename to static/css/RPA_Intraz/api_iscrizioni.css diff --git a/static/pages/email.css b/static/css/RPA_Intraz/email.css similarity index 100% rename from static/pages/email.css rename to static/css/RPA_Intraz/email.css diff --git a/static/pages/iscrizioni.css b/static/css/RPA_Intraz/iscrizioni.css similarity index 100% rename from static/pages/iscrizioni.css rename to static/css/RPA_Intraz/iscrizioni.css diff --git a/static/pages/documenti.css b/static/css/RPA_Reg Lom/documenti.css similarity index 100% rename from static/pages/documenti.css rename to static/css/RPA_Reg Lom/documenti.css diff --git a/static/pages/documenti_filters.css b/static/css/RPA_Reg Lom/documenti_filters.css similarity index 100% rename from static/pages/documenti_filters.css rename to static/css/RPA_Reg Lom/documenti_filters.css diff --git a/static/pages/pec.css b/static/css/RPA_Reg Lom/pec.css similarity index 100% rename from static/pages/pec.css rename to static/css/RPA_Reg Lom/pec.css diff --git a/static/pages/report.css b/static/css/RPA_Reg Lom/report.css similarity index 100% rename from static/pages/report.css rename to static/css/RPA_Reg Lom/report.css diff --git a/static/css/dashboard.css b/static/css/dashboard.css new file mode 100644 index 0000000..d02caac --- /dev/null +++ b/static/css/dashboard.css @@ -0,0 +1,10 @@ +/* dashboard.css — stili specifici per la pagina Dashboard */ +.sec-link{color:inherit;text-decoration:none} +.sec-link:hover{text-decoration:underline;text-underline-offset:3px} + +/* Section collapse toggle */ +.sec-toggle-btn{background:none;border:none;cursor:pointer;padding:0 0 0 .5rem;vertical-align:middle;color:inherit;opacity:.6;line-height:1} +.sec-toggle-btn:hover{opacity:1} +.sec-toggle-arrow{width:1.1em;height:1.1em;display:inline-block;transition:transform .22s ease;transform:rotate(-90deg)} +.sec-toggle-arrow.open{transform:rotate(0deg)} +.dash-grid-hidden{display:none} diff --git a/static/pages/filters.css b/static/css/filters.css similarity index 100% rename from static/pages/filters.css rename to static/css/filters.css diff --git a/static/pages/logs.css b/static/css/logs.css similarity index 100% rename from static/pages/logs.css rename to static/css/logs.css diff --git a/static/pages/runs.css b/static/css/runs.css similarity index 100% rename from static/pages/runs.css rename to static/css/runs.css diff --git a/static/pages/schema.css b/static/css/schema.css similarity index 100% rename from static/pages/schema.css rename to static/css/schema.css diff --git a/static/pages/server-logs.css b/static/css/server-logs.css similarity index 100% rename from static/pages/server-logs.css rename to static/css/server-logs.css diff --git a/static/style.css b/static/css/style.css similarity index 100% rename from static/style.css rename to static/css/style.css diff --git a/static/js/api_iscrizioni.js b/static/js/RPA_Intraz/page_api_iscrizioni.js similarity index 100% rename from static/js/api_iscrizioni.js rename to static/js/RPA_Intraz/page_api_iscrizioni.js diff --git a/static/js/email.js b/static/js/RPA_Intraz/page_email.js similarity index 100% rename from static/js/email.js rename to static/js/RPA_Intraz/page_email.js diff --git a/static/js/iscrizioni.js b/static/js/RPA_Intraz/page_iscrizioni.js similarity index 98% rename from static/js/iscrizioni.js rename to static/js/RPA_Intraz/page_iscrizioni.js index 794e772..f701a51 100644 --- a/static/js/iscrizioni.js +++ b/static/js/RPA_Intraz/page_iscrizioni.js @@ -13,7 +13,7 @@ } var COLS = ['sorgente', 'azienda', 'sessione', 'corso', 'data', - 'ftp', 'bc', 'iscrizione', 'odv', 'sharepoint', 'report', 'email']; + 'ftp', 'bc', 'iscrizione', 'odv_number', 'odv', 'sharepoint', 'report', 'email']; var STEP_COLS = ['ftp', 'bc', 'iscrizione', 'odv', 'sharepoint', 'report', 'email']; var BADGE_CLS = { done: 'ok', processing: 'proc', pending: 'warn', error: 'err', skipped: 'info' }; diff --git a/static/js/sharepoint.js b/static/js/RPA_Intraz/page_sharepoint.js similarity index 100% rename from static/js/sharepoint.js rename to static/js/RPA_Intraz/page_sharepoint.js diff --git a/static/js/documenti.js b/static/js/RPA_Reg Lom/page_documenti.js similarity index 100% rename from static/js/documenti.js rename to static/js/RPA_Reg Lom/page_documenti.js diff --git a/static/js/documenti_export.js b/static/js/RPA_Reg Lom/page_documenti_export.js similarity index 100% rename from static/js/documenti_export.js rename to static/js/RPA_Reg Lom/page_documenti_export.js diff --git a/static/js/documenti_filters.js b/static/js/RPA_Reg Lom/page_documenti_filters.js similarity index 100% rename from static/js/documenti_filters.js rename to static/js/RPA_Reg Lom/page_documenti_filters.js diff --git a/static/js/pec.js b/static/js/RPA_Reg Lom/page_pec.js similarity index 100% rename from static/js/pec.js rename to static/js/RPA_Reg Lom/page_pec.js diff --git a/static/js/report.js b/static/js/RPA_Reg Lom/page_report.js similarity index 100% rename from static/js/report.js rename to static/js/RPA_Reg Lom/page_report.js diff --git a/static/js/page_dashboard.js b/static/js/page_dashboard.js new file mode 100644 index 0000000..27ee595 --- /dev/null +++ b/static/js/page_dashboard.js @@ -0,0 +1,34 @@ +(function () { + // ── Section collapse (visible by default) ──────────────────────────────── + document.querySelectorAll('section:not(.page-header)').forEach(function (sec, idx) { + var grid = sec.querySelector('.grid'); + if (!grid) return; + var h2 = sec.querySelector('h2'); + if (!h2) return; + + var key = 'dash_sec_' + idx; + var isOpen = (sessionStorage.getItem(key) !== 'closed'); + + grid.classList.toggle('dash-grid-hidden', !isOpen); + + var btn = document.createElement('button'); + btn.className = 'sec-toggle-btn'; + btn.title = 'Espandi / Comprimi'; + btn.innerHTML = ( + '' + + '' + ); + h2.appendChild(btn); + + btn.addEventListener('click', function (e) { + e.preventDefault(); + e.stopPropagation(); + var hidden = grid.classList.toggle('dash-grid-hidden'); + var arrow = btn.querySelector('.sec-toggle-arrow'); + if (arrow) arrow.classList.toggle('open', !hidden); + try { sessionStorage.setItem(key, hidden ? 'closed' : 'open'); } catch(e2) {} + }); + }); +})(); diff --git a/static/js/logs.js b/static/js/page_logs.js similarity index 73% rename from static/js/logs.js rename to static/js/page_logs.js index c013b75..3eeac4f 100644 --- a/static/js/logs.js +++ b/static/js/page_logs.js @@ -5,42 +5,29 @@ var pgSelect = document.getElementById('pg-run-select'); var dateFrom = document.getElementById('filter-date-from'); var dateTo = document.getElementById('filter-date-to'); - var filterBtn = document.getElementById('filter-date-btn'); - var STORAGE_KEY = 'logs_pn_filter'; - var STORAGE_KEY_DATE = 'logs_date_filter'; var STORAGE_KEY_ACTIVE = 'logs_date_active'; - function toIsoDate(d) { return d.toISOString().slice(0, 10); } - - // ── Restore / default date range ────────────────────────────────────────── - function loadSavedDates() { - try { return JSON.parse(sessionStorage.getItem(STORAGE_KEY_DATE) || 'null'); } catch(e) { return null; } - } - function saveDates() { - try { - sessionStorage.setItem(STORAGE_KEY_DATE, JSON.stringify({ - from: dateFrom ? dateFrom.value : '', - to: dateTo ? dateTo.value : '', - })); - sessionStorage.setItem(STORAGE_KEY_ACTIVE, '1'); - } catch(e) {} - } - var dateActive = (function() { try { return sessionStorage.getItem(STORAGE_KEY_ACTIVE) === '1'; } catch(e) { return false; } })(); - var savedDates = loadSavedDates(); - if (savedDates) { - if (dateFrom) dateFrom.value = savedDates.from || ''; - if (dateTo) dateTo.value = savedDates.to || ''; - } else { - var today = new Date(); - var twoWeeksAgo = new Date(today); twoWeeksAgo.setDate(today.getDate() - 14); - if (dateFrom) dateFrom.value = toIsoDate(twoWeeksAgo); - if (dateTo) dateTo.value = toIsoDate(today); - } + // ── Date range filter (client-side DOM filtering) ───────────────────────── + window.initDateRangeFilter({ + storageKey: 'logs_date_filter', + readUrlParams: false, + defaultFrom: function () { + var d = new Date(); d.setDate(d.getDate() - 14); return d.toISOString().slice(0, 10); + }, + defaultTo: function () { return new Date().toISOString().slice(0, 10); }, + onFilter: function () { + console.log('[logs] filtra clicked — from:', dateFrom && dateFrom.value, 'to:', dateTo && dateTo.value); + dateActive = true; + try { sessionStorage.setItem(STORAGE_KEY_ACTIVE, '1'); } catch(e) {} + applyFilter(); + filterSelect(); + }, + }); // ── Process-name checkboxes (built from pagination select options) ───────── var names = []; @@ -53,12 +40,12 @@ } function loadSaved() { - try { return JSON.parse(sessionStorage.getItem(STORAGE_KEY) || '{}'); } catch(e) { return {}; } + try { return JSON.parse(sessionStorage.getItem('logs_pn_filter') || '{}'); } catch(e) { return {}; } } function saveState() { var state = {}; Object.keys(pnChecks).forEach(function(n){ state[n] = pnChecks[n].checked; }); - try { sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } catch(e) {} + try { sessionStorage.setItem('logs_pn_filter', JSON.stringify(state)); } catch(e) {} } var pnChecks = {}; @@ -124,17 +111,6 @@ }); } - // ── Filter button — saves dates then applies both filters ───────────────── - if (filterBtn) { - filterBtn.addEventListener('click', function() { - console.log('[logs] filtra clicked — from:', dateFrom && dateFrom.value, 'to:', dateTo && dateTo.value); - dateActive = true; - saveDates(); - applyFilter(); - filterSelect(); - }); - } - if (search) search.addEventListener('input', function() { console.log('[logs] search input:', search.value); applyFilter(); diff --git a/static/js/runs.js b/static/js/page_runs.js similarity index 100% rename from static/js/runs.js rename to static/js/page_runs.js diff --git a/static/js/schema.js b/static/js/page_schema.js similarity index 100% rename from static/js/schema.js rename to static/js/page_schema.js diff --git a/static/js/filters.js b/static/js/shared/filters.js similarity index 100% rename from static/js/filters.js rename to static/js/shared/filters.js diff --git a/static/js/shared/generic_filters.js b/static/js/shared/generic_filters.js new file mode 100644 index 0000000..f468437 --- /dev/null +++ b/static/js/shared/generic_filters.js @@ -0,0 +1,92 @@ +// filters/generic_filters.js — shared date-range filter initialiser +// +// Usage: +// var df = window.initDateRangeFilter({ +// storageKey: 'my_page_date_filter', // sessionStorage key +// defaultFrom: function() { return '2025-01-01'; }, +// defaultTo: function() { return '2025-01-02'; }, +// readUrlParams: true, // sync from/to URL params on load (for server-side pages) +// onFilter: function(from, to) { ... }, +// onReset: function() { ... }, // optional +// }); +// // df.getDates() → { from, to } + +window.initDateRangeFilter = function (opts) { + var dateFrom = document.getElementById('filter-date-from'); + var dateTo = document.getElementById('filter-date-to'); + var filterBtn = document.getElementById('filter-date-btn'); + var resetBtn = document.getElementById('filter-date-reset'); + + function toIsoDate(d) { return d.toISOString().slice(0, 10); } + + function getUrlParam(name) { + try { return new URLSearchParams(window.location.search).get(name); } catch(e) { return null; } + } + + function loadSaved() { + try { return JSON.parse(sessionStorage.getItem(opts.storageKey) || 'null'); } catch(e) { return null; } + } + + function saveDates(from, to) { + try { sessionStorage.setItem(opts.storageKey, JSON.stringify({ from: from, to: to })); } catch(e) {} + } + + function clearSaved() { + try { sessionStorage.removeItem(opts.storageKey); } catch(e) {} + } + + // ── Initialise input values ─────────────────────────────────────────────── + var initFrom = '', initTo = ''; + + if (opts.readUrlParams) { + var urlFrom = getUrlParam('from'); + var urlTo = getUrlParam('to'); + if (urlFrom || urlTo) { + initFrom = urlFrom || ''; + initTo = urlTo || ''; + saveDates(initFrom, initTo); + } + } + + if (!initFrom && !initTo) { + var saved = loadSaved(); + if (saved) { + initFrom = saved.from || ''; + initTo = saved.to || ''; + } else { + initFrom = opts.defaultFrom ? opts.defaultFrom() : ''; + initTo = opts.defaultTo ? opts.defaultTo() : ''; + } + } + + if (dateFrom) dateFrom.value = initFrom; + if (dateTo) dateTo.value = initTo; + + // ── Wire buttons ───────────────────────────────────────────────────────── + if (filterBtn) { + filterBtn.addEventListener('click', function () { + var from = dateFrom ? dateFrom.value : ''; + var to = dateTo ? dateTo.value : ''; + saveDates(from, to); + if (opts.onFilter) opts.onFilter(from, to); + }); + } + + if (resetBtn && opts.onReset) { + resetBtn.addEventListener('click', function () { + clearSaved(); + opts.onReset(); + }); + } + + // ── Public API ──────────────────────────────────────────────────────────── + return { + getDates: function () { + return { + from: dateFrom ? dateFrom.value : '', + to: dateTo ? dateTo.value : '', + }; + }, + toIsoDate: toIsoDate, + }; +}; diff --git a/static/pages/dashboard.css b/static/pages/dashboard.css deleted file mode 100644 index 6397d51..0000000 --- a/static/pages/dashboard.css +++ /dev/null @@ -1,3 +0,0 @@ -/* dashboard.css — stili specifici per la pagina Dashboard */ -.sec-link{color:inherit;text-decoration:none} -.sec-link:hover{text-decoration:underline;text-underline-offset:3px}