mirror of
https://github.com/kestra-io/kestra.git
synced 2025-12-25 11:12:12 -05:00
Compare commits
61 Commits
run-develo
...
v0.22.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9857930da1 | ||
|
|
f9c47b2324 | ||
|
|
38f68dae5b | ||
|
|
632c5836da | ||
|
|
fedbffbdf5 | ||
|
|
8ccab1d6df | ||
|
|
0833e800d3 | ||
|
|
6ead4e63cd | ||
|
|
9cb51ba0ee | ||
|
|
b78748ebfb | ||
|
|
5757b576e9 | ||
|
|
94dcba1262 | ||
|
|
ae223c8d78 | ||
|
|
7cfbb91e7b | ||
|
|
3ce2cdaeb9 | ||
|
|
c5f2901f7f | ||
|
|
ea2bb3f6bd | ||
|
|
ed58b7b5b8 | ||
|
|
e6e0ffcdb7 | ||
|
|
ca84a0fbfd | ||
|
|
08579cf555 | ||
|
|
2b5d08c9f2 | ||
|
|
822a3b438a | ||
|
|
f6db013142 | ||
|
|
a031bfc129 | ||
|
|
1613dee76b | ||
|
|
a884708862 | ||
|
|
91bf3207f4 | ||
|
|
95b1f8dfcc | ||
|
|
4e7c6e87be | ||
|
|
8ac089de1d | ||
|
|
3d7c891b95 | ||
|
|
54eccac637 | ||
|
|
b3799cc039 | ||
|
|
143ebc061f | ||
|
|
224026c399 | ||
|
|
a093198004 | ||
|
|
380e329e97 | ||
|
|
6ee206f5f3 | ||
|
|
6c43f9c7c3 | ||
|
|
ec067e1a06 | ||
|
|
8ebc3fbba7 | ||
|
|
7e087c696c | ||
|
|
04b84df6ea | ||
|
|
b8e8333f62 | ||
|
|
54aa935702 | ||
|
|
8be17827c7 | ||
|
|
9d83d9b6eb | ||
|
|
ccd47f14ae | ||
|
|
8f4ce5fc18 | ||
|
|
acb305dfdb | ||
|
|
4c93a2b0e9 | ||
|
|
dea66ca259 | ||
|
|
c965f2f64c | ||
|
|
6516f7fc60 | ||
|
|
2dd61fc194 | ||
|
|
771e841d78 | ||
|
|
4448203031 | ||
|
|
e083163583 | ||
|
|
8617eb0c7b | ||
|
|
2a002e9531 |
60
.github/workflows/workflow-publish-docker.yml
vendored
60
.github/workflows/workflow-publish-docker.yml
vendored
@@ -8,6 +8,11 @@ on:
|
||||
default: 'LATEST'
|
||||
required: false
|
||||
type: string
|
||||
force-download-artifact:
|
||||
description: 'Force download artifact'
|
||||
required: false
|
||||
type: string
|
||||
default: "true"
|
||||
workflow_call:
|
||||
inputs:
|
||||
plugin-version:
|
||||
@@ -15,6 +20,11 @@ on:
|
||||
default: 'LATEST'
|
||||
required: false
|
||||
type: string
|
||||
force-download-artifact:
|
||||
description: 'Force download artifact'
|
||||
required: false
|
||||
type: string
|
||||
default: "true"
|
||||
secrets:
|
||||
DOCKERHUB_USERNAME:
|
||||
description: "The Dockerhub username."
|
||||
@@ -24,25 +34,38 @@ on:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
# ********************************************************************************************************************
|
||||
# Build
|
||||
# ********************************************************************************************************************
|
||||
build-artifacts:
|
||||
name: Build - Artifacts
|
||||
name: Build Artifacts
|
||||
if: ${{ github.event.inputs.force-download-artifact == 'true' }}
|
||||
uses: ./.github/workflows/workflow-build-artifacts.yml
|
||||
with:
|
||||
plugin-version: ${{ github.event.inputs.plugin-version != null && github.event.inputs.plugin-version || 'LATEST' }}
|
||||
|
||||
# ********************************************************************************************************************
|
||||
# Docker
|
||||
# ********************************************************************************************************************
|
||||
publish:
|
||||
name: Publish - Docker
|
||||
needs: build-artifacts
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-artifacts
|
||||
if: |
|
||||
always() &&
|
||||
(needs.build-artifacts.result == 'success' ||
|
||||
github.event.inputs.force-download-artifact != 'true')
|
||||
env:
|
||||
PLUGIN_VERSION: ${{ github.event.inputs.plugin-version != null && github.event.inputs.plugin-version || 'LATEST' }}
|
||||
strategy:
|
||||
matrix:
|
||||
image:
|
||||
- tag: ${{ needs.build-artifacts.outputs.docker-tag }}-no-plugins
|
||||
- tag: -no-plugins
|
||||
packages: jattach
|
||||
plugins: false
|
||||
python-libraries: ""
|
||||
|
||||
- tag: ${{ needs.build-artifacts.outputs.docker-tag }}
|
||||
plugins: ${{ needs.build-artifacts.outputs.plugins }}
|
||||
- tag: ""
|
||||
plugins: true
|
||||
packages: python3 python3-venv python-is-python3 python3-pip nodejs npm curl zip unzip jattach
|
||||
python-libraries: kestra
|
||||
steps:
|
||||
@@ -68,17 +91,34 @@ jobs:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
|
||||
# # Get Plugins List
|
||||
- name: Plugins - Get List
|
||||
uses: ./.github/actions/plugins-list
|
||||
id: plugins-list
|
||||
if: ${{ matrix.image.plugins}}
|
||||
with:
|
||||
plugin-version: ${{ env.PLUGIN_VERSION }}
|
||||
|
||||
# Vars
|
||||
- name: Docker - Set image name
|
||||
- name: Docker - Set variables
|
||||
shell: bash
|
||||
id: vars
|
||||
run: |
|
||||
TAG=${GITHUB_REF#refs/*/}
|
||||
if [[ $TAG = "master" || $TAG == v* ]]; then
|
||||
PLUGINS="${{ matrix.image.plugins == true && steps.plugins-list.outputs.plugins || '' }}"
|
||||
if [[ $TAG == v* ]]; then
|
||||
TAG="${TAG}";
|
||||
echo "plugins=${{ matrix.image.plugins }}" >> $GITHUB_OUTPUT
|
||||
elif [[ $TAG = "develop" ]]; then
|
||||
TAG="develop";
|
||||
echo "plugins=--repositories=https://s01.oss.sonatype.org/content/repositories/snapshots $PLUGINS" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "plugins=--repositories=https://s01.oss.sonatype.org/content/repositories/snapshots ${{ matrix.image.plugins }}" >> $GITHUB_OUTPUT
|
||||
TAG="build-${{ github.run_id }}";
|
||||
echo "plugins=--repositories=https://s01.oss.sonatype.org/content/repositories/snapshots $PLUGINS" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
echo "tag=${TAG}${{ matrix.image.tag }}" >> $GITHUB_OUTPUT
|
||||
|
||||
# Build Docker Image
|
||||
- name: Artifacts - Download executable
|
||||
@@ -98,7 +138,7 @@ jobs:
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: kestra/kestra:${{ matrix.image.tag }}
|
||||
tags: kestra/kestra:${{ steps.vars.outputs.tag }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
build-args: |
|
||||
KESTRA_PLUGINS=${{ steps.vars.outputs.plugins }}
|
||||
|
||||
11
.github/workflows/workflow-release.yml
vendored
11
.github/workflows/workflow-release.yml
vendored
@@ -38,9 +38,19 @@ on:
|
||||
description: "The Sonatype GPG file."
|
||||
required: true
|
||||
jobs:
|
||||
build-artifacts:
|
||||
name: Build - Artifacts
|
||||
uses: ./.github/workflows/workflow-build-artifacts.yml
|
||||
with:
|
||||
plugin-version: ${{ github.event.inputs.plugin-version != null && github.event.inputs.plugin-version || 'LATEST' }}
|
||||
|
||||
Docker:
|
||||
name: Publish Docker
|
||||
needs: build-artifacts
|
||||
uses: ./.github/workflows/workflow-publish-docker.yml
|
||||
with:
|
||||
force-download-artifact: 'false'
|
||||
plugin-version: ${{ github.event.inputs.plugin-version != null && github.event.inputs.plugin-version || 'LATEST' }}
|
||||
secrets:
|
||||
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
DOCKERHUB_PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
@@ -57,6 +67,7 @@ jobs:
|
||||
|
||||
Github:
|
||||
name: Github Release
|
||||
needs: build-artifacts
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
uses: ./.github/workflows/workflow-github-release.yml
|
||||
secrets:
|
||||
|
||||
775
CHANGELOG.md
Normal file
775
CHANGELOG.md
Normal file
@@ -0,0 +1,775 @@
|
||||
# 0.22.0
|
||||
|
||||
**Full Changelog**: [v0.21.0...v0.22.0](https://github.com/kestra-io/kestra/compare/v0.21.0...v0.22.0)
|
||||
|
||||
### 🚀 Enhancements
|
||||
|
||||
- **ui:** Don't show deprecated tasks in the plugins list ([8d00c8a55](https://github.com/kestra-io/kestra/commit/8d00c8a55))
|
||||
- **webserver:** If no date provided for dashboard, then use default timewindow ([b86b4bb16](https://github.com/kestra-io/kestra/commit/b86b4bb16))
|
||||
- Add a shadow to cards ([#7038](https://github.com/kestra-io/kestra/pull/7038))
|
||||
- **ui:** Multiple improvements of no code editor ([#7076](https://github.com/kestra-io/kestra/pull/7076))
|
||||
- **ui:** Display attempts status on taskrun on left ([84447fd42](https://github.com/kestra-io/kestra/commit/84447fd42))
|
||||
- **ui:** Improve the task array component ([#7095](https://github.com/kestra-io/kestra/pull/7095))
|
||||
- Show a lock on EE only pages ([#7093](https://github.com/kestra-io/kestra/pull/7093))
|
||||
- **ui:** Allow task re-ordering from no code editor ([#7120](https://github.com/kestra-io/kestra/pull/7120))
|
||||
- **ui:** Add finally block to no code editor ([#7123](https://github.com/kestra-io/kestra/pull/7123))
|
||||
- **build:** Add script to makefile ([#7125](https://github.com/kestra-io/kestra/pull/7125))
|
||||
- **ui:** Add a link to the filtered Executions table. ([#7129](https://github.com/kestra-io/kestra/pull/7129))
|
||||
- **ui:** Multiple improvements of no code editor ([#7146](https://github.com/kestra-io/kestra/pull/7146))
|
||||
- **core:** New Publish task for metrics ([#7122](https://github.com/kestra-io/kestra/pull/7122))
|
||||
- **jdbc-*:** Delete subflow_executions table ([671eb2b57](https://github.com/kestra-io/kestra/commit/671eb2b57))
|
||||
- **ui:** Add keyboard shortcuts dialog to editor ([#6628](https://github.com/kestra-io/kestra/pull/6628))
|
||||
- **ui:** Now display an error when SSE failed ([#7177](https://github.com/kestra-io/kestra/pull/7177))
|
||||
- **ui:** Docs markdown alert styled based on alert level in product. ([#6818](https://github.com/kestra-io/kestra/pull/6818))
|
||||
- **ui:** Add option to choose visible columns in flow and execution listings ([#6932](https://github.com/kestra-io/kestra/pull/6932))
|
||||
- Theme switch to "theme switch" the charts ([#7151](https://github.com/kestra-io/kestra/pull/7151))
|
||||
- **ui:** Add script to help with creation of release notes ([#7212](https://github.com/kestra-io/kestra/pull/7212))
|
||||
- **core:** Allow loading secrets from a different namspace ([21aebe4e7](https://github.com/kestra-io/kestra/commit/21aebe4e7))
|
||||
- **webserver:** Optimize queue usage for follow endpoints ([13be8b812](https://github.com/kestra-io/kestra/commit/13be8b812))
|
||||
- **webserver:** Improvement to ExecutionStreaminService ([4c401ce0c](https://github.com/kestra-io/kestra/commit/4c401ce0c))
|
||||
- **cicd:** Codecov + tests report ([03dccd144](https://github.com/kestra-io/kestra/commit/03dccd144))
|
||||
- **cicd:** Add codecov bundle analysis ([ab2a0108a](https://github.com/kestra-io/kestra/commit/ab2a0108a))
|
||||
- **webserver:** Use a shared queue consumer from the log follow endpoint ([2a95aee96](https://github.com/kestra-io/kestra/commit/2a95aee96))
|
||||
- **core:** Add sanity check to request task ([#7230](https://github.com/kestra-io/kestra/pull/7230))
|
||||
- **ci:** Add workflows for release process ([480fc7589](https://github.com/kestra-io/kestra/commit/480fc7589))
|
||||
- **cicd:** Add codecov flags ([3f429ef0a](https://github.com/kestra-io/kestra/commit/3f429ef0a))
|
||||
- **core:** Simplify Pebble error messages ([1eacb447d](https://github.com/kestra-io/kestra/commit/1eacb447d))
|
||||
- **cicd:** Add unit test for js ([#7246](https://github.com/kestra-io/kestra/pull/7246))
|
||||
- **cicd:** Add test analysis on frontend ([123f74803](https://github.com/kestra-io/kestra/commit/123f74803))
|
||||
- **cicd:** Don't mark failed for front end test ([1bbe0e659](https://github.com/kestra-io/kestra/commit/1bbe0e659))
|
||||
- **cicd:** Restore codeql weekly ([0c3ed3b75](https://github.com/kestra-io/kestra/commit/0c3ed3b75))
|
||||
- **core, jdbc:** Directly process WorkerTaskResult from flowable tasks ([be1871430](https://github.com/kestra-io/kestra/commit/be1871430))
|
||||
- **ui:** Center view when switching between topology modes ([#7257](https://github.com/kestra-io/kestra/pull/7257))
|
||||
- Give blueprint pages a distinct name ([#7254](https://github.com/kestra-io/kestra/pull/7254))
|
||||
- **core:** Added FileEmpty & FileExists Pebble Functions ([88a5cd69e](https://github.com/kestra-io/kestra/commit/88a5cd69e))
|
||||
- **jdbc:** Purge execution queue early ([dd8ae5e64](https://github.com/kestra-io/kestra/commit/dd8ae5e64))
|
||||
- **jdbc:** Puerge worker task result queue early ([31d221241](https://github.com/kestra-io/kestra/commit/31d221241))
|
||||
- **jdbc:** Purge worker job queue early ([e7f551edc](https://github.com/kestra-io/kestra/commit/e7f551edc))
|
||||
- **core:** Add system.correlationId label to triggered executions ([ed1449363](https://github.com/kestra-io/kestra/commit/ed1449363))
|
||||
- **jdbc:** Queues.updated should be set when the record is updated ([9d717caf9](https://github.com/kestra-io/kestra/commit/9d717caf9))
|
||||
- **jdbc:** Clean more eagerly some queues based on configuration ([13ac335c9](https://github.com/kestra-io/kestra/commit/13ac335c9))
|
||||
- **core, jdbc:** Use an elastic thread pool ([f8a6e3fb0](https://github.com/kestra-io/kestra/commit/f8a6e3fb0))
|
||||
- **jdbc:** Consume multiple times the execution and worker task result queues ([41712b8d8](https://github.com/kestra-io/kestra/commit/41712b8d8))
|
||||
- ([#7389](https://github.com/kestra-io/kestra/pull/7389))
|
||||
- ([#7432](https://github.com/kestra-io/kestra/pull/7432))
|
||||
- **ui:** Add keyboard shortcuts for changing editor font size ([#7450](https://github.com/kestra-io/kestra/pull/7450))
|
||||
- **ui:** Introduce topology export to image files ([#7541](https://github.com/kestra-io/kestra/pull/7541))
|
||||
- Add plugin search command ([e7950279b](https://github.com/kestra-io/kestra/commit/e7950279b))
|
||||
- **ui:** Improve inspecting details of multiple executions ([#7516](https://github.com/kestra-io/kestra/pull/7516))
|
||||
- **ui:** Add ability to have persistent filter options ([#7276](https://github.com/kestra-io/kestra/pull/7276))
|
||||
- Add full examples for datetimebetween condition ([#7598](https://github.com/kestra-io/kestra/pull/7598))
|
||||
- **ui:** Introduce the execution timeline section on overview tab ([#7498](https://github.com/kestra-io/kestra/pull/7498))
|
||||
- **ui:** Make filter dropdown be positioned below the input caret ([#7614](https://github.com/kestra-io/kestra/pull/7614))
|
||||
- **core:** Enhance plugin management ([a098847c6](https://github.com/kestra-io/kestra/commit/a098847c6))
|
||||
- **ui:** Allow reordering tabs in the editor ([#7531](https://github.com/kestra-io/kestra/pull/7531))
|
||||
- **core:** Improve performance of ExecutorService.handleChildWorkerTaskResult ([fa07cbd3b](https://github.com/kestra-io/kestra/commit/fa07cbd3b))
|
||||
- **#7636:** Add default options for HttpClient ([5b42d0adb](https://github.com/kestra-io/kestra/commit/5b42d0adb))
|
||||
- **#7636:** Add default options for HttpClient" ([7ccb97a96](https://github.com/kestra-io/kestra/commit/7ccb97a96))
|
||||
- **core:** Replace new ArrayList by Collections.emptyList() ([ff3f90465](https://github.com/kestra-io/kestra/commit/ff3f90465))
|
||||
- **core:** Use HashMap.newHashMap(int) ([677585213](https://github.com/kestra-io/kestra/commit/677585213))
|
||||
- **core:** Improve merging outputs by merging them at the task level ([8c708e2d5](https://github.com/kestra-io/kestra/commit/8c708e2d5))
|
||||
- Add examples for conditions - 3 ([#7657](https://github.com/kestra-io/kestra/pull/7657))
|
||||
- Add examples for flow conditions ([#7659](https://github.com/kestra-io/kestra/pull/7659))
|
||||
- Add example for expression condition ([#7660](https://github.com/kestra-io/kestra/pull/7660))
|
||||
- **#7636:** Add default options for HttpClient ([#7650](https://github.com/kestra-io/kestra/pull/7650))
|
||||
- **core, jdbc:** DashboardRepository.findAll() ([cd97705d8](https://github.com/kestra-io/kestra/commit/cd97705d8))
|
||||
- **ui:** Add markdown formatting to flow run dialog ([#7663](https://github.com/kestra-io/kestra/pull/7663))
|
||||
- **core, jdbc:** Dynamic worker group key ([2c63112a5](https://github.com/kestra-io/kestra/commit/2c63112a5))
|
||||
- **core-ee:** #2838 add audit log shipper ([#7701](https://github.com/kestra-io/kestra/pull/7701), [#2838](https://github.com/kestra-io/kestra/issues/2838))
|
||||
- **core:** Allow reading file from any namespaces ([dfe5552a1](https://github.com/kestra-io/kestra/commit/dfe5552a1))
|
||||
- **core:** Add new crudEventType value ([f7e61a46d](https://github.com/kestra-io/kestra/commit/f7e61a46d))
|
||||
- **core:** #7721 add namespace to pebble file functions ([#7729](https://github.com/kestra-io/kestra/pull/7729), [#7721](https://github.com/kestra-io/kestra/issues/7721))
|
||||
- **webserver:** Mask the secret() function result from eval outputs ([88341bb5c](https://github.com/kestra-io/kestra/commit/88341bb5c))
|
||||
- **core:** Handle worker group fallback inside the scheduler ([e9f2711cd](https://github.com/kestra-io/kestra/commit/e9f2711cd))
|
||||
- **core:** #5467 add namespaces in the namespaceFiles parameter ([#7749](https://github.com/kestra-io/kestra/pull/7749), [#5467](https://github.com/kestra-io/kestra/issues/5467))
|
||||
- **core:** Add outputs to the Flow trigger ([1692cab53](https://github.com/kestra-io/kestra/commit/1692cab53))
|
||||
- **core:** Custom log filter ([3ef11044a](https://github.com/kestra-io/kestra/commit/3ef11044a))
|
||||
- **core-ee:** Add json format to file log exporter ([#7789](https://github.com/kestra-io/kestra/pull/7789))
|
||||
- **ui:** Introduce kv() and secret() pebble autocompletions ([a064c7a95](https://github.com/kestra-io/kestra/commit/a064c7a95))
|
||||
- **core:** Add execution state in Pebbe context ([d0af5767d](https://github.com/kestra-io/kestra/commit/d0af5767d))
|
||||
- **core:** AfterExecution tasks ([39b8fc103](https://github.com/kestra-io/kestra/commit/39b8fc103))
|
||||
- **core,jdbc:** Switch back to a cached thread pool for async JDBC queue ([c2e62d653](https://github.com/kestra-io/kestra/commit/c2e62d653))
|
||||
- **build:** Configure heap size to max 50% of available memory ([#7800](https://github.com/kestra-io/kestra/pull/7800))
|
||||
- **core:** Redact KESTRA_JAVA_OPTS from the env available to executions ([ecfe925ec](https://github.com/kestra-io/kestra/commit/ecfe925ec))
|
||||
- Add finally to the flow assets in basic.md ([#7857](https://github.com/kestra-io/kestra/pull/7857))
|
||||
- **core:** Add afterExecution to the topology ([f7019af9d](https://github.com/kestra-io/kestra/commit/f7019af9d))
|
||||
- **ui:** Add `afterExecution` block to no code editor ([#7848](https://github.com/kestra-io/kestra/pull/7848))
|
||||
- **cli:** Add new --all option to plugin install cmd ([#7375](https://github.com/kestra-io/kestra/pull/7375))
|
||||
- **core:** Add Kestra env name and URL to the expression context ([1ba54cd08](https://github.com/kestra-io/kestra/commit/1ba54cd08))
|
||||
- **webserver:** Add Kestra URL to the config endpoint ([70e6d47c1](https://github.com/kestra-io/kestra/commit/70e6d47c1))
|
||||
- **ui:** Add copy button to kv store listing rows ([#7907](https://github.com/kestra-io/kestra/pull/7907))
|
||||
- **ui:** Implement a default tab setting for flows ([#7917](https://github.com/kestra-io/kestra/pull/7917))
|
||||
- ⚠️ Make kv pebble function raise error by default ([#7855](https://github.com/kestra-io/kestra/pull/7855))
|
||||
- **ui:** Add the option to copy single/all logs to clipboard ([#7755](https://github.com/kestra-io/kestra/pull/7755))
|
||||
- **ui:** Add beta badge global component ([#7934](https://github.com/kestra-io/kestra/pull/7934))
|
||||
- **model, core:** Document tasks props that are internal storage URI ([745c64c4b](https://github.com/kestra-io/kestra/commit/745c64c4b))
|
||||
- **core:** Add correlationId to the Flow trigger ([a7433c6f6](https://github.com/kestra-io/kestra/commit/a7433c6f6))
|
||||
- ***:** Allow disabling flow logs and use a specific logger for executions, tasks and triggers ([11a166486](https://github.com/kestra-io/kestra/commit/11a166486))
|
||||
- **core:** Require existing namespace ([6194f244c](https://github.com/kestra-io/kestra/commit/6194f244c))
|
||||
- **ui:** Introduce global KV Store view ([ab7788aea](https://github.com/kestra-io/kestra/commit/ab7788aea))
|
||||
- **core:** Allow null or empty proxy address to bypass proxy conf ([73c7a2d3d](https://github.com/kestra-io/kestra/commit/73c7a2d3d))
|
||||
- **core:** Speed up namespace file download and add a log & metrics ([f29aab071](https://github.com/kestra-io/kestra/commit/f29aab071))
|
||||
- **core:** #7932 add file exist comportment to NamespaceFiles ([#7979](https://github.com/kestra-io/kestra/pull/7979), [#7932](https://github.com/kestra-io/kestra/issues/7932))
|
||||
- **core:** Add new subkey arg to secret pebble function ([0987d0b34](https://github.com/kestra-io/kestra/commit/0987d0b34))
|
||||
- Multi panel editor without the refactor ([#7971](https://github.com/kestra-io/kestra/pull/7971))
|
||||
- Parse docs is 2 steps to avoid user waiting with nothing ([#7149](https://github.com/kestra-io/kestra/pull/7149))
|
||||
- **core,jdbc:** Reset the trigger inside the JdbcExecutor ([4a3d6b30d](https://github.com/kestra-io/kestra/commit/4a3d6b30d))
|
||||
- **ui:** Introduce global Secrets page ([d9ac26716](https://github.com/kestra-io/kestra/commit/d9ac26716))
|
||||
- **docs:** Add example for best practice with multiline json http post request ([#8023](https://github.com/kestra-io/kestra/pull/8023))
|
||||
- **core:** #5467 add inheritance for KV in pebble and Get task ([#8031](https://github.com/kestra-io/kestra/pull/8031), [#5467](https://github.com/kestra-io/kestra/issues/5467))
|
||||
- Cleaner multipanel tab move ([#8029](https://github.com/kestra-io/kestra/pull/8029))
|
||||
- **ui:** Improve styling of saved filter searches ([#8040](https://github.com/kestra-io/kestra/pull/8040))
|
||||
- ***:** Add new methods findAllAsync for the backup ([c965f2f64](https://github.com/kestra-io/kestra/commit/c965f2f64))
|
||||
- **core-ee:** #7501 split file log exporter to multiple files ([#8138](https://github.com/kestra-io/kestra/pull/8138), [#7501](https://github.com/kestra-io/kestra/issues/7501))
|
||||
|
||||
### 🩹 Fixes
|
||||
|
||||
- **cli:** Flow watcher should compute plugin defaults ([07dfaada9](https://github.com/kestra-io/kestra/commit/07dfaada9))
|
||||
- **ui:** Dynamic format date ([d17fe2548](https://github.com/kestra-io/kestra/commit/d17fe2548))
|
||||
- Namespaces should have the card background ([b8fac95e1](https://github.com/kestra-io/kestra/commit/b8fac95e1))
|
||||
- **styles:** Remove background color from edit buttons ([#7037](https://github.com/kestra-io/kestra/pull/7037))
|
||||
- Use proper css variables for table colors ([#7049](https://github.com/kestra-io/kestra/pull/7049))
|
||||
- Remove default variables for box-shadow ([f1b294065](https://github.com/kestra-io/kestra/commit/f1b294065))
|
||||
- Color of tags in executions list ([#7035](https://github.com/kestra-io/kestra/pull/7035))
|
||||
- **core:** RestartForEachItem() is flaky ([6afdbb01f](https://github.com/kestra-io/kestra/commit/6afdbb01f))
|
||||
- **script:** AbstractExecScript.injectDefaults should throw IllegalVariableEvaluationException ([2777b3438](https://github.com/kestra-io/kestra/commit/2777b3438))
|
||||
- **cli:** Repeate flaky tests FileChangedEventListenerTest ([03caf3825](https://github.com/kestra-io/kestra/commit/03caf3825))
|
||||
- **demo:** Make button clickable with utm link ([491546557](https://github.com/kestra-io/kestra/commit/491546557))
|
||||
- Remove the topbar from namepasce/flows ([accbafe13](https://github.com/kestra-io/kestra/commit/accbafe13))
|
||||
- Remove some warnings ([7a299e51f](https://github.com/kestra-io/kestra/commit/7a299e51f))
|
||||
- **ui:** Amend no code editor breadcrumbs issue ([#7054](https://github.com/kestra-io/kestra/pull/7054))
|
||||
- **docs:** Remove custom dashboard website component ([e1a4f2e2f](https://github.com/kestra-io/kestra/commit/e1a4f2e2f))
|
||||
- Unlock audit logs in execution ([157566300](https://github.com/kestra-io/kestra/commit/157566300))
|
||||
- Transfer utm parameters correctly ([0e09f6821](https://github.com/kestra-io/kestra/commit/0e09f6821))
|
||||
- **ui:** Fix missing param kind for blueprint in flow editor ([#7087](https://github.com/kestra-io/kestra/pull/7087))
|
||||
- **core:** Subflow validation didn't work anymore ([9b2c4c9a1](https://github.com/kestra-io/kestra/commit/9b2c4c9a1))
|
||||
- **core:** Retry flaky test AbstractRunnerTest.multipleConditionTriggerFailed() ([db4f186bd](https://github.com/kestra-io/kestra/commit/db4f186bd))
|
||||
- **core:** Http request with head and 404 and sending the wrong exception ([6ee0e86ca](https://github.com/kestra-io/kestra/commit/6ee0e86ca))
|
||||
- **cli:** Retry flaky test FlowCreateOrUpdateCommandTest.runWithDelete. ([96f4466f1](https://github.com/kestra-io/kestra/commit/96f4466f1))
|
||||
- **core:** Subflow labels must not be overriden by parent flow ones ([6190d9113](https://github.com/kestra-io/kestra/commit/6190d9113))
|
||||
- Use the new charts in the flows page ([#6970](https://github.com/kestra-io/kestra/pull/6970))
|
||||
- Plugin header icon for ticket #4252 ([#4252](https://github.com/kestra-io/kestra/issues/4252))
|
||||
- Make sure normal single line table dont' push the build #7018 ([#7018](https://github.com/kestra-io/kestra/issues/7018))
|
||||
- **core:** Retry flaky test TimeoutTest.timeout() ([4e753c7b9](https://github.com/kestra-io/kestra/commit/4e753c7b9))
|
||||
- Protect axios JSON parsing ([a4dcb8dcd](https://github.com/kestra-io/kestra/commit/a4dcb8dcd))
|
||||
- Remove FE warnings on flow edition ([65dd4f9fd](https://github.com/kestra-io/kestra/commit/65dd4f9fd))
|
||||
- Remove Labels tag type warning ([3a8b24eda](https://github.com/kestra-io/kestra/commit/3a8b24eda))
|
||||
- Avoid clearing selected value on every error ([631a016e0](https://github.com/kestra-io/kestra/commit/631a016e0))
|
||||
- **ui:** Remove useless double click row action ([e527f0133](https://github.com/kestra-io/kestra/commit/e527f0133))
|
||||
- **ci:** Update scripts/workflows for plugins ([555b769aa](https://github.com/kestra-io/kestra/commit/555b769aa))
|
||||
- Use the proper variable for select header in table ([#7107](https://github.com/kestra-io/kestra/pull/7107))
|
||||
- Make table links primary instead of purple ([#7106](https://github.com/kestra-io/kestra/pull/7106))
|
||||
- **ui:** Restore namespace filter manual typing & various improvements ([#7127](https://github.com/kestra-io/kestra/pull/7127))
|
||||
- **core:** Remove the dynamic property patterns ([e6827f273](https://github.com/kestra-io/kestra/commit/e6827f273))
|
||||
- **cli:** Print help on missing parameters ([ae05de4a1](https://github.com/kestra-io/kestra/commit/ae05de4a1))
|
||||
- **ui:** Amend log lines in Firefox ([#7133](https://github.com/kestra-io/kestra/pull/7133))
|
||||
- Enterprise edition tag in light mode ([85ebf49b6](https://github.com/kestra-io/kestra/commit/85ebf49b6))
|
||||
- Sidemenu bring back the gray hover ([e15eb5587](https://github.com/kestra-io/kestra/commit/e15eb5587))
|
||||
- **ui:** Get the string fields in no code to use editor and have auto completion back ([#7150](https://github.com/kestra-io/kestra/pull/7150))
|
||||
- **ui:** Switching from custom Flow blueprints tab to dashboard was not working ([fa5ef3b4c](https://github.com/kestra-io/kestra/commit/fa5ef3b4c))
|
||||
- **ui:** Custom Dashboard name overflows. ([#7124](https://github.com/kestra-io/kestra/pull/7124))
|
||||
- Setup docId for blueprints ([9499ee2c2](https://github.com/kestra-io/kestra/commit/9499ee2c2))
|
||||
- Bring back hover in main menu ([1bbe48fe5](https://github.com/kestra-io/kestra/commit/1bbe48fe5))
|
||||
- **core:** Process runner are not serialized correctly on worker ([c91827610](https://github.com/kestra-io/kestra/commit/c91827610))
|
||||
- **ui:** Amend pagination on namespace flows listing ([#7163](https://github.com/kestra-io/kestra/pull/7163))
|
||||
- **core:** Retry flaky test AbstractRunnerTest.restartFailedThenFailureWithGlobalErrors ([560703fde](https://github.com/kestra-io/kestra/commit/560703fde))
|
||||
- **ui:** Null-safe search filters ([21733d849](https://github.com/kestra-io/kestra/commit/21733d849))
|
||||
- **core:** Retry flaky test AbstractRunnereTest.concurrencyQueuePause ([f8b64cfbd](https://github.com/kestra-io/kestra/commit/f8b64cfbd))
|
||||
- **ui:** Amend translation string for no results ([#7172](https://github.com/kestra-io/kestra/pull/7172))
|
||||
- **ui:** Align dashboard button label to icon ([#7175](https://github.com/kestra-io/kestra/pull/7175))
|
||||
- **core:** Retry test HttpClientTest.getText ([20d55122e](https://github.com/kestra-io/kestra/commit/20d55122e))
|
||||
- **core:** Retry flaky test AbstractRunnerTest.restartForEachItem ([30db740de](https://github.com/kestra-io/kestra/commit/30db740de))
|
||||
- **core:** Make flow/namespace variables available for input expr ([8d8b7e7a6](https://github.com/kestra-io/kestra/commit/8d8b7e7a6))
|
||||
- **ui:** Global plugin doc with new redesign + auto-expand properties initially ([bbb03b288](https://github.com/kestra-io/kestra/commit/bbb03b288))
|
||||
- **theme:** Make plugin rendering reactive to theme switch ([9619dca76](https://github.com/kestra-io/kestra/commit/9619dca76))
|
||||
- **core:** #7181 log level rendered as string ([#7198](https://github.com/kestra-io/kestra/pull/7198), [#7181](https://github.com/kestra-io/kestra/issues/7181))
|
||||
- **core:** Request option doesn't initialize properly ([a0483dc20](https://github.com/kestra-io/kestra/commit/a0483dc20))
|
||||
- **ui:** Prevent doubling the executions chart on flow overview ([#7219](https://github.com/kestra-io/kestra/pull/7219))
|
||||
- **core:** Possible NPE on LabelService.containsAll ([ecd36ec2a](https://github.com/kestra-io/kestra/commit/ecd36ec2a))
|
||||
- **ui:** Amend the language switching issue ([#7235](https://github.com/kestra-io/kestra/pull/7235))
|
||||
- Add comment on i18n code ([e0ee26a9c](https://github.com/kestra-io/kestra/commit/e0ee26a9c))
|
||||
- Labels should not be purple if inactive ([95b94f396](https://github.com/kestra-io/kestra/commit/95b94f396))
|
||||
- **webserver,core:** Move the LogStreamService in core so EE can use it for apps ([84c07ef01](https://github.com/kestra-io/kestra/commit/84c07ef01))
|
||||
- **ci:** Fix and remove unecessary setps in set version workflows ([dc8576afe](https://github.com/kestra-io/kestra/commit/dc8576afe))
|
||||
- Make dashboard tables the right color ([6f7bb80c6](https://github.com/kestra-io/kestra/commit/6f7bb80c6))
|
||||
- Use the udpated labelsFromQuery in labels ([ec967a57f](https://github.com/kestra-io/kestra/commit/ec967a57f))
|
||||
- **ci:** Workflow test correct previous job status usage ([9ba27b9bd](https://github.com/kestra-io/kestra/commit/9ba27b9bd))
|
||||
- **ci:** Disabled previous generate translations CI ([5dcd27c06](https://github.com/kestra-io/kestra/commit/5dcd27c06))
|
||||
- **ci:** Missing checkout in release step ([09ff9d405](https://github.com/kestra-io/kestra/commit/09ff9d405))
|
||||
- **ci:** Removed useless name in action files ([4986d68f5](https://github.com/kestra-io/kestra/commit/4986d68f5))
|
||||
- **ci:** Pass correctly secret + cleanup ([945564366](https://github.com/kestra-io/kestra/commit/945564366))
|
||||
- **cicd:** Add npm install on vulnerabilities check ([9790f0237](https://github.com/kestra-io/kestra/commit/9790f0237))
|
||||
- **ci:** Workflow test ouptputs + changes for codecov ([c3e830c2c](https://github.com/kestra-io/kestra/commit/c3e830c2c))
|
||||
- **ci:** Inputs instead of secrets ([c53239470](https://github.com/kestra-io/kestra/commit/c53239470))
|
||||
- **core:** #7227 cron schedule with timezone and backfile not triggering ([#7285](https://github.com/kestra-io/kestra/pull/7285), [#7227](https://github.com/kestra-io/kestra/issues/7227))
|
||||
- Force run docs ([#7289](https://github.com/kestra-io/kestra/pull/7289))
|
||||
- Collapsed menu colors in light mode ([0becf7433](https://github.com/kestra-io/kestra/commit/0becf7433))
|
||||
- **ui:** Match chart colors ([#7290](https://github.com/kestra-io/kestra/pull/7290))
|
||||
- **makefile:** Build plugin now build main branch too ([#7297](https://github.com/kestra-io/kestra/pull/7297))
|
||||
- **core:** Flacky trigger with backfile test ([#7295](https://github.com/kestra-io/kestra/pull/7295))
|
||||
- **core:** Http client was not using deprecated setter ([25370d10b](https://github.com/kestra-io/kestra/commit/25370d10b))
|
||||
- **core:** Do not validate subflow if namespace or id is pebble ([#7294](https://github.com/kestra-io/kestra/pull/7294))
|
||||
- **h2:** Remove indenting in sql file ([#7306](https://github.com/kestra-io/kestra/pull/7306))
|
||||
- **core:** Add request.yaml file back ([#7308](https://github.com/kestra-io/kestra/pull/7308))
|
||||
- **core:** Possible NPE when an execution has no labels ([7dbf86d54](https://github.com/kestra-io/kestra/commit/7dbf86d54))
|
||||
- **cicd:** Npm install in the wrong folder for vulnerabilities checks ([7bf42cb1c](https://github.com/kestra-io/kestra/commit/7bf42cb1c))
|
||||
- Add proper ellipsis to sidemenu ([#7361](https://github.com/kestra-io/kestra/pull/7361))
|
||||
- Trim bookmarks better ([#7359](https://github.com/kestra-io/kestra/pull/7359))
|
||||
- **ui:** Make sure bulk selection is taking into account only selected items ([#7362](https://github.com/kestra-io/kestra/pull/7362))
|
||||
- Make menu hierarchy get closer to the original designs ([#7102](https://github.com/kestra-io/kestra/pull/7102))
|
||||
- **core:** Render list ([b45a44bd3](https://github.com/kestra-io/kestra/commit/b45a44bd3))
|
||||
- **jdbc:** Delete the executor state at the correct stage ([1d65fd96b](https://github.com/kestra-io/kestra/commit/1d65fd96b))
|
||||
- **ui:** Refresh dashboard list ([#7370](https://github.com/kestra-io/kestra/pull/7370))
|
||||
- **core:** Handle http request with no content type ([239fb6a68](https://github.com/kestra-io/kestra/commit/239fb6a68))
|
||||
- **cicd:** Add mariadb plugins on docker image ([5b29a0d07](https://github.com/kestra-io/kestra/commit/5b29a0d07))
|
||||
- **scheduler:** Delete trigger when flow is not found ([#7366](https://github.com/kestra-io/kestra/pull/7366))
|
||||
- **cli:** Disable by default OTEL metrics ([def8fa3ff](https://github.com/kestra-io/kestra/commit/def8fa3ff))
|
||||
- Changing language should work with providers too ([b8d0ae3ec](https://github.com/kestra-io/kestra/commit/b8d0ae3ec))
|
||||
- **ui:** Fix slack button on error toast ([ad651cdc5](https://github.com/kestra-io/kestra/commit/ad651cdc5))
|
||||
- **ui:** Properly handle the operation labels in filter component ([#7399](https://github.com/kestra-io/kestra/pull/7399))
|
||||
- **core:** Taskrun list can be null ([ddfed2e65](https://github.com/kestra-io/kestra/commit/ddfed2e65))
|
||||
- **ui:** Correct english translations ([#7401](https://github.com/kestra-io/kestra/pull/7401))
|
||||
- **core:** ForEachItem inside an If task ([d9d2f8697](https://github.com/kestra-io/kestra/commit/d9d2f8697))
|
||||
- **test:** Attempt at making the test not flakky ([#7400](https://github.com/kestra-io/kestra/pull/7400))
|
||||
- Enable rendering of commands properties inside CommandsWrapper ([#7381](https://github.com/kestra-io/kestra/pull/7381))
|
||||
- Restore red dot when there is news ([fbd893434](https://github.com/kestra-io/kestra/commit/fbd893434))
|
||||
- **tests:** Wider maxDuration for retry-failed-flow-duration.yml ([d55ce16f5](https://github.com/kestra-io/kestra/commit/d55ce16f5))
|
||||
- **ui:** Better duration consistency on Gantt chart ([4a55485cd](https://github.com/kestra-io/kestra/commit/4a55485cd))
|
||||
- **tests:** Logs are asynchronously inserted so we wait for them to be fully in ([13cb0fb96](https://github.com/kestra-io/kestra/commit/13cb0fb96))
|
||||
- **ui:** Improve modifying inputs from no code editor ([#7440](https://github.com/kestra-io/kestra/pull/7440))
|
||||
- **core:** Provide tenantId when looking for subflow ([#7442](https://github.com/kestra-io/kestra/pull/7442))
|
||||
- **core:** Move back to the old worker thread pool because it was restricting it to 1 thread ([372327581](https://github.com/kestra-io/kestra/commit/372327581))
|
||||
- **core:** Remove props with default from `required` in json schema to avoid validation errors ([15b85ac95](https://github.com/kestra-io/kestra/commit/15b85ac95))
|
||||
- **core:** Render `delete` property at the beginning in Docker task runner ([16e3830c9](https://github.com/kestra-io/kestra/commit/16e3830c9))
|
||||
- **tests:** Increase timeout on JdbcServiceLivenessCoordinatorTest.taskResubmitSkipExecution ([cebe8f354](https://github.com/kestra-io/kestra/commit/cebe8f354))
|
||||
- **cicd:** Update concurrency key ([666f8a7ad](https://github.com/kestra-io/kestra/commit/666f8a7ad))
|
||||
- **core:** Http proxy was not passed to configuration ([a53395ab3](https://github.com/kestra-io/kestra/commit/a53395ab3))
|
||||
- **ci:** QEMU issue ([ce15ca1ca](https://github.com/kestra-io/kestra/commit/ce15ca1ca))
|
||||
- **webserver:** Allow special chars in label key ([#7419](https://github.com/kestra-io/kestra/pull/7419))
|
||||
- **ui:** Properly cast value to boolean ([#7455](https://github.com/kestra-io/kestra/pull/7455))
|
||||
- **ui:** Improve handling of main filter labels on page load ([#7456](https://github.com/kestra-io/kestra/pull/7456))
|
||||
- **ui:** Fix the light theme contrast for editor. ([#7438](https://github.com/kestra-io/kestra/pull/7438))
|
||||
- **core:** If subflow is disabled, raise an error ([#7490](https://github.com/kestra-io/kestra/pull/7490))
|
||||
- Render before command with options in CommandsWrapper ([#7496](https://github.com/kestra-io/kestra/pull/7496))
|
||||
- **tasks:** Remove useless format metrics on return ([#7486](https://github.com/kestra-io/kestra/pull/7486))
|
||||
- **core:** Require condition in Flow trigger ([#7494](https://github.com/kestra-io/kestra/pull/7494))
|
||||
- **ui:** Make flow metrics behave as expected ([#7502](https://github.com/kestra-io/kestra/pull/7502))
|
||||
- **ui:** Properly filter out log levels ([#7503](https://github.com/kestra-io/kestra/pull/7503))
|
||||
- **core:** Add package-info.java to dashboard package ([df92491e5](https://github.com/kestra-io/kestra/commit/df92491e5))
|
||||
- **core:** Add package-info.java to script + handle subgroups properly ([ac2643c10](https://github.com/kestra-io/kestra/commit/ac2643c10))
|
||||
- **core:** Try to log message for unhandled realtime trigger exception ([a115eb537](https://github.com/kestra-io/kestra/commit/a115eb537))
|
||||
- **core:** Move package-info.java to proper dashboard packages ([16284e5b9](https://github.com/kestra-io/kestra/commit/16284e5b9))
|
||||
- **core:** Rename dashboards subgroups ([9ec4d9282](https://github.com/kestra-io/kestra/commit/9ec4d9282))
|
||||
- **core:** Typo in PluginScanner ([25723b1ac](https://github.com/kestra-io/kestra/commit/25723b1ac))
|
||||
- **core:** Camel to snake-case for app-blocks in RegisteredPlugin ([c8c0c4e63](https://github.com/kestra-io/kestra/commit/c8c0c4e63))
|
||||
- **core:** Missing content type on http client ([9fce6cfe6](https://github.com/kestra-io/kestra/commit/9fce6cfe6))
|
||||
- **jdbc:** Be resilient to DataException ([cf10269f2](https://github.com/kestra-io/kestra/commit/cf10269f2))
|
||||
- **core:** Content type encoding should not be mandatory ([4500c976d](https://github.com/kestra-io/kestra/commit/4500c976d))
|
||||
- **core:** #172 add reactor into classloader blacklist ([#172](https://github.com/kestra-io/kestra/issues/172))
|
||||
- **ui:** Amend filtering of logs ([#7535](https://github.com/kestra-io/kestra/pull/7535))
|
||||
- **core:** Handle space in HTTP request URI ([a2c89e508](https://github.com/kestra-io/kestra/commit/a2c89e508))
|
||||
- **core:** Subflow using the old task name never ends ([38b8190be](https://github.com/kestra-io/kestra/commit/38b8190be))
|
||||
- **ui:** Amend label filter encoding after values change ([#7536](https://github.com/kestra-io/kestra/pull/7536))
|
||||
- **ui:** Plugins TOC is now handling every type of plugins ([48b117b35](https://github.com/kestra-io/kestra/commit/48b117b35))
|
||||
- **ui:** Styling enhancements for plugin doc ([ff4f7abb0](https://github.com/kestra-io/kestra/commit/ff4f7abb0))
|
||||
- **ui:** Preselect filter comparator option ([#7518](https://github.com/kestra-io/kestra/pull/7518))
|
||||
- **ui:** Improve coloring for task object tooltips in no code editor ([#7515](https://github.com/kestra-io/kestra/pull/7515))
|
||||
- Refactor PluginSearchCommand ([8d2af87db](https://github.com/kestra-io/kestra/commit/8d2af87db))
|
||||
- **ui:** Make flow deletion work as expected ([#7579](https://github.com/kestra-io/kestra/pull/7579))
|
||||
- **ui:** Amend inconsistencies inside the product tour ([#7582](https://github.com/kestra-io/kestra/pull/7582))
|
||||
- **core:** Log can have no executionId ([fc7ef1ca3](https://github.com/kestra-io/kestra/commit/fc7ef1ca3))
|
||||
- **core:** Properly render list properties ([7fbe43322](https://github.com/kestra-io/kestra/commit/7fbe43322))
|
||||
- **ui:** Make sure adding labels on flow run dialog is possible ([#7587](https://github.com/kestra-io/kestra/pull/7587))
|
||||
- **ui:** LabelInput.vue was causing UI freeze ([a996347de](https://github.com/kestra-io/kestra/commit/a996347de))
|
||||
- Ci for translations ([#7602](https://github.com/kestra-io/kestra/pull/7602))
|
||||
- **translations:** Fix translation key detection by comparing against last modifying commit ([#7604](https://github.com/kestra-io/kestra/pull/7604))
|
||||
- Only re-translate if the key is not already in the target dict ([#7608](https://github.com/kestra-io/kestra/pull/7608))
|
||||
- Clean up translations script ([81635ddc8](https://github.com/kestra-io/kestra/commit/81635ddc8))
|
||||
- Improve some wording ([ae75ea06d](https://github.com/kestra-io/kestra/commit/ae75ea06d))
|
||||
- **translations:** Allow retranslating modified keys when needed ([020d674d8](https://github.com/kestra-io/kestra/commit/020d674d8))
|
||||
- Turn CI flag to a dropdown ([d04764814](https://github.com/kestra-io/kestra/commit/d04764814))
|
||||
- Improve translation prompt ([3804bdc7f](https://github.com/kestra-io/kestra/commit/3804bdc7f))
|
||||
- Make sure nocode edits the right task from the topology ([3dc8e98ed](https://github.com/kestra-io/kestra/commit/3dc8e98ed))
|
||||
- **ui:** Replace alert blocks upon markdown rendering to display them properly ([9b4f3148f](https://github.com/kestra-io/kestra/commit/9b4f3148f))
|
||||
- Confusing trace log ([c8207b870](https://github.com/kestra-io/kestra/commit/c8207b870))
|
||||
- **ui:** Executions naviation based on start Date. ([#7626](https://github.com/kestra-io/kestra/pull/7626))
|
||||
- **core:** No longer lowercasing PluginClassIdentifier to have proper validation upon Plugin deserialization ([17e54134c](https://github.com/kestra-io/kestra/commit/17e54134c))
|
||||
- **ui:** Additional check for text label of filters section ([446a034d6](https://github.com/kestra-io/kestra/commit/446a034d6))
|
||||
- **ui:** Improve check for text label of filters section ([036a7cf4f](https://github.com/kestra-io/kestra/commit/036a7cf4f))
|
||||
- **ui:** Use watch with ref instead of accessing the value ([5f21eb579](https://github.com/kestra-io/kestra/commit/5f21eb579))
|
||||
- **ui:** Allow sidebar theme toggle to update the editor theme ([#7648](https://github.com/kestra-io/kestra/pull/7648))
|
||||
- **ci:** Fix vulnerability check workflow ([8bd3c2fef](https://github.com/kestra-io/kestra/commit/8bd3c2fef))
|
||||
- **ui:** Make sure adding labels on flow run dialog is possible ([#7652](https://github.com/kestra-io/kestra/pull/7652))
|
||||
- **cicd:** Missing acls for test reports ([d2bf56fec](https://github.com/kestra-io/kestra/commit/d2bf56fec))
|
||||
- **core:** Validation error when timeWindow.type is null ([1eb9adf30](https://github.com/kestra-io/kestra/commit/1eb9adf30))
|
||||
- **core:** MultipleCondition documentation ([12180457e](https://github.com/kestra-io/kestra/commit/12180457e))
|
||||
- **core:** Avoid duplicates in plugins subgroups + properly retrieve subgroup title ([ef65623b1](https://github.com/kestra-io/kestra/commit/ef65623b1))
|
||||
- **cli:** Fix regression on CLI plugin doc cmd ([e200bbdb6](https://github.com/kestra-io/kestra/commit/e200bbdb6))
|
||||
- **core:** Stop Docker runner gracefully ([8f9fc5fe4](https://github.com/kestra-io/kestra/commit/8f9fc5fe4))
|
||||
- **ui:** Prevent context docs open on editor custom blueprints click ([#7716](https://github.com/kestra-io/kestra/pull/7716))
|
||||
- **runner-memory:** Delete MemorySchedulerTriggerState back due to cherry-pick ([593558dd2](https://github.com/kestra-io/kestra/commit/593558dd2))
|
||||
- **ui:** Improved fetch of type for pluginDoc and avoid removing doc if map has "type" as property but without doc (like ENUM value) ([#7727](https://github.com/kestra-io/kestra/pull/7727))
|
||||
- **demo:** On pages stop showing the docs without a button ([07e4598fa](https://github.com/kestra-io/kestra/commit/07e4598fa))
|
||||
- Repair collapsed menu submenus ([467861652](https://github.com/kestra-io/kestra/commit/467861652))
|
||||
- **flow editor:** Enhance behavior when switching file tabs ([#7722](https://github.com/kestra-io/kestra/pull/7722))
|
||||
- **tests:** Reject promise with 404 instead of empty resolve if non-mocked store call in flowAutoCompletionProvider.spec.ts ([166262209](https://github.com/kestra-io/kestra/commit/166262209))
|
||||
- **jdbc:** Resubmit worker job to the good worker group ([7696d41d5](https://github.com/kestra-io/kestra/commit/7696d41d5))
|
||||
- **ci:** Generate_translations.py is now deleting keys that are no longer in en translation to avoid ghost translations ([440a94290](https://github.com/kestra-io/kestra/commit/440a94290))
|
||||
- **core:** ThresholdFilter is now stricly lower" ([4276a0afd](https://github.com/kestra-io/kestra/commit/4276a0afd))
|
||||
- **core:** Failing schedule test ([#7783](https://github.com/kestra-io/kestra/pull/7783))
|
||||
- **cli:** Fix double shutdown warn messages ([d2d0726f7](https://github.com/kestra-io/kestra/commit/d2d0726f7))
|
||||
- **core:** Flaky test ExitTest.shouldExitAndKillTheExecution() ([0870d8ebd](https://github.com/kestra-io/kestra/commit/0870d8ebd))
|
||||
- **jdbc:** Flaky tests JdbcServiceLivenessCoordinatorTest ([5ffeee532](https://github.com/kestra-io/kestra/commit/5ffeee532))
|
||||
- **core:** Wait for service-manager-task thread to be stopped ([01036c829](https://github.com/kestra-io/kestra/commit/01036c829))
|
||||
- **tests:** Increase seconds diff between dates ([#7785](https://github.com/kestra-io/kestra/pull/7785))
|
||||
- **core:** #7740 http configuration bearer token may change to basic because of allowFailed ([#7788](https://github.com/kestra-io/kestra/pull/7788), [#7740](https://github.com/kestra-io/kestra/issues/7740))
|
||||
- **jdbc:** Return correct total when paginating custom dashboard chart ([#7790](https://github.com/kestra-io/kestra/pull/7790))
|
||||
- **webserver:** Add endpoint for inherited secrets ([9b5b2b981](https://github.com/kestra-io/kestra/commit/9b5b2b981))
|
||||
- **ui:** Make switch view buttons from dashboard editor the same as flow editor ones ([82a346b2c](https://github.com/kestra-io/kestra/commit/82a346b2c))
|
||||
- **ui:** Remove errors from dashboard validation if it's fixed ([4a1282768](https://github.com/kestra-io/kestra/commit/4a1282768))
|
||||
- **core:** Fix properly map MavenPluginRepositoryConfig ([1cb323b7a](https://github.com/kestra-io/kestra/commit/1cb323b7a))
|
||||
- **docs:** 2025 get started video ([977fe222a](https://github.com/kestra-io/kestra/commit/977fe222a))
|
||||
- **core:** AllowedNamespace is already called in the KvStoreService ([e2da2dfeb](https://github.com/kestra-io/kestra/commit/e2da2dfeb))
|
||||
- **core:** Missing afterExecution in FlowForExecution ([141968000](https://github.com/kestra-io/kestra/commit/141968000))
|
||||
- **deps:** Move OTLP metrics lib to CLI to avoid warning in tests ([acebfef0d](https://github.com/kestra-io/kestra/commit/acebfef0d))
|
||||
- **core:** Avoid calling Worker post construct method twice ([c9baaf856](https://github.com/kestra-io/kestra/commit/c9baaf856))
|
||||
- **ui:** Display back core property if not in a task ([64e5b8004](https://github.com/kestra-io/kestra/commit/64e5b8004))
|
||||
- **docs:** Add parallel example ([ff504afd8](https://github.com/kestra-io/kestra/commit/ff504afd8))
|
||||
- Remove labels from an execution ([#7256](https://github.com/kestra-io/kestra/pull/7256))
|
||||
- **docs:** Schedule example ([ebec8c212](https://github.com/kestra-io/kestra/commit/ebec8c212))
|
||||
- **docs:** Fail examples ([379199e18](https://github.com/kestra-io/kestra/commit/379199e18))
|
||||
- **docs:** Typos ([02336ed39](https://github.com/kestra-io/kestra/commit/02336ed39))
|
||||
- **ui:** Use container queries for dashboard ([#7889](https://github.com/kestra-io/kestra/pull/7889))
|
||||
- **core:** Avoid ClassCastException when parsing flow inputs ([#7882](https://github.com/kestra-io/kestra/pull/7882))
|
||||
- **ui:** Amend displaying large amount of logs ([#7923](https://github.com/kestra-io/kestra/pull/7923))
|
||||
- Disable micronaut otel by default ([8076fcc99](https://github.com/kestra-io/kestra/commit/8076fcc99))
|
||||
- **cli:** Return exit 0 in CLI plugins cmd ([3566c4d36](https://github.com/kestra-io/kestra/commit/3566c4d36))
|
||||
- OpenTelemetry should be optional ([0ee9abb37](https://github.com/kestra-io/kestra/commit/0ee9abb37))
|
||||
- ***:** Improve log timestamp precision + allow to override timestamp… ([#7847](https://github.com/kestra-io/kestra/pull/7847))
|
||||
- **ui:** Amend dependabot errors with parsing of package-lock.json file ([#7941](https://github.com/kestra-io/kestra/pull/7941))
|
||||
- **core:** Possible NPE if no manifest ([8cba4dab6](https://github.com/kestra-io/kestra/commit/8cba4dab6))
|
||||
- **ui:** Prevent filter text prefix to show up when searching locally ([#7947](https://github.com/kestra-io/kestra/pull/7947))
|
||||
- **core:** Triggers don't have an execution ID already ([0579e23a2](https://github.com/kestra-io/kestra/commit/0579e23a2))
|
||||
- **core-ee:** NPE when execution labels are null ([#7950](https://github.com/kestra-io/kestra/pull/7950))
|
||||
- Only run posthog in prod mode ([#7952](https://github.com/kestra-io/kestra/pull/7952))
|
||||
- **core:** Add metric Publish task doc & icon ([481138e43](https://github.com/kestra-io/kestra/commit/481138e43))
|
||||
- Update ui-libs ([cca7ed0bf](https://github.com/kestra-io/kestra/commit/cca7ed0bf))
|
||||
- **ui:** Filter tests were not up-to-date ([f3419084f](https://github.com/kestra-io/kestra/commit/f3419084f))
|
||||
- **cicd:** Display ui unit test status ([df1bbcfb7](https://github.com/kestra-io/kestra/commit/df1bbcfb7))
|
||||
- **ui:** Change plugin doc properly upon switching plugin type ([773a6e909](https://github.com/kestra-io/kestra/commit/773a6e909))
|
||||
- **core:** Working dir interface contract by putting back putFile(path, content) ([#7980](https://github.com/kestra-io/kestra/pull/7980))
|
||||
- **ui:** Include parameters into request for plugin schema fetching ([#8002](https://github.com/kestra-io/kestra/pull/8002))
|
||||
- **core:** Amend server start announcements ([49a29c4bf](https://github.com/kestra-io/kestra/commit/49a29c4bf))
|
||||
- **build:** Gradle space-assignment deprecation ([a1abd28a3](https://github.com/kestra-io/kestra/commit/a1abd28a3))
|
||||
- **core:** Race in the FlowListener ([19894dbcd](https://github.com/kestra-io/kestra/commit/19894dbcd))
|
||||
- **core:** Race while initializing trigger + possible duplicate update ([742169344](https://github.com/kestra-io/kestra/commit/742169344))
|
||||
- Remove unwanted change in Curl ([3244b1c29](https://github.com/kestra-io/kestra/commit/3244b1c29))
|
||||
- **ui:** Amend task source tabs colors ([#8010](https://github.com/kestra-io/kestra/pull/8010))
|
||||
- **platform:** Move slf4j api to enforce platform to fix it's version in test ([#8007](https://github.com/kestra-io/kestra/pull/8007))
|
||||
- **core:** Handling for trailing slash in the KESTRA_URL configuration ([#6373](https://github.com/kestra-io/kestra/pull/6373))
|
||||
- **ui:** Prevent function parameters autocompletion from deleting parenthesis ([74455ad99](https://github.com/kestra-io/kestra/commit/74455ad99))
|
||||
- **ui:** Handle properly layout of global Secrets when there is a secret manager ([edbf14c1b](https://github.com/kestra-io/kestra/commit/edbf14c1b))
|
||||
- **core:** Ensure defaults can be injected in flows ([#3206](https://github.com/kestra-io/kestra/pull/3206))
|
||||
- **ui:** Allow multi label filtering ([#8022](https://github.com/kestra-io/kestra/pull/8022))
|
||||
- **ui:** Fail-safe secrets API calls ([c64c2c710](https://github.com/kestra-io/kestra/commit/c64c2c710))
|
||||
- **ui:** Amend operator value of labels inside the filter ([#8028](https://github.com/kestra-io/kestra/pull/8028))
|
||||
- **ui:** Fail-safe secrets API calls on global secrets view ([28d1f005a](https://github.com/kestra-io/kestra/commit/28d1f005a))
|
||||
- **core:** Fix NPE when closing standalone runner ([6c9dc8fba](https://github.com/kestra-io/kestra/commit/6c9dc8fba))
|
||||
- **ui:** Make sure global secret view iterates over all secrets ([75e763550](https://github.com/kestra-io/kestra/commit/75e763550))
|
||||
- **cli:** Make worker args available through static KestraContext ([dea66ca25](https://github.com/kestra-io/kestra/commit/dea66ca25))
|
||||
- **core:** Flatten map should not throw an exception ([4c93a2b0e](https://github.com/kestra-io/kestra/commit/4c93a2b0e))
|
||||
- **webserver:** First eval without masking secret function to error in case of missing secret ([8f4ce5fc1](https://github.com/kestra-io/kestra/commit/8f4ce5fc1))
|
||||
- **ui:** Properly detect yaml to inject json schema into MonacoEditor ([8be17827c](https://github.com/kestra-io/kestra/commit/8be17827c))
|
||||
- **core:** HttpClient log the URL even if it's a secret ([54aa93570](https://github.com/kestra-io/kestra/commit/54aa93570))
|
||||
- **core:** Properly fix the issue with MapUtils.flattenToNestedMap ([b8e8333f6](https://github.com/kestra-io/kestra/commit/b8e8333f6))
|
||||
- **kafka runner:** #2709 filter child forEach tasks before merging th… ([#8095](https://github.com/kestra-io/kestra/pull/8095), [#2709](https://github.com/kestra-io/kestra/issues/2709))
|
||||
- **core:** Avoid flow validation error on plugin alias duplicates ([8ebc3fbba](https://github.com/kestra-io/kestra/commit/8ebc3fbba))
|
||||
- Doc and deprecated field was not showing for dynamic non-string properties ([#8006](https://github.com/kestra-io/kestra/pull/8006))
|
||||
- **core:** Require condition in Flow trigger " ([#7494](https://github.com/kestra-io/kestra/pull/7494))
|
||||
- **core:** Compilation issue ([380e329e9](https://github.com/kestra-io/kestra/commit/380e329e9))
|
||||
- **core:** Namespace service now properly detects namespaces with flows inside ([a09319800](https://github.com/kestra-io/kestra/commit/a09319800))
|
||||
- **webserver:** Handle out-of-bounds (>) namespaces fetch ([224026c39](https://github.com/kestra-io/kestra/commit/224026c39))
|
||||
- **ui:** Add routeContext where it was missing ([143ebc061](https://github.com/kestra-io/kestra/commit/143ebc061))
|
||||
- **ui:** Repair tenant translation ([b3799cc03](https://github.com/kestra-io/kestra/commit/b3799cc03))
|
||||
- **ui:** Global secret page design ([54eccac63](https://github.com/kestra-io/kestra/commit/54eccac63))
|
||||
- **ui:** Search bars are properly working in secrets & KV pages ([4e7c6e87b](https://github.com/kestra-io/kestra/commit/4e7c6e87b))
|
||||
- **core:** Allow dash in plugin version qualifier ([95b1f8dfc](https://github.com/kestra-io/kestra/commit/95b1f8dfc))
|
||||
- **cli:** Properly register plugins uninstall cmd ([91bf3207f](https://github.com/kestra-io/kestra/commit/91bf3207f))
|
||||
- **core:** Add missing docker plugin subgroup icon ([1613dee76](https://github.com/kestra-io/kestra/commit/1613dee76))
|
||||
- Task array needed better typings ([#8158](https://github.com/kestra-io/kestra/pull/8158))
|
||||
- Make flowWarnings show to unlock saving ([#8157](https://github.com/kestra-io/kestra/pull/8157))
|
||||
|
||||
### 💅 Refactors
|
||||
|
||||
- Introduce render in commands wrapper for property string ([#7430](https://github.com/kestra-io/kestra/pull/7430))
|
||||
- Avoid en.json warning when building ([df6d33931](https://github.com/kestra-io/kestra/commit/df6d33931))
|
||||
- Remove rendering from Docker ([#7439](https://github.com/kestra-io/kestra/pull/7439))
|
||||
- Return only command when no interpreter and no beforeCommands ([#7452](https://github.com/kestra-io/kestra/pull/7452))
|
||||
- **ui:** Remove obsolete `chartjs-chart-treemap` library ([#7529](https://github.com/kestra-io/kestra/pull/7529))
|
||||
- Update http client and fix tests ([be04c168f](https://github.com/kestra-io/kestra/commit/be04c168f))
|
||||
- **ui:** Remove the obsolete console statement ([#7887](https://github.com/kestra-io/kestra/pull/7887))
|
||||
- Move flow editor logic into flow store ([#7968](https://github.com/kestra-io/kestra/pull/7968))
|
||||
|
||||
### 📖 Documentation
|
||||
|
||||
- **core:** Better documentation on docker tasks ([f4b78755a](https://github.com/kestra-io/kestra/commit/f4b78755a))
|
||||
- Debug expression ([#7514](https://github.com/kestra-io/kestra/pull/7514))
|
||||
- Fix typo in storage reverse task title ([#7667](https://github.com/kestra-io/kestra/pull/7667))
|
||||
- Kv pebble ([#7886](https://github.com/kestra-io/kestra/pull/7886))
|
||||
|
||||
### 📦 Build
|
||||
|
||||
- Try and fix FE CI ([4234c76b0](https://github.com/kestra-io/kestra/commit/4234c76b0))
|
||||
- Prevent corepack crash ([3c7e26c88](https://github.com/kestra-io/kestra/commit/3c7e26c88))
|
||||
- **deps:** Bump software.amazon.awssdk:bom from 2.30.6 to 2.30.11 ([d50f631fb](https://github.com/kestra-io/kestra/commit/d50f631fb))
|
||||
- **deps:** Bump com.azure:azure-sdk-bom from 1.2.30 to 1.2.31 ([bd0e4a5f4](https://github.com/kestra-io/kestra/commit/bd0e4a5f4))
|
||||
- **deps:** Bump software.amazon.awssdk.crt:aws-crt ([f1f0d3186](https://github.com/kestra-io/kestra/commit/f1f0d3186))
|
||||
- **deps:** Bump flyingSaucerVersion from 9.11.2 to 9.11.3 ([d769b7aad](https://github.com/kestra-io/kestra/commit/d769b7aad))
|
||||
- **deps:** Bump com.gradleup.shadow from 8.3.5 to 8.3.6 ([3a0beabe4](https://github.com/kestra-io/kestra/commit/3a0beabe4))
|
||||
- **deps:** Bump org.owasp.dependencycheck from 12.0.1 to 12.0.2 ([36306495e](https://github.com/kestra-io/kestra/commit/36306495e))
|
||||
- **deps:** Bump posthog-js from 1.215.2 to 1.215.3 in /ui ([#7182](https://github.com/kestra-io/kestra/pull/7182))
|
||||
- **deps:** Bump shiki from 2.3.0 to 2.3.1 in /ui ([#7183](https://github.com/kestra-io/kestra/pull/7183))
|
||||
- **deps-dev:** Bump @shikijs/markdown-it from 2.3.0 to 2.3.1 in /ui ([#7184](https://github.com/kestra-io/kestra/pull/7184))
|
||||
- **deps:** Bump com.google.cloud:libraries-bom from 26.53.0 to 26.54.0 ([5aa73ec48](https://github.com/kestra-io/kestra/commit/5aa73ec48))
|
||||
- **deps:** Bump software.amazon.awssdk:bom from 2.30.11 to 2.30.16 ([8a3f41323](https://github.com/kestra-io/kestra/commit/8a3f41323))
|
||||
- **deps:** Bump software.amazon.awssdk.crt:aws-crt ([55bdfac7f](https://github.com/kestra-io/kestra/commit/55bdfac7f))
|
||||
- **deps:** Bump com.microsoft.playwright:playwright ([48320a89d](https://github.com/kestra-io/kestra/commit/48320a89d))
|
||||
- **deps:** Bump io.pebbletemplates:pebble from 3.2.2 to 3.2.3 ([8260dc603](https://github.com/kestra-io/kestra/commit/8260dc603))
|
||||
- **deps:** Bump io.micronaut.platform:micronaut-platform ([4c5638d95](https://github.com/kestra-io/kestra/commit/4c5638d95))
|
||||
- **deps:** Bump org.opensearch.client:opensearch-java ([90da5f7cf](https://github.com/kestra-io/kestra/commit/90da5f7cf))
|
||||
- **deps:** Bump io.micronaut.platform:micronaut-platform ([f3cff1b8c](https://github.com/kestra-io/kestra/commit/f3cff1b8c))
|
||||
- **deps:** Bump com.github.oshi:oshi-core from 6.6.6 to 6.7.0 ([66fdb58f4](https://github.com/kestra-io/kestra/commit/66fdb58f4))
|
||||
- **deps:** Bump nl.basjes.gitignore:gitignore-reader ([4b48ad597](https://github.com/kestra-io/kestra/commit/4b48ad597))
|
||||
- **deps:** Bump org.owasp.dependencycheck from 12.0.2 to 12.1.0 ([94421f141](https://github.com/kestra-io/kestra/commit/94421f141))
|
||||
- **deps:** Bump software.amazon.awssdk:bom from 2.30.16 to 2.30.31 ([e7f2ec2ae](https://github.com/kestra-io/kestra/commit/e7f2ec2ae))
|
||||
- **deps:** Bump opensearchRestVersion from 2.18.0 to 2.19.1 ([b6f91128a](https://github.com/kestra-io/kestra/commit/b6f91128a))
|
||||
- **deps:** Bump com.google.cloud:libraries-bom from 26.54.0 to 26.56.0 ([82df58d26](https://github.com/kestra-io/kestra/commit/82df58d26))
|
||||
- **deps:** Bump org.opensearch.client:opensearch-java ([ca4e6a4b3](https://github.com/kestra-io/kestra/commit/ca4e6a4b3))
|
||||
- **deps:** Bump jacksonVersion from 2.18.2 to 2.18.3 ([20b87f1c9](https://github.com/kestra-io/kestra/commit/20b87f1c9))
|
||||
- **deps:** Bump robinraju/release-downloader from 1.11 to 1.12 ([038890982](https://github.com/kestra-io/kestra/commit/038890982))
|
||||
- **deps:** Bump com.azure:azure-sdk-bom from 1.2.31 to 1.2.32 ([92418841f](https://github.com/kestra-io/kestra/commit/92418841f))
|
||||
- **deps:** Bump com.gorylenko.gradle-git-properties ([0a304ff1d](https://github.com/kestra-io/kestra/commit/0a304ff1d))
|
||||
- **deps:** Bump org.testcontainers:junit-jupiter from 1.20.5 to 1.20.6 ([5af085844](https://github.com/kestra-io/kestra/commit/5af085844))
|
||||
- **deps:** Bump org.opensearch.client:opensearch-java ([03a44c103](https://github.com/kestra-io/kestra/commit/03a44c103))
|
||||
- **deps:** Bump com.github.docker-java:docker-java from 3.4.1 to 3.4.2 ([8d7bc6fdd](https://github.com/kestra-io/kestra/commit/8d7bc6fdd))
|
||||
- **deps:** Bump org.jsoup:jsoup from 1.18.3 to 1.19.1 ([83f06f337](https://github.com/kestra-io/kestra/commit/83f06f337))
|
||||
- **deps:** Bump software.amazon.awssdk.crt:aws-crt ([5935308e4](https://github.com/kestra-io/kestra/commit/5935308e4))
|
||||
- **deps:** Bump org.testcontainers:testcontainers ([fefaa7cdb](https://github.com/kestra-io/kestra/commit/fefaa7cdb))
|
||||
- **deps:** Bump software.amazon.awssdk:bom from 2.30.31 to 2.30.36 ([66e5a7ca3](https://github.com/kestra-io/kestra/commit/66e5a7ca3))
|
||||
- **deps:** Bump io.micrometer:micrometer-core from 1.14.3 to 1.14.5 ([dea392a94](https://github.com/kestra-io/kestra/commit/dea392a94))
|
||||
- **deps:** Bump @babel/helpers from 7.26.9 to 7.26.10 in /ui ([#7841](https://github.com/kestra-io/kestra/pull/7841))
|
||||
- **deps:** Bump @babel/runtime-corejs3 from 7.26.9 to 7.26.10 in /ui ([#7840](https://github.com/kestra-io/kestra/pull/7840))
|
||||
- **deps:** Bump software.amazon.awssdk:bom from 2.30.36 to 2.31.1 ([149dcac5f](https://github.com/kestra-io/kestra/commit/149dcac5f))
|
||||
- **deps:** Bump protobufVersion from 3.25.5 to 4.30.1 ([6946c9268](https://github.com/kestra-io/kestra/commit/6946c9268))
|
||||
- **deps:** Bump software.amazon.awssdk.crt:aws-crt ([0134d5e5c](https://github.com/kestra-io/kestra/commit/0134d5e5c))
|
||||
- **deps:** Bump com.github.oshi:oshi-core from 6.7.0 to 6.7.1 ([8eb91b75e](https://github.com/kestra-io/kestra/commit/8eb91b75e))
|
||||
- **deps:** Bump dorny/test-reporter from 1 to 2 ([ab061e9a1](https://github.com/kestra-io/kestra/commit/ab061e9a1))
|
||||
- **deps:** Bump aquasecurity/trivy-action from 0.29.0 to 0.30.0 ([7f6e15ec4](https://github.com/kestra-io/kestra/commit/7f6e15ec4))
|
||||
- **deps:** Bump nl.basjes.gitignore:gitignore-reader ([3dcd3c978](https://github.com/kestra-io/kestra/commit/3dcd3c978))
|
||||
- **deps:** Bump org.jooq:jooq from 3.19.18 to 3.20.2 ([ab9ba91e5](https://github.com/kestra-io/kestra/commit/ab9ba91e5))
|
||||
- **deps:** Bump org.slf4j:slf4j-api from 2.0.16 to 2.0.17 ([f89aa8d27](https://github.com/kestra-io/kestra/commit/f89aa8d27))
|
||||
- **deps:** Bump org.aspectj:aspectjweaver from 1.9.22.1 to 1.9.23 ([5c73953c8](https://github.com/kestra-io/kestra/commit/5c73953c8))
|
||||
- **deps:** Bump pdfjs-dist from 4.10.38 to 5.0.375 in /ui ([#7942](https://github.com/kestra-io/kestra/pull/7942))
|
||||
- **deps:** Bump protobufVersion from 3.25.5 to 4.30.1" ([0ec2d8842](https://github.com/kestra-io/kestra/commit/0ec2d8842))
|
||||
- **deps:** Bump com.microsoft.playwright:playwright ([6d59630a6](https://github.com/kestra-io/kestra/commit/6d59630a6))
|
||||
- **deps:** Bump com.google.cloud:libraries-bom from 26.56.0 to 26.57.0 ([491f07296](https://github.com/kestra-io/kestra/commit/491f07296))
|
||||
- **deps:** Bump com.github.oshi:oshi-core from 6.7.1 to 6.8.0 ([37af61f41](https://github.com/kestra-io/kestra/commit/37af61f41))
|
||||
- **deps:** Bump software.amazon.awssdk:bom from 2.31.1 to 2.31.6 ([62e37f3b1](https://github.com/kestra-io/kestra/commit/62e37f3b1))
|
||||
- **deps:** Bump software.amazon.awssdk.crt:aws-crt ([5a2ac895e](https://github.com/kestra-io/kestra/commit/5a2ac895e))
|
||||
|
||||
### 🏡 Chore
|
||||
|
||||
- **ci:** Update release workflows ([0b82b25a4](https://github.com/kestra-io/kestra/commit/0b82b25a4))
|
||||
- Update "cluster" into "instance" in side menu ([#6996](https://github.com/kestra-io/kestra/pull/6996))
|
||||
- **ui:** Move apps link in left menu just below the flows ([#7063](https://github.com/kestra-io/kestra/pull/7063))
|
||||
- **ui:** Properly check the existence of fields inside schema ([cd822bd34](https://github.com/kestra-io/kestra/commit/cd822bd34))
|
||||
- Update palette ([7a37a950b](https://github.com/kestra-io/kestra/commit/7a37a950b))
|
||||
- **translations:** Auto generate values for languages other than english ([dee76c038](https://github.com/kestra-io/kestra/commit/dee76c038))
|
||||
- **core:** Fix various compilation warnings ([625135959](https://github.com/kestra-io/kestra/commit/625135959))
|
||||
- Add a test for firefox weird wrap ([97d12f9bc](https://github.com/kestra-io/kestra/commit/97d12f9bc))
|
||||
- **ui:** Properly pass a prop related to saved searches ([594d00516](https://github.com/kestra-io/kestra/commit/594d00516))
|
||||
- **core:** Small perf improvements to MapUtils ([5a4620439](https://github.com/kestra-io/kestra/commit/5a4620439))
|
||||
- **ui:** Show each plugin deprecation warning in new line ([#6839](https://github.com/kestra-io/kestra/pull/6839))
|
||||
- **translations:** Auto generate values for languages other than english ([52159ee64](https://github.com/kestra-io/kestra/commit/52159ee64))
|
||||
- **ui:** Amend color of the input length counter ([#6990](https://github.com/kestra-io/kestra/pull/6990))
|
||||
- **ui:** Enable command palette for monaco editor ([#6944](https://github.com/kestra-io/kestra/pull/6944))
|
||||
- **translations:** Auto generate values for languages other than english ([fff8d630c](https://github.com/kestra-io/kestra/commit/fff8d630c))
|
||||
- **translations:** Auto generate values for languages other than english ([6ba71712a](https://github.com/kestra-io/kestra/commit/6ba71712a))
|
||||
- **ui:** Add skeleton loaders to dashboard cards ([#6602](https://github.com/kestra-io/kestra/pull/6602))
|
||||
- Add utility script to check for plugin artifacts ([42ad09d79](https://github.com/kestra-io/kestra/commit/42ad09d79))
|
||||
- **translations:** Auto generate values for languages other than english ([a9042fb27](https://github.com/kestra-io/kestra/commit/a9042fb27))
|
||||
- **ui:** Improve the example for not condition ([#6820](https://github.com/kestra-io/kestra/pull/6820))
|
||||
- **ui:** Update the visual of no data component ([#7179](https://github.com/kestra-io/kestra/pull/7179))
|
||||
- **ui:** Improve the states options list inside filter values ([#7176](https://github.com/kestra-io/kestra/pull/7176))
|
||||
- **translations:** Auto generate values for languages other than english ([86f3acace](https://github.com/kestra-io/kestra/commit/86f3acace))
|
||||
- **ui:** Rename advanced properties to other in no code ([#7189](https://github.com/kestra-io/kestra/pull/7189))
|
||||
- **translations:** Auto generate values for languages other than english ([e4973c331](https://github.com/kestra-io/kestra/commit/e4973c331))
|
||||
- **ui:** Rename advanced properties to other in no code ([#7190](https://github.com/kestra-io/kestra/pull/7190))
|
||||
- **translations:** Auto generate values for languages other than english ([cb7ed73be](https://github.com/kestra-io/kestra/commit/cb7ed73be))
|
||||
- **ui:** Remove the option to change editor theme separately ([#7192](https://github.com/kestra-io/kestra/pull/7192))
|
||||
- **translations:** Remove extra keys from translation files ([#7193](https://github.com/kestra-io/kestra/pull/7193))
|
||||
- **ui:** Consolidate markdown files ([#7197](https://github.com/kestra-io/kestra/pull/7197))
|
||||
- **ui:** Replace the visual for no tabs opened on namespace editor ([#7204](https://github.com/kestra-io/kestra/pull/7204))
|
||||
- **ui:** Re-order the list of optional columns ([#7213](https://github.com/kestra-io/kestra/pull/7213))
|
||||
- **ui:** Amended global pagination coloring ([#7201](https://github.com/kestra-io/kestra/pull/7201))
|
||||
- **ui:** Generate random flow ID using combination of animal names and numbers ([#7223](https://github.com/kestra-io/kestra/pull/7223))
|
||||
- **ui:** Only show warning on bulk execution deletion if nonTerminated is true ([#7211](https://github.com/kestra-io/kestra/pull/7211))
|
||||
- **ui:** Show executions per namespace only if there are 2 or more items for chart ([#7216](https://github.com/kestra-io/kestra/pull/7216))
|
||||
- **translations:** Auto generate values for languages other than english ([440faa7cd](https://github.com/kestra-io/kestra/commit/440faa7cd))
|
||||
- **ui:** Initial work on filter persistency ([#7234](https://github.com/kestra-io/kestra/pull/7234))
|
||||
- **ui:** Check for missing property on update metadata ([e335b76b3](https://github.com/kestra-io/kestra/commit/e335b76b3))
|
||||
- Update theme colors ([c31609a12](https://github.com/kestra-io/kestra/commit/c31609a12))
|
||||
- **ui:** Align chart duration label with switch toggle ([#7259](https://github.com/kestra-io/kestra/pull/7259))
|
||||
- **ui:** Align chart duration label with switch toggle ([#7258](https://github.com/kestra-io/kestra/pull/7258))
|
||||
- **ui:** Tweak the video container ratio in the docs sidebar ([#7260](https://github.com/kestra-io/kestra/pull/7260))
|
||||
- **translations:** Auto generate values for languages other than english ([e0f4ab735](https://github.com/kestra-io/kestra/commit/e0f4ab735))
|
||||
- **ui:** Disable saving flow actions if there are errors ([#7278](https://github.com/kestra-io/kestra/pull/7278))
|
||||
- **ui:** Improve flow description coloring ([#7282](https://github.com/kestra-io/kestra/pull/7282))
|
||||
- **ui:** Make action columns always visible on executions and flows ([#7291](https://github.com/kestra-io/kestra/pull/7291))
|
||||
- **core:** Rename fileEmpty Pebble function to isFileEmpty ([8de839f32](https://github.com/kestra-io/kestra/commit/8de839f32))
|
||||
- **core:** Refactor file related Pebble function to share code ([f599f2575](https://github.com/kestra-io/kestra/commit/f599f2575))
|
||||
- Remove some compilation warnings ([9505c48e5](https://github.com/kestra-io/kestra/commit/9505c48e5))
|
||||
- **ui:** Improve styling of main filter tags ([#7305](https://github.com/kestra-io/kestra/pull/7305))
|
||||
- **ui:** Introduce filters bar to flow triggers page ([#7292](https://github.com/kestra-io/kestra/pull/7292))
|
||||
- **ui:** Improve the doughnut chart legend ([#7321](https://github.com/kestra-io/kestra/pull/7321))
|
||||
- **translations:** Amend theme key ([#7356](https://github.com/kestra-io/kestra/pull/7356))
|
||||
- **ui:** Add shadows to main charts ([#7314](https://github.com/kestra-io/kestra/pull/7314))
|
||||
- **ui:** Add validation messages for custom dashboard crud actions ([#7367](https://github.com/kestra-io/kestra/pull/7367))
|
||||
- **ui:** Add link to filtered triggers page from backfill dialog ([#7380](https://github.com/kestra-io/kestra/pull/7380))
|
||||
- **ui:** Include autocompletion shortcut in the preview list ([#7384](https://github.com/kestra-io/kestra/pull/7384))
|
||||
- **ui:** Improve breadcrumbs on namespace view ([#7386](https://github.com/kestra-io/kestra/pull/7386))
|
||||
- **ui:** Improve the labels behavior ([#7397](https://github.com/kestra-io/kestra/pull/7397))
|
||||
- **ui:** Improve colors of filter dropdown selector ([#7403](https://github.com/kestra-io/kestra/pull/7403))
|
||||
- **ui:** Vertically center all elements in table rows ([#7372](https://github.com/kestra-io/kestra/pull/7372))
|
||||
- **ui:** Make import flows button be a secondary one, styling-wise ([#7405](https://github.com/kestra-io/kestra/pull/7405))
|
||||
- **ui:** Improve execution outputs section ([#7377](https://github.com/kestra-io/kestra/pull/7377))
|
||||
- **ui:** Improve filter parameters decoding for absolute date ([#7409](https://github.com/kestra-io/kestra/pull/7409))
|
||||
- **ui:** Improved Logs empty page ([#7415](https://github.com/kestra-io/kestra/pull/7415))
|
||||
- **ui:** Amend namespace flow creation label ([#7443](https://github.com/kestra-io/kestra/pull/7443))
|
||||
- **ui:** Add missing translations ([#7444](https://github.com/kestra-io/kestra/pull/7444))
|
||||
- **ui:** Add arrows to namespace listing ([#7448](https://github.com/kestra-io/kestra/pull/7448))
|
||||
- **ui:** Disable click on search button if filtering is automatic ([#7454](https://github.com/kestra-io/kestra/pull/7454))
|
||||
- **ui:** Remove obsolete props ([#7487](https://github.com/kestra-io/kestra/pull/7487))
|
||||
- **ui:** Improve styling of editor file tree ([#7420](https://github.com/kestra-io/kestra/pull/7420))
|
||||
- **translations:** Add missing key/value pairs ([#7492](https://github.com/kestra-io/kestra/pull/7492))
|
||||
- **ui:** Amend margins of EE locked pages ([#7446](https://github.com/kestra-io/kestra/pull/7446))
|
||||
- **ui:** Simplify query search with spaces inside ([#7404](https://github.com/kestra-io/kestra/pull/7404))
|
||||
- **ui:** Improve scope type filters ([#7504](https://github.com/kestra-io/kestra/pull/7504))
|
||||
- **ui:** Add translation key/value pairs ([#7509](https://github.com/kestra-io/kestra/pull/7509))
|
||||
- **ui:** Improve the scope of translations ([#7505](https://github.com/kestra-io/kestra/pull/7505))
|
||||
- **ui:** Restore automatic scroll to bottom on logs ([#7365](https://github.com/kestra-io/kestra/pull/7365))
|
||||
- **ui:** Prevent sending random strings as child filter values ([#7526](https://github.com/kestra-io/kestra/pull/7526))
|
||||
- **ui:** Purge empty labels on execution ([#7527](https://github.com/kestra-io/kestra/pull/7527))
|
||||
- **ui:** Use system namespace label from configs ([cf635058c](https://github.com/kestra-io/kestra/commit/cf635058c))
|
||||
- **ui:** Prevent system labels to be shown in set labels dialog ([#7539](https://github.com/kestra-io/kestra/pull/7539))
|
||||
- **core:** Move run context property validation to the run context ([8a26fdd83](https://github.com/kestra-io/kestra/commit/8a26fdd83))
|
||||
- Add wiremock and update tests ([04c4916ac](https://github.com/kestra-io/kestra/commit/04c4916ac))
|
||||
- **ui:** Respect default execution tab settings field when opening single execution ([#7576](https://github.com/kestra-io/kestra/pull/7576))
|
||||
- **ui:** Remove background and check mark from selected filters dropdown list ([#7583](https://github.com/kestra-io/kestra/pull/7583))
|
||||
- Introduce Devcontainer setup ([#7507](https://github.com/kestra-io/kestra/pull/7507))
|
||||
- **translations:** Standalone action for translations ([#7597](https://github.com/kestra-io/kestra/pull/7597))
|
||||
- **translations:** Localize to languages other than English ([#7605](https://github.com/kestra-io/kestra/pull/7605))
|
||||
- **translations:** Localize to languages other than English " ([#7605](https://github.com/kestra-io/kestra/pull/7605), [#7609](https://github.com/kestra-io/kestra/pull/7609))
|
||||
- **translations:** Localize to languages other than English ([#7610](https://github.com/kestra-io/kestra/pull/7610))
|
||||
- **translations:** Localize to languages other than English ([#7613](https://github.com/kestra-io/kestra/pull/7613))
|
||||
- **translations:** Localize to languages other than English ([#7618](https://github.com/kestra-io/kestra/pull/7618))
|
||||
- **ui:** Improve label for text search in filters section ([#7631](https://github.com/kestra-io/kestra/pull/7631))
|
||||
- **translations:** Localize to languages other than English ([#7633](https://github.com/kestra-io/kestra/pull/7633))
|
||||
- **ui:** Remove crud details from execution overview ([#7634](https://github.com/kestra-io/kestra/pull/7634))
|
||||
- **ui:** Improve empty state of the namespace files editor ([#7495](https://github.com/kestra-io/kestra/pull/7495))
|
||||
- **translations:** Localize to languages other than English ([#7635](https://github.com/kestra-io/kestra/pull/7635))
|
||||
- **core:** Eval value property once for flowable task Switch ([bfd82e0b5](https://github.com/kestra-io/kestra/commit/bfd82e0b5))
|
||||
- **ui:** Improve the topology tooltip label for adding task button ([#7656](https://github.com/kestra-io/kestra/pull/7656))
|
||||
- **ui:** Properly sanitize markdown content before rendering ([#7662](https://github.com/kestra-io/kestra/pull/7662))
|
||||
- **ui:** Make sure chart stacks are following the same order every time ([#7664](https://github.com/kestra-io/kestra/pull/7664))
|
||||
- **ui:** Properly sanitize markdown content before rendering ([#7697](https://github.com/kestra-io/kestra/pull/7697))
|
||||
- **ui:** Auto expand first element in execution overview cascaders ([#7715](https://github.com/kestra-io/kestra/pull/7715))
|
||||
- **core:** Make registry unregister usable with immutable list ([9a56b763f](https://github.com/kestra-io/kestra/commit/9a56b763f))
|
||||
- **ui:** Properly sanitize markdown content before rendering ([#7724](https://github.com/kestra-io/kestra/pull/7724))
|
||||
- **ui:** Uniforming empty state for components ([#7737](https://github.com/kestra-io/kestra/pull/7737))
|
||||
- **translations:** Localize to languages other than English ([#7739](https://github.com/kestra-io/kestra/pull/7739))
|
||||
- **ui:** Use uniformed pagination component for custom dashboard tables ([#7744](https://github.com/kestra-io/kestra/pull/7744))
|
||||
- **translations:** Localize to languages other than English ([#7746](https://github.com/kestra-io/kestra/pull/7746))
|
||||
- **ui:** Remove single empty space between label key and value so it can be copied ([#7774](https://github.com/kestra-io/kestra/pull/7774))
|
||||
- **ui:** Re-order namespace tabs ([#7778](https://github.com/kestra-io/kestra/pull/7778))
|
||||
- **translations:** Localize to languages other than English ([#7780](https://github.com/kestra-io/kestra/pull/7780))
|
||||
- **ui:** Respect line numbers prop as part of editor options ([#7781](https://github.com/kestra-io/kestra/pull/7781))
|
||||
- **core:** Disable OTLP metrics on tests ([c60676052](https://github.com/kestra-io/kestra/commit/c60676052))
|
||||
- Update ui-libs ([14ff4438f](https://github.com/kestra-io/kestra/commit/14ff4438f))
|
||||
- **ui:** Add the ability to change word wrap and to copy the preview output content ([#7801](https://github.com/kestra-io/kestra/pull/7801))
|
||||
- **translations:** Localize to languages other than English ([#7803](https://github.com/kestra-io/kestra/pull/7803))
|
||||
- **translations:** Localize to languages other than English ([#7863](https://github.com/kestra-io/kestra/pull/7863))
|
||||
- **ui:** Re-organize visuals for empty state component ([#7866](https://github.com/kestra-io/kestra/pull/7866))
|
||||
- **ui:** Prevent node state history to be shown if there is no date present ([#7867](https://github.com/kestra-io/kestra/pull/7867))
|
||||
- **core:** Add PluginVersioning interface and version for TaskRunner ([bed11f154](https://github.com/kestra-io/kestra/commit/bed11f154))
|
||||
- **ui:** Re-organize visuals for empty state component ([#7875](https://github.com/kestra-io/kestra/pull/7875))
|
||||
- **ui:** Complete refactor of yaml utils ([#7888](https://github.com/kestra-io/kestra/pull/7888))
|
||||
- **ui:** Create flow button on welcome page to start product tour ([#7906](https://github.com/kestra-io/kestra/pull/7906))
|
||||
- **translations:** Localize to languages other than English ([#7908](https://github.com/kestra-io/kestra/pull/7908))
|
||||
- **ui:** Show loading skeletons on dashboard ([#7417](https://github.com/kestra-io/kestra/pull/7417))
|
||||
- **ui:** Use the correct shadow on charts ([#7752](https://github.com/kestra-io/kestra/pull/7752))
|
||||
- **ui:** Change display on gantt page for created & queued executions ([#7706](https://github.com/kestra-io/kestra/pull/7706))
|
||||
- **ui:** Improve charts horizontal scrollbar ([#7508](https://github.com/kestra-io/kestra/pull/7508))
|
||||
- **translations:** Localize to languages other than English ([#7909](https://github.com/kestra-io/kestra/pull/7909))
|
||||
- **core:** Merge outputs only when necessary ([355e24c9d](https://github.com/kestra-io/kestra/commit/355e24c9d))
|
||||
- **ui:** Properly sanitize execution errors markdown content before rendering ([#7914](https://github.com/kestra-io/kestra/pull/7914))
|
||||
- **translations:** Localize to languages other than English ([#7915](https://github.com/kestra-io/kestra/pull/7915))
|
||||
- **translations:** Localize to languages other than English ([#7918](https://github.com/kestra-io/kestra/pull/7918))
|
||||
- **translations:** Localize to languages other than English ([#7929](https://github.com/kestra-io/kestra/pull/7929))
|
||||
- **ui:** Remove the flow topology control button from image export ([#7937](https://github.com/kestra-io/kestra/pull/7937))
|
||||
- **ui:** Introduce a refresh functionality to execution logs page ([#7946](https://github.com/kestra-io/kestra/pull/7946))
|
||||
- Add jattach into our Docker image ([fe944ccc5](https://github.com/kestra-io/kestra/commit/fe944ccc5))
|
||||
- Add GraalVM plugin ([43f1374aa](https://github.com/kestra-io/kestra/commit/43f1374aa))
|
||||
- **ui:** Removing dynamic section of collapsible plugin properties ([#8008](https://github.com/kestra-io/kestra/pull/8008))
|
||||
- **ui:** Highlight first item in global search bar autocomplete ([#8009](https://github.com/kestra-io/kestra/pull/8009))
|
||||
- Refactor StorageInterfaceFactory to be a bean ([fe7c14c04](https://github.com/kestra-io/kestra/commit/fe7c14c04))
|
||||
- **ui:** Add anchors to plugin documentation ([#8014](https://github.com/kestra-io/kestra/pull/8014))
|
||||
- **translations:** Localize to languages other than English ([#8013](https://github.com/kestra-io/kestra/pull/8013))
|
||||
- **ui:** Limit flow run dialog maximum height ([#7938](https://github.com/kestra-io/kestra/pull/7938))
|
||||
- **ci:** Lower build-artifacts workflow so github release can use it ([2a002e953](https://github.com/kestra-io/kestra/commit/2a002e953))
|
||||
- Upgrade to version 'v0.22.0-rc1-SNAPSHOT' ([8617eb0c7](https://github.com/kestra-io/kestra/commit/8617eb0c7))
|
||||
- **ci:** Pass plugin version to docker workflow ([771e841d7](https://github.com/kestra-io/kestra/commit/771e841d7))
|
||||
- **translations:** Localize to languages other than English ([#8071](https://github.com/kestra-io/kestra/pull/8071))
|
||||
- **ui:** Improve saved search filtering functionality ([#8073](https://github.com/kestra-io/kestra/pull/8073))
|
||||
- **ui:** Make app & dashboard editors re-sizable ([#8096](https://github.com/kestra-io/kestra/pull/8096))
|
||||
- **ui:** Include labels of saved search filter on page reload ([#8099](https://github.com/kestra-io/kestra/pull/8099))
|
||||
- **ui:** Pass custom height property to execution output debug editors ([#8100](https://github.com/kestra-io/kestra/pull/8100))
|
||||
- **ui:** Handle editor blueprint loading problem ([#8113](https://github.com/kestra-io/kestra/pull/8113))
|
||||
- **ui:** Amend file tree context menu link colors ([#8123](https://github.com/kestra-io/kestra/pull/8123))
|
||||
- **ui:** Add padlock icon to secrets menu item ([#8129](https://github.com/kestra-io/kestra/pull/8129))
|
||||
- Upgrade to version 'v0.22.0-rc2-SNAPSHOT' ([a88470886](https://github.com/kestra-io/kestra/commit/a88470886))
|
||||
- **ui:** Show blueprint `id` field in case of missing title ([#8154](https://github.com/kestra-io/kestra/pull/8154))
|
||||
- Disable tests that are too flaky ([822a3b438](https://github.com/kestra-io/kestra/commit/822a3b438))
|
||||
- Upgrade to v0.22.0-rc3-SNAPSHOT ([08579cf55](https://github.com/kestra-io/kestra/commit/08579cf55))
|
||||
- Version v0.22.0-rc4-SNAPSHOT ([ed58b7b5b](https://github.com/kestra-io/kestra/commit/ed58b7b5b))
|
||||
- Upgrade to v0.22.0 ([c5f2901f7](https://github.com/kestra-io/kestra/commit/c5f2901f7))
|
||||
|
||||
### ✅ Tests
|
||||
|
||||
- **webserver:** Flaky ExecutionControllerTest for kill ([#7368](https://github.com/kestra-io/kestra/pull/7368))
|
||||
|
||||
### 🤖 CI
|
||||
|
||||
- Update workflow docker ([84a30d400](https://github.com/kestra-io/kestra/commit/84a30d400))
|
||||
- Update workflow docker ([f96cbf1ad](https://github.com/kestra-io/kestra/commit/f96cbf1ad))
|
||||
- Fix workflow docker ([fde739a3b](https://github.com/kestra-io/kestra/commit/fde739a3b))
|
||||
- Fix workflow docker for all plugins ([d4d8e326e](https://github.com/kestra-io/kestra/commit/d4d8e326e))
|
||||
- Fix release workflows ([e2b67f253](https://github.com/kestra-io/kestra/commit/e2b67f253))
|
||||
- Cleanup ([d657f4827](https://github.com/kestra-io/kestra/commit/d657f4827))
|
||||
- **docker:** Fixed version of qemu ([49fe36250](https://github.com/kestra-io/kestra/commit/49fe36250))
|
||||
- **docker:** Revert fixed qemu version ([cfc0c9f9f](https://github.com/kestra-io/kestra/commit/cfc0c9f9f))
|
||||
- **publish-docker:** Attempts with ubuntu 0.20 ([#7431](https://github.com/kestra-io/kestra/pull/7431))
|
||||
- **publish-docker:** Attempts with command on qemu docker image ([a89ef7158](https://github.com/kestra-io/kestra/commit/a89ef7158))
|
||||
- **test:** Force test if ref is a tag ([a020e3f3a](https://github.com/kestra-io/kestra/commit/a020e3f3a))
|
||||
|
||||
### ⚠️ Breaking Changes
|
||||
|
||||
### EE: Default tenant deprecation
|
||||
|
||||
Multi-tenancy was introduced in Kestra 0.13. For backward compatibility with older versions (≤0.12), you could use the concept of a default tenant, which imitated the multitenancy feature with the so-called “null”-tenant. One and a half years later, in Kestra 0.22, we are deprecating the default tenant functionality and plan to remove it in the future. We will provide a detailed migration guide for all customers who still use the default tenant. Until then, you can continue using `defaultTenant` by setting the corresponding configuration flag to `true`:
|
||||
|
||||
```yaml
|
||||
kestra:
|
||||
tenants:
|
||||
enabled: true
|
||||
defaultTenant: true
|
||||
```
|
||||
|
||||
Note that in Kestra 0.22 and higher, `defaultTenant` is NOT enabled by default, so you must explicitly set that configuration option to `true` to keep using the default tenant.
|
||||
|
||||
Also, keep in mind that prior to Kestra 0.22, `tenants.enabled` was by default set to `false` and now they are enabled.
|
||||
|
||||
### EE: Azure log exporter
|
||||
|
||||
The log exporter plugin for Azure `io.kestra.plugin.ee.azure.LogExporter`, introduced in Kestra 0.21, got split into two `io.kestra.plugin.ee.azure.monitor.LogExporter` and `io.kestra.plugin.ee.azure.storage.LogExporter` to reflect that you can now export your log to Azure either using Azure Monitor or using Azure Blob Storage.
|
||||
|
||||
### EE: Enterprise Edition API changes
|
||||
|
||||
Before Kestra 0.22, the Service Account name had to be globally unique within the instance. As a result, attempting to create a Service Account `cicd` in a `dev` tenant would raise an error `"Username already exists"` if your `prod` tenant also has a Service Account with the name `cicd`.
|
||||
|
||||
To support multiple service accounts with the same name, we’ve renamed the `username` property to `name` in the JSON payload for the following REST API endpoint: `POST /api/v1{/tenant}/users/service-accounts{/id}`.
|
||||
|
||||
### EE: Too many failed login attempts now lock the account
|
||||
|
||||
To improve the security of your Enterprise Edition instance, we now automatically lock user accounts after a `threshold` number of failed login attempts made within `monitoring-window`. Both, the number of failed attempts, the monitoring window to track consecutive number of failed attempts and (soon) the duration of how long the user remains locked are configurable.
|
||||
|
||||
```yaml
|
||||
security:
|
||||
login:
|
||||
failed-attempts:
|
||||
threshold: 10
|
||||
monitoring-window: PT15M # period to count failed attempts
|
||||
# lockout-duration: PT24H # period the account remains locked — will be added in the next release
|
||||
```
|
||||
|
||||
Note that this change is only relevant for users who leverage LDAP or basic authentication (not relevant for SSO-users). Superadmin can unlock the user manually by resetting their password from the user's detail page.
|
||||
|
||||
### Change to `readinessProbe` and `livenessProbe`
|
||||
|
||||
Before [this PR](https://github.com/kestra-io/helm-charts/pull/62/files), both probes pointed to `/health`. This caused Kubernetes to restart the pod when an external component was unavailable. To resolve this, we updated the value file to configure the liveness and readiness probes to use the health paths recommended by Micronaut:
|
||||
|
||||
- Liveness probe now points to `/health/liveness`
|
||||
- Readiness probe now points to `/health/readiness`.
|
||||
|
||||
### Plugins using the `version` property
|
||||
|
||||
With the introduction of plugin versioning, we reserve the `version` keyword for internal use, allowing us to specify the Kestra plugin version. As a result, we’ve renamed the `version` property for a few plugins that already used it, incl. the following:
|
||||
|
||||
- `io.kestra.plugin.elasticsearch.Get` → renamed as `docVersion`
|
||||
- `io.kestra.plugin.opensearch.Get` → renamed as `docVersion`
|
||||
- `io.kestra.plugin.mqtt.RealtimeTrigger` → renamed as `mqttVersion`
|
||||
- `io.kestra.plugin.mqtt.Trigger` → renamed as `mqttVersion`
|
||||
- `io.kestra.plugin.serdes.parquet.IonToParquet` → renamed as `parquetVersion`
|
||||
|
||||
Note that your **custom plugins** will need an equivalent approach of renaming any plugin that uses the `version` property, as this is now a core property reserved for plugin management. If any of your custom plugins rely on a `version` property, they won't compile anymore unless you rename that property to a different name.
|
||||
|
||||
### Change in the default value for the `kv()` function
|
||||
|
||||
Before Kestra 0.22, the `kv()` function had the property `errorOnMissing` set to `false` by default. We changed it to be `true` by default. If you want to keep the previous behavior of returning `null` without an error when attempting to fetch non-existing KV-pairs, use the syntax `"{{ kv('NON_EXISTING_KV_PAIR', errorOnMissing=false) }}"`.
|
||||
|
||||
### ❤️ Contributors
|
||||
|
||||
- Loïc Mathieu ([@loicmathieu](https://github.com/loicmathieu))
|
||||
- Barthélémy Ledoux <ledouxb@me.com>
|
||||
- Nicolas K. <nk_mikmak@hotmail.com>
|
||||
- Miloš Paunović ([@MilosPaunovic](https://github.com/MilosPaunovic))
|
||||
- Florian Hussonnois ([@fhussonnois](https://github.com/fhussonnois))
|
||||
- Brian.mulier ([@brian-mulier-p](https://github.com/brian-mulier-p))
|
||||
- Roman Acevedo <roman.acevedo62@gmail.com>
|
||||
- YannC <ycoornaert@kestra.io>
|
||||
- Yuri <1969yuri1969@gmail.com>
|
||||
- AJ Emerich <aemerich@kestra.io>
|
||||
- Satvik Kushwaha ([@satvik2131](https://github.com/satvik2131))
|
||||
- BenjoEK1337 ([@benjoEK1337](https://github.com/benjoEK1337))
|
||||
- Piyush Bhaskar ([@Piyush-r-bhaskar](https://github.com/Piyush-r-bhaskar))
|
||||
- Bart Ledoux <bledoux@kestra.io>
|
||||
- Yuri1969 <1969yuri1969@gmail.com>
|
||||
- Ludovic DEHON ([@tchiotludo](https://github.com/tchiotludo))
|
||||
- Rajatsingh23 ([@rajatsingh23](https://github.com/rajatsingh23))
|
||||
- Ash ([@Alessandra005](https://github.com/Alessandra005))
|
||||
- Will Russell ([@wrussell1999](https://github.com/wrussell1999))
|
||||
- Malay Dewangan ([@Malaydewangan09](https://github.com/Malaydewangan09))
|
||||
- Anna Geller <anna.m.geller@gmail.com>
|
||||
- Shruti Mantri <shruti1810@gmail.com>
|
||||
- NKwiatkowski <nkwiatkowski@kestra.io>
|
||||
- MilosPaunovic ([@MilosPaunovic](https://github.com/MilosPaunovic))
|
||||
- Harshit Dhaduk <harshitdhaduk5831@gmail.com>
|
||||
- Tanvir Ahmed ([@m-t-a97](https://github.com/m-t-a97))
|
||||
- Malaydewangan09 <malaydewangan310@gmail.com>
|
||||
- Đỗ Trọng Hải ([@hainenber](https://github.com/hainenber))
|
||||
- AeSouid <aesouid@kestra.io>
|
||||
- Adam Hirshson ([@Ahirshson02](https://github.com/Ahirshson02))
|
||||
- Mathieu Gabelle ([@mgabelle](https://github.com/mgabelle))
|
||||
- Aabhas Sao ([@aabhas-sao](https://github.com/aabhas-sao))
|
||||
- Laibrez <laishabj@gmail.com>
|
||||
- Eduardo Goncalvez ([@Edugre](https://github.com/Edugre))
|
||||
- Shamar ([@Shamar12334](https://github.com/Shamar12334))
|
||||
- Pravesh-Sudha ([@Pravesh-Sudha](https://github.com/Pravesh-Sudha))
|
||||
- ByronBlaze <pg903@snu.edu.in>
|
||||
- GitHub Action ([@Github-Action-Bot](https://github.com/Github-Action-Bot))
|
||||
- Dheeraj_R_Gowda ([@Dheerajr444](https://github.com/Dheerajr444))
|
||||
- 咬轮猫 <10928033@qq.com>
|
||||
- Amartknez <amartknez98@gmail.com>
|
||||
- Malay.worldref@gmail.com <malay@Malays-MacBook-Air.local>
|
||||
- Karthik73965 ([@Karthik73965](https://github.com/Karthik73965))
|
||||
- Brian-mulier-p ([@brian-mulier-p](https://github.com/brian-mulier-p))
|
||||
@@ -46,6 +46,13 @@ public abstract class AbstractApiCommand extends AbstractCommand {
|
||||
@Nullable
|
||||
private HttpClientConfiguration httpClientConfiguration;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected boolean loadExternalPlugins() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected DefaultHttpClient client() throws URISyntaxException {
|
||||
DefaultHttpClient defaultHttpClient = new DefaultHttpClient(server.toURI(), httpClientConfiguration != null ? httpClientConfiguration : new DefaultHttpClientConfiguration());
|
||||
MessageBodyHandlerRegistry defaultHandlerRegistry = defaultHttpClient.getHandlerRegistry();
|
||||
|
||||
@@ -31,6 +31,12 @@ public abstract class AbstractValidateCommand extends AbstractApiCommand {
|
||||
@CommandLine.Parameters(index = "0", description = "the directory containing files to check")
|
||||
protected Path directory;
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
@Override
|
||||
protected boolean loadExternalPlugins() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public static void handleException(ConstraintViolationException e, String resource) {
|
||||
stdErr("\t@|fg(red) Unable to parse {0} due to the following error(s):|@", resource);
|
||||
e.getConstraintViolations()
|
||||
|
||||
@@ -18,6 +18,8 @@ import picocli.CommandLine;
|
||||
FlowNamespaceCommand.class,
|
||||
FlowDotCommand.class,
|
||||
FlowExportCommand.class,
|
||||
FlowUpdateCommand.class,
|
||||
FlowUpdatesCommand.class
|
||||
}
|
||||
)
|
||||
@Slf4j
|
||||
|
||||
@@ -87,4 +87,9 @@ public class FlowUpdatesCommand extends AbstractApiCommand {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean loadExternalPlugins() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import picocli.CommandLine.Command;
|
||||
mixinStandardHelpOptions = true,
|
||||
subcommands = {
|
||||
PluginInstallCommand.class,
|
||||
PluginUninstallCommand.class,
|
||||
PluginListCommand.class,
|
||||
PluginDocCommand.class,
|
||||
PluginSearchCommand.class
|
||||
|
||||
@@ -17,10 +17,10 @@ import java.util.List;
|
||||
|
||||
@CommandLine.Command(
|
||||
name = "uninstall",
|
||||
description = "uninstall a plugin"
|
||||
description = "Uninstall plugins"
|
||||
)
|
||||
public class PluginUninstallCommand extends AbstractCommand {
|
||||
@Parameters(index = "0..*", description = "the plugins to uninstall")
|
||||
@Parameters(index = "0..*", description = "The plugins to uninstall. Represented as Maven artifact coordinates (i.e., <groupId>:<artifactId>:(<version>|LATEST)")
|
||||
List<String> dependencies = new ArrayList<>();
|
||||
|
||||
@Spec
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.kestra.cli.commands.servers;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.kestra.cli.services.FileChangedEventListener;
|
||||
import io.kestra.core.contexts.KestraContext;
|
||||
import io.kestra.core.models.ServerType;
|
||||
import io.kestra.core.repositories.LocalFlowRepositoryLoader;
|
||||
import io.kestra.core.runners.StandAloneRunner;
|
||||
@@ -88,9 +89,10 @@ public class StandAloneCommand extends AbstractServerCommand {
|
||||
this.skipExecutionService.setSkipFlows(skipFlows);
|
||||
this.skipExecutionService.setSkipNamespaces(skipNamespaces);
|
||||
this.skipExecutionService.setSkipTenants(skipTenants);
|
||||
|
||||
this.startExecutorService.applyOptions(startExecutors, notStartExecutors);
|
||||
|
||||
KestraContext.getContext().injectWorkerConfigs(workerThread, null);
|
||||
|
||||
super.call();
|
||||
|
||||
if (flowPath != null) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.kestra.cli.commands.servers;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import io.kestra.core.contexts.KestraContext;
|
||||
import io.kestra.core.models.ServerType;
|
||||
import io.kestra.core.runners.Worker;
|
||||
import io.kestra.core.utils.Await;
|
||||
@@ -36,7 +37,11 @@ public class WorkerCommand extends AbstractServerCommand {
|
||||
|
||||
@Override
|
||||
public Integer call() throws Exception {
|
||||
|
||||
KestraContext.getContext().injectWorkerConfigs(thread, workerGroupKey);
|
||||
|
||||
super.call();
|
||||
|
||||
if (this.workerGroupKey != null && !this.workerGroupKey.matches("[a-zA-Z0-9_-]+")) {
|
||||
throw new IllegalArgumentException("The --worker-group option must match the [a-zA-Z0-9_-]+ pattern");
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ class FlowExportCommandTest {
|
||||
|
||||
// we use the update command to add flows to extract
|
||||
String[] updateArgs = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -44,6 +46,8 @@ class FlowExportCommandTest {
|
||||
|
||||
// then we export them
|
||||
String[] exportArgs = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
|
||||
@@ -28,6 +28,8 @@ class FlowUpdatesCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -41,6 +43,8 @@ class FlowUpdatesCommandTest {
|
||||
out.reset();
|
||||
|
||||
args = new String[]{
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -70,6 +74,8 @@ class FlowUpdatesCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -84,6 +90,8 @@ class FlowUpdatesCommandTest {
|
||||
|
||||
// no "delete" arg should behave as no-delete
|
||||
args = new String[]{
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -96,6 +104,8 @@ class FlowUpdatesCommandTest {
|
||||
out.reset();
|
||||
|
||||
args = new String[]{
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -121,6 +131,8 @@ class FlowUpdatesCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -148,6 +160,8 @@ class FlowUpdatesCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
|
||||
@@ -46,6 +46,8 @@ class TemplateValidateCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
|
||||
@@ -31,6 +31,8 @@ class NamespaceFilesUpdateCommandTest {
|
||||
|
||||
String to = "/some/directory";
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -61,6 +63,8 @@ class NamespaceFilesUpdateCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -90,6 +94,8 @@ class NamespaceFilesUpdateCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
|
||||
@@ -28,6 +28,8 @@ class KvUpdateCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -54,6 +56,8 @@ class KvUpdateCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -80,6 +84,8 @@ class KvUpdateCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -108,6 +114,8 @@ class KvUpdateCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -134,6 +142,8 @@ class KvUpdateCommandTest {
|
||||
embeddedServer.start();
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
@@ -167,6 +177,8 @@ class KvUpdateCommandTest {
|
||||
Files.write(file.toPath(), "{\"some\":\"json\",\"from\":\"file\"}".getBytes());
|
||||
|
||||
String[] args = {
|
||||
"--plugins",
|
||||
"/tmp", // pass this arg because it can cause failure
|
||||
"--server",
|
||||
embeddedServer.getURL().toString(),
|
||||
"--user",
|
||||
|
||||
@@ -10,6 +10,8 @@ import io.micronaut.context.env.Environment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -27,6 +29,10 @@ public abstract class KestraContext {
|
||||
// Properties
|
||||
public static final String KESTRA_SERVER_TYPE = "kestra.server-type";
|
||||
|
||||
// Those properties are injected bases on the CLI args.
|
||||
private static final String KESTRA_WORKER_MAX_NUM_THREADS = "kestra.worker.max-num-threads";
|
||||
private static final String KESTRA_WORKER_GROUP_KEY = "kestra.worker.group-key";
|
||||
|
||||
/**
|
||||
* Gets the current {@link KestraContext}.
|
||||
*
|
||||
@@ -54,6 +60,12 @@ public abstract class KestraContext {
|
||||
*/
|
||||
public abstract ServerType getServerType();
|
||||
|
||||
public abstract Optional<Integer> getWorkerMaxNumThreads();
|
||||
|
||||
public abstract Optional<String> getWorkerGroupKey();
|
||||
|
||||
public abstract void injectWorkerConfigs(Integer maxNumThreads, String workerGroupKey);
|
||||
|
||||
/**
|
||||
* Returns the Kestra Version.
|
||||
*
|
||||
@@ -110,6 +122,34 @@ public abstract class KestraContext {
|
||||
.orElse(ServerType.STANDALONE);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
@Override
|
||||
public Optional<Integer> getWorkerMaxNumThreads() {
|
||||
return Optional.ofNullable(environment)
|
||||
.flatMap(env -> env.getProperty(KESTRA_WORKER_MAX_NUM_THREADS, Integer.class));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
@Override
|
||||
public Optional<String> getWorkerGroupKey() {
|
||||
return Optional.ofNullable(environment)
|
||||
.flatMap(env -> env.getProperty(KESTRA_WORKER_GROUP_KEY, String.class));
|
||||
}
|
||||
/** {@inheritDoc} **/
|
||||
@Override
|
||||
public void injectWorkerConfigs(Integer maxNumThreads, String workerGroupKey) {
|
||||
final Map<String, Object> configs = new HashMap<>();
|
||||
Optional.ofNullable(maxNumThreads)
|
||||
.ifPresent(val -> configs.put(KESTRA_WORKER_MAX_NUM_THREADS, val));
|
||||
|
||||
Optional.ofNullable(workerGroupKey)
|
||||
.ifPresent(val -> configs.put(KESTRA_WORKER_GROUP_KEY, val));
|
||||
|
||||
if (!configs.isEmpty()) {
|
||||
environment.addPropertySource("kestra-runtime", configs);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
|
||||
@@ -81,7 +81,7 @@ public class JsonSchemaGenerator {
|
||||
objectNode.put("type", "array");
|
||||
}
|
||||
replaceAnyOfWithOneOf(objectNode);
|
||||
pullOfDefaultFromOneOf(objectNode);
|
||||
pullDocumentationAndDefaultFromOneOf(objectNode);
|
||||
removeRequiredOnPropsWithDefaults(objectNode);
|
||||
|
||||
return JacksonMapper.toMap(objectNode);
|
||||
@@ -122,22 +122,35 @@ public class JsonSchemaGenerator {
|
||||
// This hack exists because for Property we generate a oneOf for properties that are not strings.
|
||||
// By default, the 'default' is in each oneOf which Monaco editor didn't take into account.
|
||||
// So, we pull off the 'default' from any of the oneOf to the parent.
|
||||
private void pullOfDefaultFromOneOf(ObjectNode objectNode) {
|
||||
// same thing for documentation fields: 'title', 'description', '$deprecated'
|
||||
private void pullDocumentationAndDefaultFromOneOf(ObjectNode objectNode) {
|
||||
objectNode.findParents("oneOf").forEach(jsonNode -> {
|
||||
if (jsonNode instanceof ObjectNode oNode) {
|
||||
JsonNode oneOf = oNode.get("oneOf");
|
||||
if (oneOf instanceof ArrayNode arrayNode) {
|
||||
Iterator<JsonNode> it = arrayNode.elements();
|
||||
JsonNode defaultNode = null;
|
||||
while (it.hasNext() && defaultNode == null) {
|
||||
var nodesToPullUp = new HashMap<String, Optional<JsonNode>>(Map.ofEntries(
|
||||
Map.entry("default", Optional.empty()),
|
||||
Map.entry("title", Optional.empty()),
|
||||
Map.entry("description", Optional.empty()),
|
||||
Map.entry("$deprecated", Optional.empty())
|
||||
));
|
||||
// find nodes to pull up
|
||||
while (it.hasNext() && nodesToPullUp.containsValue(Optional.<JsonNode>empty())) {
|
||||
JsonNode next = it.next();
|
||||
if (next instanceof ObjectNode nextAsObj) {
|
||||
defaultNode = nextAsObj.get("default");
|
||||
nodesToPullUp.entrySet().stream()
|
||||
.filter(node -> node.getValue().isEmpty())
|
||||
.forEach(node -> node
|
||||
.setValue(Optional.ofNullable(
|
||||
nextAsObj.get(node.getKey())
|
||||
)));
|
||||
}
|
||||
}
|
||||
if (defaultNode != null) {
|
||||
oNode.set("default", defaultNode);
|
||||
}
|
||||
// create nodes on parent
|
||||
nodesToPullUp.entrySet().stream()
|
||||
.filter(node -> node.getValue().isPresent())
|
||||
.forEach(node -> oNode.set(node.getKey(), node.getValue().get()));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -629,7 +642,7 @@ public class JsonSchemaGenerator {
|
||||
try {
|
||||
ObjectNode objectNode = generator.generateSchema(cls);
|
||||
replaceAnyOfWithOneOf(objectNode);
|
||||
pullOfDefaultFromOneOf(objectNode);
|
||||
pullDocumentationAndDefaultFromOneOf(objectNode);
|
||||
removeRequiredOnPropsWithDefaults(objectNode);
|
||||
|
||||
return JacksonMapper.toMap(extractMainRef(objectNode));
|
||||
|
||||
@@ -64,8 +64,10 @@ public class EncryptionService {
|
||||
* The IV is recovered from the beginning of the string.
|
||||
*
|
||||
* @see #decrypt(String, byte[])
|
||||
* @throws IllegalArgumentException when the cipherText cannot be BASE64 decoded.
|
||||
* This may indicate that the cipherText was not encrypted at first so a caller may use this as an indication as it tries to decode a text that was not encoded.
|
||||
*/
|
||||
public static String decrypt(String key, String cipherText) throws GeneralSecurityException {
|
||||
public static String decrypt(String key, String cipherText) throws GeneralSecurityException, IllegalArgumentException {
|
||||
if (cipherText == null || cipherText.isEmpty()) {
|
||||
return cipherText;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ public enum CrudEventType {
|
||||
LOGIN,
|
||||
LOGOUT,
|
||||
IMPERSONATE,
|
||||
LOGIN_FAILURE
|
||||
LOGIN_FAILURE,
|
||||
ACCOUNT_LOCKED
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ public record Label(@NotNull String key, @NotNull String value) {
|
||||
public static final String RESTARTED = SYSTEM_PREFIX + "restarted";
|
||||
public static final String REPLAY = SYSTEM_PREFIX + "replay";
|
||||
public static final String REPLAYED = SYSTEM_PREFIX + "replayed";
|
||||
public static final String SIMULATED_EXECUTION = SYSTEM_PREFIX + "simulatedExecution";
|
||||
|
||||
/**
|
||||
* Static helper method for converting a list of labels to a nested map.
|
||||
|
||||
@@ -10,7 +10,7 @@ import jakarta.validation.constraints.Pattern;
|
||||
*/
|
||||
public interface PluginVersioning {
|
||||
|
||||
@Pattern(regexp="\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9]+)?|([a-zA-Z0-9]+)")
|
||||
@Pattern(regexp="\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9-]+)?|([a-zA-Z0-9]+)")
|
||||
@Schema(title = "The version of the plugin to use.")
|
||||
String getVersion();
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public record QueryFilter(
|
||||
NAMESPACE("namespace") {
|
||||
@Override
|
||||
public List<Op> supportedOp() {
|
||||
return List.of(Op.EQUALS, Op.NOT_EQUALS, Op.CONTAINS, Op.STARTS_WITH, Op.ENDS_WITH, Op.REGEX);
|
||||
return List.of(Op.EQUALS, Op.NOT_EQUALS, Op.CONTAINS, Op.STARTS_WITH, Op.ENDS_WITH, Op.REGEX, Op.IN);
|
||||
}
|
||||
},
|
||||
LABELS("labels") {
|
||||
|
||||
@@ -38,7 +38,7 @@ public record PluginArtifact(
|
||||
"([^: ]+):([^: ]+)(:([^: ]*)(:([^: ]+))?)?:([^: ]+)"
|
||||
);
|
||||
private static final Pattern FILENAME_PATTERN = Pattern.compile(
|
||||
"^(?<groupId>[\\w_]+)__(?<artifactId>[\\w-_]+)(?:__(?<classifier>[\\w-_]+))?__(?<version>\\d+_\\d+_\\d+(-[a-zA-Z0-9]+)?|([a-zA-Z0-9]+))\\.jar$"
|
||||
"^(?<groupId>[\\w_]+)__(?<artifactId>[\\w-_]+)(?:__(?<classifier>[\\w-_]+))?__(?<version>\\d+_\\d+_\\d+(-[a-zA-Z0-9-]+)?|([a-zA-Z0-9]+))\\.jar$"
|
||||
);
|
||||
|
||||
public static final String JAR_EXTENSION = "jar";
|
||||
|
||||
@@ -94,6 +94,7 @@ public interface ExecutionRepositoryInterface extends SaveRepositoryInterface<Ex
|
||||
boolean allowDeleted
|
||||
);
|
||||
|
||||
Flux<Execution> findAllAsync(@Nullable String tenantId);
|
||||
|
||||
ArrayListTotal<TaskRun> findTaskRun(
|
||||
Pageable pageable,
|
||||
|
||||
@@ -88,6 +88,8 @@ public interface LogRepositoryInterface extends SaveRepositoryInterface<LogEntry
|
||||
ZonedDateTime startDate
|
||||
);
|
||||
|
||||
Flux<LogEntry> findAllAsync(@Nullable String tenantId);
|
||||
|
||||
List<LogStatistics> statistics(
|
||||
@Nullable String query,
|
||||
@Nullable String tenantId,
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.kestra.core.models.executions.metrics.MetricAggregations;
|
||||
import io.kestra.plugin.core.dashboard.data.Metrics;
|
||||
import io.micronaut.core.annotation.Nullable;
|
||||
import io.micronaut.data.model.Pageable;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
@@ -28,6 +29,8 @@ public interface MetricRepositoryInterface extends SaveRepositoryInterface<Metri
|
||||
|
||||
Integer purge(Execution execution);
|
||||
|
||||
Flux<MetricEntry> findAllAsync(@Nullable String tenantId);
|
||||
|
||||
default Function<String, String> sortMapping() throws IllegalArgumentException {
|
||||
return s -> s;
|
||||
}
|
||||
|
||||
@@ -51,10 +51,12 @@ public class RunContextLogger implements Supplier<org.slf4j.Logger> {
|
||||
}
|
||||
|
||||
public RunContextLogger(QueueInterface<LogEntry> logQueue, LogEntry logEntry, org.slf4j.event.Level loglevel, boolean logToFile) {
|
||||
if (logEntry.getExecutionId() != null) {
|
||||
this.loggerName = "flow." + logEntry.getFlowId() + "." + logEntry.getExecutionId() + (logEntry.getTaskRunId() != null ? "." + logEntry.getTaskRunId() : "");
|
||||
} else {
|
||||
if (logEntry.getTaskId() != null) {
|
||||
this.loggerName = "flow." + logEntry.getFlowId() + "." + logEntry.getTaskId();
|
||||
} else if (logEntry.getTriggerId() != null) {
|
||||
this.loggerName = "flow." + logEntry.getFlowId() + "." + logEntry.getTriggerId();
|
||||
} else {
|
||||
this.loggerName = "flow." + logEntry.getFlowId();
|
||||
}
|
||||
|
||||
this.logQueue = logQueue;
|
||||
@@ -258,7 +260,8 @@ public class RunContextLogger implements Supplier<org.slf4j.Logger> {
|
||||
} else if (object instanceof String string) {
|
||||
return replaceSecret(string);
|
||||
} else {
|
||||
return object;
|
||||
// toString will be called anyway at some point so better to all it now
|
||||
return replaceSecret(object.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.kestra.core.runners;
|
||||
|
||||
import io.kestra.core.encryption.EncryptionService;
|
||||
import io.kestra.core.models.tasks.common.EncryptedString;
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
@@ -50,8 +49,11 @@ final class Secret {
|
||||
try {
|
||||
String decoded = decrypt((String) map.get("value"));
|
||||
decryptedMap.put(entry.getKey(), decoded);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (GeneralSecurityException | IllegalArgumentException e) {
|
||||
// NOTE: in rare cases, if for ex a Worker didn't have the encryption but an Executor has it,
|
||||
// we can have a non-encrypted output that we try to decrypt, this will lead to an IllegalArgumentException.
|
||||
// As it could break the executor, the best is to do nothing in this case and only log an error.
|
||||
logger.get().warn("Unable to decrypt the output", e);
|
||||
}
|
||||
} else {
|
||||
decryptedMap.put(entry.getKey(), decrypt((Map<String, Object>) map));
|
||||
|
||||
@@ -201,7 +201,7 @@ public final class FileSerde {
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> SequenceWriter createSequenceWriter(ObjectMapper objectMapper, Writer writer, TypeReference<T> type) throws IOException {
|
||||
public static <T> SequenceWriter createSequenceWriter(ObjectMapper objectMapper, Writer writer, TypeReference<T> type) throws IOException {
|
||||
return objectMapper.writerFor(type).writeValues(writer);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,15 @@ public class FlowService {
|
||||
}
|
||||
|
||||
List<String> warnings = new ArrayList<>(checkValidSubflows(flow, tenantId));
|
||||
List<io.kestra.plugin.core.trigger.Flow> flowTriggers = ListUtils.emptyOnNull(flow.getTriggers()).stream()
|
||||
.filter(io.kestra.plugin.core.trigger.Flow.class::isInstance)
|
||||
.map(io.kestra.plugin.core.trigger.Flow.class::cast)
|
||||
.toList();
|
||||
flowTriggers.forEach(flowTrigger -> {
|
||||
if (ListUtils.emptyOnNull(flowTrigger.getConditions()).isEmpty() && flowTrigger.getPreconditions() == null) {
|
||||
warnings.add("This flow will be triggered for EVERY execution of EVERY flow on your instance. We recommend adding the preconditions property to the Flow trigger '" + flowTrigger.getId() + "'.");
|
||||
}
|
||||
});
|
||||
|
||||
return warnings;
|
||||
}
|
||||
@@ -140,7 +149,11 @@ public class FlowService {
|
||||
try {
|
||||
Map<String, Class<?>> aliases = pluginRegistry.plugins().stream()
|
||||
.flatMap(plugin -> plugin.getAliases().values().stream())
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
.collect(Collectors.toMap(
|
||||
Map.Entry::getKey,
|
||||
Map.Entry::getValue,
|
||||
(existing, duplicate) -> existing
|
||||
));
|
||||
Map<String, Object> stringObjectMap = JacksonMapper.ofYaml().readValue(flowSource, JacksonMapper.MAP_TYPE_REFERENCE);
|
||||
return relocations(aliases, stringObjectMap);
|
||||
} catch (JsonProcessingException e) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package io.kestra.core.services;
|
||||
|
||||
import io.kestra.core.repositories.FlowRepositoryInterface;
|
||||
import io.kestra.core.utils.NamespaceUtils;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
@@ -19,7 +21,7 @@ public class NamespaceService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a given namespace exists.
|
||||
* Checks whether a given namespace exists. A namespace is considered existing if at least one Flow is within the namespace or a parent namespace
|
||||
*
|
||||
* @param tenant The tenant ID
|
||||
* @param namespace The namespace - cannot be null.
|
||||
@@ -29,7 +31,10 @@ public class NamespaceService {
|
||||
Objects.requireNonNull(namespace, "namespace cannot be null");
|
||||
|
||||
if (flowRepository.isPresent()) {
|
||||
List<String> namespaces = flowRepository.get().findDistinctNamespace(tenant);
|
||||
List<String> namespaces = flowRepository.get().findDistinctNamespace(tenant).stream()
|
||||
.map(NamespaceUtils::asTree)
|
||||
.flatMap(Collection::stream)
|
||||
.toList();
|
||||
return namespaces.stream().anyMatch(ns -> ns.equals(namespace) || ns.startsWith(namespace));
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -29,7 +29,7 @@ import java.util.stream.Stream;
|
||||
@Slf4j
|
||||
@Singleton
|
||||
public class FlowTopologyService {
|
||||
public static final Label SIMULATED_EXECUTION = new Label(Label.SYSTEM_PREFIX + "simulatedExecution", "true");
|
||||
public static final Label SIMULATED_EXECUTION = new Label(Label.SIMULATED_EXECUTION, "true");
|
||||
|
||||
@Inject
|
||||
protected ConditionService conditionService;
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package io.kestra.core.utils;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Slf4j
|
||||
public class MapUtils {
|
||||
private static final String CONFLICT_AT_KEY_MSG = "Conflict at key: '{}', ignoring it. Map keys are: {}";
|
||||
|
||||
public static Map<String, Object> merge(Map<String, Object> a, Map<String, Object> b) {
|
||||
if (a == null && b == null) {
|
||||
return null;
|
||||
@@ -136,9 +140,9 @@ public class MapUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method nested a flatten map.
|
||||
* Utility method nested a flattened map.
|
||||
*
|
||||
* @param flatMap the flatten map.
|
||||
* @param flatMap the flattened map.
|
||||
* @return the nested map.
|
||||
*
|
||||
* @throws IllegalArgumentException if the given map contains conflicting keys.
|
||||
@@ -156,13 +160,15 @@ public class MapUtils {
|
||||
currentMap.put(key, new HashMap<>());
|
||||
} else if (!(currentMap.get(key) instanceof Map)) {
|
||||
var invalidKey = String.join(",", Arrays.copyOfRange(keys, 0, i));
|
||||
throw new IllegalArgumentException("Conflict at key: '" + invalidKey + "'. Map keys are: " + flatMap.keySet());
|
||||
log.warn(CONFLICT_AT_KEY_MSG, invalidKey, flatMap.keySet());
|
||||
continue;
|
||||
}
|
||||
currentMap = (Map<String, Object>) currentMap.get(key);
|
||||
}
|
||||
String lastKey = keys[keys.length - 1];
|
||||
if (currentMap.containsKey(lastKey)) {
|
||||
throw new IllegalArgumentException("Conflict at key: '" + lastKey + "', Map keys are: " + flatMap.keySet());
|
||||
log.warn("Conflict at key: '{}', ignoring it. Map keys are: {}", lastKey, flatMap.keySet());
|
||||
continue;
|
||||
}
|
||||
currentMap.put(lastKey, entry.getValue());
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package io.kestra.core.validations;
|
||||
|
||||
import io.kestra.core.validations.validator.ConditionValidator;
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = ConditionValidator.class)
|
||||
public @interface ConditionValidation {
|
||||
String message() default "one condition must be set";
|
||||
Class<?>[] groups() default {};
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package io.kestra.core.validations.validator;
|
||||
|
||||
import io.kestra.core.validations.ConditionValidation;
|
||||
import io.kestra.plugin.core.trigger.Flow;
|
||||
import io.micronaut.core.annotation.AnnotationValue;
|
||||
import io.micronaut.core.annotation.NonNull;
|
||||
import io.micronaut.core.annotation.Nullable;
|
||||
import io.micronaut.validation.validator.constraints.ConstraintValidator;
|
||||
import io.micronaut.validation.validator.constraints.ConstraintValidatorContext;
|
||||
import jakarta.inject.Singleton;
|
||||
|
||||
@Singleton
|
||||
public class ConditionValidator implements ConstraintValidator<ConditionValidation, Flow> {
|
||||
@Override
|
||||
public boolean isValid(@Nullable Flow value, @NonNull AnnotationValue<ConditionValidation> annotationMetadata, @NonNull ConstraintValidatorContext context) {
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return value.getConditions() != null || value.getPreconditions() != null;
|
||||
}
|
||||
}
|
||||
@@ -4,47 +4,51 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.kestra.core.exceptions.IllegalVariableEvaluationException;
|
||||
import io.kestra.core.exceptions.InternalException;
|
||||
import io.kestra.core.models.Label;
|
||||
import io.kestra.core.models.annotations.Example;
|
||||
import io.kestra.core.models.annotations.Plugin;
|
||||
import io.kestra.core.models.annotations.PluginProperty;
|
||||
import io.kestra.core.models.conditions.Condition;
|
||||
import io.kestra.core.models.conditions.ConditionContext;
|
||||
import io.kestra.core.models.executions.Execution;
|
||||
import io.kestra.core.models.executions.ExecutionTrigger;
|
||||
import io.kestra.core.models.flows.State;
|
||||
import io.kestra.core.models.triggers.AbstractTrigger;
|
||||
import io.kestra.core.models.triggers.TimeWindow;
|
||||
import io.kestra.core.models.triggers.TriggerOutput;
|
||||
import io.kestra.core.models.triggers.multipleflows.MultipleCondition;
|
||||
import io.kestra.core.models.triggers.multipleflows.MultipleConditionStorageInterface;
|
||||
import io.kestra.core.models.triggers.multipleflows.MultipleConditionWindow;
|
||||
import io.kestra.core.runners.RunContext;
|
||||
import io.kestra.core.services.LabelService;
|
||||
import io.kestra.core.utils.IdUtils;
|
||||
import io.kestra.core.utils.ListUtils;
|
||||
import io.kestra.core.utils.MapUtils;
|
||||
import io.kestra.core.utils.TruthUtils;
|
||||
import io.kestra.core.validations.ConditionValidation;
|
||||
import io.kestra.core.validations.PreconditionFilterValidation;
|
||||
import io.micronaut.core.annotation.Nullable;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
import lombok.*;
|
||||
import lombok.experimental.SuperBuilder;
|
||||
import io.kestra.core.models.annotations.Example;
|
||||
import io.kestra.core.models.annotations.Plugin;
|
||||
import io.kestra.core.models.executions.Execution;
|
||||
import io.kestra.core.models.executions.ExecutionTrigger;
|
||||
import io.kestra.core.models.flows.State;
|
||||
import io.kestra.core.models.triggers.AbstractTrigger;
|
||||
import io.kestra.core.models.triggers.TriggerOutput;
|
||||
import io.kestra.core.runners.RunContext;
|
||||
import io.kestra.core.utils.IdUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.stream.Streams;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import io.micronaut.core.annotation.Nullable;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import static io.kestra.core.topologies.FlowTopologyService.SIMULATED_EXECUTION;
|
||||
import static io.kestra.core.utils.Rethrow.throwPredicate;
|
||||
|
||||
@@ -194,7 +198,6 @@ import static io.kestra.core.utils.Rethrow.throwPredicate;
|
||||
aliases = "io.kestra.core.models.triggers.types.Flow"
|
||||
)
|
||||
@Slf4j
|
||||
@ConditionValidation
|
||||
public class Flow extends AbstractTrigger implements TriggerOutput<Flow.Output> {
|
||||
private static final String TRIGGER_VAR = "trigger";
|
||||
private static final String OUTPUTS_VAR = "outputs";
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package io.kestra.core.contexts;
|
||||
|
||||
import io.kestra.core.junit.annotations.KestraTest;
|
||||
import io.micronaut.context.ApplicationContext;
|
||||
import jakarta.inject.Inject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@KestraTest
|
||||
class KestraContextTest {
|
||||
|
||||
@Inject
|
||||
KestraContext context;
|
||||
|
||||
@Test
|
||||
void shouldGetWorkerMaxNumThreads() {
|
||||
// When
|
||||
context.injectWorkerConfigs(16, null);
|
||||
|
||||
// Then
|
||||
assertThat(KestraContext.getContext().getWorkerMaxNumThreads(), is(Optional.of(16)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldGetWorkerGroupKey() {
|
||||
// When
|
||||
context.injectWorkerConfigs(null, "my-key");
|
||||
|
||||
// Then
|
||||
assertThat(KestraContext.getContext().getWorkerGroupKey(), is(Optional.of("my-key")));
|
||||
}
|
||||
}
|
||||
@@ -249,6 +249,30 @@ class JsonSchemaGeneratorTest {
|
||||
assertThat((List<String>) generate.get("required"), containsInAnyOrder("requiredWithNoDefault"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void testDocumentation() {
|
||||
Map<String, Object> generate = jsonSchemaGenerator.properties(Task.class, TaskWithDynamicDocumentedFields.class);
|
||||
assertThat(generate, is(not(nullValue())));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringProperty").get("title"), is("stringProperty title"));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringProperty").get("description"), is("stringProperty description"));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringProperty").get("$deprecated"), is(true));
|
||||
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerProperty").get("title"), is("integerProperty title"));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerProperty").get("description"), is("integerProperty description"));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerProperty").get("$deprecated"), is(true));
|
||||
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringPropertyWithDefault").get("title"), is("stringPropertyWithDefault title"));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringPropertyWithDefault").get("description"), is("stringPropertyWithDefault description"));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringPropertyWithDefault").get("$deprecated"), is(true));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("stringPropertyWithDefault").get("default"), is("my string"));
|
||||
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerPropertyWithDefault").get("title"), is("integerPropertyWithDefault title"));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerPropertyWithDefault").get("description"), is("integerPropertyWithDefault description"));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerPropertyWithDefault").get("$deprecated"), is(true));
|
||||
assertThat(((Map<String, Map<String, Object>>) generate.get("properties")).get("integerPropertyWithDefault").get("default"), is("10000"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void dashboard() throws URISyntaxException {
|
||||
@@ -314,10 +338,11 @@ class JsonSchemaGeneratorTest {
|
||||
private TestEnum testEnum;
|
||||
|
||||
@PluginProperty
|
||||
@Schema(title = "Title from the attribute")
|
||||
@Schema(title = "Title from the attribute", description = "Description from the attribute")
|
||||
private TestClass testClass;
|
||||
|
||||
@PluginProperty(internalStorageURI = true)
|
||||
@Schema(title = "Title from the attribute", description = "Description from the attribute")
|
||||
private String uri;
|
||||
|
||||
@PluginProperty
|
||||
@@ -392,4 +417,49 @@ class JsonSchemaGeneratorTest {
|
||||
@NotNull
|
||||
private Property<TaskWithEnum.TestClass> requiredWithNoDefault;
|
||||
}
|
||||
|
||||
@SuperBuilder
|
||||
@ToString
|
||||
@EqualsAndHashCode
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public static class TaskWithDynamicDocumentedFields extends Task implements RunnableTask<VoidOutput> {
|
||||
|
||||
@Deprecated(since="deprecation_version_1", forRemoval=true)
|
||||
@Schema(
|
||||
title = "integerPropertyWithDefault title",
|
||||
description = "integerPropertyWithDefault description"
|
||||
)
|
||||
@Builder.Default
|
||||
protected Property<Integer> integerPropertyWithDefault = Property.of(10000);
|
||||
|
||||
@Deprecated(since="deprecation_version_1", forRemoval=true)
|
||||
@Schema(
|
||||
title = "stringPropertyWithDefault title",
|
||||
description = "stringPropertyWithDefault description"
|
||||
)
|
||||
@Builder.Default
|
||||
protected Property<String> stringPropertyWithDefault = Property.of("my string");
|
||||
|
||||
|
||||
@Deprecated(since="deprecation_version_1", forRemoval=true)
|
||||
@Schema(
|
||||
title = "stringProperty title",
|
||||
description = "stringProperty description"
|
||||
)
|
||||
protected Property<String> stringProperty;
|
||||
|
||||
@Deprecated(since="deprecation_version_1", forRemoval=true)
|
||||
@Schema(
|
||||
title = "integerProperty title",
|
||||
description = "integerProperty description"
|
||||
)
|
||||
protected Property<Integer> integerProperty;
|
||||
|
||||
@Override
|
||||
public VoidOutput run(RunContext runContext) throws Exception {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,32 @@ class PluginArtifactTest {
|
||||
assertNull(artifact.uri());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldParseGivenValidFilenameWithQualifier() {
|
||||
String fileName = "io_kestra_plugin__plugin-serdes__custom-classifier__0_20_0-SNAPSHOT.jar";
|
||||
PluginArtifact artifact = PluginArtifact.fromFileName(fileName);
|
||||
|
||||
assertEquals("io.kestra.plugin", artifact.groupId());
|
||||
assertEquals("plugin-serdes", artifact.artifactId());
|
||||
assertEquals("jar", artifact.extension());
|
||||
assertEquals("custom-classifier", artifact.classifier());
|
||||
assertEquals("0.20.0-SNAPSHOT", artifact.version());
|
||||
assertNull(artifact.uri());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldParseGivenValidFilenameWithNonStandardQualifier() {
|
||||
String fileName = "io_kestra_plugin__plugin-serdes__custom-classifier__0_20_0-RC1-SNAPSHOT.jar";
|
||||
PluginArtifact artifact = PluginArtifact.fromFileName(fileName);
|
||||
|
||||
assertEquals("io.kestra.plugin", artifact.groupId());
|
||||
assertEquals("plugin-serdes", artifact.artifactId());
|
||||
assertEquals("jar", artifact.extension());
|
||||
assertEquals("custom-classifier", artifact.classifier());
|
||||
assertEquals("0.20.0-RC1-SNAPSHOT", artifact.version());
|
||||
assertNull(artifact.uri());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowIllegalArgumentExceptionGivenInvalidFilenameMissingVersion() {
|
||||
String fileName = "io_kestra_plugin__plugin-serdes__custom-classifier.jar";
|
||||
|
||||
@@ -784,4 +784,12 @@ public abstract class AbstractExecutionRepositoryTest {
|
||||
.taskRunList(List.of())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
protected void findAllAsync() {
|
||||
inject();
|
||||
|
||||
List<Execution> executions = executionRepository.findAllAsync(null).collectList().block();
|
||||
assertThat(executions, hasSize(28));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.kestra.core.repositories;
|
||||
|
||||
import io.kestra.core.models.QueryFilter;
|
||||
import io.kestra.core.models.QueryFilter.Field;
|
||||
import io.kestra.core.models.executions.Execution;
|
||||
import io.kestra.core.models.executions.LogEntry;
|
||||
import io.kestra.core.models.executions.statistics.LogStatistics;
|
||||
@@ -8,6 +9,7 @@ import io.kestra.core.utils.IdUtils;
|
||||
import io.micronaut.data.model.Pageable;
|
||||
import io.kestra.core.junit.annotations.KestraTest;
|
||||
import jakarta.inject.Inject;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.slf4j.event.Level;
|
||||
|
||||
@@ -17,6 +19,7 @@ import java.util.List;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@KestraTest
|
||||
@@ -55,7 +58,12 @@ public abstract class AbstractLogRepositoryTest {
|
||||
.field(QueryFilter.Field.MIN_LEVEL)
|
||||
.operation(QueryFilter.Op.EQUALS)
|
||||
.value(Level.WARN)
|
||||
.build());
|
||||
.build(),
|
||||
QueryFilter.builder()
|
||||
.field(Field.START_DATE)
|
||||
.operation(QueryFilter.Op.GREATER_THAN)
|
||||
.value(Instant.now().minus(1, ChronoUnit.HOURS))
|
||||
.build());
|
||||
find = logRepository.find(Pageable.UNPAGED, "doe", filters);
|
||||
assertThat(find.size(), is(0));
|
||||
|
||||
@@ -205,7 +213,7 @@ public abstract class AbstractLogRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void findAsych() {
|
||||
void findAsync() {
|
||||
logRepository.save(logEntry(Level.INFO).build());
|
||||
logRepository.save(logEntry(Level.ERROR).build());
|
||||
logRepository.save(logEntry(Level.WARN).build());
|
||||
@@ -214,18 +222,29 @@ public abstract class AbstractLogRepositoryTest {
|
||||
|
||||
Flux<LogEntry> find = logRepository.findAsync(null, "io.kestra.unittest", Level.INFO, startDate);
|
||||
List<LogEntry> logEntries = find.collectList().block();
|
||||
assertThat(logEntries.size(), is(3));
|
||||
assertThat(logEntries, hasSize(3));
|
||||
|
||||
find = logRepository.findAsync(null, null, Level.ERROR, startDate);
|
||||
logEntries = find.collectList().block();
|
||||
assertThat(logEntries.size(), is(1));
|
||||
assertThat(logEntries, hasSize(1));
|
||||
|
||||
find = logRepository.findAsync(null, "io.kestra.unused", Level.INFO, startDate);
|
||||
logEntries = find.collectList().block();
|
||||
assertThat(logEntries.size(), is(0));
|
||||
assertThat(logEntries, hasSize(0));
|
||||
|
||||
find = logRepository.findAsync(null, null, Level.INFO, startDate.plusSeconds(2));
|
||||
logEntries = find.collectList().block();
|
||||
assertThat(logEntries.size(), is(0));
|
||||
assertThat(logEntries, hasSize(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findAllAsync() {
|
||||
logRepository.save(logEntry(Level.INFO).build());
|
||||
logRepository.save(logEntry(Level.ERROR).build());
|
||||
logRepository.save(logEntry(Level.WARN).build());
|
||||
|
||||
Flux<LogEntry> find = logRepository.findAllAsync(null);
|
||||
List<LogEntry> logEntries = find.collectList().block();
|
||||
assertThat(logEntries, hasSize(3));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import io.kestra.core.models.executions.metrics.Timer;
|
||||
import io.micronaut.data.model.Pageable;
|
||||
import io.kestra.core.junit.annotations.KestraTest;
|
||||
import jakarta.inject.Inject;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Duration;
|
||||
@@ -17,6 +16,7 @@ import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@KestraTest
|
||||
@@ -95,6 +95,20 @@ public abstract class AbstractMetricRepositoryTest {
|
||||
assertThat(tasksWithMetrics.size(), is(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
void findAllAsync() {
|
||||
String executionId = FriendlyId.createFriendlyId();
|
||||
TaskRun taskRun1 = taskRun(executionId, "task");
|
||||
MetricEntry counter = MetricEntry.of(taskRun1, counter("counter"));
|
||||
TaskRun taskRun2 = taskRun(executionId, "task");
|
||||
MetricEntry timer = MetricEntry.of(taskRun2, timer());
|
||||
metricRepository.save(counter);
|
||||
metricRepository.save(timer);
|
||||
|
||||
List<MetricEntry> results = metricRepository.findAllAsync(null).collectList().block();
|
||||
assertThat(results, hasSize(2));
|
||||
}
|
||||
|
||||
private Counter counter(String metricName) {
|
||||
return Counter.of(metricName, 1);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.kestra.core.runners;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import io.kestra.core.junit.annotations.ExecuteFlow;
|
||||
import io.kestra.core.junit.annotations.KestraTest;
|
||||
@@ -10,11 +9,9 @@ import io.kestra.core.junit.annotations.LoadFlows;
|
||||
import io.kestra.core.models.executions.Execution;
|
||||
import io.kestra.core.models.executions.LogEntry;
|
||||
import io.kestra.core.models.flows.State;
|
||||
import io.kestra.core.queues.MessageTooBigException;
|
||||
import io.kestra.core.queues.QueueException;
|
||||
import io.kestra.core.queues.QueueFactoryInterface;
|
||||
import io.kestra.core.queues.QueueInterface;
|
||||
import io.kestra.core.utils.TestsUtils;
|
||||
import io.kestra.plugin.core.flow.EachSequentialTest;
|
||||
import io.kestra.plugin.core.flow.FlowCaseTest;
|
||||
import io.kestra.plugin.core.flow.ForEachItemCaseTest;
|
||||
@@ -23,20 +20,12 @@ import io.kestra.plugin.core.flow.WaitForCaseTest;
|
||||
import io.kestra.plugin.core.flow.WorkingDirectoryTest;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import java.time.Duration;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.junitpioneer.jupiter.RetryingTest;
|
||||
import org.slf4j.event.Level;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@KestraTest(startRunner = true)
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
@@ -370,7 +359,7 @@ public abstract class AbstractRunnerTest {
|
||||
forEachItemCaseTest.forEachItemWithSubflowOutputs();
|
||||
}
|
||||
|
||||
@RetryingTest(5) // Flaky on CI but never locally even with 100 repetitions
|
||||
@Test
|
||||
@LoadFlows({"flows/valids/restart-for-each-item.yaml", "flows/valids/restart-child.yaml"})
|
||||
void restartForEachItem() throws Exception {
|
||||
forEachItemCaseTest.restartForEachItem();
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.event.Level;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
@@ -56,11 +57,11 @@ class RunContextLoggerTest {
|
||||
|
||||
matchingLog = TestsUtils.awaitLogs(logs, 5);
|
||||
receive.blockLast();
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.TRACE)).findFirst().orElse(null).getMessage(), is("trace"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.DEBUG)).findFirst().orElse(null).getMessage(), is("debug"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.INFO)).findFirst().orElse(null).getMessage(), is("info"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.WARN)).findFirst().orElse(null).getMessage(), is("warn"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.ERROR)).findFirst().orElse(null).getMessage(), is("error"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.TRACE)).findFirst().orElseThrow().getMessage(), is("trace"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.DEBUG)).findFirst().orElseThrow().getMessage(), is("debug"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.INFO)).findFirst().orElseThrow().getMessage(), is("info"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.WARN)).findFirst().orElseThrow().getMessage(), is("warn"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.ERROR)).findFirst().orElseThrow().getMessage(), is("error"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -105,17 +106,20 @@ class RunContextLoggerTest {
|
||||
|
||||
runContextLogger.usedSecret("doe.com");
|
||||
runContextLogger.usedSecret("myawesomepass");
|
||||
runContextLogger.usedSecret("http://it-s.secret");
|
||||
runContextLogger.usedSecret(null);
|
||||
|
||||
Logger logger = runContextLogger.logger();
|
||||
// exception are not handle and secret will not be replaced
|
||||
logger.debug("test {} test", "john@doe.com", new Exception("exception from doe.com"));
|
||||
logger.info("test myawesomepassmyawesomepass myawesomepass myawesomepassmyawesomepass");
|
||||
logger.warn("test {}", URI.create("http://it-s.secret"));
|
||||
|
||||
matchingLog = TestsUtils.awaitLogs(logs, 3);
|
||||
receive.blockLast();
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.DEBUG)).findFirst().orElse(null).getMessage(), is("test john@******* test"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.TRACE)).findFirst().orElse(null).getMessage(), containsString("exception from doe.com"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.INFO)).findFirst().orElse(null).getMessage(), is("test **masked****************** ************* **************************"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.DEBUG)).findFirst().orElseThrow().getMessage(), is("test john@******* test"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.TRACE)).findFirst().orElseThrow().getMessage(), containsString("exception from doe.com"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.INFO)).findFirst().orElseThrow().getMessage(), is("test **masked****************** ************* **************************"));
|
||||
assertThat(matchingLog.stream().filter(logEntry -> logEntry.getLevel().equals(Level.WARN)).findFirst().orElseThrow().getMessage(), is("test **masked**********"));
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import io.kestra.core.runners.FlowListeners;
|
||||
import io.kestra.core.utils.Await;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@@ -525,6 +526,7 @@ public class SchedulerScheduleTest extends AbstractSchedulerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("too flaky on CI")
|
||||
void recoverLASTLongRunningExecution() throws Exception {
|
||||
// mock flow listeners
|
||||
FlowListeners flowListenersServiceSpy = spy(this.flowListenersService);
|
||||
@@ -596,6 +598,7 @@ public class SchedulerScheduleTest extends AbstractSchedulerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled("too flaky on CI")
|
||||
void recoverNONELongRunningExecution() throws Exception {
|
||||
// mock flow listeners
|
||||
FlowListeners flowListenersServiceSpy = spy(this.flowListenersService);
|
||||
|
||||
@@ -205,6 +205,26 @@ class FlowServiceTest {
|
||||
assertThat(collect.stream().filter(flow -> flow.getId().equals("test3")).findFirst().orElseThrow().getRevision(), is(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
void warnings() {
|
||||
Flow flow = create("test", "test", 1).toBuilder()
|
||||
.namespace("system")
|
||||
.triggers(List.of(
|
||||
io.kestra.plugin.core.trigger.Flow.builder()
|
||||
.id("flow-trigger")
|
||||
.type(io.kestra.plugin.core.trigger.Flow.class.getName())
|
||||
.build()
|
||||
))
|
||||
.build();
|
||||
|
||||
List<String> warnings = flowService.warnings(flow, null);
|
||||
|
||||
assertThat(warnings.size(), is(1));
|
||||
assertThat(warnings, containsInAnyOrder(
|
||||
"This flow will be triggered for EVERY execution of EVERY flow on your instance. We recommend adding the preconditions property to the Flow trigger 'flow-trigger'."
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
void aliases() {
|
||||
List<FlowService.Relocation> warnings = flowService.relocations("""
|
||||
|
||||
@@ -125,12 +125,13 @@ class MapUtilsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionWhenNestingMapGivenFlattenMapWithConflicts() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||
MapUtils.flattenToNestedMap(Map.of(
|
||||
"k1.k2", "v1",
|
||||
"k1.k2.k3", "v2"
|
||||
));
|
||||
});
|
||||
void shouldReturnMapAndIgnoreConflicts() {
|
||||
Map<String, Object> results = MapUtils.flattenToNestedMap(Map.of(
|
||||
"k1.k2", "v1",
|
||||
"k1.k2.k3", "v2"
|
||||
));
|
||||
|
||||
assertThat(results, aMapWithSize(1));
|
||||
// due to ordering change on each JVM restart, the result map would be different as different entries will be skipped
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static io.kestra.core.models.flows.State.Type.FAILED;
|
||||
import static io.kestra.core.utils.Rethrow.throwRunnable;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
@@ -136,7 +137,6 @@ public class ForEachItemCaseTest {
|
||||
Flux<Execution> receive = TestsUtils.receive(executionQueue, either -> {
|
||||
Execution execution = either.getLeft();
|
||||
if (execution.getFlowId().equals("for-each-item-subflow")) {
|
||||
log.info("Received sub-execution " + execution.getId() + " with status " + execution.getState().getCurrent());
|
||||
if (execution.getState().getCurrent().isTerminated()) {
|
||||
triggered.set(execution);
|
||||
countDownLatch.countDown();
|
||||
@@ -204,8 +204,9 @@ public class ForEachItemCaseTest {
|
||||
// assert on the main flow execution
|
||||
assertThat(execution.getTaskRunList(), hasSize(3));
|
||||
assertThat(execution.getTaskRunList().get(2).getAttempts(), hasSize(1));
|
||||
assertThat(execution.getTaskRunList().get(2).getAttempts().getFirst().getState().getCurrent(), is(State.Type.FAILED));
|
||||
assertThat(execution.getState().getCurrent(), is(State.Type.FAILED));
|
||||
assertThat(execution.getTaskRunList().get(2).getAttempts().getFirst().getState().getCurrent(), is(
|
||||
FAILED));
|
||||
assertThat(execution.getState().getCurrent(), is(FAILED));
|
||||
Map<String, Object> outputs = execution.getTaskRunList().get(2).getOutputs();
|
||||
assertThat(outputs.get("numberOfBatches"), is(26));
|
||||
assertThat(outputs.get("iterations"), notNullValue());
|
||||
@@ -215,7 +216,7 @@ public class ForEachItemCaseTest {
|
||||
assertThat(iterations.get("FAILED"), is(26));
|
||||
|
||||
// assert on the last subflow execution
|
||||
assertThat(triggered.get().getState().getCurrent(), is(State.Type.FAILED));
|
||||
assertThat(triggered.get().getState().getCurrent(), is(FAILED));
|
||||
assertThat(triggered.get().getFlowId(), is("for-each-item-subflow-failed"));
|
||||
assertThat((String) triggered.get().getInputs().get("items"), matchesRegex("kestra:///io/kestra/tests/for-each-item-failed/executions/.*/tasks/each-split/.*\\.txt"));
|
||||
assertThat(triggered.get().getTaskRunList(), hasSize(1));
|
||||
@@ -290,7 +291,7 @@ public class ForEachItemCaseTest {
|
||||
(flow, execution1) -> flowIO.readExecutionInputs(flow, execution1, inputs),
|
||||
Duration.ofSeconds(30));
|
||||
assertThat(execution.getTaskRunList(), hasSize(3));
|
||||
assertThat(execution.getState().getCurrent(), is(State.Type.FAILED));
|
||||
assertThat(execution.getState().getCurrent(), is(FAILED));
|
||||
|
||||
// here we must have 1 failed subflows
|
||||
assertTrue(countDownLatch.await(1, TimeUnit.MINUTES));
|
||||
@@ -303,11 +304,15 @@ public class ForEachItemCaseTest {
|
||||
successLatch.countDown();
|
||||
}
|
||||
});
|
||||
|
||||
//Wait before restarting until the failed execution tasks are persisted.
|
||||
Thread.sleep(1000L);
|
||||
|
||||
Execution restarted = executionService.restart(execution, null);
|
||||
execution = runnerUtils.awaitExecution(
|
||||
e -> e.getState().getCurrent() == State.Type.SUCCESS && e.getFlowId().equals("restart-for-each-item"),
|
||||
throwRunnable(() -> executionQueue.emit(restarted)),
|
||||
Duration.ofSeconds(10)
|
||||
Duration.ofSeconds(20)
|
||||
);
|
||||
assertThat(execution.getTaskRunList(), hasSize(4));
|
||||
assertTrue(successLatch.await(1, TimeUnit.MINUTES));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
version=0.22.0-SNAPSHOT
|
||||
version=0.22.1
|
||||
|
||||
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
org.gradle.parallel=true
|
||||
org.gradle.caching=true
|
||||
org.gradle.priority=low
|
||||
org.gradle.priority=low
|
||||
|
||||
@@ -80,7 +80,7 @@ REM Java options that Kestra engineers think are best for Kestra, they should be
|
||||
REM -XX:MaxRAMPercentage=50.0: configure max heap to 50% of available RAM (default 25%)
|
||||
SET "KESTRA_JAVA_OPTS=-XX:MaxRAMPercentage=50.0"
|
||||
|
||||
java %KESTRA_JAVA_OPTS %JAVA_OPTS% %JAVA_ADD_OPENS% -Djava.security.manager=allow -jar "%this%" %*
|
||||
java %KESTRA_JAVA_OPTS% %JAVA_OPTS% %JAVA_ADD_OPENS% -Djava.security.manager=allow -jar "%this%" %*
|
||||
|
||||
ENDLOCAL
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ import java.util.*;
|
||||
import java.util.Comparator;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcRepository implements ExecutionRepositoryInterface, JdbcQueueIndexerInterface<Execution> {
|
||||
private static final int FETCH_SIZE = 100;
|
||||
@@ -297,7 +298,7 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
|
||||
} else if (field.equals(QueryFilter.Field.LABELS) && value instanceof Map<?, ?> labels)
|
||||
select = select.and(findCondition(labels, operation));
|
||||
else
|
||||
select = getConditionOnField(select, field, value, operation, "\"start_date\"");
|
||||
select = getConditionOnField(select, field, value, operation, "start_date");
|
||||
}
|
||||
|
||||
return select;
|
||||
@@ -343,6 +344,28 @@ public abstract class AbstractJdbcExecutionRepository extends AbstractJdbcReposi
|
||||
return select;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<Execution> findAllAsync(@Nullable String tenantId) {
|
||||
return Flux.create(emitter -> this.jdbcRepository
|
||||
.getDslContextWrapper()
|
||||
.transaction(configuration -> {
|
||||
DSLContext context = DSL.using(configuration);
|
||||
|
||||
SelectConditionStep<Record1<Object>> select = context
|
||||
.select(field("value"))
|
||||
.hint(context.configuration().dialect().supports(SQLDialect.MYSQL) ? "SQL_CALC_FOUND_ROWS" : null)
|
||||
.from(this.jdbcRepository.getTable())
|
||||
.where(this.defaultFilter(tenantId));
|
||||
|
||||
try (Stream<Record1<Object>> stream = select.fetchSize(FETCH_SIZE).stream()){
|
||||
stream.map((Record record) -> jdbcRepository.map(record))
|
||||
.forEach(emitter::next);
|
||||
} finally {
|
||||
emitter.complete();
|
||||
}
|
||||
}), FluxSink.OverflowStrategy.BUFFER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayListTotal<Execution> findByFlowId(String tenantId, String namespace, String id, Pageable pageable) {
|
||||
return this.jdbcRepository
|
||||
|
||||
@@ -183,6 +183,28 @@ public abstract class AbstractJdbcLogRepository extends AbstractJdbcRepository i
|
||||
}), FluxSink.OverflowStrategy.BUFFER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<LogEntry> findAllAsync(@Nullable String tenantId) {
|
||||
return Flux.create(emitter -> this.jdbcRepository
|
||||
.getDslContextWrapper()
|
||||
.transaction(configuration -> {
|
||||
DSLContext context = DSL.using(configuration);
|
||||
|
||||
SelectConditionStep<Record1<Object>> select = context
|
||||
.select(field("value"))
|
||||
.hint(context.configuration().dialect().supports(SQLDialect.MYSQL) ? "SQL_CALC_FOUND_ROWS" : null)
|
||||
.from(this.jdbcRepository.getTable())
|
||||
.where(this.defaultFilter(tenantId));
|
||||
|
||||
try (Stream<Record1<Object>> stream = select.fetchSize(FETCH_SIZE).stream()){
|
||||
stream.map((Record record) -> jdbcRepository.map(record))
|
||||
.forEach(emitter::next);
|
||||
} finally {
|
||||
emitter.complete();
|
||||
}
|
||||
}), FluxSink.OverflowStrategy.BUFFER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LogStatistics> statistics(
|
||||
@Nullable String query,
|
||||
|
||||
@@ -18,6 +18,8 @@ import lombok.Getter;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.*;
|
||||
import org.jooq.impl.DSL;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.FluxSink;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.ZoneId;
|
||||
@@ -27,6 +29,7 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public abstract class AbstractJdbcMetricRepository extends AbstractJdbcRepository implements MetricRepositoryInterface {
|
||||
protected io.kestra.jdbc.AbstractJdbcRepository<MetricEntry> jdbcRepository;
|
||||
@@ -92,6 +95,28 @@ public abstract class AbstractJdbcMetricRepository extends AbstractJdbcRepositor
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<MetricEntry> findAllAsync(@io.micronaut.core.annotation.Nullable String tenantId) {
|
||||
return Flux.create(emitter -> this.jdbcRepository
|
||||
.getDslContextWrapper()
|
||||
.transaction(configuration -> {
|
||||
DSLContext context = DSL.using(configuration);
|
||||
|
||||
SelectConditionStep<Record1<Object>> select = context
|
||||
.select(field("value"))
|
||||
.hint(context.configuration().dialect().supports(SQLDialect.MYSQL) ? "SQL_CALC_FOUND_ROWS" : null)
|
||||
.from(this.jdbcRepository.getTable())
|
||||
.where(this.defaultFilter(tenantId));
|
||||
|
||||
try (Stream<Record1<Object>> stream = select.fetchSize(FETCH_SIZE).stream()){
|
||||
stream.map((Record record) -> jdbcRepository.map(record))
|
||||
.forEach(emitter::next);
|
||||
} finally {
|
||||
emitter.complete();
|
||||
}
|
||||
}), FluxSink.OverflowStrategy.BUFFER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> flowMetrics(
|
||||
String tenantId,
|
||||
|
||||
@@ -381,7 +381,7 @@ public abstract class AbstractJdbcRepository {
|
||||
};
|
||||
}
|
||||
protected Condition statesFilter(List<State.Type> state) {
|
||||
return DSL.field(DSL.quotedName("state_current"))
|
||||
return field("state_current")
|
||||
.in(state.stream().map(Enum::name).toList());
|
||||
}
|
||||
|
||||
@@ -390,8 +390,8 @@ public abstract class AbstractJdbcRepository {
|
||||
ChildFilter childFilter = (value instanceof String val)? ChildFilter.valueOf(val) : (ChildFilter) value;
|
||||
|
||||
return switch (childFilter) {
|
||||
case CHILD -> select.and(DSL.field(DSL.quotedName("trigger_execution_id")).isNotNull());
|
||||
case MAIN -> select.and(DSL.field(DSL.quotedName("trigger_execution_id")).isNull());
|
||||
case CHILD -> select.and(field("trigger_execution_id").isNotNull());
|
||||
case MAIN -> select.and(field("trigger_execution_id").isNull());
|
||||
};
|
||||
}
|
||||
|
||||
@@ -423,12 +423,12 @@ public abstract class AbstractJdbcRepository {
|
||||
SelectConditionStep<T> select, OffsetDateTime dateTime, QueryFilter.Op operation,String fieldName
|
||||
) {
|
||||
switch (operation) {
|
||||
case LESS_THAN -> select = select.and(DSL.field(fieldName).lessThan(dateTime));
|
||||
case LESS_THAN_OR_EQUAL_TO -> select = select.and(DSL.field(fieldName).lessOrEqual(dateTime));
|
||||
case GREATER_THAN -> select = select.and(DSL.field(fieldName).greaterThan(dateTime));
|
||||
case GREATER_THAN_OR_EQUAL_TO -> select = select.and(DSL.field(fieldName).greaterOrEqual(dateTime));
|
||||
case EQUALS -> select = select.and(DSL.field(fieldName).eq(dateTime));
|
||||
case NOT_EQUALS -> select = select.and(DSL.field(fieldName).ne(dateTime));
|
||||
case LESS_THAN -> select = select.and(field(fieldName).lessThan(dateTime));
|
||||
case LESS_THAN_OR_EQUAL_TO -> select = select.and(field(fieldName).lessOrEqual(dateTime));
|
||||
case GREATER_THAN -> select = select.and(field(fieldName).greaterThan(dateTime));
|
||||
case GREATER_THAN_OR_EQUAL_TO -> select = select.and(field(fieldName).greaterOrEqual(dateTime));
|
||||
case EQUALS -> select = select.and(field(fieldName).eq(dateTime));
|
||||
case NOT_EQUALS -> select = select.and(field(fieldName).ne(dateTime));
|
||||
default -> throw new UnsupportedOperationException("Unsupported operation for date condition: " + operation);
|
||||
}
|
||||
return select;
|
||||
|
||||
@@ -122,7 +122,7 @@ public abstract class AbstractJdbcServiceInstanceRepository extends AbstractJdbc
|
||||
.where(STATE.in(states.stream().map(Enum::name).toList()));
|
||||
|
||||
return isForUpdate ?
|
||||
this.jdbcRepository.fetch(query.forUpdate()) :
|
||||
this.jdbcRepository.fetch(query.forUpdate().skipLocked()) :
|
||||
this.jdbcRepository.fetch(query);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ public abstract class AbstractJdbcServiceInstanceRepository extends AbstractJdbc
|
||||
.where(STATE.notIn(Service.ServiceState.CREATED.name(), Service.ServiceState.RUNNING.name()));
|
||||
|
||||
return isForUpdate ?
|
||||
this.jdbcRepository.fetch(query.forUpdate()) :
|
||||
this.jdbcRepository.fetch(query.forUpdate().skipLocked()) :
|
||||
this.jdbcRepository.fetch(query);
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ public abstract class AbstractJdbcServiceInstanceRepository extends AbstractJdbc
|
||||
.where(STATE.eq(Service.ServiceState.NOT_RUNNING.name()));
|
||||
|
||||
return isForUpdate ?
|
||||
this.jdbcRepository.fetch(query.forUpdate()) :
|
||||
this.jdbcRepository.fetch(query.forUpdate().skipLocked()) :
|
||||
this.jdbcRepository.fetch(query);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ dependencies {
|
||||
// ugly hack on crypto plugin
|
||||
api("org.bouncycastle:bcprov-jdk18on:$bouncycastleVersion")
|
||||
api("org.bouncycastle:bcpg-jdk18on:$bouncycastleVersion")
|
||||
api("org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion")
|
||||
// ugly hack for jackson: as enforcing platform didn't work (it didn't enforce everywhere, not in plugins), we had to force all jackson libs individually.
|
||||
api("com.fasterxml.jackson.core:jackson-core:$jacksonVersion")
|
||||
api("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion")
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 439 309" style="enable-background:new 0 0 439 309;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#1D63ED;}
|
||||
</style>
|
||||
<path class="st0" d="M379.6,111.7c-2.3-16.7-11.5-31.2-28.1-44.3l-9.6-6.5l-6.4,9.7c-8.2,12.5-12.3,29.9-11,46.6
|
||||
c0.6,5.8,2.5,16.4,8.4,25.5c-5.9,3.3-17.6,7.7-33.2,7.4H1.7l-0.6,3.5c-2.8,16.7-2.8,69,30.7,109.1c25.5,30.5,63.6,46,113.4,46
|
||||
c108,0,187.8-50.3,225.3-141.9c14.7,0.3,46.4,0.1,62.7-31.4c0.4-0.7,1.4-2.6,4.2-8.6l1.6-3.3l-9.1-6.2
|
||||
C419.9,110.8,397.2,108.3,379.6,111.7L379.6,111.7z M240,0h-45.3v41.7H240V0z M240,50.1h-45.3v41.7H240V50.1z M186.4,50.1h-45.3
|
||||
v41.7h45.3V50.1z M132.9,50.1H87.6v41.7h45.3V50.1z M79.3,100.2H34v41.7h45.3V100.2z M132.9,100.2H87.6v41.7h45.3V100.2z
|
||||
M186.4,100.2h-45.3v41.7h45.3V100.2z M240,100.2h-45.3v41.7H240V100.2z M293.6,100.2h-45.3v41.7h45.3V100.2z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -31,6 +31,7 @@ The table below describes all these properties in detail.
|
||||
| `sla` | The list of [SLA conditions](https://kestra.io/docs/workflow-components/sla) specifying an execution `behavior` if the workflow doesn't satisfy the assertion defined in the SLA. This feature is currently in Beta so some properties might change in the next releases. |
|
||||
| `errors` | The list of [error tasks](https://kestra.io/docs/workflow-components/errors) that will run if there is an error in the current execution. |
|
||||
| `finally` | The list of [finally tasks](https://kestra.io/docs/workflow-components/finally) that will run after the workflow is complete. These tasks will run regardless of whether the workflow was successful or not. |
|
||||
| `afterExecution` | The list of [afterExecution](https://kestra.io/docs/workflow-components/afterexecution) tasks that will run after the workflow is complete. These tasks will run after execution of the workflow reaches a final state, including the execution of the finally tasks. |
|
||||
| `disabled` | Set it to `true` to temporarily [disable](https://kestra.io/docs/workflow-components/disabled) any new executions of the flow. This is useful when you want to stop a flow from running (even manually) without deleting it. Once you set this property to true, nobody will be able to trigger any execution of that flow, whether from the UI or via an API call, until the flow is reenabled by setting this property back to `false` (default behavior) or by deleting this property. |
|
||||
| `revision` | The [flow version](https://kestra.io/docs/concepts/revision), managed internally by Kestra, and incremented upon each modification. You should **not** manually set it. |
|
||||
| `triggers` | The list of [triggers](https://kestra.io/docs/workflow-components/triggers) which automatically start a flow execution based on events, such as a scheduled date, a new file arrival, a new message in a queue, or the completion event of another flow's execution. |
|
||||
@@ -149,6 +150,16 @@ tasks:
|
||||
type: io.kestra.plugin.core.debug.Return
|
||||
format: fallback output
|
||||
|
||||
finally:
|
||||
- id: finally_log
|
||||
type: io.kestra.plugin.core.log.Log
|
||||
message: "This task runs after all the tasks are run, irrespective of whether the tasks ran successfully or failed. Execution {{ execution.state }}" # Execution RUNNING
|
||||
|
||||
afterExecution:
|
||||
- id: afterExecution_log
|
||||
type: io.kestra.plugin.core.log.Log
|
||||
message: "This task runs after the flow execution is complete. Execution {{ execution.state }}" # Execution FAILED / SUCCESS
|
||||
|
||||
outputs:
|
||||
- id: flow_output
|
||||
type: STRING
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
import Utils from "../utils/utils";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<span v-if="required" class="me-1 text-danger">*</span>
|
||||
<span v-if="label" class="label">{{ label }}</span>
|
||||
<label v-if="label" class="label" :for="uid">{{ label }}</label>
|
||||
<div class="mt-1 mb-2 wrapper" :class="props.class">
|
||||
<el-input
|
||||
v-model="input"
|
||||
@input="handleInput"
|
||||
:id="uid"
|
||||
:placeholder
|
||||
:disabled
|
||||
type="textarea"
|
||||
@@ -14,10 +14,12 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref, watch} from "vue";
|
||||
import {useId, computed} from "vue";
|
||||
|
||||
defineOptions({inheritAttrs: false});
|
||||
|
||||
const uid = useId();
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const props = defineProps({
|
||||
modelValue: {type: [String, Number, Boolean], default: undefined},
|
||||
@@ -28,20 +30,12 @@
|
||||
class: {type: String, default: undefined},
|
||||
});
|
||||
|
||||
const input = ref(props.modelValue);
|
||||
|
||||
const handleInput = (value: string) => {
|
||||
emits("update:modelValue", value);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
if (newValue !== input.value) {
|
||||
input.value = newValue;
|
||||
}
|
||||
const input = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emits("update:modelValue", value);
|
||||
},
|
||||
);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -112,11 +112,12 @@
|
||||
>
|
||||
<PluginDocumentation
|
||||
v-if="currentView === views.DOC"
|
||||
class="plugin-doc combined-right-view enhance-readability"
|
||||
class="combined-right-view enhance-readability"
|
||||
:override-intro="intro"
|
||||
absolute
|
||||
/>
|
||||
<div
|
||||
class="d-flex justify-content-center align-items-center w-100 p-5"
|
||||
class="d-flex justify-content-center align-items-center w-100 p-3"
|
||||
v-else-if="currentView === views.CHART"
|
||||
>
|
||||
<div v-if="selectedChart" class="w-100">
|
||||
@@ -129,7 +130,7 @@
|
||||
<small>{{ selectedChart.chartOptions.description }}</small>
|
||||
</p>
|
||||
|
||||
<div class="w-100">
|
||||
<div :style="`position: relative; width:calc(${100}% - 10px)`">
|
||||
<component
|
||||
:key="selectedChart.id"
|
||||
:is="types[selectedChart.type]"
|
||||
@@ -171,6 +172,8 @@
|
||||
defineEmits(["save"])
|
||||
</script>
|
||||
<script>
|
||||
import {shallowRef} from "vue";
|
||||
|
||||
import Editor from "../../inputs/Editor.vue";
|
||||
import yaml from "yaml";
|
||||
import ContentSave from "vue-material-design-icons/ContentSave.vue";
|
||||
@@ -312,11 +315,11 @@
|
||||
charts: [],
|
||||
chartError: null,
|
||||
types: {
|
||||
"io.kestra.plugin.core.dashboard.chart.TimeSeries": TimeSeries,
|
||||
"io.kestra.plugin.core.dashboard.chart.Bar": Bar,
|
||||
"io.kestra.plugin.core.dashboard.chart.Markdown": Markdown,
|
||||
"io.kestra.plugin.core.dashboard.chart.Table": Table,
|
||||
"io.kestra.plugin.core.dashboard.chart.Pie": Pie,
|
||||
"io.kestra.plugin.core.dashboard.chart.TimeSeries": shallowRef(TimeSeries),
|
||||
"io.kestra.plugin.core.dashboard.chart.Bar": shallowRef(Bar),
|
||||
"io.kestra.plugin.core.dashboard.chart.Markdown": shallowRef(Markdown),
|
||||
"io.kestra.plugin.core.dashboard.chart.Table": shallowRef(Table),
|
||||
"io.kestra.plugin.core.dashboard.chart.Pie": shallowRef(Pie),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
import Pencil from "vue-material-design-icons/Pencil.vue";
|
||||
import Plus from "vue-material-design-icons/Plus.vue";
|
||||
import ViewDashboardEdit from "vue-material-design-icons/ViewDashboardEdit.vue";
|
||||
import useRouteContext from "../../../mixins/useRouteContext.js";
|
||||
|
||||
const store = useStore();
|
||||
const {t} = useI18n({useScope: "global"});
|
||||
@@ -72,4 +73,6 @@
|
||||
const routeInfo = computed(() => ({
|
||||
title: props.title ?? t("homeDashboard.title"),
|
||||
}));
|
||||
|
||||
useRouteContext(routeInfo);
|
||||
</script>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
defineOptions({inheritAttrs: false});
|
||||
const props = defineProps({
|
||||
identifier: {type: Number, required: true},
|
||||
identifier: {type: [Number, String], required: true},
|
||||
chart: {type: Object, required: true},
|
||||
isPreview: {type: Boolean, required: false, default: false}
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
defineOptions({inheritAttrs: false});
|
||||
const props = defineProps({
|
||||
identifier: {type: Number, required: true},
|
||||
identifier: {type: [Number, String], required: true},
|
||||
chart: {type: Object, required: true},
|
||||
isPreview: {type: Boolean, required: false, default: false}
|
||||
});
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
defineOptions({inheritAttrs: false});
|
||||
const props = defineProps({
|
||||
identifier: {type: Number, required: true},
|
||||
identifier: {type: [Number, String], required: true},
|
||||
chart: {type: Object, required: true},
|
||||
isPreview: {type: Boolean, required: false, default: false}
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
defineOptions({inheritAttrs: false});
|
||||
const props = defineProps({
|
||||
identifier: {type: Number, required: true},
|
||||
identifier: {type: [Number, String], required: true},
|
||||
chart: {type: Object, required: true},
|
||||
isPreview: {type: Boolean, required: false, default: false}
|
||||
});
|
||||
|
||||
34
ui/src/components/demo/DemoButtons.vue
Normal file
34
ui/src/components/demo/DemoButtons.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div>
|
||||
<a class="el-button el-button--large el-button--primary" target="_blank" :href="getADemoUrl.href">
|
||||
{{ $t("demos.get_a_demo_button") }}
|
||||
</a>
|
||||
<el-button size="large" @click="store.commit('misc/setContextInfoBarOpenTab', 'docs')">
|
||||
Learn More
|
||||
<el-icon class="el-icon--right">
|
||||
<ArrowRightIcon />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ArrowRightIcon from "vue-material-design-icons/ArrowRight.vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {useStore} from "vuex";
|
||||
import {computed} from "vue";
|
||||
|
||||
const store = useStore();
|
||||
const route = useRoute();
|
||||
|
||||
const getADemoUrl = computed(() => {
|
||||
const demoUrl = new URL("https://kestra.io/demo");
|
||||
// set all utm params from the route query
|
||||
for (const [key, value] of Object.entries(route.query)) {
|
||||
if (key.startsWith("utm_")) {
|
||||
demoUrl.searchParams.set(key, value as string);
|
||||
}
|
||||
}
|
||||
return demoUrl;
|
||||
});
|
||||
</script>
|
||||
@@ -8,39 +8,14 @@
|
||||
</div>
|
||||
<h2>{{ title }}</h2>
|
||||
<p><slot name="message" /></p>
|
||||
<a class="el-button el-button--large el-button--primary" target="_blank" :href="getADemoUrl.href">
|
||||
{{ $t("demos.get_a_demo_button") }}
|
||||
</a>
|
||||
<el-button size="large" @click="store.commit('misc/setContextInfoBarOpenTab', 'docs')">
|
||||
Learn More
|
||||
<el-icon class="el-icon--right">
|
||||
<ArrowRightIcon />
|
||||
</el-icon>
|
||||
</el-button>
|
||||
<DemoButtons />
|
||||
</div>
|
||||
</EmptyTemplate>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import {computed} from "vue";
|
||||
import {useStore} from "vuex";
|
||||
import {useRoute} from "vue-router";
|
||||
import ArrowRightIcon from "vue-material-design-icons/ArrowRight.vue";
|
||||
import EmptyTemplate from "../layout/EmptyTemplate.vue";
|
||||
|
||||
const store = useStore();
|
||||
const route = useRoute();
|
||||
|
||||
const getADemoUrl = computed(() => {
|
||||
const demoUrl = new URL("https://kestra.io/demo");
|
||||
// set all utm params from the route query
|
||||
for (const [key, value] of Object.entries(route.query)) {
|
||||
if (key.startsWith("utm_")) {
|
||||
demoUrl.searchParams.set(key, value as string);
|
||||
}
|
||||
}
|
||||
return demoUrl;
|
||||
});
|
||||
import DemoButtons from "./DemoButtons.vue";
|
||||
|
||||
defineProps<{
|
||||
title: string;
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
<editor
|
||||
ref="debugEditor"
|
||||
:full-height="false"
|
||||
:custom-height="20"
|
||||
:input="true"
|
||||
:navbar="false"
|
||||
:model-value="computedDebugValue"
|
||||
@@ -100,6 +101,7 @@
|
||||
:read-only="true"
|
||||
:input="true"
|
||||
:full-height="false"
|
||||
:custom-height="20"
|
||||
:navbar="false"
|
||||
:model-value="debugExpression"
|
||||
:lang="isJSON ? 'json' : ''"
|
||||
|
||||
@@ -201,7 +201,7 @@
|
||||
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {useStore} from "vuex";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import {useRoute, useRouter, LocationQueryRaw} from "vue-router";
|
||||
import {useFilters} from "./composables/useFilters";
|
||||
import action from "../../models/action";
|
||||
import permission from "../../models/permission";
|
||||
@@ -632,21 +632,9 @@
|
||||
|
||||
watch(
|
||||
() => route.query,
|
||||
(q: any) => {
|
||||
// Handling change of label filters from direct click events
|
||||
if (
|
||||
Object.keys(q).length === 0 ||
|
||||
Object.keys(q).some((key) => key.startsWith("filters[labels]"))
|
||||
) {
|
||||
const routeFilters = decodeParams(
|
||||
route.name,
|
||||
q,
|
||||
props.include,
|
||||
OPTIONS,
|
||||
props.isDefaultDashboard
|
||||
);
|
||||
currentFilters.value = routeFilters;
|
||||
}
|
||||
(q: LocationQueryRaw) => {
|
||||
const routeFilters = decodeParams(route.name, q, props.include, OPTIONS, props.isDefaultDashboard) as CurrentItem[];
|
||||
currentFilters.value = routeFilters;
|
||||
},
|
||||
{immediate: true},
|
||||
);
|
||||
@@ -736,7 +724,7 @@
|
||||
|
||||
const handleClickedItems = (value) => {
|
||||
if (value) currentFilters.value = value;
|
||||
select.value?.focus();
|
||||
triggerSearch();
|
||||
};
|
||||
|
||||
const triggerSearch = () => {
|
||||
|
||||
@@ -41,14 +41,20 @@
|
||||
class="me-2"
|
||||
>
|
||||
<span class="small">
|
||||
<Label :option="value" />
|
||||
<Label :option="value" :prefix="props.prefix" />
|
||||
</span>
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<DeleteOutline @click.stop="remove(index)" />
|
||||
<KestraIcon
|
||||
@click.stop="remove(index)"
|
||||
:tooltip="$t('filters.save.remove')"
|
||||
placement="right"
|
||||
>
|
||||
<DeleteOutline />
|
||||
</KestraIcon>
|
||||
</div>
|
||||
</div>
|
||||
</el-dropdown-item>
|
||||
@@ -96,10 +102,15 @@
|
||||
@import "../styles/filter";
|
||||
|
||||
.dropdown {
|
||||
width: 400px;
|
||||
width: 800px;
|
||||
|
||||
&:hover {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.items {
|
||||
background-color: var(--el-bg-color-overlay);
|
||||
max-height: 170px !important; // 5 visible items
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -15,8 +15,9 @@ $filters-font-xs: var(--el-font-size-extra-small);
|
||||
|
||||
.items {
|
||||
.el-tag {
|
||||
background: $filters-border-color;
|
||||
color: $filters-gray-900;
|
||||
padding: 0;
|
||||
color: var(--ks-tag-content);
|
||||
background: var(--ks-tag-background-active);
|
||||
}
|
||||
|
||||
.small {
|
||||
|
||||
@@ -121,22 +121,22 @@ export const encodeSearchParams = (filters, OPTIONS) => {
|
||||
};
|
||||
|
||||
return filters.reduce((query, filter) => {
|
||||
if(filter.field === "labels" && filter.operation) {
|
||||
Object.assign(query, encode(filter.value, "labels", "EQUALS"));
|
||||
}
|
||||
if(filter.operation) {
|
||||
Object.assign(query, encode(filter.value, filter.field, filter.operation));
|
||||
} else {
|
||||
const match = OPTIONS.find((o) => o.value.label === filter.label);
|
||||
const key = match ? match.key : filter.label === "text" ? "q" : null;
|
||||
const operation = filter.comparator?.value || match?.comparators?.find(c => c.value === filter.operation)?.value || "EQUALS";
|
||||
|
||||
const match = OPTIONS.find((o) => o.value.label === filter.label);
|
||||
const key = match ? match.key : filter.label === "text" ? "q" : null;
|
||||
const operation = filter.comparator?.value || match?.comparators?.find(c => c.value === filter.operation)?.value || "EQUALS";
|
||||
|
||||
if (key) {
|
||||
if (key !== "date") {
|
||||
Object.assign(query, encode(filter.value, key, operation));
|
||||
} else if (filter.value?.length > 0) {
|
||||
const {startDate, endDate} = filter.value[0];
|
||||
if(startDate && endDate) {
|
||||
query["filters[startDate][GREATER_THAN_OR_EQUAL_TO]"] = startDate;
|
||||
query["filters[endDate][LESS_THAN_OR_EQUAL_TO]"] = endDate;
|
||||
if (key) {
|
||||
if (key !== "date") {
|
||||
Object.assign(query, encode(filter.value, key, operation));
|
||||
} else if (filter.value?.length > 0) {
|
||||
const {startDate, endDate} = filter.value[0];
|
||||
if(startDate && endDate) {
|
||||
query["filters[startDate][GREATER_THAN_OR_EQUAL_TO]"] = startDate;
|
||||
query["filters[endDate][LESS_THAN_OR_EQUAL_TO]"] = endDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
</el-card>
|
||||
<template v-if="blueprint.description">
|
||||
<h4>{{ $t('about_this_blueprint') }}</h4>
|
||||
<div v-if="!system" class="tags text-uppercase">
|
||||
<div class="tags text-uppercase">
|
||||
<div v-for="(tag, index) in blueprint.tags" :key="index" class="tag-box">
|
||||
<el-tag type="info" size="small">
|
||||
{{ tag }}
|
||||
@@ -130,6 +130,10 @@
|
||||
type: String,
|
||||
default: "flow",
|
||||
},
|
||||
combinedView: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
@@ -153,7 +157,11 @@
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
this.$store.dispatch("blueprints/getBlueprint", {type: this.$route.params.tab, kind: this.blueprintKind, id: this.blueprintId})
|
||||
this.$store.dispatch("blueprints/getBlueprint", {
|
||||
type: this.combinedView ? this.blueprintType : this.$route.params.tab,
|
||||
kind: this.blueprintKind,
|
||||
id: this.blueprintId
|
||||
})
|
||||
.then(data => {
|
||||
this.blueprint = data;
|
||||
if (this.kind === "flow") {
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<InputText
|
||||
:model-value="YamUtils.stringify(element)"
|
||||
:model-value="element"
|
||||
@update:model-value="(v) => handleInput(v, index)"
|
||||
:placeholder="$t('value')"
|
||||
class="w-100"
|
||||
@@ -35,7 +35,11 @@
|
||||
defineOptions({inheritAttrs: false});
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const props = defineProps({modelValue: {type: Array, default: undefined}});
|
||||
const props = withDefaults(defineProps<{
|
||||
modelValue?: (string | number | boolean | undefined)[]
|
||||
}>(), {
|
||||
modelValue: undefined
|
||||
});
|
||||
|
||||
const items = ref(
|
||||
!Array.isArray(props.modelValue) ? [props.modelValue] : props.modelValue,
|
||||
|
||||
@@ -37,11 +37,14 @@
|
||||
import {computed, getCurrentInstance} from "vue";
|
||||
import {useStore} from "vuex"
|
||||
import {useRouter, useRoute} from "vue-router";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import EditorButtons from "./EditorButtons.vue";
|
||||
import ValidationError from "../flows/ValidationError.vue";
|
||||
|
||||
import localUtils from "../../utils/utils";
|
||||
|
||||
const {t} = useI18n();
|
||||
|
||||
const exportYaml = () => {
|
||||
const blob = new Blob([store.getters["flow/flowYaml"]], {type: "text/yaml"});
|
||||
localUtils.downloadUrl(window.URL.createObjectURL(blob), "flow.yaml");
|
||||
@@ -57,12 +60,33 @@
|
||||
const isAllowedEdit = computed(() => store.getters["flow/isAllowedEdit"])
|
||||
const flowHaveTasks = computed(() => store.getters["flow/flowHaveTasks"])
|
||||
const flowErrors = computed(() => store.getters["flow/flowErrors"])
|
||||
const flowWarnings = computed(() => store.getters["flow/flowWarnings"])
|
||||
const flowInfos = computed(() => store.getters["flow/flowInfos"])
|
||||
const flowParsed = computed(() => store.getters["flow/flow"])
|
||||
const tabs = computed<{dirty:boolean}[]>(() => store.state.editor.tabs)
|
||||
const metadata = computed(() => store.state.flow.metadata);
|
||||
const toast = getCurrentInstance().appContext.config.globalProperties.$toast();
|
||||
const toast = getCurrentInstance()?.appContext.config.globalProperties.$toast();
|
||||
const flowWarnings = computed(() => {
|
||||
|
||||
const outdatedWarning =
|
||||
store.state.flow.flowValidation?.outdated && !store.state.flow.isCreating
|
||||
? [store.getters["flow/outdatedMessage"]]
|
||||
: [];
|
||||
|
||||
const deprecationWarnings =
|
||||
store.state.flow.flowValidation?.deprecationPaths?.map(
|
||||
(f: string) => `${f} ${t("is deprecated")}.`
|
||||
) ?? [];
|
||||
|
||||
const otherWarnings = store.state.flow.flowValidation?.warnings ?? [];
|
||||
|
||||
const warnings = [
|
||||
...outdatedWarning,
|
||||
...deprecationWarnings,
|
||||
...otherWarnings,
|
||||
];
|
||||
|
||||
return warnings.length === 0 ? undefined : warnings;
|
||||
});
|
||||
|
||||
async function save(){
|
||||
await store.dispatch("flow/saveAll")
|
||||
|
||||
@@ -1148,7 +1148,7 @@
|
||||
height: 30px;
|
||||
padding: 16px;
|
||||
font-size: var(--el-font-size-small);
|
||||
color: $gray-900;
|
||||
color: var(--ks-content-primary);
|
||||
|
||||
&:hover {
|
||||
color: var(--ks-content-secondary);
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
v-if="viewType === editorViewTypes.SOURCE_BLUEPRINTS"
|
||||
class="combined-right-view enhance-readability"
|
||||
>
|
||||
<Blueprints @loaded="blueprintsLoaded = true" embed kind="flow" />
|
||||
<Blueprints @loaded="blueprintsLoaded = true" embed kind="flow" combined-view />
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -560,7 +560,31 @@
|
||||
|
||||
const baseOutdatedTranslationKey = computed(() => store.getters["flow/baseOutdatedTranslationKey"]);
|
||||
const flowErrors = computed(() => store.getters["flow/flowErrors"]);
|
||||
const flowWarnings = computed(() => store.getters["flow/flowWarnings"]);
|
||||
const flowWarnings = computed(() => {
|
||||
if (isFlow.value) {
|
||||
const outdatedWarning =
|
||||
store.state.flow.flowValidation?.outdated && !store.state.flow.isCreating
|
||||
? [store.getters["flow/outdatedMessage"]]
|
||||
: [];
|
||||
|
||||
const deprecationWarnings =
|
||||
store.state.flow.flowValidation?.deprecationPaths?.map(
|
||||
(f) => `${f} ${t("is deprecated")}.`
|
||||
) ?? [];
|
||||
|
||||
const otherWarnings = store.state.flow.flowValidation?.warnings ?? [];
|
||||
|
||||
const warnings = [
|
||||
...outdatedWarning,
|
||||
...deprecationWarnings,
|
||||
...otherWarnings,
|
||||
];
|
||||
|
||||
return warnings.length === 0 ? undefined : warnings;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
const flowInfos = computed(() => store.getters["flow/flowInfos"]);
|
||||
const flowHaveTasks = computed(() => store.getters["flow/flowHaveTasks"]);
|
||||
|
||||
@@ -862,11 +886,11 @@
|
||||
|
||||
const onUpdateMetadata = (event, shouldSave) => {
|
||||
if(shouldSave) {
|
||||
metadata.value = {...metadata.value, ...(event.concurrency?.limit === 0 ? {concurrency: null} : event)};
|
||||
onSaveMetadata();
|
||||
validateFlow(flowYaml.value)
|
||||
store.commit("flow/setMetadata", {...metadata.value, ...(event.concurrency?.limit === 0 ? {concurrency: null} : event)});
|
||||
store.dispatch("flow/onSaveMetadata");
|
||||
store.dispatch("flow/validateFlow", {flow: flowYaml.value});
|
||||
} else {
|
||||
metadata.value = event.concurrency?.limit === 0 ? {concurrency: null} : event;
|
||||
store.commit("flow/setMetadata", event.concurrency?.limit === 0 ? {concurrency: null} : event);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -875,22 +899,6 @@
|
||||
isEditMetadataOpen.value = false;
|
||||
};
|
||||
|
||||
const validateFlow = (flow) => {
|
||||
if(!flow) return;
|
||||
|
||||
return store
|
||||
.dispatch("flow/validateFlow", {flow})
|
||||
.then((value) => {
|
||||
if (validationDomElement.value && editorDomElement.value) {
|
||||
validationDomElement.value.onResize(
|
||||
editorDomElement.value.$el.offsetWidth
|
||||
);
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
};
|
||||
|
||||
const handleReorder = (yaml) => {
|
||||
store.commit("flow/setFlowYaml", yaml);
|
||||
store.commit("flow/setHaveChange", true)
|
||||
@@ -953,7 +961,7 @@
|
||||
|
||||
const save = async () => {
|
||||
const result = await store.dispatch("flow/save", {
|
||||
content: editorDomElement.value.$refs.monacoEditor.value,
|
||||
content: editorDomElement.value?.$refs.monacoEditor.value ?? flowYaml.value,
|
||||
})
|
||||
if(result === "redirect_to_update"){
|
||||
await router.push({
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
this.initMonaco(monaco)
|
||||
})
|
||||
|
||||
if (!this.monacoYamlConfigured && (this.creating || this.current?.flow)) {
|
||||
if (!this.monacoYamlConfigured && this.language === "yaml") {
|
||||
this.$store.commit("core/setMonacoYamlConfigured", true);
|
||||
configureMonacoYaml(monaco, {
|
||||
enableSchemaRequest: true,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<KestraFilter :placeholder="$t('search')" :search-callback="(input) => search = input" :decode="false" />
|
||||
<section class="d-inline-flex mb-3 filters">
|
||||
<el-input v-model="search" :placeholder="$t('search')" />
|
||||
</section>
|
||||
|
||||
<select-table
|
||||
:data="filteredKvs"
|
||||
@@ -190,7 +192,6 @@
|
||||
import ContentSave from "vue-material-design-icons/ContentSave.vue";
|
||||
import TimeSelect from "../executions/date-select/TimeSelect.vue";
|
||||
import Check from "vue-material-design-icons/Check.vue";
|
||||
import KestraFilter from "../filter/KestraFilter.vue";
|
||||
import NamespaceSelect from "../namespace/NamespaceSelect.vue";
|
||||
|
||||
import Utils from "../../utils/utils";
|
||||
@@ -258,6 +259,13 @@
|
||||
if (this.$refs.form) {
|
||||
this.$refs.form.clearValidate("value");
|
||||
}
|
||||
},
|
||||
search(newValue) {
|
||||
if (newValue !== undefined) {
|
||||
this.$router.push({query: {
|
||||
q: newValue
|
||||
}})
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -272,7 +280,7 @@
|
||||
},
|
||||
kvs: undefined,
|
||||
namespaceIterator: undefined,
|
||||
search: "",
|
||||
search: this.$route.query?.q ?? "",
|
||||
rules: {
|
||||
key: [
|
||||
{required: true, trigger: "change"},
|
||||
@@ -358,6 +366,10 @@
|
||||
|
||||
this.kvs = this.kvs?.concat(kvFetch) ?? kvFetch;
|
||||
|
||||
if (this.filteredKvs.length === 0) {
|
||||
return this.fetchKvs();
|
||||
}
|
||||
|
||||
return kvFetch;
|
||||
},
|
||||
kvKeyDuplicate(rule, value, callback) {
|
||||
@@ -411,13 +423,15 @@
|
||||
});
|
||||
});
|
||||
},
|
||||
reloadKvs() {
|
||||
async reloadKvs() {
|
||||
this.namespaceIterator = undefined;
|
||||
|
||||
const previousLength = this.secrets?.length ?? 0;
|
||||
await this.$refs.selectTable.resetInfiniteScroll();
|
||||
this.kvs = [];
|
||||
this.$refs.selectTable.resetInfiniteScroll();
|
||||
|
||||
// If we are in the global KV view we let the infinite scroll handling the fetch
|
||||
if (this.namespace !== undefined) {
|
||||
if (this.namespace !== undefined || previousLength === 0) {
|
||||
this.fetchKvs();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -24,9 +24,11 @@
|
||||
import Navbar from "../layout/TopNavBar.vue";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {computed, ref} from "vue";
|
||||
import useRouteContext from "../../mixins/useRouteContext.js";
|
||||
|
||||
const addKvModalVisible = ref(false);
|
||||
|
||||
const {t} = useI18n({useScope: "global"});
|
||||
const routeInfo = computed(() => ({title: t("kv.name")}));
|
||||
useRouteContext(routeInfo);
|
||||
</script>
|
||||
@@ -25,12 +25,9 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {default as vElTableInfiniteScroll} from "el-table-infinite-scroll";
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import NoData from "./NoData.vue";
|
||||
import elTableInfiniteScroll from "el-table-infinite-scroll";
|
||||
|
||||
export default {
|
||||
components: {NoData},
|
||||
@@ -61,9 +58,13 @@
|
||||
return this.infiniteScrollDisabled === false;
|
||||
}
|
||||
},
|
||||
directives: {
|
||||
elTableInfiniteScroll
|
||||
},
|
||||
methods: {
|
||||
async resetInfiniteScroll() {
|
||||
this.infiniteScrollDisabled = false;
|
||||
this.tableHeight = await this.computeTableHeight();
|
||||
},
|
||||
async waitTableRender() {
|
||||
if (this.tableView === undefined) {
|
||||
@@ -82,19 +83,9 @@
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(this.tableView.querySelector(".el-table__body > tbody"), {childList: true,});
|
||||
observer.observe(this.tableView.querySelector(".el-table__body > tbody"), {childList: true});
|
||||
});
|
||||
},
|
||||
async hasScrollbar() {
|
||||
const scrollEl = this.scrollWrapper;
|
||||
if (scrollEl === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.waitTableRender();
|
||||
|
||||
return scrollEl.clientHeight < scrollEl.scrollHeight;
|
||||
},
|
||||
selectionChanged(selection) {
|
||||
this.hasSelection = selection.length > 0;
|
||||
this.$emit("selection-change", selection);
|
||||
@@ -114,6 +105,10 @@
|
||||
return "auto";
|
||||
}
|
||||
|
||||
if (!this.stillHaveDataToFetch && this.data.length === 0) {
|
||||
return "calc(var(--table-header-height) + 60px)";
|
||||
}
|
||||
|
||||
return this.stillHaveDataToFetch || this.tableView === undefined ? "100%" : `min(${this.tableView.scrollHeight}px, 100%)`;
|
||||
},
|
||||
async infiniteScrollLoadWithDisableHandling() {
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
import {useRoute} from "vue-router";
|
||||
import useNamespaces, {Namespace} from "../../composables/useNamespaces";
|
||||
import {useI18n} from "vue-i18n";
|
||||
import useRouteContext from "../../mixins/useRouteContext.ts";
|
||||
|
||||
const {t} = useI18n({useScope: "global"});
|
||||
|
||||
@@ -74,6 +75,8 @@
|
||||
}
|
||||
|
||||
const routeInfo = computed(() => ({title: t("namespaces")}));
|
||||
useRouteContext(routeInfo);
|
||||
|
||||
const user = computed(() => store.state.auth.user);
|
||||
const isUserEmpty = computed(() => Object.keys(user.value).length === 0);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</schema-to-html>
|
||||
</Suspense>
|
||||
</template>
|
||||
<markdown v-else :source="introContent" />
|
||||
<markdown v-else :source="introContent" :class="{'position-absolute': absolute}" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
overrideIntro: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
absolute: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -10,23 +10,57 @@
|
||||
</ul>
|
||||
</template>
|
||||
</Navbar>
|
||||
<section data-component="FILENAME_PLACEHOLDER" class="d-flex flex-column fill-height container padding-bottom" :class="configs?.secretsEnabled === undefined ? 'min-w-auto ms-auto me-auto' : ''">
|
||||
<template v-if="configs?.secretsEnabled === undefined">
|
||||
<Layout
|
||||
:title="$t('demos.secrets.title')"
|
||||
:image="{source: sourceImg, alt: $t('demos.secrets.title')}"
|
||||
>
|
||||
<template #message>
|
||||
{{ $t('demos.secrets.message') }}
|
||||
</template>
|
||||
</Layout>
|
||||
<el-divider />
|
||||
<p>Here are secret-type environment variables identified at instance start-time:</p>
|
||||
</template>
|
||||
<section
|
||||
data-component="FILENAME_PLACEHOLDER"
|
||||
class="d-flex flex-column fill-height padding-bottom"
|
||||
:class="configs?.secretsEnabled === undefined ? 'mt-0 p-0' : 'container'"
|
||||
>
|
||||
<EmptyTemplate v-if="configs?.secretsEnabled === undefined" class="d-flex flex-column text-start m-0 p-0 mw-100">
|
||||
<div class="no-secret-manager-block d-flex flex-column gap-6">
|
||||
<div class="header-block d-flex align-items-center">
|
||||
<div class="d-flex flex-column">
|
||||
<h5 class="mb-3">
|
||||
{{ $t('demos.secrets.title') }}
|
||||
</h5>
|
||||
<p>{{ $t('demos.secrets.message') }}</p>
|
||||
<DemoButtons />
|
||||
</div>
|
||||
<div class="img-wrapper">
|
||||
<img :src="sourceImg" :alt="$t('demos.secrets.title')">
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-0">
|
||||
{{ $t('demos.secrets.detected_env') }}
|
||||
</p>
|
||||
<div v-if="hasData === false">
|
||||
<p class="text-tertiary mb-4">
|
||||
{{ $t('demos.secrets.empty_env') }}
|
||||
</p>
|
||||
<div class="text-secondary">
|
||||
<p class="bold mb-0">
|
||||
{{ $t('demos.secrets.add_env.intro') }}
|
||||
</p>
|
||||
<ul>
|
||||
<li v-html="$t('demos.secrets.add_env.first')" />
|
||||
<li v-html="$t('demos.secrets.add_env.second')" />
|
||||
<li v-html="$t('demos.secrets.add_env.third')" />
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<SecretsTable
|
||||
v-show="hasData === true"
|
||||
:filterable="false"
|
||||
key-only
|
||||
:namespace="configs?.systemNamespace ?? 'system'"
|
||||
:add-secret-modal-visible="addSecretModalVisible"
|
||||
@update:add-secret-modal-visible="addSecretModalVisible = $event"
|
||||
@has-data="hasData = $event"
|
||||
/>
|
||||
</div>
|
||||
</EmptyTemplate>
|
||||
<SecretsTable
|
||||
:filterable="configs?.secretsEnabled !== undefined"
|
||||
:key-only="configs?.secretsEnabled === undefined"
|
||||
:namespace="configs?.secretsEnabled === true ? undefined : (configs?.systemNamespace ?? 'system')"
|
||||
v-else
|
||||
filterable
|
||||
:add-secret-modal-visible="addSecretModalVisible"
|
||||
@update:add-secret-modal-visible="addSecretModalVisible = $event"
|
||||
/>
|
||||
@@ -40,21 +74,50 @@
|
||||
import {useI18n} from "vue-i18n";
|
||||
import {computed, ref} from "vue";
|
||||
import {useStore} from "vuex";
|
||||
import useRouteContext from "../../mixins/useRouteContext.js";
|
||||
import sourceImg from "../../assets/demo/secrets.png";
|
||||
import Layout from "../demo/Layout.vue";
|
||||
import DemoButtons from "../demo/DemoButtons.vue";
|
||||
import EmptyTemplate from "../layout/EmptyTemplate.vue";
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const configs = computed(() => store.getters["misc/configs"]);
|
||||
|
||||
const addSecretModalVisible = ref(false);
|
||||
const hasData = ref(undefined);
|
||||
|
||||
const {t} = useI18n({useScope: "global"});
|
||||
const routeInfo = computed(() => ({title: t("secret.names")}));
|
||||
|
||||
useRouteContext(routeInfo);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.message-block) {
|
||||
width: 100%;
|
||||
.no-secret-manager-block {
|
||||
padding: 0 10.75rem;
|
||||
|
||||
*[style*="display: none"] { display: none !important }
|
||||
|
||||
.header-block {
|
||||
border-bottom: 1px solid var(--ks-border-primary);
|
||||
|
||||
p {
|
||||
font-size: .875rem;
|
||||
}
|
||||
|
||||
.img-wrapper {
|
||||
width: 350px;
|
||||
overflow: visible;
|
||||
direction: rtl;
|
||||
}
|
||||
}
|
||||
|
||||
.text-secondary {
|
||||
color: var(--ks-content-secondary) !important;
|
||||
|
||||
.bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,148 +1,155 @@
|
||||
<template>
|
||||
<KestraFilter v-if="filterable" :placeholder="$t('search')" :decode="false" />
|
||||
|
||||
<select-table
|
||||
:data="secrets"
|
||||
v-bind="$attrs"
|
||||
ref="selectTable"
|
||||
:default-sort="{prop: 'key', order: 'ascending'}"
|
||||
table-layout="auto"
|
||||
fixed
|
||||
:selectable="false"
|
||||
@sort-change="handleSort"
|
||||
:infinite-scroll-load="namespace === undefined ? fetchSecrets : undefined"
|
||||
class="fill-height"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="namespace === undefined"
|
||||
prop="namespace"
|
||||
sortable="custom"
|
||||
:sort-orders="['ascending', 'descending']"
|
||||
:label="$t('namespace')"
|
||||
/>
|
||||
<el-table-column prop="key" sortable="custom" :sort-orders="['ascending', 'descending']" :label="keyOnly ? $t('secret.names') : $t('key')">
|
||||
<template #default="scope">
|
||||
<id v-if="scope.row.key !== undefined" :value="scope.row.key" :shrink="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="!keyOnly" prop="description" :label="$t('description')">
|
||||
<template #default="scope">
|
||||
{{ scope.row.description }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="!keyOnly" prop="tags" :label="$t('tags')">
|
||||
<template #default="scope">
|
||||
<labels v-if="scope.row.tags !== undefined" :labels="scope.row.tags" read-only />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column column-key="locked" class-name="row-action">
|
||||
<template #default="scope">
|
||||
<el-tooltip v-if="scope.row.namespace !== undefined && areNamespaceSecretsReadOnly?.[scope.row.namespace]" transition="" :hide-after="0" :persistent="false" effect="light">
|
||||
<template #content>
|
||||
<span v-html="$t('secret.isReadOnly')" />
|
||||
</template>
|
||||
<Lock />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column column-key="copy" class-name="row-action">
|
||||
<template #default="scope">
|
||||
<el-tooltip :content="$t('copy_to_clipboard')">
|
||||
<el-button :icon="ContentCopy" link @click="Utils.copy(`\{\{ secret('${scope.row.key}') \}\}`)" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column column-key="update" class-name="row-action">
|
||||
<template #default="scope">
|
||||
<el-button v-if="canUpdate(scope.row)" :icon="FileDocumentEdit" link @click="updateSecretModal(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column column-key="delete" class-name="row-action">
|
||||
<template #default="scope">
|
||||
<el-button v-if="canDelete(scope.row)" :icon="Delete" link @click="removeSecret(scope.row.key)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</select-table>
|
||||
|
||||
<drawer
|
||||
v-if="addSecretDrawerVisible"
|
||||
v-model="addSecretDrawerVisible"
|
||||
:title="secretModalTitle"
|
||||
>
|
||||
<el-form class="ks-horizontal" :model="secret" :rules="rules" ref="form">
|
||||
<el-form-item v-if="namespace === undefined" :label="$t('namespace')" prop="namespace" required>
|
||||
<!-- TODO ADD FILTER ON NAMESPACES WITH READ-ONLY SECRETS, FOR NOW IT WOULD BE TOO COSTFUL AS IT REQUIRES 1 CALL PER NAMESPACE -->
|
||||
<namespace-select
|
||||
v-model="secret.namespace"
|
||||
:readonly="secret.update"
|
||||
data-type="flow"
|
||||
:include-system-namespace="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('secret.key')" prop="key">
|
||||
<el-input v-model="secret.key" :readonly="secret.update" required />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!secret.update" :label="$t('secret.name')" prop="value">
|
||||
<el-input v-model="secret.value" :placeholder="secretModalTitle" autosize type="textarea" required />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="secret.update" :label="$t('secret.name')" prop="value">
|
||||
<el-col :span="20">
|
||||
<el-input
|
||||
v-model="secret.value"
|
||||
:placeholder="secretModalTitle"
|
||||
autosize
|
||||
type="textarea"
|
||||
required
|
||||
:disabled="!secret.updateValue"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col class="px-2" :span="4">
|
||||
<el-switch
|
||||
size="large"
|
||||
inline-prompt
|
||||
v-model="secret.updateValue"
|
||||
:active-icon="PencilOutline"
|
||||
:inactive-icon="PencilOff"
|
||||
/>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('secret.description')" prop="description">
|
||||
<el-input v-model="secret.description" :placeholder="$t('secret.descriptionPlaceholder')" required />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('secret.tags')" prop="tags">
|
||||
<el-row :gutter="20" v-for="(tag, index) in secret.tags" :key="index">
|
||||
<el-col :span="8">
|
||||
<el-input required v-model="tag.key" :placeholder="$t('key')" />
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-input required v-model="tag.value" :placeholder="$t('value')" />
|
||||
</el-col>
|
||||
<el-button-group class="d-flex flex-nowrap">
|
||||
<el-button
|
||||
:icon="Delete"
|
||||
@click="removeSecretTag(index)"
|
||||
:disabled="secret.tags.length === 1"
|
||||
/>
|
||||
</el-button-group>
|
||||
</el-row>
|
||||
<el-button :icon="Plus" @click="addSecretTag" type="primary">
|
||||
{{ $t('secret.addTag') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button :icon="ContentSave" @click="saveSecret($refs.form)" type="primary">
|
||||
{{ $t('save') }}
|
||||
</el-button>
|
||||
<div class="d-flex flex-column fill-height">
|
||||
<template v-if="filterable">
|
||||
<KestraFilter v-if="namespace" :placeholder="$t('search')" :decode="false" />
|
||||
<section v-else class="d-inline-flex mb-3 filters">
|
||||
<el-input v-model="search" :placeholder="$t('search')" />
|
||||
</section>
|
||||
</template>
|
||||
</drawer>
|
||||
|
||||
<select-table
|
||||
:data="filteredSecrets"
|
||||
ref="selectTable"
|
||||
:default-sort="{prop: 'key', order: 'ascending'}"
|
||||
table-layout="auto"
|
||||
fixed
|
||||
:selectable="false"
|
||||
@sort-change="handleSort"
|
||||
:infinite-scroll-load="namespace === undefined ? fetchSecrets : undefined"
|
||||
class="fill-height"
|
||||
>
|
||||
<el-table-column
|
||||
v-if="namespace === undefined"
|
||||
prop="namespace"
|
||||
sortable="custom"
|
||||
:sort-orders="['ascending', 'descending']"
|
||||
:label="$t('namespace')"
|
||||
/>
|
||||
<el-table-column prop="key" sortable="custom" :sort-orders="['ascending', 'descending']" :label="keyOnly ? $t('secret.names') : $t('key')">
|
||||
<template #default="scope">
|
||||
<id v-if="scope.row.key !== undefined" :value="scope.row.key" :shrink="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="!keyOnly" prop="description" :label="$t('description')">
|
||||
<template #default="scope">
|
||||
{{ scope.row.description }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="!keyOnly" prop="tags" :label="$t('tags')">
|
||||
<template #default="scope">
|
||||
<labels v-if="scope.row.tags !== undefined" :labels="scope.row.tags" read-only />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column column-key="locked" class-name="row-action">
|
||||
<template #default="scope">
|
||||
<el-tooltip v-if="scope.row.namespace !== undefined && areNamespaceSecretsReadOnly?.[scope.row.namespace]" transition="" :hide-after="0" :persistent="false" effect="light">
|
||||
<template #content>
|
||||
<span v-html="$t('secret.isReadOnly')" />
|
||||
</template>
|
||||
<el-icon class="d-flex justify-content-center text-base">
|
||||
<Lock />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column column-key="copy" class-name="row-action">
|
||||
<template #default="scope">
|
||||
<el-tooltip :content="$t('copy_to_clipboard')">
|
||||
<el-button :icon="ContentCopy" link @click="Utils.copy(`\{\{ secret('${scope.row.key}') \}\}`)" />
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="!keyOnly" column-key="update" class-name="row-action">
|
||||
<template #default="scope">
|
||||
<el-button v-if="canUpdate(scope.row)" :icon="FileDocumentEdit" link @click="updateSecretModal(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column v-if="!keyOnly" column-key="delete" class-name="row-action">
|
||||
<template #default="scope">
|
||||
<el-button v-if="canDelete(scope.row)" :icon="Delete" link @click="removeSecret(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</select-table>
|
||||
|
||||
<drawer
|
||||
v-if="addSecretDrawerVisible"
|
||||
v-model="addSecretDrawerVisible"
|
||||
:title="secretModalTitle"
|
||||
>
|
||||
<el-form class="ks-horizontal" :model="secret" :rules="rules" ref="form">
|
||||
<el-form-item v-if="namespace === undefined" :label="$t('namespace')" prop="namespace" required>
|
||||
<namespace-select
|
||||
v-model="secret.namespace"
|
||||
:readonly="secret.update"
|
||||
data-type="flow"
|
||||
:include-system-namespace="true"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('secret.key')" prop="key">
|
||||
<el-input v-model="secret.key" :readonly="secret.update" required />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!secret.update" :label="$t('secret.name')" prop="value">
|
||||
<el-input v-model="secret.value" :placeholder="secretModalTitle" autosize type="textarea" required />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="secret.update" :label="$t('secret.name')" prop="value">
|
||||
<el-col :span="20">
|
||||
<el-input
|
||||
v-model="secret.value"
|
||||
:placeholder="secretModalTitle"
|
||||
autosize
|
||||
type="textarea"
|
||||
required
|
||||
:disabled="!secret.updateValue"
|
||||
/>
|
||||
</el-col>
|
||||
<el-col class="px-2" :span="4">
|
||||
<el-switch
|
||||
size="large"
|
||||
inline-prompt
|
||||
v-model="secret.updateValue"
|
||||
:active-icon="PencilOutline"
|
||||
:inactive-icon="PencilOff"
|
||||
/>
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('secret.description')" prop="description">
|
||||
<el-input v-model="secret.description" :placeholder="$t('secret.descriptionPlaceholder')" required />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('secret.tags')" prop="tags">
|
||||
<el-row :gutter="20" v-for="(tag, index) in secret.tags" :key="index">
|
||||
<el-col :span="8">
|
||||
<el-input required v-model="tag.key" :placeholder="$t('key')" />
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-input required v-model="tag.value" :placeholder="$t('value')" />
|
||||
</el-col>
|
||||
<el-button-group class="d-flex flex-nowrap">
|
||||
<el-button
|
||||
:icon="Delete"
|
||||
@click="removeSecretTag(index)"
|
||||
:disabled="secret.tags.length === 1"
|
||||
/>
|
||||
</el-button-group>
|
||||
</el-row>
|
||||
<el-button :icon="Plus" @click="addSecretTag" type="primary">
|
||||
{{ $t('secret.addTag') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button :icon="ContentSave" @click="saveSecret($refs.form)" type="primary">
|
||||
{{ $t('save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -176,9 +183,13 @@
|
||||
Id,
|
||||
Drawer
|
||||
},
|
||||
inheritAttrs: false,
|
||||
computed: {
|
||||
...mapState("auth", ["user"]),
|
||||
filteredSecrets() {
|
||||
return this.namespace === undefined
|
||||
? this.secrets?.filter((secret: {key: string}) => !this.search || secret.key.toLowerCase().includes(this.search.toLowerCase()))
|
||||
: this.secrets;
|
||||
},
|
||||
secretModalTitle() {
|
||||
return this.secret?.update ? this.$t("secret.update", {name: this.secret.key}) : this.$t("secret.add");
|
||||
},
|
||||
@@ -219,13 +230,36 @@
|
||||
}
|
||||
},
|
||||
emits: [
|
||||
"update:addSecretModalVisible"
|
||||
"update:addSecretModalVisible",
|
||||
"update:isSecretReadOnly",
|
||||
"hasData"
|
||||
],
|
||||
watch: {
|
||||
addSecretModalVisible(newValue) {
|
||||
if (!newValue) {
|
||||
this.resetForm();
|
||||
}
|
||||
},
|
||||
hasData(newValue, oldValue) {
|
||||
if (oldValue === undefined) {
|
||||
this.$emit("hasData", newValue);
|
||||
}
|
||||
},
|
||||
search(newValue) {
|
||||
if (newValue !== undefined) {
|
||||
this.$router.push({query: {
|
||||
q: newValue
|
||||
}})
|
||||
}
|
||||
},
|
||||
"$route.query.q"(newValue, oldValue) {
|
||||
if (newValue !== undefined && newValue !== oldValue) {
|
||||
if (this.namespace === undefined && this.search !== newValue) {
|
||||
this.search = newValue;
|
||||
|
||||
this.reloadSecrets();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -263,7 +297,9 @@
|
||||
required: false,
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
hasData: undefined,
|
||||
search: this.$route.query?.q ?? ""
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
@@ -275,7 +311,14 @@
|
||||
},
|
||||
async fetchSecrets() {
|
||||
if (this.secretsIterator === undefined) {
|
||||
this.secretsIterator = this.namespace === undefined ? useAllSecrets(this.$store, 20) : useNamespaceSecrets(this.$store, this.namespace, 20);
|
||||
this.secretsIterator = this.namespace === undefined ? useAllSecrets(this.$store, 20) : useNamespaceSecrets(this.$store, this.namespace, 20, {
|
||||
sort: this.$route.query.sort || "key:asc",
|
||||
...(this.$route.query.q === undefined ? {} : {filters: {
|
||||
q: {
|
||||
STARTS_WITH: this.$route.query.q[0]
|
||||
}
|
||||
}})
|
||||
});
|
||||
}
|
||||
|
||||
let emitReadOnly = false;
|
||||
@@ -288,11 +331,17 @@
|
||||
}
|
||||
|
||||
if (fetch.length === 0) {
|
||||
this.hasData = false;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this.hasData = true;
|
||||
this.secrets = [...(this.secrets || []), ...fetch];
|
||||
|
||||
if (this.filteredSecrets.length === 0) {
|
||||
return this.fetchSecrets();
|
||||
}
|
||||
|
||||
return fetch;
|
||||
},
|
||||
updateSecretModal(secret) {
|
||||
@@ -338,26 +387,26 @@
|
||||
removeSecretTag(index) {
|
||||
this.secret.tags.splice(index, 1);
|
||||
},
|
||||
reloadSecrets() {
|
||||
async reloadSecrets() {
|
||||
this.secretsIterator = undefined;
|
||||
|
||||
const previousLength = this.secrets?.length ?? 0;
|
||||
await this.$refs.selectTable.resetInfiniteScroll();
|
||||
this.secrets = [];
|
||||
this.$refs.selectTable.resetInfiniteScroll();
|
||||
|
||||
// If we are in the global Secrets view we let the infinite scroll handling the fetch
|
||||
if (this.namespace !== undefined) {
|
||||
if (this.namespace !== undefined || previousLength === 0) {
|
||||
this.fetchSecrets();
|
||||
}
|
||||
},
|
||||
removeSecret(key) {
|
||||
removeSecret({key, namespace}) {
|
||||
this.$toast().confirm(this.$t("delete confirm", {name: key}), () => {
|
||||
return this.$store
|
||||
.dispatch("namespace/deleteSecrets", {namespace: this.$route.params.id, key: key})
|
||||
.dispatch("namespace/deleteSecrets", {namespace: namespace, key})
|
||||
.then(() => {
|
||||
this.$toast().deleted(key);
|
||||
})
|
||||
.then(() => {
|
||||
this.reloadSecrets();
|
||||
})
|
||||
.then(() => this.reloadSecrets())
|
||||
});
|
||||
},
|
||||
isSecretValueUpdated() {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
export type FetchResult<T> = { total: number, results: T[] };
|
||||
|
||||
export abstract class EntityIterator<T> {
|
||||
private readonly fetchSize: number;
|
||||
private total: number | undefined;
|
||||
readonly fetchSize: number;
|
||||
private _total: number | undefined;
|
||||
private page = 0;
|
||||
private alreadyFetched: T[] = [];
|
||||
private buffered: T[] = [];
|
||||
private readonly options: any;
|
||||
readonly options: any;
|
||||
|
||||
protected constructor(fetchSize: number, options?: any) {
|
||||
if (fetchSize <= 0) {
|
||||
@@ -14,6 +16,10 @@ export abstract class EntityIterator<T> {
|
||||
this.options = options ?? {};
|
||||
}
|
||||
|
||||
get total(): number | undefined {
|
||||
return this._total;
|
||||
}
|
||||
|
||||
fetchOptions() {
|
||||
return {
|
||||
commit: false,
|
||||
@@ -24,13 +30,17 @@ export abstract class EntityIterator<T> {
|
||||
}
|
||||
}
|
||||
|
||||
abstract fetchCall(options: any): Promise<{total: number, results: T[]}>;
|
||||
abstract fetchCall(): Promise<FetchResult<T>>;
|
||||
|
||||
stopCondition() {
|
||||
return this.total === this.alreadyFetched.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* If no buffer is available, fetches the next entity and returns the first entity while buffering the rest
|
||||
*/
|
||||
async single(): Promise<T | undefined> {
|
||||
if (this.total === this.alreadyFetched.length && this.buffered.length === 0) {
|
||||
if (this.stopCondition() && this.buffered.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
@@ -45,12 +55,12 @@ export abstract class EntityIterator<T> {
|
||||
* Fetches the next batch of entities
|
||||
*/
|
||||
async next(): Promise<T[]> {
|
||||
if (this.total === this.alreadyFetched.length) {
|
||||
if (this.stopCondition()) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
const entityFetch = await this.fetchCall();
|
||||
this.total = entityFetch.total;
|
||||
this._total = entityFetch.total;
|
||||
this.alreadyFetched = [...this.alreadyFetched, ...entityFetch.results];
|
||||
return entityFetch.results;
|
||||
}
|
||||
@@ -64,9 +74,9 @@ export abstract class EntityIterator<T> {
|
||||
}
|
||||
|
||||
await this.next();
|
||||
const entitiesFetchPromises: Promise<T[]> = [];
|
||||
const entitiesFetchPromises: Promise<T[]>[] = [];
|
||||
|
||||
for (let i = this.page; i < this.total / this.fetchSize; i++) {
|
||||
for (let i = this.page; i < this.total! / this.fetchSize; i++) {
|
||||
entitiesFetchPromises.push(this.next());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {Store} from "vuex";
|
||||
import {EntityIterator} from "./entityIterator.ts";
|
||||
import {EntityIterator, FetchResult} from "./entityIterator.ts";
|
||||
import {NamespaceIterator} from "./useNamespaces.ts";
|
||||
import {Me} from "../stores/auth";
|
||||
import permissions from "../models/permission";
|
||||
@@ -14,10 +14,12 @@ export interface NamespaceSecret {
|
||||
|
||||
export type SecretIterator = NamespaceSecretIterator | AllSecretIterator;
|
||||
|
||||
type NamespaceSecretFetchResult = FetchResult<NamespaceSecret> & { readOnly: boolean };
|
||||
|
||||
export class NamespaceSecretIterator extends EntityIterator<NamespaceSecret>{
|
||||
private readonly store: Store<any>;
|
||||
readonly namespace: string;
|
||||
areNamespaceSecretsReadOnly: boolean | undefined = ref(undefined);
|
||||
areNamespaceSecretsReadOnly = ref(undefined) as unknown as boolean | undefined;
|
||||
|
||||
constructor(store: Store<any>, namespace: string, fetchSize: number, options?: any) {
|
||||
super(fetchSize, options);
|
||||
@@ -34,12 +36,12 @@ export class NamespaceSecretIterator extends EntityIterator<NamespaceSecret>{
|
||||
};
|
||||
}
|
||||
|
||||
fetchCall(): Promise<{ total: number; results: NamespaceSecret[], readOnly: boolean }> {
|
||||
fetchCall(): Promise<NamespaceSecretFetchResult> {
|
||||
return this.doFetch();
|
||||
}
|
||||
|
||||
private async doFetch(): Promise<{ total: number; results: NamespaceSecret[], readOnly: boolean }> {
|
||||
const fetch = await this.store.dispatch("namespace/listSecrets", this.fetchOptions());
|
||||
private async doFetch(): Promise<NamespaceSecretFetchResult> {
|
||||
const fetch = (await this.store.dispatch("namespace/listSecrets", this.fetchOptions())) as NamespaceSecretFetchResult;
|
||||
this.areNamespaceSecretsReadOnly = fetch.readOnly ?? true;
|
||||
|
||||
return {
|
||||
@@ -52,9 +54,9 @@ export class NamespaceSecretIterator extends EntityIterator<NamespaceSecret>{
|
||||
export class AllSecretIterator extends EntityIterator<NamespaceSecret>{
|
||||
private readonly store: Store<any>;
|
||||
private readonly user: Me;
|
||||
private namespaceIterator: NamespaceIterator;
|
||||
private namespaceSecretIterator: NamespaceSecretIterator;
|
||||
private areNamespaceSecretsReadOnly: {[namespace: string]: boolean} = ref({});
|
||||
private namespaceIterator: NamespaceIterator | undefined;
|
||||
private namespaceSecretIterator: NamespaceSecretIterator | undefined;
|
||||
private areNamespaceSecretsReadOnly = ref({}) as unknown as {[namespace: string]: boolean};
|
||||
|
||||
constructor(store: Store<any>, fetchSize: number, options?: any) {
|
||||
super(fetchSize, options);
|
||||
@@ -62,7 +64,11 @@ export class AllSecretIterator extends EntityIterator<NamespaceSecret>{
|
||||
this.user = this.store.state?.["auth"]?.user;
|
||||
}
|
||||
|
||||
async fetchCall(): Promise<{ total: number; results: NamespaceSecret[], readOnly: boolean }> {
|
||||
stopCondition(): boolean {
|
||||
return this.total === 0;
|
||||
}
|
||||
|
||||
async fetchCall(): Promise<FetchResult<NamespaceSecret>> {
|
||||
if (this.namespaceIterator === undefined) {
|
||||
this.namespaceIterator = new NamespaceIterator(this.store, 20, {
|
||||
commit: false,
|
||||
@@ -83,16 +89,25 @@ export class AllSecretIterator extends EntityIterator<NamespaceSecret>{
|
||||
|
||||
this.namespaceSecretIterator = new NamespaceSecretIterator(this.store, namespace.id, this.fetchSize, this.options);
|
||||
}
|
||||
const fetch = await this.namespaceSecretIterator.fetchCall();
|
||||
if (fetch.results.length > 0) {
|
||||
this.areNamespaceSecretsReadOnly[this.namespaceSecretIterator.namespace] = fetch.readOnly;
|
||||
return {
|
||||
...fetch,
|
||||
results: fetch.results.map(secret => ({...secret, namespace: this.namespaceSecretIterator.namespace}))
|
||||
};
|
||||
|
||||
const fetch = {
|
||||
results: await this.namespaceSecretIterator.next(),
|
||||
namespace: this.namespaceSecretIterator.namespace,
|
||||
areNamespaceSecretsReadOnly: this.namespaceSecretIterator.areNamespaceSecretsReadOnly,
|
||||
total: this.namespaceSecretIterator.total
|
||||
};
|
||||
|
||||
if (this.namespaceSecretIterator.stopCondition()) {
|
||||
this.namespaceSecretIterator = undefined;
|
||||
}
|
||||
|
||||
this.namespaceSecretIterator = undefined;
|
||||
if (fetch.results.length > 0) {
|
||||
this.areNamespaceSecretsReadOnly[fetch.namespace] = fetch.areNamespaceSecretsReadOnly!;
|
||||
return {
|
||||
total: fetch.total!,
|
||||
results: fetch.results.map(secret => ({...secret, namespace: fetch.namespace}))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,6 +116,6 @@ export function useNamespaceSecrets(store: Store<any>, namespace: string, secret
|
||||
return new NamespaceSecretIterator(store, namespace, secretsFetchSize, options);
|
||||
}
|
||||
|
||||
export function useAllSecrets(store: Store<any>, secretsFetchSize: number, options?: any): NamespaceSecretIterator {
|
||||
export function useAllSecrets(store: Store<any>, secretsFetchSize: number, options?: any): AllSecretIterator {
|
||||
return new AllSecretIterator(store, secretsFetchSize, options);
|
||||
}
|
||||
@@ -14,6 +14,7 @@
|
||||
:blueprint-id="selectedBlueprintId"
|
||||
blueprint-type="community"
|
||||
@back="selectedBlueprintId = undefined"
|
||||
:combined-view
|
||||
/>
|
||||
<blueprints-browser
|
||||
@loaded="$emit('loaded', $event)"
|
||||
@@ -75,7 +76,11 @@
|
||||
tab: {
|
||||
type: String,
|
||||
default: "community"
|
||||
}
|
||||
},
|
||||
combinedView: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<div class="left">
|
||||
<div class="blueprint">
|
||||
<div class="ps-0 title">
|
||||
{{ blueprint.title }}
|
||||
{{ blueprint.title ?? blueprint.id }}
|
||||
</div>
|
||||
<div v-if="!system" class="tags text-uppercase">
|
||||
<div v-for="(tag, index) in blueprint.tags" :key="index" class="tag-box">
|
||||
|
||||
@@ -138,6 +138,9 @@ export function useLeftMenu() {
|
||||
icon: {
|
||||
element: shallowRef(ShieldKeyOutline),
|
||||
class: "menu-icon"
|
||||
},
|
||||
attributes: {
|
||||
locked: true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -233,7 +236,7 @@ export function useLeftMenu() {
|
||||
{
|
||||
href: {name: "admin/tenants/list"},
|
||||
routes: routeStartWith("admin/tenants"),
|
||||
title: t("tenants"),
|
||||
title: t("tenant.names"),
|
||||
icon: {
|
||||
element: shallowRef(ShieldLockOutline),
|
||||
class: "menu-icon"
|
||||
|
||||
@@ -768,31 +768,6 @@ export default {
|
||||
|
||||
return undefined;
|
||||
},
|
||||
flowWarnings(state, getters){
|
||||
if (getters.isFlow) {
|
||||
const outdatedWarning =
|
||||
state.flowValidation?.outdated && !state.isCreating
|
||||
? [getters.outdatedMessage]
|
||||
: [];
|
||||
|
||||
const deprecationWarnings =
|
||||
state.flowValidation?.deprecationPaths?.map(
|
||||
(f) => `${f} ${this.$i18n.t("is deprecated")}.`
|
||||
) ?? [];
|
||||
|
||||
const otherWarnings = state.flowValidation?.warnings ?? [];
|
||||
|
||||
const warnings = [
|
||||
...outdatedWarning,
|
||||
...deprecationWarnings,
|
||||
...otherWarnings,
|
||||
];
|
||||
|
||||
return warnings.length === 0 ? undefined : warnings;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
flowInfos(state, getters){
|
||||
if (getters.isFlow) {
|
||||
const infos = state.flowValidation?.infos ?? [];
|
||||
|
||||
@@ -303,6 +303,14 @@
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"add_env": {
|
||||
"first": "Kodieren Sie den <strong><a href=\"https://kestra.io/docs/how-to-guides/secrets#using-secrets-in-kestra\" target=\"_blank\">geheimen Wert in Base64</a></strong>",
|
||||
"intro": "Um ein neues Secret zu erstellen:",
|
||||
"second": "Fügen Sie eine Umgebungsvariable mit dem Namen '<strong>SECRET_{'{MY_SECRET_KEY}'}</strong>' mit dem obigen Wert hinzu",
|
||||
"third": "Starte deine Kestra-Instanz neu"
|
||||
},
|
||||
"detected_env": "Hier sind Umgebungsvariablen vom Typ \"secret\", die beim Start der Instanz identifiziert wurden:",
|
||||
"empty_env": "Sie haben noch keine Secrets in Ihrer Umgebung.",
|
||||
"message": "Die Enterprise Edition (EE) ermöglicht es Ihnen, Geheimnisse direkt in der UI hinzuzufügen, zu bearbeiten oder zu löschen – ohne Neustart der Instanz. Organisieren Sie Geheimnisse nach namespace mit detaillierten RBAC-Berechtigungen und erben Sie sie von übergeordneten zu untergeordneten namespaces. EE integriert sich mit Geheimnis-Managern wie HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager und Elasticsearch. Richten Sie dedizierte Backends pro namespace, Mandant oder Instanz ein, um Geheimnisse zwischen Teams zu isolieren, oder aktivieren Sie schreibgeschützte Geheimnisse, die in externen Tresoren gespeichert sind. Geheimnisse bleiben sowohl im Ruhezustand als auch während der Übertragung verschlüsselt. Optionales Caching reduziert API-Aufrufe, und Prüfpfade protokollieren alle Zugriffe.",
|
||||
"title": "Aktualisieren Sie Ihr Secrets Management"
|
||||
},
|
||||
@@ -547,6 +555,7 @@
|
||||
},
|
||||
"empty": "Sie haben noch keine Suche gespeichert.",
|
||||
"label": "Gespeicherte Suchen",
|
||||
"remove": "Entfernen",
|
||||
"tooltip": "Sie können keine leeren Suchkriterien speichern."
|
||||
},
|
||||
"settings": {
|
||||
@@ -1152,8 +1161,10 @@
|
||||
"templates deleted": "<code>{count}</code> Vorlage(n) gelöscht",
|
||||
"templates deprecated": "Vorlagen sind veraltet. Bitte verwenden Sie stattdessen Subflows. Siehe den <a href=\"https://kestra.io/docs/migration-guide/0.11.0/templates\" target=\"_blank\">Migrationsabschnitt</a>, der erklärt, wie Sie von Vorlagen zu Subflows migrieren können.",
|
||||
"templates exported": "Vorlagen exportiert",
|
||||
"tenant": "Tenant",
|
||||
"tenants": "Tenants",
|
||||
"tenant": {
|
||||
"name": "Mandant",
|
||||
"names": "Mandanten"
|
||||
},
|
||||
"theme": "Modus",
|
||||
"this_task_has": "Diese Task hat",
|
||||
"timezone": "Zeitzone",
|
||||
|
||||
@@ -807,7 +807,15 @@
|
||||
"get_a_demo_button": "Get a Demo",
|
||||
"secrets": {
|
||||
"title": "Upgrade your Secrets Management",
|
||||
"message": "The Enterprise Edition (EE) lets you add, edit, or delete secrets directly in the UI—no instance restarts needed. Organize secrets by namespace with granular RBAC permissions, and inherit them from parent to child namespaces. EE integrates with secrets managers like HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager, and Elasticsearch. Set up dedicated backends per namespace, tenant, or instance to isolate secrets across teams, or enable read-only secrets stored in external vaults. Secrets stay encrypted at rest and in transit. Optional caching reduces API calls, and audit trails log all access."
|
||||
"message": "The Enterprise Edition (EE) lets you add, edit, or delete secrets directly in the UI—no instance restarts needed. Organize secrets by namespace with granular RBAC permissions, and inherit them from parent to child namespaces. EE integrates with secrets managers like HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager, and Elasticsearch. Set up dedicated backends per namespace, tenant, or instance to isolate secrets across teams, or enable read-only secrets stored in external vaults. Secrets stay encrypted at rest and in transit. Optional caching reduces API calls, and audit trails log all access.",
|
||||
"detected_env": "Here are secret-type environment variables identified at instance start-time:",
|
||||
"empty_env": "You don't have any Secrets in your environment yet.",
|
||||
"add_env": {
|
||||
"intro": "To create a new Secret:",
|
||||
"first": "Encode the <strong><a href=\"https://kestra.io/docs/how-to-guides/secrets#using-secrets-in-kestra\" target=\"_blank\">secret value in Base64</a></strong>",
|
||||
"second": "Add an environment variable named '<strong>SECRET_{'{MY_SECRET_KEY}'}</strong>' with the above value",
|
||||
"third": "Restart your Kestra instance"
|
||||
}
|
||||
},
|
||||
"apps": {
|
||||
"title": "Build custom Apps with Kestra",
|
||||
@@ -905,8 +913,10 @@
|
||||
"enable concurrency": "Enable concurrency",
|
||||
"auditlogs": "Audit Logs",
|
||||
"iam": "IAM",
|
||||
"tenant": "Tenant",
|
||||
"tenants": "Tenants",
|
||||
"tenant": {
|
||||
"name": "Tenant",
|
||||
"names": "Tenants"
|
||||
},
|
||||
"ee-tooltip": {
|
||||
"features-blocked": "This feature requires Enterprise Edition.",
|
||||
"button": "Talk to us"
|
||||
@@ -1116,6 +1126,7 @@
|
||||
},
|
||||
"save": {
|
||||
"label": "Saved searches",
|
||||
"remove": "Remove",
|
||||
"empty": "You still haven't saved any search.",
|
||||
"tooltip": "You can't save empty search criteria.",
|
||||
"dialog": {
|
||||
@@ -1248,7 +1259,7 @@
|
||||
"task_runners": "Task Runners",
|
||||
"empty": {
|
||||
"announcements": {
|
||||
"title": "You have no annoucements yet!",
|
||||
"title": "You have no announcements yet!",
|
||||
"content": "Announcements allow you to notify your users about any changes or inform them about planned maintenance downtime. Simply select the announcement type, the date range for which it should be displayed, and write the announcement message."
|
||||
},
|
||||
"apps": {
|
||||
|
||||
@@ -303,6 +303,14 @@
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"add_env": {
|
||||
"first": "Codifica el <strong><a href=\"https://kestra.io/docs/how-to-guides/secrets#using-secrets-in-kestra\" target=\"_blank\">valor secreto en Base64</a></strong>",
|
||||
"intro": "Para crear un nuevo Secret:",
|
||||
"second": "Agrega una variable de entorno llamada '<strong>SECRET_{'{MY_SECRET_KEY}'}</strong>' con el valor anterior",
|
||||
"third": "Reinicia tu instancia de Kestra"
|
||||
},
|
||||
"detected_env": "Aquí están las variables de entorno de tipo secreto identificadas al momento de inicio de la instancia:",
|
||||
"empty_env": "Todavía no tienes ningún Secret en tu entorno.",
|
||||
"message": "La Enterprise Edition (EE) te permite agregar, editar o eliminar secretos directamente en la UI, sin necesidad de reiniciar la instancia. Organiza secretos por namespace con permisos RBAC granulares, y herédalos de namespaces padre a hijo. EE se integra con gestores de secretos como HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager y Elasticsearch. Configura backends dedicados por namespace, tenant o instancia para aislar secretos entre equipos, o habilita secretos de solo lectura almacenados en vaults externos. Los secretos permanecen cifrados en reposo y en tránsito. El almacenamiento en caché opcional reduce las llamadas a la API, y las auditorías registran todo el acceso.",
|
||||
"title": "Mejora tu Gestión de Secrets"
|
||||
},
|
||||
@@ -547,6 +555,7 @@
|
||||
},
|
||||
"empty": "Todavía no has guardado ninguna búsqueda.",
|
||||
"label": "Búsquedas guardadas",
|
||||
"remove": "Eliminar",
|
||||
"tooltip": "No puedes guardar criterios de búsqueda vacíos."
|
||||
},
|
||||
"settings": {
|
||||
@@ -1152,8 +1161,10 @@
|
||||
"templates deleted": "<code>{count}</code> Plantilla(s) eliminadas",
|
||||
"templates deprecated": "Las plantillas están obsoletas. Por favor usa subflows en su lugar. Consulta la <a href=\"https://kestra.io/docs/migration-guide/0.11.0/templates\" target=\"_blank\">sección de Migraciones</a> que explica cómo puedes migrar de plantillas a subflows.",
|
||||
"templates exported": "Plantillas exportadas",
|
||||
"tenant": "Tenant",
|
||||
"tenants": "Tenants",
|
||||
"tenant": {
|
||||
"name": "Mandante",
|
||||
"names": "Arrendatarios"
|
||||
},
|
||||
"theme": "Tema",
|
||||
"this_task_has": "Esta tarea tiene",
|
||||
"timezone": "Zona horaria",
|
||||
|
||||
@@ -303,6 +303,14 @@
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"add_env": {
|
||||
"first": "Encodez la <strong><a href=\"https://kestra.io/docs/how-to-guides/secrets#using-secrets-in-kestra\" target=\"_blank\">valeur secrète en Base64</a></strong>",
|
||||
"intro": "Pour créer un nouveau Secret :",
|
||||
"second": "Ajoutez une variable d'environnement nommée '<strong>SECRET_{'{MY_SECRET_KEY}'}</strong>' avec la valeur ci-dessus.",
|
||||
"third": "Redémarrez votre instance Kestra"
|
||||
},
|
||||
"detected_env": "Voici les variables d'environnement de type secret identifiées au démarrage de l'instance :",
|
||||
"empty_env": "Vous n'avez pas encore de Secrets dans votre environnement.",
|
||||
"message": "L'Enterprise Edition (EE) vous permet d'ajouter, de modifier ou de supprimer des secrets directement dans l'UI, sans redémarrage de l'instance. Organisez les secrets par namespace avec des permissions RBAC granulaires, et héritez-les des namespaces parents aux namespaces enfants. EE s'intègre avec des gestionnaires de secrets comme HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager et Elasticsearch. Configurez des backends dédiés par namespace, tenant ou instance pour isoler les secrets entre les équipes, ou activez des secrets en lecture seule stockés dans des coffres externes. Les secrets restent chiffrés au repos et en transit. Un cache optionnel réduit les appels API, et les pistes d'audit loguent tous les accès.",
|
||||
"title": "Améliorez votre gestion des Secrets"
|
||||
},
|
||||
@@ -547,6 +555,7 @@
|
||||
},
|
||||
"empty": "Vous n'avez pas encore enregistré de recherche.",
|
||||
"label": "Recherches enregistrées",
|
||||
"remove": "Supprimer",
|
||||
"tooltip": "Vous ne pouvez pas enregistrer des critères de recherche vides."
|
||||
},
|
||||
"settings": {
|
||||
@@ -1152,8 +1161,10 @@
|
||||
"templates deleted": "<code>{count}</code> Template(s) supprimé(s)",
|
||||
"templates deprecated": "Les templates sont obsolètes. Veuillez utiliser des sous-flux au lieu des templates. Consultez <a href=\"https://kestra.io/docs/migration-guide/0.11.0/templates\" target=\"_blank\">section Migrations</a> expliquant comment vous pouvez migrer vers les sous-flux.",
|
||||
"templates exported": "Templates exportés",
|
||||
"tenant": "Tenant",
|
||||
"tenants": "Tenants",
|
||||
"tenant": {
|
||||
"name": "Mandant",
|
||||
"names": "Mandants"
|
||||
},
|
||||
"theme": "Thème",
|
||||
"this_task_has": "Cette tâche a",
|
||||
"timezone": "Fuseau horaire",
|
||||
|
||||
@@ -303,6 +303,14 @@
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"add_env": {
|
||||
"first": "<strong><a href=\"https://kestra.io/docs/how-to-guides/secrets#using-secrets-in-kestra\" target=\"_blank\">गुप्त value को Base64 में एन्कोड करें</a></strong>",
|
||||
"intro": "नया Secret बनाने के लिए:",
|
||||
"second": "'<strong>SECRET_{'{MY_SECRET_KEY}'}</strong>' नामक एक environment variable जोड़ें उपरोक्त value के साथ",
|
||||
"third": "अपने Kestra instance को पुनः प्रारंभ करें"
|
||||
},
|
||||
"detected_env": "यहाँ instance start-time पर पहचाने गए secret-type environment variables हैं:",
|
||||
"empty_env": "आपके वातावरण में अभी तक कोई Secrets नहीं हैं।",
|
||||
"message": "एंटरप्राइज एडिशन (EE) आपको UI में सीधे secrets जोड़ने, संपादित करने या हटाने की अनुमति देता है—कोई instance पुनरारंभ की आवश्यकता नहीं है। secrets को namespace द्वारा संगठित करें, जिसमें सूक्ष्म RBAC अनुमतियाँ हों, और उन्हें parent से child namespaces में विरासत में लें। EE HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager, और Elasticsearch जैसे secrets प्रबंधकों के साथ एकीकृत होता है। टीमों के बीच secrets को अलग करने के लिए namespace, tenant, या instance के अनुसार समर्पित बैकएंड सेट करें, या बाहरी vaults में संग्रहीत read-only secrets को सक्षम करें। secrets को आराम और ट्रांजिट में एन्क्रिप्टेड रखा जाता है। वैकल्पिक caching API कॉल्स को कम करता है, और audit trails सभी एक्सेस को log करते हैं।",
|
||||
"title": "अपने Secrets Management को अपग्रेड करें"
|
||||
},
|
||||
@@ -547,6 +555,7 @@
|
||||
},
|
||||
"empty": "आपने अभी तक कोई खोज सहेजी नहीं है।",
|
||||
"label": "सहेजे गए खोजें",
|
||||
"remove": "हटाएं",
|
||||
"tooltip": "आप खाली खोज मानदंड सहेज नहीं सकते।"
|
||||
},
|
||||
"settings": {
|
||||
@@ -1152,8 +1161,10 @@
|
||||
"templates deleted": "<code>{count}</code> template(s) हटाए गए",
|
||||
"templates deprecated": "templates अप्रचलित हैं। कृपया इसके बजाय subflows का उपयोग करें। यह समझाने वाला <a href=\"https://kestra.io/docs/migration-guide/0.11.0/templates\" target=\"_blank\">माइग्रेशन अनुभाग</a> देखें कि आप टेम्पलेट्स से subflows में कैसे माइग्रेट कर सकते हैं।",
|
||||
"templates exported": "templates निर्यात किए गए",
|
||||
"tenant": "Tenant",
|
||||
"tenants": "Tenants",
|
||||
"tenant": {
|
||||
"name": "मंडल",
|
||||
"names": "मंडल"
|
||||
},
|
||||
"theme": "थीम",
|
||||
"this_task_has": "यह task है",
|
||||
"timezone": "समय क्षेत्र",
|
||||
|
||||
@@ -303,6 +303,14 @@
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"add_env": {
|
||||
"first": "Codifica il <strong><a href=\"https://kestra.io/docs/how-to-guides/secrets#using-secrets-in-kestra\" target=\"_blank\">valore segreto in Base64</a></strong>",
|
||||
"intro": "Per creare un nuovo Secret:",
|
||||
"second": "Aggiungi una variabile di ambiente chiamata '<strong>SECRET_{'{MY_SECRET_KEY}'}</strong>' con il valore sopra indicato",
|
||||
"third": "Riavvia la tua istanza di Kestra"
|
||||
},
|
||||
"detected_env": "Ecco le variabili d'ambiente di tipo secret identificate al momento dell'avvio dell'istanza:",
|
||||
"empty_env": "Non hai ancora alcun Secret nel tuo ambiente.",
|
||||
"message": "L'Enterprise Edition (EE) ti consente di aggiungere, modificare o eliminare segreti direttamente nell'interfaccia utente, senza bisogno di riavviare l'istanza. Organizza i segreti per namespace con permessi RBAC granulari e ereditali dai namespace genitori a quelli figli. EE si integra con gestori di segreti come HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, Google Secret Manager ed Elasticsearch. Configura backend dedicati per namespace, tenant o istanza per isolare i segreti tra i team, oppure abilita segreti di sola lettura memorizzati in vault esterni. I segreti rimangono crittografati a riposo e in transito. La cache opzionale riduce le chiamate API e le tracce di audit registrano tutti gli accessi.",
|
||||
"title": "Aggiorna il tuo Secrets Management"
|
||||
},
|
||||
@@ -547,6 +555,7 @@
|
||||
},
|
||||
"empty": "Non hai ancora salvato alcuna ricerca.",
|
||||
"label": "Ricerche salvate",
|
||||
"remove": "Rimuovi",
|
||||
"tooltip": "Non puoi salvare criteri di ricerca vuoti."
|
||||
},
|
||||
"settings": {
|
||||
@@ -1152,8 +1161,10 @@
|
||||
"templates deleted": "<code>{count}</code> Template/i eliminati",
|
||||
"templates deprecated": "I templates sono deprecati. Si prega di utilizzare i subflows. Vedi la <a href=\"https://kestra.io/docs/migration-guide/0.11.0/templates\" target=\"_blank\">sezione Migrazioni</a> che spiega come migrare dai templates ai subflows.",
|
||||
"templates exported": "Template esportati",
|
||||
"tenant": "Tenant",
|
||||
"tenants": "Tenants",
|
||||
"tenant": {
|
||||
"name": "Mandante",
|
||||
"names": "Mandanti"
|
||||
},
|
||||
"theme": "Tema",
|
||||
"this_task_has": "Questo task ha",
|
||||
"timezone": "Fuso orario",
|
||||
|
||||
@@ -303,6 +303,14 @@
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"add_env": {
|
||||
"first": "<strong><a href=\"https://kestra.io/docs/how-to-guides/secrets#using-secrets-in-kestra\" target=\"_blank\">シークレットの値をBase64でエンコード</a></strong>",
|
||||
"intro": "新しいSecretを作成するには:",
|
||||
"second": "`<strong>SECRET_{'{MY_SECRET_KEY}'}</strong>`という名前の環境変数を上記の値で追加してください。",
|
||||
"third": "Kestraインスタンスを再起動する"
|
||||
},
|
||||
"detected_env": "インスタンス開始時に識別されたシークレットタイプの環境変数は次のとおりです:",
|
||||
"empty_env": "まだ環境にSecretsがありません。",
|
||||
"message": "エンタープライズエディション (EE) では、UIで直接シークレットを追加、編集、または削除できます。インスタンスの再起動は不要です。シークレットをnamespaceごとに整理し、詳細なRBAC権限を設定し、親namespaceから子namespaceに継承します。EEは、HashiCorp Vault、AWS Secrets Manager、Azure Key Vault、Google Secret Manager、Elasticsearchなどのシークレットマネージャーと統合します。namespace、テナント、またはインスタンスごとに専用のバックエンドを設定して、チーム間でシークレットを分離するか、外部のvaultに保存された読み取り専用のシークレットを有効にします。シークレットは、保存時および転送時に暗号化されたままです。オプションのキャッシュによりAPIコールが削減され、監査証跡がすべてのアクセスをログに記録します。",
|
||||
"title": "シークレット管理をアップグレード"
|
||||
},
|
||||
@@ -547,6 +555,7 @@
|
||||
},
|
||||
"empty": "検索をまだ保存していません。",
|
||||
"label": "保存済み検索",
|
||||
"remove": "削除",
|
||||
"tooltip": "空の検索条件を保存することはできません。"
|
||||
},
|
||||
"settings": {
|
||||
@@ -1152,8 +1161,10 @@
|
||||
"templates deleted": "<code>{count}</code>件のテンプレートが削除されました",
|
||||
"templates deprecated": "テンプレートは非推奨です。代わりにsubflowsを使用してください。テンプレートからsubflowsへの移行方法については、<a href=\"https://kestra.io/docs/migration-guide/0.11.0/templates\" target=\"_blank\">移行セクション</a>を参照してください。",
|
||||
"templates exported": "テンプレートがエクスポートされました",
|
||||
"tenant": "Tenant",
|
||||
"tenants": "Tenants",
|
||||
"tenant": {
|
||||
"name": "テナント",
|
||||
"names": "テナント"
|
||||
},
|
||||
"theme": "テーマ",
|
||||
"this_task_has": "このtaskは",
|
||||
"timezone": "タイムゾーン",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user