mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-04-15 22:51:37 -07:00
Merge pull request #1577 from netalertx/next_release
feat(plugins): Optimize badge fetching by using lightweight JSON inst…
This commit is contained in:
+59
-32
@@ -348,51 +348,78 @@ function postPluginGraphQL(gqlField, prefix, foreignKey, dtRequest, callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire a single batched GraphQL request to fetch the Objects dbCount for
|
// Fetch badge counts for every plugin and populate sidebar + sub-tab counters.
|
||||||
// every plugin and populate the sidebar badges immediately on page load.
|
// Fast path: static JSON (~1KB) when no MAC filter is active.
|
||||||
function prefetchPluginBadges() {
|
// Filtered path: batched GraphQL aliases when a foreignKey (MAC) is set.
|
||||||
const apiToken = getSetting("API_TOKEN");
|
async function prefetchPluginBadges() {
|
||||||
const apiBase = getApiBase();
|
|
||||||
const mac = $("#txtMacFilter").val();
|
const mac = $("#txtMacFilter").val();
|
||||||
const foreignKey = (mac && mac !== "--") ? mac : null;
|
const foreignKey = (mac && mac !== "--") ? mac : null;
|
||||||
|
|
||||||
// Build one aliased sub-query per visible plugin
|
|
||||||
const prefixes = pluginDefinitions
|
const prefixes = pluginDefinitions
|
||||||
.filter(p => p.show_ui)
|
.filter(p => p.show_ui)
|
||||||
.map(p => p.unique_prefix);
|
.map(p => p.unique_prefix);
|
||||||
|
|
||||||
if (prefixes.length === 0) return;
|
if (prefixes.length === 0) return;
|
||||||
|
|
||||||
// GraphQL aliases must be valid identifiers — prefixes already are (A-Z0-9_)
|
try {
|
||||||
const fkOpt = foreignKey ? `, foreignKey: "${foreignKey}"` : '';
|
let counts = {}; // { PREFIX: { objects: N, events: N, history: N } }
|
||||||
const fragments = prefixes.map(p => [
|
|
||||||
`${p}_obj: pluginsObjects(options: {plugin: "${p}", page: 1, limit: 1${fkOpt}}) { dbCount }`,
|
|
||||||
`${p}_evt: pluginsEvents(options: {plugin: "${p}", page: 1, limit: 1${fkOpt}}) { dbCount }`,
|
|
||||||
`${p}_hist: pluginsHistory(options: {plugin: "${p}", page: 1, limit: 1${fkOpt}}) { dbCount }`,
|
|
||||||
].join('\n ')).join('\n ');
|
|
||||||
|
|
||||||
const query = `query BadgeCounts {\n ${fragments}\n }`;
|
if (!foreignKey) {
|
||||||
|
// ---- FAST PATH: lightweight pre-computed JSON ----
|
||||||
$.ajax({
|
const stats = await fetchJson('table_plugins_stats.json');
|
||||||
method: "POST",
|
for (const row of stats.data) {
|
||||||
url: `${apiBase}/graphql`,
|
const p = row.tableName; // 'objects' | 'events' | 'history'
|
||||||
headers: { "Authorization": `Bearer ${apiToken}`, "Content-Type": "application/json" },
|
const plugin = row.plugin;
|
||||||
data: JSON.stringify({ query }),
|
if (!counts[plugin]) counts[plugin] = { objects: 0, events: 0, history: 0 };
|
||||||
success: function(response) {
|
counts[plugin][p] = row.cnt;
|
||||||
if (response.errors) {
|
|
||||||
console.error("[plugins] badge prefetch errors:", response.errors);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
prefixes.forEach(p => {
|
} else {
|
||||||
const obj = response.data[`${p}_obj`];
|
// ---- FILTERED PATH: GraphQL with foreignKey ----
|
||||||
const evt = response.data[`${p}_evt`];
|
const apiToken = getSetting("API_TOKEN");
|
||||||
const hist = response.data[`${p}_hist`];
|
const apiBase = getApiBase();
|
||||||
if (obj) { $(`#badge_${p}`).text(obj.dbCount); $(`#objCount_${p}`).text(obj.dbCount); }
|
const fkOpt = `, foreignKey: "${foreignKey}"`;
|
||||||
if (evt) { $(`#evtCount_${p}`).text(evt.dbCount); }
|
const fragments = prefixes.map(p => [
|
||||||
if (hist) { $(`#histCount_${p}`).text(hist.dbCount); }
|
`${p}_obj: pluginsObjects(options: {plugin: "${p}", page: 1, limit: 1${fkOpt}}) { dbCount }`,
|
||||||
|
`${p}_evt: pluginsEvents(options: {plugin: "${p}", page: 1, limit: 1${fkOpt}}) { dbCount }`,
|
||||||
|
`${p}_hist: pluginsHistory(options: {plugin: "${p}", page: 1, limit: 1${fkOpt}}) { dbCount }`,
|
||||||
|
].join('\n ')).join('\n ');
|
||||||
|
|
||||||
|
const query = `query BadgeCounts {\n ${fragments}\n }`;
|
||||||
|
const response = await $.ajax({
|
||||||
|
method: "POST",
|
||||||
|
url: `${apiBase}/graphql`,
|
||||||
|
headers: { "Authorization": `Bearer ${apiToken}`, "Content-Type": "application/json" },
|
||||||
|
data: JSON.stringify({ query }),
|
||||||
});
|
});
|
||||||
|
if (response.errors) { console.error("[plugins] badge GQL errors:", response.errors); return; }
|
||||||
|
for (const p of prefixes) {
|
||||||
|
counts[p] = {
|
||||||
|
objects: response.data[`${p}_obj`]?.dbCount ?? 0,
|
||||||
|
events: response.data[`${p}_evt`]?.dbCount ?? 0,
|
||||||
|
history: response.data[`${p}_hist`]?.dbCount ?? 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
// Update DOM
|
||||||
|
for (const [prefix, c] of Object.entries(counts)) {
|
||||||
|
$(`#badge_${prefix}`).text(c.objects);
|
||||||
|
$(`#objCount_${prefix}`).text(c.objects);
|
||||||
|
$(`#evtCount_${prefix}`).text(c.events);
|
||||||
|
$(`#histCount_${prefix}`).text(c.history);
|
||||||
|
}
|
||||||
|
// Zero out plugins with no rows in any table
|
||||||
|
prefixes.forEach(prefix => {
|
||||||
|
if (!counts[prefix]) {
|
||||||
|
$(`#badge_${prefix}`).text(0);
|
||||||
|
$(`#objCount_${prefix}`).text(0);
|
||||||
|
$(`#evtCount_${prefix}`).text(0);
|
||||||
|
$(`#histCount_${prefix}`).text(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[plugins] badge prefetch failed:', err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateTabs() {
|
function generateTabs() {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from const import (
|
|||||||
sql_plugins_events,
|
sql_plugins_events,
|
||||||
sql_plugins_history,
|
sql_plugins_history,
|
||||||
sql_plugins_objects,
|
sql_plugins_objects,
|
||||||
|
sql_plugins_stats,
|
||||||
sql_language_strings,
|
sql_language_strings,
|
||||||
sql_notifications_all,
|
sql_notifications_all,
|
||||||
sql_online_history,
|
sql_online_history,
|
||||||
@@ -66,6 +67,7 @@ def update_api(
|
|||||||
["plugins_events", sql_plugins_events],
|
["plugins_events", sql_plugins_events],
|
||||||
["plugins_history", sql_plugins_history],
|
["plugins_history", sql_plugins_history],
|
||||||
["plugins_objects", sql_plugins_objects],
|
["plugins_objects", sql_plugins_objects],
|
||||||
|
["plugins_stats", sql_plugins_stats],
|
||||||
["plugins_language_strings", sql_language_strings],
|
["plugins_language_strings", sql_language_strings],
|
||||||
["notifications", sql_notifications_all],
|
["notifications", sql_notifications_all],
|
||||||
["online_history", sql_online_history],
|
["online_history", sql_online_history],
|
||||||
@@ -74,6 +76,13 @@ def update_api(
|
|||||||
["custom_endpoint", conf.API_CUSTOM_SQL],
|
["custom_endpoint", conf.API_CUSTOM_SQL],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# plugins_stats is derived from plugins_objects/events/history —
|
||||||
|
# ensure it is refreshed when any of its sources are partially updated.
|
||||||
|
_STATS_SOURCES = {"plugins_objects", "plugins_events", "plugins_history"}
|
||||||
|
if updateOnlyDataSources and _STATS_SOURCES & set(updateOnlyDataSources):
|
||||||
|
if "plugins_stats" not in updateOnlyDataSources:
|
||||||
|
updateOnlyDataSources = list(updateOnlyDataSources) + ["plugins_stats"]
|
||||||
|
|
||||||
# Save selected database tables
|
# Save selected database tables
|
||||||
for dsSQL in dataSourcesSQLs:
|
for dsSQL in dataSourcesSQLs:
|
||||||
if not updateOnlyDataSources or dsSQL[0] in updateOnlyDataSources:
|
if not updateOnlyDataSources or dsSQL[0] in updateOnlyDataSources:
|
||||||
|
|||||||
@@ -120,6 +120,11 @@ sql_events_pending_alert = "SELECT * FROM Events where evePendingAlertEmail is
|
|||||||
sql_events_all = "SELECT rowid, * FROM Events ORDER BY eveDateTime DESC"
|
sql_events_all = "SELECT rowid, * FROM Events ORDER BY eveDateTime DESC"
|
||||||
sql_settings = "SELECT * FROM Settings"
|
sql_settings = "SELECT * FROM Settings"
|
||||||
sql_plugins_objects = "SELECT * FROM Plugins_Objects"
|
sql_plugins_objects = "SELECT * FROM Plugins_Objects"
|
||||||
|
sql_plugins_stats = """SELECT 'objects' AS tableName, plugin, COUNT(*) AS cnt FROM Plugins_Objects GROUP BY plugin
|
||||||
|
UNION ALL
|
||||||
|
SELECT 'events', plugin, COUNT(*) FROM Plugins_Events GROUP BY plugin
|
||||||
|
UNION ALL
|
||||||
|
SELECT 'history', plugin, COUNT(*) FROM Plugins_History GROUP BY plugin"""
|
||||||
sql_language_strings = "SELECT * FROM Plugins_Language_Strings"
|
sql_language_strings = "SELECT * FROM Plugins_Language_Strings"
|
||||||
sql_notifications_all = "SELECT * FROM Notifications"
|
sql_notifications_all = "SELECT * FROM Notifications"
|
||||||
sql_online_history = "SELECT * FROM Online_History"
|
sql_online_history = "SELECT * FROM Online_History"
|
||||||
|
|||||||
Reference in New Issue
Block a user