Repository: kestra-io/kestra
Issue: Flow list : allow to filter execution based on status directly on flow list

we are displaying usefull stats on flow list page. 

![image](https://user-images.githubusercontent.com/2064609/79745786-3546d400-8309-11ea-84f6-389730e897bf.png)

It can be really useful to have a link directly on execution from this charts.
* The lowest effort will be to go to execution filter for current date.
* The best one will be to allow to go on execution filter for current date **and** status.  

Issue comments:
@tchiotludo it's good for this version.
for now the chart bar click redirects to execution page with state selection using a the dedicated status filter select. But it still filters execution using the free search bar.
Going a step beyond will be done in issue https://github.com/kestra-io/kestra/issues/124


Pull request review comments:

Patch that resolved the issue:
diff --git a/core/src/main/java/org/kestra/core/repositories/ExecutionRepositoryInterface.java b/core/src/main/java/org/kestra/core/repositories/ExecutionRepositoryInterface.java
index b808b9954f..7258e48e63 100644
--- a/core/src/main/java/org/kestra/core/repositories/ExecutionRepositoryInterface.java
+++ b/core/src/main/java/org/kestra/core/repositories/ExecutionRepositoryInterface.java
@@ -4,6 +4,7 @@
 import org.kestra.core.models.executions.Execution;
 import org.kestra.core.models.executions.metrics.ExecutionMetricsAggregation;
 import org.kestra.core.models.executions.metrics.Stats;
+import org.kestra.core.models.flows.State;
 
 import java.util.Map;
 import java.util.Optional;
@@ -13,7 +14,7 @@ public interface ExecutionRepositoryInterface {
 
     ArrayListTotal<Execution> findByFlowId(String namespace, String id, Pageable pageable);
 
-    ArrayListTotal<Execution> find(String query, Pageable pageable);
+    ArrayListTotal<Execution> find(String query, Pageable pageable, State.Type state);
 
     Map<String, ExecutionMetricsAggregation> aggregateByStateWithDurationStats(String query, Pageable pageable);
 
diff --git a/repository-elasticsearch/src/main/java/org/kestra/repository/elasticsearch/ElasticSearchExecutionRepository.java b/repository-elasticsearch/src/main/java/org/kestra/repository/elasticsearch/ElasticSearchExecutionRepository.java
index a327ac76d7..ef5eed5bf5 100644
--- a/repository-elasticsearch/src/main/java/org/kestra/repository/elasticsearch/ElasticSearchExecutionRepository.java
+++ b/repository-elasticsearch/src/main/java/org/kestra/repository/elasticsearch/ElasticSearchExecutionRepository.java
@@ -26,6 +26,7 @@
 import org.kestra.core.utils.ThreadMainFactoryBuilder;
 import org.kestra.repository.elasticsearch.configs.IndicesConfig;
 
+import javax.annotation.Nullable;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import java.io.IOException;
@@ -177,8 +178,15 @@ public Map<String, Stats> findLast24hDurationStats(String query, Pageable pageab
 
 
     @Override
-    public ArrayListTotal<Execution> find(String query, Pageable pageable) {
-        return super.findQueryString(INDEX_NAME, query, pageable);
+    public ArrayListTotal<Execution> find(String query, Pageable pageable, @Nullable State.Type state) {
+        BoolQueryBuilder bool = this.defaultFilter()
+            .must(QueryBuilders.queryStringQuery(query));
+        if (state != null) {
+            bool = bool.must(QueryBuilders.termQuery("state.current", state.name()));
+        }
+        SearchSourceBuilder sourceBuilder = this.searchSource(bool, Optional.empty(), pageable);
+
+        return this.query(INDEX_NAME, sourceBuilder);
     }
 
     @Override
diff --git a/repository-memory/src/main/java/org/kestra/repository/memory/MemoryExecutionRepository.java b/repository-memory/src/main/java/org/kestra/repository/memory/MemoryExecutionRepository.java
index ca6032516c..993151b310 100644
--- a/repository-memory/src/main/java/org/kestra/repository/memory/MemoryExecutionRepository.java
+++ b/repository-memory/src/main/java/org/kestra/repository/memory/MemoryExecutionRepository.java
@@ -5,6 +5,7 @@
 import org.kestra.core.models.executions.Execution;
 import org.kestra.core.models.executions.metrics.ExecutionMetricsAggregation;
 import org.kestra.core.models.executions.metrics.Stats;
+import org.kestra.core.models.flows.State;
 import org.kestra.core.repositories.ArrayListTotal;
 import org.kestra.core.repositories.ExecutionRepositoryInterface;
 
@@ -19,7 +20,7 @@ public class MemoryExecutionRepository implements ExecutionRepositoryInterface {
     private Map<String, Execution> executions = new HashMap<>();
 
     @Override
-    public ArrayListTotal<Execution> find(String query, Pageable pageable) {
+    public ArrayListTotal<Execution> find(String query, Pageable pageable, State.Type state) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/ui/src/components/executions/Executions.vue b/ui/src/components/executions/Executions.vue
index cf0d3e18af..6e4499868c 100644
--- a/ui/src/components/executions/Executions.vue
+++ b/ui/src/components/executions/Executions.vue
@@ -8,7 +8,7 @@
                 <date-range @onDate="onSearch" />
                 <refresh-button class="float-right" @onRefresh="loadData"/>
                 <v-s />
-                <status-filter-buttons @onRefresh="addStatusToQuery"/>
+                <status-filter-buttons @onRefresh="loadData"/>
             </template>
             <template v-slot:table>
                 <b-table
@@ -91,6 +91,7 @@ export default {
     beforeCreate () {
         const params = JSON.parse(localStorage.getItem('executionQueries') || '{}')
         params.sort = 'state.startDate:desc'
+        params.status = this.$route.query.status || params.status || 'ALL'
         localStorage.setItem('executionQueries', JSON.stringify(params))
     },
     computed: {
@@ -179,7 +180,8 @@ export default {
                 size: parseInt(this.$route.query.size || 25),
                 page: parseInt(this.$route.query.page || 1),
                 q: this.executionQuery,
-                sort: this.$route.query.sort
+                sort: this.$route.query.sort,
+                state: this.$route.query.status
             }).finally(callback);
         }
     }
diff --git a/ui/src/components/flows/Chart.vue b/ui/src/components/flows/Chart.vue
index 327164b299..c3b54de3f9 100644
--- a/ui/src/components/flows/Chart.vue
+++ b/ui/src/components/flows/Chart.vue
@@ -45,6 +45,29 @@ export default {
                 }
             };
             const data = this.getData();
+            data.onclick = d => {
+                const executionDay = this.$moment(
+                    this.$chart.categories()[d.index]
+                );
+                const start = executionDay.unix() * 1000;
+                executionDay.add(1, "d");
+                const end = executionDay.unix() * 1000;
+
+                const routeParams = {
+                    name: "executionsByFlow",
+                    params: {
+                        namespace: data.row.item.namespace,
+                        flowId: data.row.item.id
+                    },
+                    query: {
+                        start,
+                        end,
+                        q: data.row.item.id,
+                        status: d.id.toUpperCase()
+                    }
+                };
+                this.$router.push(routeParams);
+            };
             const config = this.getConfig();
 
             return defaultsDeep({ data }, size, config);
diff --git a/ui/src/components/flows/Flows.vue b/ui/src/components/flows/Flows.vue
index a8bf0b6b35..6f164ddb40 100644
--- a/ui/src/components/flows/Flows.vue
+++ b/ui/src/components/flows/Flows.vue
@@ -179,7 +179,8 @@ export default {
             return {
                 json: row.item.metrics,
                 keys: { x: "startDate", value: statuses },
-                groups: [statuses]
+                groups: [statuses],
+                row
             };
         },
         loadData(callback) {
diff --git a/ui/src/components/layout/StatusFilterButtons.vue b/ui/src/components/layout/StatusFilterButtons.vue
index 8accc8381d..8da33be611 100644
--- a/ui/src/components/layout/StatusFilterButtons.vue
+++ b/ui/src/components/layout/StatusFilterButtons.vue
@@ -9,11 +9,17 @@ export default {
             selected: "all"
         };
     },
+    created() {
+        if (this.$route.query.status) {
+            this.selected = this.$route.query.status.toLowerCase();
+        }
+    },
     methods: {
         searchStatus() {
-            const token = this.selected.toUpperCase();
-            if (this.$route.query.q !== token) {
-                this.$emit("onRefresh", token === "ALL" ? "" : token);
+            const status = this.selected.toUpperCase();
+            if (this.$route.query.status !== status) {
+                this.$router.push({ query: { ...this.$route.query, status } });
+                this.$emit("onRefresh");
             }
         }
     }
diff --git a/webserver/src/main/java/org/kestra/webserver/controllers/ExecutionController.java b/webserver/src/main/java/org/kestra/webserver/controllers/ExecutionController.java
index 5120929fbf..d7dd4d828a 100644
--- a/webserver/src/main/java/org/kestra/webserver/controllers/ExecutionController.java
+++ b/webserver/src/main/java/org/kestra/webserver/controllers/ExecutionController.java
@@ -18,6 +18,7 @@
 import org.kestra.core.exceptions.IllegalVariableEvaluationException;
 import org.kestra.core.models.executions.Execution;
 import org.kestra.core.models.flows.Flow;
+import org.kestra.core.models.flows.State;
 import org.kestra.core.models.hierarchies.FlowTree;
 import org.kestra.core.queues.QueueFactoryInterface;
 import org.kestra.core.queues.QueueInterface;
@@ -72,11 +73,12 @@ public PagedResults<Execution> find(
         @QueryValue(value = "q") String query,
         @QueryValue(value = "page", defaultValue = "1") int page,
         @QueryValue(value = "size", defaultValue = "10") int size,
+        @Nullable @QueryValue(value = "state") State.Type state,
         @Nullable @QueryValue(value = "sort") List<String> sort
     ) throws HttpStatusException {
         return PagedResults.of(
             executionRepository
-                .find(query, PageableUtils.from(page, size, sort))
+                .find(query, PageableUtils.from(page, size, sort), state)
         );
     }
 


Test patch: