From 0679b84f6ca3cd142c7ba61d9e434895f3b27b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Tue, 18 Jul 2023 09:53:48 +0200 Subject: [PATCH 001/121] fix(core): flaky labels tests --- .../java/io/kestra/core/models/triggers/types/FlowTest.java | 5 +++-- .../io/kestra/core/models/triggers/types/ScheduleTest.java | 5 +++-- .../java/io/kestra/core/schedulers/SchedulerThreadTest.java | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/core/src/test/java/io/kestra/core/models/triggers/types/FlowTest.java b/core/src/test/java/io/kestra/core/models/triggers/types/FlowTest.java index 01032e5104..ae4f467b3f 100644 --- a/core/src/test/java/io/kestra/core/models/triggers/types/FlowTest.java +++ b/core/src/test/java/io/kestra/core/models/triggers/types/FlowTest.java @@ -15,6 +15,7 @@ import java.util.Optional; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; @MicronautTest @@ -59,7 +60,7 @@ void success() { assertThat(evaluate.isPresent(), is(true)); assertThat(evaluate.get().getFlowId(), is("flow-with-flow-trigger")); - assertThat(evaluate.get().getLabels().get(0), is(new Label("flow-label-1", "flow-label-1"))); - assertThat(evaluate.get().getLabels().get(1), is(new Label("flow-label-2", "flow-label-2"))); + assertThat(evaluate.get().getLabels(), hasItem(new Label("flow-label-1", "flow-label-1"))); + assertThat(evaluate.get().getLabels(), hasItem(new Label("flow-label-2", "flow-label-2"))); } } diff --git a/core/src/test/java/io/kestra/core/models/triggers/types/ScheduleTest.java b/core/src/test/java/io/kestra/core/models/triggers/types/ScheduleTest.java index 15bbc8fc70..5cdad63d3e 100644 --- a/core/src/test/java/io/kestra/core/models/triggers/types/ScheduleTest.java +++ b/core/src/test/java/io/kestra/core/models/triggers/types/ScheduleTest.java @@ -25,6 +25,7 @@ import jakarta.inject.Inject; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; @MicronautTest @@ -92,8 +93,8 @@ void success() throws Exception { assertThat(dateFromVars(vars.get("date"), date), is(date)); assertThat(dateFromVars(vars.get("next"), date), is(date.plusMonths(1))); assertThat(dateFromVars(vars.get("previous"), date), is(date.minusMonths(1))); - assertThat(evaluate.get().getLabels().get(0), is(new Label("flow-label-1", "flow-label-1"))); - assertThat(evaluate.get().getLabels().get(1), is(new Label("flow-label-2", "flow-label-2"))); + assertThat(evaluate.get().getLabels(), hasItem(new Label("flow-label-1", "flow-label-1"))); + assertThat(evaluate.get().getLabels(), hasItem(new Label("flow-label-2", "flow-label-2"))); } @SuppressWarnings("unchecked") diff --git a/core/src/test/java/io/kestra/core/schedulers/SchedulerThreadTest.java b/core/src/test/java/io/kestra/core/schedulers/SchedulerThreadTest.java index c323d565a6..7f471ca39f 100644 --- a/core/src/test/java/io/kestra/core/schedulers/SchedulerThreadTest.java +++ b/core/src/test/java/io/kestra/core/schedulers/SchedulerThreadTest.java @@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicReference; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.*; @@ -94,8 +95,8 @@ void thread() throws Exception { assertThat(last.get().getTrigger().getVariables().get("defaultInjected"), is("done")); assertThat(last.get().getTrigger().getVariables().get("counter"), is(3)); - assertThat(last.get().getLabels().get(0), is(new Label("flow-label-1", "flow-label-1"))); - assertThat(last.get().getLabels().get(1), is(new Label("flow-label-2", "flow-label-2"))); + assertThat(last.get().getLabels(), hasItem(new Label("flow-label-1", "flow-label-1"))); + assertThat(last.get().getLabels(), hasItem(new Label("flow-label-2", "flow-label-2"))); AbstractSchedulerTest.COUNTER = 0; } } From 45146c59dd564c5b5822cb4fb6a4aa13fee132bc Mon Sep 17 00:00:00 2001 From: YannC Date: Tue, 18 Jul 2023 11:48:01 +0200 Subject: [PATCH 002/121] chore(version): update snapshot version 'v0.11.0-SNAPSHOT'. --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 7884f77a3f..e99505f821 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -version=0.10.2-SNAPSHOT +version=0.11.0-SNAPSHOT micronautVersion=3.9.3 lombokVersion=1.18.28 From 48ad3fecf0b020559a6530fb8843a639cb81c82a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Wed, 12 Jul 2023 11:29:38 +0200 Subject: [PATCH 003/121] chore: avoid recreating an ObjectMapper for non-strict mapper --- .../io/kestra/core/serializers/JacksonMapper.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/io/kestra/core/serializers/JacksonMapper.java b/core/src/main/java/io/kestra/core/serializers/JacksonMapper.java index 82c0146581..5482c58112 100644 --- a/core/src/main/java/io/kestra/core/serializers/JacksonMapper.java +++ b/core/src/main/java/io/kestra/core/serializers/JacksonMapper.java @@ -30,18 +30,16 @@ abstract public class JacksonMapper { new ObjectMapper() ); + private static final ObjectMapper NON_STRICT_MAPPER = MAPPER + .copy() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + public static ObjectMapper ofJson() { return MAPPER; } public static ObjectMapper ofJson(boolean strict) { - if (strict) { - return MAPPER; - } - - return MAPPER - .copy() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + return strict ? MAPPER : NON_STRICT_MAPPER; } private static final ObjectMapper YAML_MAPPER = JacksonMapper.configure( From 11b3ae99eca66f545b9e47da8df0483b3b002e17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Wed, 19 Jul 2023 14:56:30 +0200 Subject: [PATCH 004/121] chore: refactor FlowController.updateNamespace() --- .../webserver/controllers/FlowController.java | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/webserver/src/main/java/io/kestra/webserver/controllers/FlowController.java b/webserver/src/main/java/io/kestra/webserver/controllers/FlowController.java index 4fc46e515e..f9f2f7ea0f 100644 --- a/webserver/src/main/java/io/kestra/webserver/controllers/FlowController.java +++ b/webserver/src/main/java/io/kestra/webserver/controllers/FlowController.java @@ -227,9 +227,8 @@ public List updateNamespace( namespace, sources .stream() - .map(flow -> yamlFlowParser.parse(flow, Flow.class)) - .collect(Collectors.toList()), - sources, + .map(flow -> FlowWithSource.of(yamlFlowParser.parse(flow, Flow.class), flow)) + .toList(), delete ); } @@ -250,19 +249,18 @@ public List updateNamespace( return this .updateCompleteNamespace( namespace, - flows, flows .stream() - .map(throwFunction(Flow::generateSource)) + .map(throwFunction(flow -> FlowWithSource.of(flow, flow.generateSource()))) .collect(Collectors.toList()), delete ) .stream() .map(FlowWithSource::toFlow) - .collect(Collectors.toList()); + .toList(); } - private List updateCompleteNamespace(String namespace, List flows, List sources, Boolean delete) { + protected List updateCompleteNamespace(String namespace, List flows, Boolean delete) { // control namespace to update Set> invalids = flows .stream() @@ -285,7 +283,7 @@ private List updateCompleteNamespace(String namespace, List updateCompleteNamespace(String namespace, List ids = flows .stream() .map(Flow::getId) - .collect(Collectors.toList()); + .toList(); // delete all not in updated ids List deleted = new ArrayList<>(); @@ -314,25 +312,23 @@ private List updateCompleteNamespace(String namespace, List updatedOrCreated = IntStream.range(0, flows.size()) - .mapToObj(index -> { - Flow flow = flows.get(index); - String source = sources.get(index); - + List updatedOrCreated = flows.stream() + .map(flowWithSource -> { + Flow flow = flowWithSource.toFlow(); Optional existingFlow = flowRepository.findById(namespace, flow.getId()); if (existingFlow.isPresent()) { - return flowRepository.update(flow, existingFlow.get(), source, taskDefaultService.injectDefaults(flow)); + return flowRepository.update(flow, existingFlow.get(), flowWithSource.getSource(), taskDefaultService.injectDefaults(flow)); } else { - return flowRepository.create(flow, source, taskDefaultService.injectDefaults(flow)); + return flowRepository.create(flow, flowWithSource.getSource(), taskDefaultService.injectDefaults(flow)); } }) - .collect(Collectors.toList()); + .toList(); - return Stream.concat(deleted.stream(), updatedOrCreated.stream()).collect(Collectors.toList()); + return Stream.concat(deleted.stream(), updatedOrCreated.stream()).toList(); } @Put(uri = "{namespace}/{id}", produces = MediaType.TEXT_JSON, consumes = MediaType.APPLICATION_YAML) From 52eef24de19ae17d005a5c2c290ce28bde1a4b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Thu, 20 Jul 2023 14:30:57 +0200 Subject: [PATCH 005/121] feat: add Databricks plugin --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 88a0ecfdff..8860e3b35f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -139,7 +139,7 @@ jobs: plugins: "" packages: "" - name: "-full" - plugins: io.kestra.storage:storage-azure:LATEST io.kestra.storage:storage-gcs:LATEST io.kestra.storage:storage-minio:LATEST io.kestra.plugin:plugin-airbyte:LATEST io.kestra.plugin:plugin-amqp:LATEST io.kestra.plugin:plugin-aws:LATEST io.kestra.plugin:plugin-azure:LATEST io.kestra.plugin:plugin-powerbi:LATEST io.kestra.plugin:plugin-pulsar:LATEST io.kestra.plugin:plugin-cassandra:LATEST io.kestra.plugin:plugin-compress:LATEST io.kestra.plugin:plugin-couchbase:LATEST io.kestra.plugin:plugin-crypto:LATEST io.kestra.plugin:plugin-dbt:LATEST io.kestra.plugin:plugin-debezium-mysql:LATEST io.kestra.plugin:plugin-debezium-postgres:LATEST io.kestra.plugin:plugin-debezium-sqlserver:LATEST io.kestra.plugin:plugin-elasticsearch:LATEST io.kestra.plugin:plugin-fivetran:LATEST io.kestra.plugin:plugin-fs:LATEST io.kestra.plugin:plugin-gcp:LATEST io.kestra.plugin:plugin-git:LATEST io.kestra.plugin:plugin-googleworkspace:LATEST io.kestra.plugin:plugin-jdbc-clickhouse:LATEST io.kestra.plugin:plugin-jdbc-duckdb:LATEST io.kestra.plugin:plugin-jdbc-mysql:LATEST io.kestra.plugin:plugin-nats:LATEST io.kestra.plugin:plugin-jdbc-oracle:LATEST io.kestra.plugin:plugin-jdbc-pinot:LATEST io.kestra.plugin:plugin-jdbc-postgres:LATEST io.kestra.plugin:plugin-jdbc-redshift:LATEST io.kestra.plugin:plugin-jdbc-rockset:LATEST io.kestra.plugin:plugin-jdbc-snowflake:LATEST io.kestra.plugin:plugin-jdbc-sqlserver:LATEST io.kestra.plugin:plugin-jdbc-trino:LATEST io.kestra.plugin:plugin-jdbc-vertica:LATEST io.kestra.plugin:plugin-jdbc-vectorwise:LATEST io.kestra.plugin:plugin-kafka:LATEST io.kestra.plugin:plugin-kubernetes:LATEST io.kestra.plugin:plugin-mongodb:LATEST io.kestra.plugin:plugin-mqtt:LATEST io.kestra.plugin:plugin-neo4j:LATEST io.kestra.plugin:plugin-notifications:LATEST io.kestra.plugin:plugin-openai:LATEST io.kestra.plugin:plugin-redis:LATEST io.kestra.plugin:plugin-script-groovy:LATEST io.kestra.plugin:plugin-script-jython:LATEST io.kestra.plugin:plugin-script-nashorn:LATEST io.kestra.plugin:plugin-script-node:LATEST io.kestra.plugin:plugin-script-powershell:LATEST io.kestra.plugin:plugin-script-python:LATEST io.kestra.plugin:plugin-script-r:LATEST io.kestra.plugin:plugin-script-shell:LATEST io.kestra.plugin:plugin-serdes:LATEST io.kestra.plugin:plugin-servicenow:LATEST io.kestra.plugin:plugin-singer:LATEST io.kestra.plugin:plugin-soda:LATEST io.kestra.plugin:plugin-spark:LATEST io.kestra.plugin:plugin-tika:LATEST + plugins: io.kestra.storage:storage-azure:LATEST io.kestra.storage:storage-gcs:LATEST io.kestra.storage:storage-minio:LATEST io.kestra.plugin:plugin-airbyte:LATEST io.kestra.plugin:plugin-amqp:LATEST io.kestra.plugin:plugin-aws:LATEST io.kestra.plugin:plugin-azure:LATEST io.kestra.plugin:plugin-powerbi:LATEST io.kestra.plugin:plugin-pulsar:LATEST io.kestra.plugin:plugin-cassandra:LATEST io.kestra.plugin:plugin-compress:LATEST io.kestra.plugin:plugin-couchbase:LATEST io.kestra.plugin:plugin-crypto:LATEST io.kestra.plugin:plugin-databricks:LATEST io.kestra.plugin:plugin-dbt:LATEST io.kestra.plugin:plugin-debezium-mysql:LATEST io.kestra.plugin:plugin-debezium-postgres:LATEST io.kestra.plugin:plugin-debezium-sqlserver:LATEST io.kestra.plugin:plugin-elasticsearch:LATEST io.kestra.plugin:plugin-fivetran:LATEST io.kestra.plugin:plugin-fs:LATEST io.kestra.plugin:plugin-gcp:LATEST io.kestra.plugin:plugin-git:LATEST io.kestra.plugin:plugin-googleworkspace:LATEST io.kestra.plugin:plugin-jdbc-clickhouse:LATEST io.kestra.plugin:plugin-jdbc-duckdb:LATEST io.kestra.plugin:plugin-jdbc-mysql:LATEST io.kestra.plugin:plugin-nats:LATEST io.kestra.plugin:plugin-jdbc-oracle:LATEST io.kestra.plugin:plugin-jdbc-pinot:LATEST io.kestra.plugin:plugin-jdbc-postgres:LATEST io.kestra.plugin:plugin-jdbc-redshift:LATEST io.kestra.plugin:plugin-jdbc-rockset:LATEST io.kestra.plugin:plugin-jdbc-snowflake:LATEST io.kestra.plugin:plugin-jdbc-sqlserver:LATEST io.kestra.plugin:plugin-jdbc-trino:LATEST io.kestra.plugin:plugin-jdbc-vertica:LATEST io.kestra.plugin:plugin-jdbc-vectorwise:LATEST io.kestra.plugin:plugin-kafka:LATEST io.kestra.plugin:plugin-kubernetes:LATEST io.kestra.plugin:plugin-mongodb:LATEST io.kestra.plugin:plugin-mqtt:LATEST io.kestra.plugin:plugin-neo4j:LATEST io.kestra.plugin:plugin-notifications:LATEST io.kestra.plugin:plugin-openai:LATEST io.kestra.plugin:plugin-redis:LATEST io.kestra.plugin:plugin-script-groovy:LATEST io.kestra.plugin:plugin-script-jython:LATEST io.kestra.plugin:plugin-script-nashorn:LATEST io.kestra.plugin:plugin-script-node:LATEST io.kestra.plugin:plugin-script-powershell:LATEST io.kestra.plugin:plugin-script-python:LATEST io.kestra.plugin:plugin-script-r:LATEST io.kestra.plugin:plugin-script-shell:LATEST io.kestra.plugin:plugin-serdes:LATEST io.kestra.plugin:plugin-servicenow:LATEST io.kestra.plugin:plugin-singer:LATEST io.kestra.plugin:plugin-soda:LATEST io.kestra.plugin:plugin-spark:LATEST io.kestra.plugin:plugin-tika:LATEST packages: python3 python3-venv python-is-python3 nodejs npm curl zip unzip steps: - uses: actions/checkout@v3 From 226e971496407e7e3a40890a0be97014bcd63c98 Mon Sep 17 00:00:00 2001 From: YannC <37600690+Skraye@users.noreply.github.com> Date: Fri, 21 Jul 2023 10:08:03 +0200 Subject: [PATCH 006/121] feat(): Allow to change fontSize & fontFamily in editor from Settings (#1787) * feat(): Allow to change fontSize & fontFamily in editor from Settings * fix(): review changes --- ui/src/components/inputs/Editor.vue | 6 +- ui/src/components/inputs/MonacoEditor.vue | 2 +- ui/src/components/settings/Settings.vue | 73 ++++++++++++++++++++++- ui/src/translations.json | 4 ++ 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/ui/src/components/inputs/Editor.vue b/ui/src/components/inputs/Editor.vue index d16d6cc50d..3fcd8192f3 100644 --- a/ui/src/components/inputs/Editor.vue +++ b/ui/src/components/inputs/Editor.vue @@ -20,7 +20,7 @@ - + @@ -185,8 +185,8 @@ return { ...{ tabSize: 2, - fontFamily: "'Source Code Pro', monospace", - fontSize: 12, + fontFamily: localStorage.getItem("editorFontFamily") ? localStorage.getItem("editorFontFamily") : "'Source Code Pro', monospace", + fontSize: localStorage.getItem("editorFontSize") ? parseInt(localStorage.getItem("editorFontSize")) : 12, showFoldingControls: "always", scrollBeyondLastLine: false, roundedSelection: false, diff --git a/ui/src/components/inputs/MonacoEditor.vue b/ui/src/components/inputs/MonacoEditor.vue index f995cf5c07..33f5f9820a 100644 --- a/ui/src/components/inputs/MonacoEditor.vue +++ b/ui/src/components/inputs/MonacoEditor.vue @@ -12,7 +12,7 @@ import * as monaco from "monaco-editor/esm/vs/editor/editor.api"; import EditorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker"; import YamlWorker from "./yaml.worker.js?worker"; - import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'; + import JsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker"; import {setDiagnosticsOptions} from "monaco-yaml"; import {yamlSchemas} from "override/utils/yamlSchemas" import Utils from "../../utils/utils"; diff --git a/ui/src/components/settings/Settings.vue b/ui/src/components/settings/Settings.vue index 412afa8ebf..132ba2415e 100644 --- a/ui/src/components/settings/Settings.vue +++ b/ui/src/components/settings/Settings.vue @@ -1,6 +1,6 @@ + + + + {{ $t("unlock trigger.warning") }} + + - + - + \ No newline at end of file diff --git a/ui/src/stores/trigger.js b/ui/src/stores/trigger.js index 357151ddb1..a617697fba 100644 --- a/ui/src/stores/trigger.js +++ b/ui/src/stores/trigger.js @@ -10,6 +10,9 @@ export default { }).then(response => { return response.data; }) + }, + async unlock({commit}, options) { + return (await this.$http.post(`/api/v1/triggers/${options.namespace}/${options.flowId}/${options.triggerId}/unlock`)).data; } } } diff --git a/ui/src/translations.json b/ui/src/translations.json index 7d5f901054..3034b70362 100644 --- a/ui/src/translations.json +++ b/ui/src/translations.json @@ -465,7 +465,16 @@ "cannot swap tasks": "Can't swap the tasks", "dependency task": "Task {taskId} is a dependency of another task", "administration": "Administration", - "evaluation lock date": "Evaluation lock date" + "evaluation lock date": "Evaluation lock date", + "unlock trigger": { + "tooltip": { + "execution": "There is an execution running for this trigger", + "evaluation": "The trigger is currently in evaluation" + }, + "confirmation": "Are you sure you want to unlock the trigger ?", + "warning": "It could lead to concurrent executions for the same trigger and should be considered as a last resort option.", + "button": "Unlock trigger" + } }, "fr": { "id": "Identifiant", @@ -935,6 +944,15 @@ "cannot swap tasks": "Impossible de permuter les tâches", "dependency task": "La tâche {taskId} est une dépendance d'une autre tâche", "administration": "Administration", - "evaluation lock date": "Date verrou évaluation" + "evaluation lock date": "Date verrou évaluation", + "unlock trigger": { + "tooltip": { + "execution": "Il existe une exécution en cours pour ce trigger", + "evaluation": "Le déclencheur est en cours d'évaluation" + }, + "confirmation": "Êtes vous sûr(e) de vouloir débloquer le déclencheur ?", + "warning": "Cela pourrait amener à de multiples exécutions concurrentes pour le même déclencheur et devrait être considéré comme une solution de dernier recours.", + "button": "Débloquer le déclencheur" + } } } diff --git a/webserver/src/main/java/io/kestra/webserver/controllers/TriggerController.java b/webserver/src/main/java/io/kestra/webserver/controllers/TriggerController.java index ce026498e4..bda87937ac 100644 --- a/webserver/src/main/java/io/kestra/webserver/controllers/TriggerController.java +++ b/webserver/src/main/java/io/kestra/webserver/controllers/TriggerController.java @@ -1,14 +1,15 @@ package io.kestra.webserver.controllers; import io.kestra.core.models.triggers.Trigger; +import io.kestra.core.models.triggers.TriggerContext; +import io.kestra.core.queues.QueueInterface; import io.kestra.core.repositories.TriggerRepositoryInterface; import io.kestra.webserver.responses.PagedResults; import io.kestra.webserver.utils.PageableUtils; import io.micronaut.core.annotation.Nullable; +import io.micronaut.http.HttpResponse; import io.micronaut.http.MediaType; -import io.micronaut.http.annotation.Controller; -import io.micronaut.http.annotation.Get; -import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.annotation.*; import io.micronaut.http.exceptions.HttpStatusException; import io.micronaut.scheduling.TaskExecutors; import io.micronaut.scheduling.annotation.ExecuteOn; @@ -17,12 +18,16 @@ import jakarta.inject.Inject; import java.util.List; +import java.util.Optional; @Controller("/api/v1/triggers") public class TriggerController { @Inject private TriggerRepositoryInterface triggerRepository; + @Inject + private QueueInterface triggerQueue; + @ExecuteOn(TaskExecutors.IO) @Get(uri = "/search", produces = MediaType.TEXT_JSON) @Operation(tags = {"Triggers"}, summary = "Search for triggers") @@ -39,4 +44,33 @@ public PagedResults search( namespace )); } + + @ExecuteOn(TaskExecutors.IO) + @Post(uri = "/{namespace}/{flowId}/{triggerId}/unlock") + @Operation(tags = {"Triggers"}, summary = "Unlock a trigger") + public HttpResponse unlock( + @Parameter(description = "The namespace") @PathVariable String namespace, + @Parameter(description = "The flow id") @PathVariable String flowId, + @Parameter(description = "The trigger id") @PathVariable String triggerId + ) throws HttpStatusException { + Optional triggerOpt = triggerRepository.findLast(TriggerContext.builder() + .namespace(namespace) + .flowId(flowId) + .triggerId(triggerId) + .build()); + + if (triggerOpt.isEmpty()) { + return HttpResponse.notFound(); + } + + Trigger trigger = triggerOpt.get(); + if (trigger.getExecutionId() == null && trigger.getEvaluateRunningDate() == null) { + throw new IllegalStateException("Trigger is not locked"); + } + + trigger = trigger.resetExecution(); + triggerQueue.emit(trigger); + + return HttpResponse.ok(trigger); + } } diff --git a/webserver/src/test/java/io/kestra/webserver/controllers/TriggerControllerTest.java b/webserver/src/test/java/io/kestra/webserver/controllers/TriggerControllerTest.java index 85053107b0..071056d1a4 100644 --- a/webserver/src/test/java/io/kestra/webserver/controllers/TriggerControllerTest.java +++ b/webserver/src/test/java/io/kestra/webserver/controllers/TriggerControllerTest.java @@ -2,13 +2,16 @@ import io.kestra.core.models.triggers.Trigger; import io.kestra.core.utils.Await; +import io.kestra.core.utils.IdUtils; import io.kestra.jdbc.repository.AbstractJdbcFlowRepository; import io.kestra.jdbc.repository.AbstractJdbcTriggerRepository; import io.kestra.webserver.controllers.h2.JdbcH2ControllerTest; import io.kestra.webserver.responses.PagedResults; import io.micronaut.core.type.Argument; import io.micronaut.http.HttpRequest; +import io.micronaut.http.HttpStatus; import io.micronaut.http.client.annotation.Client; +import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.micronaut.rxjava2.http.client.RxHttpClient; import jakarta.inject.Inject; import org.hamcrest.Matchers; @@ -20,6 +23,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; +import static org.junit.jupiter.api.Assertions.assertThrows; class TriggerControllerTest extends JdbcH2ControllerTest { @Inject @@ -65,4 +69,50 @@ void search() { ) ); } + + @Test + void unlock() { + Trigger trigger = Trigger.builder() + .flowId(IdUtils.create()) + .namespace("io.kestra.unittest") + .triggerId(IdUtils.create()) + .executionId(IdUtils.create()) + .build(); + + jdbcTriggerRepository.save(trigger); + + trigger = client.toBlocking().retrieve(HttpRequest.POST("/api/v1/triggers/%s/%s/%s/unlock".formatted( + trigger.getNamespace(), + trigger.getFlowId(), + trigger.getTriggerId() + ), null), Trigger.class); + + assertThat(trigger.getExecutionId(), is(nullValue())); + assertThat(trigger.getEvaluateRunningDate(), is(nullValue())); + + Trigger unlockedTrigger = jdbcTriggerRepository.findLast(trigger).orElseThrow(); + + assertThat(unlockedTrigger.getExecutionId(), is(nullValue())); + assertThat(unlockedTrigger.getEvaluateRunningDate(), is(nullValue())); + + HttpClientResponseException e = assertThrows(HttpClientResponseException.class, () -> + client.toBlocking().exchange(HttpRequest.POST("/api/v1/triggers/%s/%s/%s/unlock".formatted( + unlockedTrigger.getNamespace(), + unlockedTrigger.getFlowId(), + unlockedTrigger.getTriggerId() + ), null))); + + assertThat(e.getStatus(), is(HttpStatus.CONFLICT)); + assertThat(e.getMessage(), is("Illegal state: Trigger is not locked")); + + e = assertThrows(HttpClientResponseException.class, () -> + client.toBlocking().exchange(HttpRequest.POST("/api/v1/triggers/%s/%s/%s/unlock".formatted( + "bad.namespace", + "some-flow-id", + "some-trigger-id" + ), null)) + ); + + assertThat(e.getStatus(), is(HttpStatus.NOT_FOUND)); + } } From 9ce70f7ef82d36acb580175ed376398c25e2470b Mon Sep 17 00:00:00 2001 From: "brian.mulier" Date: Mon, 24 Jul 2023 16:57:48 +0200 Subject: [PATCH 025/121] fix(ui): auto-refresh button is now animated for better feedback closes #1802 --- ui/src/components/layout/RefreshButton.vue | 39 ++++++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/ui/src/components/layout/RefreshButton.vue b/ui/src/components/layout/RefreshButton.vue index 9fa6677b69..d5e8d6ee48 100644 --- a/ui/src/components/layout/RefreshButton.vue +++ b/ui/src/components/layout/RefreshButton.vue @@ -1,8 +1,8 @@ - + \ No newline at end of file From e66ed6c333eac32459c58ffa719d7f11961575b1 Mon Sep 17 00:00:00 2001 From: "brian.mulier" Date: Wed, 26 Jul 2023 09:26:23 +0200 Subject: [PATCH 026/121] fix(core): can now override the way to retrieve registered plugins in JsonSchemaGenerator used in #1807 --- .../kestra/core/docs/JsonSchemaGenerator.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/io/kestra/core/docs/JsonSchemaGenerator.java b/core/src/main/java/io/kestra/core/docs/JsonSchemaGenerator.java index 5e381441cc..76309fdacb 100644 --- a/core/src/main/java/io/kestra/core/docs/JsonSchemaGenerator.java +++ b/core/src/main/java/io/kestra/core/docs/JsonSchemaGenerator.java @@ -23,6 +23,7 @@ import io.kestra.core.models.tasks.Output; import io.kestra.core.models.tasks.Task; import io.kestra.core.models.triggers.AbstractTrigger; +import io.kestra.core.plugins.RegisteredPlugin; import io.kestra.core.serializers.JacksonMapper; import io.kestra.core.services.PluginService; import io.micronaut.core.annotation.Nullable; @@ -304,29 +305,25 @@ public CustomDefinition provideCustomSchemaDefinition(ResolvedType javaType, Sch TypeContext typeContext = context.getTypeContext(); if (declaredType.getErasedType() == Task.class) { - return pluginService - .allPlugins() + return getRegisteredPlugins() .stream() .flatMap(registeredPlugin -> registeredPlugin.getTasks().stream()) .map(clz -> typeContext.resolveSubtype(declaredType, clz)) .collect(Collectors.toList()); } else if (declaredType.getErasedType() == AbstractTrigger.class) { - return pluginService - .allPlugins() + return getRegisteredPlugins() .stream() .flatMap(registeredPlugin -> registeredPlugin.getTriggers().stream()) .map(clz -> typeContext.resolveSubtype(declaredType, clz)) .collect(Collectors.toList()); } else if (declaredType.getErasedType() == Condition.class) { - return pluginService - .allPlugins() + return getRegisteredPlugins() .stream() .flatMap(registeredPlugin -> registeredPlugin.getConditions().stream()) .map(clz -> typeContext.resolveSubtype(declaredType, clz)) .collect(Collectors.toList()); } else if (declaredType.getErasedType() == ScheduleCondition.class) { - return pluginService - .allPlugins() + return getRegisteredPlugins() .stream() .flatMap(registeredPlugin -> registeredPlugin.getConditions().stream()) .filter(ScheduleCondition.class::isAssignableFrom) @@ -404,6 +401,11 @@ public CustomDefinition provideCustomSchemaDefinition(ResolvedType javaType, Sch } } + protected List getRegisteredPlugins() { + return pluginService + .allPlugins(); + } + private boolean defaultInAllOf(JsonNode property) { if (property.has("allOf")) { for (Iterator it = property.get("allOf").elements(); it.hasNext(); ) { From 96551f4e7672ea59e06f9c67fc8f610ccdd79380 Mon Sep 17 00:00:00 2001 From: "brian.mulier" Date: Mon, 31 Jul 2023 11:29:06 +0200 Subject: [PATCH 027/121] fix(doc-gen): now also displaying properties with @PluginProperty inside bases in json schema (including conditions) closes #1704 --- .../java/io/kestra/core/docs/JsonSchemaGenerator.java | 4 ++-- .../io/kestra/core/models/triggers/AbstractTrigger.java | 2 ++ .../java/io/kestra/core/docs/JsonSchemaGeneratorTest.java | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/io/kestra/core/docs/JsonSchemaGenerator.java b/core/src/main/java/io/kestra/core/docs/JsonSchemaGenerator.java index 76309fdacb..3d90b70cb7 100644 --- a/core/src/main/java/io/kestra/core/docs/JsonSchemaGenerator.java +++ b/core/src/main/java/io/kestra/core/docs/JsonSchemaGenerator.java @@ -426,10 +426,10 @@ protected Map generate(Class cls, @Nullable Cla this.build(builder,false); - // base is passed, we don't return base properties + // we don't return base properties unless specified with @PluginProperty builder .forFields() - .withIgnoreCheck(fieldScope -> base != null && fieldScope.getDeclaringType().getTypeName().equals(base.getName())); + .withIgnoreCheck(fieldScope -> base != null && fieldScope.getAnnotation(PluginProperty.class) == null && fieldScope.getDeclaringType().getTypeName().equals(base.getName())); SchemaGeneratorConfig schemaGeneratorConfig = builder.build(); diff --git a/core/src/main/java/io/kestra/core/models/triggers/AbstractTrigger.java b/core/src/main/java/io/kestra/core/models/triggers/AbstractTrigger.java index 4d3e6c2434..caf232712f 100644 --- a/core/src/main/java/io/kestra/core/models/triggers/AbstractTrigger.java +++ b/core/src/main/java/io/kestra/core/models/triggers/AbstractTrigger.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import io.kestra.core.models.annotations.PluginProperty; import io.kestra.core.models.conditions.Condition; import io.kestra.core.models.tasks.WorkerGroup; import io.micronaut.core.annotation.Introspected; @@ -39,6 +40,7 @@ abstract public class AbstractTrigger { private String description; @Valid + @PluginProperty @Schema( title = "List of Conditions in order to limit the flow trigger." ) diff --git a/core/src/test/java/io/kestra/core/docs/JsonSchemaGeneratorTest.java b/core/src/test/java/io/kestra/core/docs/JsonSchemaGeneratorTest.java index 91598b4fab..2de360d3b2 100644 --- a/core/src/test/java/io/kestra/core/docs/JsonSchemaGeneratorTest.java +++ b/core/src/test/java/io/kestra/core/docs/JsonSchemaGeneratorTest.java @@ -22,6 +22,7 @@ import lombok.NoArgsConstructor; import lombok.ToString; import lombok.experimental.SuperBuilder; +import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import java.net.URISyntaxException; @@ -121,6 +122,13 @@ void trigger() throws URISyntaxException { var allOf = (List) task.get("allOf"); assertThat(allOf.size(), is(1)); + + Map jsonSchema = jsonSchemaGenerator.generate(AbstractTrigger.class, AbstractTrigger.class); + + assertThat((Map) jsonSchema.get("properties"), allOf( + Matchers.aMapWithSize(1), + hasKey("conditions") + )); }); } From 9dd10175ce4461331d65c4f1531edc987282aee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Wed, 26 Jul 2023 10:33:11 +0200 Subject: [PATCH 028/121] fix: remove deprecated --- .../main/java/io/kestra/jdbc/JooqExecuteListenerFactory.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/jdbc/src/main/java/io/kestra/jdbc/JooqExecuteListenerFactory.java b/jdbc/src/main/java/io/kestra/jdbc/JooqExecuteListenerFactory.java index e945557a0d..a8b12036d2 100644 --- a/jdbc/src/main/java/io/kestra/jdbc/JooqExecuteListenerFactory.java +++ b/jdbc/src/main/java/io/kestra/jdbc/JooqExecuteListenerFactory.java @@ -20,19 +20,16 @@ public org.jooq.ExecuteListenerProvider jooqConfiguration(MetricRegistry metricR return new org.jooq.ExecuteListenerProvider() { @Override public @NotNull ExecuteListener provide() { - return new DefaultExecuteListener() { + return new ExecuteListener() { Long startTime; @Override public void executeStart(ExecuteContext ctx) { - super.executeStart(ctx); startTime = System.currentTimeMillis(); } @Override public void executeEnd(ExecuteContext ctx) { - super.executeEnd(ctx); - Duration duration = Duration.ofMillis(System.currentTimeMillis() - startTime); metricRegistry.timer(MetricRegistry.JDBC_QUERY_DURATION, "sql", ctx.sql()) From 5327c7307e820a10d5ac7084a7688645c10cbf07 Mon Sep 17 00:00:00 2001 From: "brian.mulier" Date: Tue, 1 Aug 2023 09:52:38 +0200 Subject: [PATCH 029/121] fix(tests): longer timeout int MultipleConditionTriggerCaseTest --- .../kestra/core/runners/MultipleConditionTriggerCaseTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/test/java/io/kestra/core/runners/MultipleConditionTriggerCaseTest.java b/core/src/test/java/io/kestra/core/runners/MultipleConditionTriggerCaseTest.java index abf2f7c258..d11b82c9b6 100644 --- a/core/src/test/java/io/kestra/core/runners/MultipleConditionTriggerCaseTest.java +++ b/core/src/test/java/io/kestra/core/runners/MultipleConditionTriggerCaseTest.java @@ -115,7 +115,7 @@ public void failed() throws InterruptedException, TimeoutException { assertThat(execution.getState().getCurrent(), is(State.Type.FAILED)); // trigger was not done - countDownLatch.await(5, TimeUnit.SECONDS); + countDownLatch.await(10, TimeUnit.SECONDS); assertThat(ended.size(), is(2)); } } From 968f97d6920d0d7e16ab403abde64e5bc2042e52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Tue, 1 Aug 2023 09:31:01 +0200 Subject: [PATCH 030/121] fix(core): WorkingDirectory validation throws an exception when tasks is null or empty --- .../io/kestra/core/validations/ValidationFactory.java | 7 ++++++- .../java/io/kestra/core/models/flows/FlowTest.java | 11 +++++++++++ .../flows/invalids/workingdirectory-no-tasks.yaml | 6 ++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 core/src/test/resources/flows/invalids/workingdirectory-no-tasks.yaml diff --git a/core/src/main/java/io/kestra/core/validations/ValidationFactory.java b/core/src/main/java/io/kestra/core/validations/ValidationFactory.java index 813bf43d6d..33c2b9b99c 100644 --- a/core/src/main/java/io/kestra/core/validations/ValidationFactory.java +++ b/core/src/main/java/io/kestra/core/validations/ValidationFactory.java @@ -160,7 +160,12 @@ ConstraintValidator workingDir return true; } - if(value.getTasks().stream().anyMatch(task -> !(task instanceof RunnableTask))) { + if (value.getTasks() == null || value.getTasks().isEmpty()) { + context.messageTemplate("The 'tasks' property cannot be empty"); + return false; + } + + if (value.getTasks().stream().anyMatch(task -> !(task instanceof RunnableTask))) { context.messageTemplate("Only runnable tasks are allowed as children of a WorkingDirectory task"); return false; } diff --git a/core/src/test/java/io/kestra/core/models/flows/FlowTest.java b/core/src/test/java/io/kestra/core/models/flows/FlowTest.java index 26ba97877e..80802f1451 100644 --- a/core/src/test/java/io/kestra/core/models/flows/FlowTest.java +++ b/core/src/test/java/io/kestra/core/models/flows/FlowTest.java @@ -95,6 +95,17 @@ void workingDirectoryTaskInvalid() { assertThat(validate.get().getMessage(), containsString("tasks[0]: Only runnable tasks are allowed as children of a WorkingDirectory task")); } + @Test + void workingDirectoryNoTasks() { + Flow flow = this.parse("flows/invalids/workingdirectory-no-tasks.yaml"); + Optional validate = modelValidator.isValid(flow); + + assertThat(validate.isPresent(), is(true)); + assertThat(validate.get().getConstraintViolations().size(), is(2)); + + assertThat(validate.get().getMessage(), containsString("tasks[0]: The tasks property cannot be empty")); + } + @Test void updateTask() throws InternalException { Flow flow = this.parse("flows/valids/each-sequential-nested.yaml"); diff --git a/core/src/test/resources/flows/invalids/workingdirectory-no-tasks.yaml b/core/src/test/resources/flows/invalids/workingdirectory-no-tasks.yaml new file mode 100644 index 0000000000..e450b10c3c --- /dev/null +++ b/core/src/test/resources/flows/invalids/workingdirectory-no-tasks.yaml @@ -0,0 +1,6 @@ +id: workingdirectory-no-tasks +namespace: io.kestra.tests + +tasks: + - id: impossible + type: io.kestra.core.tasks.flows.WorkingDirectory \ No newline at end of file From e4678a5a9ede1d2b70c376f9026f6e4aedab204d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Tue, 1 Aug 2023 09:45:52 +0200 Subject: [PATCH 031/121] doc(core): WorkingDirectory - add an example with a cache --- .../core/tasks/flows/WorkingDirectory.java | 122 +++++++++++------- 1 file changed, 72 insertions(+), 50 deletions(-) diff --git a/core/src/main/java/io/kestra/core/tasks/flows/WorkingDirectory.java b/core/src/main/java/io/kestra/core/tasks/flows/WorkingDirectory.java index b534742894..5d7db714a5 100644 --- a/core/src/main/java/io/kestra/core/tasks/flows/WorkingDirectory.java +++ b/core/src/main/java/io/kestra/core/tasks/flows/WorkingDirectory.java @@ -88,56 +88,56 @@ full = true, title = "Add input and output files within a Working Directory to use them in a Python script", code = """ - id: apiJSONtoMongoDB - namespace: dev - - tasks: - - id: wdir - type: io.kestra.core.tasks.flows.WorkingDirectory - tasks: - - id: demoSQL - type: io.kestra.core.tasks.storages.LocalFiles - inputs: - query.sql: | - SELECT sum(total) as total, avg(quantity) as avg_quantity - FROM sales; - - - id: inlineScript - type: io.kestra.plugin.scripts.python.Script - runner: DOCKER - docker: - image: python:3.11-slim - beforeCommands: - - pip install requests kestra > /dev/null - warningOnStdErr: false - script: | - import requests - import json - from kestra import Kestra - - with open('query.sql', 'r') as input_file: - sql = input_file.read() - - response = requests.get('https://api.github.com') - data = response.json() - - with open('output.json', 'w') as output_file: - json.dump(data, output_file) - - Kestra.outputs({'receivedSQL': sql, 'status': response.status_code}) - - - id: jsonFiles - type: io.kestra.core.tasks.storages.LocalFiles - outputs: - - output.json - - - id: loadToMongoDB - type: io.kestra.plugin.mongodb.Load - connection: - uri: mongodb://host.docker.internal:27017/ - database: local - collection: github - from: "{{outputs.jsonFiles.uris['output.json']}}" + id: apiJSONtoMongoDB + namespace: dev + + tasks: + - id: wdir + type: io.kestra.core.tasks.flows.WorkingDirectory + tasks: + - id: demoSQL + type: io.kestra.core.tasks.storages.LocalFiles + inputs: + query.sql: | + SELECT sum(total) as total, avg(quantity) as avg_quantity + FROM sales; + + - id: inlineScript + type: io.kestra.plugin.scripts.python.Script + runner: DOCKER + docker: + image: python:3.11-slim + beforeCommands: + - pip install requests kestra > /dev/null + warningOnStdErr: false + script: | + import requests + import json + from kestra import Kestra + + with open('query.sql', 'r') as input_file: + sql = input_file.read() + + response = requests.get('https://api.github.com') + data = response.json() + + with open('output.json', 'w') as output_file: + json.dump(data, output_file) + + Kestra.outputs({'receivedSQL': sql, 'status': response.status_code}) + + - id: jsonFiles + type: io.kestra.core.tasks.storages.LocalFiles + outputs: + - output.json + + - id: loadToMongoDB + type: io.kestra.plugin.mongodb.Load + connection: + uri: mongodb://host.docker.internal:27017/ + database: local + collection: github + from: "{{outputs.jsonFiles.uris['output.json']}}" """ ), @Example( @@ -160,6 +160,28 @@ with open('output.json', 'w') as output_file: " - |", " echo '::{\"outputs\": {\"stay\":\"'$(cat {{ workingDir }}/stay.txt)'\"}}::'" } + ), + @Example( + full = true, + title = "A working directory with a cache of the node_modules directory", + code = """ + id: node-with-cache + namespace: dev + tasks: + - id: working-dir + type: io.kestra.core.tasks.flows.WorkingDirectory + cache: + patterns: + - node_modules/** + ttl: PT1H + tasks: + - id: script + type: io.kestra.plugin.scripts.node.Script + beforeCommands: + - npm install colors + script: | + const colors = require("colors"); + console.log(colors.red("Hello"));""" ) } ) From 89e3fc677efe4156bbb8674269c6ffa3af787b7d Mon Sep 17 00:00:00 2001 From: Ludovic DEHON Date: Wed, 2 Aug 2023 12:12:51 +0200 Subject: [PATCH 032/121] feat(webserver): exposed all usages and not only the execution one --- .../src/test/java/io/kestra/core/Helpers.java | 8 +++- .../webserver/controllers/MiscController.java | 10 ++--- .../controllers/MiscControllerTest.java | 9 ----- .../controllers/MiscUsageControllerTest.java | 37 +++++++++++++++++++ 4 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 webserver/src/test/java/io/kestra/webserver/controllers/MiscUsageControllerTest.java diff --git a/core/src/test/java/io/kestra/core/Helpers.java b/core/src/test/java/io/kestra/core/Helpers.java index b35aa8f976..2db92928b9 100644 --- a/core/src/test/java/io/kestra/core/Helpers.java +++ b/core/src/test/java/io/kestra/core/Helpers.java @@ -98,10 +98,10 @@ public static void runApplicationContext(BiConsumer consumer) throws URISyntaxException { + public static void runApplicationContext(String[] env, Map properties, BiConsumer consumer) throws URISyntaxException { try (ApplicationContext applicationContext = applicationContext( pluginsPath(), - null, + properties, env ).start()) { EmbeddedServer embeddedServer = applicationContext.getBean(EmbeddedServer.class); @@ -110,4 +110,8 @@ public static void runApplicationContext(String[] env, BiConsumer consumer) throws URISyntaxException { + runApplicationContext(env, null, consumer); + } } diff --git a/webserver/src/main/java/io/kestra/webserver/controllers/MiscController.java b/webserver/src/main/java/io/kestra/webserver/controllers/MiscController.java index f06a833e4d..5d1c789cfd 100644 --- a/webserver/src/main/java/io/kestra/webserver/controllers/MiscController.java +++ b/webserver/src/main/java/io/kestra/webserver/controllers/MiscController.java @@ -1,7 +1,7 @@ package io.kestra.webserver.controllers; import com.fasterxml.jackson.annotation.JsonInclude; -import io.kestra.core.models.collectors.ExecutionUsage; +import io.kestra.core.models.collectors.Usage; import io.kestra.core.repositories.ExecutionRepositoryInterface; import io.kestra.core.services.CollectorService; import io.kestra.core.services.InstanceService; @@ -18,8 +18,6 @@ import lombok.Value; import lombok.extern.slf4j.Slf4j; -import javax.validation.Valid; - @Slf4j @Controller public class MiscController { @@ -57,11 +55,11 @@ public Configuration configuration() { .build(); } - @Get("/api/v1/execution-usage") + @Get("/api/v1/usages") @ExecuteOn(TaskExecutors.IO) @Operation(tags = {"Misc"}, summary = "Get execution usage information") - public ExecutionUsage executionUsage() { - return ExecutionUsage.of(executionRepository); + public Usage usages() { + return collectorService.metrics(); } @Value diff --git a/webserver/src/test/java/io/kestra/webserver/controllers/MiscControllerTest.java b/webserver/src/test/java/io/kestra/webserver/controllers/MiscControllerTest.java index fdd410e00c..d9767c091c 100644 --- a/webserver/src/test/java/io/kestra/webserver/controllers/MiscControllerTest.java +++ b/webserver/src/test/java/io/kestra/webserver/controllers/MiscControllerTest.java @@ -1,6 +1,5 @@ package io.kestra.webserver.controllers; -import io.kestra.core.models.collectors.ExecutionUsage; import io.kestra.webserver.controllers.h2.JdbcH2ControllerTest; import io.micronaut.http.client.annotation.Client; import io.micronaut.rxjava2.http.client.RxHttpClient; @@ -32,12 +31,4 @@ void configuration() { assertThat(response.getIsTaskRunEnabled(), is(false)); assertThat(response.getIsAnonymousUsageEnabled(), is(true)); } - - @Test - void executionUsage() { - var response = client.toBlocking().retrieve("/api/v1/execution-usage", ExecutionUsage.class); - - assertThat(response, notNullValue()); - // the memory executor didn't support daily statistics so we cannot have real execution usage - } } \ No newline at end of file diff --git a/webserver/src/test/java/io/kestra/webserver/controllers/MiscUsageControllerTest.java b/webserver/src/test/java/io/kestra/webserver/controllers/MiscUsageControllerTest.java new file mode 100644 index 0000000000..b26ab7fc8f --- /dev/null +++ b/webserver/src/test/java/io/kestra/webserver/controllers/MiscUsageControllerTest.java @@ -0,0 +1,37 @@ +package io.kestra.webserver.controllers; + +import io.kestra.core.Helpers; +import io.kestra.core.models.collectors.Usage; +import io.micronaut.http.HttpRequest; +import io.micronaut.rxjava2.http.client.RxHttpClient; +import org.junit.jupiter.api.Test; + +import java.net.URISyntaxException; +import java.util.Map; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; + +class MiscUsageControllerTest { + @Test + void usages() throws URISyntaxException { + Helpers.runApplicationContext(new String[]{"test"}, Map.of("kestra.server-type", "STANDALONE"), (applicationContext, embeddedServer) -> { + try (RxHttpClient client = RxHttpClient.create(embeddedServer.getURL())) { + + var response = client.toBlocking().retrieve(HttpRequest.GET("/api/v1/usages"), Usage.class); + + assertThat(response.getUuid(), notNullValue()); + assertThat(response.getVersion(), notNullValue()); + assertThat(response.getStartTime(), notNullValue()); + assertThat(response.getEnvironments(), contains("test")); + assertThat(response.getStartTime(), notNullValue()); + assertThat(response.getHost().getUuid(), notNullValue()); + assertThat(response.getHost().getHardware().getLogicalProcessorCount(), notNullValue()); + assertThat(response.getHost().getJvm().getName(), notNullValue()); + assertThat(response.getHost().getOs().getFamily(), notNullValue()); + assertThat(response.getConfigurations().getRepositoryType(), is("h2")); + assertThat(response.getConfigurations().getQueueType(), is("h2")); + } + }); + } +} \ No newline at end of file From fdc568dffbdabfec3305ede9589ac8dc4c10b2db Mon Sep 17 00:00:00 2001 From: YannC <37600690+Skraye@users.noreply.github.com> Date: Wed, 2 Aug 2023 18:34:15 +0200 Subject: [PATCH 033/121] fix(deps): force bouncycastle version for crypto plugin compatibility (#1844) relate to kestra-io/plugin-crypto#30 --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index 0499855755..27e49f3a46 100644 --- a/build.gradle +++ b/build.gradle @@ -78,6 +78,10 @@ allprojects { // ugly bug for elastic plugins force("org.apache.httpcomponents:httpclient:4.5.13") + + // ugly bug on crypto plugin + force('org.bouncycastle:bcprov-jdk15on:1.70') + force('org.bouncycastle:bcpg-jdk15on:1.70') } } From 11c95867b16d0161a8d3b392d62401667d728252 Mon Sep 17 00:00:00 2001 From: "brian.mulier" Date: Tue, 1 Aug 2023 12:01:35 +0200 Subject: [PATCH 034/121] fix(ui): load config synchronously --- ui/src/App.vue | 31 ++++++++++++------------- ui/src/override/components/LeftMenu.vue | 9 +++---- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/ui/src/App.vue b/ui/src/App.vue index feec3b08b6..945ee23863 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -1,6 +1,6 @@ + @@ -67,18 +89,6 @@
    -
      - - - {{ $t('export') }} - - - {{ $t('delete') }} - - -
    - -
  • @@ -109,6 +119,8 @@ + + \ No newline at end of file diff --git a/ui/src/components/executions/ExecutionOutput.vue b/ui/src/components/executions/ExecutionOutput.vue index aa2f1a49a4..3571f973be 100644 --- a/ui/src/components/executions/ExecutionOutput.vue +++ b/ui/src/components/executions/ExecutionOutput.vue @@ -85,6 +85,12 @@ + + + +
    @@ -96,9 +102,11 @@ import Editor from "../../components/inputs/Editor.vue"; import Collapse from "../layout/Collapse.vue"; import Pagination from "../layout/Pagination.vue"; + import FilePreview from "./FilePreview.vue"; export default { components: { + FilePreview, Pagination, VarValue, Editor, @@ -113,7 +121,9 @@ debugStackTrace: "", isModalOpen: false, size: this.$route.query.size ? this.$route.query.size : 25, - page: this.$route.query.page ? this.$route.query.page : 1 + page: this.$route.query.page ? this.$route.query.page : 1, + isPreviewOpen: false, + selectedPreview: null }; }, created() { @@ -171,10 +181,10 @@ page: item.page } }); - }, + } }, computed: { - ...mapState("execution", ["execution"]), + ...mapState("execution", ["execution", "filePreview"]), selectOptions() { const options = {}; for (const taskRun of this.execution.taskRunList || []) { diff --git a/ui/src/components/executions/FilePreview.vue b/ui/src/components/executions/FilePreview.vue new file mode 100644 index 0000000000..9ac5d75e88 --- /dev/null +++ b/ui/src/components/executions/FilePreview.vue @@ -0,0 +1,87 @@ + + \ No newline at end of file diff --git a/ui/src/components/executions/VarValue.vue b/ui/src/components/executions/VarValue.vue index 4bc283155e..f3d50667e8 100644 --- a/ui/src/components/executions/VarValue.vue +++ b/ui/src/components/executions/VarValue.vue @@ -1,5 +1,5 @@ @@ -28,9 +34,12 @@ import VarValue from "./VarValue.vue"; import DateAgo from "../../components/layout/DateAgo.vue"; import SubFlowLink from "../flows/SubFlowLink.vue" + import FilePreview from "./FilePreview.vue"; + import {mapState} from "vuex"; export default { components: { + FilePreview, DateAgo, VarValue, SubFlowLink @@ -47,6 +56,7 @@ }, }, computed: { + ...mapState("execution", ["execution"]), variables() { return Utils.executionVars(this.data); }, diff --git a/ui/src/components/inputs/Editor.vue b/ui/src/components/inputs/Editor.vue index 3fcd8192f3..7cf274649b 100644 --- a/ui/src/components/inputs/Editor.vue +++ b/ui/src/components/inputs/Editor.vue @@ -80,7 +80,7 @@ readOnly: {type: Boolean, default: false}, lineNumbers: {type: Boolean, default: undefined}, minimap: {type: Boolean, default: false}, - creating: {type: Boolean, default: false}, + creating: {type: Boolean, default: false} }, components: { MonacoEditor, diff --git a/ui/src/stores/executions.js b/ui/src/stores/executions.js index a293f9b544..17bde51b39 100644 --- a/ui/src/stores/executions.js +++ b/ui/src/stores/executions.js @@ -12,6 +12,7 @@ export default { }, metrics: [], metricsTotal: 0, + filePreview: undefined }, actions: { loadExecutions({commit}, options) { @@ -143,6 +144,13 @@ export default { }).then(response => { return response.data }) + }, + filePreview({commit}, options) { + return this.$http.get(`api/v1/executions/${options.executionId}/file/preview`, { + params: options + }).then(response => { + commit("setFilePreview", response.data) + }) } }, mutations: { @@ -179,6 +187,9 @@ export default { }, setMetricsTotal(state, metrics) { state.metricsTotal = metrics + }, + setFilePreview(state, filePreview) { + state.filePreview = filePreview } }, getters: { diff --git a/ui/src/translations.json b/ui/src/translations.json index b69f2acead..b573cf9a11 100644 --- a/ui/src/translations.json +++ b/ui/src/translations.json @@ -462,6 +462,8 @@ "slack support": "Ask help on our Slack", "error detected": "Error detected", "cannot swap tasks": "Can't swap the tasks", + "preview": "Preview", + "open": "Open", "dependency task": "Task {taskId} is a dependency of another task", "administration": "Administration", "evaluation lock date": "Evaluation lock date", @@ -942,6 +944,8 @@ "slack support": "Demandez de l'aide sur notre Slack", "error detected": "Erreur détectée", "cannot swap tasks": "Impossible de permuter les tâches", + "preview": "Aperçu", + "open": "Afficher", "dependency task": "La tâche {taskId} est une dépendance d'une autre tâche", "administration": "Administration", "evaluation lock date": "Date verrou évaluation", diff --git a/webserver/src/main/java/io/kestra/webserver/controllers/ExecutionController.java b/webserver/src/main/java/io/kestra/webserver/controllers/ExecutionController.java index 9d9412c141..f41f76bd55 100644 --- a/webserver/src/main/java/io/kestra/webserver/controllers/ExecutionController.java +++ b/webserver/src/main/java/io/kestra/webserver/controllers/ExecutionController.java @@ -1,16 +1,42 @@ package io.kestra.webserver.controllers; +import io.kestra.core.events.CrudEvent; +import io.kestra.core.events.CrudEventType; +import io.kestra.core.exceptions.IllegalVariableEvaluationException; import io.kestra.core.exceptions.InternalException; import io.kestra.core.models.Label; +import io.kestra.core.models.executions.Execution; +import io.kestra.core.models.executions.ExecutionKilled; +import io.kestra.core.models.executions.TaskRun; +import io.kestra.core.models.flows.Flow; +import io.kestra.core.models.flows.State; +import io.kestra.core.models.hierarchies.FlowGraph; +import io.kestra.core.models.storage.FileMetas; import io.kestra.core.models.tasks.Task; +import io.kestra.core.models.triggers.AbstractTrigger; +import io.kestra.core.models.triggers.types.Webhook; import io.kestra.core.models.validations.ManualConstraintViolation; +import io.kestra.core.queues.QueueFactoryInterface; +import io.kestra.core.queues.QueueInterface; +import io.kestra.core.repositories.ExecutionRepositoryInterface; +import io.kestra.core.repositories.FlowRepositoryInterface; import io.kestra.core.runners.RunContext; import io.kestra.core.runners.RunContextFactory; +import io.kestra.core.runners.RunnerUtils; +import io.kestra.core.services.ConditionService; +import io.kestra.core.services.ExecutionService; +import io.kestra.core.storages.StorageInterface; +import io.kestra.core.utils.Await; import io.kestra.webserver.responses.BulkErrorResponse; import io.kestra.webserver.responses.BulkResponse; +import io.kestra.webserver.responses.PagedResults; +import io.kestra.webserver.utils.PageableUtils; import io.kestra.webserver.utils.RequestUtils; +import io.kestra.webserver.utils.filepreview.FileRender; +import io.kestra.webserver.utils.filepreview.FileRenderBuilder; import io.micronaut.context.annotation.Value; import io.micronaut.context.event.ApplicationEventPublisher; +import io.micronaut.core.annotation.Nullable; import io.micronaut.core.convert.format.Format; import io.micronaut.data.model.Pageable; import io.micronaut.http.*; @@ -31,40 +57,16 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import lombok.*; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; -import io.kestra.core.events.CrudEvent; -import io.kestra.core.events.CrudEventType; -import io.kestra.core.exceptions.IllegalVariableEvaluationException; -import io.kestra.core.models.executions.Execution; -import io.kestra.core.models.executions.ExecutionKilled; -import io.kestra.core.models.executions.TaskRun; -import io.kestra.core.models.storage.FileMetas; -import io.kestra.core.models.flows.Flow; -import io.kestra.core.models.flows.State; -import io.kestra.core.models.hierarchies.FlowGraph; -import io.kestra.core.models.triggers.AbstractTrigger; -import io.kestra.core.models.triggers.types.Webhook; -import io.kestra.core.queues.QueueFactoryInterface; -import io.kestra.core.queues.QueueInterface; -import io.kestra.core.repositories.ExecutionRepositoryInterface; -import io.kestra.core.repositories.FlowRepositoryInterface; -import io.kestra.core.runners.RunnerUtils; -import io.kestra.core.services.ConditionService; -import io.kestra.core.services.ExecutionService; -import io.kestra.core.storages.StorageInterface; -import io.kestra.core.utils.Await; -import io.kestra.webserver.responses.PagedResults; -import io.kestra.webserver.utils.PageableUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.reactivestreams.Publisher; -import io.micronaut.core.annotation.Nullable; -import jakarta.inject.Inject; -import jakarta.inject.Named; - import java.io.IOException; import java.io.InputStream; import java.net.URI; @@ -967,4 +969,23 @@ public Flowable> follow( } }); } + + @ExecuteOn(TaskExecutors.IO) + @Get(uri = "executions/{executionId}/file/preview", produces = MediaType.APPLICATION_JSON) + @Operation(tags = {"Executions"}, summary = "Get file preview for an execution") + public HttpResponse filePreview( + @Parameter(description = "The execution id") @PathVariable String executionId, + @Parameter(description = "The internal storage uri") @QueryValue URI path + ) throws IOException { + HttpResponse httpResponse = this.validateFile(executionId, path, "/api/v1/executions/{executionId}/file?path=" + path); + if (httpResponse != null) { + return httpResponse; + } + + String extension = FilenameUtils.getExtension(path.toString()); + InputStream fileStream = storageInterface.get(path); + + FileRender fileRender = FileRenderBuilder.of(extension, fileStream); + return HttpResponse.ok(fileRender); + } } diff --git a/webserver/src/main/java/io/kestra/webserver/utils/filepreview/DefaultFileRender.java b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/DefaultFileRender.java new file mode 100644 index 0000000000..fe961a1ff1 --- /dev/null +++ b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/DefaultFileRender.java @@ -0,0 +1,58 @@ +package io.kestra.webserver.utils.filepreview; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class DefaultFileRender extends FileRender { + public String content; + + DefaultFileRender(String extension, InputStream filestream) throws IOException { + super(extension); + renderContent(filestream); + + this.type = Type.TEXT; + } + + DefaultFileRender(String extension, InputStream filestream, Type type) throws IOException { + super(extension); + renderContent(filestream); + + this.type = type; + } + + private void renderContent(InputStream fileStream) throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader(fileStream)); + String line = reader.readLine(); + int lineCount = 0; + + StringBuilder contentBuilder = new StringBuilder(); + + while (line != null && lineCount < MAX_LINES) { + contentBuilder.append(line); + lineCount++; + if ((line = reader.readLine()) != null) { + contentBuilder.append("\n"); + } + } + + this.content = truncateStringSize(contentBuilder.toString()); + } + + private String truncateStringSize(String content) { + // Equivalent to 2MB + int maxSizeInBytes = 2097152; + byte[] inputBytes = content.getBytes(); + + if (inputBytes.length <= maxSizeInBytes) { + + return content; + } + byte[] truncatedBytes = new byte[maxSizeInBytes]; + System.arraycopy(inputBytes, 0, truncatedBytes, 0, maxSizeInBytes); + + return new String(truncatedBytes); + } + +} diff --git a/webserver/src/main/java/io/kestra/webserver/utils/filepreview/FileRender.java b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/FileRender.java new file mode 100644 index 0000000000..bd4d78384b --- /dev/null +++ b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/FileRender.java @@ -0,0 +1,22 @@ +package io.kestra.webserver.utils.filepreview; + +public abstract class FileRender { + protected static int MAX_LINES = 100; + + public String extension; + + public Type type; + + public Object content; + + FileRender(String extension) { + this.extension = extension; + } + + public enum Type { + TEXT, + LIST, + IMAGE, + MARKDOWN + } +} diff --git a/webserver/src/main/java/io/kestra/webserver/utils/filepreview/FileRenderBuilder.java b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/FileRenderBuilder.java new file mode 100644 index 0000000000..daf68aa357 --- /dev/null +++ b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/FileRenderBuilder.java @@ -0,0 +1,18 @@ +package io.kestra.webserver.utils.filepreview; + +import java.io.IOException; +import java.io.InputStream; + +public class FileRenderBuilder { + public static FileRender of(String extension, InputStream filestream) throws IOException { + if (ImageFileRender.ImageFileExtension.isImageFileExtension(extension)) { + return new ImageFileRender(extension, filestream); + } + + return switch (extension) { + case "ion" -> new IonFileRender(extension, filestream); + case "md" -> new DefaultFileRender(extension, filestream, FileRender.Type.MARKDOWN); + default -> new DefaultFileRender(extension, filestream); + }; + } +} diff --git a/webserver/src/main/java/io/kestra/webserver/utils/filepreview/ImageFileRender.java b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/ImageFileRender.java new file mode 100644 index 0000000000..16ad2cb0bd --- /dev/null +++ b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/ImageFileRender.java @@ -0,0 +1,41 @@ +package io.kestra.webserver.utils.filepreview; + +import lombok.Getter; +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Base64; + +public class ImageFileRender extends FileRender { + public String content; + + ImageFileRender(String extension, InputStream inputStream) throws IOException { + super(extension); + this.content = Base64.getEncoder().encodeToString(IOUtils.toByteArray(inputStream)); + this.type = Type.IMAGE; + } + + @Getter + public enum ImageFileExtension { + JPG("jpg"), + JPEG("jpeg"), + PNG("png"), + SVG("svg"), + GIF("gif"), + BMP("bmp"), + WEBP("webp"); + + private final String extension; + + ImageFileExtension(String extension) { + this.extension = extension; + } + + public static boolean isImageFileExtension(String extension) { + return Arrays.stream(ImageFileExtension.values()) + .anyMatch(r -> r.getExtension().equalsIgnoreCase(extension)); + } + } +} diff --git a/webserver/src/main/java/io/kestra/webserver/utils/filepreview/IonFileRender.java b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/IonFileRender.java new file mode 100644 index 0000000000..ff67b5e313 --- /dev/null +++ b/webserver/src/main/java/io/kestra/webserver/utils/filepreview/IonFileRender.java @@ -0,0 +1,42 @@ +package io.kestra.webserver.utils.filepreview; + +import io.kestra.core.serializers.FileSerde; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import static io.kestra.core.utils.Rethrow.throwConsumer; + +public class IonFileRender extends FileRender { + public List content; + + IonFileRender(String extension, InputStream filestream) throws IOException { + super(extension); + renderContent(filestream); + + this.type = Type.LIST; + } + + private void renderContent(InputStream filestream) throws IOException { + try (BufferedReader inputStream = new BufferedReader(new InputStreamReader(filestream))) { + AtomicLong lineCount = new AtomicLong(); + + List list = new ArrayList<>(); + FileSerde.reader(inputStream, throwConsumer(e -> { + if (lineCount.get() > MAX_LINES) { + return; + } + + list.add(e); + lineCount.incrementAndGet(); + })); + + this.content = list; + } + } +} From 3cb3f9d3b9041b9af74f4c1a9b61c666630ec43c Mon Sep 17 00:00:00 2001 From: yuri <1969yuri1969@gmail.com> Date: Fri, 18 Aug 2023 08:39:25 +0200 Subject: [PATCH 079/121] feat(core): add a configuration to display environments (#1875) Co-authored-by: Ludovic DEHON --- ui/src/components/layout/Environment.vue | 43 +++++++++++++++++++ ui/src/components/settings/Settings.vue | 42 +++++++++++++++++- ui/src/override/components/LeftMenu.vue | 5 ++- ui/src/stores/layout.js | 27 +++++++++++- ui/src/translations.json | 2 + .../webserver/controllers/MiscController.java | 34 +++++++++++++-- 6 files changed, 145 insertions(+), 8 deletions(-) create mode 100644 ui/src/components/layout/Environment.vue diff --git a/ui/src/components/layout/Environment.vue b/ui/src/components/layout/Environment.vue new file mode 100644 index 0000000000..25acca9d23 --- /dev/null +++ b/ui/src/components/layout/Environment.vue @@ -0,0 +1,43 @@ + + + + + \ No newline at end of file diff --git a/ui/src/components/settings/Settings.vue b/ui/src/components/settings/Settings.vue index f7f450a2e3..ef23b3247b 100644 --- a/ui/src/components/settings/Settings.vue +++ b/ui/src/components/settings/Settings.vue @@ -108,6 +108,23 @@ /> + + + + + + + + @@ -121,7 +138,7 @@ import NamespaceSelect from "../../components/namespace/NamespaceSelect.vue"; import LogLevelSelector from "../../components/logs/LogLevelSelector.vue"; import Utils from "../../utils/utils"; - import {mapGetters, mapState} from "vuex"; + import {mapGetters, mapState, useStore} from "vuex"; import permission from "../../models/permission"; import action from "../../models/action"; import {logDisplayTypes} from "../../utils/constants"; @@ -156,11 +173,14 @@ logDisplay: undefined, editorFontSize: undefined, editorFontFamily: undefined, - now: this.$moment() + now: this.$moment(), + envName: undefined, + envColor: undefined }; }, created() { const darkTheme = document.getElementsByTagName("html")[0].className.indexOf("dark") >= 0; + const store = useStore(); this.defaultNamespace = localStorage.getItem("defaultNamespace") || ""; this.defaultLogLevel = localStorage.getItem("defaultLogLevel") || "INFO"; @@ -174,6 +194,8 @@ this.logDisplay = localStorage.getItem("logDisplay") || logDisplayTypes.DEFAULT; this.editorFontSize = localStorage.getItem("editorFontSize") || 12; this.editorFontFamily = localStorage.getItem("editorFontFamily") || "'Source Code Pro', monospace"; + this.envName = store.getters["layout/envName"] || this.configs?.environment?.name; + this.envColor = store.getters["layout/envColor"] || this.configs?.environment?.color; }, methods: { onNamespaceSelect(value) { @@ -255,12 +277,28 @@ onFontFamily(value) { localStorage.setItem("editorFontFamily", value); this.editorFontFamily = value; + this.$toast().saved(); + }, + onEnvNameChange(value) { + if (value && value !== this.configs?.environment?.name) { + this.$store.commit("layout/setEnvName", value); + } + + this.$toast().saved(); + }, + onEnvColorChange(value) { + console.log(value, this.configs?.environment?.color) + if (value && value !== this.configs?.environment?.color) { + this.$store.commit("layout/setEnvColor", value); + } + this.$toast().saved(); } }, computed: { ...mapGetters("core", ["guidedProperties"]), ...mapState("auth", ["user"]), + ...mapGetters("misc", ["configs"]), routeInfo() { return { title: this.$t("settings") diff --git a/ui/src/override/components/LeftMenu.vue b/ui/src/override/components/LeftMenu.vue index f98fb6c5d5..f1711ed831 100644 --- a/ui/src/override/components/LeftMenu.vue +++ b/ui/src/override/components/LeftMenu.vue @@ -14,6 +14,7 @@ + @@ -114,10 +135,14 @@ &.only-icon { > .icon { - margin: 0; - margin-top: 2px; height: 100%; - vertical-align: center; + position: relative; + + :deep(svg) { + position: absolute; + padding: 2px; + top: 0 + } } } } diff --git a/ui/src/components/settings/Settings.vue b/ui/src/components/settings/Settings.vue index ef23b3247b..46b388c6be 100644 --- a/ui/src/components/settings/Settings.vue +++ b/ui/src/components/settings/Settings.vue @@ -287,7 +287,6 @@ this.$toast().saved(); }, onEnvColorChange(value) { - console.log(value, this.configs?.environment?.color) if (value && value !== this.configs?.environment?.color) { this.$store.commit("layout/setEnvColor", value); } diff --git a/ui/src/override/components/flows/blueprints/BlueprintsBrowser.vue b/ui/src/override/components/flows/blueprints/BlueprintsBrowser.vue index 4169d8f5ef..5bc79a3d55 100644 --- a/ui/src/override/components/flows/blueprints/BlueprintsBrowser.vue +++ b/ui/src/override/components/flows/blueprints/BlueprintsBrowser.vue @@ -342,10 +342,6 @@ padding: 0.2rem; border-radius: $border-radius; - html.dark & { - background-color: var(--bs-white); - } - & * { margin-top: 0; } From 06f23fbee3b038daaf745d3b1f0e43a10e2d66a5 Mon Sep 17 00:00:00 2001 From: Ludovic DEHON Date: Thu, 24 Aug 2023 09:46:23 +0200 Subject: [PATCH 092/121] fix(ui): display null key on inputs overview --- ui/src/components/executions/Overview.vue | 8 ++------ ui/src/components/executions/Vars.vue | 2 +- ui/src/utils/utils.js | 6 +++++- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/src/components/executions/Overview.vue b/ui/src/components/executions/Overview.vue index 65bd92bebf..8ea1dd007d 100644 --- a/ui/src/components/executions/Overview.vue +++ b/ui/src/components/executions/Overview.vue @@ -73,6 +73,7 @@ import Crud from "override/components/auth/Crud.vue"; import Duration from "../layout/Duration.vue"; import Labels from "../layout/Labels.vue" + import {toRaw} from "vue"; export default { components: { @@ -162,12 +163,7 @@ return ret; }, inputs() { - const inputs = {}; - for (const key in this.execution.inputs) { - inputs[key] = this.execution.inputs[key]; - } - - return inputs; + return toRaw(this.execution.inputs); } }, }; diff --git a/ui/src/components/executions/Vars.vue b/ui/src/components/executions/Vars.vue index cb62321ec8..2b8217aa3c 100644 --- a/ui/src/components/executions/Vars.vue +++ b/ui/src/components/executions/Vars.vue @@ -23,7 +23,7 @@ diff --git a/ui/src/utils/utils.js b/ui/src/utils/utils.js index bcae98933a..9fae611ee3 100644 --- a/ui/src/utils/utils.js +++ b/ui/src/utils/utils.js @@ -33,9 +33,13 @@ export default class Utils { static flatten(object) { return Object.assign({}, ...function _flatten(child, path = []) { + if (child === null) { + return {[path.join(".")]: null}; + } + return [] .concat(...Object - .keys(child) + .keys(child === null ? [] : child) .map(key => typeof child[key] === "object" ? _flatten(child[key], path.concat([key])) : ({[path.concat([key]).join(".")]: child[key]}) From 04e7618fc99a10d81f1b2a5197357444fd179b58 Mon Sep 17 00:00:00 2001 From: Ludovic DEHON Date: Thu, 24 Aug 2023 11:58:29 +0200 Subject: [PATCH 093/121] feat(ui): better display of file preview close #1919 --- ui/src/components/executions/FilePreview.vue | 12 +++++++--- ui/src/components/executions/VarValue.vue | 24 +++++++++++++------- ui/src/components/executions/Vars.vue | 8 ------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/ui/src/components/executions/FilePreview.vue b/ui/src/components/executions/FilePreview.vue index 9ac5d75e88..8ed2a48e39 100644 --- a/ui/src/components/executions/FilePreview.vue +++ b/ui/src/components/executions/FilePreview.vue @@ -1,5 +1,7 @@ + + + - + @@ -59,7 +59,7 @@ {{ $t("source") }} Date: Tue, 29 Aug 2023 15:30:14 +0200 Subject: [PATCH 115/121] feat(docker): introduce Malloy plugin (#1987) --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3833eec7da..833151861a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -139,7 +139,7 @@ jobs: plugins: "" packages: "" - name: "-full" - plugins: io.kestra.storage:storage-azure:LATEST io.kestra.storage:storage-gcs:LATEST io.kestra.storage:storage-minio:LATEST io.kestra.plugin:plugin-airbyte:LATEST io.kestra.plugin:plugin-amqp:LATEST io.kestra.plugin:plugin-aws:LATEST io.kestra.plugin:plugin-azure:LATEST io.kestra.plugin:plugin-powerbi:LATEST io.kestra.plugin:plugin-pulsar:LATEST io.kestra.plugin:plugin-cassandra:LATEST io.kestra.plugin:plugin-compress:LATEST io.kestra.plugin:plugin-couchbase:LATEST io.kestra.plugin:plugin-crypto:LATEST io.kestra.plugin:plugin-databricks:LATEST io.kestra.plugin:plugin-dbt:LATEST io.kestra.plugin:plugin-debezium-mysql:LATEST io.kestra.plugin:plugin-debezium-postgres:LATEST io.kestra.plugin:plugin-debezium-sqlserver:LATEST io.kestra.plugin:plugin-elasticsearch:LATEST io.kestra.plugin:plugin-fivetran:LATEST io.kestra.plugin:plugin-fs:LATEST io.kestra.plugin:plugin-gcp:LATEST io.kestra.plugin:plugin-git:LATEST io.kestra.plugin:plugin-googleworkspace:LATEST io.kestra.plugin:plugin-hightouch:LATEST io.kestra.plugin:plugin-jdbc-clickhouse:LATEST io.kestra.plugin:plugin-jdbc-duckdb:LATEST io.kestra.plugin:plugin-jdbc-mysql:LATEST io.kestra.plugin:plugin-nats:LATEST io.kestra.plugin:plugin-jdbc-oracle:LATEST io.kestra.plugin:plugin-jdbc-pinot:LATEST io.kestra.plugin:plugin-jdbc-postgres:LATEST io.kestra.plugin:plugin-jdbc-redshift:LATEST io.kestra.plugin:plugin-jdbc-rockset:LATEST io.kestra.plugin:plugin-jdbc-snowflake:LATEST io.kestra.plugin:plugin-jdbc-sqlserver:LATEST io.kestra.plugin:plugin-jdbc-trino:LATEST io.kestra.plugin:plugin-jdbc-vertica:LATEST io.kestra.plugin:plugin-jdbc-vectorwise:LATEST io.kestra.plugin:plugin-kafka:LATEST io.kestra.plugin:plugin-kubernetes:LATEST io.kestra.plugin:plugin-mongodb:LATEST io.kestra.plugin:plugin-mqtt:LATEST io.kestra.plugin:plugin-neo4j:LATEST io.kestra.plugin:plugin-notifications:LATEST io.kestra.plugin:plugin-openai:LATEST io.kestra.plugin:plugin-redis:LATEST io.kestra.plugin:plugin-script-groovy:LATEST io.kestra.plugin:plugin-script-jython:LATEST io.kestra.plugin:plugin-script-nashorn:LATEST io.kestra.plugin:plugin-script-julia:LATEST io.kestra.plugin:plugin-script-node:LATEST io.kestra.plugin:plugin-script-powershell:LATEST io.kestra.plugin:plugin-script-python:LATEST io.kestra.plugin:plugin-script-r:LATEST io.kestra.plugin:plugin-script-shell:LATEST io.kestra.plugin:plugin-serdes:LATEST io.kestra.plugin:plugin-servicenow:LATEST io.kestra.plugin:plugin-singer:LATEST io.kestra.plugin:plugin-soda:LATEST io.kestra.plugin:plugin-spark:LATEST io.kestra.plugin:plugin-tika:LATEST + plugins: io.kestra.storage:storage-azure:LATEST io.kestra.storage:storage-gcs:LATEST io.kestra.storage:storage-minio:LATEST io.kestra.plugin:plugin-airbyte:LATEST io.kestra.plugin:plugin-amqp:LATEST io.kestra.plugin:plugin-aws:LATEST io.kestra.plugin:plugin-azure:LATEST io.kestra.plugin:plugin-powerbi:LATEST io.kestra.plugin:plugin-pulsar:LATEST io.kestra.plugin:plugin-cassandra:LATEST io.kestra.plugin:plugin-compress:LATEST io.kestra.plugin:plugin-couchbase:LATEST io.kestra.plugin:plugin-crypto:LATEST io.kestra.plugin:plugin-databricks:LATEST io.kestra.plugin:plugin-dbt:LATEST io.kestra.plugin:plugin-debezium-mysql:LATEST io.kestra.plugin:plugin-debezium-postgres:LATEST io.kestra.plugin:plugin-debezium-sqlserver:LATEST io.kestra.plugin:plugin-elasticsearch:LATEST io.kestra.plugin:plugin-fivetran:LATEST io.kestra.plugin:plugin-fs:LATEST io.kestra.plugin:plugin-gcp:LATEST io.kestra.plugin:plugin-git:LATEST io.kestra.plugin:plugin-googleworkspace:LATEST io.kestra.plugin:plugin-hightouch:LATEST io.kestra.plugin:plugin-jdbc-clickhouse:LATEST io.kestra.plugin:plugin-jdbc-duckdb:LATEST io.kestra.plugin:plugin-jdbc-mysql:LATEST io.kestra.plugin:plugin-nats:LATEST io.kestra.plugin:plugin-jdbc-oracle:LATEST io.kestra.plugin:plugin-jdbc-pinot:LATEST io.kestra.plugin:plugin-jdbc-postgres:LATEST io.kestra.plugin:plugin-jdbc-redshift:LATEST io.kestra.plugin:plugin-jdbc-rockset:LATEST io.kestra.plugin:plugin-jdbc-snowflake:LATEST io.kestra.plugin:plugin-jdbc-sqlserver:LATEST io.kestra.plugin:plugin-jdbc-trino:LATEST io.kestra.plugin:plugin-jdbc-vertica:LATEST io.kestra.plugin:plugin-jdbc-vectorwise:LATEST io.kestra.plugin:plugin-kafka:LATEST io.kestra.plugin:plugin-kubernetes:LATEST io.kestra.plugin:plugin-mongodb:LATEST io.kestra.plugin:plugin-mqtt:LATEST io.kestra.plugin:plugin-neo4j:LATEST io.kestra.plugin:plugin-notifications:LATEST io.kestra.plugin:plugin-openai:LATEST io.kestra.plugin:plugin-redis:LATEST io.kestra.plugin:plugin-script-groovy:LATEST io.kestra.plugin:plugin-script-jython:LATEST io.kestra.plugin:plugin-script-nashorn:LATEST io.kestra.plugin:plugin-script-julia:LATEST io.kestra.plugin:plugin-script-node:LATEST io.kestra.plugin:plugin-script-powershell:LATEST io.kestra.plugin:plugin-script-python:LATEST io.kestra.plugin:plugin-script-r:LATEST io.kestra.plugin:plugin-script-shell:LATEST io.kestra.plugin:plugin-serdes:LATEST io.kestra.plugin:plugin-servicenow:LATEST io.kestra.plugin:plugin-singer:LATEST io.kestra.plugin:plugin-soda:LATEST io.kestra.plugin:plugin-spark:LATEST io.kestra.plugin:plugin-tika:LATEST io.kestra.plugin:plugin-malloy:LATEST packages: python3 python3-venv python-is-python3 nodejs npm curl zip unzip steps: - uses: actions/checkout@v3 From cd4b0938f33e8dbd47d8b4055537475b680feabf Mon Sep 17 00:00:00 2001 From: Ludovic DEHON Date: Tue, 29 Aug 2023 19:14:23 +0200 Subject: [PATCH 116/121] feat(ui): update to latest ui-libs --- ui/package-lock.json | 8 ++++---- ui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui/package-lock.json b/ui/package-lock.json index 871e91e787..6e40fd97b9 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -8,7 +8,7 @@ "name": "kestra", "version": "0.1.0", "dependencies": { - "@kestra-io/ui-libs": "^0.0.12", + "@kestra-io/ui-libs": "^0.0.13", "@popperjs/core": "npm:@sxzz/popperjs-es@2.11.7", "@vue-flow/background": "^1.2.0", "@vue-flow/controls": "1.0.6", @@ -655,9 +655,9 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@kestra-io/ui-libs": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/@kestra-io/ui-libs/-/ui-libs-0.0.12.tgz", - "integrity": "sha512-P7mUVHuNJsvc3oyniHhN4dyIjbjOo8Mdf1CZWZcTRqTJvh5IPOMbVwDQu8vjqX1FJ3MkQj8fyjR85nWd0tSAJg==", + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/@kestra-io/ui-libs/-/ui-libs-0.0.13.tgz", + "integrity": "sha512-mk6UZB884slKkvFtegMLmVTumWPw9jinEGmYTmBalWN89SnykroY55vqy703rG/sYzW/mqvAxfNK7rvU3QSA+A==", "peerDependencies": { "@vue-flow/background": "^1.2.0", "@vue-flow/controls": "1.0.6", diff --git a/ui/package.json b/ui/package.json index 192712f153..fdcf2add50 100644 --- a/ui/package.json +++ b/ui/package.json @@ -10,7 +10,7 @@ "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path ../.gitignore" }, "dependencies": { - "@kestra-io/ui-libs": "^0.0.12", + "@kestra-io/ui-libs": "^0.0.13", "@popperjs/core": "npm:@sxzz/popperjs-es@2.11.7", "@vue-flow/background": "^1.2.0", "@vue-flow/controls": "1.0.6", From ff6409b05749299d90048563041435e30c1c7b35 Mon Sep 17 00:00:00 2001 From: Ludovic DEHON Date: Tue, 29 Aug 2023 22:19:17 +0200 Subject: [PATCH 117/121] feat(cicd): analyse with sonar cloud --- .github/workflows/sonar.yml | 45 +++++++++++++++++++++++++++++++++++++ build.gradle | 12 ++++++++++ 2 files changed, 57 insertions(+) create mode 100644 .github/workflows/sonar.yml diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml new file mode 100644 index 0000000000..feff199d12 --- /dev/null +++ b/.github/workflows/sonar.yml @@ -0,0 +1,45 @@ +name: SonarCloud +on: + push: + branches: + - develop + pull_request: + types: [opened, synchronize, reopened] + +jobs: + build: + name: Build and analyze + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: 17 + + - name: Cache SonarCloud packages + uses: actions/cache@v3 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + - name: Cache Gradle packages + uses: actions/cache@v3 + with: + path: | + ~/.gradle/caches + ~/.gradle/wrapper + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle*.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Build and analyze + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: ./gradlew build jacoco sonar --info \ No newline at end of file diff --git a/build.gradle b/build.gradle index dc92eec9f6..f1842a6396 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,7 @@ plugins { // test id 'com.adarshr.test-logger' version '3.2.0' + id "org.sonarqube" version "4.2.1.3168" // helper id "com.github.ben-manes.versions" version "0.47.0" @@ -332,6 +333,17 @@ task jacoco(type: JacocoReport) { } } +/**********************************************************************************************************************\ + * Sonar + **********************************************************************************************************************/ +sonar { + properties { + property "sonar.projectKey", "kestra-io_kestra" + property "sonar.organization", "kestra-io" + property "sonar.host.url", "https://sonarcloud.io" + } +} + /**********************************************************************************************************************\ * Standalone **********************************************************************************************************************/ From 181a40cde9d6d18d7e0c663fe8df175a9edf9be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Wed, 30 Aug 2023 08:35:51 +0200 Subject: [PATCH 118/121] chore(core): remove unneeded memory runner dependency (#1979) --- jdbc-h2/build.gradle | 1 - jdbc-mysql/build.gradle | 1 - jdbc-postgres/build.gradle | 1 - jdbc/build.gradle | 1 - 4 files changed, 4 deletions(-) diff --git a/jdbc-h2/build.gradle b/jdbc-h2/build.gradle index f55d919189..053a562bff 100644 --- a/jdbc-h2/build.gradle +++ b/jdbc-h2/build.gradle @@ -9,7 +9,6 @@ dependencies { testImplementation project(':core').sourceSets.test.output testImplementation project(':jdbc').sourceSets.test.output - testImplementation project(':runner-memory') testImplementation project(':storage-local') testImplementation 'org.mockito:mockito-junit-jupiter:5.4.0' } diff --git a/jdbc-mysql/build.gradle b/jdbc-mysql/build.gradle index 3c0ea03c45..6ea55c45d9 100644 --- a/jdbc-mysql/build.gradle +++ b/jdbc-mysql/build.gradle @@ -10,7 +10,6 @@ dependencies { testImplementation project(':core').sourceSets.test.output testImplementation project(':jdbc').sourceSets.test.output - testImplementation project(':runner-memory') testImplementation project(':storage-local') testImplementation 'org.mockito:mockito-junit-jupiter:5.4.0' } diff --git a/jdbc-postgres/build.gradle b/jdbc-postgres/build.gradle index 7810949483..5d1385c546 100644 --- a/jdbc-postgres/build.gradle +++ b/jdbc-postgres/build.gradle @@ -9,7 +9,6 @@ dependencies { testImplementation project(':core').sourceSets.test.output testImplementation project(':jdbc').sourceSets.test.output - testImplementation project(':runner-memory') testImplementation project(':storage-local') testImplementation 'org.mockito:mockito-junit-jupiter:5.4.0' } diff --git a/jdbc/build.gradle b/jdbc/build.gradle index bb571c0d6f..1986e9b87a 100644 --- a/jdbc/build.gradle +++ b/jdbc/build.gradle @@ -7,5 +7,4 @@ dependencies { implementation("io.micronaut.flyway:micronaut-flyway") testImplementation project(':core').sourceSets.test.output - testImplementation project(':runner-memory') } From 35ce94776ab17217a612ce5164fded284075515b Mon Sep 17 00:00:00 2001 From: Ludovic DEHON Date: Wed, 30 Aug 2023 08:49:19 +0200 Subject: [PATCH 119/121] fix(ui): invalid tooltip date on state chart --- ui/src/components/stats/StateChart.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/components/stats/StateChart.vue b/ui/src/components/stats/StateChart.vue index e6ff2d7325..986fd5049c 100644 --- a/ui/src/components/stats/StateChart.vue +++ b/ui/src/components/stats/StateChart.vue @@ -142,7 +142,7 @@ }, Object.create(null)) return { - labels: props.data.map(r => moment(r.date).format(getFormat(r.groupBy))), + labels: props.data.map(r => moment(r.startDate).format(getFormat(r.groupBy))), datasets: props.big || props.global || props.duration ? [{ type: "line", From f81c160fe9b04200ebab43505cf805c18d0157da Mon Sep 17 00:00:00 2001 From: Ludovic DEHON Date: Wed, 30 Aug 2023 11:49:22 +0200 Subject: [PATCH 120/121] fix(ui): move icon to ui-libs --- .../flows/blueprints/BlueprintDetail.vue | 4 +- ui/src/components/graph/TreeNode.vue | 177 --------- ui/src/components/graph/TreeTaskNode.vue | 354 ------------------ ui/src/components/graph/TreeTriggerNode.vue | 145 ------- ui/src/components/logs/LogList.vue | 2 +- ui/src/components/plugins/PluginSelect.vue | 19 +- ui/src/components/plugins/TaskIcon.vue | 147 -------- ui/src/components/plugins/Toc.vue | 2 +- .../flows/blueprints/Blueprints.vue | 2 - .../flows/blueprints/BlueprintsBrowser.vue | 15 +- ui/src/styles/app.scss | 4 - ui/src/styles/components/vue-flow.scss | 28 -- .../unit/components/graph/TreeNode.spec.js | 58 --- 13 files changed, 13 insertions(+), 944 deletions(-) delete mode 100644 ui/src/components/graph/TreeNode.vue delete mode 100644 ui/src/components/graph/TreeTaskNode.vue delete mode 100644 ui/src/components/graph/TreeTriggerNode.vue delete mode 100644 ui/src/components/plugins/TaskIcon.vue delete mode 100644 ui/src/styles/components/vue-flow.scss delete mode 100644 ui/tests/unit/components/graph/TreeNode.spec.js diff --git a/ui/src/components/flows/blueprints/BlueprintDetail.vue b/ui/src/components/flows/blueprints/BlueprintDetail.vue index ca30bb00af..2ea6c95c29 100644 --- a/ui/src/components/flows/blueprints/BlueprintDetail.vue +++ b/ui/src/components/flows/blueprints/BlueprintDetail.vue @@ -83,7 +83,7 @@ import ArrowLeft from "vue-material-design-icons/ArrowLeft.vue"; import Editor from "../../inputs/Editor.vue"; import LowCodeEditor from "../../inputs/LowCodeEditor.vue"; - import TaskIcon from "../../plugins/TaskIcon.vue"; + import TaskIcon from "@kestra-io/ui-libs/src/components/misc/TaskIcon.vue"; import HomeOutline from "vue-material-design-icons/HomeOutline.vue"; import Utils from "../../../utils/utils"; @@ -254,7 +254,7 @@ :deep(.wrapper) { .icon { - height: 70%; + height: 100%; margin: 0; } diff --git a/ui/src/components/graph/TreeNode.vue b/ui/src/components/graph/TreeNode.vue deleted file mode 100644 index e392108746..0000000000 --- a/ui/src/components/graph/TreeNode.vue +++ /dev/null @@ -1,177 +0,0 @@ - - - - -- \ No newline at end of file diff --git a/ui/src/components/graph/TreeTaskNode.vue b/ui/src/components/graph/TreeTaskNode.vue deleted file mode 100644 index 49092d9727..0000000000 --- a/ui/src/components/graph/TreeTaskNode.vue +++ /dev/null @@ -1,354 +0,0 @@ - - - - - - diff --git a/ui/src/components/graph/TreeTriggerNode.vue b/ui/src/components/graph/TreeTriggerNode.vue deleted file mode 100644 index 01360f60bd..0000000000 --- a/ui/src/components/graph/TreeTriggerNode.vue +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - - diff --git a/ui/src/components/logs/LogList.vue b/ui/src/components/logs/LogList.vue index 7e94b473c4..6beac1d819 100644 --- a/ui/src/components/logs/LogList.vue +++ b/ui/src/components/logs/LogList.vue @@ -174,7 +174,7 @@ import SubFlowLink from "../flows/SubFlowLink.vue" import TaskEdit from "../flows/TaskEdit.vue"; import Duration from "../layout/Duration.vue"; - import TaskIcon from "../plugins/TaskIcon.vue"; + import TaskIcon from "@kestra-io/ui-libs/src/components/misc/TaskIcon.vue"; import _xor from "lodash/xor"; import FlowUtils from "../../utils/flowUtils.js"; import moment from "moment"; diff --git a/ui/src/components/plugins/PluginSelect.vue b/ui/src/components/plugins/PluginSelect.vue index 676447f811..63bece807e 100644 --- a/ui/src/components/plugins/PluginSelect.vue +++ b/ui/src/components/plugins/PluginSelect.vue @@ -28,8 +28,7 @@ diff --git a/ui/src/components/plugins/Toc.vue b/ui/src/components/plugins/Toc.vue index 24d19348b2..9f4826f6f4 100644 --- a/ui/src/components/plugins/Toc.vue +++ b/ui/src/components/plugins/Toc.vue @@ -40,7 +40,7 @@