@@ -348,28 +348,68 @@ function postPluginGraphQL(gqlField, prefix, foreignKey, dtRequest, callback) {
348348 });
349349}
350350
351- // Fetch the lightweight plugins_stats.json (~1KB) and populate all badge
352- // and sub-tab counts instantly — no GraphQL, no 250MB file loads.
351+ // Fetch badge counts for every plugin and populate sidebar + sub-tab counters.
352+ // Fast path: static JSON (~1KB) when no MAC filter is active.
353+ // Filtered path: batched GraphQL aliases when a foreignKey (MAC) is set.
353354async function prefetchPluginBadges() {
355+ const mac = $("#txtMacFilter").val();
356+ const foreignKey = (mac && mac !== "--") ? mac : null;
357+
358+ const prefixes = pluginDefinitions
359+ .filter(p => p.show_ui)
360+ .map(p => p.unique_prefix);
361+
362+ if (prefixes.length === 0) return;
363+
354364 try {
355- const stats = await fetchJson('table_plugins_stats.json');
356- // Build lookup: { ARPSCAN: { objects: 42, events: 3, history: 100 }, ... }
357- const counts = {};
358- for (const row of stats.data) {
359- const p = row.tableName; // 'objects' | 'events' | 'history'
360- const plugin = row.plugin;
361- if (!counts[plugin]) counts[plugin] = { objects: 0, events: 0, history: 0 };
362- counts[plugin][p] = row.cnt;
365+ let counts = {}; // { PREFIX: { objects: N, events: N, history: N } }
366+
367+ if (!foreignKey) {
368+ // ---- FAST PATH: lightweight pre-computed JSON ----
369+ const stats = await fetchJson('table_plugins_stats.json');
370+ for (const row of stats.data) {
371+ const p = row.tableName; // 'objects' | 'events' | 'history'
372+ const plugin = row.plugin;
373+ if (!counts[plugin]) counts[plugin] = { objects: 0, events: 0, history: 0 };
374+ counts[plugin][p] = row.cnt;
375+ }
376+ } else {
377+ // ---- FILTERED PATH: GraphQL with foreignKey ----
378+ const apiToken = getSetting("API_TOKEN");
379+ const apiBase = getApiBase();
380+ const fkOpt = `, foreignKey: "${foreignKey}"`;
381+ const fragments = prefixes.map(p => [
382+ `${p}_obj: pluginsObjects(options: {plugin: "${p}", page: 1, limit: 1${fkOpt}}) { dbCount }`,
383+ `${p}_evt: pluginsEvents(options: {plugin: "${p}", page: 1, limit: 1${fkOpt}}) { dbCount }`,
384+ `${p}_hist: pluginsHistory(options: {plugin: "${p}", page: 1, limit: 1${fkOpt}}) { dbCount }`,
385+ ].join('\n ')).join('\n ');
386+
387+ const query = `query BadgeCounts {\n ${fragments}\n }`;
388+ const response = await $.ajax({
389+ method: "POST",
390+ url: `${apiBase}/graphql`,
391+ headers: { "Authorization": `Bearer ${apiToken}`, "Content-Type": "application/json" },
392+ data: JSON.stringify({ query }),
393+ });
394+ if (response.errors) { console.error("[plugins] badge GQL errors:", response.errors); return; }
395+ for (const p of prefixes) {
396+ counts[p] = {
397+ objects: response.data[`${p}_obj`]?.dbCount ?? 0,
398+ events: response.data[`${p}_evt`]?.dbCount ?? 0,
399+ history: response.data[`${p}_hist`]?.dbCount ?? 0,
400+ };
401+ }
363402 }
403+
404+ // Update DOM
364405 for (const [prefix, c] of Object.entries(counts)) {
365406 $(`#badge_${prefix}`).text(c.objects);
366407 $(`#objCount_${prefix}`).text(c.objects);
367408 $(`#evtCount_${prefix}`).text(c.events);
368409 $(`#histCount_${prefix}`).text(c.history);
369410 }
370- // Set 0 for plugins with no rows in any table
371- pluginDefinitions.filter(p => p.show_ui).forEach(p => {
372- const prefix = p.unique_prefix;
411+ // Zero out plugins with no rows in any table
412+ prefixes.forEach(prefix => {
373413 if (!counts[prefix]) {
374414 $(`#badge_${prefix}`).text(0);
375415 $(`#objCount_${prefix}`).text(0);
0 commit comments