Merge pull request #123 from ClusterCockpit/121_fix_filter_reactivity_crash

121 fix filter reactivity crash
This commit is contained in:
Jan Eitzinger 2023-06-07 17:24:46 +02:00 committed by GitHub
commit 1b1e46bf01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 72 additions and 171 deletions

View File

@ -10,7 +10,6 @@ type Job {
jobId: Int! jobId: Int!
user: String! user: String!
project: String! project: String!
jobName: String
cluster: String! cluster: String!
subCluster: String! subCluster: String!
startTime: Time! startTime: Time!
@ -286,7 +285,7 @@ type HistoPoint {
type JobsStatistics { type JobsStatistics {
id: ID! # If `groupBy` was used, ID of the user/project/cluster id: ID! # If `groupBy` was used, ID of the user/project/cluster
name: String # if User-Statistics: Given Name of Account (ID) Owner name: String! # if User-Statistics: Given Name of Account (ID) Owner
totalJobs: Int! # Number of jobs that matched totalJobs: Int! # Number of jobs that matched
shortJobs: Int! # Number of jobs with a duration of less than 2 minutes shortJobs: Int! # Number of jobs with a duration of less than 2 minutes
totalWalltime: Int! # Sum of the duration of all matched jobs in hours totalWalltime: Int! # Sum of the duration of all matched jobs in hours

View File

@ -90,7 +90,6 @@ type ComplexityRoot struct {
Exclusive func(childComplexity int) int Exclusive func(childComplexity int) int
ID func(childComplexity int) int ID func(childComplexity int) int
JobID func(childComplexity int) int JobID func(childComplexity int) int
JobName func(childComplexity int) int
MetaData func(childComplexity int) int MetaData func(childComplexity int) int
MonitoringStatus func(childComplexity int) int MonitoringStatus func(childComplexity int) int
NumAcc func(childComplexity int) int NumAcc func(childComplexity int) int
@ -287,8 +286,6 @@ type ClusterResolver interface {
Partitions(ctx context.Context, obj *schema.Cluster) ([]string, error) Partitions(ctx context.Context, obj *schema.Cluster) ([]string, error)
} }
type JobResolver interface { type JobResolver interface {
JobName(ctx context.Context, obj *schema.Job) (*string, error)
Tags(ctx context.Context, obj *schema.Job) ([]*schema.Tag, error) Tags(ctx context.Context, obj *schema.Job) ([]*schema.Tag, error)
ConcurrentJobs(ctx context.Context, obj *schema.Job) (*model.JobLinkResultList, error) ConcurrentJobs(ctx context.Context, obj *schema.Job) (*model.JobLinkResultList, error)
@ -489,13 +486,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Job.JobID(childComplexity), true return e.complexity.Job.JobID(childComplexity), true
case "Job.jobName":
if e.complexity.Job.JobName == nil {
break
}
return e.complexity.Job.JobName(childComplexity), true
case "Job.metaData": case "Job.metaData":
if e.complexity.Job.MetaData == nil { if e.complexity.Job.MetaData == nil {
break break
@ -1498,7 +1488,6 @@ type Job {
jobId: Int! jobId: Int!
user: String! user: String!
project: String! project: String!
jobName: String
cluster: String! cluster: String!
subCluster: String! subCluster: String!
startTime: Time! startTime: Time!
@ -1774,7 +1763,7 @@ type HistoPoint {
type JobsStatistics { type JobsStatistics {
id: ID! # If ` + "`" + `groupBy` + "`" + ` was used, ID of the user/project/cluster id: ID! # If ` + "`" + `groupBy` + "`" + ` was used, ID of the user/project/cluster
name: String # if User-Statistics: Given Name of Account (ID) Owner name: String! # if User-Statistics: Given Name of Account (ID) Owner
totalJobs: Int! # Number of jobs that matched totalJobs: Int! # Number of jobs that matched
shortJobs: Int! # Number of jobs with a duration of less than 2 minutes shortJobs: Int! # Number of jobs with a duration of less than 2 minutes
totalWalltime: Int! # Sum of the duration of all matched jobs in hours totalWalltime: Int! # Sum of the duration of all matched jobs in hours
@ -3177,47 +3166,6 @@ func (ec *executionContext) fieldContext_Job_project(ctx context.Context, field
return fc, nil return fc, nil
} }
func (ec *executionContext) _Job_jobName(ctx context.Context, field graphql.CollectedField, obj *schema.Job) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Job_jobName(ctx, field)
if err != nil {
return graphql.Null
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Job().JobName(rctx, obj)
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
return graphql.Null
}
res := resTmp.(*string)
fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res)
}
func (ec *executionContext) fieldContext_Job_jobName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: "Job",
Field: field,
IsMethod: true,
IsResolver: true,
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
return nil, errors.New("field of type String does not have child fields")
},
}
return fc, nil
}
func (ec *executionContext) _Job_cluster(ctx context.Context, field graphql.CollectedField, obj *schema.Job) (ret graphql.Marshaler) { func (ec *executionContext) _Job_cluster(ctx context.Context, field graphql.CollectedField, obj *schema.Job) (ret graphql.Marshaler) {
fc, err := ec.fieldContext_Job_cluster(ctx, field) fc, err := ec.fieldContext_Job_cluster(ctx, field)
if err != nil { if err != nil {
@ -4636,8 +4584,6 @@ func (ec *executionContext) fieldContext_JobResultList_items(ctx context.Context
return ec.fieldContext_Job_user(ctx, field) return ec.fieldContext_Job_user(ctx, field)
case "project": case "project":
return ec.fieldContext_Job_project(ctx, field) return ec.fieldContext_Job_project(ctx, field)
case "jobName":
return ec.fieldContext_Job_jobName(ctx, field)
case "cluster": case "cluster":
return ec.fieldContext_Job_cluster(ctx, field) return ec.fieldContext_Job_cluster(ctx, field)
case "subCluster": case "subCluster":
@ -4871,11 +4817,14 @@ func (ec *executionContext) _JobsStatistics_name(ctx context.Context, field grap
return graphql.Null return graphql.Null
} }
if resTmp == nil { if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null return graphql.Null
} }
res := resTmp.(*string) res := resTmp.(string)
fc.Result = res fc.Result = res
return ec.marshalOString2ᚖstring(ctx, field.Selections, res) return ec.marshalNString2string(ctx, field.Selections, res)
} }
func (ec *executionContext) fieldContext_JobsStatistics_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { func (ec *executionContext) fieldContext_JobsStatistics_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
@ -6635,8 +6584,6 @@ func (ec *executionContext) fieldContext_Query_job(ctx context.Context, field gr
return ec.fieldContext_Job_user(ctx, field) return ec.fieldContext_Job_user(ctx, field)
case "project": case "project":
return ec.fieldContext_Job_project(ctx, field) return ec.fieldContext_Job_project(ctx, field)
case "jobName":
return ec.fieldContext_Job_jobName(ctx, field)
case "cluster": case "cluster":
return ec.fieldContext_Job_cluster(ctx, field) return ec.fieldContext_Job_cluster(ctx, field)
case "subCluster": case "subCluster":
@ -11711,23 +11658,6 @@ func (ec *executionContext) _Job(ctx context.Context, sel ast.SelectionSet, obj
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
atomic.AddUint32(&invalids, 1) atomic.AddUint32(&invalids, 1)
} }
case "jobName":
field := field
innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
}
}()
res = ec._Job_jobName(ctx, field, obj)
return res
}
out.Concurrently(i, func() graphql.Marshaler {
return innerFunc(ctx)
})
case "cluster": case "cluster":
out.Values[i] = ec._Job_cluster(ctx, field, obj) out.Values[i] = ec._Job_cluster(ctx, field, obj)
@ -12125,6 +12055,9 @@ func (ec *executionContext) _JobsStatistics(ctx context.Context, sel ast.Selecti
out.Values[i] = ec._JobsStatistics_name(ctx, field, obj) out.Values[i] = ec._JobsStatistics_name(ctx, field, obj)
if out.Values[i] == graphql.Null {
invalids++
}
case "totalJobs": case "totalJobs":
out.Values[i] = ec._JobsStatistics_totalJobs(ctx, field, obj) out.Values[i] = ec._JobsStatistics_totalJobs(ctx, field, obj)

View File

@ -88,7 +88,7 @@ type JobResultList struct {
type JobsStatistics struct { type JobsStatistics struct {
ID string `json:"id"` ID string `json:"id"`
Name *string `json:"name"` Name string `json:"name"`
TotalJobs int `json:"totalJobs"` TotalJobs int `json:"totalJobs"`
ShortJobs int `json:"shortJobs"` ShortJobs int `json:"shortJobs"`
TotalWalltime int `json:"totalWalltime"` TotalWalltime int `json:"totalWalltime"`

View File

@ -26,11 +26,6 @@ func (r *clusterResolver) Partitions(ctx context.Context, obj *schema.Cluster) (
return r.Repo.Partitions(obj.Name) return r.Repo.Partitions(obj.Name)
} }
// JobName is the resolver for the jobName field.
func (r *jobResolver) JobName(ctx context.Context, obj *schema.Job) (*string, error) {
return r.Repo.FetchJobName(obj)
}
// Tags is the resolver for the tags field. // Tags is the resolver for the tags field.
func (r *jobResolver) Tags(ctx context.Context, obj *schema.Job) ([]*schema.Tag, error) { func (r *jobResolver) Tags(ctx context.Context, obj *schema.Job) ([]*schema.Tag, error) {
return r.Repo.GetTags(&obj.ID) return r.Repo.GetTags(&obj.ID)
@ -38,7 +33,6 @@ func (r *jobResolver) Tags(ctx context.Context, obj *schema.Job) ([]*schema.Tag,
// ConcurrentJobs is the resolver for the concurrentJobs field. // ConcurrentJobs is the resolver for the concurrentJobs field.
func (r *jobResolver) ConcurrentJobs(ctx context.Context, obj *schema.Job) (*model.JobLinkResultList, error) { func (r *jobResolver) ConcurrentJobs(ctx context.Context, obj *schema.Job) (*model.JobLinkResultList, error) {
exc := int(obj.Exclusive) exc := int(obj.Exclusive)
if exc != 1 { if exc != 1 {
filter := []*model.JobFilter{} filter := []*model.JobFilter{}

View File

@ -151,39 +151,6 @@ func scanJobLink(row interface{ Scan(...interface{}) error }) (*model.JobLink, e
return jobLink, nil return jobLink, nil
} }
func (r *JobRepository) FetchJobName(job *schema.Job) (*string, error) {
start := time.Now()
cachekey := fmt.Sprintf("metadata:%d", job.ID)
if cached := r.cache.Get(cachekey, nil); cached != nil {
job.MetaData = cached.(map[string]string)
if jobName := job.MetaData["jobName"]; jobName != "" {
return &jobName, nil
}
}
if err := sq.Select("job.meta_data").From("job").Where("job.id = ?", job.ID).
RunWith(r.stmtCache).QueryRow().Scan(&job.RawMetaData); err != nil {
return nil, err
}
if len(job.RawMetaData) == 0 {
return nil, nil
}
if err := json.Unmarshal(job.RawMetaData, &job.MetaData); err != nil {
return nil, err
}
r.cache.Put(cachekey, job.MetaData, len(job.RawMetaData), 24*time.Hour)
log.Infof("Timer FetchJobName %s", time.Since(start))
if jobName := job.MetaData["jobName"]; jobName != "" {
return &jobName, nil
} else {
return new(string), nil
}
}
func (r *JobRepository) FetchMetadata(job *schema.Job) (map[string]string, error) { func (r *JobRepository) FetchMetadata(job *schema.Job) (map[string]string, error) {
start := time.Now() start := time.Now()
cachekey := fmt.Sprintf("metadata:%d", job.ID) cachekey := fmt.Sprintf("metadata:%d", job.ID)
@ -597,9 +564,18 @@ func (r *JobRepository) FindColumnValue(user *auth.User, searchterm string, tabl
query = "%" + searchterm + "%" query = "%" + searchterm + "%"
} }
if user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport, auth.RoleManager}) { if user.HasAnyRole([]auth.Role{auth.RoleAdmin, auth.RoleSupport, auth.RoleManager}) {
err := sq.Select(table+"."+selectColumn).Distinct().From(table). theQuery := sq.Select(table+"."+selectColumn).Distinct().From(table).
Where(table+"."+whereColumn+compareStr, query). Where(table+"."+whereColumn+compareStr, query)
RunWith(r.stmtCache).QueryRow().Scan(&result)
// theSql, args, theErr := theQuery.ToSql()
// if theErr != nil {
// log.Warn("Error while converting query to sql")
// return "", err
// }
// log.Debugf("SQL query (FindColumnValue): `%s`, args: %#v", theSql, args)
err := theQuery.RunWith(r.stmtCache).QueryRow().Scan(&result)
if err != nil && err != sql.ErrNoRows { if err != nil && err != sql.ErrNoRows {
return "", err return "", err
} else if err == nil { } else if err == nil {
@ -913,9 +889,9 @@ func (r *JobRepository) JobsStatistics(ctx context.Context,
user := auth.GetUser(ctx) user := auth.GetUser(ctx)
name, _ := r.FindColumnValue(user, id, "user", "name", "username", false) name, _ := r.FindColumnValue(user, id, "user", "name", "username", false)
if name != "" { if name != "" {
stats[id].Name = &name stats[id].Name = name
} else { } else {
stats[id].Name = &emptyDash stats[id].Name = emptyDash
} }
} }
} }

View File

@ -25,12 +25,13 @@
filterPresets.startTime = { from: hourAgo.toISOString(), to: now.toISOString() } filterPresets.startTime = { from: hourAgo.toISOString(), to: now.toISOString() }
} }
let cluster let cluster;
let filters 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 rooflineMaxY let jobFilters = [];
let colWidth let rooflineMaxY;
let numBins = 50 let colWidth;
let maxY = -1 let numBins = 50;
let maxY = -1;
const ccconfig = getContext('cc-config') const ccconfig = getContext('cc-config')
const metricConfig = getContext('metrics') const metricConfig = getContext('metrics')
@ -54,8 +55,8 @@
$: statsQuery = queryStore({ $: statsQuery = queryStore({
client: client, client: client,
query: gql` query: gql`
query($filters: [JobFilter!]!) { query($jobFilters: [JobFilter!]!) {
stats: jobsStatistics(filter: $filters) { stats: jobsStatistics(filter: $jobFilters) {
totalJobs totalJobs
shortJobs shortJobs
totalWalltime totalWalltime
@ -67,34 +68,34 @@
topUsers: jobsCount(filter: $filters, groupBy: USER, weight: NODE_HOURS, limit: 5) { name, count } topUsers: jobsCount(filter: $filters, groupBy: USER, weight: NODE_HOURS, limit: 5) { name, count }
} }
`, `,
variables: { filters } variables: { jobFilters }
}) })
$: footprintsQuery = queryStore({ $: footprintsQuery = queryStore({
client: client, client: client,
query: gql` query: gql`
query($filters: [JobFilter!]!, $metrics: [String!]!) { query($jobFilters: [JobFilter!]!, $metrics: [String!]!) {
footprints: jobsFootprints(filter: $filters, metrics: $metrics) { footprints: jobsFootprints(filter: $jobFilters, metrics: $metrics) {
nodehours, nodehours,
metrics { metric, data } metrics { metric, data }
} }
}`, }`,
variables: { filters, metrics } variables: { jobFilters, metrics }
}) })
$: rooflineQuery = queryStore({ $: rooflineQuery = queryStore({
client: client, client: client,
query: gql` query: gql`
query($filters: [JobFilter!]!, $rows: Int!, $cols: Int!, query($jobFilters: [JobFilter!]!, $rows: Int!, $cols: Int!,
$minX: Float!, $minY: Float!, $maxX: Float!, $maxY: Float!) { $minX: Float!, $minY: Float!, $maxX: Float!, $maxY: Float!) {
rooflineHeatmap(filter: $filters, rows: $rows, cols: $cols, rooflineHeatmap(filter: $jobFilters, rows: $rows, cols: $cols,
minX: $minX, minY: $minY, maxX: $maxX, maxY: $maxY) minX: $minX, minY: $minY, maxX: $maxX, maxY: $maxY)
} }
`, `,
variables: { filters, rows: 50, cols: 50, minX: 0.01, minY: 1., maxX: 1000., maxY } variables: { jobFilters, rows: 50, cols: 50, minX: 0.01, minY: 1., maxX: 1000., maxY }
}) })
onMount(() => filters.update()) onMount(() => filterComponent.update())
</script> </script>
<Row> <Row>
@ -115,12 +116,12 @@
</Col> </Col>
<Col xs="auto"> <Col xs="auto">
<Filters <Filters
bind:this={filters} bind:this={filterComponent}
filterPresets={filterPresets} filterPresets={filterPresets}
disableClusterSelection={true} disableClusterSelection={true}
startTimeQuickSelect={true} startTimeQuickSelect={true}
on:update={({ detail }) => { on:update={({ detail }) => {
filters = detail.filters; jobFilters = detail.filters;
}} /> }} />
</Col> </Col>
</Row> </Row>

View File

@ -17,7 +17,7 @@
export let authlevel export let authlevel
export let roles export let roles
let filters = [] 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 jobList, matchedJobs = null let jobList, matchedJobs = null
let sorting = { field: 'startTime', order: 'DESC' }, isSortingOpen = false, isMetricsSelectionOpen = false let sorting = { field: 'startTime', order: 'DESC' }, isSortingOpen = false, isMetricsSelectionOpen = false
let metrics = filterPresets.cluster let metrics = filterPresets.cluster
@ -25,12 +25,10 @@
: ccconfig.plot_list_selectedMetrics : ccconfig.plot_list_selectedMetrics
let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null let selectedCluster = filterPresets?.cluster ? filterPresets.cluster : null
$: selectedCluster = filters[0]?.cluster ? filters[0].cluster.eq : null
// The filterPresets are handled by the Filters component, // The filterPresets are handled by the Filters component,
// so we need to wait for it to be ready before we can start a query. // 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. // This is also why JobList component starts out with a paused query.
onMount(() => filters.update()) onMount(() => filterComponent.update())
</script> </script>
<Row> <Row>
@ -61,15 +59,16 @@
<Col xs="auto"> <Col xs="auto">
<Filters <Filters
filterPresets={filterPresets} filterPresets={filterPresets}
bind:this={filters} bind:this={filterComponent}
on:update={({ detail }) => { on:update={({ detail }) => {
filters = detail.filters selectedCluster = detail.filters[0]?.cluster ? detail.filters[0].cluster.eq : null
jobList.update(detail.filters)} jobList.update(detail.filters)
}
} /> } />
</Col> </Col>
<Col xs="3" style="margin-left: auto;"> <Col xs="3" style="margin-left: auto;">
<UserOrProject bind:authlevel={authlevel} bind:roles={roles} on:update={({ detail }) => filters.update(detail)}/> <UserOrProject bind:authlevel={authlevel} bind:roles={roles} on:update={({ detail }) => filterComponent.update(detail)}/>
</Col> </Col>
<Col xs="2"> <Col xs="2">
<Refresher on:reload={() => jobList.refresh()} /> <Refresher on:reload={() => jobList.refresh()} />

View File

@ -29,12 +29,17 @@
"Invalid list type provided!" "Invalid list type provided!"
); );
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 jobFilters = [];
let nameFilter = "";
let sorting = { field: "totalJobs", direction: "down" };
const client = getContextClient(); const client = getContextClient();
$: stats = queryStore({ $: stats = queryStore({
client: client, client: client,
query: gql` query: gql`
query($filters: [JobFilter!]!) { query($jobFilters: [JobFilter!]!) {
rows: jobsStatistics(filter: $filters, groupBy: ${type}) { rows: jobsStatistics(filter: $jobFilters, groupBy: ${type}) {
id id
name name
totalJobs totalJobs
@ -42,13 +47,9 @@
totalCoreHours totalCoreHours
} }
}`, }`,
variables: { filters } variables: { jobFilters }
}); });
let filters;
let nameFilter = "";
let sorting = { field: "totalJobs", direction: "down" };
function changeSorting(event, field) { function changeSorting(event, field) {
let target = event.target; let target = event.target;
while (target.tagName != "BUTTON") target = target.parentElement; while (target.tagName != "BUTTON") target = target.parentElement;
@ -73,7 +74,7 @@
return stats.filter((u) => u.id.includes(nameFilter)).sort(cmp); return stats.filter((u) => u.id.includes(nameFilter)).sort(cmp);
} }
onMount(() => filters.update()); onMount(() => filterComponent.update());
</script> </script>
<Row> <Row>
@ -93,12 +94,12 @@
</Col> </Col>
<Col xs="auto"> <Col xs="auto">
<Filters <Filters
bind:this={filters} bind:this={filterComponent}
{filterPresets} {filterPresets}
startTimeQuickSelect={true} startTimeQuickSelect={true}
menuText="Only {type.toLowerCase()}s with jobs that match the filters will show up" menuText="Only {type.toLowerCase()}s with jobs that match the filters will show up"
on:update={({ detail }) => { on:update={({ detail }) => {
filters = detail.filters; jobFilters = detail.filters;
}} }}
/> />
</Col> </Col>

View File

@ -18,8 +18,9 @@
export let user export let user
export let filterPresets export let filterPresets
let filters = [] 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 jobList let jobList;
let jobFilters = [];
let sorting = { field: 'startTime', order: 'DESC' }, isSortingOpen = false let sorting = { field: 'startTime', order: 'DESC' }, isSortingOpen = false
let metrics = ccconfig.plot_list_selectedMetrics, isMetricsSelectionOpen = false let metrics = ccconfig.plot_list_selectedMetrics, isMetricsSelectionOpen = false
let w1, w2, histogramHeight = 250 let w1, w2, histogramHeight = 250
@ -29,8 +30,8 @@
$: stats = queryStore({ $: stats = queryStore({
client: client, client: client,
query: gql` query: gql`
query($filters: [JobFilter!]!) { query($jobFilters: [JobFilter!]!) {
jobsStatistics(filter: $filters) { jobsStatistics(filter: $jobFilters) {
totalJobs totalJobs
shortJobs shortJobs
totalWalltime totalWalltime
@ -38,12 +39,10 @@
histDuration { count, value } histDuration { count, value }
histNumNodes { count, value } histNumNodes { count, value }
}}`, }}`,
variables: { filters } variables: { jobFilters }
}) })
$: selectedCluster = filters[0]?.cluster ? filters[0].cluster.eq : null onMount(() => filterComponent.update())
onMount(() => filters.update())
</script> </script>
<Row> <Row>
@ -74,10 +73,10 @@
<Filters <Filters
filterPresets={filterPresets} filterPresets={filterPresets}
startTimeQuickSelect={true} startTimeQuickSelect={true}
bind:this={filters} bind:this={filterComponent}
on:update={({ detail }) => { on:update={({ detail }) => {
let jobFilters = [...detail.filters, { user: { eq: user.username } }] jobFilters = [...detail.filters, { user: { eq: user.username } }]
filters = jobFilters selectedCluster = jobFilters[0]?.cluster ? jobFilters[0].cluster.eq : null
jobList.update(jobFilters) jobList.update(jobFilters)
}} /> }} />
</Col> </Col>

View File

@ -47,7 +47,6 @@
jobId jobId
user user
project project
jobName
cluster cluster
subCluster subCluster
startTime startTime