Compare commits
76 Commits
feat/execu
...
debug-flak
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3e49125f4 | ||
|
|
6aa2639949 | ||
|
|
d167934fa6 | ||
|
|
93662f331a | ||
|
|
427c6f5ecf | ||
|
|
f0ceda5002 | ||
|
|
39095d072c | ||
|
|
beea77a311 | ||
|
|
5ada578271 | ||
|
|
b5f76332d1 | ||
|
|
6862202afe | ||
|
|
33299dc3ec | ||
|
|
073891e1a5 | ||
|
|
3b7b0baa26 | ||
|
|
1e80b7f7d7 | ||
|
|
a5f17b9242 | ||
|
|
7ff51bcc08 | ||
|
|
a345a0518d | ||
|
|
0b6a4d2520 | ||
|
|
a60bc2e155 | ||
|
|
5bd401a038 | ||
|
|
a7312ef615 | ||
|
|
6175af66c1 | ||
|
|
86dead7f57 | ||
|
|
f10f7ea008 | ||
|
|
4c58a646c9 | ||
|
|
686c99f09a | ||
|
|
8947fec1a4 | ||
|
|
8fdbd0abb6 | ||
|
|
98fe1aead2 | ||
|
|
1143caf498 | ||
|
|
a3c781f2ea | ||
|
|
123c006dc7 | ||
|
|
003e93be08 | ||
|
|
efdca4bff1 | ||
|
|
5542b7318b | ||
|
|
e5849335e5 | ||
|
|
0726bd8082 | ||
|
|
417a5426ff | ||
|
|
c3e4f58964 | ||
|
|
f081be2413 | ||
|
|
f7e3d1e6c5 | ||
|
|
7ba29e593f | ||
|
|
8b1ceb836b | ||
|
|
9d3d40ade8 | ||
|
|
ca3e765e58 | ||
|
|
4b719eab82 | ||
|
|
a2eb94b382 | ||
|
|
4e793ef30d | ||
|
|
a3fe9f280a | ||
|
|
51db6c45f1 | ||
|
|
067ca723c8 | ||
|
|
12768d1bc9 | ||
|
|
67d3f84c51 | ||
|
|
17af9fb311 | ||
|
|
8da27576b5 | ||
|
|
d56381df77 | ||
|
|
a133043d0c | ||
|
|
bb92592418 | ||
|
|
6e35326c75 | ||
|
|
b8b416038b | ||
|
|
0b5b2825ee | ||
|
|
886b047ace | ||
|
|
5ad9862680 | ||
|
|
a0fe9cad06 | ||
|
|
be970009a2 | ||
|
|
562253b776 | ||
|
|
df97207c48 | ||
|
|
aa2bc06ea8 | ||
|
|
65d42c001e | ||
|
|
ba3952bd89 | ||
|
|
ef88af1f9a | ||
|
|
8ab2bdcfde | ||
|
|
190bf6f3db | ||
|
|
18b6b4ce5d | ||
|
|
dd65b4697e |
2
.github/CONTRIBUTING.md
vendored
@@ -126,7 +126,7 @@ By default, Kestra will be installed under: `$HOME/.kestra/current`. Set the `KE
|
|||||||
```bash
|
```bash
|
||||||
# build and install Kestra
|
# build and install Kestra
|
||||||
make install
|
make install
|
||||||
# install plugins (plugins installation is based on the `.plugins` or `.plugins.override` files located at the root of the project.
|
# install plugins (plugins installation is based on the API).
|
||||||
make install-plugins
|
make install-plugins
|
||||||
# start Kestra in standalone mode with Postgres as backend
|
# start Kestra in standalone mode with Postgres as backend
|
||||||
make start-standalone-postgres
|
make start-standalone-postgres
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
name: Run Gradle Release for Kestra Plugins
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
releaseVersion:
|
|
||||||
description: 'The release version (e.g., 0.21.0)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
nextVersion:
|
|
||||||
description: 'The next version (e.g., 0.22.0-SNAPSHOT)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
dryRun:
|
|
||||||
description: 'Use DRY_RUN mode'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
name: Release plugins
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
# Checkout
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
# Setup build
|
|
||||||
- uses: kestra-io/actions/composite/setup-build@main
|
|
||||||
id: build
|
|
||||||
with:
|
|
||||||
java-enabled: true
|
|
||||||
node-enabled: true
|
|
||||||
python-enabled: true
|
|
||||||
|
|
||||||
# Get Plugins List
|
|
||||||
- name: Get Plugins List
|
|
||||||
uses: kestra-io/actions/composite/kestra-oss/kestra-oss-plugins-list@main
|
|
||||||
id: plugins-list
|
|
||||||
with:
|
|
||||||
plugin-version: 'LATEST'
|
|
||||||
|
|
||||||
- name: 'Configure Git'
|
|
||||||
run: |
|
|
||||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
git config --global user.name "github-actions[bot]"
|
|
||||||
|
|
||||||
# Execute
|
|
||||||
- name: Run Gradle Release
|
|
||||||
if: ${{ github.event.inputs.dryRun == 'false' }}
|
|
||||||
env:
|
|
||||||
GITHUB_PAT: ${{ secrets.GH_PERSONAL_TOKEN }}
|
|
||||||
run: |
|
|
||||||
chmod +x ./dev-tools/release-plugins.sh;
|
|
||||||
|
|
||||||
./dev-tools/release-plugins.sh \
|
|
||||||
--release-version=${{github.event.inputs.releaseVersion}} \
|
|
||||||
--next-version=${{github.event.inputs.nextVersion}} \
|
|
||||||
--yes \
|
|
||||||
${{ steps.plugins-list.outputs.repositories }}
|
|
||||||
|
|
||||||
- name: Run Gradle Release (DRY_RUN)
|
|
||||||
if: ${{ github.event.inputs.dryRun == 'true' }}
|
|
||||||
env:
|
|
||||||
GITHUB_PAT: ${{ secrets.GH_PERSONAL_TOKEN }}
|
|
||||||
run: |
|
|
||||||
chmod +x ./dev-tools/release-plugins.sh;
|
|
||||||
|
|
||||||
./dev-tools/release-plugins.sh \
|
|
||||||
--release-version=${{github.event.inputs.releaseVersion}} \
|
|
||||||
--next-version=${{github.event.inputs.nextVersion}} \
|
|
||||||
--dry-run \
|
|
||||||
--yes \
|
|
||||||
${{ steps.plugins-list.outputs.repositories }}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
name: Set Version and Tag Plugins
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
inputs:
|
|
||||||
releaseVersion:
|
|
||||||
description: 'The release version (e.g., 0.21.0)'
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
dryRun:
|
|
||||||
description: 'Use DRY_RUN mode'
|
|
||||||
required: false
|
|
||||||
default: 'false'
|
|
||||||
jobs:
|
|
||||||
tag:
|
|
||||||
name: Release plugins
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
# Checkout
|
|
||||||
- uses: actions/checkout@v5
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
# Get Plugins List
|
|
||||||
- name: Get Plugins List
|
|
||||||
uses: kestra-io/actions/composite/kestra-oss/kestra-oss-plugins-list@main
|
|
||||||
id: plugins-list
|
|
||||||
with:
|
|
||||||
plugin-version: 'LATEST'
|
|
||||||
|
|
||||||
- name: 'Configure Git'
|
|
||||||
run: |
|
|
||||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
||||||
git config --global user.name "github-actions[bot]"
|
|
||||||
|
|
||||||
# Execute
|
|
||||||
- name: Set Version and Tag Plugins
|
|
||||||
if: ${{ github.event.inputs.dryRun == 'false' }}
|
|
||||||
env:
|
|
||||||
GITHUB_PAT: ${{ secrets.GH_PERSONAL_TOKEN }}
|
|
||||||
run: |
|
|
||||||
chmod +x ./dev-tools/setversion-tag-plugins.sh;
|
|
||||||
|
|
||||||
./dev-tools/setversion-tag-plugins.sh \
|
|
||||||
--release-version=${{github.event.inputs.releaseVersion}} \
|
|
||||||
--yes \
|
|
||||||
${{ steps.plugins-list.outputs.repositories }}
|
|
||||||
|
|
||||||
- name: Set Version and Tag Plugins (DRY_RUN)
|
|
||||||
if: ${{ github.event.inputs.dryRun == 'true' }}
|
|
||||||
env:
|
|
||||||
GITHUB_PAT: ${{ secrets.GH_PERSONAL_TOKEN }}
|
|
||||||
run: |
|
|
||||||
chmod +x ./dev-tools/setversion-tag-plugins.sh;
|
|
||||||
|
|
||||||
./dev-tools/setversion-tag-plugins.sh \
|
|
||||||
--release-version=${{github.event.inputs.releaseVersion}} \
|
|
||||||
--dry-run \
|
|
||||||
--yes \
|
|
||||||
${{ steps.plugins-list.outputs.repositories }}
|
|
||||||
65
Makefile
@@ -13,7 +13,7 @@ SHELL := /bin/bash
|
|||||||
|
|
||||||
KESTRA_BASEDIR := $(shell echo $${KESTRA_HOME:-$$HOME/.kestra/current})
|
KESTRA_BASEDIR := $(shell echo $${KESTRA_HOME:-$$HOME/.kestra/current})
|
||||||
KESTRA_WORKER_THREAD := $(shell echo $${KESTRA_WORKER_THREAD:-4})
|
KESTRA_WORKER_THREAD := $(shell echo $${KESTRA_WORKER_THREAD:-4})
|
||||||
VERSION := $(shell ./gradlew properties -q | awk '/^version:/ {print $$2}')
|
VERSION := $(shell awk -F= '/^version=/ {gsub(/-SNAPSHOT/, "", $$2); gsub(/[[:space:]]/, "", $$2); print $$2}' gradle.properties)
|
||||||
GIT_COMMIT := $(shell git rev-parse --short HEAD)
|
GIT_COMMIT := $(shell git rev-parse --short HEAD)
|
||||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||||
DATE := $(shell date --rfc-3339=seconds)
|
DATE := $(shell date --rfc-3339=seconds)
|
||||||
@@ -48,38 +48,43 @@ build-exec:
|
|||||||
./gradlew -q executableJar --no-daemon --priority=normal
|
./gradlew -q executableJar --no-daemon --priority=normal
|
||||||
|
|
||||||
install: build-exec
|
install: build-exec
|
||||||
echo "Installing Kestra: ${KESTRA_BASEDIR}"
|
@echo "Installing Kestra in ${KESTRA_BASEDIR}" ; \
|
||||||
mkdir -p ${KESTRA_BASEDIR}/bin ${KESTRA_BASEDIR}/plugins ${KESTRA_BASEDIR}/flows ${KESTRA_BASEDIR}/logs
|
KESTRA_BASEDIR="${KESTRA_BASEDIR}" ; \
|
||||||
cp build/executable/* ${KESTRA_BASEDIR}/bin/kestra && chmod +x ${KESTRA_BASEDIR}/bin
|
mkdir -p "$${KESTRA_BASEDIR}/bin" "$${KESTRA_BASEDIR}/plugins" "$${KESTRA_BASEDIR}/flows" "$${KESTRA_BASEDIR}/logs" ; \
|
||||||
VERSION_INSTALLED=$$(${KESTRA_BASEDIR}/bin/kestra --version); \
|
echo "Copying executable..." ; \
|
||||||
echo "Kestra installed successfully (version=$$VERSION_INSTALLED) 🚀"
|
EXECUTABLE_FILE=$$(ls build/executable/kestra-* 2>/dev/null | head -n1) ; \
|
||||||
|
if [ -z "$${EXECUTABLE_FILE}" ]; then \
|
||||||
# Install plugins for Kestra from (.plugins file).
|
echo "[ERROR] No Kestra executable found in build/executable"; \
|
||||||
install-plugins:
|
|
||||||
if [[ ! -f ".plugins" && ! -f ".plugins.override" ]]; then \
|
|
||||||
echo "[ERROR] file '$$(pwd)/.plugins' and '$$(pwd)/.plugins.override' not found."; \
|
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi; \
|
fi ; \
|
||||||
|
cp "$${EXECUTABLE_FILE}" "$${KESTRA_BASEDIR}/bin/kestra" ; \
|
||||||
|
chmod +x "$${KESTRA_BASEDIR}/bin/kestra" ; \
|
||||||
|
VERSION_INSTALLED=$$("$${KESTRA_BASEDIR}/bin/kestra" --version 2>/dev/null || echo "unknown") ; \
|
||||||
|
echo "Kestra installed successfully (version=$${VERSION_INSTALLED}) 🚀"
|
||||||
|
|
||||||
PLUGIN_LIST="./.plugins"; \
|
# Install plugins for Kestra from the API.
|
||||||
if [[ -f ".plugins.override" ]]; then \
|
install-plugins:
|
||||||
PLUGIN_LIST="./.plugins.override"; \
|
@echo "Installing plugins for Kestra version ${VERSION}" ; \
|
||||||
fi; \
|
if [ -z "${VERSION}" ]; then \
|
||||||
while IFS= read -r plugin; do \
|
echo "[ERROR] Kestra version could not be determined."; \
|
||||||
[[ $$plugin =~ ^#.* ]] && continue; \
|
exit 1; \
|
||||||
PLUGINS_PATH="${KESTRA_INSTALL_DIR}/plugins"; \
|
fi ; \
|
||||||
CURRENT_PLUGIN=$${plugin/LATEST/"${VERSION}"}; \
|
PLUGINS_PATH="${KESTRA_BASEDIR}/plugins" ; \
|
||||||
CURRENT_PLUGIN=$$(echo $$CURRENT_PLUGIN | cut -d':' -f2-); \
|
echo "Fetching plugin list from Kestra API for version ${VERSION}..." ; \
|
||||||
PLUGIN_FILE="$$PLUGINS_PATH/$$(echo $$CURRENT_PLUGIN | awk -F':' '{print $$2"-"$$3}').jar"; \
|
RESPONSE=$$(curl -s "https://api.kestra.io/v1/plugins/artifacts/core-compatibility/${VERSION}/latest") ; \
|
||||||
echo "Installing Kestra plugin $$CURRENT_PLUGIN > ${KESTRA_INSTALL_DIR}/plugins"; \
|
if [ -z "$${RESPONSE}" ]; then \
|
||||||
if [ -f "$$PLUGIN_FILE" ]; then \
|
echo "[ERROR] Failed to fetch plugin list from API."; \
|
||||||
echo "Plugin already installed in > $$PLUGIN_FILE"; \
|
exit 1; \
|
||||||
else \
|
fi ; \
|
||||||
|
echo "Parsing plugin list (excluding EE and secret plugins)..." ; \
|
||||||
|
echo "$${RESPONSE}" | jq -r '.[] | select(.license == "OPEN_SOURCE" and (.groupId != "io.kestra.plugin.ee") and (.groupId != "io.kestra.ee.secret")) | .groupId + ":" + .artifactId + ":" + .version' | while read -r plugin; do \
|
||||||
|
[[ $$plugin =~ ^#.* ]] && continue ; \
|
||||||
|
CURRENT_PLUGIN=$${plugin} ; \
|
||||||
|
echo "Installing $$CURRENT_PLUGIN..." ; \
|
||||||
${KESTRA_BASEDIR}/bin/kestra plugins install $$CURRENT_PLUGIN \
|
${KESTRA_BASEDIR}/bin/kestra plugins install $$CURRENT_PLUGIN \
|
||||||
--plugins ${KESTRA_BASEDIR}/plugins \
|
--plugins ${KESTRA_BASEDIR}/plugins \
|
||||||
--repositories=https://central.sonatype.com/repository/maven-snapshots || exit 1; \
|
--repositories=https://central.sonatype.com/repository/maven-snapshots || exit 1 ; \
|
||||||
fi \
|
done
|
||||||
done < $$PLUGIN_LIST
|
|
||||||
|
|
||||||
# Build docker image from Kestra source.
|
# Build docker image from Kestra source.
|
||||||
build-docker: build-exec
|
build-docker: build-exec
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ subprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
agent "org.aspectj:aspectjweaver:1.9.24"
|
agent "org.aspectj:aspectjweaver:1.9.25"
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.kestra.cli.commands.migrations.metadata;
|
|||||||
|
|
||||||
import io.kestra.cli.AbstractCommand;
|
import io.kestra.cli.AbstractCommand;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.inject.Provider;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
|
|
||||||
@@ -12,13 +13,13 @@ import picocli.CommandLine;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class KvMetadataMigrationCommand extends AbstractCommand {
|
public class KvMetadataMigrationCommand extends AbstractCommand {
|
||||||
@Inject
|
@Inject
|
||||||
private MetadataMigrationService metadataMigrationService;
|
private Provider<MetadataMigrationService> metadataMigrationServiceProvider;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer call() throws Exception {
|
public Integer call() throws Exception {
|
||||||
super.call();
|
super.call();
|
||||||
try {
|
try {
|
||||||
metadataMigrationService.kvMigration();
|
metadataMigrationServiceProvider.get().kvMigration();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("❌ KV Metadata migration failed: " + e.getMessage());
|
System.err.println("❌ KV Metadata migration failed: " + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.kestra.cli.commands.migrations.metadata;
|
|||||||
|
|
||||||
import io.kestra.cli.AbstractCommand;
|
import io.kestra.cli.AbstractCommand;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.inject.Provider;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
|
|
||||||
@@ -12,13 +13,13 @@ import picocli.CommandLine;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class SecretsMetadataMigrationCommand extends AbstractCommand {
|
public class SecretsMetadataMigrationCommand extends AbstractCommand {
|
||||||
@Inject
|
@Inject
|
||||||
private MetadataMigrationService metadataMigrationService;
|
private Provider<MetadataMigrationService> metadataMigrationServiceProvider;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer call() throws Exception {
|
public Integer call() throws Exception {
|
||||||
super.call();
|
super.call();
|
||||||
try {
|
try {
|
||||||
metadataMigrationService.secretMigration();
|
metadataMigrationServiceProvider.get().secretMigration();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println("❌ Secrets Metadata migration failed: " + e.getMessage());
|
System.err.println("❌ Secrets Metadata migration failed: " + e.getMessage());
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package io.kestra.cli.commands.servers;
|
package io.kestra.cli.commands.servers;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import io.kestra.cli.services.TenantIdSelectorService;
|
||||||
import io.kestra.core.models.ServerType;
|
import io.kestra.core.models.ServerType;
|
||||||
|
import io.kestra.core.repositories.LocalFlowRepositoryLoader;
|
||||||
import io.kestra.core.runners.ExecutorInterface;
|
import io.kestra.core.runners.ExecutorInterface;
|
||||||
import io.kestra.core.services.SkipExecutionService;
|
import io.kestra.core.services.SkipExecutionService;
|
||||||
import io.kestra.core.services.StartExecutorService;
|
import io.kestra.core.services.StartExecutorService;
|
||||||
@@ -10,6 +12,8 @@ import io.micronaut.context.ApplicationContext;
|
|||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -19,6 +23,9 @@ import java.util.Map;
|
|||||||
description = "Start the Kestra executor"
|
description = "Start the Kestra executor"
|
||||||
)
|
)
|
||||||
public class ExecutorCommand extends AbstractServerCommand {
|
public class ExecutorCommand extends AbstractServerCommand {
|
||||||
|
@CommandLine.Spec
|
||||||
|
CommandLine.Model.CommandSpec spec;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ApplicationContext applicationContext;
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
@@ -28,22 +35,28 @@ public class ExecutorCommand extends AbstractServerCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private StartExecutorService startExecutorService;
|
private StartExecutorService startExecutorService;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-executions"}, split=",", description = "The list of execution identifiers to skip, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"-f", "--flow-path"}, description = "Tenant identifier required to load flows from the specified path")
|
||||||
|
private File flowPath;
|
||||||
|
|
||||||
|
@CommandLine.Option(names = "--tenant", description = "Tenant identifier, Required to load flows from path")
|
||||||
|
private String tenantId;
|
||||||
|
|
||||||
|
@CommandLine.Option(names = {"--skip-executions"}, split=",", description = "List of execution IDs to skip, separated by commas; for troubleshooting only")
|
||||||
private List<String> skipExecutions = Collections.emptyList();
|
private List<String> skipExecutions = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-flows"}, split=",", description = "The list of flow identifiers (tenant|namespace|flowId) to skip, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-flows"}, split=",", description = "List of flow identifiers (tenant|namespace|flowId) to skip, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipFlows = Collections.emptyList();
|
private List<String> skipFlows = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-namespaces"}, split=",", description = "The list of namespace identifiers (tenant|namespace) to skip, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-namespaces"}, split=",", description = "List of namespace identifiers (tenant|namespace) to skip, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipNamespaces = Collections.emptyList();
|
private List<String> skipNamespaces = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-tenants"}, split=",", description = "The list of tenants to skip, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-tenants"}, split=",", description = "List of tenants to skip, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipTenants = Collections.emptyList();
|
private List<String> skipTenants = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--start-executors"}, split=",", description = "The list of Kafka Stream executors to start, separated by a command. Use it only with the Kafka queue, for debugging purpose.")
|
@CommandLine.Option(names = {"--start-executors"}, split=",", description = "List of Kafka Stream executors to start, separated by a command. Use it only with the Kafka queue; for debugging only")
|
||||||
private List<String> startExecutors = Collections.emptyList();
|
private List<String> startExecutors = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--not-start-executors"}, split=",", description = "The list of Kafka Stream executors to not start, separated by a command. Use it only with the Kafka queue, for debugging purpose.")
|
@CommandLine.Option(names = {"--not-start-executors"}, split=",", description = "Lst of Kafka Stream executors to not start, separated by a command. Use it only with the Kafka queue; for debugging only")
|
||||||
private List<String> notStartExecutors = Collections.emptyList();
|
private List<String> notStartExecutors = Collections.emptyList();
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@@ -64,6 +77,16 @@ public class ExecutorCommand extends AbstractServerCommand {
|
|||||||
|
|
||||||
super.call();
|
super.call();
|
||||||
|
|
||||||
|
if (flowPath != null) {
|
||||||
|
try {
|
||||||
|
LocalFlowRepositoryLoader localFlowRepositoryLoader = applicationContext.getBean(LocalFlowRepositoryLoader.class);
|
||||||
|
TenantIdSelectorService tenantIdSelectorService = applicationContext.getBean(TenantIdSelectorService.class);
|
||||||
|
localFlowRepositoryLoader.load(tenantIdSelectorService.getTenantId(this.tenantId), this.flowPath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CommandLine.ParameterException(this.spec.commandLine(), "Invalid flow path", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ExecutorInterface executorService = applicationContext.getBean(ExecutorInterface.class);
|
ExecutorInterface executorService = applicationContext.getBean(ExecutorInterface.class);
|
||||||
executorService.run();
|
executorService.run();
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public class IndexerCommand extends AbstractServerCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private SkipExecutionService skipExecutionService;
|
private SkipExecutionService skipExecutionService;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-indexer-records"}, split=",", description = "a list of indexer record keys, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-indexer-records"}, split=",", description = "a list of indexer record keys, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipIndexerRecords = Collections.emptyList();
|
private List<String> skipIndexerRecords = Collections.emptyList();
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public class StandAloneCommand extends AbstractServerCommand {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private FileChangedEventListener fileWatcher;
|
private FileChangedEventListener fileWatcher;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-f", "--flow-path"}, description = "the flow path containing flow to inject at startup (when running with a memory flow repository)")
|
@CommandLine.Option(names = {"-f", "--flow-path"}, description = "Tenant identifier required to load flows from the specified path")
|
||||||
private File flowPath;
|
private File flowPath;
|
||||||
|
|
||||||
@CommandLine.Option(names = "--tenant", description = "Tenant identifier, Required to load flows from path with the enterprise edition")
|
@CommandLine.Option(names = "--tenant", description = "Tenant identifier, Required to load flows from path with the enterprise edition")
|
||||||
@@ -51,19 +51,19 @@ public class StandAloneCommand extends AbstractServerCommand {
|
|||||||
@CommandLine.Option(names = {"--worker-thread"}, description = "the number of worker threads, defaults to eight times the number of available processors. Set it to 0 to avoid starting a worker.")
|
@CommandLine.Option(names = {"--worker-thread"}, description = "the number of worker threads, defaults to eight times the number of available processors. Set it to 0 to avoid starting a worker.")
|
||||||
private int workerThread = defaultWorkerThread();
|
private int workerThread = defaultWorkerThread();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-executions"}, split=",", description = "a list of execution identifiers to skip, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-executions"}, split=",", description = "a list of execution identifiers to skip, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipExecutions = Collections.emptyList();
|
private List<String> skipExecutions = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-flows"}, split=",", description = "a list of flow identifiers (namespace.flowId) to skip, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-flows"}, split=",", description = "a list of flow identifiers (namespace.flowId) to skip, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipFlows = Collections.emptyList();
|
private List<String> skipFlows = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-namespaces"}, split=",", description = "a list of namespace identifiers (tenant|namespace) to skip, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-namespaces"}, split=",", description = "a list of namespace identifiers (tenant|namespace) to skip, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipNamespaces = Collections.emptyList();
|
private List<String> skipNamespaces = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-tenants"}, split=",", description = "a list of tenants to skip, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-tenants"}, split=",", description = "a list of tenants to skip, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipTenants = Collections.emptyList();
|
private List<String> skipTenants = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-indexer-records"}, split=",", description = "a list of indexer record keys, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-indexer-records"}, split=",", description = "a list of indexer record keys, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipIndexerRecords = Collections.emptyList();
|
private List<String> skipIndexerRecords = Collections.emptyList();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--no-tutorials"}, description = "Flag to disable auto-loading of tutorial flows.")
|
@CommandLine.Option(names = {"--no-tutorials"}, description = "Flag to disable auto-loading of tutorial flows.")
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class WebServerCommand extends AbstractServerCommand {
|
|||||||
@Option(names = {"--no-indexer"}, description = "Flag to disable starting an embedded indexer.")
|
@Option(names = {"--no-indexer"}, description = "Flag to disable starting an embedded indexer.")
|
||||||
private boolean indexerDisabled = false;
|
private boolean indexerDisabled = false;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"--skip-indexer-records"}, split=",", description = "a list of indexer record keys, separated by a coma; for troubleshooting purpose only")
|
@CommandLine.Option(names = {"--skip-indexer-records"}, split=",", description = "a list of indexer record keys, separated by a coma; for troubleshooting only")
|
||||||
private List<String> skipIndexerRecords = Collections.emptyList();
|
private List<String> skipIndexerRecords = Collections.emptyList();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import io.kestra.core.validations.Regex;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.ConstraintViolationException;
|
import jakarta.validation.ConstraintViolationException;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
@@ -27,6 +28,7 @@ public class SelectInput extends Input<String> implements RenderableInput {
|
|||||||
@Schema(
|
@Schema(
|
||||||
title = "List of values."
|
title = "List of values."
|
||||||
)
|
)
|
||||||
|
@Size(min = 2)
|
||||||
List<@Regex String> values;
|
List<@Regex String> values;
|
||||||
|
|
||||||
@Schema(
|
@Schema(
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ public interface FlowTopologyRepositoryInterface {
|
|||||||
|
|
||||||
List<FlowTopology> findByNamespace(String tenantId, String namespace);
|
List<FlowTopology> findByNamespace(String tenantId, String namespace);
|
||||||
|
|
||||||
|
List<FlowTopology> findByNamespacePrefix(String tenantId, String namespacePrefix);
|
||||||
|
|
||||||
List<FlowTopology> findAll(String tenantId);
|
List<FlowTopology> findAll(String tenantId);
|
||||||
|
|
||||||
FlowTopology save(FlowTopology flowTopology);
|
FlowTopology save(FlowTopology flowTopology);
|
||||||
|
|||||||
@@ -383,6 +383,7 @@ public class ExecutionService {
|
|||||||
if (!isFlowable || s.equals(taskRunId)) {
|
if (!isFlowable || s.equals(taskRunId)) {
|
||||||
TaskRun newTaskRun;
|
TaskRun newTaskRun;
|
||||||
|
|
||||||
|
State.Type targetState = newState;
|
||||||
if (task instanceof Pause pauseTask) {
|
if (task instanceof Pause pauseTask) {
|
||||||
State.Type terminalState = newState == State.Type.RUNNING ? State.Type.SUCCESS : newState;
|
State.Type terminalState = newState == State.Type.RUNNING ? State.Type.SUCCESS : newState;
|
||||||
Pause.Resumed _resumed = resumed != null ? resumed : Pause.Resumed.now(terminalState);
|
Pause.Resumed _resumed = resumed != null ? resumed : Pause.Resumed.now(terminalState);
|
||||||
@@ -392,23 +393,23 @@ public class ExecutionService {
|
|||||||
// if it's a Pause task with no subtask, we terminate the task
|
// if it's a Pause task with no subtask, we terminate the task
|
||||||
if (ListUtils.isEmpty(pauseTask.getTasks()) && ListUtils.isEmpty(pauseTask.getErrors()) && ListUtils.isEmpty(pauseTask.getFinally())) {
|
if (ListUtils.isEmpty(pauseTask.getTasks()) && ListUtils.isEmpty(pauseTask.getErrors()) && ListUtils.isEmpty(pauseTask.getFinally())) {
|
||||||
if (newState == State.Type.RUNNING) {
|
if (newState == State.Type.RUNNING) {
|
||||||
newTaskRun = newTaskRun.withState(State.Type.SUCCESS);
|
targetState = State.Type.SUCCESS;
|
||||||
} else if (newState == State.Type.KILLING) {
|
} else if (newState == State.Type.KILLING) {
|
||||||
newTaskRun = newTaskRun.withState(State.Type.KILLED);
|
targetState = State.Type.KILLED;
|
||||||
} else {
|
|
||||||
newTaskRun = newTaskRun.withState(newState);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// we should set the state to RUNNING so that subtasks are executed
|
// we should set the state to RUNNING so that subtasks are executed
|
||||||
newTaskRun = newTaskRun.withState(State.Type.RUNNING);
|
targetState = State.Type.RUNNING;
|
||||||
}
|
}
|
||||||
|
newTaskRun = newTaskRun.withState(targetState);
|
||||||
} else {
|
} else {
|
||||||
newTaskRun = originalTaskRun.withState(newState);
|
newTaskRun = originalTaskRun.withState(targetState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (originalTaskRun.getAttempts() != null && !originalTaskRun.getAttempts().isEmpty()) {
|
if (originalTaskRun.getAttempts() != null && !originalTaskRun.getAttempts().isEmpty()) {
|
||||||
ArrayList<TaskRunAttempt> attempts = new ArrayList<>(originalTaskRun.getAttempts());
|
ArrayList<TaskRunAttempt> attempts = new ArrayList<>(originalTaskRun.getAttempts());
|
||||||
attempts.set(attempts.size() - 1, attempts.getLast().withState(newState));
|
attempts.set(attempts.size() - 1, attempts.getLast().withState(targetState));
|
||||||
newTaskRun = newTaskRun.withAttempts(attempts);
|
newTaskRun = newTaskRun.withAttempts(attempts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -548,6 +548,8 @@ public class FlowService {
|
|||||||
|
|
||||||
var flowTopologies = flowTopologyRepository.get().findByFlow(tenantId, namespace, id, destinationOnly);
|
var flowTopologies = flowTopologyRepository.get().findByFlow(tenantId, namespace, id, destinationOnly);
|
||||||
|
|
||||||
|
var visitedNodes = new ArrayList<String>();
|
||||||
|
visitedNodes.add(id);
|
||||||
return flowTopologies.stream()
|
return flowTopologies.stream()
|
||||||
// ignore already visited topologies
|
// ignore already visited topologies
|
||||||
.filter(x -> !visitedTopologies.contains(x.uid()))
|
.filter(x -> !visitedTopologies.contains(x.uid()))
|
||||||
@@ -555,8 +557,13 @@ public class FlowService {
|
|||||||
visitedTopologies.add(topology.uid());
|
visitedTopologies.add(topology.uid());
|
||||||
Stream<FlowTopology> subTopologies = Stream
|
Stream<FlowTopology> subTopologies = Stream
|
||||||
.of(topology.getDestination(), topology.getSource())
|
.of(topology.getDestination(), topology.getSource())
|
||||||
|
// ignore already visited nodes
|
||||||
|
.filter(x -> !visitedNodes.contains(x.getId()))
|
||||||
// recursively visit children and parents nodes
|
// recursively visit children and parents nodes
|
||||||
.flatMap(relationNode -> recursiveFlowTopology(visitedTopologies, relationNode.getTenantId(), relationNode.getNamespace(), relationNode.getId(), destinationOnly));
|
.flatMap(relationNode -> {
|
||||||
|
visitedNodes.add(relationNode.getId());
|
||||||
|
return recursiveFlowTopology(visitedTopologies, relationNode.getTenantId(), relationNode.getNamespace(), relationNode.getId(), destinationOnly);
|
||||||
|
});
|
||||||
return Stream.concat(Stream.of(topology), subTopologies);
|
return Stream.concat(Stream.of(topology), subTopologies);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -360,4 +360,41 @@ public interface StorageInterface extends AutoCloseable, Plugin {
|
|||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures the object name length does not exceed the allowed maximum.
|
||||||
|
* If it does, the object name is truncated and a short random prefix is added
|
||||||
|
* to avoid potential name collisions.
|
||||||
|
*
|
||||||
|
* @param uri the URI of the object
|
||||||
|
* @param maxObjectNameLength the maximum allowed length for the object name
|
||||||
|
* @return a normalized URI respecting the length limit
|
||||||
|
* @throws IOException if the URI cannot be rebuilt
|
||||||
|
*/
|
||||||
|
default URI limit(URI uri, int maxObjectNameLength) throws IOException {
|
||||||
|
if (uri == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String path = uri.getPath();
|
||||||
|
String objectName = path.contains("/") ? path.substring(path.lastIndexOf("/") + 1) : path;
|
||||||
|
|
||||||
|
if (objectName.length() > maxObjectNameLength) {
|
||||||
|
objectName = objectName.substring(objectName.length() - maxObjectNameLength + 6);
|
||||||
|
String prefix = org.apache.commons.lang3.RandomStringUtils.secure()
|
||||||
|
.nextAlphanumeric(5)
|
||||||
|
.toLowerCase();
|
||||||
|
|
||||||
|
String newPath = (path.contains("/") ? path.substring(0, path.lastIndexOf("/") + 1) : "")
|
||||||
|
+ prefix + "-" + objectName;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new URI(uri.getScheme(), uri.getHost(), newPath, uri.getFragment());
|
||||||
|
} catch (java.net.URISyntaxException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uri;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class FlowTopologyService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public FlowTopologyGraph namespaceGraph(String tenantId, String namespace) {
|
public FlowTopologyGraph namespaceGraph(String tenantId, String namespace) {
|
||||||
List<FlowTopology> flowTopologies = flowTopologyRepository.findByNamespace(tenantId, namespace);
|
List<FlowTopology> flowTopologies = flowTopologyRepository.findByNamespacePrefix(tenantId, namespace);
|
||||||
|
|
||||||
FlowTopologyGraph graph = this.graph(flowTopologies.stream(), (flowNode -> flowNode));
|
FlowTopologyGraph graph = this.graph(flowTopologies.stream(), (flowNode -> flowNode));
|
||||||
|
|
||||||
|
|||||||
@@ -206,22 +206,22 @@ import static io.kestra.core.utils.Rethrow.throwPredicate;
|
|||||||
tasks:
|
tasks:
|
||||||
- id: send_alert
|
- id: send_alert
|
||||||
type: io.kestra.plugin.notifications.sentry.SentryExecution
|
type: io.kestra.plugin.notifications.sentry.SentryExecution
|
||||||
executionId: "{{ trigger.executionId }}"
|
executionId: "{{ trigger.executionId }}"
|
||||||
transaction: "/execution/id/{{ trigger.executionId }}"
|
transaction: "/execution/id/{{ trigger.executionId }}"
|
||||||
dsn: "{{ secret('SENTRY_DSN') }}"
|
dsn: "{{ secret('SENTRY_DSN') }}"
|
||||||
level: ERROR
|
level: ERROR
|
||||||
|
|
||||||
triggers:
|
triggers:
|
||||||
- id: failed_prod_workflows
|
- id: failed_prod_workflows
|
||||||
type: io.kestra.plugin.core.trigger.Flow
|
type: io.kestra.plugin.core.trigger.Flow
|
||||||
conditions:
|
conditions:
|
||||||
- type: io.kestra.plugin.core.condition.ExecutionStatus
|
- type: io.kestra.plugin.core.condition.ExecutionStatus
|
||||||
in:
|
in:
|
||||||
- FAILED
|
- FAILED
|
||||||
- WARNING
|
- WARNING
|
||||||
- type: io.kestra.plugin.core.condition.ExecutionNamespace
|
- type: io.kestra.plugin.core.condition.ExecutionNamespace
|
||||||
namespace: company.payroll
|
namespace: company.payroll
|
||||||
prefix: false"""
|
prefix: false"""
|
||||||
)
|
)
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import jakarta.validation.constraints.Size;
|
|||||||
description = """
|
description = """
|
||||||
Webhook trigger allows you to create a unique URL that you can use to trigger a Kestra flow execution based on events in another application such as GitHub or Amazon EventBridge. In order to use that URL, you have to add a secret key to secure your webhook URL.
|
Webhook trigger allows you to create a unique URL that you can use to trigger a Kestra flow execution based on events in another application such as GitHub or Amazon EventBridge. In order to use that URL, you have to add a secret key to secure your webhook URL.
|
||||||
|
|
||||||
The URL will then follow the following format: `https://{your_hostname}/api/v1/executions/webhook/{namespace}/{flowId}/{key}`. Replace the templated values according to your workflow setup.
|
The URL will then follow the following format: `https://{your_hostname}/api/v1/{tenant}/executions/webhook/{namespace}/{flowId}/{key}`. Replace the templated values according to your workflow setup.
|
||||||
|
|
||||||
The webhook URL accepts `GET`, `POST`, and `PUT` requests.
|
The webhook URL accepts `GET`, `POST`, and `PUT` requests.
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ import jakarta.validation.constraints.Size;
|
|||||||
@Plugin(
|
@Plugin(
|
||||||
examples = {
|
examples = {
|
||||||
@Example(
|
@Example(
|
||||||
title = "Add a webhook trigger to the current flow with the key `4wjtkzwVGBM9yKnjm3yv8r`; the webhook will be available at the URI `/api/v1/executions/webhook/{namespace}/{flowId}/4wjtkzwVGBM9yKnjm3yv8r`.",
|
title = "Add a webhook trigger to the current flow with the key `4wjtkzwVGBM9yKnjm3yv8r`; the webhook will be available at the URI `/api/v1/{tenant}/executions/webhook/{namespace}/{flowId}/4wjtkzwVGBM9yKnjm3yv8r`.",
|
||||||
code = """
|
code = """
|
||||||
id: webhook_flow
|
id: webhook_flow
|
||||||
namespace: company.team
|
namespace: company.team
|
||||||
|
|||||||
@@ -1,6 +1,31 @@
|
|||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3H5C3.9 3 3 3.9 3 5V19C3 20.1 3.9 21 5 21ZM5 5H19V19H5V5Z" fill="currentColor"/>
|
<g id="debug=Return">
|
||||||
<path d="M17.19 12C17.19 10.5913 16.5227 9.25676 15.4106 8.29291L14.2243 8.73776C15.1881 9.47918 15.7071 10.7396 15.7071 12C15.7071 13.2604 15.1881 14.5208 14.2243 15.2623L15.4106 15.7071C16.5227 14.7433 17.19 13.4087 17.19 12Z" fill="currentColor"/>
|
<g id="Bkg" filter="url(#filter0_i_1386_1709)">
|
||||||
<path d="M9.77575 8.73776L8.58947 8.29291C7.47734 9.25676 6.81006 10.5913 6.81006 12C6.81006 13.4087 7.47734 14.7433 8.58947 15.7071L9.77575 15.2623C8.8119 14.5208 8.2929 13.2604 8.2929 12C8.2929 10.7396 8.8119 9.47918 9.77575 8.73776Z" fill="currentColor"/>
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1709)"/>
|
||||||
<path d="M13.1121 9.77575L12.0742 11.2586L11.481 9.77575H10.5172L11.481 11.9259L9.77575 14.2243H10.962L12 12.7414L12.5931 14.2243H13.557L12.5931 12L14.2243 9.77575H13.1121Z" fill="currentColor"/>
|
</g>
|
||||||
|
<g clip-path="url(#paint1_angular_1386_1709_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
<g id="bug-check-outline">
|
||||||
|
<path id="Union" d="M41.2998 36.0703L38.8701 38.5H46V43.5H44.5V40H38.8701L41.2998 42.4297L40.2402 43.5L36 39.25L40.2402 35L41.2998 36.0703ZM37.333 14.8252L34.5488 17.542C35.8299 18.3961 36.8895 19.5915 37.6582 20.958H42.458V24.375H38.8877C38.9902 24.9386 39.042 25.5023 39.042 26.083V27.792H42.458V31.208H39.042V31.8066C37.7438 32.2678 36.5479 32.9849 35.54 33.9072C35.6253 33.5829 35.625 33.2414 35.625 32.917V26.083C35.6248 22.3079 32.5671 19.2502 28.792 19.25C25.0167 19.25 21.9582 22.3078 21.958 26.083V32.917C21.9581 36.6923 25.0167 39.75 28.792 39.75C30.1585 39.7499 31.5083 39.34 32.6357 38.5713C32.3624 39.5107 32.2081 40.4844 32.208 41.458V42.5684C27.5615 44.2082 22.4029 42.3125 19.9258 38.042H15.125V34.625H18.6953C18.5928 34.0614 18.542 33.4977 18.542 32.917V31.208H15.125V27.792H18.542V26.083C18.542 25.5023 18.5928 24.9386 18.6953 24.375H15.125V20.958H19.9258C20.6945 19.6086 21.7365 18.3961 23.0176 17.542L20.25 14.8252L22.6592 12.417L26.3828 16.124C27.1686 15.9361 27.9378 15.833 28.792 15.833C29.646 15.833 30.432 15.9361 31.2178 16.124L34.9248 12.417L37.333 14.8252ZM32.208 34.625H25.375V31.208H32.208V34.625ZM32.208 27.792H25.375V24.375H32.208V27.792Z" fill="url(#paint2_linear_1386_1709)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1709" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1709"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint1_angular_1386_1709_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1709" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1386_1709" x1="32.4922" y1="35.7292" x2="32.4922" y2="10.4743" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 957 B After Width: | Height: | Size: 5.2 KiB |
@@ -1,4 +1,31 @@
|
|||||||
<svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path
|
<g id="debug=Main">
|
||||||
d="M20,8H17.19C16.74,7.2 16.12,6.5 15.37,6L17,4.41L15.59,3L13.42,5.17C12.96,5.06 12.5,5 12,5C11.5,5 11.05,5.06 10.59,5.17L8.41,3L7,4.41L8.62,6C7.87,6.5 7.26,7.21 6.81,8H4V10H6.09C6.03,10.33 6,10.66 6,11V12H4V14H6V15C6,15.34 6.03,15.67 6.09,16H4V18H6.81C8.47,20.87 12.14,21.84 15,20.18C15.91,19.66 16.67,18.9 17.19,18H20V16H17.91C17.97,15.67 18,15.34 18,15V14H20V12H18V11C18,10.66 17.97,10.33 17.91,10H20V8M16,15A4,4 0 0,1 12,19A4,4 0 0,1 8,15V11A4,4 0 0,1 12,7A4,4 0 0,1 16,11V15M14,10V12H10V10H14M10,14H14V16H10V14Z" fill="currentColor"/>
|
<g id="Bkg" filter="url(#filter0_i_1386_1701)">
|
||||||
</svg>
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1701)"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#paint1_angular_1386_1701_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
<g id="bug-outline">
|
||||||
|
<path id="Vector" d="M42.1666 20.6667H37.3662C36.5975 19.3 35.5383 18.1042 34.2571 17.25L37.0416 14.5337L34.6329 12.125L30.9258 15.8321C30.14 15.6442 29.3541 15.5417 28.5 15.5417C27.6458 15.5417 26.8771 15.6442 26.0912 15.8321L22.3671 12.125L19.9583 14.5337L22.7258 17.25C21.4446 18.1042 20.4025 19.3171 19.6337 20.6667H14.8333V24.0833H18.4037C18.3012 24.6471 18.25 25.2108 18.25 25.7917V27.5H14.8333V30.9167H18.25V32.625C18.25 33.2058 18.3012 33.7696 18.4037 34.3333H14.8333V37.75H19.6337C22.4696 42.6529 28.7391 44.31 33.625 41.4742C35.1796 40.5858 36.4779 39.2875 37.3662 37.75H42.1666V34.3333H38.5962C38.6987 33.7696 38.75 33.2058 38.75 32.625V30.9167H42.1666V27.5H38.75V25.7917C38.75 25.2108 38.6987 24.6471 38.5962 24.0833H42.1666V20.6667ZM35.3333 32.625C35.3333 34.4373 34.6134 36.1754 33.3319 37.4569C32.0504 38.7384 30.3123 39.4583 28.5 39.4583C26.6877 39.4583 24.9496 38.7384 23.6681 37.4569C22.3866 36.1754 21.6666 34.4373 21.6666 32.625V25.7917C21.6666 23.9794 22.3866 22.2413 23.6681 20.9598C24.9496 19.6783 26.6877 18.9583 28.5 18.9583C30.3123 18.9583 32.0504 19.6783 33.3319 20.9598C34.6134 22.2413 35.3333 23.9794 35.3333 25.7917V32.625ZM31.9166 24.0833V27.5H25.0833V24.0833H31.9166ZM25.0833 30.9167H31.9166V34.3333H25.0833V30.9167Z" fill="url(#paint2_linear_1386_1701)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1701" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1701"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint1_angular_1386_1701_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1701" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1386_1701" x1="30.2083" y1="35.1752" x2="30.2083" y2="10.2041" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 645 B After Width: | Height: | Size: 5.3 KiB |
@@ -0,0 +1,50 @@
|
|||||||
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="kv=Delete">
|
||||||
|
<g id="Bkg" filter="url(#filter0_i_1386_1687)">
|
||||||
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1687)"/>
|
||||||
|
</g>
|
||||||
|
<g id="KV">
|
||||||
|
<path id="Vector" d="M32.5532 24L28 14H30.7801L33.6454 20.6525L36.5106 14H39.1915L34.6241 24H32.5532Z" fill="url(#paint1_linear_1386_1687)"/>
|
||||||
|
<path id="Vector_2" d="M17 24V14H19.6099V18.2837H19.6383L23.5248 14H26.617L22.1631 18.7518L26.773 24H23.6667L19.6383 19.4894H19.6099V24H17Z" fill="url(#paint2_linear_1386_1687)"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#paint3_angular_1386_1687_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
<g id="Vector_3">
|
||||||
|
<path d="M47.3949 43.2913L43.7056 46.9807L28.9483 32.2233L32.6376 28.534L47.3949 43.2913Z" fill="url(#paint4_linear_1386_1687)"/>
|
||||||
|
<path d="M32.6376 46.9807L28.9483 43.2913L43.7056 28.534L47.3949 32.2233L32.6376 46.9807Z" fill="url(#paint5_linear_1386_1687)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1687" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1687"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint3_angular_1386_1687_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1687" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1386_1687" x1="28.7989" y1="16.9796" x2="29.988" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1386_1687" x1="26.1471" y1="16.9796" x2="27.3362" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint4_linear_1386_1687" x1="35.4046" y1="42.369" x2="47.3949" y2="30.3786" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint5_linear_1386_1687" x1="35.4046" y1="42.369" x2="47.3949" y2="30.3786" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.3 KiB |
@@ -1,4 +1,45 @@
|
|||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M21.5 19.5L18.5 22.5L15.5 19.5H17.5V15.5H19.5V19.5H21.5Z" fill="currentColor"/>
|
<g id="kv=Get">
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.97119 2.03955C3.86662 2.03955 2.97119 2.93498 2.97119 4.03955V19.9785C2.97119 21.0831 3.86662 21.9785 4.97119 21.9785H13.7188C13.2039 21.0924 12.9091 20.0627 12.9091 18.964C12.9091 15.6454 15.5994 12.9551 18.918 12.9551C19.6608 12.9551 20.3721 13.0899 21.0288 13.3363V4.03955C21.0288 2.93498 20.1334 2.03955 19.0288 2.03955H4.97119ZM13.5582 10.54L12.1582 5.42804H13.4542L14.4582 9.60804H14.5502L15.5582 5.42804H16.8502L15.4542 10.54H13.5582ZM8.57785 8.30004L10.0458 10.54H11.4978L9.72544 7.86056L11.4418 5.42804H10.0258L8.57785 7.54804H8.38985V5.42804H7.14985V10.54H8.38985V8.30004H8.57785Z" fill="currentColor"/>
|
<g id="Bkg" filter="url(#filter0_i_1386_1587)">
|
||||||
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1587)"/>
|
||||||
|
</g>
|
||||||
|
<g id="KV">
|
||||||
|
<path id="Vector" d="M32.5532 24L28 14H30.7801L33.6454 20.6525L36.5106 14H39.1915L34.6241 24H32.5532Z" fill="url(#paint1_linear_1386_1587)"/>
|
||||||
|
<path id="Vector_2" d="M17 24V14H19.6099V18.2837H19.6383L23.5248 14H26.617L22.1631 18.7518L26.773 24H23.6667L19.6383 19.4894H19.6099V24H17Z" fill="url(#paint2_linear_1386_1587)"/>
|
||||||
|
</g>
|
||||||
|
<g id="download">
|
||||||
|
<path id="Vector_3" d="M31 46H45V44H31M45 35H41V29H35V35H31L38 42L45 35Z" fill="url(#paint3_linear_1386_1587)"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#paint4_angular_1386_1587_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1587" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1587"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint4_angular_1386_1587_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1587" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1386_1587" x1="28.7989" y1="16.9796" x2="29.988" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1386_1587" x1="26.1471" y1="16.9796" x2="27.3362" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_1386_1587" x1="38.875" y1="41.75" x2="38.875" y2="27.9375" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 866 B After Width: | Height: | Size: 5.0 KiB |
@@ -1,3 +1,45 @@
|
|||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.97852 4.03955C2.97852 2.93498 3.87395 2.03955 4.97852 2.03955H19.0288C20.1334 2.03955 21.0288 2.93498 21.0288 4.03955V19.957C21.0288 21.0616 20.1334 21.957 19.0288 21.957H4.97852C3.87395 21.957 2.97852 21.0616 2.97852 19.957V4.03955ZM7.00647 14.001C7.00647 13.4487 7.45419 13.001 8.00647 13.001C8.55875 13.001 9.00647 13.4487 9.00647 14.001C9.00647 14.5533 8.55875 15.001 8.00647 15.001C7.45419 15.001 7.00647 14.5533 7.00647 14.001ZM8.00647 16.9235C7.45419 16.9235 7.00647 17.3712 7.00647 17.9235C7.00647 18.4758 7.45419 18.9235 8.00647 18.9235C8.55875 18.9235 9.00647 18.4758 9.00647 17.9235C9.00647 17.3712 8.55875 16.9235 8.00647 16.9235ZM10.0037 14.001C10.0037 13.4487 10.4514 13.001 11.0037 13.001H15.988C16.5403 13.001 16.988 13.4487 16.988 14.001C16.988 14.5533 16.5403 15.001 15.988 15.001H11.0037C10.4514 15.001 10.0037 14.5533 10.0037 14.001ZM11.0037 16.9235C10.4514 16.9235 10.0037 17.3712 10.0037 17.9235C10.0037 18.4758 10.4514 18.9235 11.0037 18.9235H15.988C16.5403 18.9235 16.988 18.4758 16.988 17.9235C16.988 17.3712 16.5403 16.9235 15.988 16.9235H11.0037ZM13.5618 10.54L12.1618 5.42804H13.4578L14.4618 9.60804H14.5538L15.5618 5.42804H16.8538L15.4578 10.54H13.5618ZM8.5815 8.30004L10.0495 10.54H11.5015L9.7291 7.86056L11.4455 5.42804H10.0295L8.5815 7.54804H8.3935V5.42804H7.1535V10.54H8.3935V8.30004H8.5815Z" fill="currentColor"/>
|
<g id="kv=Get​Keys">
|
||||||
|
<g id="Bkg" filter="url(#filter0_i_1386_1593)">
|
||||||
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1593)"/>
|
||||||
|
</g>
|
||||||
|
<g id="KV">
|
||||||
|
<path id="Vector" d="M32.5532 24L28 14H30.7801L33.6454 20.6525L36.5106 14H39.1915L34.6241 24H32.5532Z" fill="url(#paint1_linear_1386_1593)"/>
|
||||||
|
<path id="Vector_2" d="M17 24V14H19.6099V18.2837H19.6383L23.5248 14H26.617L22.1631 18.7518L26.773 24H23.6667L19.6383 19.4894H19.6099V24H17Z" fill="url(#paint2_linear_1386_1593)"/>
|
||||||
|
</g>
|
||||||
|
<g id="database-search-outline">
|
||||||
|
<path id="Vector_3" d="M37 44.95C33.77 44.72 32 43.45 32 43V40.77C33.13 41.32 34.5 41.69 36 41.87C36 41.21 36.04 40.54 36.21 39.89C34.5 39.67 32.97 39.16 32 38.45V35.64C33.43 36.45 35.5 36.97 37.82 37C37.85 36.97 37.87 36.93 37.9 36.9C40.1 34.71 43.5 34.41 46 36.03V33C46 30.79 42.42 29 38 29C33.58 29 30 30.79 30 33V43C30 45.21 33.59 47 38 47C38.34 47 38.68 47 39 46.97C38.62 46.72 38.24 46.44 37.9 46.1C37.55 45.74 37.25 45.36 37 44.95ZM38 31C41.87 31 44 32.5 44 33C44 33.5 41.87 35 38 35C34.13 35 32 33.5 32 33C32 32.5 34.13 31 38 31ZM46.31 43.9C46.75 43.21 47 42.38 47 41.5C47 39 45 37 42.5 37C40 37 38 39 38 41.5C38 44 40 46 42.5 46C43.37 46 44.19 45.75 44.88 45.32L48 48.39L49.39 47L46.31 43.9ZM42.5 44C41.12 44 40 42.88 40 41.5C40 40.12 41.12 39 42.5 39C43.88 39 45 40.12 45 41.5C45 42.88 43.88 44 42.5 44Z" fill="url(#paint3_linear_1386_1593)"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#paint4_angular_1386_1593_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1593" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1593"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint4_angular_1386_1593_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1593" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1386_1593" x1="28.7989" y1="16.9796" x2="29.988" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1386_1593" x1="26.1471" y1="16.9796" x2="27.3362" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_1386_1593" x1="40.9069" y1="43.5425" x2="40.9069" y2="27.7881" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 5.7 KiB |
@@ -0,0 +1,45 @@
|
|||||||
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="kv=Purge​K​V">
|
||||||
|
<g id="Bkg" filter="url(#filter0_i_1386_1599)">
|
||||||
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1599)"/>
|
||||||
|
</g>
|
||||||
|
<g id="delete-variant">
|
||||||
|
<path id="Vector" d="M47.03 29L44 46.31C43.83 47.27 43 48 42 48H34C33 48 32.17 47.27 32 46.31L28.97 29H47.03ZM31.36 31L34 46H42L44.64 31H31.36ZM35 44V40H39V44H35ZM39 39.18L35.82 36L39 32.82L42.18 36L39 39.18Z" fill="url(#paint1_linear_1386_1599)"/>
|
||||||
|
</g>
|
||||||
|
<g id="KV">
|
||||||
|
<path id="Vector_2" d="M32.5532 24L28 14H30.7801L33.6454 20.6525L36.5106 14H39.1915L34.6241 24H32.5532Z" fill="url(#paint2_linear_1386_1599)"/>
|
||||||
|
<path id="Vector_3" d="M17 24V14H19.6099V18.2837H19.6383L23.5248 14H26.617L22.1631 18.7518L26.773 24H23.6667L19.6383 19.4894H19.6099V24H17Z" fill="url(#paint3_linear_1386_1599)"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#paint4_angular_1386_1599_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1599" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1599"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint4_angular_1386_1599_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1599" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1386_1599" x1="39.1287" y1="43.25" x2="39.1287" y2="27.8125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1386_1599" x1="28.7989" y1="16.9796" x2="29.988" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_1386_1599" x1="26.1471" y1="16.9796" x2="27.3362" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 5.2 KiB |
@@ -1,4 +1,43 @@
|
|||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.97119 2.03955C3.86662 2.03955 2.97119 2.93498 2.97119 4.03955V19.9785C2.97119 21.0831 3.86662 21.9785 4.97119 21.9785H13.7188C13.2039 21.0924 12.9091 20.0627 12.9091 18.964C12.9091 15.6454 15.5994 12.9551 18.918 12.9551C19.6608 12.9551 20.3721 13.0899 21.0288 13.3363V4.03955C21.0288 2.93498 20.1334 2.03955 19.0288 2.03955H4.97119ZM13.5582 10.54L12.1582 5.42804H13.4542L14.4582 9.60804H14.5502L15.5582 5.42804H16.8502L15.4542 10.54H13.5582ZM8.57785 8.30004L10.0458 10.54H11.4978L9.72544 7.86056L11.4418 5.42804H10.0258L8.57785 7.54804H8.38984V5.42804H7.14985V10.54H8.38984V8.30004H8.57785Z" fill="currentColor"/>
|
<g id="kv=Set">
|
||||||
<path d="M19.7985 18.4785H21.7985L18.7985 15.4785L15.7985 18.4785H17.7985V22.4785H19.7985V18.4785Z" fill="currentColor"/>
|
<g id="Bkg" filter="url(#filter0_i_1386_1605)">
|
||||||
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1605)"/>
|
||||||
|
</g>
|
||||||
|
<path id="Vector" d="M45.8388 31.7499C46.1564 31.3317 46.0799 30.724 45.6729 30.4318L43.2165 28.5663C42.8257 28.2526 42.2198 28.342 41.9022 28.7603L40.4024 30.7242L44.339 33.7138M30.5324 43.7314L30.9735 47.237L34.4689 46.721L43.4757 34.8506L39.5391 31.861L30.5324 43.7314Z" fill="url(#paint1_linear_1386_1605)"/>
|
||||||
|
<g id="KV">
|
||||||
|
<path id="Vector_2" d="M32.5532 24L28 14H30.7801L33.6454 20.6525L36.5106 14H39.1915L34.6241 24H32.5532Z" fill="url(#paint2_linear_1386_1605)"/>
|
||||||
|
<path id="Vector_3" d="M17 24V14H19.6099V18.2837H19.6383L23.5248 14H26.617L22.1631 18.7518L26.773 24H23.6667L19.6383 19.4894H19.6099V24H17Z" fill="url(#paint3_linear_1386_1605)"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#paint4_angular_1386_1605_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1605" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1605"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint4_angular_1386_1605_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1605" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1386_1605" x1="39.534" y1="38.0057" x2="45.0867" y2="29.2374" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1386_1605" x1="28.7989" y1="16.9796" x2="29.988" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_1386_1605" x1="26.1471" y1="16.9796" x2="27.3362" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 899 B After Width: | Height: | Size: 5.1 KiB |
@@ -1,3 +1,45 @@
|
|||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.97852 4.03955C2.97852 2.93498 3.87395 2.03955 4.97852 2.03955H19.0288C20.1334 2.03955 21.0288 2.93498 21.0288 4.03955V19.957C21.0288 21.0616 20.1334 21.957 19.0288 21.957H4.97852C3.87395 21.957 2.97852 21.0616 2.97852 19.957V4.03955ZM13.5618 14.5L12.1618 9.388H13.4578L14.4618 13.568H14.5538L15.5618 9.388H16.8538L15.4578 14.5H13.5618ZM8.5815 12.26L10.0495 14.5H11.5015L9.7291 11.8205L11.4455 9.388H10.0295L8.5815 11.508H8.3935V9.388H7.1535V14.5H8.3935V12.26H8.5815Z" fill="currentColor"/>
|
<g id="kv=Main">
|
||||||
|
<g id="Bkg" filter="url(#filter0_i_1386_1574)">
|
||||||
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1574)"/>
|
||||||
|
</g>
|
||||||
|
<g id="database">
|
||||||
|
<path id="Vector" d="M38 29C33.58 29 30 30.79 30 33C30 35.21 33.58 37 38 37C42.42 37 46 35.21 46 33C46 30.79 42.42 29 38 29ZM30 35V38C30 40.21 33.58 42 38 42C42.42 42 46 40.21 46 38V35C46 37.21 42.42 39 38 39C33.58 39 30 37.21 30 35ZM30 40V43C30 45.21 33.58 47 38 47C42.42 47 46 45.21 46 43V40C46 42.21 42.42 44 38 44C33.58 44 30 42.21 30 40Z" fill="url(#paint1_linear_1386_1574)"/>
|
||||||
|
</g>
|
||||||
|
<g id="KV">
|
||||||
|
<path id="Vector_2" d="M32.5532 24L28 14H30.7801L33.6454 20.6525L36.5106 14H39.1915L34.6241 24H32.5532Z" fill="url(#paint2_linear_1386_1574)"/>
|
||||||
|
<path id="Vector_3" d="M17 24V14H19.6099V18.2837H19.6383L23.5248 14H26.617L22.1631 18.7518L26.773 24H23.6667L19.6383 19.4894H19.6099V24H17Z" fill="url(#paint3_linear_1386_1574)"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#paint4_angular_1386_1574_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1574" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1574"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint4_angular_1386_1574_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1574" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1386_1574" x1="39" y1="42.5" x2="39" y2="27.875" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint2_linear_1386_1574" x1="28.7989" y1="16.9796" x2="29.988" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint3_linear_1386_1574" x1="26.1471" y1="16.9796" x2="27.3362" y2="28.4007" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#EEDBFF"/>
|
||||||
|
<stop offset="0.774038" stop-color="#FBF8FF"/>
|
||||||
|
<stop offset="1" stop-color="#F7E7FF"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 653 B After Width: | Height: | Size: 5.2 KiB |
@@ -1,6 +1,31 @@
|
|||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3H5C3.9 3 3 3.9 3 5V19C3 20.1 3.9 21 5 21ZM5 5H19V19H5V5Z" fill="currentColor"/>
|
<g id="output=Output​Values">
|
||||||
<path d="M17.19 12C17.19 10.5913 16.5227 9.25676 15.4106 8.29291L14.2243 8.73776C15.1881 9.47918 15.7071 10.7396 15.7071 12C15.7071 13.2604 15.1881 14.5208 14.2243 15.2623L15.4106 15.7071C16.5227 14.7433 17.19 13.4087 17.19 12Z" fill="currentColor"/>
|
<g id="Bkg" filter="url(#filter0_i_1386_1788)">
|
||||||
<path d="M9.77575 8.73776L8.58947 8.29291C7.47734 9.25676 6.81006 10.5913 6.81006 12C6.81006 13.4087 7.47734 14.7433 8.58947 15.7071L9.77575 15.2623C8.8119 14.5208 8.2929 13.2604 8.2929 12C8.2929 10.7396 8.8119 9.47918 9.77575 8.73776Z" fill="currentColor"/>
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1788)"/>
|
||||||
<path d="M13.1121 9.77575L12.0742 11.2586L11.481 9.77575H10.5172L11.481 11.9259L9.77575 14.2243H10.962L12 12.7414L12.5931 14.2243H13.557L12.5931 12L14.2243 9.77575H13.1121Z" fill="currentColor"/>
|
</g>
|
||||||
</svg>
|
<g id="table-arrow-right">
|
||||||
|
<path id="Vector" d="M15.8334 14.125H39.75C41.6463 14.125 43.1667 15.6625 43.1667 17.5417V29.6367C40.5188 29.1925 37.905 29.8075 35.7867 31.2083H29.5V38.0417H31.345C31.1571 39.2033 31.1571 40.3479 31.345 41.4583H15.8334C13.9542 41.4583 12.4167 39.9379 12.4167 38.0417V17.5417C12.4167 15.6625 13.9542 14.125 15.8334 14.125ZM15.8334 20.9583V27.7917H26.0834V20.9583H15.8334ZM29.5 20.9583V27.7917H39.75V20.9583H29.5ZM15.8334 31.2083V38.0417H26.0834V31.2083H15.8334ZM42.21 44.875V41.4583H35.3767V38.0417H42.21V34.625L47.335 39.75L42.21 44.875Z" fill="url(#paint1_linear_1386_1788)"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#paint2_angular_1386_1788_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1788" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1788"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint2_angular_1386_1788_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1788" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1386_1788" x1="32.0583" y1="37.1875" x2="32.0583" y2="12.2031" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 957 B After Width: | Height: | Size: 4.9 KiB |
@@ -1,6 +1,31 @@
|
|||||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
<svg width="57" height="57" viewBox="0 0 57 57" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M5 21H19C20.1 21 21 20.1 21 19V5C21 3.9 20.1 3 19 3H5C3.9 3 3 3.9 3 5V19C3 20.1 3.9 21 5 21ZM5 5H19V19H5V5Z" fill="currentColor"/>
|
<g id="output=Main">
|
||||||
<path d="M17.19 12C17.19 10.5913 16.5227 9.25676 15.4106 8.29291L14.2243 8.73776C15.1881 9.47918 15.7071 10.7396 15.7071 12C15.7071 13.2604 15.1881 14.5208 14.2243 15.2623L15.4106 15.7071C16.5227 14.7433 17.19 13.4087 17.19 12Z" fill="currentColor"/>
|
<g id="Bkg" filter="url(#filter0_i_1386_1783)">
|
||||||
<path d="M9.77575 8.73776L8.58947 8.29291C7.47734 9.25676 6.81006 10.5913 6.81006 12C6.81006 13.4087 7.47734 14.7433 8.58947 15.7071L9.77575 15.2623C8.8119 14.5208 8.2929 13.2604 8.2929 12C8.2929 10.7396 8.8119 9.47918 9.77575 8.73776Z" fill="currentColor"/>
|
<path d="M0 14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57H14.25C6.37994 57 0 50.6201 0 42.75V14.25Z" fill="url(#paint0_linear_1386_1783)"/>
|
||||||
<path d="M13.1121 9.77575L12.0742 11.2586L11.481 9.77575H10.5172L11.481 11.9259L9.77575 14.2243H10.962L12 12.7414L12.5931 14.2243H13.557L12.5931 12L14.2243 9.77575H13.1121Z" fill="currentColor"/>
|
</g>
|
||||||
</svg>
|
<g id="table">
|
||||||
|
<path id="Vector" d="M16.8577 14.2791H40.7744C41.6805 14.2791 42.5496 14.639 43.1903 15.2798C43.8311 15.9205 44.191 16.7896 44.191 17.6957V38.1957C44.191 39.1019 43.8311 39.9709 43.1903 40.6117C42.5496 41.2524 41.6805 41.6124 40.7744 41.6124H16.8577C15.9516 41.6124 15.0825 41.2524 14.4418 40.6117C13.801 39.9709 13.441 39.1019 13.441 38.1957V17.6957C13.441 16.7896 13.801 15.9205 14.4418 15.2798C15.0825 14.639 15.9516 14.2791 16.8577 14.2791ZM16.8577 21.1124V27.9457H27.1077V21.1124H16.8577ZM30.5244 21.1124V27.9457H40.7744V21.1124H30.5244ZM16.8577 31.3624V38.1957H27.1077V31.3624H16.8577ZM30.5244 31.3624V38.1957H40.7744V31.3624H30.5244Z" fill="url(#paint1_linear_1386_1783)"/>
|
||||||
|
</g>
|
||||||
|
<g clip-path="url(#paint2_angular_1386_1783_clip_path)" data-figma-skip-parse="true"><g transform="matrix(0 0.0285 -0.0285 0 28.5 28.5)"><foreignObject x="-1035.09" y="-1035.09" width="2070.18" height="2070.18"><div xmlns="http://www.w3.org/1999/xhtml" style="background:conic-gradient(from 90deg,rgba(181, 231, 255, 1) 0deg,rgba(241, 117, 255, 1) 72.6923deg,rgba(241, 117, 255, 0.1) 360deg);height:100%;width:100%;opacity:1"></div></foreignObject></g></g><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z" data-figma-gradient-fill="{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"stopsVar":[{"color":{"r":0.71089994907379150,"g":0.90845167636871338,"b":1.0,"a":1.0},"position":0.0},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":1.0},"position":0.20192307233810425},{"color":{"r":0.94509804248809814,"g":0.45882353186607361,"b":1.0,"a":0.10000000149011612},"position":1.0}],"transform":{"m00":3.4902435166328386e-15,"m01":-57.0,"m02":57.0,"m10":57.0,"m11":3.4902435166328386e-15,"m12":0.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_i_1386_1783" x="0" y="0" width="57" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.75 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1386_1783"/>
|
||||||
|
</filter>
|
||||||
|
<clipPath id="paint2_angular_1386_1783_clip_path"><path id="Stroke" d="M42.75 54.625V57H14.25V54.625H42.75ZM54.625 42.75V14.25C54.625 7.69162 49.3084 2.375 42.75 2.375H14.25C7.69162 2.375 2.375 7.69162 2.375 14.25V42.75C2.375 49.3084 7.69162 54.625 14.25 54.625V57C6.37994 57 0 50.6201 0 42.75V14.25C0 6.37994 6.37994 0 14.25 0H42.75C50.6201 0 57 6.37994 57 14.25V42.75C57 50.6201 50.6201 57 42.75 57V54.625C49.3084 54.625 54.625 49.3084 54.625 42.75Z"/></clipPath><linearGradient id="paint0_linear_1386_1783" x1="52.25" y1="48.6875" x2="8.3125" y2="7.125" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#01000B"/>
|
||||||
|
<stop offset="1" stop-color="#520188"/>
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient id="paint1_linear_1386_1783" x1="30.7379" y1="34.7791" x2="30.7379" y2="12.5707" gradientUnits="userSpaceOnUse">
|
||||||
|
<stop stop-color="#91F4FF"/>
|
||||||
|
<stop offset="0.5" stop-color="#D67EE2"/>
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 957 B After Width: | Height: | Size: 4.9 KiB |
@@ -49,6 +49,32 @@ public abstract class AbstractFlowTopologyRepositoryTest {
|
|||||||
assertThat(list.size()).isEqualTo(1);
|
assertThat(list.size()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void findByNamespacePrefix() {
|
||||||
|
String tenant = TestsUtils.randomTenant(this.getClass().getSimpleName());
|
||||||
|
|
||||||
|
flowTopologyRepository.save(
|
||||||
|
createSimpleFlowTopology(tenant, "flow-a", "flow-b", "io.kestra.tests")
|
||||||
|
);
|
||||||
|
|
||||||
|
flowTopologyRepository.save(
|
||||||
|
createSimpleFlowTopology(tenant, "flow-x", "flow-y", "io.kestra.tests.sub")
|
||||||
|
);
|
||||||
|
|
||||||
|
flowTopologyRepository.save(
|
||||||
|
createSimpleFlowTopology(tenant, "flow-p", "flow-q", "io.other.namespace")
|
||||||
|
);
|
||||||
|
|
||||||
|
List<FlowTopology> list = flowTopologyRepository.findByNamespacePrefix(tenant, "io.kestra.tests");
|
||||||
|
|
||||||
|
assertThat(list)
|
||||||
|
.extracting(ft -> ft.getSource().getNamespace())
|
||||||
|
.contains("io.kestra.tests", "io.kestra.tests.sub")
|
||||||
|
.doesNotContain("io.other.namespace");
|
||||||
|
|
||||||
|
assertThat(list.size()).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void findByNamespace() {
|
void findByNamespace() {
|
||||||
String tenant = TestsUtils.randomTenant(this.getClass().getSimpleName());
|
String tenant = TestsUtils.randomTenant(this.getClass().getSimpleName());
|
||||||
|
|||||||
@@ -267,6 +267,12 @@ public abstract class AbstractRunnerTest {
|
|||||||
multipleConditionTriggerCaseTest.flowTriggerMultiplePreconditions();
|
multipleConditionTriggerCaseTest.flowTriggerMultiplePreconditions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@LoadFlows({"flows/valids/flow-trigger-multiple-conditions-flow-a.yaml", "flows/valids/flow-trigger-multiple-conditions-flow-listen.yaml"})
|
||||||
|
void flowTriggerMultipleConditions() throws Exception {
|
||||||
|
multipleConditionTriggerCaseTest.flowTriggerMultipleConditions();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@LoadFlows({"flows/valids/each-null.yaml"})
|
@LoadFlows({"flows/valids/each-null.yaml"})
|
||||||
void eachWithNull() throws Exception {
|
void eachWithNull() throws Exception {
|
||||||
|
|||||||
@@ -445,6 +445,7 @@ class ExecutionServiceTest {
|
|||||||
|
|
||||||
assertThat(killed.getState().getCurrent()).isEqualTo(State.Type.CANCELLED);
|
assertThat(killed.getState().getCurrent()).isEqualTo(State.Type.CANCELLED);
|
||||||
assertThat(killed.findTaskRunsByTaskId("pause").getFirst().getState().getCurrent()).isEqualTo(State.Type.KILLED);
|
assertThat(killed.findTaskRunsByTaskId("pause").getFirst().getState().getCurrent()).isEqualTo(State.Type.KILLED);
|
||||||
|
assertThat(killed.findTaskRunsByTaskId("pause").getFirst().getAttempts().getFirst().getState().getCurrent()).isEqualTo(State.Type.KILLED);
|
||||||
assertThat(killed.getState().getHistories()).hasSize(5);
|
assertThat(killed.getState().getHistories()).hasSize(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,4 +212,24 @@ public class MultipleConditionTriggerCaseTest {
|
|||||||
e -> e.getState().getCurrent().equals(Type.SUCCESS),
|
e -> e.getState().getCurrent().equals(Type.SUCCESS),
|
||||||
MAIN_TENANT, "io.kestra.tests.trigger.multiple.preconditions", "flow-trigger-multiple-preconditions-flow-listen", Duration.ofSeconds(1)));
|
MAIN_TENANT, "io.kestra.tests.trigger.multiple.preconditions", "flow-trigger-multiple-preconditions-flow-listen", Duration.ofSeconds(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void flowTriggerMultipleConditions() throws TimeoutException, QueueException {
|
||||||
|
Execution execution = runnerUtils.runOne(MAIN_TENANT, "io.kestra.tests.trigger.multiple.conditions",
|
||||||
|
"flow-trigger-multiple-conditions-flow-a");
|
||||||
|
assertThat(execution.getTaskRunList().size()).isEqualTo(1);
|
||||||
|
assertThat(execution.getState().getCurrent()).isEqualTo(State.Type.SUCCESS);
|
||||||
|
|
||||||
|
// trigger is done
|
||||||
|
Execution triggerExecution = runnerUtils.awaitFlowExecution(
|
||||||
|
e -> e.getState().getCurrent().equals(Type.SUCCESS),
|
||||||
|
MAIN_TENANT, "io.kestra.tests.trigger.multiple.conditions", "flow-trigger-multiple-conditions-flow-listen");
|
||||||
|
executionRepository.delete(triggerExecution);
|
||||||
|
assertThat(triggerExecution.getTaskRunList().size()).isEqualTo(1);
|
||||||
|
assertThat(triggerExecution.getState().getCurrent()).isEqualTo(State.Type.SUCCESS);
|
||||||
|
|
||||||
|
// we assert that we didn't have any other flow triggered
|
||||||
|
assertThrows(RuntimeException.class, () -> runnerUtils.awaitFlowExecution(
|
||||||
|
e -> e.getState().getCurrent().equals(Type.SUCCESS),
|
||||||
|
MAIN_TENANT, "io.kestra.tests.trigger.multiple.conditions", "flow-trigger-multiple-conditions-flow-listen", Duration.ofSeconds(1)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,20 +12,24 @@ import io.kestra.core.queues.QueueInterface;
|
|||||||
import io.kestra.core.repositories.FlowRepositoryInterface;
|
import io.kestra.core.repositories.FlowRepositoryInterface;
|
||||||
import io.kestra.core.runners.ConcurrencyLimit;
|
import io.kestra.core.runners.ConcurrencyLimit;
|
||||||
import io.kestra.core.runners.RunnerUtils;
|
import io.kestra.core.runners.RunnerUtils;
|
||||||
|
import io.kestra.core.utils.TestsUtils;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.inject.Named;
|
import jakarta.inject.Named;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.TestInstance;
|
import org.junit.jupiter.api.TestInstance;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
import static io.kestra.core.utils.Rethrow.throwRunnable;
|
import static io.kestra.core.utils.Rethrow.throwRunnable;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@KestraTest(startRunner = true)
|
@KestraTest(startRunner = true)
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
@@ -54,14 +58,29 @@ class ConcurrencyLimitServiceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@LoadFlows("flows/valids/flow-concurrency-queue.yml")
|
@LoadFlows("flows/valids/flow-concurrency-queue.yml")
|
||||||
void unqueueExecution() throws QueueException, TimeoutException {
|
void unqueueExecution() throws QueueException, TimeoutException, InterruptedException {
|
||||||
// run a first flow so the second is queued
|
// run a first flow so the second is queued
|
||||||
runnerUtils.runOneUntilRunning(TENANT_ID, TESTS_FLOW_NS, "flow-concurrency-queue");
|
Execution first = runnerUtils.runOneUntilRunning(TENANT_ID, TESTS_FLOW_NS, "flow-concurrency-queue");
|
||||||
Execution result = runUntilQueued(TESTS_FLOW_NS, "flow-concurrency-queue");
|
Execution result = runUntilQueued(TESTS_FLOW_NS, "flow-concurrency-queue");
|
||||||
assertThat(result.getState().isQueued()).isTrue();
|
assertThat(result.getState().isQueued()).isTrue();
|
||||||
|
|
||||||
|
// await for the execution to be terminated
|
||||||
|
CountDownLatch terminated = new CountDownLatch(2);
|
||||||
|
Flux<Execution> receive = TestsUtils.receive(executionQueue, (either) -> {
|
||||||
|
if (either.getLeft().getId().equals(first.getId()) && either.getLeft().getState().isTerminated()) {
|
||||||
|
terminated.countDown();
|
||||||
|
}
|
||||||
|
if (either.getLeft().getId().equals(result.getId()) && either.getLeft().getState().isTerminated()) {
|
||||||
|
terminated.countDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Execution unqueued = concurrencyLimitService.unqueue(result, State.Type.RUNNING);
|
Execution unqueued = concurrencyLimitService.unqueue(result, State.Type.RUNNING);
|
||||||
assertThat(unqueued.getState().isRunning()).isTrue();
|
assertThat(unqueued.getState().isRunning()).isTrue();
|
||||||
|
executionQueue.emit(unqueued);
|
||||||
|
|
||||||
|
assertTrue(terminated.await(10, TimeUnit.SECONDS));
|
||||||
|
receive.blockLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -73,7 +92,6 @@ class ConcurrencyLimitServiceTest {
|
|||||||
assertThat(limit.get().getTenantId()).isEqualTo(execution.getTenantId());
|
assertThat(limit.get().getTenantId()).isEqualTo(execution.getTenantId());
|
||||||
assertThat(limit.get().getNamespace()).isEqualTo(execution.getNamespace());
|
assertThat(limit.get().getNamespace()).isEqualTo(execution.getNamespace());
|
||||||
assertThat(limit.get().getFlowId()).isEqualTo(execution.getFlowId());
|
assertThat(limit.get().getFlowId()).isEqualTo(execution.getFlowId());
|
||||||
assertThat(limit.get().getRunning()).isEqualTo(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -3,12 +3,16 @@ package io.kestra.core.topologies;
|
|||||||
import io.kestra.core.exceptions.FlowProcessingException;
|
import io.kestra.core.exceptions.FlowProcessingException;
|
||||||
import io.kestra.core.junit.annotations.KestraTest;
|
import io.kestra.core.junit.annotations.KestraTest;
|
||||||
import io.kestra.core.models.flows.FlowWithSource;
|
import io.kestra.core.models.flows.FlowWithSource;
|
||||||
|
import io.kestra.core.models.topologies.FlowNode;
|
||||||
import io.kestra.core.models.topologies.FlowTopology;
|
import io.kestra.core.models.topologies.FlowTopology;
|
||||||
|
import io.kestra.core.models.topologies.FlowTopologyGraph;
|
||||||
import io.kestra.core.repositories.FlowRepositoryInterface;
|
import io.kestra.core.repositories.FlowRepositoryInterface;
|
||||||
import io.kestra.core.repositories.FlowTopologyRepositoryInterface;
|
import io.kestra.core.repositories.FlowTopologyRepositoryInterface;
|
||||||
import io.kestra.core.services.FlowService;
|
import io.kestra.core.services.FlowService;
|
||||||
import io.kestra.core.utils.IdUtils;
|
import io.kestra.core.utils.IdUtils;
|
||||||
|
import io.kestra.plugin.core.execution.AssertTest;
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.validation.constraints.AssertTrue;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@@ -56,15 +60,8 @@ public class FlowTopologyTest {
|
|||||||
|
|
||||||
// When
|
// When
|
||||||
computeAndSaveTopologies(List.of(child, parent, unrelatedFlow));
|
computeAndSaveTopologies(List.of(child, parent, unrelatedFlow));
|
||||||
System.out.println();
|
|
||||||
flowTopologyRepository.findAll(tenantId).forEach(topology -> {
|
|
||||||
System.out.println(FlowTopologyTestData.of(topology));
|
|
||||||
});
|
|
||||||
|
|
||||||
var dependencies = flowService.findDependencies(tenantId, "io.kestra.unittest", parent.getId(), false, true);
|
var dependencies = flowService.findDependencies(tenantId, "io.kestra.unittest", parent.getId(), false, true);
|
||||||
flowTopologyRepository.findAll(tenantId).forEach(topology -> {
|
|
||||||
System.out.println(FlowTopologyTestData.of(topology));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assertThat(dependencies.map(FlowTopologyTestData::of))
|
assertThat(dependencies.map(FlowTopologyTestData::of))
|
||||||
@@ -123,16 +120,8 @@ public class FlowTopologyTest {
|
|||||||
|
|
||||||
// When
|
// When
|
||||||
computeAndSaveTopologies(List.of(subChild, child, superParent, parent, unrelatedFlow));
|
computeAndSaveTopologies(List.of(subChild, child, superParent, parent, unrelatedFlow));
|
||||||
System.out.println();
|
|
||||||
flowTopologyRepository.findAll(tenantId).forEach(topology -> {
|
|
||||||
System.out.println(FlowTopologyTestData.of(topology));
|
|
||||||
});
|
|
||||||
System.out.println();
|
|
||||||
|
|
||||||
var dependencies = flowService.findDependencies(tenantId, "io.kestra.unittest", parent.getId(), false, true);
|
var dependencies = flowService.findDependencies(tenantId, "io.kestra.unittest", parent.getId(), false, true);
|
||||||
flowTopologyRepository.findAll(tenantId).forEach(topology -> {
|
|
||||||
System.out.println(FlowTopologyTestData.of(topology));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assertThat(dependencies.map(FlowTopologyTestData::of))
|
assertThat(dependencies.map(FlowTopologyTestData::of))
|
||||||
@@ -180,16 +169,8 @@ public class FlowTopologyTest {
|
|||||||
// When
|
// When
|
||||||
computeAndSaveTopologies(List.of(triggeredFlowOne, triggeredFlowTwo));
|
computeAndSaveTopologies(List.of(triggeredFlowOne, triggeredFlowTwo));
|
||||||
|
|
||||||
flowTopologyRepository.findAll(tenantId).forEach(topology -> {
|
|
||||||
System.out.println(FlowTopologyTestData.of(topology));
|
|
||||||
});
|
|
||||||
|
|
||||||
var dependencies = flowService.findDependencies(tenantId, "io.kestra.unittest", triggeredFlowTwo.getId(), false, true).toList();
|
var dependencies = flowService.findDependencies(tenantId, "io.kestra.unittest", triggeredFlowTwo.getId(), false, true).toList();
|
||||||
|
|
||||||
flowTopologyRepository.findAll(tenantId).forEach(topology -> {
|
|
||||||
System.out.println(FlowTopologyTestData.of(topology));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assertThat(dependencies.stream().map(FlowTopologyTestData::of))
|
assertThat(dependencies.stream().map(FlowTopologyTestData::of))
|
||||||
.containsExactlyInAnyOrder(
|
.containsExactlyInAnyOrder(
|
||||||
@@ -211,7 +192,7 @@ public class FlowTopologyTest {
|
|||||||
- id: a
|
- id: a
|
||||||
type: BOOL
|
type: BOOL
|
||||||
defaults: true
|
defaults: true
|
||||||
|
|
||||||
- id: b
|
- id: b
|
||||||
type: BOOL
|
type: BOOL
|
||||||
defaults: "{{ inputs.a == true }}"
|
defaults: "{{ inputs.a == true }}"
|
||||||
@@ -251,15 +232,8 @@ public class FlowTopologyTest {
|
|||||||
|
|
||||||
// When
|
// When
|
||||||
computeAndSaveTopologies(List.of(child, parent, unrelatedFlow));
|
computeAndSaveTopologies(List.of(child, parent, unrelatedFlow));
|
||||||
System.out.println();
|
|
||||||
flowTopologyRepository.findAll(tenantId).forEach(topology -> {
|
|
||||||
System.out.println(FlowTopologyTestData.of(topology));
|
|
||||||
});
|
|
||||||
|
|
||||||
var dependencies = flowService.findDependencies(tenantId, "io.kestra.unittest", parent.getId(), false, true);
|
var dependencies = flowService.findDependencies(tenantId, "io.kestra.unittest", parent.getId(), false, true);
|
||||||
flowTopologyRepository.findAll(tenantId).forEach(topology -> {
|
|
||||||
System.out.println(FlowTopologyTestData.of(topology));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Then
|
// Then
|
||||||
assertThat(dependencies.map(FlowTopologyTestData::of))
|
assertThat(dependencies.map(FlowTopologyTestData::of))
|
||||||
@@ -268,6 +242,63 @@ public class FlowTopologyTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testNamespaceGraph() throws FlowProcessingException {
|
||||||
|
var tenantId = randomTenantId();
|
||||||
|
|
||||||
|
var subChild = flowService.importFlow(tenantId,
|
||||||
|
"""
|
||||||
|
id: sub_child
|
||||||
|
namespace: io.kestra.unittest.sub
|
||||||
|
tasks:
|
||||||
|
- id: log
|
||||||
|
type: io.kestra.plugin.core.log.Log
|
||||||
|
message: Sub Child
|
||||||
|
""");
|
||||||
|
|
||||||
|
var child = flowService.importFlow(tenantId,
|
||||||
|
"""
|
||||||
|
id: child
|
||||||
|
namespace: io.kestra.unittest
|
||||||
|
tasks:
|
||||||
|
- id: callSub
|
||||||
|
type: io.kestra.core.tasks.flows.Flow
|
||||||
|
flowId: sub_child
|
||||||
|
namespace: io.kestra.unittest.sub
|
||||||
|
""");
|
||||||
|
|
||||||
|
var parent = flowService.importFlow(tenantId,
|
||||||
|
"""
|
||||||
|
id: parent
|
||||||
|
namespace: io.kestra.unittest
|
||||||
|
tasks:
|
||||||
|
- id: callChild
|
||||||
|
type: io.kestra.core.tasks.flows.Flow
|
||||||
|
flowId: child
|
||||||
|
namespace: io.kestra.unittest
|
||||||
|
""");
|
||||||
|
|
||||||
|
var unrelated = flowService.importFlow(tenantId,
|
||||||
|
"""
|
||||||
|
id: unrelated
|
||||||
|
namespace: io.kestra.unittest
|
||||||
|
tasks:
|
||||||
|
- id: log
|
||||||
|
type: io.kestra.plugin.core.log.Log
|
||||||
|
message: Not part of deps
|
||||||
|
""");
|
||||||
|
|
||||||
|
computeAndSaveTopologies(List.of(subChild, child, parent, unrelated));
|
||||||
|
|
||||||
|
FlowTopologyGraph graph = flowTopologyService.namespaceGraph(tenantId, "io.kestra.unittest");
|
||||||
|
|
||||||
|
assertThat(graph.getNodes())
|
||||||
|
.extracting(FlowNode::getId)
|
||||||
|
.contains("parent", "child", "sub_child", "unrelated");
|
||||||
|
|
||||||
|
assertThat(graph.getEdges().size()).isEqualTo(2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this function mimics the production behaviour
|
* this function mimics the production behaviour
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
id: flow-trigger-multiple-conditions-flow-a
|
||||||
|
namespace: io.kestra.tests.trigger.multiple.conditions
|
||||||
|
|
||||||
|
labels:
|
||||||
|
some: label
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- id: only
|
||||||
|
type: io.kestra.plugin.core.debug.Return
|
||||||
|
format: "from parents: {{execution.id}}"
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
id: flow-trigger-multiple-conditions-flow-listen
|
||||||
|
namespace: io.kestra.tests.trigger.multiple.conditions
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
- id: on_completion
|
||||||
|
type: io.kestra.plugin.core.trigger.Flow
|
||||||
|
states: [ SUCCESS ]
|
||||||
|
conditions:
|
||||||
|
- type: io.kestra.plugin.core.condition.ExecutionFlow
|
||||||
|
namespace: io.kestra.tests.trigger.multiple.conditions
|
||||||
|
flowId: flow-trigger-multiple-conditions-flow-a
|
||||||
|
- id: on_failure
|
||||||
|
type: io.kestra.plugin.core.trigger.Flow
|
||||||
|
states: [ FAILED ]
|
||||||
|
conditions:
|
||||||
|
- type: io.kestra.plugin.core.condition.ExecutionFlow
|
||||||
|
namespace: io.kestra.tests.trigger.multiple.conditions
|
||||||
|
flowId: flow-trigger-multiple-conditions-flow-a
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- id: only
|
||||||
|
type: io.kestra.plugin.core.debug.Return
|
||||||
|
format: "It works"
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#===============================================================================
|
|
||||||
# SCRIPT: check-plugin-artifacts.sh
|
|
||||||
#
|
|
||||||
# DESCRIPTION:
|
|
||||||
# This script can be used to check if plugins are available on Maven Central or Sonatype
|
|
||||||
#
|
|
||||||
# USAGE: ./ check-plugin-artifacts.sh [options]
|
|
||||||
# OPTIONS:
|
|
||||||
# --plugin-file File containing the plugin list (default: .plugins)
|
|
||||||
# --version Version for plugins
|
|
||||||
# -y, --yes Automatically confirm prompts (non-interactive).
|
|
||||||
# -h, --help Show the help message and exit
|
|
||||||
|
|
||||||
# EXAMPLES:
|
|
||||||
# To clone all plugins:
|
|
||||||
# ./check-plugin-artifacts.sh --plugin-file .plugins --version 0.21.0
|
|
||||||
|
|
||||||
#===============================================================================
|
|
||||||
|
|
||||||
set -e;
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Global vars
|
|
||||||
###############################################################
|
|
||||||
BASEDIR=$(dirname "$(readlink -f $0)")
|
|
||||||
WORKING_DIR=/tmp/kestra-plugins;
|
|
||||||
PLUGIN_FILE="$BASEDIR/../.plugins"
|
|
||||||
|
|
||||||
# Maven Central URL
|
|
||||||
MAVEN_CENTRAL="https://repo1.maven.org/maven2"
|
|
||||||
SONATYPE_SNAPSHOT="https://central.sonatype.com/repository/maven-snapshots"
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Functions
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
# Function to display the help message
|
|
||||||
usage() {
|
|
||||||
echo "Usage: $0 --version <version> [--plugin-file]"
|
|
||||||
echo
|
|
||||||
echo "Options:"
|
|
||||||
echo " --plugin-file File containing the plugin list"
|
|
||||||
echo " --version Version for plugins"
|
|
||||||
echo " -y, --yes Automatically confirm prompts (non-interactive)."
|
|
||||||
echo " -h, --help Show this help message and exit."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to ask to continue
|
|
||||||
function askToContinue() {
|
|
||||||
read -p "Are you sure you want to continue? [y/N] " confirm
|
|
||||||
[[ "$confirm" =~ ^[Yy]$ ]] || { echo "Operation cancelled."; exit 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Options
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
PLUGINS_ARGS=()
|
|
||||||
AUTO_YES=false
|
|
||||||
# Get the options
|
|
||||||
while [[ "$#" -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--plugin-file)
|
|
||||||
PLUGIN_FILE="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--plugin-file=*)
|
|
||||||
PLUGIN_FILE="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--version)
|
|
||||||
VERSION="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--version=*)
|
|
||||||
VERSION="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-y|--yes)
|
|
||||||
AUTO_YES=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h|--help)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
PLUGINS_ARGS+=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
## Check options
|
|
||||||
if [[ -z "$VERSION" ]]; then
|
|
||||||
echo -e "Missing required argument: --version\n";
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
## Get plugin list
|
|
||||||
if [[ "${#PLUGINS_ARGS[@]}" -eq 0 ]]; then
|
|
||||||
if [ -f "$PLUGIN_FILE" ]; then
|
|
||||||
PLUGINS=$(cat "$PLUGIN_FILE" | grep "io\\.kestra\\." | sed -e '/#/s/^.//' | cut -d':' -f2-3 | uniq | sort);
|
|
||||||
PLUGINS_COUNT=$(echo "$PLUGINS" | wc -l);
|
|
||||||
PLUGINS_ARRAY=$(echo "$PLUGINS" | xargs || echo '');
|
|
||||||
PLUGINS_ARRAY=($PLUGINS_ARRAY);
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
PLUGINS_ARRAY=("${PLUGINS_ARGS[@]}")
|
|
||||||
PLUGINS_COUNT="${#PLUGINS_ARGS[@]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Arguments: "
|
|
||||||
echo "VERSION=$VERSION"
|
|
||||||
echo "PLUGIN_FILE=$PLUGIN_FILE"
|
|
||||||
|
|
||||||
for PLUGIN in "${PLUGINS_ARRAY[@]}"; do
|
|
||||||
echo "$PLUGIN"
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ "$AUTO_YES" == false ]]; then
|
|
||||||
askToContinue
|
|
||||||
fi
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Main
|
|
||||||
###############################################################
|
|
||||||
mkdir -p "$WORKING_DIR"
|
|
||||||
|
|
||||||
COUNTER=1;
|
|
||||||
AVAILABLE=0;
|
|
||||||
NOT_AVAILABLE=0;
|
|
||||||
for PLUGIN in "${PLUGINS_ARRAY[@]}"
|
|
||||||
do
|
|
||||||
# Extract groupId and artifactId
|
|
||||||
GROUP_ID="${PLUGIN%%:*}"
|
|
||||||
ARTIFACT_ID="${PLUGIN##*:}"
|
|
||||||
|
|
||||||
# Convert groupId to Maven repository path
|
|
||||||
GROUP_PATH="${GROUP_ID//./\/}"
|
|
||||||
if [[ "$VERSION" == *"-SNAPSHOT" ]]; then
|
|
||||||
ARTIFACT_URL="${GROUP_PATH}/${ARTIFACT_ID}/${VERSION}/maven-metadata.xml"
|
|
||||||
ARTIFACT_URL="${SONATYPE_SNAPSHOT}/${ARTIFACT_URL}"
|
|
||||||
else
|
|
||||||
ARTIFACT_URL="${GROUP_PATH}/${ARTIFACT_ID}/${VERSION}/${ARTIFACT_ID}-${VERSION}.jar"
|
|
||||||
ARTIFACT_URL="${MAVEN_CENTRAL}/${ARTIFACT_URL}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if curl --silent --fail --head "$ARTIFACT_URL" > /dev/null; then
|
|
||||||
printf "✅ [$COUNTER/$PLUGINS_COUNT] %-45s : %s\n" "[$PLUGIN]" "Artifact is available: $ARTIFACT_URL";
|
|
||||||
AVAILABLE=$(( AVAILABLE + 1 ))
|
|
||||||
else
|
|
||||||
printf "❌ [$COUNTER/$PLUGINS_COUNT] %-45s : %s\n" "[$PLUGIN]" "Artifact is NOT available: $ARTIFACT_URL";
|
|
||||||
NOT_AVAILABLE=$(( NOT_AVAILABLE + 1 ))
|
|
||||||
fi
|
|
||||||
COUNTER=$(( COUNTER + 1 ));
|
|
||||||
done;
|
|
||||||
|
|
||||||
echo -e "\n\n✅ Available: $AVAILABLE, ❌ Unavailable: $NOT_AVAILABLE";
|
|
||||||
|
|
||||||
exit 0;
|
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#===============================================================================
|
|
||||||
# SCRIPT: release-plugins.sh
|
|
||||||
#
|
|
||||||
# DESCRIPTION:
|
|
||||||
# This script can be used to run a ./gradlew release command on each kestra plugin repository.
|
|
||||||
# By default, if no `GITHUB_PAT` environment variable exist, the script will attempt to clone GitHub repositories using SSH_KEY.
|
|
||||||
#
|
|
||||||
# USAGE: ./release-plugins.sh [options]
|
|
||||||
# OPTIONS:
|
|
||||||
# --release-version <version> Specify the release version (required)
|
|
||||||
# --next-version <version> Specify the next version (required)
|
|
||||||
# --dry-run Specify to run in DRY_RUN.
|
|
||||||
# -y, --yes Automatically confirm prompts (non-interactive).
|
|
||||||
# -h, --help Show the help message and exit
|
|
||||||
|
|
||||||
# EXAMPLES:
|
|
||||||
# To release all plugins:
|
|
||||||
# ./release-plugins.sh --release-version=0.20.0 --next-version=0.21.0-SNAPSHOT
|
|
||||||
# To release a specific plugin:
|
|
||||||
# ./release-plugins.sh --release-version=0.20.0 --next-version=0.21.0-SNAPSHOT plugin-kubernetes
|
|
||||||
# To release specific plugins from file:
|
|
||||||
# ./release-plugins.sh --release-version=0.20.0 --plugin-file .plugins
|
|
||||||
#===============================================================================
|
|
||||||
|
|
||||||
set -e;
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Global vars
|
|
||||||
###############################################################
|
|
||||||
BASEDIR=$(dirname "$(readlink -f $0)")
|
|
||||||
WORKING_DIR=/tmp/kestra-release-plugins-$(date +%s);
|
|
||||||
PLUGIN_FILE="$BASEDIR/../.plugins"
|
|
||||||
GIT_BRANCH=master
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Functions
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
# Function to display the help message
|
|
||||||
usage() {
|
|
||||||
echo "Usage: $0 --release-version <version> --next-version [plugin-repositories...]"
|
|
||||||
echo
|
|
||||||
echo "Options:"
|
|
||||||
echo " --release-version <version> Specify the release version (required)."
|
|
||||||
echo " --next-version <version> Specify the next version (required)."
|
|
||||||
echo " --plugin-file File containing the plugin list (default: .plugins)"
|
|
||||||
echo " --dry-run Specify to run in DRY_RUN."
|
|
||||||
echo " -y, --yes Automatically confirm prompts (non-interactive)."
|
|
||||||
echo " -h, --help Show this help message and exit."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to ask to continue
|
|
||||||
function askToContinue() {
|
|
||||||
read -p "Are you sure you want to continue? [y/N] " confirm
|
|
||||||
[[ "$confirm" =~ ^[Yy]$ ]] || { echo "Operation cancelled."; exit 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Options
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
PLUGINS_ARGS=()
|
|
||||||
AUTO_YES=false
|
|
||||||
DRY_RUN=false
|
|
||||||
# Get the options
|
|
||||||
while [[ "$#" -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--release-version)
|
|
||||||
RELEASE_VERSION="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--release-version=*)
|
|
||||||
RELEASE_VERSION="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--next-version)
|
|
||||||
NEXT_VERSION="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--next-version=*)
|
|
||||||
NEXT_VERSION="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--plugin-file)
|
|
||||||
PLUGIN_FILE="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--plugin-file=*)
|
|
||||||
PLUGIN_FILE="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--dry-run)
|
|
||||||
DRY_RUN=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-y|--yes)
|
|
||||||
AUTO_YES=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h|--help)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
PLUGINS_ARGS+=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
## Check options
|
|
||||||
if [[ -z "$RELEASE_VERSION" ]]; then
|
|
||||||
echo -e "Missing required argument: --release-version\n";
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -z "$NEXT_VERSION" ]]; then
|
|
||||||
echo -e "Missing required argument: --next-version\n";
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
## Get plugin list
|
|
||||||
if [[ "${#PLUGINS_ARGS[@]}" -eq 0 ]]; then
|
|
||||||
if [ -f "$PLUGIN_FILE" ]; then
|
|
||||||
PLUGINS=$(cat "$PLUGIN_FILE" | grep "io\\.kestra\\." | sed -e '/#/s/^.//' | cut -d':' -f1 | uniq | sort);
|
|
||||||
PLUGINS_COUNT=$(echo "$PLUGINS" | wc -l);
|
|
||||||
PLUGINS_ARRAY=$(echo "$PLUGINS" | xargs || echo '');
|
|
||||||
PLUGINS_ARRAY=($PLUGINS_ARRAY);
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
PLUGINS_ARRAY=("${PLUGINS_ARGS[@]}")
|
|
||||||
PLUGINS_COUNT="${#PLUGINS_ARGS[@]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract the major and minor versions
|
|
||||||
BASE_VERSION=$(echo "$RELEASE_VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\..*/\1/')
|
|
||||||
PUSH_RELEASE_BRANCH="releases/v${BASE_VERSION}.x"
|
|
||||||
|
|
||||||
## Get plugin list
|
|
||||||
echo "RELEASE_VERSION=$RELEASE_VERSION"
|
|
||||||
echo "NEXT_VERSION=$NEXT_VERSION"
|
|
||||||
echo "PUSH_RELEASE_BRANCH=$PUSH_RELEASE_BRANCH"
|
|
||||||
echo "GIT_BRANCH=$GIT_BRANCH"
|
|
||||||
echo "DRY_RUN=$DRY_RUN"
|
|
||||||
echo "Found ($PLUGINS_COUNT) plugin repositories:";
|
|
||||||
|
|
||||||
for PLUGIN in "${PLUGINS_ARRAY[@]}"; do
|
|
||||||
echo "$PLUGIN"
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ "$AUTO_YES" == false ]]; then
|
|
||||||
askToContinue
|
|
||||||
fi
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Main
|
|
||||||
###############################################################
|
|
||||||
mkdir -p $WORKING_DIR
|
|
||||||
|
|
||||||
COUNTER=1;
|
|
||||||
for PLUGIN in "${PLUGINS_ARRAY[@]}"
|
|
||||||
do
|
|
||||||
cd $WORKING_DIR;
|
|
||||||
|
|
||||||
echo "---------------------------------------------------------------------------------------"
|
|
||||||
echo "[$COUNTER/$PLUGINS_COUNT] Release Plugin: $PLUGIN"
|
|
||||||
echo "---------------------------------------------------------------------------------------"
|
|
||||||
if [[ -z "${GITHUB_PAT}" ]]; then
|
|
||||||
git clone git@github.com:kestra-io/$PLUGIN
|
|
||||||
else
|
|
||||||
echo "Clone git repository using GITHUB PAT"
|
|
||||||
git clone https://${GITHUB_PAT}@github.com/kestra-io/$PLUGIN.git
|
|
||||||
fi
|
|
||||||
cd "$PLUGIN";
|
|
||||||
|
|
||||||
if [[ "$PLUGIN" == "plugin-transform" ]] && [[ "$GIT_BRANCH" == "master" ]]; then # quickfix
|
|
||||||
git checkout main;
|
|
||||||
else
|
|
||||||
git checkout "$GIT_BRANCH";
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if tag already exists on remote
|
|
||||||
TAG_EXISTS=$(git ls-remote --tags origin "refs/tags/v${RELEASE_VERSION}" | wc -l)
|
|
||||||
if [[ "$TAG_EXISTS" -ne 0 ]]; then
|
|
||||||
echo "Tag ${RELEASE_VERSION} already exists for $PLUGIN. Skipping..."
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == false ]]; then
|
|
||||||
CURRENT_BRANCH=$(git branch --show-current);
|
|
||||||
|
|
||||||
echo "Run gradle release for plugin: $PLUGIN";
|
|
||||||
echo "Branch: $CURRENT_BRANCH";
|
|
||||||
|
|
||||||
if [[ "$AUTO_YES" == false ]]; then
|
|
||||||
askToContinue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Create and push release branch
|
|
||||||
git checkout -b "$PUSH_RELEASE_BRANCH";
|
|
||||||
git push -u origin "$PUSH_RELEASE_BRANCH";
|
|
||||||
|
|
||||||
# Run gradle release
|
|
||||||
git checkout "$CURRENT_BRANCH";
|
|
||||||
|
|
||||||
if [[ "$RELEASE_VERSION" == *"-SNAPSHOT" ]]; then
|
|
||||||
# -SNAPSHOT qualifier maybe used to test release-candidates
|
|
||||||
./gradlew release -Prelease.useAutomaticVersion=true \
|
|
||||||
-Prelease.releaseVersion="${RELEASE_VERSION}" \
|
|
||||||
-Prelease.newVersion="${NEXT_VERSION}" \
|
|
||||||
-Prelease.pushReleaseVersionBranch="${PUSH_RELEASE_BRANCH}" \
|
|
||||||
-Prelease.failOnSnapshotDependencies=false
|
|
||||||
else
|
|
||||||
./gradlew release -Prelease.useAutomaticVersion=true \
|
|
||||||
-Prelease.releaseVersion="${RELEASE_VERSION}" \
|
|
||||||
-Prelease.newVersion="${NEXT_VERSION}" \
|
|
||||||
-Prelease.pushReleaseVersionBranch="${PUSH_RELEASE_BRANCH}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
git push;
|
|
||||||
# Update the upper bound version of kestra
|
|
||||||
PLUGIN_KESTRA_VERSION="[${BASE_VERSION},)"
|
|
||||||
git checkout "$PUSH_RELEASE_BRANCH" && git pull;
|
|
||||||
sed -i "s/^kestraVersion=.*/kestraVersion=${PLUGIN_KESTRA_VERSION}/" ./gradle.properties
|
|
||||||
git add ./gradle.properties
|
|
||||||
# Check if there are staged changes
|
|
||||||
if ! git diff --cached --quiet; then
|
|
||||||
git commit -m"chore(deps): update kestraVersion to ${PLUGIN_KESTRA_VERSION}."
|
|
||||||
git push
|
|
||||||
fi
|
|
||||||
sleep 5; # add a short delay to not spam Maven Central
|
|
||||||
else
|
|
||||||
echo "Skip gradle release [DRY_RUN=true]";
|
|
||||||
fi
|
|
||||||
COUNTER=$(( COUNTER + 1 ));
|
|
||||||
done;
|
|
||||||
|
|
||||||
exit 0;
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#===============================================================================
|
|
||||||
# SCRIPT: setversion-tag-plugins.sh
|
|
||||||
#
|
|
||||||
# DESCRIPTION:
|
|
||||||
# This script can be used to update and tag plugins from a release branch .e.g., releases/v0.21.x.
|
|
||||||
# By default, if no `GITHUB_PAT` environment variable exist, the script will attempt to clone GitHub repositories using SSH_KEY.
|
|
||||||
#
|
|
||||||
# USAGE: ./setversion-tag-plugins.sh [options]
|
|
||||||
# OPTIONS:
|
|
||||||
# --release-version <version> Specify the release version (required)
|
|
||||||
# --dry-run Specify to run in DRY_RUN.
|
|
||||||
# -y, --yes Automatically confirm prompts (non-interactive).
|
|
||||||
# -h, --help Show the help message and exit
|
|
||||||
|
|
||||||
# EXAMPLES:
|
|
||||||
# To release all plugins:
|
|
||||||
# ./setversion-tag-plugins.sh --release-version=0.20.0
|
|
||||||
# To release a specific plugin:
|
|
||||||
# ./setversion-tag-plugins.sh --release-version=0.20.0 plugin-kubernetes
|
|
||||||
# To release specific plugins from file:
|
|
||||||
# ./setversion-tag-plugins.sh --release-version=0.20.0 --plugin-file .plugins
|
|
||||||
#===============================================================================
|
|
||||||
|
|
||||||
set -e;
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Global vars
|
|
||||||
###############################################################
|
|
||||||
BASEDIR=$(dirname "$(readlink -f $0)")
|
|
||||||
WORKING_DIR=/tmp/kestra-release-plugins-$(date +%s);
|
|
||||||
PLUGIN_FILE="$BASEDIR/../.plugins"
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Functions
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
# Function to display the help message
|
|
||||||
usage() {
|
|
||||||
echo "Usage: $0 --release-version <version> [plugin-repositories...]"
|
|
||||||
echo
|
|
||||||
echo "Options:"
|
|
||||||
echo " --release-version <version> Specify the release version (required)."
|
|
||||||
echo " --plugin-file File containing the plugin list (default: .plugins)"
|
|
||||||
echo " --dry-run Specify to run in DRY_RUN."
|
|
||||||
echo " -y, --yes Automatically confirm prompts (non-interactive)."
|
|
||||||
echo " -h, --help Show this help message and exit."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to ask to continue
|
|
||||||
function askToContinue() {
|
|
||||||
read -p "Are you sure you want to continue? [y/N] " confirm
|
|
||||||
[[ "$confirm" =~ ^[Yy]$ ]] || { echo "Operation cancelled."; exit 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Options
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
PLUGINS_ARGS=()
|
|
||||||
AUTO_YES=false
|
|
||||||
DRY_RUN=false
|
|
||||||
# Get the options
|
|
||||||
while [[ "$#" -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--release-version)
|
|
||||||
RELEASE_VERSION="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--release-version=*)
|
|
||||||
RELEASE_VERSION="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--plugin-file)
|
|
||||||
PLUGIN_FILE="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--plugin-file=*)
|
|
||||||
PLUGIN_FILE="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--dry-run)
|
|
||||||
DRY_RUN=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-y|--yes)
|
|
||||||
AUTO_YES=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h|--help)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
PLUGINS_ARGS+=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
## Check options
|
|
||||||
if [[ -z "$RELEASE_VERSION" ]]; then
|
|
||||||
echo -e "Missing required argument: --release-version\n";
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
## Get plugin list
|
|
||||||
if [[ "${#PLUGINS_ARGS[@]}" -eq 0 ]]; then
|
|
||||||
if [ -f "$PLUGIN_FILE" ]; then
|
|
||||||
PLUGINS=$(cat "$PLUGIN_FILE" | grep "io\\.kestra\\." | sed -e '/#/s/^.//' | cut -d':' -f1 | uniq | sort);
|
|
||||||
PLUGINS_COUNT=$(echo "$PLUGINS" | wc -l);
|
|
||||||
PLUGINS_ARRAY=$(echo "$PLUGINS" | xargs || echo '');
|
|
||||||
PLUGINS_ARRAY=($PLUGINS_ARRAY);
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
PLUGINS_ARRAY=("${PLUGINS_ARGS[@]}")
|
|
||||||
PLUGINS_COUNT="${#PLUGINS_ARGS[@]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract the major and minor versions
|
|
||||||
BASE_VERSION=$(echo "$RELEASE_VERSION" | sed -E 's/^([0-9]+\.[0-9]+)\..*/\1/')
|
|
||||||
RELEASE_BRANCH="releases/v${BASE_VERSION}.x"
|
|
||||||
|
|
||||||
## Get plugin list
|
|
||||||
echo "RELEASE_VERSION=$RELEASE_VERSION"
|
|
||||||
echo "RELEASE_BRANCH=$RELEASE_BRANCH"
|
|
||||||
echo "DRY_RUN=$DRY_RUN"
|
|
||||||
echo "Found ($PLUGINS_COUNT) plugin repositories:";
|
|
||||||
|
|
||||||
for PLUGIN in "${PLUGINS_ARRAY[@]}"; do
|
|
||||||
echo "$PLUGIN"
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ "$AUTO_YES" == false ]]; then
|
|
||||||
askToContinue
|
|
||||||
fi
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Main
|
|
||||||
###############################################################
|
|
||||||
mkdir -p $WORKING_DIR
|
|
||||||
|
|
||||||
COUNTER=1;
|
|
||||||
for PLUGIN in "${PLUGINS_ARRAY[@]}"
|
|
||||||
do
|
|
||||||
cd $WORKING_DIR;
|
|
||||||
|
|
||||||
echo "---------------------------------------------------------------------------------------"
|
|
||||||
echo "[$COUNTER/$PLUGINS_COUNT] $PLUGIN"
|
|
||||||
echo "---------------------------------------------------------------------------------------"
|
|
||||||
if [[ -z "${GITHUB_PAT}" ]]; then
|
|
||||||
git clone git@github.com:kestra-io/$PLUGIN
|
|
||||||
else
|
|
||||||
echo "Clone git repository using GITHUB PAT"
|
|
||||||
git clone https://${GITHUB_PAT}@github.com/kestra-io/$PLUGIN.git
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$PLUGIN";
|
|
||||||
|
|
||||||
git checkout $RELEASE_BRANCH;
|
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == false ]]; then
|
|
||||||
CURRENT_BRANCH=$(git branch --show-current);
|
|
||||||
|
|
||||||
echo "Update version and tag plugin: $PLUGIN";
|
|
||||||
echo "Branch: $CURRENT_BRANCH";
|
|
||||||
|
|
||||||
if [[ "$AUTO_YES" == false ]]; then
|
|
||||||
askToContinue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Checkout release branch
|
|
||||||
git checkout "$RELEASE_BRANCH";
|
|
||||||
|
|
||||||
# Update version
|
|
||||||
sed -i "s/^version=.*/version=$RELEASE_VERSION/" ./gradle.properties
|
|
||||||
git add ./gradle.properties
|
|
||||||
git commit -m"chore(version): update to version 'v$RELEASE_VERSION'."
|
|
||||||
git push
|
|
||||||
git tag -a "v$RELEASE_VERSION" -m"v$RELEASE_VERSION"
|
|
||||||
git push origin "v$RELEASE_VERSION"
|
|
||||||
|
|
||||||
sleep 5; # add a short delay to not spam Maven Central
|
|
||||||
else
|
|
||||||
echo "Skip tagging [DRY_RUN=true]";
|
|
||||||
fi
|
|
||||||
COUNTER=$(( COUNTER + 1 ));
|
|
||||||
done;
|
|
||||||
|
|
||||||
exit 0;
|
|
||||||
@@ -1,200 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#===============================================================================
|
|
||||||
# SCRIPT: update-plugin-kestra-version.sh
|
|
||||||
#
|
|
||||||
# DESCRIPTION:
|
|
||||||
# This script can be used to update the gradle 'kestraVersion' property on each kestra plugin repository.
|
|
||||||
# By default, if no `GITHUB_PAT` environment variable exist, the script will attempt to clone GitHub repositories using SSH_KEY.
|
|
||||||
#
|
|
||||||
#USAGE:
|
|
||||||
# ./dev-tools/update-plugin-kestra-version.sh --branch <branch> --version <version> [plugin-repositories...]
|
|
||||||
#
|
|
||||||
#OPTIONS:
|
|
||||||
# --branch <branch> Specify the branch on which to update the kestraCoreVersion (default: master).
|
|
||||||
# --version <version> Specify the Kestra core version (required).
|
|
||||||
# --plugin-file File containing the plugin list (default: .plugins)
|
|
||||||
# --dry-run Specify to run in DRY_RUN.
|
|
||||||
# -y, --yes Automatically confirm prompts (non-interactive).
|
|
||||||
# -h, --help Show this help message and exit.
|
|
||||||
|
|
||||||
|
|
||||||
# EXAMPLES:
|
|
||||||
# To release all plugins:
|
|
||||||
# ./update-plugin-kestra-version.sh --branch=releases/v0.23.x --version="[0.23,0.24)"
|
|
||||||
# To release a specific plugin:
|
|
||||||
# ./update-plugin-kestra-version.sh --branch=releases/v0.23.x --version="[0.23,0.24)" plugin-kubernetes
|
|
||||||
# To release specific plugins from file:
|
|
||||||
# ./update-plugin-kestra-version.sh --branch=releases/v0.23.x --version="[0.23,0.24)" --plugin-file .plugins
|
|
||||||
#===============================================================================
|
|
||||||
|
|
||||||
set -e;
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Global vars
|
|
||||||
###############################################################
|
|
||||||
BASEDIR=$(dirname "$(readlink -f $0)")
|
|
||||||
SCRIPT_NAME=$(basename "$0")
|
|
||||||
SCRIPT_NAME="${SCRIPT_NAME%.*}"
|
|
||||||
WORKING_DIR="/tmp/kestra-$SCRIPT_NAME-$(date +%s)"
|
|
||||||
PLUGIN_FILE="$BASEDIR/../.plugins"
|
|
||||||
GIT_BRANCH=master
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Functions
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
# Function to display the help message
|
|
||||||
usage() {
|
|
||||||
echo "Usage: $0 --branch <branch> --version <version> [plugin-repositories...]"
|
|
||||||
echo
|
|
||||||
echo "Options:"
|
|
||||||
echo " --branch <branch> Specify the branch on which to update the kestraCoreVersion (default: master)."
|
|
||||||
echo " --version <version> Specify the Kestra core version (required)."
|
|
||||||
echo " --plugin-file File containing the plugin list (default: .plugins)"
|
|
||||||
echo " --dry-run Specify to run in DRY_RUN."
|
|
||||||
echo " -y, --yes Automatically confirm prompts (non-interactive)."
|
|
||||||
echo " -h, --help Show this help message and exit."
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to ask to continue
|
|
||||||
function askToContinue() {
|
|
||||||
read -p "Are you sure you want to continue? [y/N] " confirm
|
|
||||||
[[ "$confirm" =~ ^[Yy]$ ]] || { echo "Operation cancelled."; exit 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Options
|
|
||||||
###############################################################
|
|
||||||
|
|
||||||
PLUGINS_ARGS=()
|
|
||||||
AUTO_YES=false
|
|
||||||
DRY_RUN=false
|
|
||||||
# Get the options
|
|
||||||
while [[ "$#" -gt 0 ]]; do
|
|
||||||
case "$1" in
|
|
||||||
--branch)
|
|
||||||
GIT_BRANCH="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--branch=*)
|
|
||||||
GIT_BRANCH="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--version)
|
|
||||||
VERSION="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--version=*)
|
|
||||||
VERSION="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--plugin-file)
|
|
||||||
PLUGIN_FILE="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
--plugin-file=*)
|
|
||||||
PLUGIN_FILE="${1#*=}"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--dry-run)
|
|
||||||
DRY_RUN=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-y|--yes)
|
|
||||||
AUTO_YES=true
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-h|--help)
|
|
||||||
usage
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
PLUGINS_ARGS+=("$1")
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
## Check options
|
|
||||||
if [[ -z "$VERSION" ]]; then
|
|
||||||
echo -e "Missing required argument: --version\n";
|
|
||||||
usage
|
|
||||||
fi
|
|
||||||
|
|
||||||
## Get plugin list
|
|
||||||
if [[ "${#PLUGINS_ARGS[@]}" -eq 0 ]]; then
|
|
||||||
if [ -f "$PLUGIN_FILE" ]; then
|
|
||||||
PLUGINS=$(cat "$PLUGIN_FILE" | grep "io\\.kestra\\." | sed -e '/#/s/^.//' | cut -d':' -f1 | uniq | sort);
|
|
||||||
PLUGINS_COUNT=$(echo "$PLUGINS" | wc -l);
|
|
||||||
PLUGINS_ARRAY=$(echo "$PLUGINS" | xargs || echo '');
|
|
||||||
PLUGINS_ARRAY=($PLUGINS_ARRAY);
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
PLUGINS_ARRAY=("${PLUGINS_ARGS[@]}")
|
|
||||||
PLUGINS_COUNT="${#PLUGINS_ARGS[@]}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
## Get plugin list
|
|
||||||
echo "VERSION=$RELEASE_VERSION"
|
|
||||||
echo "GIT_BRANCH=$GIT_BRANCH"
|
|
||||||
echo "DRY_RUN=$DRY_RUN"
|
|
||||||
echo "Found ($PLUGINS_COUNT) plugin repositories:";
|
|
||||||
|
|
||||||
for PLUGIN in "${PLUGINS_ARRAY[@]}"; do
|
|
||||||
echo "$PLUGIN"
|
|
||||||
done
|
|
||||||
|
|
||||||
if [[ "$AUTO_YES" == false ]]; then
|
|
||||||
askToContinue
|
|
||||||
fi
|
|
||||||
|
|
||||||
###############################################################
|
|
||||||
# Main
|
|
||||||
###############################################################
|
|
||||||
mkdir -p $WORKING_DIR
|
|
||||||
|
|
||||||
COUNTER=1;
|
|
||||||
for PLUGIN in "${PLUGINS_ARRAY[@]}"
|
|
||||||
do
|
|
||||||
cd $WORKING_DIR;
|
|
||||||
|
|
||||||
echo "---------------------------------------------------------------------------------------"
|
|
||||||
echo "[$COUNTER/$PLUGINS_COUNT] Update Plugin: $PLUGIN"
|
|
||||||
echo "---------------------------------------------------------------------------------------"
|
|
||||||
if [[ -z "${GITHUB_PAT}" ]]; then
|
|
||||||
git clone git@github.com:kestra-io/$PLUGIN
|
|
||||||
else
|
|
||||||
echo "Clone git repository using GITHUB PAT"
|
|
||||||
git clone https://${GITHUB_PAT}@github.com/kestra-io/$PLUGIN.git
|
|
||||||
fi
|
|
||||||
cd "$PLUGIN";
|
|
||||||
|
|
||||||
if [[ "$PLUGIN" == "plugin-transform" ]] && [[ "$GIT_BRANCH" == "master" ]]; then # quickfix
|
|
||||||
git checkout main;
|
|
||||||
else
|
|
||||||
git checkout "$GIT_BRANCH" || git checkout -b "$GIT_BRANCH";
|
|
||||||
fi
|
|
||||||
|
|
||||||
CURRENT_BRANCH=$(git branch --show-current);
|
|
||||||
|
|
||||||
echo "Update kestraVersion for plugin: $PLUGIN on branch $CURRENT_BRANCH:";
|
|
||||||
# Update the kestraVersion property
|
|
||||||
sed -i "s/^kestraVersion=.*/kestraVersion=${VERSION}/" ./gradle.properties
|
|
||||||
# Display diff
|
|
||||||
git diff --exit-code --unified=0 ./gradle.properties | grep -E '^\+|^-' | grep -v -E '^\+\+\+|^---' || echo "No changes detected in gradle.properties";
|
|
||||||
|
|
||||||
if [[ "$DRY_RUN" == false ]]; then
|
|
||||||
if [[ "$AUTO_YES" == false ]]; then
|
|
||||||
askToContinue
|
|
||||||
fi
|
|
||||||
git add ./gradle.properties
|
|
||||||
git commit -m"chore(deps): update kestraVersion to ${VERSION}." || true
|
|
||||||
git push --set-upstream origin $GIT_BRANCH || true
|
|
||||||
else
|
|
||||||
echo "Skip git commit/push [DRY_RUN=true]";
|
|
||||||
fi
|
|
||||||
COUNTER=$(( COUNTER + 1 ));
|
|
||||||
done;
|
|
||||||
|
|
||||||
exit 0;
|
|
||||||
@@ -15,9 +15,9 @@ volumes:
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres
|
image: postgres:18
|
||||||
volumes:
|
volumes:
|
||||||
- postgres-data:/var/lib/postgresql/data
|
- postgres-data:/var/lib/postgresql/18/docker
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: kestra
|
POSTGRES_DB: kestra
|
||||||
POSTGRES_USER: kestra
|
POSTGRES_USER: kestra
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ volumes:
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres
|
image: postgres:18
|
||||||
volumes:
|
volumes:
|
||||||
- postgres-data:/var/lib/postgresql/data
|
- postgres-data:/var/lib/postgresql/18/docker
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: kestra
|
POSTGRES_DB: kestra
|
||||||
POSTGRES_USER: kestra
|
POSTGRES_USER: kestra
|
||||||
|
|||||||
@@ -79,6 +79,28 @@ public abstract class AbstractJdbcFlowTopologyRepository extends AbstractJdbcRep
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FlowTopology> findByNamespacePrefix(String tenantId, String namespacePrefix) {
|
||||||
|
return jdbcRepository
|
||||||
|
.getDslContextWrapper()
|
||||||
|
.transactionResult(configuration -> {
|
||||||
|
// Match flows that originate from the namespace or its children
|
||||||
|
Condition sourceCondition = field("source_namespace").eq(namespacePrefix)
|
||||||
|
.or(field("source_namespace").likeIgnoreCase(namespacePrefix + ".%"));
|
||||||
|
|
||||||
|
Condition tenantSource = buildTenantCondition("source", tenantId);
|
||||||
|
Condition tenantDest = buildTenantCondition("destination", tenantId);
|
||||||
|
|
||||||
|
Select<Record1<Object>> from = DSL
|
||||||
|
.using(configuration)
|
||||||
|
.select(field("value"))
|
||||||
|
.from(this.jdbcRepository.getTable())
|
||||||
|
.where(tenantSource.and(tenantDest).and(sourceCondition));
|
||||||
|
|
||||||
|
return this.jdbcRepository.fetch(from);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<FlowTopology> findAll(String tenantId) {
|
public List<FlowTopology> findAll(String tenantId) {
|
||||||
return jdbcRepository
|
return jdbcRepository
|
||||||
|
|||||||
@@ -1230,8 +1230,10 @@ public class JdbcExecutor implements ExecutorInterface {
|
|||||||
private void processFlowTriggers(Execution execution) throws QueueException {
|
private void processFlowTriggers(Execution execution) throws QueueException {
|
||||||
// directly process simple conditions
|
// directly process simple conditions
|
||||||
flowTriggerService.withFlowTriggersOnly(allFlows.stream())
|
flowTriggerService.withFlowTriggersOnly(allFlows.stream())
|
||||||
.filter(f ->ListUtils.emptyOnNull(f.getTrigger().getConditions()).stream().noneMatch(c -> c instanceof MultipleCondition) && f.getTrigger().getPreconditions() == null)
|
.filter(f -> ListUtils.emptyOnNull(f.getTrigger().getConditions()).stream().noneMatch(c -> c instanceof MultipleCondition) && f.getTrigger().getPreconditions() == null)
|
||||||
.flatMap(f -> flowTriggerService.computeExecutionsFromFlowTriggers(execution, List.of(f.getFlow()), Optional.empty()).stream())
|
.map(f -> f.getFlow())
|
||||||
|
.distinct() // as computeExecutionsFromFlowTriggers is based on flow, we must map FlowWithFlowTrigger to a flow and distinct to avoid multiple execution for the same flow
|
||||||
|
.flatMap(f -> flowTriggerService.computeExecutionsFromFlowTriggers(execution, List.of(f), Optional.empty()).stream())
|
||||||
.forEach(throwConsumer(exec -> executionQueue.emit(exec)));
|
.forEach(throwConsumer(exec -> executionQueue.emit(exec)));
|
||||||
|
|
||||||
// send multiple conditions to the multiple condition queue for later processing
|
// send multiple conditions to the multiple condition queue for later processing
|
||||||
|
|||||||
@@ -19,9 +19,9 @@ dependencies {
|
|||||||
def jsonschemaVersion = "4.38.0"
|
def jsonschemaVersion = "4.38.0"
|
||||||
def kafkaVersion = "4.1.0"
|
def kafkaVersion = "4.1.0"
|
||||||
def opensearchVersion = "3.2.0"
|
def opensearchVersion = "3.2.0"
|
||||||
def opensearchRestVersion = "3.3.1"
|
def opensearchRestVersion = "3.3.2"
|
||||||
def flyingSaucerVersion = "10.0.3"
|
def flyingSaucerVersion = "10.0.3"
|
||||||
def jacksonVersion = "2.20.0"
|
def jacksonVersion = "2.20.1"
|
||||||
def jacksonAnnotationsVersion = "2.20"
|
def jacksonAnnotationsVersion = "2.20"
|
||||||
def jugVersion = "5.1.1"
|
def jugVersion = "5.1.1"
|
||||||
def langchain4jVersion = "1.8.0"
|
def langchain4jVersion = "1.8.0"
|
||||||
@@ -34,8 +34,8 @@ dependencies {
|
|||||||
api platform("io.qameta.allure:allure-bom:2.30.0")
|
api platform("io.qameta.allure:allure-bom:2.30.0")
|
||||||
// we define cloud bom here for GCP, Azure and AWS so they are aligned for all plugins that use them (secret, storage, oss and ee plugins)
|
// we define cloud bom here for GCP, Azure and AWS so they are aligned for all plugins that use them (secret, storage, oss and ee plugins)
|
||||||
api platform('com.google.cloud:libraries-bom:26.71.0')
|
api platform('com.google.cloud:libraries-bom:26.71.0')
|
||||||
api platform("com.azure:azure-sdk-bom:1.3.0")
|
api platform("com.azure:azure-sdk-bom:1.3.2")
|
||||||
api platform('software.amazon.awssdk:bom:2.36.3')
|
api platform('software.amazon.awssdk:bom:2.37.5')
|
||||||
api platform("dev.langchain4j:langchain4j-bom:$langchain4jVersion")
|
api platform("dev.langchain4j:langchain4j-bom:$langchain4jVersion")
|
||||||
api platform("dev.langchain4j:langchain4j-community-bom:$langchain4jCommunityVersion")
|
api platform("dev.langchain4j:langchain4j-community-bom:$langchain4jCommunityVersion")
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ dependencies {
|
|||||||
api group: 'co.elastic.logging', name: 'logback-ecs-encoder', version: '1.7.0'
|
api group: 'co.elastic.logging', name: 'logback-ecs-encoder', version: '1.7.0'
|
||||||
api group: 'de.focus-shift', name: 'jollyday-core', version: jollydayVersion
|
api group: 'de.focus-shift', name: 'jollyday-core', version: jollydayVersion
|
||||||
api group: 'de.focus-shift', name: 'jollyday-jaxb', version: jollydayVersion
|
api group: 'de.focus-shift', name: 'jollyday-jaxb', version: jollydayVersion
|
||||||
api 'nl.basjes.gitignore:gitignore-reader:1.12.0'
|
api 'nl.basjes.gitignore:gitignore-reader:1.12.1'
|
||||||
api group: 'dev.failsafe', name: 'failsafe', version: '3.3.2'
|
api group: 'dev.failsafe', name: 'failsafe', version: '3.3.2'
|
||||||
api group: 'com.cronutils', name: 'cron-utils', version: '9.2.1'
|
api group: 'com.cronutils', name: 'cron-utils', version: '9.2.1'
|
||||||
api group: 'com.github.victools', name: 'jsonschema-generator', version: jsonschemaVersion
|
api group: 'com.github.victools', name: 'jsonschema-generator', version: jsonschemaVersion
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Singleton
|
@Singleton
|
||||||
public class TestRunner implements Runnable, AutoCloseable {
|
public class TestRunner implements Runnable, AutoCloseable {
|
||||||
@Setter private int workerThread = Math.max(3, Runtime.getRuntime().availableProcessors());
|
@Setter private int workerThread = Math.max(3, Runtime.getRuntime().availableProcessors()) * 16;
|
||||||
@Setter private boolean schedulerEnabled = true;
|
@Setter private boolean schedulerEnabled = true;
|
||||||
@Setter private boolean workerEnabled = true;
|
@Setter private boolean workerEnabled = true;
|
||||||
|
|
||||||
|
|||||||
228
ui/package-lock.json
generated
@@ -10,7 +10,7 @@
|
|||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@js-joda/core": "^5.6.5",
|
"@js-joda/core": "^5.6.5",
|
||||||
"@kestra-io/ui-libs": "^0.0.261",
|
"@kestra-io/ui-libs": "^0.0.263",
|
||||||
"@vue-flow/background": "^1.3.2",
|
"@vue-flow/background": "^1.3.2",
|
||||||
"@vue-flow/controls": "^1.1.2",
|
"@vue-flow/controls": "^1.1.2",
|
||||||
"@vue-flow/core": "^1.47.0",
|
"@vue-flow/core": "^1.47.0",
|
||||||
@@ -105,6 +105,7 @@
|
|||||||
"patch-package": "^8.0.1",
|
"patch-package": "^8.0.1",
|
||||||
"playwright": "^1.55.0",
|
"playwright": "^1.55.0",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
|
"rimraf": "^6.0.1",
|
||||||
"rolldown-vite": "^7.1.20",
|
"rolldown-vite": "^7.1.20",
|
||||||
"rollup-plugin-copy": "^3.5.0",
|
"rollup-plugin-copy": "^3.5.0",
|
||||||
"sass": "^1.92.3",
|
"sass": "^1.92.3",
|
||||||
@@ -2118,6 +2119,29 @@
|
|||||||
"url": "https://github.com/sponsors/kazupon"
|
"url": "https://github.com/sponsors/kazupon"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@isaacs/balanced-match": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@isaacs/brace-expansion": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@isaacs/balanced-match": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@isaacs/cliui": {
|
"node_modules/@isaacs/cliui": {
|
||||||
"version": "8.0.2",
|
"version": "8.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
|
||||||
@@ -3296,9 +3320,9 @@
|
|||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/@kestra-io/ui-libs": {
|
"node_modules/@kestra-io/ui-libs": {
|
||||||
"version": "0.0.261",
|
"version": "0.0.263",
|
||||||
"resolved": "https://registry.npmjs.org/@kestra-io/ui-libs/-/ui-libs-0.0.261.tgz",
|
"resolved": "https://registry.npmjs.org/@kestra-io/ui-libs/-/ui-libs-0.0.263.tgz",
|
||||||
"integrity": "sha512-beKqB90UYHdJ8jwlTjrenqecYWxM8DuWRaxWogWLVOqFS191kmKo5Qme6fhLbOVMVVdsxH2nY4VIMIvYFnHIOw==",
|
"integrity": "sha512-j1rWqcQAK2CudNBkcDPjUXyaGFeBzJ7QEhPKFAbleHSw0N3QFu/iy0rFZxJNIMWRi1mGZBh74D6vL0OqQJkT2Q==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxtjs/mdc": "^0.17.3",
|
"@nuxtjs/mdc": "^0.17.3",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
@@ -12584,6 +12608,23 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/istanbul-lib-processinfo/node_modules/rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/istanbul-lib-processinfo/node_modules/uuid": {
|
"node_modules/istanbul-lib-processinfo/node_modules/uuid": {
|
||||||
"version": "8.3.2",
|
"version": "8.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
@@ -13421,6 +13462,23 @@
|
|||||||
"jest-runner": "^29.3.1"
|
"jest-runner": "^29.3.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jest-playwright-preset/node_modules/rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jest-playwright-preset/node_modules/uuid": {
|
"node_modules/jest-playwright-preset/node_modules/uuid": {
|
||||||
"version": "8.3.2",
|
"version": "8.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
@@ -17064,6 +17122,23 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/nyc/node_modules/rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/nyc/node_modules/semver": {
|
"node_modules/nyc/node_modules/semver": {
|
||||||
"version": "6.3.1",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
@@ -18910,17 +18985,133 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/rimraf": {
|
"node_modules/rimraf": {
|
||||||
"version": "3.0.2",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz",
|
||||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
"integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==",
|
||||||
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"glob": "^7.1.3"
|
"glob": "^11.0.0",
|
||||||
|
"package-json-from-dist": "^1.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"rimraf": "bin.js"
|
"rimraf": "dist/esm/bin.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rimraf/node_modules/foreground-child": {
|
||||||
|
"version": "3.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
|
||||||
|
"integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": "^7.0.6",
|
||||||
|
"signal-exit": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rimraf/node_modules/glob": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"foreground-child": "^3.3.1",
|
||||||
|
"jackspeak": "^4.1.1",
|
||||||
|
"minimatch": "^10.0.3",
|
||||||
|
"minipass": "^7.1.2",
|
||||||
|
"package-json-from-dist": "^1.0.0",
|
||||||
|
"path-scurry": "^2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"glob": "dist/esm/bin.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rimraf/node_modules/jackspeak": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BlueOak-1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"@isaacs/cliui": "^8.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rimraf/node_modules/lru-cache": {
|
||||||
|
"version": "11.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz",
|
||||||
|
"integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rimraf/node_modules/minimatch": {
|
||||||
|
"version": "10.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz",
|
||||||
|
"integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@isaacs/brace-expansion": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rimraf/node_modules/path-scurry": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BlueOak-1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"lru-cache": "^11.0.0",
|
||||||
|
"minipass": "^7.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "20 || >=22"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/rimraf/node_modules/signal-exit": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/isaacs"
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
@@ -19708,6 +19899,23 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/spawn-wrap/node_modules/rimraf": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||||
|
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"rimraf": "bin.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/isaacs"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/spawn-wrap/node_modules/semver": {
|
"node_modules/spawn-wrap/node_modules/semver": {
|
||||||
"version": "6.3.1",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
|
|||||||
@@ -19,12 +19,12 @@
|
|||||||
"lint": "eslint --fix",
|
"lint": "eslint --fix",
|
||||||
"storybook": "storybook dev -p 6006",
|
"storybook": "storybook dev -p 6006",
|
||||||
"build-storybook": "storybook build",
|
"build-storybook": "storybook build",
|
||||||
"prepare": "cd .. && husky ui/.husky && rm -f .git/hooks/*",
|
"prepare": "cd .. && husky ui/.husky && rimraf .git/hooks",
|
||||||
"postinstall": "patch-package"
|
"postinstall": "patch-package"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@js-joda/core": "^5.6.5",
|
"@js-joda/core": "^5.6.5",
|
||||||
"@kestra-io/ui-libs": "^0.0.261",
|
"@kestra-io/ui-libs": "^0.0.263",
|
||||||
"@vue-flow/background": "^1.3.2",
|
"@vue-flow/background": "^1.3.2",
|
||||||
"@vue-flow/controls": "^1.1.2",
|
"@vue-flow/controls": "^1.1.2",
|
||||||
"@vue-flow/core": "^1.47.0",
|
"@vue-flow/core": "^1.47.0",
|
||||||
@@ -119,6 +119,7 @@
|
|||||||
"patch-package": "^8.0.1",
|
"patch-package": "^8.0.1",
|
||||||
"playwright": "^1.55.0",
|
"playwright": "^1.55.0",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
|
"rimraf": "^6.0.1",
|
||||||
"rolldown-vite": "^7.1.20",
|
"rolldown-vite": "^7.1.20",
|
||||||
"rollup-plugin-copy": "^3.5.0",
|
"rollup-plugin-copy": "^3.5.0",
|
||||||
"sass": "^1.92.3",
|
"sass": "^1.92.3",
|
||||||
|
|||||||
@@ -35,16 +35,18 @@
|
|||||||
<WeatherSunny v-else />
|
<WeatherSunny v-else />
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="panelWrapper" :class="{panelTabResizing: resizing}" :style="{width: activeTab?.length ? `${panelWidth}px` : 0}">
|
<div class="panelWrapper" ref="panelWrapper" :class="{panelTabResizing: resizing}" :style="{width: activeTab?.length ? `${panelWidth}px` : 0}">
|
||||||
<div :style="{overflow: 'hidden'}">
|
<div :style="{overflow: 'hidden'}">
|
||||||
<button v-if="activeTab.length" class="closeButton" @click="setActiveTab('')">
|
<button v-if="activeTab.length" class="closeButton" @click="setActiveTab('')">
|
||||||
<Close />
|
<Close />
|
||||||
</button>
|
</button>
|
||||||
<ContextDocs v-if="activeTab === 'docs'" />
|
<KeepAlive v-if="activeTab">
|
||||||
<ContextNews v-else-if="activeTab === 'news'" />
|
<ContextDocs v-if="activeTab === 'docs'" />
|
||||||
<template v-else>
|
<ContextNews v-else-if="activeTab === 'news'" />
|
||||||
{{ activeTab }}
|
<template v-else>
|
||||||
</template>
|
{{ activeTab }}
|
||||||
|
</template>
|
||||||
|
</KeepAlive>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -96,6 +98,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const panelWidth = ref(640)
|
const panelWidth = ref(640)
|
||||||
|
const panelWrapper = ref<HTMLDivElement | null>(null)
|
||||||
|
|
||||||
const {startResizing, resizing} = useResizablePanel(activeTab)
|
const {startResizing, resizing} = useResizablePanel(activeTab)
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,22 @@
|
|||||||
<slot name="back-button" />
|
<slot name="back-button" />
|
||||||
<h2>{{ title }}</h2>
|
<h2>{{ title }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content" ref="contentRef">
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import {ref} from "vue";
|
||||||
|
|
||||||
defineProps<{title:string}>();
|
defineProps<{title:string}>();
|
||||||
|
|
||||||
|
const contentRef = ref<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
contentRef
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -197,7 +197,6 @@
|
|||||||
|
|
||||||
import {trackTabOpen, trackTabClose} from "../utils/tabTracking";
|
import {trackTabOpen, trackTabClose} from "../utils/tabTracking";
|
||||||
import {Panel, Tab, TabLive} from "../utils/multiPanelTypes";
|
import {Panel, Tab, TabLive} from "../utils/multiPanelTypes";
|
||||||
import {usePanelDefaultSize} from "../composables/usePanelDefaultSize";
|
|
||||||
|
|
||||||
const {t} = useI18n();
|
const {t} = useI18n();
|
||||||
const {showKeyShortcuts} = useKeyShortcuts();
|
const {showKeyShortcuts} = useKeyShortcuts();
|
||||||
@@ -449,7 +448,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSize = usePanelDefaultSize(panels);
|
const defaultSize = computed(() => panels.value.length === 0 ? 1 : (panels.value.reduce((acc, panel) => acc + panel.size, 0) / panels.value.length));
|
||||||
|
|
||||||
function newPanelDrop(_e: DragEvent, direction: "left" | "right") {
|
function newPanelDrop(_e: DragEvent, direction: "left" | "right") {
|
||||||
if (!movedTabInfo.value) return;
|
if (!movedTabInfo.value) return;
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
<template>
|
|
||||||
<el-button data-test-id="execution-status" class="status" :size="props.size ?? ''" :style="style">
|
|
||||||
{{ props.title || FILTERS.cap(props.status) }}
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import {computed} from "vue";
|
|
||||||
import * as FILTERS from "../utils/filters";
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
status: string;
|
|
||||||
size?: string;
|
|
||||||
title?: string;
|
|
||||||
label?: boolean;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const style = computed(() => {
|
|
||||||
const statusVarname = props.status?.toLowerCase();
|
|
||||||
return {
|
|
||||||
color: `var(--ks-content-${statusVarname}) !important`,
|
|
||||||
"border-color": `var(--ks-border-${statusVarname}) !important`,
|
|
||||||
"background-color": `var(--ks-background-${statusVarname}) !important`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<style scoped lang="scss">
|
|
||||||
button.el-button {
|
|
||||||
white-space: nowrap;
|
|
||||||
border-radius: var(--el-border-radius-base);
|
|
||||||
width: 7rem;
|
|
||||||
cursor: default;
|
|
||||||
|
|
||||||
&.no-label {
|
|
||||||
padding: 0.5rem;
|
|
||||||
line-height: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -128,14 +128,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getTabClasses(tab) {
|
getTabClasses(tab) {
|
||||||
const isEnterpriseTab = tab.locked;
|
if(tab.locked) return {"px-0": true};
|
||||||
|
return {"container": true, "mt-4": true};
|
||||||
return {
|
}
|
||||||
"container": !isEnterpriseTab,
|
|
||||||
"mt-4": !isEnterpriseTab,
|
|
||||||
"px-0": isEnterpriseTab,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
containerClass() {
|
containerClass() {
|
||||||
|
|||||||
@@ -5,17 +5,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
const props = defineProps({
|
import type {Component} from "vue";
|
||||||
icon: {
|
|
||||||
type: Object,
|
const props = defineProps<{
|
||||||
required: true
|
icon: Component;
|
||||||
},
|
label: string;
|
||||||
label: {
|
}>();
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -41,7 +41,13 @@
|
|||||||
<template #expand>
|
<template #expand>
|
||||||
<el-table-column type="expand">
|
<el-table-column type="expand">
|
||||||
<template #default="props">
|
<template #default="props">
|
||||||
<LogsWrapper class="m-3" :filters="props.row" v-if="hasLogsContent(props.row)" :withCharts="false" embed />
|
<LogsWrapper
|
||||||
|
class="m-3"
|
||||||
|
:filters="props.row"
|
||||||
|
v-if="hasLogsContent(props.row)"
|
||||||
|
:withCharts="false"
|
||||||
|
embed
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</template>
|
</template>
|
||||||
@@ -71,6 +77,9 @@
|
|||||||
<el-button @click="deleteBackfills()">
|
<el-button @click="deleteBackfills()">
|
||||||
{{ $t("delete backfills") }}
|
{{ $t("delete backfills") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button @click="deleteTriggers()" type="danger">
|
||||||
|
{{ $t("delete triggers") }}
|
||||||
|
</el-button>
|
||||||
</BulkSelect>
|
</BulkSelect>
|
||||||
</template>
|
</template>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
@@ -95,17 +104,32 @@
|
|||||||
:sortOrders="['flowId', 'namespace', 'nextExecutionDate'].includes(col.prop) ? ['ascending', 'descending'] : undefined"
|
:sortOrders="['flowId', 'namespace', 'nextExecutionDate'].includes(col.prop) ? ['ascending', 'descending'] : undefined"
|
||||||
>
|
>
|
||||||
<template #header v-if="col.prop === 'date'">
|
<template #header v-if="col.prop === 'date'">
|
||||||
<el-tooltip :content="$t('last trigger date tooltip')" placement="top" effect="light" popperClass="wide-tooltip">
|
<el-tooltip
|
||||||
|
:content="$t('last trigger date tooltip')"
|
||||||
|
placement="top"
|
||||||
|
effect="light"
|
||||||
|
popperClass="wide-tooltip"
|
||||||
|
>
|
||||||
<span>{{ col.label }}</span>
|
<span>{{ col.label }}</span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<template #header v-else-if="col.prop === 'updatedDate'">
|
<template #header v-else-if="col.prop === 'updatedDate'">
|
||||||
<el-tooltip :content="$t('context updated date tooltip')" placement="top" effect="light" popperClass="wide-tooltip">
|
<el-tooltip
|
||||||
|
:content="$t('context updated date tooltip')"
|
||||||
|
placement="top"
|
||||||
|
effect="light"
|
||||||
|
popperClass="wide-tooltip"
|
||||||
|
>
|
||||||
<span>{{ col.label }}</span>
|
<span>{{ col.label }}</span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
<template #header v-else-if="col.prop === 'nextExecutionDate'">
|
<template #header v-else-if="col.prop === 'nextExecutionDate'">
|
||||||
<el-tooltip :content="$t('next evaluation date tooltip')" placement="top" effect="light" popperClass="wide-tooltip">
|
<el-tooltip
|
||||||
|
:content="$t('next evaluation date tooltip')"
|
||||||
|
placement="top"
|
||||||
|
effect="light"
|
||||||
|
popperClass="wide-tooltip"
|
||||||
|
>
|
||||||
<span>{{ col.label }}</span>
|
<span>{{ col.label }}</span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
@@ -181,13 +205,26 @@
|
|||||||
<LockOff />
|
<LockOff />
|
||||||
</Kicon>
|
</Kicon>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button>
|
||||||
|
<Kicon
|
||||||
|
:tooltip="$t('delete trigger')"
|
||||||
|
placement="left"
|
||||||
|
@click="confirmDeleteTrigger(scope.row)"
|
||||||
|
>
|
||||||
|
<Delete />
|
||||||
|
</Kicon>
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('backfill')" columnKey="backfill">
|
<el-table-column :label="$t('backfill')" columnKey="backfill">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div class="backfillContainer items-center gap-2">
|
<div class="backfillContainer items-center gap-2">
|
||||||
<span v-if="scope.row.backfill" class="statusIcon">
|
<span v-if="scope.row.backfill" class="statusIcon">
|
||||||
<el-tooltip v-if="!scope.row.backfill.paused" :content="$t('backfill running')" effect="light">
|
<el-tooltip
|
||||||
|
v-if="!scope.row.backfill.paused"
|
||||||
|
:content="$t('backfill running')"
|
||||||
|
effect="light"
|
||||||
|
>
|
||||||
<PlayBox font />
|
<PlayBox font />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip v-else :content="$t('backfill paused')">
|
<el-tooltip v-else :content="$t('backfill paused')">
|
||||||
@@ -298,6 +335,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import _merge from "lodash/merge";
|
import _merge from "lodash/merge";
|
||||||
import {ref, computed, watch} from "vue";
|
import {ref, computed, watch} from "vue";
|
||||||
|
import moment from "moment";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import {useRoute} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
import {ElMessage} from "element-plus";
|
import {ElMessage} from "element-plus";
|
||||||
@@ -311,18 +349,16 @@
|
|||||||
import {useTriggerFilter} from "../filter/configurations";
|
import {useTriggerFilter} from "../filter/configurations";
|
||||||
import {useDataTableActions} from "../../composables/useDataTableActions";
|
import {useDataTableActions} from "../../composables/useDataTableActions";
|
||||||
import {useSelectTableActions} from "../../composables/useSelectTableActions";
|
import {useSelectTableActions} from "../../composables/useSelectTableActions";
|
||||||
import {useTableColumns, type ColumnConfig} from "../../composables/useTableColumns";
|
import {type ColumnConfig, useTableColumns} from "../../composables/useTableColumns";
|
||||||
|
|
||||||
import action from "../../models/action";
|
import action from "../../models/action";
|
||||||
import permission from "../../models/permission";
|
import permission from "../../models/permission";
|
||||||
|
|
||||||
const triggerFilter = useTriggerFilter();
|
|
||||||
|
|
||||||
import LockOff from "vue-material-design-icons/LockOff.vue";
|
import LockOff from "vue-material-design-icons/LockOff.vue";
|
||||||
import PlayBox from "vue-material-design-icons/PlayBox.vue";
|
import PlayBox from "vue-material-design-icons/PlayBox.vue";
|
||||||
import PauseBox from "vue-material-design-icons/PauseBox.vue";
|
import PauseBox from "vue-material-design-icons/PauseBox.vue";
|
||||||
import AlertCircle from "vue-material-design-icons/AlertCircle.vue";
|
import AlertCircle from "vue-material-design-icons/AlertCircle.vue";
|
||||||
import CalendarCollapseHorizontalOutline from "vue-material-design-icons/CalendarCollapseHorizontalOutline.vue";
|
import CalendarCollapseHorizontalOutline from "vue-material-design-icons/CalendarCollapseHorizontalOutline.vue";
|
||||||
|
import Delete from "vue-material-design-icons/Delete.vue";
|
||||||
|
|
||||||
import Id from "../Id.vue";
|
import Id from "../Id.vue";
|
||||||
import Kicon from "../Kicon.vue";
|
import Kicon from "../Kicon.vue";
|
||||||
@@ -341,6 +377,8 @@
|
|||||||
import MarkdownTooltip from "../layout/MarkdownTooltip.vue";
|
import MarkdownTooltip from "../layout/MarkdownTooltip.vue";
|
||||||
import useRouteContext from "../../composables/useRouteContext";
|
import useRouteContext from "../../composables/useRouteContext";
|
||||||
|
|
||||||
|
const triggerFilter = useTriggerFilter();
|
||||||
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
@@ -369,55 +407,55 @@
|
|||||||
end: null,
|
end: null,
|
||||||
inputs: null,
|
inputs: null,
|
||||||
labels: []
|
labels: []
|
||||||
});
|
});
|
||||||
|
|
||||||
const optionalColumns = computed(() => [
|
const optionalColumns = computed(() => [
|
||||||
{
|
{
|
||||||
label: t("flow"),
|
label: t("flow"),
|
||||||
prop: "flowId",
|
prop: "flowId",
|
||||||
default: true,
|
default: true,
|
||||||
description: t("filter.table_column.triggers.flow")
|
description: t("filter.table_column.triggers.flow")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t("namespace"),
|
label: t("namespace"),
|
||||||
prop: "namespace",
|
prop: "namespace",
|
||||||
default: true,
|
default: true,
|
||||||
description: t("filter.table_column.triggers.namespace")
|
description: t("filter.table_column.triggers.namespace")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t("current execution"),
|
label: t("current execution"),
|
||||||
prop: "executionId",
|
prop: "executionId",
|
||||||
default: false,
|
default: false,
|
||||||
description: t("filter.table_column.triggers.current execution")
|
description: t("filter.table_column.triggers.current execution")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t("workerId"),
|
label: t("workerId"),
|
||||||
prop: "workerId",
|
prop: "workerId",
|
||||||
default: false,
|
default: false,
|
||||||
description: t("filter.table_column.triggers.workerId")
|
description: t("filter.table_column.triggers.workerId")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t("last trigger date"),
|
label: t("last trigger date"),
|
||||||
prop: "date",
|
prop: "date",
|
||||||
default: true,
|
default: true,
|
||||||
description: t("filter.table_column.triggers.last trigger date")
|
description: t("filter.table_column.triggers.last trigger date")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t("context updated date"),
|
label: t("context updated date"),
|
||||||
prop: "updatedDate",
|
prop: "updatedDate",
|
||||||
default: false,
|
default: false,
|
||||||
description: t("filter.table_column.triggers.context updated date")
|
description: t("filter.table_column.triggers.context updated date")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t("next evaluation date"),
|
label: t("next evaluation date"),
|
||||||
prop: "nextExecutionDate",
|
prop: "nextExecutionDate",
|
||||||
default: false,
|
default: false,
|
||||||
description: t("filter.table_column.triggers.next evaluation date")
|
description: t("filter.table_column.triggers.next evaluation date")
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t("evaluation lock date"),
|
label: t("evaluation lock date"),
|
||||||
prop: "evaluateRunningDate",
|
prop: "evaluateRunningDate",
|
||||||
default: false,
|
default: false,
|
||||||
description: t("filter.table_column.triggers.evaluation lock date")
|
description: t("filter.table_column.triggers.evaluation lock date")
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
@@ -430,7 +468,7 @@
|
|||||||
initialVisibleColumns: optionalColumns.value.filter(col => col.default).map(col => col.prop)
|
initialVisibleColumns: optionalColumns.value.filter(col => col.default).map(col => col.prop)
|
||||||
});
|
});
|
||||||
|
|
||||||
const visibleColumns = computed(() =>
|
const visibleColumns = computed(() =>
|
||||||
displayColumns.value
|
displayColumns.value
|
||||||
.map(prop => optionalColumns.value.find(c => c.prop === prop))
|
.map(prop => optionalColumns.value.find(c => c.prop === prop))
|
||||||
.filter(Boolean) as ColumnConfig[]
|
.filter(Boolean) as ColumnConfig[]
|
||||||
@@ -468,7 +506,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
queryBulkAction,
|
queryBulkAction,
|
||||||
selection,
|
selection,
|
||||||
handleSelectionChange,
|
handleSelectionChange,
|
||||||
toggleAllUnselected,
|
toggleAllUnselected,
|
||||||
@@ -544,7 +582,7 @@
|
|||||||
const disabledEndDate = (time: Date) => {
|
const disabledEndDate = (time: Date) => {
|
||||||
return new Date() < time || (backfill.value.start && backfill.value.start > time);
|
return new Date() < time || (backfill.value.start && backfill.value.start > time);
|
||||||
};
|
};
|
||||||
|
|
||||||
const triggerLoadDataAfterBulkEditAction = () => {
|
const triggerLoadDataAfterBulkEditAction = () => {
|
||||||
loadData();
|
loadData();
|
||||||
setTimeout(() => loadData(), 200);
|
setTimeout(() => loadData(), 200);
|
||||||
@@ -601,9 +639,44 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const genericConfirmAction = (toastKey: string, queryAction: string, byIdAction: string, success: string, data?: any) => {
|
const confirmDeleteTrigger = (trigger) => {
|
||||||
toast.confirm(
|
toast.confirm(
|
||||||
t(toastKey, {"count": queryBulkAction.value ? total.value : selection.value?.length}) + ". " + t("bulk action async warning"),
|
t("delete trigger confirmation", {id: trigger.id}),
|
||||||
|
() => triggerStore.delete({
|
||||||
|
namespace: trigger.namespace,
|
||||||
|
flowId: trigger.flowId,
|
||||||
|
triggerId: trigger.triggerId
|
||||||
|
}).then(() => {
|
||||||
|
toast.success(t("delete trigger success", {id: trigger.id}));
|
||||||
|
loadData();
|
||||||
|
}).catch(error => {
|
||||||
|
toast.error(t("delete trigger error", {id: trigger.id}));
|
||||||
|
console.error(error);
|
||||||
|
}),
|
||||||
|
"warning"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteTriggers = () => {
|
||||||
|
genericConfirmAction(
|
||||||
|
"bulk delete triggers",
|
||||||
|
"deleteByQuery",
|
||||||
|
"deleteByTriggers",
|
||||||
|
"bulk success delete triggers",
|
||||||
|
null,
|
||||||
|
"WARNING: deleting triggers may lead to duplicate executions if the triggers are still active in flows"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const genericConfirmAction = (toastKey: string, queryAction: string, byIdAction: string, success: string, data?: any, extraWarning = null) => {
|
||||||
|
let message = t(toastKey, {"count": queryBulkAction.value ? total.value : selection.value?.length}) + ". " + t("bulk action async warning");
|
||||||
|
|
||||||
|
if (extraWarning) {
|
||||||
|
message += "<br><br><strong>" + extraWarning + "</strong>";
|
||||||
|
}
|
||||||
|
|
||||||
|
toast.confirm(
|
||||||
|
message,
|
||||||
() => genericConfirmCallback(queryAction, byIdAction, success, data)
|
() => genericConfirmCallback(queryAction, byIdAction, success, data)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -620,6 +693,8 @@
|
|||||||
"unlockByTriggers": () => triggerStore.unlockByTriggers,
|
"unlockByTriggers": () => triggerStore.unlockByTriggers,
|
||||||
"setDisabledByQuery": () => triggerStore.setDisabledByQuery,
|
"setDisabledByQuery": () => triggerStore.setDisabledByQuery,
|
||||||
"setDisabledByTriggers": () => triggerStore.setDisabledByTriggers,
|
"setDisabledByTriggers": () => triggerStore.setDisabledByTriggers,
|
||||||
|
"deleteByQuery": () => triggerStore.deleteByQuery,
|
||||||
|
"deleteByTriggers": () => triggerStore.deleteByTriggers,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (queryBulkAction.value) {
|
if (queryBulkAction.value) {
|
||||||
@@ -696,7 +771,16 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const loadQuery = (base: any) => {
|
const loadQuery = (base: any) => {
|
||||||
let queryFilter = queryWithFilter();
|
const queryFilter = queryWithFilter();
|
||||||
|
|
||||||
|
const timeRange = queryFilter["filters[timeRange][EQUALS]"];
|
||||||
|
if (timeRange) {
|
||||||
|
const end = new Date();
|
||||||
|
const start = new Date(end.getTime() - moment.duration(timeRange).asMilliseconds());
|
||||||
|
queryFilter["filters[startDate][GREATER_THAN_OR_EQUAL_TO]"] = start.toISOString();
|
||||||
|
queryFilter["filters[endDate][LESS_THAN_OR_EQUAL_TO]"] = end.toISOString();
|
||||||
|
delete queryFilter["filters[timeRange][EQUALS]"];
|
||||||
|
}
|
||||||
|
|
||||||
return _merge(base, queryFilter);
|
return _merge(base, queryFilter);
|
||||||
};
|
};
|
||||||
@@ -752,86 +836,86 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.data-table-wrapper {
|
.data-table-wrapper {
|
||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
padding-left: 0 !important;
|
padding-left: 0 !important;
|
||||||
}
|
|
||||||
|
|
||||||
.backfillContainer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.statusIcon {
|
|
||||||
font-size: large;
|
|
||||||
}
|
|
||||||
|
|
||||||
.trigger-issue-icon {
|
|
||||||
color: var(--ks-content-warning);
|
|
||||||
font-size: 1.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-circle-icon {
|
|
||||||
color: var(--ks-content-warning);
|
|
||||||
font-size: 1.4em;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-table__expand-icon) {
|
|
||||||
pointer-events: none;
|
|
||||||
|
|
||||||
.el-icon {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-switch) {
|
|
||||||
.is-text {
|
|
||||||
padding: 0 3px;
|
|
||||||
color: inherit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-checked {
|
.backfillContainer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusIcon {
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-issue-icon {
|
||||||
|
color: var(--ks-content-warning);
|
||||||
|
font-size: 1.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-circle-icon {
|
||||||
|
color: var(--ks-content-warning);
|
||||||
|
font-size: 1.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-table__expand-icon) {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-switch) {
|
||||||
.is-text {
|
.is-text {
|
||||||
color: #ffffff;
|
padding: 0 3px;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-checked {
|
||||||
|
.is-text {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.el-table {
|
.el-table {
|
||||||
a {
|
a {
|
||||||
color: var(--ks-content-link);
|
color: var(--ks-content-link);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.wide-tooltip {
|
|
||||||
max-width: 400px;
|
|
||||||
white-space: normal;
|
|
||||||
word-break: break-word;
|
|
||||||
color: var(--ks-content-primary) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-collapse) {
|
|
||||||
border-radius: var(--bs-border-radius-lg);
|
|
||||||
border: 1px solid var(--ks-border-primary);
|
|
||||||
background: var(--bs-gray-100);
|
|
||||||
|
|
||||||
.el-collapse-item__header {
|
|
||||||
background: transparent;
|
|
||||||
border-bottom: 1px solid var(--ks-border-primary);
|
|
||||||
font-size: var(--bs-font-size-sm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-collapse-item__content {
|
.wide-tooltip {
|
||||||
|
max-width: 400px;
|
||||||
|
white-space: normal;
|
||||||
|
word-break: break-word;
|
||||||
|
color: var(--ks-content-primary) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-collapse) {
|
||||||
|
border-radius: var(--bs-border-radius-lg);
|
||||||
|
border: 1px solid var(--ks-border-primary);
|
||||||
background: var(--bs-gray-100);
|
background: var(--bs-gray-100);
|
||||||
border-bottom: 1px solid var(--ks-border-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-collapse-item__header,
|
.el-collapse-item__header {
|
||||||
.el-collapse-item__content {
|
background: transparent;
|
||||||
&:last-child {
|
border-bottom: 1px solid var(--ks-border-primary);
|
||||||
border-bottom-left-radius: var(--bs-border-radius-lg);
|
font-size: var(--bs-font-size-sm);
|
||||||
border-bottom-right-radius: var(--bs-border-radius-lg);
|
}
|
||||||
|
|
||||||
|
.el-collapse-item__content {
|
||||||
|
background: var(--bs-gray-100);
|
||||||
|
border-bottom: 1px solid var(--ks-border-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-collapse-item__header,
|
||||||
|
.el-collapse-item__content {
|
||||||
|
&:last-child {
|
||||||
|
border-bottom-left-radius: var(--bs-border-radius-lg);
|
||||||
|
border-bottom-right-radius: var(--bs-border-radius-lg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
</style>
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -194,6 +194,10 @@
|
|||||||
showClose: false
|
showClose: false
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage.error({
|
||||||
|
message: t("setup.validation.incorrect_creds")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
ElMessage.error({
|
ElMessage.error({
|
||||||
@@ -266,6 +270,7 @@
|
|||||||
.basic-auth-login {
|
.basic-auth-login {
|
||||||
flex-shrink: 1;
|
flex-shrink: 1;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
|
container-type: inline-size;
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
width: 250px;
|
width: 250px;
|
||||||
@@ -306,5 +311,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
width: 100%;
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 200px;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form {
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, onBeforeMount, ref, useTemplateRef} from "vue";
|
import {computed, onBeforeMount, ref, useTemplateRef, watch} from "vue";
|
||||||
import {stringify, parse} from "@kestra-io/ui-libs/flow-yaml-utils";
|
import {stringify, parse} from "@kestra-io/ui-libs/flow-yaml-utils";
|
||||||
|
|
||||||
import type {Dashboard, Chart} from "./composables/useDashboards";
|
import type {Dashboard, Chart} from "./composables/useDashboards";
|
||||||
@@ -89,9 +89,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!props.isFlow && !props.isNamespace) {
|
if (!props.isFlow && !props.isNamespace) {
|
||||||
|
// Preserve timeRange filter when switching dashboards
|
||||||
|
const preservedQuery = Object.fromEntries(
|
||||||
|
Object.entries(route.query).filter(([key]) =>
|
||||||
|
key.includes("timeRange")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
router.replace({
|
router.replace({
|
||||||
params: {...route.params, dashboard: id},
|
params: {...route.params, dashboard: id},
|
||||||
query: route.params.dashboard !== id ? {} : {...route.query},
|
query: route.params.dashboard !== id ? preservedQuery : {...route.query},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,8 +109,22 @@
|
|||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
const ID = getDashboard(route, "id");
|
const ID = getDashboard(route, "id");
|
||||||
|
|
||||||
if (props.isFlow && ID === "default") load("default", processFlowYaml(YAML_FLOW, route.params.namespace as string, route.params.id as string));
|
if (props.isFlow) {
|
||||||
else if (props.isNamespace && ID === "default") load("default", YAML_NAMESPACE);
|
load(ID, processFlowYaml(YAML_FLOW, route.params.namespace as string, route.params.id as string));
|
||||||
|
} else if (props.isNamespace) {
|
||||||
|
load(ID, YAML_NAMESPACE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => getDashboard(route, "id"), (newId, oldId) => {
|
||||||
|
if (newId !== oldId) {
|
||||||
|
const defaultYAML = props.isFlow
|
||||||
|
? processFlowYaml(YAML_FLOW, route.params.namespace as string, route.params.id as string)
|
||||||
|
: props.isNamespace
|
||||||
|
? YAML_NAMESPACE
|
||||||
|
: YAML_MAIN;
|
||||||
|
load(newId, defaultYAML);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -28,33 +28,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadChart(chart: any) {
|
|
||||||
const yamlChart = YAML_UTILS.stringify(chart);
|
|
||||||
const result: { error: string | null; data: null | {
|
|
||||||
id?: string;
|
|
||||||
name?: string;
|
|
||||||
type?: string;
|
|
||||||
chartOptions?: Record<string, any>;
|
|
||||||
dataFilters?: any[];
|
|
||||||
charts?: any[];
|
|
||||||
}; raw: any } = {
|
|
||||||
error: null,
|
|
||||||
data: null,
|
|
||||||
raw: {}
|
|
||||||
};
|
|
||||||
const errors = await dashboardStore.validateChart(yamlChart);
|
|
||||||
if (errors.constraints) {
|
|
||||||
result.error = errors.constraints;
|
|
||||||
} else {
|
|
||||||
result.data = {...chart, content: yamlChart, raw: chart};
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateChartPreview(event: any) {
|
async function updateChartPreview(event: any) {
|
||||||
const chart = YAML_UTILS.getChartAtPosition(event.model.getValue(), event.position);
|
const chart = YAML_UTILS.getChartAtPosition(event.model.getValue(), event.position);
|
||||||
if (chart) {
|
if (chart) {
|
||||||
const result = await loadChart(chart);
|
const result = await dashboardStore.loadChart(chart);
|
||||||
dashboardStore.selectedChart = typeof result.data === "object"
|
dashboardStore.selectedChart = typeof result.data === "object"
|
||||||
? {
|
? {
|
||||||
...result.data,
|
...result.data,
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
FIELDNAME_INJECTION_KEY,
|
FIELDNAME_INJECTION_KEY,
|
||||||
FULL_SCHEMA_INJECTION_KEY,
|
FULL_SCHEMA_INJECTION_KEY,
|
||||||
FULL_SOURCE_INJECTION_KEY,
|
FULL_SOURCE_INJECTION_KEY,
|
||||||
|
ON_TASK_EDITOR_CLICK_INJECTION_KEY,
|
||||||
PARENT_PATH_INJECTION_KEY,
|
PARENT_PATH_INJECTION_KEY,
|
||||||
POSITION_INJECTION_KEY,
|
POSITION_INJECTION_KEY,
|
||||||
REF_PATH_INJECTION_KEY,
|
REF_PATH_INJECTION_KEY,
|
||||||
@@ -111,6 +112,15 @@
|
|||||||
provide(BLOCK_SCHEMA_PATH_INJECTION_KEY, computed(() => props.blockSchemaPath ?? dashboardStore.schema.$ref ?? ""));
|
provide(BLOCK_SCHEMA_PATH_INJECTION_KEY, computed(() => props.blockSchemaPath ?? dashboardStore.schema.$ref ?? ""));
|
||||||
provide(FULL_SOURCE_INJECTION_KEY, computed(() => dashboardStore.sourceCode ?? ""));
|
provide(FULL_SOURCE_INJECTION_KEY, computed(() => dashboardStore.sourceCode ?? ""));
|
||||||
provide(POSITION_INJECTION_KEY, props.position ?? "after");
|
provide(POSITION_INJECTION_KEY, props.position ?? "after");
|
||||||
|
provide(ON_TASK_EDITOR_CLICK_INJECTION_KEY, (elt) => {
|
||||||
|
const type = elt?.type;
|
||||||
|
dashboardStore.loadChart(elt);
|
||||||
|
if(type){
|
||||||
|
pluginsStore.updateDocumentation({type});
|
||||||
|
}else{
|
||||||
|
pluginsStore.updateDocumentation();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const pluginsStore = usePluginsStore();
|
const pluginsStore = usePluginsStore();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="w-100 p-4">
|
<div class="w-100 p-4">
|
||||||
<Sections
|
<Sections
|
||||||
|
:key="dashboardStore.sourceCode"
|
||||||
:dashboard="{id: 'default', charts: []}"
|
:dashboard="{id: 'default', charts: []}"
|
||||||
:charts="charts.map(chart => chart.data).filter(chart => chart !== null)"
|
:charts="charts.map(chart => chart.data).filter(chart => chart !== null)"
|
||||||
showDefault
|
showDefault
|
||||||
@@ -9,11 +10,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {onMounted, ref} from "vue";
|
import {ref, watch} from "vue";
|
||||||
import Sections from "../sections/Sections.vue";
|
import Sections from "../sections/Sections.vue";
|
||||||
import {Chart} from "../composables/useDashboards";
|
import {Chart} from "../composables/useDashboards";
|
||||||
import {useDashboardStore} from "../../../stores/dashboard";
|
import {useDashboardStore} from "../../../stores/dashboard";
|
||||||
import * as YAML_UTILS from "@kestra-io/ui-libs/flow-yaml-utils";
|
import * as YAML_UTILS from "@kestra-io/ui-libs/flow-yaml-utils";
|
||||||
|
import throttle from "lodash/throttle";
|
||||||
|
|
||||||
interface Result {
|
interface Result {
|
||||||
error: string[] | null;
|
error: string[] | null;
|
||||||
@@ -23,21 +25,27 @@
|
|||||||
|
|
||||||
const charts = ref<Result[]>([])
|
const charts = ref<Result[]>([])
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
validateAndLoadAllCharts();
|
|
||||||
});
|
|
||||||
|
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
function validateAndLoadAllCharts() {
|
const validateAndLoadAllChartsThrottled = throttle(validateAndLoadAllCharts, 500);
|
||||||
charts.value = [];
|
|
||||||
|
async function validateAndLoadAllCharts() {
|
||||||
const allCharts = YAML_UTILS.getAllCharts(dashboardStore.sourceCode) ?? [];
|
const allCharts = YAML_UTILS.getAllCharts(dashboardStore.sourceCode) ?? [];
|
||||||
allCharts.forEach(async (chart: any) => {
|
charts.value = await Promise.all(allCharts.map(async (chart: any) => {
|
||||||
const loadedChart = await loadChart(chart);
|
return loadChart(chart);
|
||||||
charts.value.push(loadedChart);
|
}));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => dashboardStore.sourceCode,
|
||||||
|
() => {
|
||||||
|
validateAndLoadAllChartsThrottled();
|
||||||
|
}
|
||||||
|
, {immediate: true}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function loadChart(chart: any) {
|
async function loadChart(chart: any) {
|
||||||
const yamlChart = YAML_UTILS.stringify(chart);
|
const yamlChart = YAML_UTILS.stringify(chart);
|
||||||
const result: Result = {
|
const result: Result = {
|
||||||
|
|||||||
@@ -96,14 +96,19 @@
|
|||||||
return [DEFAULT, ...dashboards.value].filter((d) => !search.value || d.title.toLowerCase().includes(search.value.toLowerCase()));
|
return [DEFAULT, ...dashboards.value].filter((d) => !search.value || d.title.toLowerCase().includes(search.value.toLowerCase()));
|
||||||
});
|
});
|
||||||
|
|
||||||
const ID = getDashboard(route, "id") as string;
|
const STORAGE_KEY = getDashboard(route, "key");
|
||||||
|
|
||||||
const selected = ref(null);
|
const selected = ref<string | null>(null);
|
||||||
const select = (dashboard: any) => {
|
const select = (dashboard: any) => {
|
||||||
selected.value = dashboard?.title;
|
selected.value = dashboard?.title;
|
||||||
|
|
||||||
if (dashboard?.id) localStorage.setItem(ID, dashboard.id)
|
if (STORAGE_KEY) {
|
||||||
else localStorage.removeItem(ID);
|
if (dashboard?.id) {
|
||||||
|
localStorage.setItem(STORAGE_KEY, dashboard.id);
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem(STORAGE_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emits("dashboard", dashboard.id);
|
emits("dashboard", dashboard.id);
|
||||||
};
|
};
|
||||||
@@ -121,7 +126,7 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchLast = () => localStorage.getItem(ID);
|
const getStoredDashboard = () => STORAGE_KEY ? localStorage.getItem(STORAGE_KEY) : null;
|
||||||
const fetchDashboards = () => {
|
const fetchDashboards = () => {
|
||||||
dashboardStore
|
dashboardStore
|
||||||
.list({})
|
.list({})
|
||||||
@@ -129,13 +134,17 @@
|
|||||||
dashboards.value = response.results;
|
dashboards.value = response.results;
|
||||||
|
|
||||||
const creation = Boolean(route.query.created);
|
const creation = Boolean(route.query.created);
|
||||||
const lastSelected = creation ? (route.params?.dashboard ?? fetchLast()) : (fetchLast() ?? route.params?.dashboard);
|
const lastSelected = creation
|
||||||
|
? (route.params?.dashboard ?? getStoredDashboard())
|
||||||
|
: (getStoredDashboard() ?? route.params?.dashboard);
|
||||||
|
|
||||||
if (lastSelected) {
|
if (lastSelected) {
|
||||||
const dashboard = dashboards.value.find((d) => d.id === lastSelected);
|
const dashboard = dashboards.value.find((d) => d.id === lastSelected);
|
||||||
|
|
||||||
if (dashboard) select(dashboard);
|
if (dashboard) {
|
||||||
else {
|
selected.value = dashboard.title;
|
||||||
|
emits("dashboard", dashboard.id);
|
||||||
|
} else {
|
||||||
selected.value = null;
|
selected.value = null;
|
||||||
emits("dashboard", "default");
|
emits("dashboard", "default");
|
||||||
}
|
}
|
||||||
@@ -145,15 +154,19 @@
|
|||||||
|
|
||||||
onBeforeMount(() => fetchDashboards());
|
onBeforeMount(() => fetchDashboards());
|
||||||
|
|
||||||
const tenant = ref(route.params.tenant);
|
const tenant = ref();
|
||||||
watch(route, (r) => {
|
watch(() => route.params.tenant, (t) => {
|
||||||
if (tenant.value !== r.params.tenant) {
|
if (tenant.value !== t) {
|
||||||
fetchDashboards();
|
fetchDashboards();
|
||||||
tenant.value = r.params.tenant;
|
tenant.value = t;
|
||||||
}
|
}
|
||||||
},
|
}, {immediate: true});
|
||||||
{deep: true},
|
|
||||||
);
|
watch(() => route.params?.dashboard, (val) => {
|
||||||
|
if(route.name === "home" && STORAGE_KEY) {
|
||||||
|
localStorage.setItem(STORAGE_KEY, val as string);
|
||||||
|
}
|
||||||
|
}, {immediate: true});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@@ -161,14 +174,6 @@
|
|||||||
span{
|
span{
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(svg){
|
|
||||||
color: var(--ks-content-tertiary);
|
|
||||||
font-size: 1.10rem;
|
|
||||||
position: absolute;
|
|
||||||
bottom: -0.10rem;
|
|
||||||
right: 0.08rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.dropdown {
|
.dropdown {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
|||||||
@@ -121,16 +121,32 @@
|
|||||||
const dataset = chart.data.datasets[0];
|
const dataset = chart.data.datasets[0];
|
||||||
const meta = chart.getDatasetMeta(0);
|
const meta = chart.getDatasetMeta(0);
|
||||||
|
|
||||||
const thicknessScale = dataset.thicknessScale;
|
//dynamically calculate thickness based on chart size
|
||||||
|
const chartArea = chart.chartArea;
|
||||||
|
if (!chartArea || !meta || !meta.data) return;
|
||||||
|
// Available radius = half of the smaller dimension (width or height)
|
||||||
|
const availableRadius = Math.min(chartArea.width, chartArea.height) / 2;
|
||||||
|
// define thickness bounds relative to available radius
|
||||||
|
const minThicknessPx = Math.max(6, availableRadius * 0.05); // >0
|
||||||
|
const maxThicknessPx = Math.max(12, availableRadius * 0.3); // >0
|
||||||
|
// Reading weights from dataset with fallback weight(1)
|
||||||
|
const weights: number[] = (dataset.thicknessWeight && Array.isArray(dataset.thicknessWeight))? dataset.thicknessWeight.map((w: any) =>
|
||||||
|
{
|
||||||
|
const n = Number(w);
|
||||||
|
return Number.isFinite(n) ? Math.min(Math.max(n, 0), 1) : 1;
|
||||||
|
})
|
||||||
|
: meta.data.map(() => 1);
|
||||||
|
for (let i = 0; i < meta.data.length; i++) {
|
||||||
|
const arc = meta.data[i];
|
||||||
|
const w = weights[i] ?? 1;
|
||||||
|
const thicknessPx = minThicknessPx + w * (maxThicknessPx - minThicknessPx);
|
||||||
|
|
||||||
meta.data.forEach((arc, index) => {
|
const baseRadius = arc.innerRadius ?? Math.max(0, availableRadius - thicknessPx);
|
||||||
const baseRadius = arc.innerRadius;
|
arc.outerRadius = baseRadius + thicknessPx;
|
||||||
const additionalThickness = thicknessScale[index];
|
|
||||||
arc.outerRadius = baseRadius + additionalThickness;
|
|
||||||
arc.innerRadius = baseRadius;
|
arc.innerRadius = baseRadius;
|
||||||
|
|
||||||
arc.draw(ctx);
|
arc.draw(ctx);
|
||||||
});
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -199,9 +215,9 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
$height: 200px;
|
|
||||||
|
.chart {
|
||||||
.chart {
|
height: 100% !important;
|
||||||
max-height: $height;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<section id="charts" :class="{padding}">
|
<div class="dashboard-sections-container">
|
||||||
<el-row :gutter="16">
|
<section id="charts" :class="{padding}">
|
||||||
<el-col
|
<div
|
||||||
v-for="chart in props.charts"
|
v-for="chart in props.charts"
|
||||||
:key="`chart__${chart.id}`"
|
:key="`chart__${chart.id}`"
|
||||||
:xs="24"
|
class="dashboard-block"
|
||||||
:sm="(chart.chartOptions?.width || 6) * 4"
|
:class="{
|
||||||
:md="(chart.chartOptions?.width || 6) * 2"
|
[`dash-width-${chart.chartOptions?.width || 6}`]: true
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
<div class="d-flex justify-content-between">
|
<div class="d-flex justify-content-between">
|
||||||
@@ -64,9 +65,9 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</div>
|
||||||
</el-row>
|
</section>
|
||||||
</section>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -133,14 +134,28 @@
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@import "@kestra-io/ui-libs/src/scss/variables";
|
@import "@kestra-io/ui-libs/src/scss/variables";
|
||||||
|
|
||||||
|
.dashboard-sections-container{
|
||||||
|
container-type: inline-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
$smallMobile: 375px;
|
||||||
|
$tablet: 768px;
|
||||||
|
|
||||||
section#charts {
|
section#charts {
|
||||||
|
display: grid;
|
||||||
|
gap: 1rem;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
@container (min-width: #{$smallMobile}) {
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
}
|
||||||
|
@container (min-width: #{$tablet}) {
|
||||||
|
grid-template-columns: repeat(12, 1fr);
|
||||||
|
}
|
||||||
&.padding {
|
&.padding {
|
||||||
padding: 0 2rem 1rem;
|
padding: 0 2rem 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .el-row .el-col {
|
.dashboard-block {
|
||||||
margin-bottom: 1rem;
|
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
@@ -159,5 +174,24 @@ section#charts {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dash-width-3, .dash-width-6, .dash-width-9, .dash-width-12 {
|
||||||
|
grid-column: span 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: #{$smallMobile}) {
|
||||||
|
.dash-width-6, .dash-width-9, .dash-width-12 {
|
||||||
|
grid-column: span 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: #{$tablet}) {
|
||||||
|
.dash-width-9 {
|
||||||
|
grid-column: span 9;
|
||||||
|
}
|
||||||
|
.dash-width-12 {
|
||||||
|
grid-column: span 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
import Duration from "./table/columns/Duration.vue";
|
import Duration from "./table/columns/Duration.vue";
|
||||||
import Link from "./table/columns/Link.vue";
|
import Link from "./table/columns/Link.vue";
|
||||||
import Namespace from "./table/columns/Namespace.vue";
|
import Namespace from "./table/columns/Namespace.vue";
|
||||||
import Status from "../../Status.vue";
|
import {Status} from "@kestra-io/ui-libs";
|
||||||
|
|
||||||
import Pagination from "../../layout/Pagination.vue";
|
import Pagination from "../../layout/Pagination.vue";
|
||||||
import NoData from "../../layout/NoData.vue";
|
import NoData from "../../layout/NoData.vue";
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
import type cytoscape from "cytoscape";
|
import type cytoscape from "cytoscape";
|
||||||
|
|
||||||
import Link from "./Link.vue";
|
import Link from "./Link.vue";
|
||||||
import Status from "../../Status.vue";
|
import {Status} from "@kestra-io/ui-libs";
|
||||||
|
|
||||||
import OpenInNew from "vue-material-design-icons/OpenInNew.vue";
|
import OpenInNew from "vue-material-design-icons/OpenInNew.vue";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<ContextInfoContent :title="routeInfo.title">
|
<ContextInfoContent :title="routeInfo.title" ref="contextInfoRef">
|
||||||
<template v-if="isOnline" #back-button>
|
<template v-if="isOnline" #back-button>
|
||||||
<button
|
<button
|
||||||
class="back-button"
|
class="back-button"
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<OpenInNew class="blank" />
|
<OpenInNew class="blank" />
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<div ref="docWrapper" class="docs-controls">
|
<div class="docs-controls">
|
||||||
<template v-if="isOnline">
|
<template v-if="isOnline">
|
||||||
<ContextDocsSearch />
|
<ContextDocsSearch />
|
||||||
<DocsMenu />
|
<DocsMenu />
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref, watch, computed, getCurrentInstance, onUnmounted, onMounted, nextTick} from "vue";
|
import {ref, watch, computed, getCurrentInstance, onUnmounted, onMounted} from "vue";
|
||||||
import {useDocStore} from "../../stores/doc";
|
import {useDocStore} from "../../stores/doc";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import OpenInNew from "vue-material-design-icons/OpenInNew.vue";
|
import OpenInNew from "vue-material-design-icons/OpenInNew.vue";
|
||||||
@@ -55,7 +55,9 @@
|
|||||||
import ContextInfoContent from "../ContextInfoContent.vue";
|
import ContextInfoContent from "../ContextInfoContent.vue";
|
||||||
import ContextChildTableOfContents from "./ContextChildTableOfContents.vue";
|
import ContextChildTableOfContents from "./ContextChildTableOfContents.vue";
|
||||||
|
|
||||||
|
|
||||||
import {useNetwork} from "@vueuse/core"
|
import {useNetwork} from "@vueuse/core"
|
||||||
|
import {useScrollMemory} from "../../composables/useScrollMemory"
|
||||||
const {isOnline} = useNetwork()
|
const {isOnline} = useNetwork()
|
||||||
|
|
||||||
import Markdown from "../../components/layout/Markdown.vue";
|
import Markdown from "../../components/layout/Markdown.vue";
|
||||||
@@ -64,19 +66,18 @@
|
|||||||
const docStore = useDocStore();
|
const docStore = useDocStore();
|
||||||
const {t} = useI18n({useScope: "global"});
|
const {t} = useI18n({useScope: "global"});
|
||||||
|
|
||||||
const docWrapper = ref<HTMLDivElement | null>(null);
|
const contextInfoRef = ref<InstanceType<typeof ContextInfoContent> | null>(null);
|
||||||
const docHistory = ref<string[]>([]);
|
const docHistory = ref<string[]>([]);
|
||||||
const currentHistoryIndex = ref(-1);
|
const currentHistoryIndex = ref(-1);
|
||||||
const ast = ref<any>(undefined);
|
const ast = ref<any>(undefined);
|
||||||
|
|
||||||
const pageMetadata = computed(() => docStore.pageMetadata);
|
const pageMetadata = computed(() => docStore.pageMetadata);
|
||||||
const docPath = computed(() => docStore.docPath);
|
const docPath = computed(() => docStore.docPath);
|
||||||
|
|
||||||
const routeInfo = computed(() => ({
|
const routeInfo = computed(() => ({
|
||||||
title: pageMetadata.value?.title ?? t("docs"),
|
title: pageMetadata.value?.title ?? t("docs"),
|
||||||
}));
|
}));
|
||||||
const canGoBack = computed(() => docHistory.value.length > 1 && currentHistoryIndex.value > 0);
|
const canGoBack = computed(() => docHistory.value.length > 1 && currentHistoryIndex.value > 0);
|
||||||
|
|
||||||
|
|
||||||
const addToHistory = (path: string) => {
|
const addToHistory = (path: string) => {
|
||||||
// Always store the path, even empty ones
|
// Always store the path, even empty ones
|
||||||
const pathToAdd = path || "";
|
const pathToAdd = path || "";
|
||||||
@@ -179,8 +180,10 @@
|
|||||||
|
|
||||||
addToHistory(val);
|
addToHistory(val);
|
||||||
refreshPage(val);
|
refreshPage(val);
|
||||||
nextTick(() => docWrapper.value?.scrollTo(0, 0));
|
|
||||||
}, {immediate: true});
|
}, {immediate: true});
|
||||||
|
|
||||||
|
const scrollableElement = computed(() => contextInfoRef.value?.contentRef ?? null)
|
||||||
|
useScrollMemory(ref("context-panel-docs"), scrollableElement as any)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@@ -241,4 +244,4 @@
|
|||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
import TopNavBar from "../layout/TopNavBar.vue";
|
import TopNavBar from "../layout/TopNavBar.vue";
|
||||||
import {useDocStore} from "../../stores/doc";
|
import {useDocStore} from "../../stores/doc";
|
||||||
import DocsLayout from "./DocsLayout.vue";
|
import DocsLayout from "./DocsLayout.vue";
|
||||||
//@ts-expect-error no declaration
|
|
||||||
import Toc from "./Toc.vue";
|
import Toc from "./Toc.vue";
|
||||||
import {computed,ref,watch,getCurrentInstance} from "vue";
|
import {computed,ref,watch,getCurrentInstance} from "vue";
|
||||||
import {useRoute} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
|
|||||||
@@ -23,9 +23,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {ref} from "vue"
|
import {ref, computed} from "vue"
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {useScrollMemory} from "../../composables/useScrollMemory";
|
||||||
|
|
||||||
const collapsed = ref(false);
|
const collapsed = ref(false);
|
||||||
|
const route = useRoute();
|
||||||
|
const scrollKey = computed(() => `docs:${route.fullPath}`);
|
||||||
|
|
||||||
|
useScrollMemory(scrollKey, undefined, true);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -224,4 +230,4 @@
|
|||||||
padding-bottom: 1px !important;
|
padding-bottom: 1px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -72,9 +72,7 @@
|
|||||||
|
|
||||||
import StateMachine from "vue-material-design-icons/StateMachine.vue";
|
import StateMachine from "vue-material-design-icons/StateMachine.vue";
|
||||||
|
|
||||||
import Status from "../../components/Status.vue";
|
import {State, Status} from "@kestra-io/ui-libs";
|
||||||
|
|
||||||
import {State} from "@kestra-io/ui-libs";
|
|
||||||
import * as ExecutionUtils from "../../utils/executionUtils";
|
import * as ExecutionUtils from "../../utils/executionUtils";
|
||||||
import permission from "../../models/permission";
|
import permission from "../../models/permission";
|
||||||
import action from "../../models/action";
|
import action from "../../models/action";
|
||||||
|
|||||||
@@ -68,8 +68,7 @@
|
|||||||
import {useExecutionsStore} from "../../stores/executions";
|
import {useExecutionsStore} from "../../stores/executions";
|
||||||
import permission from "../../models/permission";
|
import permission from "../../models/permission";
|
||||||
import action from "../../models/action";
|
import action from "../../models/action";
|
||||||
import {State} from "@kestra-io/ui-libs"
|
import {State, Status} from "@kestra-io/ui-libs"
|
||||||
import Status from "../../components/Status.vue";
|
|
||||||
import * as ExecutionUtils from "../../utils/executionUtils";
|
import * as ExecutionUtils from "../../utils/executionUtils";
|
||||||
import {shallowRef} from "vue";
|
import {shallowRef} from "vue";
|
||||||
import {useAuthStore} from "override/stores/auth"
|
import {useAuthStore} from "override/stores/auth"
|
||||||
|
|||||||
@@ -406,7 +406,7 @@
|
|||||||
|
|
||||||
import Id from "../Id.vue";
|
import Id from "../Id.vue";
|
||||||
import Kicon from "../Kicon.vue";
|
import Kicon from "../Kicon.vue";
|
||||||
import Status from "../Status.vue";
|
import {State, Status} from "@kestra-io/ui-libs";
|
||||||
import Labels from "../layout/Labels.vue";
|
import Labels from "../layout/Labels.vue";
|
||||||
import DateAgo from "../layout/DateAgo.vue";
|
import DateAgo from "../layout/DateAgo.vue";
|
||||||
import DataTable from "../layout/DataTable.vue";
|
import DataTable from "../layout/DataTable.vue";
|
||||||
@@ -420,7 +420,6 @@
|
|||||||
//@ts-expect-error no declaration file
|
//@ts-expect-error no declaration file
|
||||||
import TriggerFlow from "../../components/flows/TriggerFlow.vue";
|
import TriggerFlow from "../../components/flows/TriggerFlow.vue";
|
||||||
|
|
||||||
import {State} from "@kestra-io/ui-libs";
|
|
||||||
import {filterValidLabels} from "./utils";
|
import {filterValidLabels} from "./utils";
|
||||||
import {useToast} from "../../utils/toast";
|
import {useToast} from "../../utils/toast";
|
||||||
import {storageKeys} from "../../utils/constants";
|
import {storageKeys} from "../../utils/constants";
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
v-if="!isExecutionStarted"
|
v-if="!isExecutionStarted"
|
||||||
:execution="execution"
|
:execution="execution"
|
||||||
/>
|
/>
|
||||||
<el-card id="gantt" shadow="never" v-else-if="execution && executionsStore.flow">
|
<el-card id="gantt" shadow="never" :class="{'no-border': !hasValidDate}" v-else-if="execution && executionsStore.flow">
|
||||||
<template #header>
|
<template #header v-if="hasValidDate">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<Duration class="th text-end" :histories="execution.state.histories" />
|
<Duration class="th text-end" :histories="execution.state.histories" />
|
||||||
<span class="text-end" v-for="(date, i) in dates" :key="i">
|
<span class="text-end" v-for="(date, i) in dates" :key="i">
|
||||||
@@ -59,13 +59,13 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div
|
||||||
:style="{left: `${item.start}%`, width: `${Math.max(item.width, 3)}%`}"
|
:style="item.parentEndPercent !== undefined ? {left: `${item.start}%`, width: `${item.parentEndPercent - item.start}%`} : {left: `${item.start}%`, width: `${Math.max(item.width, 3)}%`}"
|
||||||
class="task-progress"
|
class="task-progress"
|
||||||
>
|
>
|
||||||
<div class="progress">
|
<div class="progress">
|
||||||
<div
|
<div
|
||||||
class="progress-bar"
|
|
||||||
:style="{left: `${Math.min(item.left, 90)}%`, width: `${Math.max(100 - item.left, 10)}%`}"
|
:style="{left: `${Math.min(item.left, 90)}%`, width: `${Math.max(100 - item.left, 10)}%`}"
|
||||||
|
class="progress-bar"
|
||||||
:class="'bg-' + item.color + (item.running ? ' progress-bar-striped progress-bar-animated' : '')"
|
:class="'bg-' + item.color + (item.running ? ' progress-bar-striped progress-bar-animated' : '')"
|
||||||
role="progressbar"
|
role="progressbar"
|
||||||
/>
|
/>
|
||||||
@@ -195,7 +195,7 @@
|
|||||||
const sortedTasks = []
|
const sortedTasks = []
|
||||||
const tasksById = {}
|
const tasksById = {}
|
||||||
for (let task of (this.execution.taskRunList || [])) {
|
for (let task of (this.execution.taskRunList || [])) {
|
||||||
const taskWrapper = {task}
|
const taskWrapper = {task, depth: task.parentTaskRunId ? undefined : 0}
|
||||||
if (task.parentTaskRunId) {
|
if (task.parentTaskRunId) {
|
||||||
childTasks.push(taskWrapper)
|
childTasks.push(taskWrapper)
|
||||||
} else {
|
} else {
|
||||||
@@ -208,6 +208,7 @@
|
|||||||
const taskWrapper = childTasks[i];
|
const taskWrapper = childTasks[i];
|
||||||
const parentTask = tasksById[taskWrapper.task.parentTaskRunId]
|
const parentTask = tasksById[taskWrapper.task.parentTaskRunId]
|
||||||
if (parentTask) {
|
if (parentTask) {
|
||||||
|
taskWrapper.depth = parentTask.depth + 1
|
||||||
tasksById[taskWrapper.task.id] = taskWrapper
|
tasksById[taskWrapper.task.id] = taskWrapper
|
||||||
if (!parentTask.children) {
|
if (!parentTask.children) {
|
||||||
parentTask.children = []
|
parentTask.children = []
|
||||||
@@ -222,7 +223,7 @@
|
|||||||
return nodeStart(n1) > nodeStart(n2) ? 1 : -1
|
return nodeStart(n1) > nodeStart(n2) ? 1 : -1
|
||||||
})
|
})
|
||||||
for (let node of nodes) {
|
for (let node of nodes) {
|
||||||
sortedTasks.push(node.task)
|
sortedTasks.push(node)
|
||||||
if (node.children) {
|
if (node.children) {
|
||||||
childrenSort(node.children)
|
childrenSort(node.children)
|
||||||
}
|
}
|
||||||
@@ -234,6 +235,9 @@
|
|||||||
isExecutionStarted() {
|
isExecutionStarted() {
|
||||||
return this.execution?.state?.current && !["CREATED", "QUEUED"].includes(this.execution.state.current);
|
return this.execution?.state?.current && !["CREATED", "QUEUED"].includes(this.execution.state.current);
|
||||||
},
|
},
|
||||||
|
hasValidDate() {
|
||||||
|
return isFinite(this.delta());
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
forwardEvent(type, event) {
|
forwardEvent(type, event) {
|
||||||
@@ -262,8 +266,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const series = [];
|
const series = [];
|
||||||
const executionDelta = this.delta(); //caching this value matters
|
const executionDelta = this.delta();
|
||||||
for (let task of this.tasks) {
|
const taskMap = {};
|
||||||
|
|
||||||
|
for (let taskWrapper of this.tasks) {
|
||||||
|
let task = taskWrapper.task
|
||||||
let stopTs;
|
let stopTs;
|
||||||
if (State.isRunning(task.state.current)) {
|
if (State.isRunning(task.state.current)) {
|
||||||
stopTs = ts(new Date());
|
stopTs = ts(new Date());
|
||||||
@@ -292,13 +299,21 @@
|
|||||||
|
|
||||||
let width = (stop / executionDelta) * 100
|
let width = (stop / executionDelta) * 100
|
||||||
if (State.isRunning(task.state.current)) {
|
if (State.isRunning(task.state.current)) {
|
||||||
width = ((this.stop() - startTs) / executionDelta) * 100 //(stop / executionDelta) * 100
|
width = ((this.stop() - startTs) / executionDelta) * 100
|
||||||
}
|
}
|
||||||
|
|
||||||
series.push({
|
let startPercent = (start / executionDelta) * 100;
|
||||||
|
let parentEndPercent = undefined;
|
||||||
|
|
||||||
|
if (task.parentTaskRunId && taskMap[task.parentTaskRunId]) {
|
||||||
|
const parent = taskMap[task.parentTaskRunId];
|
||||||
|
parentEndPercent = parent.start + parent.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
const seriesItem = {
|
||||||
id: task.id,
|
id: task.id,
|
||||||
name: task.taskId,
|
name: task.taskId,
|
||||||
start: (start / executionDelta) * 100,
|
start: startPercent,
|
||||||
width,
|
width,
|
||||||
left: left,
|
left: left,
|
||||||
tooltip,
|
tooltip,
|
||||||
@@ -308,8 +323,13 @@
|
|||||||
flowId: task.flowId,
|
flowId: task.flowId,
|
||||||
namespace: task.namespace,
|
namespace: task.namespace,
|
||||||
executionId: task.outputs && task.outputs.executionId,
|
executionId: task.outputs && task.outputs.executionId,
|
||||||
attempts: task.attempts ? task.attempts.length : 1
|
attempts: task.attempts ? task.attempts.length : 1,
|
||||||
});
|
depth: taskWrapper.depth,
|
||||||
|
parentEndPercent: parentEndPercent
|
||||||
|
};
|
||||||
|
|
||||||
|
taskMap[task.id] = seriesItem;
|
||||||
|
series.push(seriesItem);
|
||||||
}
|
}
|
||||||
this.series = series;
|
this.series = series;
|
||||||
},
|
},
|
||||||
@@ -443,6 +463,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.no-border {
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
// To Separate through Line
|
// To Separate through Line
|
||||||
:deep(.vue-recycle-scroller__item-view) {
|
:deep(.vue-recycle-scroller__item-view) {
|
||||||
|
|||||||
@@ -204,7 +204,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Status from "../Status.vue";
|
import {Status} from "@kestra-io/ui-libs";
|
||||||
import SetLabels from "./SetLabels.vue";
|
import SetLabels from "./SetLabels.vue";
|
||||||
import Restart from "./Restart.vue";
|
import Restart from "./Restart.vue";
|
||||||
import Resume from "./Resume.vue";
|
import Resume from "./Resume.vue";
|
||||||
|
|||||||
@@ -111,7 +111,7 @@
|
|||||||
:readOnly="true"
|
:readOnly="true"
|
||||||
component="el-dropdown-item"
|
component="el-dropdown-item"
|
||||||
:taskId="currentTaskRun.taskId"
|
:taskId="currentTaskRun.taskId"
|
||||||
:section="SECTIONS.TASKS"
|
section="tasks"
|
||||||
:flowId="followedExecution.flowId"
|
:flowId="followedExecution.flowId"
|
||||||
:namespace="followedExecution.namespace"
|
:namespace="followedExecution.namespace"
|
||||||
:revision="followedExecution.flowRevision"
|
:revision="followedExecution.flowRevision"
|
||||||
@@ -175,7 +175,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import Restart from "./Restart.vue";
|
import Restart from "./Restart.vue";
|
||||||
import Metrics from "./Metrics.vue";
|
import Metrics from "./Metrics.vue";
|
||||||
import Status from "../Status.vue";
|
import {State, Status} from "@kestra-io/ui-libs";
|
||||||
import ChangeStatus from "./ChangeStatus.vue";
|
import ChangeStatus from "./ChangeStatus.vue";
|
||||||
import TaskEdit from "../flows/TaskEdit.vue";
|
import TaskEdit from "../flows/TaskEdit.vue";
|
||||||
import SubFlowLink from "../flows/SubFlowLink.vue";
|
import SubFlowLink from "../flows/SubFlowLink.vue";
|
||||||
@@ -189,7 +189,6 @@
|
|||||||
import Download from "vue-material-design-icons/Download.vue";
|
import Download from "vue-material-design-icons/Download.vue";
|
||||||
import WorkerInfo from "./WorkerInfo.vue";
|
import WorkerInfo from "./WorkerInfo.vue";
|
||||||
import AiIcon from "../ai/AiIcon.vue";
|
import AiIcon from "../ai/AiIcon.vue";
|
||||||
import {State} from "@kestra-io/ui-libs"
|
|
||||||
import FlowUtils from "../../utils/flowUtils";
|
import FlowUtils from "../../utils/flowUtils";
|
||||||
import _groupBy from "lodash/groupBy";
|
import _groupBy from "lodash/groupBy";
|
||||||
import {TaskIcon, SECTIONS} from "@kestra-io/ui-libs";
|
import {TaskIcon, SECTIONS} from "@kestra-io/ui-libs";
|
||||||
|
|||||||
@@ -49,8 +49,7 @@
|
|||||||
import {useExecutionsStore} from "../../stores/executions";
|
import {useExecutionsStore} from "../../stores/executions";
|
||||||
import permission from "../../models/permission";
|
import permission from "../../models/permission";
|
||||||
import action from "../../models/action";
|
import action from "../../models/action";
|
||||||
import {State} from "@kestra-io/ui-libs"
|
import {State, Status} from "@kestra-io/ui-libs"
|
||||||
import Status from "../../components/Status.vue";
|
|
||||||
import {useAuthStore} from "override/stores/auth"
|
import {useAuthStore} from "override/stores/auth"
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import {useToast} from "../../utils/toast";
|
import {useToast} from "../../utils/toast";
|
||||||
|
|||||||
@@ -32,6 +32,18 @@
|
|||||||
<span v-else-if="value === null">
|
<span v-else-if="value === null">
|
||||||
<em>null</em>
|
<em>null</em>
|
||||||
</span>
|
</span>
|
||||||
|
<div v-else-if="isComplexValue(value)">
|
||||||
|
<Editor
|
||||||
|
:readOnly="true"
|
||||||
|
:input="true"
|
||||||
|
:fullHeight="false"
|
||||||
|
:customHeight="Math.min(20, Math.max(5, JSON.stringify(getDisplayValue(value), null, 2).split('\n').length))"
|
||||||
|
:navbar="false"
|
||||||
|
:modelValue="JSON.stringify(getDisplayValue(value), null, 2)"
|
||||||
|
lang="json"
|
||||||
|
class="complex-value-editor"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
{{ value }}
|
{{ value }}
|
||||||
</span>
|
</span>
|
||||||
@@ -42,6 +54,7 @@
|
|||||||
import Download from "vue-material-design-icons/Download.vue";
|
import Download from "vue-material-design-icons/Download.vue";
|
||||||
import OpenInNew from "vue-material-design-icons/OpenInNew.vue";
|
import OpenInNew from "vue-material-design-icons/OpenInNew.vue";
|
||||||
import FilePreview from "./FilePreview.vue";
|
import FilePreview from "./FilePreview.vue";
|
||||||
|
import Editor from "../inputs/Editor.vue";
|
||||||
import {apiUrl} from "override/utils/route";
|
import {apiUrl} from "override/utils/route";
|
||||||
import Utils from "../../utils/utils";
|
import Utils from "../../utils/utils";
|
||||||
|
|
||||||
@@ -88,6 +101,42 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isComplexValue = (value: unknown): boolean => {
|
||||||
|
if ((typeof value === "object" && value !== null) || Array.isArray(value)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === "string") {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(value);
|
||||||
|
return (typeof parsed === "object" && parsed !== null) || Array.isArray(parsed);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDisplayValue = (value: unknown): unknown => {
|
||||||
|
if ((typeof value === "object" && value !== null) || Array.isArray(value)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === "string") {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(value);
|
||||||
|
if ((typeof parsed === "object" && parsed !== null) || Array.isArray(parsed)) {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
const itemUrl = (value: string): string => {
|
const itemUrl = (value: string): string => {
|
||||||
return `${apiUrl()}/executions/${props.execution?.id}/file?path=${encodeURI(value)}`;
|
return `${apiUrl()}/executions/${props.execution?.id}/file?path=${encodeURI(value)}`;
|
||||||
};
|
};
|
||||||
@@ -118,3 +167,11 @@
|
|||||||
getFileSize();
|
getFileSize();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.complex-value-editor {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
border: 1px solid var(--ks-border-primary);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -183,4 +183,4 @@ export function useExecutionRoot() {
|
|||||||
getBaseTabs,
|
getBaseTabs,
|
||||||
setupLifecycle
|
setupLifecycle
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {ref, computed, watch, PropType} from "vue";
|
import {ref, computed, watch, PropType} from "vue";
|
||||||
import DateSelect from "./DateSelect.vue";
|
import DateSelect from "./DateSelect.vue";
|
||||||
|
import {useI18n} from "vue-i18n";
|
||||||
|
|
||||||
interface TimePreset {
|
interface TimePreset {
|
||||||
value?: string;
|
value?: string;
|
||||||
@@ -64,9 +65,11 @@
|
|||||||
timeFilterPresets.value.map(preset => preset.value)
|
timeFilterPresets.value.map(preset => preset.value)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const {t} = useI18n();
|
||||||
|
|
||||||
const customAwarePlaceholder = computed<string | undefined>(() => {
|
const customAwarePlaceholder = computed<string | undefined>(() => {
|
||||||
if (props.placeholder) return props.placeholder;
|
if (props.placeholder) return props.placeholder;
|
||||||
return props.allowCustom ? "datepicker.custom" : undefined;
|
return props.allowCustom ? t("datepicker.custom") : undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
const onTimeRangeSelect = (range: string | undefined) => {
|
const onTimeRangeSelect = (range: string | undefined) => {
|
||||||
@@ -92,4 +95,4 @@
|
|||||||
},
|
},
|
||||||
{immediate: true}
|
{immediate: true}
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -225,14 +225,15 @@
|
|||||||
const debugOutput = JSON.stringify(parsedResult, null, 2);
|
const debugOutput = JSON.stringify(parsedResult, null, 2);
|
||||||
debugExpression.value = debugOutput;
|
debugExpression.value = debugOutput;
|
||||||
|
|
||||||
selected.value.push(debugOutput);
|
if (response.status === 200 && debugOutput !== null && debugOutput !== undefined) {
|
||||||
|
selected.value.push(debugOutput);
|
||||||
|
}
|
||||||
isJSON.value = true;
|
isJSON.value = true;
|
||||||
} catch {
|
} catch {
|
||||||
debugExpression.value = response.data.result;
|
debugExpression.value = response.data.result;
|
||||||
|
|
||||||
// Parsing failed, therefore, copy raw result
|
// Parsing failed, therefore, copy raw result
|
||||||
if (response.status === 200 && response.data.result)
|
if (response.status === 200 && response.data.result !== null && response.data.result !== undefined)
|
||||||
selected.value.push(response.data.result);
|
selected.value.push(response.data.result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, ref} from "vue";
|
import {computed, ref} from "vue";
|
||||||
import {Magnify, InformationOutline} from "../../utils/icons";
|
import {Magnify, InformationOutline} from "../../utils/icons";
|
||||||
import Status from "../../../Status.vue";
|
import {Status} from "@kestra-io/ui-libs";
|
||||||
import Checkbox from "../../../layout/Checkbox.vue";
|
import Checkbox from "../../../layout/Checkbox.vue";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
@@ -243,7 +243,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
button.el-button {
|
button.status-button {
|
||||||
width: 10rem;
|
width: 10rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@@ -43,7 +43,7 @@ export function useValues(label: string | undefined, t?: ReturnType<typeof useI1
|
|||||||
{label: t("datepicker.last24hours"), value: "PT24H"},
|
{label: t("datepicker.last24hours"), value: "PT24H"},
|
||||||
{label: t("datepicker.last48hours"), value: "PT48H"},
|
{label: t("datepicker.last48hours"), value: "PT48H"},
|
||||||
{label: t("datepicker.last7days"), value: "PT168H"},
|
{label: t("datepicker.last7days"), value: "PT168H"},
|
||||||
{label: t("datepicker.last30days"), value: "PT720H"},
|
{label: t("datepicker.last30days"), value: "P30D"},
|
||||||
{label: t("datepicker.last365days"), value: "PT8760H"},
|
{label: t("datepicker.last365days"), value: "PT8760H"},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export const decodeSearchParams = (query: LocationQuery) =>
|
|||||||
operation
|
operation
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter(Boolean);
|
.filter(v => v !== null);
|
||||||
|
|
||||||
type Filter = Pick<AppliedFilter, "key" | "comparator" | "value">;
|
type Filter = Pick<AppliedFilter, "key" | "comparator" | "value">;
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,7 @@
|
|||||||
import {ref, computed} from "vue";
|
import {ref, computed} from "vue";
|
||||||
import Executions from "../executions/Executions.vue";
|
import Executions from "../executions/Executions.vue";
|
||||||
import Empty from "../layout/empty/Empty.vue";
|
import Empty from "../layout/empty/Empty.vue";
|
||||||
import {State} from "@kestra-io/ui-libs";
|
import {State, Status} from "@kestra-io/ui-libs";
|
||||||
import Status from "../Status.vue";
|
|
||||||
import {useFlowStore} from "../../stores/flow";
|
import {useFlowStore} from "../../stores/flow";
|
||||||
|
|
||||||
defineOptions({inheritAttrs: false});
|
defineOptions({inheritAttrs: false});
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
import FlowRootTopBar from "./FlowRootTopBar.vue";
|
import FlowRootTopBar from "./FlowRootTopBar.vue";
|
||||||
import FlowConcurrency from "./FlowConcurrency.vue";
|
import FlowConcurrency from "./FlowConcurrency.vue";
|
||||||
import DemoAuditLogs from "../demo/AuditLogs.vue";
|
import DemoAuditLogs from "../demo/AuditLogs.vue";
|
||||||
import {useAuthStore} from "override/stores/auth"
|
import {useAuthStore} from "override/stores/auth";
|
||||||
import {useMiscStore} from "override/stores/misc";
|
import {useMiscStore} from "override/stores/misc";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -59,13 +59,12 @@
|
|||||||
"$route.params.tab": {
|
"$route.params.tab": {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler: function (newTab) {
|
handler: function (newTab) {
|
||||||
if (newTab === "overview") {
|
if (newTab === "overview" || newTab === "executions") {
|
||||||
const dateTimeKeys = ["startDate", "endDate", "timeRange"];
|
const dateTimeKeys = ["startDate", "endDate", "timeRange"];
|
||||||
|
|
||||||
if (!Object.keys(this.$route.query).some((key) => dateTimeKeys.some((dateTimeKey) => key.includes(dateTimeKey)))) {
|
if (!Object.keys(this.$route.query).some((key) => dateTimeKeys.some((dateTimeKey) => key.includes(dateTimeKey)))) {
|
||||||
const miscStore = useMiscStore();
|
const DEFAULT_DURATION = this.miscStore.configs?.chartDefaultDuration ?? "P30D";
|
||||||
const defaultDuration = miscStore.configs?.chartDefaultDuration || "P30D";
|
const newQuery = {...this.$route.query, "filters[timeRange][EQUALS]": DEFAULT_DURATION};
|
||||||
const newQuery = {...this.$route.query, "filters[timeRange][EQUALS]": defaultDuration};
|
|
||||||
this.$router.replace({name: this.$route.name, params: this.$route.params, query: newQuery});
|
this.$router.replace({name: this.$route.name, params: this.$route.params, query: newQuery});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -314,7 +313,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useCoreStore, useFlowStore, useAuthStore),
|
...mapStores(useCoreStore, useFlowStore, useAuthStore, useMiscStore),
|
||||||
routeInfo() {
|
routeInfo() {
|
||||||
return {
|
return {
|
||||||
title: this.$route.params.id,
|
title: this.$route.params.id,
|
||||||
|
|||||||
@@ -204,6 +204,7 @@
|
|||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<TimeSeries
|
<TimeSeries
|
||||||
:chart="mappedChart(scope.row.id, scope.row.namespace)"
|
:chart="mappedChart(scope.row.id, scope.row.namespace)"
|
||||||
|
:filters="chartFilters()"
|
||||||
showDefault
|
showDefault
|
||||||
short
|
short
|
||||||
/>
|
/>
|
||||||
@@ -266,7 +267,7 @@
|
|||||||
import FileDocumentRemoveOutline from "vue-material-design-icons/FileDocumentRemoveOutline.vue";
|
import FileDocumentRemoveOutline from "vue-material-design-icons/FileDocumentRemoveOutline.vue";
|
||||||
|
|
||||||
import Kicon from "../Kicon.vue";
|
import Kicon from "../Kicon.vue";
|
||||||
import Status from "../Status.vue";
|
import {Status} from "@kestra-io/ui-libs";
|
||||||
import Labels from "../layout/Labels.vue";
|
import Labels from "../layout/Labels.vue";
|
||||||
import DateAgo from "../layout/DateAgo.vue";
|
import DateAgo from "../layout/DateAgo.vue";
|
||||||
import TriggerAvatar from "./TriggerAvatar.vue";
|
import TriggerAvatar from "./TriggerAvatar.vue";
|
||||||
@@ -287,6 +288,7 @@
|
|||||||
|
|
||||||
import {useFlowStore} from "../../stores/flow";
|
import {useFlowStore} from "../../stores/flow";
|
||||||
import {useAuthStore} from "override/stores/auth";
|
import {useAuthStore} from "override/stores/auth";
|
||||||
|
import {useMiscStore} from "override/stores/misc";
|
||||||
import {useExecutionsStore} from "../../stores/executions";
|
import {useExecutionsStore} from "../../stores/executions";
|
||||||
|
|
||||||
import {useTableColumns} from "../../composables/useTableColumns";
|
import {useTableColumns} from "../../composables/useTableColumns";
|
||||||
@@ -307,6 +309,7 @@
|
|||||||
const flowStore = useFlowStore();
|
const flowStore = useFlowStore();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const executionsStore = useExecutionsStore();
|
const executionsStore = useExecutionsStore();
|
||||||
|
const miscStore = useMiscStore();
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -622,6 +625,15 @@
|
|||||||
return MAPPED_CHARTS;
|
return MAPPED_CHARTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function chartFilters() {
|
||||||
|
const DEFAULT_DURATION = miscStore.configs?.chartDefaultDuration ?? "P30D";
|
||||||
|
return [{
|
||||||
|
field: "timeRange",
|
||||||
|
value: DEFAULT_DURATION,
|
||||||
|
operation: "EQUALS"
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const query = {...route.query};
|
const query = {...route.query};
|
||||||
const queryKeys = Object.keys(query);
|
const queryKeys = Object.keys(query);
|
||||||
|
|||||||
@@ -169,9 +169,14 @@
|
|||||||
? revisions.value?.[props.revision - 1]?.source
|
? revisions.value?.[props.revision - 1]?.source
|
||||||
: flowStore.flow?.source;
|
: flowStore.flow?.source;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
const load = async (taskId: string) => {
|
const load = async (taskId: string) => {
|
||||||
|
await flowStore.loadFlow({
|
||||||
|
namespace: props.namespace,
|
||||||
|
id: props.flowId,
|
||||||
|
revision: props.revision?.toString(),
|
||||||
|
});
|
||||||
if (props.revision) {
|
if (props.revision) {
|
||||||
if (!revisions.value?.[props.revision - 1]) {
|
if (!revisions.value?.[props.revision - 1]) {
|
||||||
revisions.value = await flowStore.loadRevisions({
|
revisions.value = await flowStore.loadRevisions({
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
import Markdown from "../layout/Markdown.vue";
|
import Markdown from "../layout/Markdown.vue";
|
||||||
import Cron from "../layout/Cron.vue";
|
import Cron from "../layout/Cron.vue";
|
||||||
|
|
||||||
const {t} = useI18n();
|
const {t, te} = useI18n();
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
data: Record<string, any>;
|
data: Record<string, any>;
|
||||||
@@ -51,9 +51,10 @@
|
|||||||
"date": "last trigger date",
|
"date": "last trigger date",
|
||||||
"updatedDate": "context updated date",
|
"updatedDate": "context updated date",
|
||||||
"evaluateRunningDate": "evaluation lock date",
|
"evaluateRunningDate": "evaluation lock date",
|
||||||
|
"states": "trigger_states",
|
||||||
};
|
};
|
||||||
const translationKey = mappings[key] ?? key;
|
const translationKey = mappings[key] ?? key;
|
||||||
return t(translationKey);
|
return te(translationKey) && t(translationKey) || translationKey;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Status from "../../Status.vue";
|
import {Status} from "@kestra-io/ui-libs";
|
||||||
import {date, humanizeDuration} from "../../../utils/filters";
|
import {date, humanizeDuration} from "../../../utils/filters";
|
||||||
import {Execution, useExecutionsStore} from "../../../stores/executions";
|
import {Execution, useExecutionsStore} from "../../../stores/executions";
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,7 @@
|
|||||||
/* eslint-disable vue/enforce-style-attribute */
|
/* eslint-disable vue/enforce-style-attribute */
|
||||||
import {computed, onMounted, ref, shallowRef, watch} from "vue";
|
import {computed, onMounted, ref, shallowRef, watch} from "vue";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
|
import {useThrottleFn} from "@vueuse/core";
|
||||||
import UnfoldLessHorizontal from "vue-material-design-icons/UnfoldLessHorizontal.vue";
|
import UnfoldLessHorizontal from "vue-material-design-icons/UnfoldLessHorizontal.vue";
|
||||||
import UnfoldMoreHorizontal from "vue-material-design-icons/UnfoldMoreHorizontal.vue";
|
import UnfoldMoreHorizontal from "vue-material-design-icons/UnfoldMoreHorizontal.vue";
|
||||||
import Help from "vue-material-design-icons/Help.vue";
|
import Help from "vue-material-design-icons/Help.vue";
|
||||||
@@ -94,6 +95,7 @@
|
|||||||
import {TabFocus} from "monaco-editor/esm/vs/editor/browser/config/tabFocus";
|
import {TabFocus} from "monaco-editor/esm/vs/editor/browser/config/tabFocus";
|
||||||
import MonacoEditor from "./MonacoEditor.vue";
|
import MonacoEditor from "./MonacoEditor.vue";
|
||||||
import type * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
import type * as monaco from "monaco-editor/esm/vs/editor/editor.api";
|
||||||
|
import {useScrollMemory} from "../../composables/useScrollMemory";
|
||||||
|
|
||||||
const {t} = useI18n()
|
const {t} = useI18n()
|
||||||
|
|
||||||
@@ -123,6 +125,7 @@
|
|||||||
shouldFocus: {type: Boolean, default: true},
|
shouldFocus: {type: Boolean, default: true},
|
||||||
showScroll: {type: Boolean, default: false},
|
showScroll: {type: Boolean, default: false},
|
||||||
diffOverviewBar: {type: Boolean, default: true},
|
diffOverviewBar: {type: Boolean, default: true},
|
||||||
|
scrollKey: {type: String, default: undefined},
|
||||||
})
|
})
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@@ -289,6 +292,8 @@
|
|||||||
return editor?.getEditorType() === monacoEditor.value?.monaco.editor.EditorType.ICodeEditor
|
return editor?.getEditorType() === monacoEditor.value?.monaco.editor.EditorType.ICodeEditor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollMemory = props.scrollKey ? useScrollMemory(ref(props.scrollKey)) : null;
|
||||||
|
|
||||||
function editorDidMount(monacoMounted?: monaco.editor.IStandaloneCodeEditor | monaco.editor.IStandaloneDiffEditor) {
|
function editorDidMount(monacoMounted?: monaco.editor.IStandaloneCodeEditor | monaco.editor.IStandaloneDiffEditor) {
|
||||||
|
|
||||||
const monacoRef = monacoEditor.value
|
const monacoRef = monacoEditor.value
|
||||||
@@ -300,8 +305,6 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// avoid double import of monaco editor, use a reference
|
// avoid double import of monaco editor, use a reference
|
||||||
const KeyCode = monacoRef.monaco.KeyCode;
|
const KeyCode = monacoRef.monaco.KeyCode;
|
||||||
const KeyMod = monacoRef.monaco.KeyMod;
|
const KeyMod = monacoRef.monaco.KeyMod;
|
||||||
@@ -312,6 +315,29 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const codeEditor = editor as monaco.editor.IStandaloneCodeEditor;
|
||||||
|
|
||||||
|
|
||||||
|
if (props.scrollKey && scrollMemory) {
|
||||||
|
const savedState = scrollMemory.loadData<monaco.editor.ICodeEditorViewState>("viewState");
|
||||||
|
if (savedState) {
|
||||||
|
codeEditor.restoreViewState(savedState);
|
||||||
|
codeEditor.revealLineInCenterIfOutsideViewport?.(codeEditor.getPosition()?.lineNumber ?? 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const top = scrollMemory.loadData<number>("scrollTop", 0);
|
||||||
|
if (typeof top === "number") {
|
||||||
|
codeEditor.setScrollTop(top);
|
||||||
|
}
|
||||||
|
|
||||||
|
const throttledSave = useThrottleFn(() => {
|
||||||
|
scrollMemory.saveData(codeEditor.saveViewState(), "viewState");
|
||||||
|
scrollMemory.saveData(codeEditor.getScrollTop(), "scrollTop");
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
codeEditor.onDidScrollChange?.(throttledSave);
|
||||||
|
}
|
||||||
|
|
||||||
if (!isDiff.value) {
|
if (!isDiff.value) {
|
||||||
editor.onDidBlurEditorWidget?.(() => {
|
editor.onDidBlurEditorWidget?.(() => {
|
||||||
emit("focusout", isCodeEditor(editor)
|
emit("focusout", isCodeEditor(editor)
|
||||||
@@ -468,6 +494,10 @@
|
|||||||
position: position,
|
position: position,
|
||||||
model: model,
|
model: model,
|
||||||
});
|
});
|
||||||
|
// Save view state when cursor changes
|
||||||
|
if (scrollMemory) {
|
||||||
|
scrollMemory.saveData(codeEditor.saveViewState(), "viewState");
|
||||||
|
}
|
||||||
}, 100) as unknown as number;
|
}, 100) as unknown as number;
|
||||||
highlightPebble();
|
highlightPebble();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
:creating="isCreating"
|
:creating="isCreating"
|
||||||
:path="path"
|
:path="path"
|
||||||
:diffOverviewBar="false"
|
:diffOverviewBar="false"
|
||||||
|
:scrollKey="editorScrollKey"
|
||||||
@update:model-value="editorUpdate"
|
@update:model-value="editorUpdate"
|
||||||
@cursor="updatePluginDocumentation"
|
@cursor="updatePluginDocumentation"
|
||||||
@save="flow ? saveFlowYaml(): saveFileContent()"
|
@save="flow ? saveFlowYaml(): saveFileContent()"
|
||||||
@@ -224,6 +225,19 @@
|
|||||||
const namespacesStore = useNamespacesStore();
|
const namespacesStore = useNamespacesStore();
|
||||||
const miscStore = useMiscStore();
|
const miscStore = useMiscStore();
|
||||||
|
|
||||||
|
const editorScrollKey = computed(() => {
|
||||||
|
if (props.flow) {
|
||||||
|
const ns = flowStore.flow?.namespace ?? "";
|
||||||
|
const id = flowStore.flow?.id ?? "";
|
||||||
|
return `flow:${ns}/${id}:code`;
|
||||||
|
}
|
||||||
|
const ns = namespace.value;
|
||||||
|
if (ns && props.path) {
|
||||||
|
return `file:${ns}:${props.path}`;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|
||||||
function loadPluginsHash() {
|
function loadPluginsHash() {
|
||||||
miscStore.loadConfigs().then(config => {
|
miscStore.loadConfigs().then(config => {
|
||||||
hash.value = config.pluginsHash;
|
hash.value = config.pluginsHash;
|
||||||
@@ -261,6 +275,10 @@
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearTimeout(timeout.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
function updatePluginDocumentation(event: any) {
|
function updatePluginDocumentation(event: any) {
|
||||||
const source = event.model.getValue();
|
const source = event.model.getValue();
|
||||||
|
|||||||
@@ -688,21 +688,22 @@
|
|||||||
|
|
||||||
async function removeItems() {
|
async function removeItems() {
|
||||||
if(confirmation.value.nodes === undefined) return;
|
if(confirmation.value.nodes === undefined) return;
|
||||||
for (const node of confirmation.value.nodes) {
|
await Promise.all(confirmation.value.nodes.map(async (node, i) => {
|
||||||
|
const path = filesStore.getPath(node.id) ?? "";
|
||||||
try {
|
try {
|
||||||
await namespacesStore.deleteFileDirectory({
|
await namespacesStore.deleteFileDirectory({
|
||||||
namespace: props.currentNS ?? route.params.namespace as string,
|
namespace: props.currentNS ?? route.params.namespace as string,
|
||||||
path: filesStore.getPath(node) ?? "",
|
path,
|
||||||
});
|
});
|
||||||
tree.value.remove(node.id);
|
tree.value.remove(node.id);
|
||||||
closeTab?.({
|
closeTab?.({
|
||||||
path: filesStore.getPath(node) ?? "",
|
path,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to delete file: ${node.fileName}`, error);
|
console.error(`Failed to delete file: ${node.fileName}`, error);
|
||||||
toast.error(`Failed to delete file: ${node.fileName}`);
|
toast.error(`Failed to delete file: ${node.fileName}`);
|
||||||
}
|
}
|
||||||
}
|
}));
|
||||||
confirmation.value = {visible: false, nodes: []};
|
confirmation.value = {visible: false, nodes: []};
|
||||||
toast.success("Selected files deleted successfully.");
|
toast.success("Selected files deleted successfully.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -235,7 +235,7 @@
|
|||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import {useRoute} from "vue-router";
|
import {useRoute} from "vue-router";
|
||||||
import _groupBy from "lodash/groupBy";
|
import _groupBy from "lodash/groupBy";
|
||||||
import {computed, ref, useTemplateRef, watch} from "vue";
|
import {computed, nextTick, ref, useTemplateRef, watch} from "vue";
|
||||||
|
|
||||||
import Check from "vue-material-design-icons/Check.vue";
|
import Check from "vue-material-design-icons/Check.vue";
|
||||||
import Delete from "vue-material-design-icons/Delete.vue";
|
import Delete from "vue-material-design-icons/Delete.vue";
|
||||||
@@ -491,6 +491,8 @@
|
|||||||
kv.value.key = entry.key;
|
kv.value.key = entry.key;
|
||||||
const {type, value} = await namespacesStore.kv({namespace: entry.namespace, key: entry.key});
|
const {type, value} = await namespacesStore.kv({namespace: entry.namespace, key: entry.key});
|
||||||
kv.value.type = type;
|
kv.value.type = type;
|
||||||
|
// Force the type reset before setting the value
|
||||||
|
await nextTick();
|
||||||
if (type === "JSON") {
|
if (type === "JSON") {
|
||||||
kv.value.value = JSON.stringify(value);
|
kv.value.value = JSON.stringify(value);
|
||||||
} else if (type === "BOOLEAN") {
|
} else if (type === "BOOLEAN") {
|
||||||
@@ -504,7 +506,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeKv(namespace: string, key: string) {
|
function removeKv(namespace: string, key: string) {
|
||||||
toast.confirm("delete confirm", async () => {
|
toast.confirm(t("delete confirm"), async () => {
|
||||||
return namespacesStore
|
return namespacesStore
|
||||||
.deleteKv({namespace, key: key})
|
.deleteKv({namespace, key: key})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -543,14 +545,16 @@
|
|||||||
const type = kv.value.type;
|
const type = kv.value.type;
|
||||||
let value: any = kv.value.value;
|
let value: any = kv.value.value;
|
||||||
|
|
||||||
if (type === "STRING" || type === "DURATION") {
|
if (type === "STRING") {
|
||||||
|
value = JSON.stringify(value);
|
||||||
|
} else if (["DURATION", "JSON"].includes(type)) {
|
||||||
value = value || "";
|
value = value || "";
|
||||||
} else if (type === "DATETIME") {
|
} else if (type === "DATETIME") {
|
||||||
value = new Date(value!).toISOString();
|
value = new Date(value!).toISOString();
|
||||||
} else if (type === "DATE") {
|
} else if (type === "DATE") {
|
||||||
value = new Date(value!).toISOString().split("T")[0];
|
value = new Date(value!).toISOString().split("T")[0];
|
||||||
} else if (["NUMBER", "BOOLEAN", "JSON"].includes(type)) {
|
} else {
|
||||||
value = JSON.stringify(value);
|
value = String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentType = "text/plain";
|
const contentType = "text/plain";
|
||||||
@@ -605,10 +609,9 @@
|
|||||||
|
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
|
|
||||||
watch(() => kv.value.type, () => {
|
watch(() => kv.value.type, (newType) => {
|
||||||
if (formRef.value) {
|
formRef.value?.clearValidate("value");
|
||||||
(formRef.value as any).clearValidate("value");
|
if (newType === "BOOLEAN") kv.value.value = false;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<ContextInfoContent :title="t('feeds.title')">
|
<ContextInfoContent ref="contextInfoRef" :title="t('feeds.title')">
|
||||||
<div
|
<div
|
||||||
class="post"
|
class="post"
|
||||||
:class="{
|
:class="{
|
||||||
@@ -46,9 +46,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, onMounted, reactive} from "vue";
|
import {computed, onMounted, reactive, ref} from "vue";
|
||||||
import {useI18n} from "vue-i18n";
|
import {useI18n} from "vue-i18n";
|
||||||
import {useStorage} from "@vueuse/core"
|
import {useStorage} from "@vueuse/core"
|
||||||
|
import {useScrollMemory} from "../../composables/useScrollMemory"
|
||||||
|
|
||||||
import OpenInNew from "vue-material-design-icons/OpenInNew.vue";
|
import OpenInNew from "vue-material-design-icons/OpenInNew.vue";
|
||||||
import MenuDown from "vue-material-design-icons/MenuDown.vue";
|
import MenuDown from "vue-material-design-icons/MenuDown.vue";
|
||||||
@@ -62,6 +63,7 @@
|
|||||||
const apiStore = useApiStore();
|
const apiStore = useApiStore();
|
||||||
const {t} = useI18n({useScope: "global"});
|
const {t} = useI18n({useScope: "global"});
|
||||||
|
|
||||||
|
const contextInfoRef = ref<InstanceType<typeof ContextInfoContent> | null>(null);
|
||||||
const feeds = computed(() => apiStore.feeds);
|
const feeds = computed(() => apiStore.feeds);
|
||||||
|
|
||||||
const expanded = reactive<Record<string, boolean>>({});
|
const expanded = reactive<Record<string, boolean>>({});
|
||||||
@@ -70,6 +72,9 @@
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
lastNewsReadDate.value = feeds.value[0].publicationDate;
|
lastNewsReadDate.value = feeds.value[0].publicationDate;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const scrollableElement = computed(() => contextInfoRef.value?.contentRef || null)
|
||||||
|
useScrollMemory(ref("context-panel-news"), scrollableElement as any)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -20,8 +20,7 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import {State} from "@kestra-io/ui-libs"
|
import {State, Status} from "@kestra-io/ui-libs"
|
||||||
import Status from "../Status.vue";
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {Status},
|
components: {Status},
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
|
|
||||||
const namespace = computed(() => route.params?.id) as Ref<string>;
|
const namespace = computed(() => route.params?.id) as Ref<string>;
|
||||||
|
|
||||||
|
const miscStore = useMiscStore();
|
||||||
const namespacesStore = useNamespacesStore();
|
const namespacesStore = useNamespacesStore();
|
||||||
|
|
||||||
watch(namespace, (newID) => {
|
watch(namespace, (newID) => {
|
||||||
@@ -40,13 +41,12 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
watch(() => route.params.tab, (newTab) => {
|
watch(() => route.params.tab, (newTab) => {
|
||||||
if (newTab === "overview") {
|
if (newTab === "overview" || newTab === "executions") {
|
||||||
const dateTimeKeys = ["startDate", "endDate", "timeRange"];
|
const dateTimeKeys = ["startDate", "endDate", "timeRange"];
|
||||||
|
|
||||||
if (!Object.keys(route.query).some((key) => dateTimeKeys.some((dateTimeKey) => key.includes(dateTimeKey)))) {
|
if (!Object.keys(route.query).some((key) => dateTimeKeys.some((dateTimeKey) => key.includes(dateTimeKey)))) {
|
||||||
const miscStore = useMiscStore();
|
const DEFAULT_DURATION = miscStore.configs?.chartDefaultDuration ?? "P30D";
|
||||||
const defaultDuration = miscStore.configs?.chartDefaultDuration || "P30D";
|
const newQuery = {...route.query, "filters[timeRange][EQUALS]": DEFAULT_DURATION};
|
||||||
const newQuery = {...route.query, "filters[timeRange][EQUALS]": defaultDuration};
|
|
||||||
router.replace({name: route.name, params: route.params, query: newQuery});
|
router.replace({name: route.name, params: route.params, query: newQuery});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="no-code">
|
<div class="no-code" ref="scrollContainer">
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<Task
|
<Task
|
||||||
v-if="creatingTask || editingTask"
|
v-if="creatingTask || editingTask"
|
||||||
@@ -64,6 +64,7 @@
|
|||||||
import {usePluginsStore} from "../../stores/plugins";
|
import {usePluginsStore} from "../../stores/plugins";
|
||||||
import {useKeyboardSave} from "./utils/useKeyboardSave";
|
import {useKeyboardSave} from "./utils/useKeyboardSave";
|
||||||
import {deepEqual} from "../../utils/utils";
|
import {deepEqual} from "../../utils/utils";
|
||||||
|
import {useScrollMemory} from "../../composables/useScrollMemory";
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps<NoCodeProps>();
|
const props = defineProps<NoCodeProps>();
|
||||||
@@ -195,6 +196,28 @@
|
|||||||
emit("editTask", parentPath, blockSchemaPath, refPath)
|
emit("editTask", parentPath, blockSchemaPath, refPath)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Scroll position persistence for No-code editor
|
||||||
|
const scrollContainer = ref<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
const flowIdentity = computed(() => {
|
||||||
|
const namespace = flowStore.flow?.namespace ?? "";
|
||||||
|
const flowId = flowStore.flow?.id ?? "";
|
||||||
|
return `${namespace}/${flowId}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const scrollKey = computed(() => {
|
||||||
|
const base = `nocode:${flowIdentity.value}`;
|
||||||
|
// home screen
|
||||||
|
if (!props.creatingTask && !props.editingTask) return `${base}:home`;
|
||||||
|
// task-specific
|
||||||
|
const action = props.creatingTask ? "create" : "edit";
|
||||||
|
const parentPath = props.parentPath ?? "";
|
||||||
|
const refPath = props.refPath ?? "";
|
||||||
|
const fieldName = props.fieldName ?? "";
|
||||||
|
return `${base}:task:${action}:parentPath:${parentPath}:refPath:${refPath}:fieldName:${fieldName}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
useScrollMemory(scrollKey, scrollContainer);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="playgroundStore.enabled && isTask && taskObject?.id" class="flow-playground">
|
<div v-if="playgroundStore.enabled && isTask && taskModel?.id" class="flow-playground">
|
||||||
<PlaygroundRunTaskButton :taskId="taskObject?.id" />
|
<PlaygroundRunTaskButton :taskId="taskModel?.id" />
|
||||||
</div>
|
</div>
|
||||||
<el-form v-if="isTaskDefinitionBasedOnType" labelPosition="top">
|
<el-form v-if="isTaskDefinitionBasedOnType" labelPosition="top">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
@@ -17,12 +17,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<div @click="isPlugin && pluginsStore.updateDocumentation(taskObject as Parameters<typeof pluginsStore.updateDocumentation>[0])">
|
<div @click="() => onTaskEditorClick(taskModel)">
|
||||||
<TaskObject
|
<TaskObject
|
||||||
v-loading="isLoading"
|
v-loading="isLoading"
|
||||||
v-if="(selectedTaskType || !isTaskDefinitionBasedOnType) && schema"
|
v-if="(selectedTaskType || !isTaskDefinitionBasedOnType) && schema"
|
||||||
name="root"
|
name="root"
|
||||||
:modelValue="taskObject"
|
:modelValue="taskModel"
|
||||||
@update:model-value="onTaskInput"
|
@update:model-value="onTaskInput"
|
||||||
:schema
|
:schema
|
||||||
:properties
|
:properties
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
FULL_SCHEMA_INJECTION_KEY,
|
FULL_SCHEMA_INJECTION_KEY,
|
||||||
SCHEMA_DEFINITIONS_INJECTION_KEY,
|
SCHEMA_DEFINITIONS_INJECTION_KEY,
|
||||||
DATA_TYPES_MAP_INJECTION_KEY,
|
DATA_TYPES_MAP_INJECTION_KEY,
|
||||||
|
ON_TASK_EDITOR_CLICK_INJECTION_KEY,
|
||||||
} from "../injectionKeys";
|
} from "../injectionKeys";
|
||||||
import {removeNullAndUndefined} from "../utils/cleanUp";
|
import {removeNullAndUndefined} from "../utils/cleanUp";
|
||||||
import {removeRefPrefix, usePluginsStore} from "../../../stores/plugins";
|
import {removeRefPrefix, usePluginsStore} from "../../../stores/plugins";
|
||||||
@@ -63,9 +64,9 @@
|
|||||||
const pluginsStore = usePluginsStore();
|
const pluginsStore = usePluginsStore();
|
||||||
const playgroundStore = usePlaygroundStore();
|
const playgroundStore = usePlaygroundStore();
|
||||||
|
|
||||||
type PartialCodeElement = Partial<NoCodeElement>;
|
type PartialNoCodeElement = Partial<NoCodeElement>;
|
||||||
|
|
||||||
const taskObject = ref<PartialCodeElement | undefined>({});
|
const taskModel = ref<PartialNoCodeElement | undefined>({});
|
||||||
const selectedTaskType = ref<string>();
|
const selectedTaskType = ref<string>();
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
|
|
||||||
@@ -108,7 +109,7 @@
|
|||||||
|
|
||||||
watch(modelValue, (v) => {
|
watch(modelValue, (v) => {
|
||||||
if (!v) {
|
if (!v) {
|
||||||
taskObject.value = {};
|
taskModel.value = {};
|
||||||
selectedTaskType.value = undefined;
|
selectedTaskType.value = undefined;
|
||||||
} else {
|
} else {
|
||||||
setup()
|
setup()
|
||||||
@@ -150,20 +151,20 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
const parsed = YAML_UTILS.parse<PartialCodeElement>(modelValue.value);
|
const parsed = YAML_UTILS.parse<PartialNoCodeElement>(modelValue.value);
|
||||||
if(isPluginDefaults.value){
|
if(isPluginDefaults.value){
|
||||||
const {forced, type, values} = parsed as any;
|
const {forced, type, values} = parsed as any;
|
||||||
taskObject.value = {...values, forced, type};
|
taskModel.value = {...values, forced, type};
|
||||||
}else{
|
}else{
|
||||||
taskObject.value = parsed;
|
taskModel.value = parsed;
|
||||||
}
|
}
|
||||||
selectedTaskType.value = taskObject.value?.type;
|
selectedTaskType.value = taskModel.value?.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// when tab is opened, load the documentation
|
// when tab is opened, load the documentation
|
||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
if(selectedTaskType.value && parentPath !== "inputs"){
|
if(selectedTaskType.value && parentPath !== "inputs"){
|
||||||
pluginsStore.updateDocumentation(taskObject.value as Parameters<typeof pluginsStore.updateDocumentation>[0]);
|
pluginsStore.updateDocumentation(taskModel.value as Parameters<typeof pluginsStore.updateDocumentation>[0]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -218,7 +219,7 @@
|
|||||||
const resolvedType = computed<string>(() => {
|
const resolvedType = computed<string>(() => {
|
||||||
if(resolvedTypes.value.length > 1 && selectedTaskType.value){
|
if(resolvedTypes.value.length > 1 && selectedTaskType.value){
|
||||||
// find the resolvedType that match the current dataType
|
// find the resolvedType that match the current dataType
|
||||||
const dataType = taskObject.value?.data?.type;
|
const dataType = taskModel.value?.data?.type;
|
||||||
if(dataType){
|
if(dataType){
|
||||||
for(const typeLocal of resolvedTypes.value){
|
for(const typeLocal of resolvedTypes.value){
|
||||||
const schema = definitions.value?.[typeLocal];
|
const schema = definitions.value?.[typeLocal];
|
||||||
@@ -330,13 +331,13 @@
|
|||||||
watch([selectedTaskType, fullSchema], ([task]) => {
|
watch([selectedTaskType, fullSchema], ([task]) => {
|
||||||
if (task) {
|
if (task) {
|
||||||
if(isPlugin.value){
|
if(isPlugin.value){
|
||||||
pluginsStore.updateDocumentation(taskObject.value as Parameters<typeof pluginsStore.updateDocumentation>[0]);
|
pluginsStore.updateDocumentation(taskModel.value as Parameters<typeof pluginsStore.updateDocumentation>[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {immediate: true});
|
}, {immediate: true});
|
||||||
|
|
||||||
function onTaskInput(val: PartialCodeElement | undefined) {
|
function onTaskInput(val: PartialNoCodeElement | undefined) {
|
||||||
taskObject.value = val;
|
taskModel.value = val;
|
||||||
if(fieldName){
|
if(fieldName){
|
||||||
val = {
|
val = {
|
||||||
[fieldName]: val,
|
[fieldName]: val,
|
||||||
@@ -362,12 +363,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onTaskTypeSelect() {
|
function onTaskTypeSelect() {
|
||||||
const value: PartialCodeElement = {
|
const value: PartialNoCodeElement = {
|
||||||
type: selectedTaskType.value ?? ""
|
type: selectedTaskType.value ?? ""
|
||||||
};
|
};
|
||||||
|
|
||||||
onTaskInput(value);
|
onTaskInput(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onTaskEditorClick = inject(ON_TASK_EDITOR_CLICK_INJECTION_KEY, (elt?: PartialNoCodeElement) => {
|
||||||
|
const type = elt?.type;
|
||||||
|
if(isPlugin.value && type){
|
||||||
|
pluginsStore.updateDocumentation({type});
|
||||||
|
}else{
|
||||||
|
pluginsStore.updateDocumentation();
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||