From a66560e52228c15a2c025359b39d059d6bdf6fb1 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Fri, 28 Apr 2023 14:56:30 -0700 Subject: [PATCH 1/2] implement filtering on admin jobs grid add forgotten files, format add more methods for selenium navigation add needed selectors jobs grid test: proper admin handling and wait for the workflow invocation blackened fix copypasta name Co-authored-by: John Chilton --- client/src/components/Indices/filtersMixin.js | 25 ++++++ .../components/Indices/filtersMixin.test.js | 12 +++ .../admin/{Jobs.vue => JobsList.vue} | 63 +++++++++++--- client/src/components/admin/JobsTable.vue | 41 +++++++-- .../src/entry/analysis/routes/admin-routes.js | 4 +- client/src/utils/navigation/navigation.yml | 17 ++++ lib/galaxy/selenium/navigates_galaxy.py | 36 +++++++- test/integration_selenium/test_admin_jobs.py | 84 +++++++++++++++++++ .../test_admin_jobs_job_conf.yml | 24 ++++++ 9 files changed, 282 insertions(+), 24 deletions(-) rename client/src/components/admin/{Jobs.vue => JobsList.vue} (76%) create mode 100644 test/integration_selenium/test_admin_jobs.py create mode 100644 test/integration_selenium/test_admin_jobs_job_conf.yml diff --git a/client/src/components/Indices/filtersMixin.js b/client/src/components/Indices/filtersMixin.js index 719297f4a4a3..d2c3870c1bb5 100644 --- a/client/src/components/Indices/filtersMixin.js +++ b/client/src/components/Indices/filtersMixin.js @@ -4,15 +4,40 @@ export default { components: { IndexFilter, }, + props: { + inputDebounceDelay: { + type: Number, + default: 500, + }, + }, data() { return { filter: "", + implicitFilter: null, + helpHtml: null, }; }, computed: { isFiltered() { return !!this.filter; }, + effectiveFilter() { + let filter = this.filter; + const implicitFilter = this.implicitFilter; + if (implicitFilter && filter) { + filter = `${implicitFilter} ${filter}`; + } else if (implicitFilter) { + filter = implicitFilter; + } + return filter; + }, + filterAttrs() { + return { + "debounce-delay": this.inputDebounceDelay, + placeholder: this.titleSearch, + "help-html": this.helpHtml, + }; + }, }, methods: { appendTagFilter(tag, text) { diff --git a/client/src/components/Indices/filtersMixin.test.js b/client/src/components/Indices/filtersMixin.test.js index 32d692b1c243..358b02dbcab6 100644 --- a/client/src/components/Indices/filtersMixin.test.js +++ b/client/src/components/Indices/filtersMixin.test.js @@ -43,4 +43,16 @@ describe("filtersMixin.js", () => { wrapper.vm.appendTagFilter("name", "foobar"); expect(wrapper.vm.filter).toBe("name:'foobar'"); }); + + it("should have an effective filter that combines implicit and explicit filter", async () => { + wrapper.vm.implicitFilter = "tag:cowdog"; + wrapper.vm.appendTagFilter("name", "foobar"); + expect(wrapper.vm.filter).toBe("name:'foobar'"); + expect(wrapper.vm.effectiveFilter).toBe("tag:cowdog name:'foobar'"); + }); + + it("should just use implicit filter as effective if filter is empty", async () => { + wrapper.vm.implicitFilter = "tag:cowdog"; + expect(wrapper.vm.effectiveFilter).toBe("tag:cowdog"); + }); }); diff --git a/client/src/components/admin/Jobs.vue b/client/src/components/admin/JobsList.vue similarity index 76% rename from client/src/components/admin/Jobs.vue rename to client/src/components/admin/JobsList.vue index b526ed769813..d8d2073a10fc 100644 --- a/client/src/components/admin/Jobs.vue +++ b/client/src/components/admin/JobsList.vue @@ -5,7 +5,7 @@ {{ message }} Job Lock - + Job Overview

Below unfinished jobs are displayed (in the 'new', 'queued', 'running', or 'upload' states) and recently @@ -36,9 +36,11 @@ - - - + @@ -56,11 +58,10 @@

Unfinished Jobs

- - + @@ -105,14 +109,43 @@ import { commonJobFields } from "./JobFields"; import { errorMessageAsString } from "utils/simple-error"; import { jobsProvider } from "components/providers/JobProvider"; import Heading from "components/Common/Heading"; +import IndexFilter from "components/Indices/IndexFilter"; +import filtersMixin from "components/Indices/filtersMixin"; function cancelJob(jobId, message) { const url = `${getAppRoot()}api/jobs/${jobId}`; return axios.delete(url, { data: { message: message } }); } +const helpHtml = `
+

This textbox box can be used to filter the jobs displayed. + +

Text entered here will be searched against job user, tool ID, job runner, and handler. Additionally, +advanced filtering tags can be used to refine the search more precisely. Tags are of the form +<tag_name>:<tag_value> or <tag_name>:'<tag_value>'. +For instance to search just for jobs with cat1 in the tool name, tool:cat1 can be used. +Notice by default the search is not case-sensitive. + +

If the quoted version of tag is used, the search is case sensitive and only full matches will be +returned. So tool:'cat1' would show only jobs from the cat1 tool exactly.

+ +

The available tags are: +

+
user
+
This filters the job index to contain only jobs executed by matching user(s). You may also just click on a user in the list of jobs to filter on that exact user using this directly.
+
handler
+
This filters the job index to contain only jobs executed on matching handler(s). You may also just click on a handler in the list of jobs to filter on that exact user using this directly.
+
runner
+
This filters the job index to contain only jobs executed on matching job runner(s). You may also just click on a runner in the list of jobs to filter on that exact user using this directly.
+
tool
+
This filters the job index to contain only jobs from the matching tool(s). You may also just click on a tool in the list of jobs to filter on that exact user using this directly.
+
+
+`; + export default { - components: { JobLock, JobsTable, Heading }, + components: { JobLock, JobsTable, Heading, IndexFilter }, + mixins: [filtersMixin], data() { return { jobs: [], @@ -130,13 +163,14 @@ export default { allSelected: false, indeterminate: false, stopMessage: "", - filter: "", message: "", status: "info", loading: true, busy: true, cutoffMin: 5, showAllRunning: false, + titleSearchJobs: `search jobs`, + helpHtml: helpHtml, }; }, computed: { @@ -205,6 +239,9 @@ export default { const dateRangeMin = new Date(Date.now() - cutoff * 60 * 1000).toISOString(); params.date_range_min = `${dateRangeMin}`; } + if (this.filter) { + params.search = this.filter; + } const ctx = { root: getAppRoot(), ...params, diff --git a/client/src/components/admin/JobsTable.vue b/client/src/components/admin/JobsTable.vue index b6072d4d5087..9df6ac9597e8 100644 --- a/client/src/components/admin/JobsTable.vue +++ b/client/src/components/admin/JobsTable.vue @@ -1,16 +1,16 @@