mirror of
https://github.com/kestra-io/kestra.git
synced 2025-12-26 05:00:31 -05:00
Compare commits
20 Commits
dependabot
...
v0.15.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
103320e348 | ||
|
|
410093cefc | ||
|
|
bd936125bd | ||
|
|
68ded87434 | ||
|
|
d76807235f | ||
|
|
63708a79e3 | ||
|
|
41c0018d4b | ||
|
|
2cbd86c4d1 | ||
|
|
49b64fa853 | ||
|
|
95113c5e76 | ||
|
|
1e5e300974 | ||
|
|
f69dc3c835 | ||
|
|
651c7bf589 | ||
|
|
7878bcc281 | ||
|
|
ee059106b2 | ||
|
|
4d2728a3f6 | ||
|
|
87f7cde742 | ||
|
|
2e18c87907 | ||
|
|
58352411b5 | ||
|
|
438619dd8c |
@@ -1,5 +1,6 @@
|
|||||||
package io.kestra.core.models.flows;
|
package io.kestra.core.models.flows;
|
||||||
|
|
||||||
|
import io.kestra.core.validations.TaskDefaultValidation;
|
||||||
import io.micronaut.core.annotation.Introspected;
|
import io.micronaut.core.annotation.Introspected;
|
||||||
import io.micronaut.core.convert.format.MapFormat;
|
import io.micronaut.core.convert.format.MapFormat;
|
||||||
import io.micronaut.core.naming.conventions.StringConvention;
|
import io.micronaut.core.naming.conventions.StringConvention;
|
||||||
@@ -13,6 +14,7 @@ import java.util.Map;
|
|||||||
@Builder(toBuilder = true)
|
@Builder(toBuilder = true)
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Introspected
|
@Introspected
|
||||||
|
@TaskDefaultValidation
|
||||||
public class TaskDefault {
|
public class TaskDefault {
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
|
|||||||
@@ -254,12 +254,12 @@ public class Schedule extends AbstractTrigger implements PollingTriggerInterface
|
|||||||
// is after the end, then we calculate again the nextDate
|
// is after the end, then we calculate again the nextDate
|
||||||
// based on now()
|
// based on now()
|
||||||
if (backfill != null && nextDate != null && nextDate.isAfter(backfill.getEnd())) {
|
if (backfill != null && nextDate != null && nextDate.isAfter(backfill.getEnd())) {
|
||||||
nextDate = computeNextEvaluationDate(executionTime, ZonedDateTime.now()).orElse(null);
|
nextDate = computeNextEvaluationDate(executionTime, convertDateTime(ZonedDateTime.now())).orElse(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// no previous present & no backfill or recover missed schedules, just provide now
|
// no previous present & no backfill or recover missed schedules, just provide now
|
||||||
else {
|
else {
|
||||||
nextDate = computeNextEvaluationDate(executionTime, ZonedDateTime.now()).orElse(null);
|
nextDate = computeNextEvaluationDate(executionTime, convertDateTime(ZonedDateTime.now())).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if max delay reached, we calculate a new date except if we are doing a backfill
|
// if max delay reached, we calculate a new date except if we are doing a backfill
|
||||||
@@ -280,7 +280,7 @@ public class Schedule extends AbstractTrigger implements PollingTriggerInterface
|
|||||||
public ZonedDateTime nextEvaluationDate() {
|
public ZonedDateTime nextEvaluationDate() {
|
||||||
// it didn't take into account the schedule condition, but as they are taken into account inside eval() it's OK.
|
// it didn't take into account the schedule condition, but as they are taken into account inside eval() it's OK.
|
||||||
ExecutionTime executionTime = this.executionTime();
|
ExecutionTime executionTime = this.executionTime();
|
||||||
return computeNextEvaluationDate(executionTime, ZonedDateTime.now()).orElse(ZonedDateTime.now());
|
return computeNextEvaluationDate(executionTime, convertDateTime(ZonedDateTime.now())).orElse(convertDateTime(ZonedDateTime.now()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ZonedDateTime previousEvaluationDate(ConditionContext conditionContext) {
|
public ZonedDateTime previousEvaluationDate(ConditionContext conditionContext) {
|
||||||
@@ -301,7 +301,7 @@ public class Schedule extends AbstractTrigger implements PollingTriggerInterface
|
|||||||
conditionContext.getRunContext().logger().warn("Unable to evaluate the conditions for the next evaluation date for trigger '{}', conditions will not be evaluated", this.getId());
|
conditionContext.getRunContext().logger().warn("Unable to evaluate the conditions for the next evaluation date for trigger '{}', conditions will not be evaluated", this.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return computePreviousEvaluationDate(executionTime, ZonedDateTime.now()).orElse(ZonedDateTime.now());
|
return computePreviousEvaluationDate(executionTime, convertDateTime(ZonedDateTime.now())).orElse(convertDateTime(ZonedDateTime.now()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -28,10 +28,9 @@ public class VariableRenderer {
|
|||||||
private static final Pattern RAW_PATTERN = Pattern.compile("\\{%[-]*\\s*raw\\s*[-]*%\\}(.*?)\\{%[-]*\\s*endraw\\s*[-]*%\\}");
|
private static final Pattern RAW_PATTERN = Pattern.compile("\\{%[-]*\\s*raw\\s*[-]*%\\}(.*?)\\{%[-]*\\s*endraw\\s*[-]*%\\}");
|
||||||
public static final int MAX_RENDERING_AMOUNT = 100;
|
public static final int MAX_RENDERING_AMOUNT = 100;
|
||||||
|
|
||||||
private PebbleEngine pebbleEngine;
|
private final PebbleEngine pebbleEngine;
|
||||||
private final VariableConfiguration variableConfiguration;
|
private final VariableConfiguration variableConfiguration;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Inject
|
@Inject
|
||||||
public VariableRenderer(ApplicationContext applicationContext, @Nullable VariableConfiguration variableConfiguration) {
|
public VariableRenderer(ApplicationContext applicationContext, @Nullable VariableConfiguration variableConfiguration) {
|
||||||
this.variableConfiguration = variableConfiguration != null ? variableConfiguration : new VariableConfiguration();
|
this.variableConfiguration = variableConfiguration != null ? variableConfiguration : new VariableConfiguration();
|
||||||
@@ -102,17 +101,10 @@ public class VariableRenderer {
|
|||||||
Writer writer = new JsonWriter(new StringWriter());
|
Writer writer = new JsonWriter(new StringWriter());
|
||||||
compiledTemplate.evaluate(writer, variables);
|
compiledTemplate.evaluate(writer, variables);
|
||||||
result = writer.toString();
|
result = writer.toString();
|
||||||
} catch (IOException | PebbleException e) {
|
} catch (IOException e) {
|
||||||
String alternativeRender = this.alternativeRender(e, inline, variables);
|
throw new IllegalVariableEvaluationException(e);
|
||||||
if (alternativeRender == null) {
|
} catch (PebbleException e) {
|
||||||
if (e instanceof PebbleException) {
|
throw properPebbleException(e);
|
||||||
throw properPebbleException((PebbleException) e);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalVariableEvaluationException(e);
|
|
||||||
} else {
|
|
||||||
result = alternativeRender;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// post-process raw tags
|
// post-process raw tags
|
||||||
@@ -123,10 +115,6 @@ public class VariableRenderer {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String alternativeRender(Exception e, String inline, Map<String, Object> variables) throws IllegalVariableEvaluationException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String renderRecursively(String inline, Map<String, Object> variables) throws IllegalVariableEvaluationException {
|
public String renderRecursively(String inline, Map<String, Object> variables) throws IllegalVariableEvaluationException {
|
||||||
return this.renderRecursively(0, inline, variables);
|
return this.renderRecursively(0, inline, variables);
|
||||||
}
|
}
|
||||||
@@ -180,7 +168,8 @@ public class VariableRenderer {
|
|||||||
return Optional.of(this.render(string, variables, recursive));
|
return Optional.of(this.render(string, variables, recursive));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional.empty();
|
// Return the given object if it cannot be rendered.
|
||||||
|
return Optional.ofNullable(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Object> renderList(List<Object> list, Map<String, Object> variables) throws IllegalVariableEvaluationException {
|
public List<Object> renderList(List<Object> list, Map<String, Object> variables) throws IllegalVariableEvaluationException {
|
||||||
|
|||||||
@@ -39,10 +39,9 @@ public class RenderFunction implements Function {
|
|||||||
recursiveArg = true;
|
recursiveArg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(recursiveArg instanceof Boolean)) {
|
if (!(recursiveArg instanceof Boolean recursive)) {
|
||||||
throw new PebbleException(null, "The 'render' function expects an optional argument 'recursive' with type boolean.", lineNumber, self.getName());
|
throw new PebbleException(null, "The 'render' function expects an optional argument 'recursive' with type boolean.", lineNumber, self.getName());
|
||||||
}
|
}
|
||||||
Boolean recursive = (Boolean) recursiveArg;
|
|
||||||
|
|
||||||
EvaluationContextImpl evaluationContext = (EvaluationContextImpl) context;
|
EvaluationContextImpl evaluationContext = (EvaluationContextImpl) context;
|
||||||
Map<String, Object> variables = evaluationContext.getScopeChain().getGlobalScopes().stream()
|
Map<String, Object> variables = evaluationContext.getScopeChain().getGlobalScopes().stream()
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package io.kestra.core.validations;
|
||||||
|
|
||||||
|
import jakarta.validation.Constraint;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Constraint(validatedBy = {})
|
||||||
|
public @interface TaskDefaultValidation {
|
||||||
|
String message() default "invalid taskDefault";
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package io.kestra.core.validations.validator;
|
||||||
|
|
||||||
|
import io.kestra.core.models.flows.TaskDefault;
|
||||||
|
import io.kestra.core.models.validations.ModelValidator;
|
||||||
|
import io.kestra.core.serializers.YamlFlowParser;
|
||||||
|
import io.kestra.core.services.TaskDefaultService;
|
||||||
|
import io.micronaut.core.annotation.AnnotationValue;
|
||||||
|
import io.micronaut.core.annotation.Introspected;
|
||||||
|
import io.micronaut.core.annotation.NonNull;
|
||||||
|
import io.micronaut.core.annotation.Nullable;
|
||||||
|
import io.micronaut.validation.validator.constraints.ConstraintValidator;
|
||||||
|
import io.micronaut.validation.validator.constraints.ConstraintValidatorContext;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.inject.Singleton;
|
||||||
|
import io.kestra.core.validations.TaskDefaultValidation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Introspected
|
||||||
|
public class TaskDefaultValidator implements ConstraintValidator<TaskDefaultValidation, TaskDefault> {
|
||||||
|
@Inject
|
||||||
|
private ModelValidator modelValidator;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private TaskDefaultService taskDefaultService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private YamlFlowParser yamlFlowParser;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(@Nullable TaskDefault value, @NonNull AnnotationValue<TaskDefaultValidation> annotationMetadata, @NonNull ConstraintValidatorContext context) {
|
||||||
|
if (value == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> violations = new ArrayList<>();
|
||||||
|
|
||||||
|
if (value.getValues() == null) {
|
||||||
|
violations.add("Null values map found");
|
||||||
|
context.messageTemplate("Invalid Task Default: " + String.join(", ", violations));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the "values" map is empty
|
||||||
|
for (Map.Entry<String, Object> entry : value.getValues().entrySet()) {
|
||||||
|
if (entry.getValue() == null) {
|
||||||
|
violations.add("Null value found in values with key " + entry.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!violations.isEmpty()) {
|
||||||
|
context.messageTemplate("Invalid Task Default: " + String.join(", ", violations));
|
||||||
|
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package io.kestra.core.runners.pebble.functions;
|
||||||
|
|
||||||
|
import io.kestra.core.exceptions.IllegalVariableEvaluationException;
|
||||||
|
import io.kestra.core.runners.VariableRenderer;
|
||||||
|
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@MicronautTest
|
||||||
|
class RenderFunctionTest {
|
||||||
|
@Inject
|
||||||
|
VariableRenderer variableRenderer;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRenderForString() throws IllegalVariableEvaluationException {
|
||||||
|
String rendered = variableRenderer.render("{{ render(input) }}", Map.of("input", "test"));
|
||||||
|
Assertions.assertEquals("test", rendered);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRenderForInteger() throws IllegalVariableEvaluationException {
|
||||||
|
String rendered = variableRenderer.render("{{ render(input) }}", Map.of("input", 42));
|
||||||
|
Assertions.assertEquals("42", rendered);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRenderForLong() throws IllegalVariableEvaluationException {
|
||||||
|
String rendered = variableRenderer.render("{{ render(input) }}", Map.of("input", 42L));
|
||||||
|
Assertions.assertEquals("42", rendered);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRenderForBoolean() throws IllegalVariableEvaluationException {
|
||||||
|
String rendered = variableRenderer.render("{{ render(input) }}", Map.of("input", true));
|
||||||
|
Assertions.assertEquals("true", rendered);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRenderForNull() throws IllegalVariableEvaluationException {
|
||||||
|
String rendered = variableRenderer.render("{{ render(input) }}", new HashMap<>(){{put("input", null);}});
|
||||||
|
Assertions.assertEquals("", rendered);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRenderForDateTime() throws IllegalVariableEvaluationException {
|
||||||
|
Instant now = Instant.now();
|
||||||
|
LocalDateTime datetime = LocalDateTime.ofInstant(now, ZoneOffset.UTC);
|
||||||
|
String rendered = variableRenderer.render("{{ render(input) }}", Map.of("input", datetime));
|
||||||
|
Assertions.assertEquals(datetime.toString(), rendered);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRenderForDuration() throws IllegalVariableEvaluationException {
|
||||||
|
String rendered = variableRenderer.render("{{ render(input) }}", Map.of("input", Duration.ofSeconds(5)));
|
||||||
|
Assertions.assertEquals(Duration.ofSeconds(5).toString(), rendered);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package io.kestra.core.validations;
|
||||||
|
|
||||||
|
import io.kestra.core.models.flows.Flow;
|
||||||
|
import io.kestra.core.models.flows.TaskDefault;
|
||||||
|
import io.kestra.core.models.validations.ModelValidator;
|
||||||
|
import io.kestra.core.serializers.YamlFlowParser;
|
||||||
|
import io.kestra.core.utils.TestsUtils;
|
||||||
|
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.validation.ConstraintViolationException;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
|
||||||
|
@MicronautTest
|
||||||
|
class TaskDefaultValidationTest {
|
||||||
|
@Inject
|
||||||
|
private ModelValidator modelValidator;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void nullValue() {
|
||||||
|
TaskDefault taskDefault = TaskDefault.builder()
|
||||||
|
.type("io.kestra.tests")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Optional<ConstraintViolationException> validate = modelValidator.isValid(taskDefault);
|
||||||
|
|
||||||
|
assertThat(validate.isPresent(), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
version=0.15.0
|
version=0.15.4
|
||||||
|
|
||||||
jacksonVersion=2.16.1
|
jacksonVersion=2.16.1
|
||||||
micronautVersion=4.3.4
|
micronautVersion=4.3.4
|
||||||
|
|||||||
8
ui/package-lock.json
generated
8
ui/package-lock.json
generated
@@ -8,7 +8,7 @@
|
|||||||
"name": "kestra",
|
"name": "kestra",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kestra-io/ui-libs": "^0.0.36",
|
"@kestra-io/ui-libs": "^0.0.37",
|
||||||
"@popperjs/core": "npm:@sxzz/popperjs-es@2.11.7",
|
"@popperjs/core": "npm:@sxzz/popperjs-es@2.11.7",
|
||||||
"@vue-flow/background": "^1.2.0",
|
"@vue-flow/background": "^1.2.0",
|
||||||
"@vue-flow/controls": "1.0.6",
|
"@vue-flow/controls": "1.0.6",
|
||||||
@@ -299,9 +299,9 @@
|
|||||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||||
},
|
},
|
||||||
"node_modules/@kestra-io/ui-libs": {
|
"node_modules/@kestra-io/ui-libs": {
|
||||||
"version": "0.0.36",
|
"version": "0.0.37",
|
||||||
"resolved": "https://registry.npmjs.org/@kestra-io/ui-libs/-/ui-libs-0.0.36.tgz",
|
"resolved": "https://registry.npmjs.org/@kestra-io/ui-libs/-/ui-libs-0.0.37.tgz",
|
||||||
"integrity": "sha512-yJJa0+tVlcWVllMVHoFQVrWzR7nIyF/+6aN8u+OPnMaHR0zSUx9MwaxF6u/YYPoBw6J4zq4ysn3pspq/DGB4ag==",
|
"integrity": "sha512-86l7zSjXkjyjc1pKTH3sYj4NemWdgq718yUiif8zye8XaI1np/gAeHtovyS+VF57Sx5rd3exKzMnN7HDwFgb0A==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@vue-flow/background": "^1.2.0",
|
"@vue-flow/background": "^1.2.0",
|
||||||
"@vue-flow/controls": "1.0.6",
|
"@vue-flow/controls": "1.0.6",
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix"
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@kestra-io/ui-libs": "^0.0.36",
|
"@kestra-io/ui-libs": "^0.0.37",
|
||||||
"@popperjs/core": "npm:@sxzz/popperjs-es@2.11.7",
|
"@popperjs/core": "npm:@sxzz/popperjs-es@2.11.7",
|
||||||
"@vue-flow/background": "^1.2.0",
|
"@vue-flow/background": "^1.2.0",
|
||||||
"@vue-flow/controls": "1.0.6",
|
"@vue-flow/controls": "1.0.6",
|
||||||
|
|||||||
61
ui/src/components/Drawer.vue
Normal file
61
ui/src/components/Drawer.vue
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
:model-value="props.modelValue"
|
||||||
|
@update:model-value="emit('update:modelValue', $event)"
|
||||||
|
destroy-on-close
|
||||||
|
lock-scroll
|
||||||
|
size=""
|
||||||
|
:append-to-body="true"
|
||||||
|
:class="{'full-screen': fullScreen}"
|
||||||
|
ref="editorDomElement"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<span>
|
||||||
|
{{ title }}
|
||||||
|
<slot name="header" />
|
||||||
|
</span>
|
||||||
|
<el-button link class="full-screen">
|
||||||
|
<Fullscreen :title="$t('toggle fullscreen')" @click="toggleFullScreen" />
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<slot name="footer" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #default>
|
||||||
|
<slot />
|
||||||
|
</template>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref} from "vue";
|
||||||
|
import Fullscreen from "vue-material-design-icons/Fullscreen.vue"
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:modelValue"])
|
||||||
|
|
||||||
|
const fullScreen = ref(false);
|
||||||
|
|
||||||
|
const toggleFullScreen = () => {
|
||||||
|
fullScreen.value = !fullScreen.value;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
button.full-screen {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -99,7 +99,7 @@
|
|||||||
title: this.title || "Error",
|
title: this.title || "Error",
|
||||||
message: h("div", children),
|
message: h("div", children),
|
||||||
position: "bottom-right",
|
position: "bottom-right",
|
||||||
type: "error",
|
type: this.message.variant,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
dangerouslyUseHTMLString: true,
|
dangerouslyUseHTMLString: true,
|
||||||
customClass: "error-notification" + (children.length > 1 ? " large" : "")
|
customClass: "error-notification" + (children.length > 1 ? " large" : "")
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-tabs class="router-link" :class="{top: top}" v-model="activeName">
|
<el-tabs class="router-link" :class="{top: top}" v-model="activeName">
|
||||||
<el-tab-pane
|
<el-tab-pane
|
||||||
v-for="tab in tabs"
|
v-for="tab in tabs.filter(t => !t.hidden)"
|
||||||
:key="tab.name"
|
:key="tab.name"
|
||||||
:label="tab.title"
|
:label="tab.title"
|
||||||
:name="tab.name || 'default'"
|
:name="tab.name || 'default'"
|
||||||
|
|||||||
@@ -120,6 +120,7 @@
|
|||||||
<el-table-column column-key="disable" class-name="row-action">
|
<el-table-column column-key="disable" class-name="row-action">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-switch
|
<el-switch
|
||||||
|
v-if="!scope.row.missingSource"
|
||||||
size="small"
|
size="small"
|
||||||
:active-text="$t('enabled')"
|
:active-text="$t('enabled')"
|
||||||
:model-value="!scope.row.disabled"
|
:model-value="!scope.row.disabled"
|
||||||
@@ -127,6 +128,9 @@
|
|||||||
class="switch-text"
|
class="switch-text"
|
||||||
:active-action-icon="Check"
|
:active-action-icon="Check"
|
||||||
/>
|
/>
|
||||||
|
<el-tooltip v-else :content="'flow source not found'">
|
||||||
|
<AlertCircle class="trigger-issue-icon" />
|
||||||
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -154,6 +158,7 @@
|
|||||||
import action from "../../models/action";
|
import action from "../../models/action";
|
||||||
import TopNavBar from "../layout/TopNavBar.vue";
|
import TopNavBar from "../layout/TopNavBar.vue";
|
||||||
import Check from "vue-material-design-icons/Check.vue";
|
import Check from "vue-material-design-icons/Check.vue";
|
||||||
|
import AlertCircle from "vue-material-design-icons/AlertCircle.vue";
|
||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
import NamespaceSelect from "../namespace/NamespaceSelect.vue";
|
import NamespaceSelect from "../namespace/NamespaceSelect.vue";
|
||||||
@@ -251,9 +256,21 @@
|
|||||||
},
|
},
|
||||||
triggersMerged() {
|
triggersMerged() {
|
||||||
return this.triggers.map(triggers => {
|
return this.triggers.map(triggers => {
|
||||||
return {...triggers.abstractTrigger, ...triggers.triggerContext, codeDisabled: triggers.abstractTrigger.disabled}
|
return {
|
||||||
|
...triggers?.abstractTrigger,
|
||||||
|
...triggers.triggerContext,
|
||||||
|
codeDisabled: triggers?.abstractTrigger?.disabled,
|
||||||
|
// if we have no abstract trigger, it means that flow or trigger definition hasn't been found
|
||||||
|
missingSource: !triggers.abstractTrigger
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
.trigger-issue-icon{
|
||||||
|
color: var(--bs-warning);
|
||||||
|
font-size: 1.4em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -28,13 +28,9 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</collapse>
|
</collapse>
|
||||||
|
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isModalOpen"
|
v-if="isModalOpen"
|
||||||
v-model="isModalOpen"
|
v-model="isModalOpen"
|
||||||
destroy-on-close
|
|
||||||
lock-scroll
|
|
||||||
:append-to-body="true"
|
|
||||||
size=""
|
|
||||||
:title="$t('eval.title')"
|
:title="$t('eval.title')"
|
||||||
>
|
>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@@ -52,7 +48,7 @@
|
|||||||
<p><strong>{{ debugError }}</strong></p>
|
<p><strong>{{ debugError }}</strong></p>
|
||||||
<pre class="mb-0">{{ debugStackTrace }}</pre>
|
<pre class="mb-0">{{ debugStackTrace }}</pre>
|
||||||
</el-alert>
|
</el-alert>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
|
|
||||||
<el-table
|
<el-table
|
||||||
:data="outputsPaginated"
|
:data="outputsPaginated"
|
||||||
@@ -99,6 +95,7 @@
|
|||||||
import Pagination from "../layout/Pagination.vue";
|
import Pagination from "../layout/Pagination.vue";
|
||||||
import {apiUrl} from "override/utils/route";
|
import {apiUrl} from "override/utils/route";
|
||||||
import SubFlowLink from "../flows/SubFlowLink.vue";
|
import SubFlowLink from "../flows/SubFlowLink.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -107,6 +104,7 @@
|
|||||||
VarValue,
|
VarValue,
|
||||||
Editor,
|
Editor,
|
||||||
Collapse,
|
Collapse,
|
||||||
|
Drawer
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
follow() {
|
follow() {
|
||||||
|
this.$store.dispatch("execution/loadExecution", this.$route.params)
|
||||||
const self = this;
|
const self = this;
|
||||||
this.closeSSE();
|
this.closeSSE();
|
||||||
this.previousExecutionId = this.$route.params.id;
|
this.previousExecutionId = this.$route.params.id;
|
||||||
|
|||||||
@@ -2,16 +2,12 @@
|
|||||||
<el-button size="small" type="primary" :icon="EyeOutline" @click="getFilePreview">
|
<el-button size="small" type="primary" :icon="EyeOutline" @click="getFilePreview">
|
||||||
Preview
|
Preview
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="selectedPreview === value && filePreview"
|
v-if="selectedPreview === value && filePreview"
|
||||||
v-model="isPreviewOpen"
|
v-model="isPreviewOpen"
|
||||||
destroy-on-close
|
|
||||||
lock-scroll
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<h3>{{ $t("preview") }}</h3>
|
{{ $t("preview") }}
|
||||||
</template>
|
</template>
|
||||||
<template #default>
|
<template #default>
|
||||||
<el-alert v-if="filePreview.truncated" show-icon type="warning" :closable="false" class="mb-2">
|
<el-alert v-if="filePreview.truncated" show-icon type="warning" :closable="false" class="mb-2">
|
||||||
@@ -58,7 +54,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -70,9 +66,10 @@
|
|||||||
import ListPreview from "../ListPreview.vue";
|
import ListPreview from "../ListPreview.vue";
|
||||||
import {mapGetters, mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
import Markdown from "../layout/Markdown.vue";
|
import Markdown from "../layout/Markdown.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {Markdown, ListPreview, Editor},
|
components: {Markdown, ListPreview, Editor, Drawer},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@@ -6,17 +6,13 @@
|
|||||||
{{ $t('metrics') }}
|
{{ $t('metrics') }}
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
v-model="isOpen"
|
v-model="isOpen"
|
||||||
:title="$t('metrics')"
|
:title="$t('metrics')"
|
||||||
destroy-on-close
|
|
||||||
:append-to-body="true"
|
|
||||||
size=""
|
|
||||||
direction="ltr"
|
|
||||||
>
|
>
|
||||||
<metrics-table ref="table" :task-run-id="taskRun.id" :execution="execution" />
|
<metrics-table ref="table" :task-run-id="taskRun.id" :execution="execution" />
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -26,10 +22,12 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import MetricsTable from "./MetricsTable.vue";
|
import MetricsTable from "./MetricsTable.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
MetricsTable
|
MetricsTable,
|
||||||
|
Drawer
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -7,21 +7,17 @@
|
|||||||
{{ $t('outputs') }}
|
{{ $t('outputs') }}
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
|
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
v-model="isOpen"
|
v-model="isOpen"
|
||||||
:title="$t('outputs')"
|
:title="$t('outputs')"
|
||||||
destroy-on-close
|
|
||||||
:append-to-body="true"
|
|
||||||
size=""
|
|
||||||
direction="ltr"
|
|
||||||
>
|
>
|
||||||
<vars
|
<vars
|
||||||
:execution="execution"
|
:execution="execution"
|
||||||
class="table-unrounded mt-1"
|
class="table-unrounded mt-1"
|
||||||
:data="outputs"
|
:data="outputs"
|
||||||
/>
|
/>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -30,10 +26,12 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vars from "../executions/Vars.vue";
|
import Vars from "../executions/Vars.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Vars,
|
Vars,
|
||||||
|
Drawer,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
outputs: {
|
outputs: {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
<div v-if="execution.trigger" class="mt-4">
|
<div v-if="execution.trigger" class="mt-4">
|
||||||
<h5>{{ $t("trigger") }}</h5>
|
<h5>{{ $t("trigger") }}</h5>
|
||||||
<vars :execution="execution" :data="execution.trigger" />
|
<vars :execution="execution" :data="triggerVariables" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="execution.inputs" class="mt-4">
|
<div v-if="execution.inputs" class="mt-4">
|
||||||
@@ -183,6 +183,14 @@
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
return inputs;
|
return inputs;
|
||||||
|
},
|
||||||
|
// This is used to display correctly trigger variables
|
||||||
|
triggerVariables() {
|
||||||
|
let trigger = this.execution.trigger
|
||||||
|
trigger["trigger"] = this.execution.trigger.variables
|
||||||
|
delete trigger["variables"]
|
||||||
|
|
||||||
|
return trigger
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
<p v-html="$t(replayOrRestart + ' confirm', {id: execution.id})" />
|
<p v-html="$t(replayOrRestart + ' confirm', {id: execution.id})" />
|
||||||
|
|
||||||
<el-form>
|
<el-form v-if="revisionsOptions && revisionsOptions.length > 1">
|
||||||
<p class="text-muted">
|
<p class="text-muted">
|
||||||
{{ $t("restart change revision") }}
|
{{ $t("restart change revision") }}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-table stripe table-layout="auto" fixed :data="variables">
|
<el-table stripe table-layout="auto" fixed :data="variables">
|
||||||
<el-table-column prop="key" rowspan="3" :label="$t('name')">
|
<el-table-column prop="key" min-width="500" :label="$t('name')">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<code>{{ scope.row.key }}</code>
|
<code class="key-col">{{ scope.row.key }}</code>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
@@ -50,3 +50,8 @@
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
.key-col {
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -40,6 +40,10 @@
|
|||||||
value: "P1D",
|
value: "P1D",
|
||||||
label: "datepicker.last24hours"
|
label: "datepicker.last24hours"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: "P2D",
|
||||||
|
label: "datepicker.last48hours"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: "P7D",
|
value: "P7D",
|
||||||
label: "datepicker.last7days"
|
label: "datepicker.last7days"
|
||||||
|
|||||||
@@ -20,14 +20,17 @@
|
|||||||
const store = useStore();
|
const store = useStore();
|
||||||
const axios = inject("axios")
|
const axios = inject("axios")
|
||||||
const router = getCurrentInstance().appContext.config.globalProperties.$router;
|
const router = getCurrentInstance().appContext.config.globalProperties.$router;
|
||||||
|
const t = getCurrentInstance().appContext.config.globalProperties.$t;
|
||||||
|
|
||||||
const loaded = ref([]);
|
const loaded = ref([]);
|
||||||
const dependencies = ref({
|
const dependencies = ref({
|
||||||
nodes: [],
|
nodes: [],
|
||||||
edges: []
|
edges: []
|
||||||
});
|
});
|
||||||
|
const expanded = ref([]);
|
||||||
|
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
|
const initialLoad = ref(true);
|
||||||
|
|
||||||
const load = (options) => {
|
const load = (options) => {
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
@@ -41,8 +44,21 @@
|
|||||||
dependencies.value.edges.push(...response.data.edges)
|
dependencies.value.edges.push(...response.data.edges)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!initialLoad.value) {
|
||||||
|
let newNodes = new Set(response.data.nodes.map(n => n.uid))
|
||||||
|
let oldNodes = new Set(getNodes.value.map(n => n.id))
|
||||||
|
console.log(response.data.nodes)
|
||||||
|
console.log(getNodes.value)
|
||||||
|
store.dispatch("core/showMessage", {
|
||||||
|
variant: "success",
|
||||||
|
title: t("dependencies loaded"),
|
||||||
|
message: t("loaded x dependencies", [...newNodes].filter(node => !oldNodes.has(node)).length),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
removeEdges(getEdges.value)
|
removeEdges(getEdges.value)
|
||||||
removeNodes(getNodes.value)
|
removeNodes(getNodes.value)
|
||||||
|
initialLoad.value = false
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
generateGraph();
|
generateGraph();
|
||||||
@@ -59,6 +75,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const expand = (data) => {
|
const expand = (data) => {
|
||||||
|
expanded.value.push(data.node.uid)
|
||||||
load({namespace: data.namespace, id: data.flowId})
|
load({namespace: data.namespace, id: data.flowId})
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,7 +127,8 @@
|
|||||||
flowId: node.id,
|
flowId: node.id,
|
||||||
current: node.namespace === route.params.namespace && node.id === route.params.id,
|
current: node.namespace === route.params.namespace && node.id === route.params.id,
|
||||||
color: "pink",
|
color: "pink",
|
||||||
link: true
|
link: true,
|
||||||
|
expandEnabled: !expanded.value.includes(node.uid)
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<router-link v-if="flow" :to="{name: 'flows/create', query: {copy: true}}">
|
<router-link v-if="flow && canCreate" :to="{name: 'flows/create', query: {copy: true}}">
|
||||||
<el-button :icon="icon.ContentCopy" size="large">
|
<el-button :icon="icon.ContentCopy" size="large">
|
||||||
{{ $t('copy') }}
|
{{ $t('copy') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|||||||
@@ -74,13 +74,13 @@
|
|||||||
:show-doc="false"
|
:show-doc="false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<el-drawer v-if="isModalOpen" v-model="isModalOpen" destroy-on-close :append-to-body="true" size="">
|
<drawer v-if="isModalOpen" v-model="isModalOpen">
|
||||||
<template #header>
|
<template #header>
|
||||||
<h5>{{ $t("revision") + `: ` + revision }}</h5>
|
<h5>{{ $t("revision") + `: ` + revision }}</h5>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<editor v-model="revisionYaml" lang="yaml" />
|
<editor v-model="revisionYaml" lang="yaml" />
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<el-alert class="mb-0" show-icon :closable="false">
|
<el-alert class="mb-0" show-icon :closable="false">
|
||||||
@@ -99,10 +99,11 @@
|
|||||||
import YamlUtils from "../../utils/yamlUtils";
|
import YamlUtils from "../../utils/yamlUtils";
|
||||||
import Editor from "../../components/inputs/Editor.vue";
|
import Editor from "../../components/inputs/Editor.vue";
|
||||||
import Crud from "override/components/auth/Crud.vue";
|
import Crud from "override/components/auth/Crud.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
import {saveFlowTemplate} from "../../utils/flowTemplate";
|
import {saveFlowTemplate} from "../../utils/flowTemplate";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {Editor, Crud},
|
components: {Editor, Crud, Drawer},
|
||||||
created() {
|
created() {
|
||||||
this.load();
|
this.load();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -158,13 +158,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
v-model="isOpen"
|
v-model="isOpen"
|
||||||
destroy-on-close
|
|
||||||
lock-scroll
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>{{ triggerId }}</code>
|
<code>{{ triggerId }}</code>
|
||||||
@@ -172,7 +168,7 @@
|
|||||||
|
|
||||||
<markdown v-if="triggerDefinition && triggerDefinition.description" :source="triggerDefinition.description" />
|
<markdown v-if="triggerDefinition && triggerDefinition.description" :source="triggerDefinition.description" />
|
||||||
<vars :data="modalData" />
|
<vars :data="modalData" />
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -193,12 +189,13 @@
|
|||||||
import Kicon from "../Kicon.vue"
|
import Kicon from "../Kicon.vue"
|
||||||
import DateAgo from "../layout/DateAgo.vue";
|
import DateAgo from "../layout/DateAgo.vue";
|
||||||
import Vars from "../executions/Vars.vue";
|
import Vars from "../executions/Vars.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
import permission from "../../models/permission";
|
import permission from "../../models/permission";
|
||||||
import action from "../../models/action";
|
import action from "../../models/action";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {Markdown, Kicon, DateAgo, Vars},
|
components: {Markdown, Kicon, DateAgo, Vars, Drawer},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
triggerId: undefined,
|
triggerId: undefined,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<router-link :to="{name: 'flows/create'}">
|
<router-link :to="{name: 'flows/create'}" v-if="canCreate">
|
||||||
<el-button :icon="Plus" type="primary">
|
<el-button :icon="Plus" type="primary">
|
||||||
{{ $t('create') }}
|
{{ $t('create') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -290,6 +290,9 @@
|
|||||||
canCheck() {
|
canCheck() {
|
||||||
return this.canRead || this.canDelete || this.canUpdate;
|
return this.canRead || this.canDelete || this.canUpdate;
|
||||||
},
|
},
|
||||||
|
canCreate() {
|
||||||
|
return this.user && this.user.isAllowed(permission.FLOW, action.CREATE, this.$route.query.namespace);
|
||||||
|
},
|
||||||
canRead() {
|
canRead() {
|
||||||
return this.user && this.user.isAllowed(permission.FLOW, action.READ, this.$route.query.namespace);
|
return this.user && this.user.isAllowed(permission.FLOW, action.READ, this.$route.query.namespace);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-100 d-flex flex-column align-items-center">
|
<div class="w-100 d-flex flex-column align-items-center">
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isEditOpen"
|
v-if="isEditOpen"
|
||||||
v-model="isEditOpen"
|
v-model="isEditOpen"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>inputs</code>
|
<code>inputs</code>
|
||||||
@@ -40,7 +37,7 @@
|
|||||||
:definitions="inputSchema.schema.definitions"
|
:definitions="inputSchema.schema.definitions"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
<div class="w-100">
|
<div class="w-100">
|
||||||
<div>
|
<div>
|
||||||
<div class="d-flex w-100" v-for="(input, index) in newInputs" :key="index">
|
<div class="d-flex w-100" v-for="(input, index) in newInputs" :key="index">
|
||||||
@@ -74,8 +71,10 @@
|
|||||||
</script>
|
</script>
|
||||||
<script>
|
<script>
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {Drawer},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
props: {
|
props: {
|
||||||
inputs: {
|
inputs: {
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-100">
|
<div class="w-100">
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isEditOpen"
|
v-if="isEditOpen"
|
||||||
v-model="isEditOpen"
|
v-model="isEditOpen"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>variables</code>
|
<code>variables</code>
|
||||||
@@ -43,7 +40,7 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
<div class="w-100">
|
<div class="w-100">
|
||||||
<div v-if="variables">
|
<div v-if="variables">
|
||||||
<div class="d-flex w-100" v-for="(value, index) in newVariables" :key="index">
|
<div class="d-flex w-100" v-for="(value, index) in newVariables" :key="index">
|
||||||
@@ -83,9 +80,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Editor from "../inputs/Editor.vue";
|
import Editor from "../inputs/Editor.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {Editor},
|
components: {Editor, Drawer},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
props: {
|
props: {
|
||||||
variables: {
|
variables: {
|
||||||
|
|||||||
@@ -6,13 +6,9 @@
|
|||||||
ref="taskEdit"
|
ref="taskEdit"
|
||||||
>
|
>
|
||||||
<span v-if="component !== 'el-button' && !isHidden">{{ $t("show task source") }}</span>
|
<span v-if="component !== 'el-button' && !isHidden">{{ $t("show task source") }}</span>
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isModalOpen"
|
v-if="isModalOpen"
|
||||||
v-model="isModalOpen"
|
v-model="isModalOpen"
|
||||||
destroy-on-close
|
|
||||||
lock-scroll
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>{{ taskId || task?.id || $t("add task") }}</code>
|
<code>{{ taskId || task?.id || $t("add task") }}</code>
|
||||||
@@ -81,7 +77,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -94,6 +90,7 @@
|
|||||||
import YamlUtils from "../../utils/yamlUtils";
|
import YamlUtils from "../../utils/yamlUtils";
|
||||||
import Editor from "../inputs/Editor.vue";
|
import Editor from "../inputs/Editor.vue";
|
||||||
import TaskEditor from "./TaskEditor.vue";
|
import TaskEditor from "./TaskEditor.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
import {canSaveFlowTemplate, saveFlowTemplate} from "../../utils/flowTemplate";
|
import {canSaveFlowTemplate, saveFlowTemplate} from "../../utils/flowTemplate";
|
||||||
import {mapGetters, mapState} from "vuex";
|
import {mapGetters, mapState} from "vuex";
|
||||||
import Utils from "../../utils/utils";
|
import Utils from "../../utils/utils";
|
||||||
@@ -102,7 +99,7 @@
|
|||||||
import {SECTIONS} from "../../utils/constants";
|
import {SECTIONS} from "../../utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {Editor, TaskEditor, Markdown, ValidationError},
|
components: {Editor, TaskEditor, Drawer, Markdown, ValidationError},
|
||||||
emits: ["update:task", "close"],
|
emits: ["update:task", "close"],
|
||||||
props: {
|
props: {
|
||||||
component: {
|
component: {
|
||||||
|
|||||||
@@ -8,13 +8,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
||||||
|
<drawer
|
||||||
<el-drawer
|
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
v-model="isOpen"
|
v-model="isOpen"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>{{ root }}</code>
|
<code>{{ root }}</code>
|
||||||
@@ -54,7 +50,7 @@
|
|||||||
{{ $t("save") }}
|
{{ $t("save") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -64,9 +60,11 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Task from "./Task"
|
import Task from "./Task"
|
||||||
|
import Drawer from "../../Drawer.vue"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [Task],
|
mixins: [Task],
|
||||||
|
components: {Drawer},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
|
|||||||
@@ -8,13 +8,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
||||||
|
<drawer
|
||||||
<el-drawer
|
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
v-model="isOpen"
|
v-model="isOpen"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>{{ root }}</code>
|
<code>{{ root }}</code>
|
||||||
@@ -33,7 +29,7 @@
|
|||||||
{{ $t('save') }}
|
{{ $t('save') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -43,8 +39,11 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Task from "./Task"
|
import Task from "./Task"
|
||||||
|
import Drawer from "../../Drawer.vue"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [Task],
|
mixins: [Task],
|
||||||
|
components: {Drawer},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
|
|||||||
@@ -8,13 +8,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
v-model="isOpen"
|
v-model="isOpen"
|
||||||
:title="root"
|
:title="root"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>{{ root }}</code>
|
<code>{{ root }}</code>
|
||||||
@@ -33,7 +30,7 @@
|
|||||||
{{ $t('save') }}
|
{{ $t('save') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -46,10 +43,11 @@
|
|||||||
import Task from "./Task"
|
import Task from "./Task"
|
||||||
import YamlUtils from "../../../utils/yamlUtils";
|
import YamlUtils from "../../../utils/yamlUtils";
|
||||||
import TaskEditor from "../TaskEditor.vue"
|
import TaskEditor from "../TaskEditor.vue"
|
||||||
|
import Drawer from "../../Drawer.vue"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [Task],
|
mixins: [Task],
|
||||||
components: {TaskEditor},
|
components: {TaskEditor, Drawer},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -8,12 +8,9 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
v-model="isOpen"
|
v-model="isOpen"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>{{ root }}</code>
|
<code>{{ root }}</code>
|
||||||
@@ -31,7 +28,7 @@
|
|||||||
{{ $t('save') }}
|
{{ $t('save') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -44,10 +41,11 @@
|
|||||||
import Task from "./Task"
|
import Task from "./Task"
|
||||||
import YamlUtils from "../../../utils/yamlUtils";
|
import YamlUtils from "../../../utils/yamlUtils";
|
||||||
import TaskEditor from "../TaskEditor.vue"
|
import TaskEditor from "../TaskEditor.vue"
|
||||||
|
import Drawer from "../../Drawer.vue"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [Task],
|
mixins: [Task],
|
||||||
components: {TaskEditor},
|
components: {TaskEditor, Drawer},
|
||||||
emits: ["update:modelValue"],
|
emits: ["update:modelValue"],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<top-nav-bar v-if="!embed" :title="routeInfo.title">
|
<top-nav-bar v-if="!embed" :title="routeInfo.title">
|
||||||
<template #additional-right>
|
<template #additional-right v-if="canCreate">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<router-link :to="{name: 'flows/create'}">
|
<router-link :to="{name: 'flows/create'}">
|
||||||
@@ -333,6 +333,9 @@
|
|||||||
title: this.$t("homeDashboard.title"),
|
title: this.$t("homeDashboard.title"),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
canCreate() {
|
||||||
|
return this.user.isAllowedGlobal(permission.FLOW, action.CREATE)
|
||||||
|
},
|
||||||
defaultFilters() {
|
defaultFilters() {
|
||||||
return {
|
return {
|
||||||
startDate: this.$moment(this.startDate).toISOString(true),
|
startDate: this.$moment(this.startDate).toISOString(true),
|
||||||
|
|||||||
@@ -77,6 +77,7 @@
|
|||||||
navbar: {type: Boolean, default: true},
|
navbar: {type: Boolean, default: true},
|
||||||
input: {type: Boolean, default: false},
|
input: {type: Boolean, default: false},
|
||||||
fullHeight: {type: Boolean, default: true},
|
fullHeight: {type: Boolean, default: true},
|
||||||
|
customHeight: {type: Number, default: 7},
|
||||||
theme: {type: String, default: undefined},
|
theme: {type: String, default: undefined},
|
||||||
placeholder: {type: [String, Number], default: ""},
|
placeholder: {type: [String, Number], default: ""},
|
||||||
diffSideBySide: {type: Boolean, default: true},
|
diffSideBySide: {type: Boolean, default: true},
|
||||||
@@ -298,7 +299,7 @@
|
|||||||
|
|
||||||
if (!this.fullHeight) {
|
if (!this.fullHeight) {
|
||||||
editor.onDidContentSizeChange(e => {
|
editor.onDidContentSizeChange(e => {
|
||||||
this.$refs.container.style.height = (e.contentHeight + 7) + "px";
|
this.$refs.container.style.height = (e.contentHeight + this.customHeight) + "px";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
import Utils from "@kestra-io/ui-libs/src/utils/Utils";
|
import Utils from "@kestra-io/ui-libs/src/utils/Utils";
|
||||||
import {apiUrl} from "override/utils/route";
|
import {apiUrl} from "override/utils/route";
|
||||||
import EditorButtons from "./EditorButtons.vue";
|
import EditorButtons from "./EditorButtons.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const router = getCurrentInstance().appContext.config.globalProperties.$router;
|
const router = getCurrentInstance().appContext.config.globalProperties.$router;
|
||||||
@@ -167,12 +168,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const editorDomElement = ref(null);
|
const editorDomElement = ref(null);
|
||||||
const editorWidthStorageKey = "editor-width";
|
const editorWidthStorageKey = "editor-size";
|
||||||
const editorWidth = ref(localStorage.getItem(editorWidthStorageKey));
|
const editorWidth = ref(localStorage.getItem(editorWidthStorageKey));
|
||||||
const validationDomElement = ref(null);
|
const validationDomElement = ref(null);
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const haveChange = ref(props.isDirty)
|
const haveChange = ref(props.isDirty)
|
||||||
const flowYaml = ref("")
|
const flowYaml = ref("")
|
||||||
|
const flowYamlOrigin = ref("")
|
||||||
const newTrigger = ref(null)
|
const newTrigger = ref(null)
|
||||||
const isNewTriggerOpen = ref(false)
|
const isNewTriggerOpen = ref(false)
|
||||||
const newError = ref(null)
|
const newError = ref(null)
|
||||||
@@ -235,7 +237,7 @@
|
|||||||
|
|
||||||
const initYamlSource = async () => {
|
const initYamlSource = async () => {
|
||||||
flowYaml.value = props.flow.source;
|
flowYaml.value = props.flow.source;
|
||||||
|
flowYamlOrigin.value = props.flow.source;
|
||||||
if (flowHaveTasks()) {
|
if (flowHaveTasks()) {
|
||||||
if ([editorViewTypes.TOPOLOGY, editorViewTypes.SOURCE_TOPOLOGY].includes(viewType.value)) {
|
if ([editorViewTypes.TOPOLOGY, editorViewTypes.SOURCE_TOPOLOGY].includes(viewType.value)) {
|
||||||
await fetchGraph();
|
await fetchGraph();
|
||||||
@@ -759,7 +761,7 @@
|
|||||||
:is-read-only="props.isReadOnly"
|
:is-read-only="props.isReadOnly"
|
||||||
:can-delete="canDelete()"
|
:can-delete="canDelete()"
|
||||||
:is-allowed-edit="isAllowedEdit()"
|
:is-allowed-edit="isAllowedEdit()"
|
||||||
:have-change="haveChange"
|
:have-change="flowYaml !== flowYamlOrigin"
|
||||||
:flow-have-tasks="flowHaveTasks()"
|
:flow-have-tasks="flowHaveTasks()"
|
||||||
:errors="flowErrors"
|
:errors="flowErrors"
|
||||||
:warnings="flowWarnings"
|
:warnings="flowWarnings"
|
||||||
@@ -825,13 +827,10 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isNewErrorOpen"
|
v-if="isNewErrorOpen"
|
||||||
v-model="isNewErrorOpen"
|
v-model="isNewErrorOpen"
|
||||||
title="Add a global error handler"
|
title="Add a global error handler"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<el-form label-position="top">
|
<el-form label-position="top">
|
||||||
<task-editor
|
<task-editor
|
||||||
@@ -845,14 +844,11 @@
|
|||||||
{{ $t("save") }}
|
{{ $t("save") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isNewTriggerOpen"
|
v-if="isNewTriggerOpen"
|
||||||
v-model="isNewTriggerOpen"
|
v-model="isNewTriggerOpen"
|
||||||
title="Add a trigger"
|
title="Add a trigger"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<el-form label-position="top">
|
<el-form label-position="top">
|
||||||
<task-editor
|
<task-editor
|
||||||
@@ -866,13 +862,10 @@
|
|||||||
{{ $t("save") }}
|
{{ $t("save") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isEditMetadataOpen"
|
v-if="isEditMetadataOpen"
|
||||||
v-model="isEditMetadataOpen"
|
v-model="isEditMetadataOpen"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>flow metadata</code>
|
<code>flow metadata</code>
|
||||||
@@ -896,7 +889,7 @@
|
|||||||
{{ $t("save") }}
|
{{ $t("save") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog v-if="confirmOutdatedSaveDialog" v-model="confirmOutdatedSaveDialog" destroy-on-close :append-to-body="true">
|
<el-dialog v-if="confirmOutdatedSaveDialog" v-model="confirmOutdatedSaveDialog" destroy-on-close :append-to-body="true">
|
||||||
<template #header>
|
<template #header>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
import LogLevelSelector from "../logs/LogLevelSelector.vue";
|
import LogLevelSelector from "../logs/LogLevelSelector.vue";
|
||||||
import TaskRunDetails from "../logs/TaskRunDetails.vue";
|
import TaskRunDetails from "../logs/TaskRunDetails.vue";
|
||||||
import Collapse from "../layout/Collapse.vue";
|
import Collapse from "../layout/Collapse.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
// Topology
|
// Topology
|
||||||
import {
|
import {
|
||||||
@@ -340,12 +341,9 @@
|
|||||||
|
|
||||||
<!-- Drawer to task informations (logs, description, ..) -->
|
<!-- Drawer to task informations (logs, description, ..) -->
|
||||||
<!-- Assuming selectedTask is always the id and the required data for the opened drawer -->
|
<!-- Assuming selectedTask is always the id and the required data for the opened drawer -->
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isDrawerOpen && selectedTask"
|
v-if="isDrawerOpen && selectedTask"
|
||||||
v-model="isDrawerOpen"
|
v-model="isDrawerOpen"
|
||||||
destroy-on-close
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<code>{{ selectedTask.id }}</code>
|
<code>{{ selectedTask.id }}</code>
|
||||||
@@ -373,7 +371,7 @@
|
|||||||
<div v-if="isShowDescriptionOpen">
|
<div v-if="isShowDescriptionOpen">
|
||||||
<markdown class="markdown-tooltip" :source="selectedTask.description" />
|
<markdown class="markdown-tooltip" :source="selectedTask.description" />
|
||||||
</div>
|
</div>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -32,12 +32,21 @@
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
#environment {
|
#environment {
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 1.5rem;
|
||||||
background-color: v-bind('color');
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
margin-top: -1.25rem;
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
color: var(--bs-body-bg);
|
border: 1px solid v-bind('color');
|
||||||
|
border-radius: var(--bs-border-radius);
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
padding: 0.125rem 0.25rem;
|
||||||
|
font-size: var(--font-size-sm);
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
max-width: 90%;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -7,28 +7,26 @@
|
|||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<el-drawer
|
<drawer
|
||||||
v-if="isOpen"
|
v-if="isOpen"
|
||||||
v-model="isOpen"
|
v-model="isOpen"
|
||||||
:title="title"
|
:title="title"
|
||||||
destroy-on-close
|
|
||||||
class="sm"
|
|
||||||
size=""
|
|
||||||
:append-to-body="true"
|
|
||||||
>
|
>
|
||||||
<markdown class="markdown-tooltip" :source="description" />
|
<markdown class="markdown-tooltip" :source="description" />
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import HelpCircle from "vue-material-design-icons/HelpCircle.vue";
|
import HelpCircle from "vue-material-design-icons/HelpCircle.vue";
|
||||||
import Markdown from "./Markdown.vue";
|
import Markdown from "./Markdown.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
HelpCircle,
|
HelpCircle,
|
||||||
Markdown
|
Markdown,
|
||||||
|
Drawer
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<CheckboxBlankCircle v-if="hasUnread" class="new" title="" />
|
<CheckboxBlankCircle v-if="hasUnread" class="new" title="" />
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<el-drawer size="50%" v-if="isOpen" v-model="isOpen" destroy-on-close :append-to-body="true" class="sm" :title="$t('feeds.title')">
|
<drawer v-if="isOpen" v-model="isOpen" :title="$t('feeds.title')">
|
||||||
<div class="post" v-for="(feed, index) in feeds" :key="feed.id">
|
<div class="post" v-for="(feed, index) in feeds" :key="feed.id">
|
||||||
<div v-if="feed.image" class="mt-2">
|
<div v-if="feed.image" class="mt-2">
|
||||||
<img class="float-end" :src="feed.image" alt="">
|
<img class="float-end" :src="feed.image" alt="">
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
<el-divider v-if="index !== feeds.length - 1" />
|
<el-divider v-if="index !== feeds.length - 1" />
|
||||||
</div>
|
</div>
|
||||||
</el-drawer>
|
</drawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
import CheckboxBlankCircle from "vue-material-design-icons/CheckboxBlankCircle.vue";
|
import CheckboxBlankCircle from "vue-material-design-icons/CheckboxBlankCircle.vue";
|
||||||
import Markdown from "./Markdown.vue";
|
import Markdown from "./Markdown.vue";
|
||||||
import DateAgo from "./DateAgo.vue";
|
import DateAgo from "./DateAgo.vue";
|
||||||
|
import Drawer from "../Drawer.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -39,7 +40,8 @@
|
|||||||
OpenInNew,
|
OpenInNew,
|
||||||
CheckboxBlankCircle,
|
CheckboxBlankCircle,
|
||||||
Markdown,
|
Markdown,
|
||||||
DateAgo
|
DateAgo,
|
||||||
|
Drawer
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -39,6 +39,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import {storageKeys} from "../../utils/constants";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
total: {type: Number, default: 0},
|
total: {type: Number, default: 0},
|
||||||
@@ -61,14 +63,22 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initState() {
|
initState() {
|
||||||
|
let internalSize = parseInt(localStorage.getItem(storageKeys.PAGINATION_SIZE) || this.$route.query.size || this.size)
|
||||||
|
let internalPage = parseInt(this.$route.query.page || this.page)
|
||||||
|
this.$emit("page-changed", {
|
||||||
|
page: internalPage,
|
||||||
|
size: internalSize,
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
internalSize: parseInt(this.$route.query.size || this.size),
|
internalSize: internalSize,
|
||||||
internalPage: parseInt(this.$route.query.page || this.page)
|
internalPage: internalPage
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pageSizeChange(value) {
|
pageSizeChange: function (value) {
|
||||||
this.internalPage = 1;
|
this.internalPage = 1;
|
||||||
this.internalSize = value;
|
this.internalSize = value;
|
||||||
|
localStorage.setItem(storageKeys.PAGINATION_SIZE, value);
|
||||||
this.$emit("page-changed", {
|
this.$emit("page-changed", {
|
||||||
page: 1,
|
page: 1,
|
||||||
size: this.internalSize,
|
size: this.internalSize,
|
||||||
|
|||||||
@@ -214,7 +214,7 @@
|
|||||||
this.autofoldTextEditor = localStorage.getItem("autofoldTextEditor") === "true";
|
this.autofoldTextEditor = localStorage.getItem("autofoldTextEditor") === "true";
|
||||||
this.guidedTour = localStorage.getItem("tourDoneOrSkip") === "true";
|
this.guidedTour = localStorage.getItem("tourDoneOrSkip") === "true";
|
||||||
this.logDisplay = localStorage.getItem("logDisplay") || logDisplayTypes.DEFAULT;
|
this.logDisplay = localStorage.getItem("logDisplay") || logDisplayTypes.DEFAULT;
|
||||||
this.editorFontSize = localStorage.getItem("editorFontSize") || 12;
|
this.editorFontSize = parseInt(localStorage.getItem("editorFontSize")) || 12;
|
||||||
this.editorFontFamily = localStorage.getItem("editorFontFamily") || "'Source Code Pro', monospace";
|
this.editorFontFamily = localStorage.getItem("editorFontFamily") || "'Source Code Pro', monospace";
|
||||||
this.executeFlowBehaviour = localStorage.getItem("executeFlowBehaviour") || "same tab";
|
this.executeFlowBehaviour = localStorage.getItem("executeFlowBehaviour") || "same tab";
|
||||||
this.envName = store.getters["layout/envName"] || this.configs?.environment?.name;
|
this.envName = store.getters["layout/envName"] || this.configs?.environment?.name;
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ export default {
|
|||||||
canSave() {
|
canSave() {
|
||||||
return canSaveFlowTemplate(true, this.user, this.item, this.dataType);
|
return canSaveFlowTemplate(true, this.user, this.item, this.dataType);
|
||||||
},
|
},
|
||||||
|
canCreate() {
|
||||||
|
return this.dataType === "flow" && this.user.isAllowed(permission.FLOW, action.CREATE, this.item.namespace)
|
||||||
|
},
|
||||||
canExecute() {
|
canExecute() {
|
||||||
return this.dataType === "flow" && this.user.isAllowed(permission.EXECUTION, action.CREATE, this.item.namespace)
|
return this.dataType === "flow" && this.user.isAllowed(permission.EXECUTION, action.CREATE, this.item.namespace)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,13 +15,14 @@
|
|||||||
<Environment />
|
<Environment />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer />
|
||||||
<span class="version">{{ configs.version }}</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #toggle-icon>
|
<template #toggle-icon>
|
||||||
<chevron-right v-if="collapsed" />
|
<el-button>
|
||||||
<chevron-left v-else />
|
<chevron-double-right v-if="collapsed" />
|
||||||
|
<chevron-double-left v-else />
|
||||||
|
</el-button>
|
||||||
|
<span class="version">{{ configs.version }}</span>
|
||||||
</template>
|
</template>
|
||||||
</sidebar-menu>
|
</sidebar-menu>
|
||||||
</template>
|
</template>
|
||||||
@@ -29,28 +30,28 @@
|
|||||||
<script>
|
<script>
|
||||||
import {SidebarMenu} from "vue-sidebar-menu";
|
import {SidebarMenu} from "vue-sidebar-menu";
|
||||||
import Environment from "../../components/layout/Environment.vue";
|
import Environment from "../../components/layout/Environment.vue";
|
||||||
import ChevronLeft from "vue-material-design-icons/ChevronLeft.vue";
|
import ChevronDoubleLeft from "vue-material-design-icons/ChevronDoubleLeft.vue";
|
||||||
import ChevronRight from "vue-material-design-icons/ChevronRight.vue";
|
import ChevronDoubleRight from "vue-material-design-icons/ChevronDoubleRight.vue";
|
||||||
import FileTreeOutline from "vue-material-design-icons/FileTreeOutline.vue";
|
import FileTreeOutline from "vue-material-design-icons/FileTreeOutline.vue";
|
||||||
import ContentCopy from "vue-material-design-icons/ContentCopy.vue";
|
import ContentCopy from "vue-material-design-icons/ContentCopy.vue";
|
||||||
import TimelineClockOutline from "vue-material-design-icons/TimelineClockOutline.vue";
|
import TimelineClockOutline from "vue-material-design-icons/TimelineClockOutline.vue";
|
||||||
import TimelineTextOutline from "vue-material-design-icons/TimelineTextOutline.vue";
|
import TimelineTextOutline from "vue-material-design-icons/TimelineTextOutline.vue";
|
||||||
import NotebookOutline from "vue-material-design-icons/NotebookOutline.vue";
|
import ChartTimeline from "vue-material-design-icons/ChartTimeline.vue";
|
||||||
import Ballot from "vue-material-design-icons/Ballot.vue";
|
import BallotOutline from "vue-material-design-icons/BallotOutline.vue";
|
||||||
import FolderEditOutline from "vue-material-design-icons/FolderEditOutline.vue";
|
import FolderEditOutline from "vue-material-design-icons/FolderEditOutline.vue";
|
||||||
import AccountSupervisorOutline from "vue-material-design-icons/AccountSupervisorOutline.vue";
|
import ShieldAccountVariantOutline from "vue-material-design-icons/ShieldAccountVariantOutline.vue";
|
||||||
import CogOutline from "vue-material-design-icons/CogOutline.vue";
|
import CogOutline from "vue-material-design-icons/CogOutline.vue";
|
||||||
import ViewDashboardVariantOutline from "vue-material-design-icons/ViewDashboardVariantOutline.vue";
|
import ViewDashboardVariantOutline from "vue-material-design-icons/ViewDashboardVariantOutline.vue";
|
||||||
import TimerCogOutline from "vue-material-design-icons/TimerCogOutline.vue";
|
import TimerCogOutline from "vue-material-design-icons/TimerCogOutline.vue";
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import AccountHardHatOutline from "vue-material-design-icons/AccountHardHatOutline.vue";
|
|
||||||
import ChartBoxOutline from "vue-material-design-icons/ChartBoxOutline.vue";
|
import ChartBoxOutline from "vue-material-design-icons/ChartBoxOutline.vue";
|
||||||
|
import ServerOutline from "vue-material-design-icons/ServerOutline.vue";
|
||||||
import {shallowRef} from "vue";
|
import {shallowRef} from "vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ChevronLeft,
|
ChevronDoubleLeft,
|
||||||
ChevronRight,
|
ChevronDoubleRight,
|
||||||
SidebarMenu,
|
SidebarMenu,
|
||||||
Environment
|
Environment
|
||||||
},
|
},
|
||||||
@@ -146,7 +147,7 @@
|
|||||||
routes: this.routeStartWith("taskruns"),
|
routes: this.routeStartWith("taskruns"),
|
||||||
title: this.$t("taskruns"),
|
title: this.$t("taskruns"),
|
||||||
icon: {
|
icon: {
|
||||||
element: shallowRef(TimelineTextOutline),
|
element: shallowRef(ChartTimeline),
|
||||||
class: "menu-icon"
|
class: "menu-icon"
|
||||||
},
|
},
|
||||||
hidden: !this.configs.isTaskRunEnabled
|
hidden: !this.configs.isTaskRunEnabled
|
||||||
@@ -156,7 +157,7 @@
|
|||||||
routes: this.routeStartWith("logs"),
|
routes: this.routeStartWith("logs"),
|
||||||
title: this.$t("logs"),
|
title: this.$t("logs"),
|
||||||
icon: {
|
icon: {
|
||||||
element: shallowRef(NotebookOutline),
|
element: shallowRef(TimelineTextOutline),
|
||||||
class: "menu-icon"
|
class: "menu-icon"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -165,7 +166,7 @@
|
|||||||
routes: this.routeStartWith("blueprints"),
|
routes: this.routeStartWith("blueprints"),
|
||||||
title: this.$t("blueprints.title"),
|
title: this.$t("blueprints.title"),
|
||||||
icon: {
|
icon: {
|
||||||
element: shallowRef(Ballot),
|
element: shallowRef(BallotOutline),
|
||||||
class: "menu-icon"
|
class: "menu-icon"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -173,7 +174,7 @@
|
|||||||
title: this.$t("administration"),
|
title: this.$t("administration"),
|
||||||
routes: this.routeStartWith("admin"),
|
routes: this.routeStartWith("admin"),
|
||||||
icon: {
|
icon: {
|
||||||
element: shallowRef(AccountSupervisorOutline),
|
element: shallowRef(ShieldAccountVariantOutline),
|
||||||
class: "menu-icon"
|
class: "menu-icon"
|
||||||
},
|
},
|
||||||
child: [
|
child: [
|
||||||
@@ -191,7 +192,7 @@
|
|||||||
routes: this.routeStartWith("admin/workers"),
|
routes: this.routeStartWith("admin/workers"),
|
||||||
title: this.$t("workers"),
|
title: this.$t("workers"),
|
||||||
icon: {
|
icon: {
|
||||||
element: shallowRef(AccountHardHatOutline),
|
element: shallowRef(ServerOutline),
|
||||||
class: "menu-icon"
|
class: "menu-icon"
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -302,13 +303,14 @@
|
|||||||
span.version {
|
span.version {
|
||||||
transition: 0.2s all;
|
transition: 0.2s all;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
font-size: var(--el-font-size-extra-small);
|
font-size: var(--font-size-xs);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: block;
|
display: block;
|
||||||
color: var(--bs-gray-400);
|
color: var(--bs-gray-600);
|
||||||
|
width: auto;
|
||||||
|
|
||||||
html.dark & {
|
html.dark & {
|
||||||
color: var(--bs-gray-600);
|
color: var(--bs-gray-800);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,11 +355,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.vsm--toggle-btn {
|
.vsm--toggle-btn {
|
||||||
padding-top: 4px;
|
padding-top: 16px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
font-size: 20px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: var(--bs-secondary);
|
color: var(--bs-secondary);
|
||||||
height: 30px;
|
|
||||||
border-top: 1px solid var(--bs-border-color);
|
border-top: 1px solid var(--bs-border-color);
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
padding: 8px;
|
||||||
|
margin-right: 15px;
|
||||||
|
transition: margin-right 0.2s ease;
|
||||||
|
html.dark & {
|
||||||
|
background: var(--bs-gray-500);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -410,8 +422,13 @@
|
|||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
span.version {
|
span.version {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -707,6 +707,10 @@ form.ks-horizontal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.full-screen {
|
||||||
|
width: 99% !important;
|
||||||
|
}
|
||||||
|
|
||||||
.el-drawer__header {
|
.el-drawer__header {
|
||||||
padding: var(--spacer);
|
padding: var(--spacer);
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|||||||
@@ -73,6 +73,7 @@
|
|||||||
"last1hour": "Last 1 hour",
|
"last1hour": "Last 1 hour",
|
||||||
"last12hours": "Last 12 hours",
|
"last12hours": "Last 12 hours",
|
||||||
"last24hours": "Last 24 hours",
|
"last24hours": "Last 24 hours",
|
||||||
|
"last48hours": "Last 48 hours",
|
||||||
"last7days": "Last 7 days",
|
"last7days": "Last 7 days",
|
||||||
"last30days": "Last 30 days",
|
"last30days": "Last 30 days",
|
||||||
"last365days": "Last 365 days",
|
"last365days": "Last 365 days",
|
||||||
@@ -597,7 +598,9 @@
|
|||||||
"Set labels": "Set labels",
|
"Set labels": "Set labels",
|
||||||
"Set labels to execution": "Add or update the labels of the execution <code>{id}</code>",
|
"Set labels to execution": "Add or update the labels of the execution <code>{id}</code>",
|
||||||
"Set labels done": "Successfully set the labels of the execution",
|
"Set labels done": "Successfully set the labels of the execution",
|
||||||
"bulk set labels": "Are you sure you want to set labels to <code>{executionCount}</code> executions(s)?"
|
"bulk set labels": "Are you sure you want to set labels to <code>{executionCount}</code> executions(s)?",
|
||||||
|
"dependencies loaded": "Dependencies loaded",
|
||||||
|
"loaded x dependencies": "{count} dependencies loaded"
|
||||||
},
|
},
|
||||||
"fr": {
|
"fr": {
|
||||||
"id": "Identifiant",
|
"id": "Identifiant",
|
||||||
@@ -1185,7 +1188,9 @@
|
|||||||
"Set labels": "Ajouter des labels",
|
"Set labels": "Ajouter des labels",
|
||||||
"Set labels to execution": "Ajouter ou mettre à jour des labels à l'exécution <code>{id}</code>",
|
"Set labels to execution": "Ajouter ou mettre à jour des labels à l'exécution <code>{id}</code>",
|
||||||
"Set labels done": "Labels ajoutés avec succès à l'exécution",
|
"Set labels done": "Labels ajoutés avec succès à l'exécution",
|
||||||
"bulk set labels": "Etes-vous sûr de vouloir ajouter des labels à <code>{executionCount}</code> exécutions(s)?"
|
"bulk set labels": "Etes-vous sûr de vouloir ajouter des labels à <code>{executionCount}</code> exécutions(s)?",
|
||||||
|
"dependencies loaded": "Dépendances chargées",
|
||||||
|
"loaded x dependencies": "{count} dépendances chargées"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ export const storageKeys = {
|
|||||||
SELECTED_TENANT: "selectedTenant",
|
SELECTED_TENANT: "selectedTenant",
|
||||||
EXECUTE_FLOW_BEHAVIOUR: "executeFlowBehaviour",
|
EXECUTE_FLOW_BEHAVIOUR: "executeFlowBehaviour",
|
||||||
DEFAULT_NAMESPACE: "defaultNamespace",
|
DEFAULT_NAMESPACE: "defaultNamespace",
|
||||||
LATEST_NAMESPACE: "latestNamespace"
|
LATEST_NAMESPACE: "latestNamespace",
|
||||||
|
PAGINATION_SIZE: "paginationSize",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const executeFlowBehaviours = {
|
export const executeFlowBehaviours = {
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ import io.micronaut.http.annotation.PathVariable;
|
|||||||
import io.micronaut.http.annotation.Post;
|
import io.micronaut.http.annotation.Post;
|
||||||
import io.micronaut.http.annotation.Put;
|
import io.micronaut.http.annotation.Put;
|
||||||
import io.micronaut.http.annotation.QueryValue;
|
import io.micronaut.http.annotation.QueryValue;
|
||||||
|
import io.micronaut.http.exceptions.HttpStatusException;
|
||||||
import io.micronaut.http.multipart.StreamingFileUpload;
|
import io.micronaut.http.multipart.StreamingFileUpload;
|
||||||
import io.micronaut.http.server.types.files.StreamedFile;
|
import io.micronaut.http.server.types.files.StreamedFile;
|
||||||
import io.micronaut.http.sse.Event;
|
import io.micronaut.http.sse.Event;
|
||||||
@@ -1003,7 +1004,7 @@ public class ExecutionController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Execution execution : executions) {
|
for (Execution execution : executions) {
|
||||||
Execution resumeExecution = this.executionService.resume(execution, State.Type.RUNNING);
|
Execution resumeExecution = this.executionService.resume(execution, State.Type.RUNNING);
|
||||||
this.executionQueue.emit(resumeExecution);
|
this.executionQueue.emit(resumeExecution);
|
||||||
}
|
}
|
||||||
@@ -1107,7 +1108,14 @@ public class ExecutionController {
|
|||||||
() -> executionRepository.findById(tenantService.resolveTenant(), executionId).orElse(null),
|
() -> executionRepository.findById(tenantService.resolveTenant(), executionId).orElse(null),
|
||||||
Duration.ofMillis(500)
|
Duration.ofMillis(500)
|
||||||
);
|
);
|
||||||
Flow flow = flowRepository.findByExecution(execution);
|
|
||||||
|
Flow flow;
|
||||||
|
try {
|
||||||
|
flow = flowRepository.findByExecution(execution);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
emitter.error(new HttpStatusException(HttpStatus.NOT_FOUND, "Unable to find the flow for the execution " + executionId));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.isStopFollow(flow, execution)) {
|
if (this.isStopFollow(flow, execution)) {
|
||||||
emitter.next(Event.of(execution).id("end"));
|
emitter.next(Event.of(execution).id("end"));
|
||||||
@@ -1273,7 +1281,8 @@ public class ExecutionController {
|
|||||||
return HttpResponse.ok(BulkResponse.builder().count(executions.size()).build());
|
return HttpResponse.ok(BulkResponse.builder().count(executions.size()).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public record SetLabelsByIdsRequest(List<String> executionsId, List<Label> executionLabels) {}
|
public record SetLabelsByIdsRequest(List<String> executionsId, List<Label> executionLabels) {
|
||||||
|
}
|
||||||
|
|
||||||
@ExecuteOn(TaskExecutors.IO)
|
@ExecuteOn(TaskExecutors.IO)
|
||||||
@Post(uri = "/labels/by-query")
|
@Post(uri = "/labels/by-query")
|
||||||
|
|||||||
@@ -81,6 +81,13 @@ public class TriggerController {
|
|||||||
if (flow.isEmpty()) {
|
if (flow.isEmpty()) {
|
||||||
// Warn instead of throwing to avoid blocking the trigger UI
|
// Warn instead of throwing to avoid blocking the trigger UI
|
||||||
log.warn(String.format("Flow %s not found for trigger %s", tc.getFlowId(), tc.getTriggerId()));
|
log.warn(String.format("Flow %s not found for trigger %s", tc.getFlowId(), tc.getTriggerId()));
|
||||||
|
triggers.add(Triggers.builder()
|
||||||
|
.abstractTrigger(null)
|
||||||
|
.triggerContext(tc)
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AbstractTrigger abstractTrigger = flow.get().getTriggers().stream().filter(t -> t.getId().equals(tc.getTriggerId())).findFirst().orElse(null);
|
AbstractTrigger abstractTrigger = flow.get().getTriggers().stream().filter(t -> t.getId().equals(tc.getTriggerId())).findFirst().orElse(null);
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017-2024 original authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.kestra.webserver.cookies;
|
||||||
|
|
||||||
|
import io.micronaut.core.annotation.Internal;
|
||||||
|
import io.micronaut.core.annotation.NonNull;
|
||||||
|
import io.micronaut.http.cookie.Cookie;
|
||||||
|
import io.micronaut.http.cookie.DefaultServerCookieDecoder;
|
||||||
|
import io.micronaut.http.cookie.ServerCookieDecoder;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Workaround for <a href="https://github.com/micronaut-projects/micronaut-core/issues/10435">multi-cookies header parsing issue</a>
|
||||||
|
*/
|
||||||
|
@Internal
|
||||||
|
public final class ServerMultipleCookiesDecoder implements ServerCookieDecoder {
|
||||||
|
|
||||||
|
public static final DefaultServerCookieDecoder DEFAULT_SERVER_COOKIE_DECODER = new DefaultServerCookieDecoder();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
public List<Cookie> decode(@NonNull String header) {
|
||||||
|
String cookie2Header = header;
|
||||||
|
if (!header.toLowerCase().startsWith("set-cookie2:")) {
|
||||||
|
cookie2Header = "Set-Cookie2:" + header.replace(";", ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_SERVER_COOKIE_DECODER.decode(cookie2Header);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
io.kestra.webserver.cookies.ServerMultipleCookiesDecoder
|
||||||
Reference in New Issue
Block a user