diff --git a/api/schema.graphqls b/api/schema.graphqls
index 693ed29..db19626 100644
--- a/api/schema.graphqls
+++ b/api/schema.graphqls
@@ -300,8 +300,8 @@ type TimeRangeOutput { range: String, from: Time!, to: Time! }
input JobFilter {
tags: [ID!]
+ dbId: [ID!]
jobId: StringInput
- jobIds: [ID!]
arrayJobId: Int
user: StringInput
project: StringInput
diff --git a/internal/graph/generated/generated.go b/internal/graph/generated/generated.go
index e20fb69..615b3f8 100644
--- a/internal/graph/generated/generated.go
+++ b/internal/graph/generated/generated.go
@@ -2465,8 +2465,8 @@ type TimeRangeOutput { range: String, from: Time!, to: Time! }
input JobFilter {
tags: [ID!]
+ dbId: [ID!]
jobId: StringInput
- jobIds: [ID!]
arrayJobId: Int
user: StringInput
project: StringInput
@@ -16447,7 +16447,7 @@ func (ec *executionContext) unmarshalInputJobFilter(ctx context.Context, obj any
asMap[k] = v
}
- fieldsInOrder := [...]string{"tags", "jobId", "jobIds", "arrayJobId", "user", "project", "jobName", "cluster", "partition", "duration", "energy", "minRunningFor", "numNodes", "numAccelerators", "numHWThreads", "startTime", "state", "metricStats", "exclusive", "node"}
+ fieldsInOrder := [...]string{"tags", "dbId", "jobId", "arrayJobId", "user", "project", "jobName", "cluster", "partition", "duration", "energy", "minRunningFor", "numNodes", "numAccelerators", "numHWThreads", "startTime", "state", "metricStats", "exclusive", "node"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@@ -16461,6 +16461,13 @@ func (ec *executionContext) unmarshalInputJobFilter(ctx context.Context, obj any
return it, err
}
it.Tags = data
+ case "dbId":
+ ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("dbId"))
+ data, err := ec.unmarshalOID2ᚕstringᚄ(ctx, v)
+ if err != nil {
+ return it, err
+ }
+ it.DbID = data
case "jobId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("jobId"))
data, err := ec.unmarshalOStringInput2ᚖgithubᚗcomᚋClusterCockpitᚋccᚑbackendᚋinternalᚋgraphᚋmodelᚐStringInput(ctx, v)
@@ -16468,13 +16475,6 @@ func (ec *executionContext) unmarshalInputJobFilter(ctx context.Context, obj any
return it, err
}
it.JobID = data
- case "jobIds":
- ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("jobIds"))
- data, err := ec.unmarshalOID2ᚕstringᚄ(ctx, v)
- if err != nil {
- return it, err
- }
- it.JobIds = data
case "arrayJobId":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("arrayJobId"))
data, err := ec.unmarshalOInt2ᚖint(ctx, v)
diff --git a/internal/graph/model/models_gen.go b/internal/graph/model/models_gen.go
index dbe4462..d88fdc5 100644
--- a/internal/graph/model/models_gen.go
+++ b/internal/graph/model/models_gen.go
@@ -50,8 +50,8 @@ type IntRangeOutput struct {
type JobFilter struct {
Tags []string `json:"tags,omitempty"`
+ DbID []string `json:"dbId,omitempty"`
JobID *StringInput `json:"jobId,omitempty"`
- JobIds []string `json:"jobIds,omitempty"`
ArrayJobID *int `json:"arrayJobId,omitempty"`
User *StringInput `json:"user,omitempty"`
Project *StringInput `json:"project,omitempty"`
diff --git a/internal/repository/jobQuery.go b/internal/repository/jobQuery.go
index 3f75ec6..6a2ddec 100644
--- a/internal/repository/jobQuery.go
+++ b/internal/repository/jobQuery.go
@@ -146,17 +146,16 @@ func BuildWhereClause(filter *model.JobFilter, query sq.SelectBuilder) sq.Select
// This is an OR-Logic query: Returns all distinct jobs with at least one of the requested tags; TODO: AND-Logic query?
query = query.Join("jobtag ON jobtag.job_id = job.id").Where(sq.Eq{"jobtag.tag_id": filter.Tags}).Distinct()
}
+ if filter.DbID != nil {
+ dbIDs := make([]string, len(filter.DbID))
+ for i, val := range filter.DbID {
+ dbIDs[i] = val
+ }
+ query = query.Where(sq.Eq{"job.id": dbIDs})
+ }
if filter.JobID != nil {
query = buildStringCondition("job.job_id", filter.JobID, query)
}
- if filter.JobIds != nil {
- jobIds := make([]string, len(filter.JobIds))
- for i, val := range filter.JobIds {
- jobIds[i] = string(val)
- }
-
- query = query.Where(sq.Eq{"job.job_id": jobIds})
- }
if filter.ArrayJobID != nil {
query = query.Where("job.array_job_id = ?", *filter.ArrayJobID)
}
diff --git a/internal/routerConfig/routes.go b/internal/routerConfig/routes.go
index bf74391..5386553 100644
--- a/internal/routerConfig/routes.go
+++ b/internal/routerConfig/routes.go
@@ -297,6 +297,9 @@ func buildFilterPresets(query url.Values) map[string]interface{} {
}
}
}
+ if len(query["dbId"]) != 0 {
+ filterPresets["dbId"] = query["dbId"]
+ }
if query.Get("jobId") != "" {
if len(query["jobId"]) == 1 {
filterPresets["jobId"] = query.Get("jobId")
diff --git a/web/frontend/src/Jobs.root.svelte b/web/frontend/src/Jobs.root.svelte
index 57f0b5b..6d05646 100644
--- a/web/frontend/src/Jobs.root.svelte
+++ b/web/frontend/src/Jobs.root.svelte
@@ -37,6 +37,7 @@
let filterComponent; // see why here: https://stackoverflow.com/questions/58287729/how-can-i-export-a-function-from-a-svelte-component-that-changes-a-value-in-the
let filterBuffer = [];
+ let selectedJobs = [];
let jobList,
jobCompare,
matchedListJobs,
@@ -59,6 +60,10 @@
// so we need to wait for it to be ready before we can start a query.
// This is also why JobList component starts out with a paused query.
onMount(() => filterComponent.updateFilters());
+
+ $: if (filterComponent && selectedJobs.length == 0) {
+ filterComponent.updateFilters({dbId: []})
+ }
@@ -80,7 +85,7 @@
-
@@ -148,6 +162,7 @@
bind:sorting
bind:matchedListJobs
bind:showFootprint
+ bind:selectedJobs
{filterBuffer}
/>
{:else}
@@ -161,7 +176,7 @@
-
+
Math.floor(Date.parse(rfc3339) / 1000);
-
let opts = [];
if (filters.cluster) opts.push(`cluster=${filters.cluster}`);
if (filters.node) opts.push(`node=${filters.node}`);
@@ -196,6 +198,11 @@
if (filters.startTime.range) {
opts.push(`startTime=${filters.startTime.range}`)
}
+ if (filters.dbId.length != 0) {
+ for (let dbi of filters.dbId) {
+ opts.push(`dbId=${dbi}`);
+ }
+ }
if (filters.jobId.length != 0)
if (filters.jobIdMatch != "in") {
opts.push(`jobId=${filters.jobId}`);
diff --git a/web/frontend/src/generic/JobList.svelte b/web/frontend/src/generic/JobList.svelte
index 03044f0..e6ae6f6 100644
--- a/web/frontend/src/generic/JobList.svelte
+++ b/web/frontend/src/generic/JobList.svelte
@@ -39,6 +39,7 @@
export let metrics = ccconfig.plot_list_selectedMetrics;
export let showFootprint;
export let filterBuffer = [];
+ export let selectedJobs = [];
let usePaging = ccconfig.job_list_usePaging
let itemsPerPage = usePaging ? ccconfig.plot_list_jobsPerPage : 10;
@@ -285,7 +286,10 @@
{:else}
{#each jobs as job (job)}
-
+ selectedJobs = [...selectedJobs, detail]}
+ on:unselect-job={({detail}) => selectedJobs = selectedJobs.filter(item => item !== detail)}
+ />
{:else}
No jobs found |
diff --git a/web/frontend/src/generic/joblist/JobInfo.svelte b/web/frontend/src/generic/joblist/JobInfo.svelte
index 8917653..f5cb066 100644
--- a/web/frontend/src/generic/joblist/JobInfo.svelte
+++ b/web/frontend/src/generic/joblist/JobInfo.svelte
@@ -18,6 +18,8 @@
export let username = null;
export let authlevel= null;
export let roles = null;
+ export let isSelected = null;
+ export let showSelect = false;
function formatDuration(duration) {
const hours = Math.floor(duration / 3600);
@@ -76,18 +78,39 @@
{job.jobId}
({job.cluster})
-
- {#if displayCheck}
-
- {:else}
-
+
+ {#if showSelect}
+ {
+ isSelected = !isSelected
+ }}>
+ {#if isSelected}
+
+ {:else if isSelected == false}
+
+ {:else}
+
+ {/if}
+
+
+ { 'Add or Remove Job to/from Comparison Selection' }
+
{/if}
-
-
- { displayCheck ? 'Copied!' : 'Copy Job ID to Clipboard' }
-
+
+ {#if displayCheck}
+
+ {:else}
+
+ {/if}
+
+
+ { displayCheck ? 'Copied!' : 'Copy Job ID to Clipboard' }
+
+
{#if job.metaData?.jobName}
{#if job.metaData?.jobName.length <= 25}
diff --git a/web/frontend/src/generic/joblist/JobListRow.svelte b/web/frontend/src/generic/joblist/JobListRow.svelte
index 82cf2ed..7d94943 100644
--- a/web/frontend/src/generic/joblist/JobListRow.svelte
+++ b/web/frontend/src/generic/joblist/JobListRow.svelte
@@ -12,7 +12,7 @@