From 0f76df92b95ec3883bbd6026e2965fe73290aab9 Mon Sep 17 00:00:00 2001 From: Adam Warner Date: Mon, 10 Nov 2025 00:00:08 +0000 Subject: [PATCH 1/3] Refactor date range initialization to fetch earliest timestamp from API and set default values Signed-off-by: Adam Warner --- scripts/js/queries.js | 51 +++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/scripts/js/queries.js b/scripts/js/queries.js index 3ef5f5a3..3aa0943b 100644 --- a/scripts/js/queries.js +++ b/scripts/js/queries.js @@ -9,10 +9,12 @@ "use strict"; -const beginningOfTime = 1_262_304_000; // Jan 01 2010, 00:00 in seconds -const endOfTime = 2_147_483_647; // Jan 19, 2038, 03:14 in seconds -let from = beginningOfTime; -let until = endOfTime; +// These values are provided by the API (/info/database). +// We initialize them as null and populate them during page init. +let beginningOfTime = null; // seconds since epoch (set from API: info/database.earliest_timestamp) +let endOfTime = null; // seconds since epoch (set to end of today) +let from = null; +let until = null; const dateformat = "MMM Do YYYY, HH:mm"; @@ -40,7 +42,30 @@ function getDnssecConfig() { }); } +// Fetch database info (earliest timestamp, sizes, ...) from the API and +// initialize related globals. +function getDatabaseInfo() { + $.getJSON(document.body.dataset.apiurl + "/info/database", data => { + // earliest_timestamp is provided in seconds since epoch + beginningOfTime = Number(data.earliest_timestamp_disk); + // Round down to nearest 5-minute segment (300 seconds) + beginningOfTime = Math.floor(beginningOfTime / 300) * 300; + + // endOfTime should be the end of today (local), in seconds since epoch + endOfTime = moment().endOf("day").unix(); + + // If from/until were not provided via GET, default them + from ??= beginningOfTime; + until ??= endOfTime; + + initDateRangePicker(); + }); +} + function initDateRangePicker() { + const minDateMoment = moment.unix(beginningOfTime); + const maxDateMoment = moment.unix(endOfTime); + $("#querytime").daterangepicker( { timePicker: true, @@ -52,21 +77,24 @@ function initDateRangePicker() { ranges: { "Last 10 Minutes": [moment().subtract(10, "minutes"), moment()], "Last Hour": [moment().subtract(1, "hours"), moment()], - Today: [moment().startOf("day"), moment().endOf("day")], + Today: [moment().startOf("day"), maxDateMoment], Yesterday: [ moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day"), ], - "Last 7 Days": [moment().subtract(6, "days"), moment().endOf("day")], - "Last 30 Days": [moment().subtract(29, "days"), moment().endOf("day")], + "Last 7 Days": [moment().subtract(6, "days"), maxDateMoment], + "Last 30 Days": [moment().subtract(29, "days"), maxDateMoment], "This Month": [moment().startOf("month"), moment().endOf("month")], "Last Month": [ moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month"), ], "This Year": [moment().startOf("year"), moment().endOf("year")], - "All Time": [moment(beginningOfTime * 1000), moment(endOfTime * 1000)], // convert to milliseconds since epoch + "All Time": [minDateMoment, maxDateMoment], }, + // Don't allow selecting dates outside the database range + minDate: minDateMoment, + maxDate: maxDateMoment, opens: "center", showDropdowns: true, autoUpdateInput: true, @@ -510,14 +538,15 @@ $(() => { const apiURL = getAPIURL(GETDict); if ("from" in GETDict) { - from = GETDict.from; + from = Number(GETDict.from); } if ("until" in GETDict) { - until = GETDict.until; + until = Number(GETDict.until); } - initDateRangePicker(); + // Fetch earliest timestamp from API and initialize date picker / table + getDatabaseInfo(); table = $("#all-queries").DataTable({ ajax: { From 1b509593c95a3249096a033ddf3c1f65d4f1150c Mon Sep 17 00:00:00 2001 From: Adam Warner Date: Tue, 11 Nov 2025 17:45:04 +0000 Subject: [PATCH 2/3] Treat 0.0 response as NULL. Also get the in-memory timetamp, and then use whichever of the two timestamps is smallest (and non-zero) Signed-off-by: Adam Warner --- queries.lp | 1 + scripts/js/queries.js | 43 +++++++++++++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/queries.lp b/queries.lp index df9a6cbb..dd07cfd0 100644 --- a/queries.lp +++ b/queries.lp @@ -64,6 +64,7 @@ mg.include('scripts/lua/header_authenticated.lp','r') +
diff --git a/scripts/js/queries.js b/scripts/js/queries.js index 3aa0943b..26dff876 100644 --- a/scripts/js/queries.js +++ b/scripts/js/queries.js @@ -12,7 +12,8 @@ // These values are provided by the API (/info/database). // We initialize them as null and populate them during page init. let beginningOfTime = null; // seconds since epoch (set from API: info/database.earliest_timestamp) -let endOfTime = null; // seconds since epoch (set to end of today) +// endOfTime should be the end of today (local), in seconds since epoch +const endOfTime = moment().endOf("day").unix(); let from = null; let until = null; @@ -47,24 +48,46 @@ function getDnssecConfig() { function getDatabaseInfo() { $.getJSON(document.body.dataset.apiurl + "/info/database", data => { // earliest_timestamp is provided in seconds since epoch - beginningOfTime = Number(data.earliest_timestamp_disk); - // Round down to nearest 5-minute segment (300 seconds) - beginningOfTime = Math.floor(beginningOfTime / 300) * 300; + // We have two sources: earliest_timestamp_disk (on-disk) and earliest_timestamp (in-memory) + // Use whichever is smallest and non-zero + const diskTimestamp = Number(data.earliest_timestamp_disk); + const memoryTimestamp = Number(data.earliest_timestamp); - // endOfTime should be the end of today (local), in seconds since epoch - endOfTime = moment().endOf("day").unix(); + // Filter out zero/invalid timestamps + const validTimestamps = [diskTimestamp, memoryTimestamp].filter(ts => ts > 0); + + // Use the smallest valid timestamp, or null if none exist + beginningOfTime = validTimestamps.length > 0 ? Math.min(...validTimestamps) : null; + + // Round down to nearest 5-minute segment (300 seconds) if valid + if (beginningOfTime !== null) { + beginningOfTime = Math.floor(beginningOfTime / 300) * 300; + } // If from/until were not provided via GET, default them - from ??= beginningOfTime; - until ??= endOfTime; + // Only use defaults if beginningOfTime is valid + if (beginningOfTime !== null) { + from ??= beginningOfTime; + until ??= endOfTime; + } initDateRangePicker(); }); } function initDateRangePicker() { + // If there's no valid data in the database, disable the datepicker + if (beginningOfTime === null || endOfTime === null) { + $("#querytime").prop("disabled", true); + $("#querytime").addClass("disabled"); + $("#querytime-note").text("ℹ️ No data in the database"); + return; + } + const minDateMoment = moment.unix(beginningOfTime); const maxDateMoment = moment.unix(endOfTime); + const earliestDateStr = minDateMoment.format(dateformat); + $("#querytime-note").text(`Earliest date: ${earliestDateStr}`); $("#querytime").daterangepicker( { @@ -84,12 +107,12 @@ function initDateRangePicker() { ], "Last 7 Days": [moment().subtract(6, "days"), maxDateMoment], "Last 30 Days": [moment().subtract(29, "days"), maxDateMoment], - "This Month": [moment().startOf("month"), moment().endOf("month")], + "This Month": [moment().startOf("month"), maxDateMoment], "Last Month": [ moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month"), ], - "This Year": [moment().startOf("year"), moment().endOf("year")], + "This Year": [moment().startOf("year"), maxDateMoment], "All Time": [minDateMoment, maxDateMoment], }, // Don't allow selecting dates outside the database range From 77b3833fa6c4d810baebf378ae0b5a93765f64b4 Mon Sep 17 00:00:00 2001 From: Adam Warner Date: Wed, 19 Nov 2025 19:57:03 +0000 Subject: [PATCH 3/3] Use the start of day for past 7 and 30 days No need to check for null on endofTime, it will always have a values Co-authored-by: yubiuser Signed-off-by: Adam Warner --- scripts/js/queries.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/js/queries.js b/scripts/js/queries.js index 26dff876..b16acbfb 100644 --- a/scripts/js/queries.js +++ b/scripts/js/queries.js @@ -77,7 +77,7 @@ function getDatabaseInfo() { function initDateRangePicker() { // If there's no valid data in the database, disable the datepicker - if (beginningOfTime === null || endOfTime === null) { + if (beginningOfTime === null) { $("#querytime").prop("disabled", true); $("#querytime").addClass("disabled"); $("#querytime-note").text("ℹ️ No data in the database"); @@ -105,8 +105,8 @@ function initDateRangePicker() { moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day"), ], - "Last 7 Days": [moment().subtract(6, "days"), maxDateMoment], - "Last 30 Days": [moment().subtract(29, "days"), maxDateMoment], + "Last 7 Days": [moment().subtract(6, "days").startOf("day"), maxDateMoment], + "Last 30 Days": [moment().subtract(29, "days").startOf("day"), maxDateMoment], "This Month": [moment().startOf("month"), maxDateMoment], "Last Month": [ moment().subtract(1, "month").startOf("month"),