admin: scope plugin job and activity fetches to the selected job type

The plugin page fetched the newest 500 jobs and 500 activities
cluster-wide and filtered them by job type in the browser. On a busy
cluster that window can hold none of the selected type (433
erasure_coding + 64 ec_balance jobs, 497 ec_balance activities), so
/plugin/lanes/default/execution?job=ec_vacuum showed "No execution
jobs tracked yet" while the server had seven recent ec_vacuum jobs.

When a job-type tab is active, fetch the queue/detection/execution
lists with job_type=<selected> so the server filters before applying
the limit, and refetch when the selected job type changes. The
unscoped lists are still fetched for the status cards and the overview
per-type summary.
This commit is contained in:
Chris Lu committed 2026-11-03 05:29:44 -08:00
1 parent e5bc658eb7
commit bba80bfc7b
2 files changed
+42 -25

No files matched your search

+41 -24
View File
@@ -633,6 +633,13 @@ templ Plugin(page string, initialJob string, lane string) {
return url + sep + 'lane=' + encodeURIComponent(pluginLane);
}
// appendJobTypeParam appends ?job_type= or &job_type= to a URL if a job type is given.
function appendJobTypeParam(url, jobType) {
if (!jobType) return url;
var sep = url.indexOf('?') === -1 ? '?' : '&';
return url + sep + 'job_type=' + encodeURIComponent(jobType);
}
function getCSRFToken() {
var meta = document.querySelector('meta[name="csrf-token"]');
if (!meta) {
@@ -1735,9 +1742,9 @@ templ Plugin(page string, initialJob string, lane string) {
}
var filteredJobs = [];
var allJobs = Array.isArray(state.allJobs) ? state.allJobs : [];
for (var i = 0; i < allJobs.length; i++) {
var job = allJobs[i] || {};
var jobs = Array.isArray(state.jobs) ? state.jobs : [];
for (var i = 0; i < jobs.length; i++) {
var job = jobs[i] || {};
var jobType = String(job.job_type || '').trim();
if (state.selectedJobType && jobType !== state.selectedJobType) {
continue;
@@ -1801,9 +1808,9 @@ templ Plugin(page string, initialJob string, lane string) {
}
var filteredJobs = [];
var allJobs = Array.isArray(state.allJobs) ? state.allJobs : [];
for (var i = 0; i < allJobs.length; i++) {
var queueJob = allJobs[i] || {};
var jobs = Array.isArray(state.jobs) ? state.jobs : [];
for (var i = 0; i < jobs.length; i++) {
var queueJob = jobs[i] || {};
var queueJobType = String(queueJob.job_type || '').trim();
if (state.selectedJobType && queueJobType !== state.selectedJobType) {
continue;
@@ -1858,9 +1865,9 @@ templ Plugin(page string, initialJob string, lane string) {
}
var filteredActivities = [];
var allActivities = Array.isArray(state.allActivities) ? state.allActivities : [];
for (var i = 0; i < allActivities.length; i++) {
var activity = allActivities[i] || {};
var activities = Array.isArray(state.activities) ? state.activities : [];
for (var i = 0; i < activities.length; i++) {
var activity = activities[i] || {};
var jobType = String(activity.job_type || '').trim();
if (state.selectedJobType && jobType !== state.selectedJobType) {
continue;
@@ -1900,9 +1907,9 @@ templ Plugin(page string, initialJob string, lane string) {
}
var filteredActivities = [];
var allActivities = Array.isArray(state.allActivities) ? state.allActivities : [];
for (var i = 0; i < allActivities.length; i++) {
var activity = allActivities[i] || {};
var activities = Array.isArray(state.activities) ? state.activities : [];
for (var i = 0; i < activities.length; i++) {
var activity = activities[i] || {};
if (isDetectionActivitySource(activity.source)) {
continue;
}
@@ -3075,13 +3082,21 @@ templ Plugin(page string, initialJob string, lane string) {
state.monitorExecutionJobState = executionStateFilter ? String(executionStateFilter.value || '').trim() : '';
// The newest 500 rows cluster-wide may hold none of the selected job type on a busy
// cluster, so the job-type sub-tabs fetch their own server-side filtered window.
var scopedJobType = state.activeTopTab === 'overview' ? '' : state.selectedJobType;
var allJobsPromise = pluginRequest('GET', appendLaneParam('/api/plugin/jobs?limit=500'));
var allActivitiesPromise = pluginRequest('GET', appendLaneParam('/api/plugin/activities?limit=500'));
var jobsPromise = scopedJobType ? pluginRequest('GET', appendJobTypeParam(appendLaneParam('/api/plugin/jobs?limit=500'), scopedJobType)) : allJobsPromise;
var activitiesPromise = scopedJobType ? pluginRequest('GET', appendJobTypeParam(appendLaneParam('/api/plugin/activities?limit=500'), scopedJobType)) : allActivitiesPromise;
var schedulerPromise = pluginRequest('GET', appendLaneParam('/api/plugin/scheduler-states'));
var schedulerStatusPromise = pluginRequest('GET', appendLaneParam('/api/plugin/scheduler-status'));
var allJobs = await allJobsPromise;
var allActivities = await allActivitiesPromise;
var jobs = await jobsPromise;
var activities = await activitiesPromise;
var schedulerStates = await schedulerPromise;
var schedulerStatus = null;
try {
@@ -3090,10 +3105,10 @@ templ Plugin(page string, initialJob string, lane string) {
schedulerStatus = null;
}
state.jobs = Array.isArray(allJobs) ? allJobs : [];
state.activities = Array.isArray(allActivities) ? allActivities : [];
state.allJobs = state.jobs;
state.allActivities = state.activities;
state.allJobs = Array.isArray(allJobs) ? allJobs : [];
state.allActivities = Array.isArray(allActivities) ? allActivities : [];
state.jobs = Array.isArray(jobs) ? jobs : [];
state.activities = Array.isArray(activities) ? activities : [];
state.schedulerStates = Array.isArray(schedulerStates) ? schedulerStates : [];
state.schedulerStatus = schedulerStatus && schedulerStatus.scheduler ? schedulerStatus.scheduler : null;
state.schedulerLock = schedulerStatus && schedulerStatus.lock ? schedulerStatus.lock : null;
@@ -3231,10 +3246,11 @@ templ Plugin(page string, initialJob string, lane string) {
}
await loadRunHistory(jobType);
}
renderQueueJobs();
renderDetectionJobs();
renderExecutionJobs();
renderExecutionActivities();
try {
await refreshJobsAndActivities();
} catch (e) {
notify('Refresh failed: ' + e.message, 'error');
}
return;
}
@@ -3300,10 +3316,11 @@ templ Plugin(page string, initialJob string, lane string) {
console.error('Failed to load data on popstate navigation:', e);
}
}
renderQueueJobs();
renderDetectionJobs();
renderExecutionJobs();
renderExecutionActivities();
try {
await refreshJobsAndActivities();
} catch (e) {
console.error('Failed to refresh jobs on popstate navigation:', e);
}
});
window.addEventListener('beforeunload', function() {