Skip to content

Commit ccc8e54

Browse files
committed
fix(): Adapt the usage of the new query filter for custom dashboard
close #7091
1 parent 343367d commit ccc8e54

File tree

30 files changed

+331
-344
lines changed

30 files changed

+331
-344
lines changed

core/src/main/java/io/kestra/core/models/Label.java

+16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import io.kestra.core.utils.MapUtils;
44
import jakarta.validation.constraints.NotNull;
55

6+
import java.util.HashMap;
67
import java.util.List;
78
import java.util.Map;
89
import java.util.stream.Collectors;
@@ -46,4 +47,19 @@ public static List<Label> from(final Map<String, String> map) {
4647
.map(entry -> new Label(entry.getKey(), entry.getValue()))
4748
.toList();
4849
}
50+
51+
/**
52+
* Static helper method for converting a label string to a map.
53+
*
54+
* @param label The label string.
55+
* @return The map of key/value labels.
56+
*/
57+
public static Map<String, String> from(String label) {
58+
Map<String, String> map = new HashMap<>();
59+
String[] keyValueArray = label.split(":");
60+
if (keyValueArray.length == 2) {
61+
map.put(keyValueArray[0], keyValueArray[1]);
62+
}
63+
return map;
64+
}
4965
}

core/src/main/java/io/kestra/core/models/QueryFilter.java

+71-29
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package io.kestra.core.models;
22

3+
import com.fasterxml.jackson.annotation.JsonCreator;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import com.fasterxml.jackson.annotation.JsonValue;
6+
import io.kestra.core.models.dashboards.filters.*;
37
import io.kestra.core.utils.Enums;
48
import lombok.Builder;
59

6-
import java.util.*;
10+
import java.util.Arrays;
11+
import java.util.List;
12+
import java.util.Map;
713
import java.util.function.Function;
814
import java.util.stream.Collectors;
915

@@ -13,33 +19,63 @@ public record QueryFilter(
1319
Op operation,
1420
Object value
1521
) {
16-
public enum Op {
17-
EQUALS("$eq"),
18-
NOT_EQUALS("$ne"),
19-
GREATER_THAN("$gte"),
20-
LESS_THAN("$lte"),
21-
IN("$in"),
22-
NOT_IN("$notIn"),
23-
STARTS_WITH("$startsWith"),
24-
ENDS_WITH("$endsWith"),
25-
CONTAINS("$contains"),
26-
REGEX("$regex");
27-
28-
private static final Map<String, Op> BY_VALUE = Arrays.stream(values())
29-
.collect(Collectors.toMap(Op::value, Function.identity()));
3022

31-
private final String value;
23+
@JsonCreator
24+
public QueryFilter(
25+
@JsonProperty("field") Field field,
26+
@JsonProperty("operation") Op operation,
27+
@JsonProperty("value") Object value
28+
) {
29+
this.field = field;
30+
this.operation = operation;
31+
this.value = value;
32+
}
3233

33-
Op(String value) {
34-
this.value = value;
35-
}
34+
public enum Op {
35+
EQUALS,
36+
NOT_EQUALS,
37+
GREATER_THAN,
38+
LESS_THAN,
39+
GREATER_THAN_OR_EQUAL_TO,
40+
LESS_THAN_OR_EQUAL_TO,
41+
IN,
42+
NOT_IN,
43+
STARTS_WITH,
44+
ENDS_WITH,
45+
CONTAINS,
46+
REGEX;
47+
}
3648

37-
public static Op fromString(String value) {
38-
return Enums.fromString(value, BY_VALUE, "operation");
39-
}
4049

41-
public String value() {
42-
return value;
50+
@SuppressWarnings("unchecked")
51+
public <T extends Enum<T>> AbstractFilter<T> toDashboardFilterBuilder(T field, Object value) {
52+
switch (this.operation) {
53+
case EQUALS:
54+
return EqualTo.<T>builder().field(field).value(value).build();
55+
case NOT_EQUALS:
56+
return NotEqualTo.<T>builder().field(field).value(value).build();
57+
case GREATER_THAN:
58+
return GreaterThan.<T>builder().field(field).value(value).build();
59+
case LESS_THAN:
60+
return LessThan.<T>builder().field(field).value(value).build();
61+
case GREATER_THAN_OR_EQUAL_TO:
62+
return GreaterThanOrEqualTo.<T>builder().field(field).value(value).build();
63+
case LESS_THAN_OR_EQUAL_TO:
64+
return LessThanOrEqualTo.<T>builder().field(field).value(value).build();
65+
case IN:
66+
return In.<T>builder().field(field).values((List<Object>) value).build();
67+
case NOT_IN:
68+
return NotIn.<T>builder().field(field).values((List<Object>) value).build();
69+
case STARTS_WITH:
70+
return StartsWith.<T>builder().field(field).value(value.toString()).build();
71+
case ENDS_WITH:
72+
return EndsWith.<T>builder().field(field).value(value.toString()).build();
73+
case CONTAINS:
74+
return Contains.<T>builder().field(field).value(value.toString()).build();
75+
case REGEX:
76+
return Regex.<T>builder().field(field).value(value.toString()).build();
77+
default:
78+
throw new IllegalArgumentException("Unsupported operation: " + this.operation);
4379
}
4480
}
4581

@@ -147,16 +183,17 @@ public List<Op> supportedOp() {
147183
this.value = value;
148184
}
149185

186+
@JsonCreator
150187
public static Field fromString(String value) {
151188
return Enums.fromString(value, BY_VALUE, "field");
152189
}
153190

191+
@JsonValue
154192
public String value() {
155193
return value;
156194
}
157195
}
158196

159-
160197
public enum Resource {
161198
FLOW {
162199
@Override
@@ -239,12 +276,17 @@ private static FieldOp toFieldInfo(Field field) {
239276
}
240277

241278
private static Operation toOperation(Op op) {
242-
return new Operation(op.name(), op.value());
279+
return new Operation(op.name(), op.name());
243280
}
244281
}
245282

246-
public record ResourceField(String name, List<FieldOp> fields) {}
247-
public record FieldOp(String name, String value, List<Operation> operations) {}
248-
public record Operation(String name, String value) {}
283+
public record ResourceField(String name, List<FieldOp> fields) {
284+
}
285+
286+
public record FieldOp(String name, String value, List<Operation> operations) {
287+
}
288+
289+
public record Operation(String name, String value) {
290+
}
249291

250292
}

core/src/main/java/io/kestra/core/models/dashboards/DataFilter.java

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
package io.kestra.core.models.dashboards;
22

3-
import com.fasterxml.jackson.annotation.JsonSubTypes;
4-
import com.fasterxml.jackson.annotation.JsonTypeInfo;
5-
import com.fasterxml.jackson.annotation.JsonTypeName;
3+
import io.kestra.core.models.QueryFilter;
64
import io.kestra.core.models.annotations.Plugin;
75
import io.kestra.core.models.dashboards.filters.AbstractFilter;
86
import io.kestra.core.repositories.QueryBuilderInterface;
9-
import io.kestra.plugin.core.dashboard.data.Executions;
10-
import io.kestra.plugin.core.dashboard.data.Logs;
117
import jakarta.validation.constraints.NotBlank;
128
import jakarta.validation.constraints.NotNull;
139
import jakarta.validation.constraints.Pattern;
@@ -17,6 +13,7 @@
1713
import lombok.Setter;
1814
import lombok.experimental.SuperBuilder;
1915

16+
import java.time.ZonedDateTime;
2017
import java.util.Collections;
2118
import java.util.List;
2219
import java.util.Map;
@@ -47,6 +44,6 @@ public Set<F> aggregationForbiddenFields() {
4744

4845
public abstract Class<? extends QueryBuilderInterface<F>> repositoryClass();
4946

50-
public abstract void setGlobalFilter(GlobalFilter globalFilter);
47+
public abstract void setGlobalFilter(List<QueryFilter> queryFilterList, ZonedDateTime startDate, ZonedDateTime endDate);
5148

5249
}

core/src/main/java/io/kestra/plugin/core/dashboard/data/Executions.java

+33-15
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import com.fasterxml.jackson.annotation.JsonInclude;
44
import com.fasterxml.jackson.annotation.JsonTypeName;
5+
import io.kestra.core.models.QueryFilter;
56
import io.kestra.core.models.annotations.Plugin;
67
import io.kestra.core.models.dashboards.ColumnDescriptor;
78
import io.kestra.core.models.dashboards.DataFilter;
8-
import io.kestra.core.models.dashboards.GlobalFilter;
9-
import io.kestra.core.models.dashboards.filters.*;
9+
import io.kestra.core.models.dashboards.filters.AbstractFilter;
10+
import io.kestra.core.models.dashboards.filters.Contains;
11+
import io.kestra.core.models.dashboards.filters.GreaterThanOrEqualTo;
12+
import io.kestra.core.models.dashboards.filters.LessThanOrEqualTo;
1013
import io.kestra.core.repositories.ExecutionRepositoryInterface;
1114
import io.kestra.core.repositories.QueryBuilderInterface;
1215
import io.kestra.core.validations.ExecutionsDataFilterValidation;
@@ -16,6 +19,7 @@
1619
import lombok.NoArgsConstructor;
1720
import lombok.experimental.SuperBuilder;
1821

22+
import java.time.ZonedDateTime;
1923
import java.util.ArrayList;
2024
import java.util.List;
2125

@@ -35,24 +39,38 @@ public Class<? extends QueryBuilderInterface<Executions.Fields>> repositoryClass
3539
}
3640

3741
@Override
38-
public void setGlobalFilter(GlobalFilter globalFilter) {
42+
public void setGlobalFilter(List<QueryFilter> filters, ZonedDateTime startDate, ZonedDateTime endDate) {
3943
List<AbstractFilter<Fields>> where = this.getWhere() != null ? new ArrayList<>(this.getWhere()) : new ArrayList<>();
4044

41-
if (globalFilter.getNamespace() != null) {
42-
where.removeIf(f -> f.getField().equals(Fields.NAMESPACE));
43-
where.add(EqualTo.<Executions.Fields>builder().field(Fields.NAMESPACE).value(globalFilter.getNamespace()).build());
45+
if (filters == null) {
46+
return;
4447
}
45-
if (globalFilter.getLabels() != null) {
46-
where.removeIf(f -> f.getField().equals(Fields.LABELS));
47-
where.add(Contains.<Executions.Fields>builder().field(Fields.LABELS).value(globalFilter.getLabels()).build());
48+
49+
List<QueryFilter> namespaceFilters = filters.stream().filter(f -> f.field().equals(QueryFilter.Field.NAMESPACE)).toList();
50+
if (!namespaceFilters.isEmpty()) {
51+
where.removeIf(filter -> filter.getField().equals(Executions.Fields.NAMESPACE));
52+
namespaceFilters.forEach(f -> {
53+
where.add(f.toDashboardFilterBuilder(Executions.Fields.NAMESPACE, f.value()));
54+
});
55+
}
56+
57+
List<QueryFilter> labelFilters = filters.stream().filter(f -> f.field().equals(QueryFilter.Field.LABELS)).toList();
58+
if (!labelFilters.isEmpty()) {
59+
where.removeIf(filter -> filter.getField().equals(Fields.LABELS));
60+
labelFilters.forEach(f -> {
61+
where.add(Contains.<Executions.Fields>builder().field(Fields.LABELS).value(f.value()).build());
62+
});
4863
}
49-
if (globalFilter.getStartDate() != null || globalFilter.getEndDate() != null) {
50-
where.removeIf(f -> f.getField().equals(Fields.START_DATE));
51-
if (globalFilter.getStartDate() != null) {
52-
where.add(GreaterThanOrEqualTo.<Executions.Fields>builder().field(Fields.START_DATE).value(globalFilter.getStartDate().toOffsetDateTime()).build());
64+
65+
66+
if (startDate != null || endDate != null) {
67+
if (startDate != null) {
68+
where.removeIf(f -> f.getField().equals(Fields.START_DATE));
69+
where.add(GreaterThanOrEqualTo.<Executions.Fields>builder().field(Fields.START_DATE).value(startDate.toInstant()).build());
5370
}
54-
if (globalFilter.getEndDate() != null) {
55-
where.add(LessThanOrEqualTo.<Executions.Fields>builder().field(Fields.START_DATE).value(globalFilter.getEndDate().toOffsetDateTime()).build());
71+
if (endDate != null) {
72+
where.removeIf(f -> f.getField().equals(Fields.END_DATE));
73+
where.add(LessThanOrEqualTo.<Executions.Fields>builder().field(Fields.END_DATE).value(endDate.toInstant()).build());
5674
}
5775
}
5876

core/src/main/java/io/kestra/plugin/core/dashboard/data/Logs.java

+19-11
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package io.kestra.plugin.core.dashboard.data;
22

33
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import io.kestra.core.models.QueryFilter;
45
import io.kestra.core.models.annotations.Plugin;
56
import io.kestra.core.models.dashboards.ColumnDescriptor;
67
import io.kestra.core.models.dashboards.DataFilter;
7-
import io.kestra.core.models.dashboards.GlobalFilter;
88
import io.kestra.core.models.dashboards.filters.AbstractFilter;
9-
import io.kestra.core.models.dashboards.filters.EqualTo;
109
import io.kestra.core.models.dashboards.filters.GreaterThanOrEqualTo;
1110
import io.kestra.core.models.dashboards.filters.LessThanOrEqualTo;
1211
import io.kestra.core.repositories.LogRepositoryInterface;
@@ -17,6 +16,7 @@
1716
import lombok.NoArgsConstructor;
1817
import lombok.experimental.SuperBuilder;
1918

19+
import java.time.ZonedDateTime;
2020
import java.util.ArrayList;
2121
import java.util.List;
2222
import java.util.Set;
@@ -35,20 +35,28 @@ public Class<? extends QueryBuilderInterface<Logs.Fields>> repositoryClass() {
3535
}
3636

3737
@Override
38-
public void setGlobalFilter(GlobalFilter globalFilter) {
38+
public void setGlobalFilter(List<QueryFilter> filters, ZonedDateTime startDate, ZonedDateTime endDate) {
3939
List<AbstractFilter<Fields>> where = this.getWhere() != null ? new ArrayList<>(this.getWhere()) : new ArrayList<>();
4040

41-
if (globalFilter.getNamespace() != null) {
42-
where.removeIf(f -> f.getField().equals(Fields.NAMESPACE));
43-
where.add(EqualTo.<Fields>builder().field(Fields.NAMESPACE).value(globalFilter.getNamespace()).build());
41+
if (filters == null) {
42+
return;
4443
}
45-
if (globalFilter.getStartDate() != null || globalFilter.getEndDate() != null) {
44+
45+
List<QueryFilter> namespaceFilters = filters.stream().filter(f -> f.field().equals(QueryFilter.Field.NAMESPACE)).toList();
46+
if (!namespaceFilters.isEmpty()) {
47+
where.removeIf(filter -> filter.getField().equals(Logs.Fields.NAMESPACE));
48+
namespaceFilters.forEach(f -> {
49+
where.add(f.toDashboardFilterBuilder(Logs.Fields.NAMESPACE, f.value()));
50+
});
51+
}
52+
53+
if (startDate != null || endDate != null) {
4654
where.removeIf(f -> f.getField().equals(Fields.DATE));
47-
if (globalFilter.getStartDate() != null) {
48-
where.add(GreaterThanOrEqualTo.<Fields>builder().field(Fields.DATE).value(globalFilter.getStartDate().toInstant()).build());
55+
if (startDate != null) {
56+
where.add(GreaterThanOrEqualTo.<Logs.Fields>builder().field(Fields.DATE).value(startDate.toInstant()).build());
4957
}
50-
if (globalFilter.getEndDate() != null) {
51-
where.add(LessThanOrEqualTo.<Fields>builder().field(Fields.DATE).value(globalFilter.getEndDate().toInstant()).build());
58+
if (endDate != null) {
59+
where.add(LessThanOrEqualTo.<Logs.Fields>builder().field(Fields.DATE).value(endDate.toInstant()).build());
5260
}
5361
}
5462

core/src/main/java/io/kestra/plugin/core/dashboard/data/Metrics.java

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package io.kestra.plugin.core.dashboard.data;
22

33
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import io.kestra.core.models.QueryFilter;
45
import io.kestra.core.models.annotations.Plugin;
56
import io.kestra.core.models.dashboards.ColumnDescriptor;
67
import io.kestra.core.models.dashboards.DataFilter;
7-
import io.kestra.core.models.dashboards.GlobalFilter;
88
import io.kestra.core.models.dashboards.filters.AbstractFilter;
99
import io.kestra.core.models.dashboards.filters.EqualTo;
1010
import io.kestra.core.repositories.MetricRepositoryInterface;
@@ -15,6 +15,7 @@
1515
import lombok.NoArgsConstructor;
1616
import lombok.experimental.SuperBuilder;
1717

18+
import java.time.ZonedDateTime;
1819
import java.util.ArrayList;
1920
import java.util.List;
2021

@@ -32,12 +33,19 @@ public Class<? extends QueryBuilderInterface<Metrics.Fields>> repositoryClass()
3233
}
3334

3435
@Override
35-
public void setGlobalFilter(GlobalFilter globalFilter) {
36+
public void setGlobalFilter(List<QueryFilter> filters, ZonedDateTime startDate, ZonedDateTime endDate) {
3637
List<AbstractFilter<Fields>> where = this.getWhere() != null ? new ArrayList<>(this.getWhere()) : new ArrayList<>();
3738

38-
if (globalFilter.getNamespace() != null) {
39-
where.removeIf(f -> f.getField().equals(Fields.NAMESPACE));
40-
where.add(EqualTo.<Fields>builder().field(Fields.NAMESPACE).value(globalFilter.getNamespace()).build());
39+
if (filters == null) {
40+
return;
41+
}
42+
43+
List<QueryFilter> namespaceFilters = filters.stream().filter(f -> f.field().equals(QueryFilter.Field.NAMESPACE)).toList();
44+
if (!namespaceFilters.isEmpty()) {
45+
where.removeIf(filter -> filter.getField().equals(Metrics.Fields.NAMESPACE));
46+
namespaceFilters.forEach(f -> {
47+
where.add(EqualTo.<Metrics.Fields>builder().field(Metrics.Fields.NAMESPACE).value(f.value()).build());
48+
});
4149
}
4250

4351
this.setWhere(where);

0 commit comments

Comments
 (0)