From dee62e1518e4bb4be8a339ae5f9f864002922333 Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Thu, 22 May 2025 11:58:32 +0200 Subject: [PATCH 01/30] internal: secure flows (#5796) * secure flows * add restriction to claude code --- .github/workflows/aider-after-review.yaml | 25 ++++++------- .github/workflows/aider.yaml | 45 +++++++++++++---------- .github/workflows/claude.yml | 37 ++++++++++++++++--- .github/workflows/linear-issue.yaml | 17 ++++----- 4 files changed, 78 insertions(+), 46 deletions(-) diff --git a/.github/workflows/aider-after-review.yaml b/.github/workflows/aider-after-review.yaml index abd6091a31..578c7d1b7d 100644 --- a/.github/workflows/aider-after-review.yaml +++ b/.github/workflows/aider-after-review.yaml @@ -17,10 +17,11 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} REVIEWER: ${{ github.event.review.user.login }} + ORG_ACCESS_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }} run: | ORG="windmill-labs" STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ - -H "Authorization: token $GH_TOKEN" \ + -H "Authorization: token $ORG_ACCESS_TOKEN" \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/orgs/$ORG/members/$REVIEWER") @@ -59,27 +60,25 @@ jobs: - name: Prepare prompt for Aider id: prepare_prompt shell: bash + env: + GITHUB_REPOSITORY: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + REVIEW_BODY: ${{ github.event.review.body }} run: | - # Get PR review body - REVIEW_BODY="${{ github.event.review.body }}" - REVIEW_BODY_Q=$(printf '%q' "$REVIEW_BODY") + REVIEW_BODY_ESCAPED="${REVIEW_BODY//\\/\\\\}" + REVIEW_BODY_ESCAPED="${REVIEW_BODY_ESCAPED//\"/\\\"}" - PR_NUMBER="${{ github.event.pull_request.number }}" - - # Get all PR review comments ALL_REVIEW_COMMENTS=$(gh api \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments \ - | jq '[.[] | {diff_hunk: .diff_hunk, path: .path, body: .body}]') + /repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/comments) + + FORMATTED_COMMENTS=$(jq -r '[.[] | {diff_hunk: .diff_hunk, path: .path, body: .body}]' <<< "$ALL_REVIEW_COMMENTS") BASE_PROMPT="Fix the following issues in the PR based on the review feedback. The review body is prepended with REVIEW. The review comments are prepended with REVIEW_COMMENTS. The review body and comments are separated by a blank line." - printf -v COMPLETE_PROMPT "%s\nREVIEW:\n%s\nREVIEW_COMMENTS:\n%s" \ - "$BASE_PROMPT" "$REVIEW_BODY_Q" "$ALL_REVIEW_COMMENTS" - echo "$COMPLETE_PROMPT" + COMPLETE_PROMPT="${BASE_PROMPT}"$'\n'"REVIEW:"$'\n'"${REVIEW_BODY_ESCAPED}"$'\n'"REVIEW_COMMENTS:"$'\n'"${FORMATTED_COMMENTS}" - # Use the proper multi-line output format echo "prompt_content<> $GITHUB_OUTPUT echo "$COMPLETE_PROMPT" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT diff --git a/.github/workflows/aider.yaml b/.github/workflows/aider.yaml index 50d9946094..0614627b35 100644 --- a/.github/workflows/aider.yaml +++ b/.github/workflows/aider.yaml @@ -20,10 +20,11 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} COMMENTER: ${{ github.event.comment.user.login }} + ORG_ACCESS_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }} run: | ORG="windmill-labs" STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ - -H "Authorization: token $GH_TOKEN" \ + -H "Authorization: token $ORG_ACCESS_TOKEN" \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "https://api.github.com/orgs/$ORG/members/$COMMENTER") @@ -66,6 +67,11 @@ jobs: - name: Determine inputs for Aider id: determine_inputs shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMMENT_BODY: ${{ github.event.comment.body }} + ISSUE_NUMBER: ${{ github.event.issue.number }} + GITHUB_REPOSITORY: ${{ github.repository }} run: | echo "Determining inputs for Aider..." ISSUE_TITLE_VAL="" @@ -73,28 +79,31 @@ jobs: if [[ ! -z "${{ github.event.issue.pull_request }}" ]]; then echo "This is a comment on a Pull Request" - PR_NUMBER="${{ github.event.issue.number }}" + PR_NUMBER="$ISSUE_NUMBER" - PR_BODY_JSON=$(GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" gh pr view "$PR_NUMBER" --json body --repo "$GITHUB_REPOSITORY") + PR_BODY_JSON=$(gh pr view "$PR_NUMBER" --json body --repo "$GITHUB_REPOSITORY") if [[ $? -ne 0 ]]; then echo "Error fetching PR body for PR #$PR_NUMBER" PR_BODY_VAL="" else - PR_BODY_VAL=$(echo "$PR_BODY_JSON" | jq -r .body) + PR_BODY_VAL=$(jq -r '.body // ""' <<< "$PR_BODY_JSON") fi if [[ ! -z "$PR_BODY_VAL" ]]; then - REFERENCED_ISSUE=$(echo "$PR_BODY_VAL" | grep -oE "#[0-9]+" | grep -oE "[0-9]+" | head -1) + REFERENCED_ISSUE="" + if [[ "$PR_BODY_VAL" =~ \#([0-9]+) ]]; then + REFERENCED_ISSUE="${BASH_REMATCH[1]}" + fi if [[ ! -z "$REFERENCED_ISSUE" ]]; then echo "Found referenced issue #$REFERENCED_ISSUE in PR description" - ISSUE_DETAILS_JSON=$(GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" gh issue view "$REFERENCED_ISSUE" --json title,body --repo "$GITHUB_REPOSITORY") + ISSUE_DETAILS_JSON=$(gh issue view "$REFERENCED_ISSUE" --json title,body --repo "$GITHUB_REPOSITORY") if [[ $? -ne 0 ]]; then echo "Error fetching issue details for #$REFERENCED_ISSUE" else - ISSUE_TITLE_VAL=$(echo "$ISSUE_DETAILS_JSON" | jq -r .title) - ISSUE_BODY_VAL=$(echo "$ISSUE_DETAILS_JSON" | jq -r .body) + ISSUE_TITLE_VAL=$(jq -r '.title // ""' <<< "$ISSUE_DETAILS_JSON") + ISSUE_BODY_VAL=$(jq -r '.body // ""' <<< "$ISSUE_DETAILS_JSON") fi fi else @@ -102,34 +111,32 @@ jobs: fi else echo "This is a comment on a regular issue" - ISSUE_NUMBER="${{ github.event.issue.number }}" - ISSUE_DETAILS_JSON=$(GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" gh issue view "$ISSUE_NUMBER" --json title,body --repo "$GITHUB_REPOSITORY") + + ISSUE_DETAILS_JSON=$(gh issue view "$ISSUE_NUMBER" --json title,body --repo "$GITHUB_REPOSITORY") if [[ $? -ne 0 ]]; then echo "Error fetching issue details for #$ISSUE_NUMBER" else - ISSUE_TITLE_VAL=$(echo "$ISSUE_DETAILS_JSON" | jq -r .title) - ISSUE_BODY_VAL=$(echo "$ISSUE_DETAILS_JSON" | jq -r .body) + ISSUE_TITLE_VAL=$(jq -r '.title // ""' <<< "$ISSUE_DETAILS_JSON") + ISSUE_BODY_VAL=$(jq -r '.body // ""' <<< "$ISSUE_DETAILS_JSON") fi fi - echo "Setting GITHUB_OUTPUT for ISSUE_TITLE..." echo "ISSUE_TITLE<> "$GITHUB_OUTPUT" echo "$ISSUE_TITLE_VAL" >> "$GITHUB_OUTPUT" echo "EOF_AIDER_TITLE" >> "$GITHUB_OUTPUT" - echo "Setting GITHUB_OUTPUT for ISSUE_BODY..." echo "ISSUE_BODY<> "$GITHUB_OUTPUT" echo "$ISSUE_BODY_VAL" >> "$GITHUB_OUTPUT" echo "EOF_AIDER_BODY" >> "$GITHUB_OUTPUT" - # Process COMMENT_CONTENT - printf -v COMMENT_CONTENT_VAL "%s" "$(echo "${{ github.event.comment.body }}" | sed 's|^/aider||' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" + CLEAN_COMMENT="${COMMENT_BODY/\/aider/}" + CLEAN_COMMENT="${CLEAN_COMMENT#"${CLEAN_COMMENT%%[![:space:]]*}"}" + CLEAN_COMMENT="${CLEAN_COMMENT%"${CLEAN_COMMENT##*[![:space:]]}"}" + echo "COMMENT_CONTENT<> "$GITHUB_OUTPUT" - echo "$COMMENT_CONTENT_VAL" >> "$GITHUB_OUTPUT" + echo "$CLEAN_COMMENT" >> "$GITHUB_OUTPUT" echo "EOF_AIDER_COMMENT" >> "$GITHUB_OUTPUT" echo "Finished determining inputs." - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Make sure gh cli has a token run-aider: needs: [check-membership, check-and-prepare] diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 77a96d6119..4dc170d8d1 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -11,12 +11,39 @@ on: types: [submitted] jobs: - claude-code-action: + check-membership: if: | - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/aider')) || - (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/aider')) || - (github.event_name == 'pull_request_review' && contains(github.event.review.body, '/aider')) || - (github.event_name == 'issues' && contains(github.event.issue.body, '/aider')) + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/aider') && !contains(github.event.comment.user.login, '[bot]')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/aider') && !contains(github.event.comment.user.login, '[bot]')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '/aider') && !contains(github.event.review.user.login, '[bot]')) || + (github.event_name == 'issues' && contains(github.event.issue.body, '/aider') && !contains(github.event.issue.user.login, '[bot]')) + runs-on: ubicloud-standard-2 + outputs: + is_member: ${{ steps.check-membership.outputs.is_member }} + steps: + - name: Check organization membership + id: check-membership + env: + COMMENTER: ${{ github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' ? github.event.comment.user.login : github.event_name == 'pull_request_review' ? github.event.review.user.login : github.event.issue.user.login }} + ORG_ACCESS_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }} + run: | + ORG="windmill-labs" + STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ + -H "Authorization: token $ORG_ACCESS_TOKEN" \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/orgs/$ORG/members/$COMMENTER") + + if [ "$STATUS" -eq 204 ]; then + echo "is_member=true" >> $GITHUB_OUTPUT + else + echo "is_member=false" >> $GITHUB_OUTPUT + fi + + claude-code-action: + needs: check-membership + if: | + needs.check-membership.outputs.is_member == 'true' runs-on: ubicloud-standard-8 permissions: contents: read diff --git a/.github/workflows/linear-issue.yaml b/.github/workflows/linear-issue.yaml index 1dce5b6c87..22f9e53c46 100644 --- a/.github/workflows/linear-issue.yaml +++ b/.github/workflows/linear-issue.yaml @@ -37,24 +37,23 @@ jobs: - name: Determine inputs for Aider id: determine_inputs shell: bash + env: + ISSUE_TITLE: ${{ github.event.client_payload.issue_title }} + ISSUE_BODY: ${{ github.event.client_payload.issue_body }} + INSTRUCTION: ${{ github.event.client_payload.instruction }} run: | echo "Determining inputs for Aider..." - ISSUE_TITLE_VAL="${{ github.event.client_payload.issue_title }}" - INSTRUCTION_VAL="${{ github.event.client_payload.instruction }}" - ISSUE_BODY_VAL=$(printf '%q' "${{ github.event.client_payload.issue_body }}") - echo "Setting GITHUB_OUTPUT for ISSUE_TITLE..." + echo "ISSUE_TITLE<> "$GITHUB_OUTPUT" - echo "$ISSUE_TITLE_VAL" >> "$GITHUB_OUTPUT" + echo "$ISSUE_TITLE" >> "$GITHUB_OUTPUT" echo "EOF_AIDER_TITLE" >> "$GITHUB_OUTPUT" - echo "Setting GITHUB_OUTPUT for ISSUE_BODY..." echo "ISSUE_BODY<> "$GITHUB_OUTPUT" - echo "$ISSUE_BODY_VAL" >> "$GITHUB_OUTPUT" + echo "$ISSUE_BODY" >> "$GITHUB_OUTPUT" echo "EOF_AIDER_BODY" >> "$GITHUB_OUTPUT" - echo "Setting GITHUB_OUTPUT for INSTRUCTION..." echo "INSTRUCTION<> "$GITHUB_OUTPUT" - echo "$INSTRUCTION_VAL" >> "$GITHUB_OUTPUT" + echo "$INSTRUCTION" >> "$GITHUB_OUTPUT" echo "EOF_AIDER_INSTRUCTION" >> "$GITHUB_OUTPUT" echo "Finished determining inputs." From d662e18f97c2edc3d60df9496b0927901edb26a5 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 22 May 2025 12:07:21 +0200 Subject: [PATCH 02/30] add more labels to traces --- backend/windmill-queue/src/jobs.rs | 1 + backend/windmill-worker/src/handle_child.rs | 11 +++++++---- backend/windmill-worker/src/job_logger_ee.rs | 1 + 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index 1ff103cd9a..f2b1e56153 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -980,6 +980,7 @@ pub async fn add_completed_job( is_flow_step = queued_job.is_flow_step(), language = ?queued_job.script_lang, scheduled_for = ?queued_job.scheduled_for, + workspace_id = ?queued_job.workspace_id, success, "inserted completed job: {} (success: {success})", queued_job.id diff --git a/backend/windmill-worker/src/handle_child.rs b/backend/windmill-worker/src/handle_child.rs index d82a72df98..c47af18073 100644 --- a/backend/windmill-worker/src/handle_child.rs +++ b/backend/windmill-worker/src/handle_child.rs @@ -134,7 +134,7 @@ pub async fn handle_child( let (tx, rx) = broadcast::channel::<()>(3); let mut rx2: broadcast::Receiver<()> = tx.subscribe(); - let output = child_joined_output_stream(&mut child, job_id.clone()); + let output = child_joined_output_stream(&mut child, job_id.clone(), w_id.to_string()); let job_id: Uuid = job_id.clone(); @@ -729,6 +729,7 @@ where fn child_joined_output_stream( child: &mut Child, job_id: Uuid, + w_id: String, ) -> impl stream::FusedStream> { let stderr = child .stderr @@ -743,8 +744,8 @@ fn child_joined_output_stream( let stdout = BufReader::new(stdout).lines(); let stderr = BufReader::new(stderr).lines(); stream::select( - lines_to_stream(stderr, true, job_id.clone()), - lines_to_stream(stdout, false, job_id), + lines_to_stream(stderr, true, job_id.clone(), w_id.clone(), path.clone()), + lines_to_stream(stdout, false, job_id, w_id, path), ) } @@ -752,11 +753,13 @@ pub fn lines_to_stream( mut lines: tokio::io::Lines, stderr: bool, job_id: Uuid, + w_id: String, + path: String, ) -> impl futures::Stream> { stream::poll_fn(move |cx| { std::pin::Pin::new(&mut lines) .poll_next_line(cx) - .map(|result| process_streaming_log_lines(result, stderr, &job_id)) + .map(|result| process_streaming_log_lines(result, stderr, &job_id, &w_id)) }) } diff --git a/backend/windmill-worker/src/job_logger_ee.rs b/backend/windmill-worker/src/job_logger_ee.rs index 4b1d34392c..22772878ee 100644 --- a/backend/windmill-worker/src/job_logger_ee.rs +++ b/backend/windmill-worker/src/job_logger_ee.rs @@ -36,6 +36,7 @@ pub(crate) fn process_streaming_log_lines( r: Result, io::Error>, _stderr: bool, _job_id: &Uuid, + _w_id: &str, ) -> Option> { r.transpose() } From 3fbebcdef57c75c7effde0755794e81b9722def8 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 22 May 2025 12:35:32 +0200 Subject: [PATCH 03/30] add more labels to traces --- backend/ee-repo-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 71591f02b5..36e0923e83 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -0f0df9dd99a44baf890f24323f0a2eb2ee1120ce \ No newline at end of file +7632fb040ac1dd340d7ef4ddd90304c6a06e71f1 \ No newline at end of file From d9bd80b280690bc07f1e3c125bf4d3486b8ef0c9 Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Thu, 22 May 2025 12:35:44 +0200 Subject: [PATCH 04/30] internal: fix flows (#5797) * remove test line * fix claude --- .github/workflows/aider-common.yml | 2 +- .github/workflows/claude.yml | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aider-common.yml b/.github/workflows/aider-common.yml index 2e4e99c716..dceea4a012 100644 --- a/.github/workflows/aider-common.yml +++ b/.github/workflows/aider-common.yml @@ -273,7 +273,7 @@ jobs: --read .cursor/rules/windmill-overview.mdc \ $FILES_TO_EDIT \ --model gemini/gemini-2.5-pro-preview-05-06 \ - --message "create a test file in backend/test.txt with hello world in it" \ + --message-file .aider_final_prompt.txt \ --yes \ --no-check-update \ --auto-commits \ diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 4dc170d8d1..7ac5d93802 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -24,10 +24,18 @@ jobs: - name: Check organization membership id: check-membership env: - COMMENTER: ${{ github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' ? github.event.comment.user.login : github.event_name == 'pull_request_review' ? github.event.review.user.login : github.event.issue.user.login }} ORG_ACCESS_TOKEN: ${{ secrets.ORG_ACCESS_TOKEN }} run: | ORG="windmill-labs" + + if [[ "${{ github.event_name }}" == "issue_comment" || "${{ github.event_name }}" == "pull_request_review_comment" ]]; then + COMMENTER="${{ github.event.comment.user.login }}" + elif [[ "${{ github.event_name }}" == "pull_request_review" ]]; then + COMMENTER="${{ github.event.review.user.login }}" + else + COMMENTER="${{ github.event.issue.user.login }}" + fi + STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: token $ORG_ACCESS_TOKEN" \ -H "Accept: application/vnd.github+json" \ From e3e25daee79380131f3f28ad326c4455b489f1d3 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 22 May 2025 14:12:10 +0200 Subject: [PATCH 05/30] fix --- backend/windmill-worker/src/handle_child.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/windmill-worker/src/handle_child.rs b/backend/windmill-worker/src/handle_child.rs index c47af18073..3eb9e95dc9 100644 --- a/backend/windmill-worker/src/handle_child.rs +++ b/backend/windmill-worker/src/handle_child.rs @@ -744,8 +744,8 @@ fn child_joined_output_stream( let stdout = BufReader::new(stdout).lines(); let stderr = BufReader::new(stderr).lines(); stream::select( - lines_to_stream(stderr, true, job_id.clone(), w_id.clone(), path.clone()), - lines_to_stream(stdout, false, job_id, w_id, path), + lines_to_stream(stderr, true, job_id.clone(), w_id.clone()), + lines_to_stream(stdout, false, job_id, w_id), ) } @@ -754,7 +754,6 @@ pub fn lines_to_stream( stderr: bool, job_id: Uuid, w_id: String, - path: String, ) -> impl futures::Stream> { stream::poll_fn(move |cx| { std::pin::Pin::new(&mut lines) From 21741e68bcf467b4f87390da51b076b7af91f494 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 22 May 2025 14:23:49 +0200 Subject: [PATCH 06/30] fix --- backend/ee-repo-ref.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 36e0923e83..fec7d05006 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -7632fb040ac1dd340d7ef4ddd90304c6a06e71f1 \ No newline at end of file +0854c5c00f62751aa5eb44fd9e550052fdcf7884 \ No newline at end of file From 88482c3bd76ddad16738354f7531d16fa806ad2f Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 22 May 2025 14:40:53 +0200 Subject: [PATCH 07/30] fix: improve app css consistency --- .../apps/components/buttons/AppButton.svelte | 6 +- .../apps/components/display/AppAlert.svelte | 9 +- .../apps/components/layout/AppModal.svelte | 4 +- .../apps/editor/component/components.ts | 3 +- .../componentsPanel/CssHelperPanel.svelte | 256 ++++++++++-------- .../apps/editor/componentsPanel/cssUtils.ts | 32 ++- 6 files changed, 184 insertions(+), 126 deletions(-) diff --git a/frontend/src/lib/components/apps/components/buttons/AppButton.svelte b/frontend/src/lib/components/apps/components/buttons/AppButton.svelte index ff3f34097b..5ad842ba6c 100644 --- a/frontend/src/lib/components/apps/components/buttons/AppButton.svelte +++ b/frontend/src/lib/components/apps/components/buttons/AppButton.svelte @@ -229,7 +229,8 @@ css?.button?.class ?? '', isMenuItem ? 'flex items-center justify-start' : '', isMenuItem ? '!border-0' : '', - 'wm-button' + 'wm-button', + `wm-button-${resolvedConfig.color}` )} variant={isMenuItem ? 'border' : 'contained'} style={css?.button?.style} @@ -237,7 +238,8 @@ css?.container?.class ?? '', resolvedConfig.fillContainer ? 'w-full h-full' : '', isMenuItem ? 'w-full' : '', - 'wm-button-container' + 'wm-button-container', + `wm-button-container-${resolvedConfig.color}` )} wrapperStyle={css?.container?.style} disabled={resolvedConfig.disabled} diff --git a/frontend/src/lib/components/apps/components/display/AppAlert.svelte b/frontend/src/lib/components/apps/components/display/AppAlert.svelte index 20fc60ba03..24dfa9ea51 100644 --- a/frontend/src/lib/components/apps/components/display/AppAlert.svelte +++ b/frontend/src/lib/components/apps/components/display/AppAlert.svelte @@ -10,6 +10,7 @@ import InitializeComponent from '../helpers/InitializeComponent.svelte' import { Alert } from '$lib/components/common' import AlignWrapper from '../helpers/AlignWrapper.svelte' + import { appendClass } from '../../editor/componentsPanel/cssUtils' export let id: string export let configuration: RichConfigurations @@ -63,13 +64,13 @@ tooltip={resolvedConfig.tooltip} size={resolvedConfig.size} collapsible={resolvedConfig.collapsible} - bgClass={css?.background?.class} + bgClass={appendClass(css?.background?.class, 'wm-alert-card-background')} bgStyle={css?.background?.style} - iconClass={css?.icon?.class} + iconClass={appendClass(css?.icon?.class, 'wm-alert-card-icon')} iconStyle={css?.icon?.style} - titleClass={css?.title?.class} + titleClass={appendClass(css?.title?.class, 'wm-alert-card-title')} titleStyle={css?.title?.style} - descriptionClass={css?.description?.class} + descriptionClass={appendClass(css?.description?.class, 'wm-alert-card-description')} descriptionStyle={css?.description?.style} isCollapsed={resolvedConfig.initiallyCollapsed} > diff --git a/frontend/src/lib/components/apps/components/layout/AppModal.svelte b/frontend/src/lib/components/apps/components/layout/AppModal.svelte index 3000afdedf..15f3eca206 100644 --- a/frontend/src/lib/components/apps/components/layout/AppModal.svelte +++ b/frontend/src/lib/components/apps/components/layout/AppModal.svelte @@ -179,7 +179,7 @@ >
{ e?.stopPropagation() if (!$connectingInput.opened) { diff --git a/frontend/src/lib/components/apps/editor/component/components.ts b/frontend/src/lib/components/apps/editor/component/components.ts index 2ff364f44a..27d0bfc3bf 100644 --- a/frontend/src/lib/components/apps/editor/component/components.ts +++ b/frontend/src/lib/components/apps/editor/component/components.ts @@ -3410,7 +3410,8 @@ See date-fns format for more information. By default, it is 'dd.MM.yyyy HH:mm' customCss: { button: { class: '', style: '' }, buttonContainer: { class: '', style: '' }, - popup: { class: '', style: '' } + popup: { class: '', style: '' }, + container: { class: '', style: '' } }, initialData: { horizontalAlignment: 'center', diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte b/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte index fda2b9338a..05e6380238 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte +++ b/frontend/src/lib/components/apps/editor/componentsPanel/CssHelperPanel.svelte @@ -20,20 +20,38 @@ const dispatch = createEventDispatcher() interface CustomCSSEntry { - type: CustomCSSType + type?: CustomCSSType name: string icon: any - ids: { id: string; forceStyle: boolean; forceClass: boolean }[] + ids?: { id: string; forceStyle: boolean; forceClass: boolean }[] + description?: string + order?: number } const { app } = getContext('AppViewerContext') + const descriptions = { + buttoncomponent: + 'The button component also has additional color specific classes to allow customizing classes by color. wm-button-wrapper-blue, wm-button-container-blue, ...' + } const entries: CustomCSSEntry[] = [ + { + name: 'Dark Mode', + icon: LayoutDashboardIcon, + description: + 'When in dark mode, the entire document has the .dark class applied to it. You can apply selective styling by using the .dark class: e.g. .dark .my-element { color: white; }', + order: 3 + }, { type: 'app', name: 'App', icon: LayoutDashboardIcon, - ids: ['viewer', 'grid', 'component'].map((id) => ({ id, forceStyle: true, forceClass: true })) + ids: ['viewer', 'grid', 'component'].map((id) => ({ + id, + forceStyle: true, + forceClass: true + })), + order: 2 }, { type: 'quillcomponent', @@ -51,11 +69,12 @@ id, forceStyle: v?.style != undefined, forceClass: v?.['class'] != undefined - })) + })), + description: descriptions[type as keyof typeof descriptions] })) ] - entries.sort((a, b) => a.name.localeCompare(b.name)) + entries.sort((a, b) => (b.order ?? 0) - (a.order ?? 0) + a.name.localeCompare(b.name)) let search = '' @@ -66,15 +85,15 @@
{#each search != '' ? entries.filter((x) => x.name .toLowerCase() - .includes(search.toLowerCase())) : entries as { type, name, icon, ids } (name + type)} - {#if ids.length > 0} + .includes(search.toLowerCase())) : entries as { type, name, icon, ids, description } (name + type)} + {#if description || (ids && ids.length > 0)} { if ($app.css != undefined) { - if (e.detail && $app.css[type] == undefined) { - $app.css[type] = Object.fromEntries(ids.map(({ id }) => [id, {}])) + if (type && e.detail && $app.css[type] == undefined) { + $app.css[type] = Object.fromEntries((ids ?? []).map(({ id }) => [id, {}])) } } }} @@ -85,115 +104,120 @@ {name}
-
- {#each customisationByComponent.filter( (c) => c.components.includes(type) ) as customisation (customisation.components.join('-'))} - {#if customisation.link} - -
- See documentation - -
-
- {/if} - - - {#if customisation.selectors.length > 0} - - Selectors ({customisation.selectors.length}) - - {/if} - {#if customisation.variables.length > 0} - -
- Variables ({customisation.variables.length}) + {#if description} +
{description}
+ {/if} + {#if type} +
+ {#each customisationByComponent.filter( (c) => c.components.includes(type) ) as customisation (customisation.components.join('-'))} + {#if customisation.link} + +
+ See documentation +
- +
{/if} -
- - - - - Selector - Comment - - - - {#each customisation.selectors as { selector, comment }} - - - {selector} - - - {#if comment} -
{comment}
- {/if} -
- - - -
- {/each} -
-
- - - - - Variable - Default value - Comment - - - - {#each customisation.variables as { variable, value, comment }} - - - {variable} - - - {value} - - - {#if comment} -
{comment}
- {/if} -
- - - -
- {/each} -
-
-
- - {/each} -
+ + + {#if customisation.selectors.length > 0} + + Selectors ({customisation.selectors.length}) + + {/if} + {#if customisation.variables.length > 0} + +
+ Variables ({customisation.variables.length}) +
+
+ {/if} +
+ + + + + Selector + Comment + + + + {#each customisation.selectors as { selector, comment }} + + + {selector} + + + {#if comment} +
{comment}
+ {/if} +
+ + + +
+ {/each} +
+
+ + + + + Variable + Default value + Comment + + + + {#each customisation.variables as { variable, value, comment }} + + + {variable} + + + {value} + + + {#if comment} +
{comment}
+ {/if} +
+ + + +
+ {/each} +
+
+
+
+ {/each} +
+ {/if} {/if} {/each} diff --git a/frontend/src/lib/components/apps/editor/componentsPanel/cssUtils.ts b/frontend/src/lib/components/apps/editor/componentsPanel/cssUtils.ts index 6fc8344295..4634959ac0 100644 --- a/frontend/src/lib/components/apps/editor/componentsPanel/cssUtils.ts +++ b/frontend/src/lib/components/apps/editor/componentsPanel/cssUtils.ts @@ -185,7 +185,11 @@ export const customisationByComponent: Customisation[] = [ components: ['modalcomponent'], selectors: [ { selector: '.wm-modal', comment: 'main modal element', customCssKey: 'popup' }, - { selector: '.wm-modal-button', comment: 'button to open modal', customCssKey: 'button' }, + { + selector: '.wm-modal-container', + comment: 'container for modal', + customCssKey: 'container' + }, { selector: '.wm-modal-button-container', comment: 'container for button to open modal', @@ -826,6 +830,26 @@ export const customisationByComponent: Customisation[] = [ selector: 'wm-alert-card-container', comment: 'Alert container', customCssKey: 'container' + }, + { + selector: 'wm-alert-card-background', + comment: 'Alert background', + customCssKey: 'background' + }, + { + selector: 'wm-alert-card-icon', + comment: 'Alert icon', + customCssKey: 'icon' + }, + { + selector: 'wm-alert-card-title', + comment: 'Alert title', + customCssKey: 'title' + }, + { + selector: 'wm-alert-card-description', + comment: 'Alert description', + customCssKey: 'description' } ], variables: [] @@ -860,3 +884,9 @@ export function hasStyleValue(obj: ComponentCssProperty | undefined) { return obj.style !== '' } + +export function appendClass(className: string | undefined, customCssKey: string) { + if (!className) return customCssKey + + return `${className} ${customCssKey}` +} From 55ae76648475ce9ff14b2fa33b2a71b90fbd50a1 Mon Sep 17 00:00:00 2001 From: wendrul <53628737+wendrul@users.noreply.github.com> Date: Thu, 22 May 2025 15:23:45 +0200 Subject: [PATCH 08/30] feat: job search pagination + result count (#5789) * add tracing to get of authed client * fix: make disabled items not selectable with arrow keys * Invert showing EE message only when not in EE * Makea component for the Run Search part of the Search modal * Make the button to load more jobs * Add pagination for job search * fix missing bind to the openModal bool * Turn off spinner when aborting search results * fix typo in openapi.yaml * Update ee repo ref * Remove unused imports and vars --------- Co-authored-by: Ruben Fiszel --- backend/ee-repo-ref.txt | 2 +- backend/windmill-api/openapi.yaml | 26 +- .../search/GlobalSearchModal.svelte | 211 +++----------- .../lib/components/search/RunsSearch.svelte | 266 ++++++++++++++++++ 4 files changed, 321 insertions(+), 184 deletions(-) create mode 100644 frontend/src/lib/components/search/RunsSearch.svelte diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index fec7d05006..4d15f57a97 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -0854c5c00f62751aa5eb44fd9e550052fdcf7884 \ No newline at end of file +bea87fa885dc041fba83b2491609a4a2cdbbfa6f diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 5020067440..9895efce7e 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -12590,6 +12590,11 @@ paths: required: true schema: type: string + - name: pagination_offset + in: query + required: false + schema: + type: integer responses: "200": description: search results @@ -12602,15 +12607,26 @@ paths: description: a list of the terms that couldn't be parsed (and thus ignored) type: array items: - type: object - properties: - dancer: - type: string + type: string hits: description: the jobs that matched the query type: array items: $ref: "#/components/schemas/JobSearchHit" + hit_count: + description: how many jobs matched in total + type: number + index_metadata: + description: Metadata about the index current state + type: object + properties: + indexed_until: + description: Datetime of the most recently indexed job + type: string + format: date-time + lost_lock_ownership: + description: Is the current indexer service being replaced + type: boolean /srch/index/search/service_logs: get: @@ -16810,4 +16826,4 @@ components: channel_name: type: string description: Microsoft Teams channel name - minLength: 1 \ No newline at end of file + minLength: 1 diff --git a/frontend/src/lib/components/search/GlobalSearchModal.svelte b/frontend/src/lib/components/search/GlobalSearchModal.svelte index 271389b007..e684ce0d89 100644 --- a/frontend/src/lib/components/search/GlobalSearchModal.svelte +++ b/frontend/src/lib/components/search/GlobalSearchModal.svelte @@ -3,7 +3,6 @@ import { AppService, FlowService, - IndexSearchService, RawAppService, ScriptService, type Flow, @@ -11,8 +10,7 @@ type ListableRawApp, type Script } from '$lib/gen' - import { clickOutside, displayDateOnly, isMac, sendUserToast } from '$lib/utils' - import TimeAgo from '../TimeAgo.svelte' + import { clickOutside, isMac } from '$lib/utils' import { AlertTriangle, BoxesIcon, @@ -22,14 +20,12 @@ DollarSignIcon, HomeIcon, LayoutDashboardIcon, - Loader2, PlayIcon, Route, Search, SearchCode, Unplug } from 'lucide-svelte' - import JobPreview from '../runs/JobPreview.svelte' import Portal from '$lib/components/Portal.svelte' import { twMerge } from 'tailwind-merge' @@ -44,6 +40,7 @@ import Popover from '../Popover.svelte' import Logs from 'lucide-svelte/icons/logs' import { AwsIcon, GoogleCloudIcon, KafkaIcon, MqttIcon, NatsIcon } from '../icons' + import RunsSearch from './RunsSearch.svelte' let open: boolean = false @@ -72,7 +69,7 @@ let switchModeItems: quickMenuItem[] = [ { search_id: 'switchto:run-search', - label: 'Search across completed runs' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Search across completed runs' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => switchMode('runs'), shortcutKey: RUNS_PREFIX, icon: Search, @@ -113,28 +110,28 @@ }, { search_id: 'nav:kafka_triggers', - label: 'Go to Kafka triggers' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Go to Kafka triggers' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => gotoPage('/kafka_triggers'), icon: KafkaIcon, disabled: $userStore?.operator }, { search_id: 'nav:nats_triggers', - label: 'Go to NATS triggers' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Go to NATS triggers' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => gotoPage('/nats_triggers'), icon: NatsIcon, disabled: $userStore?.operator }, { search_id: 'nav:sqs_triggers', - label: 'Go to SQS triggers' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Go to SQS triggers' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => gotoPage('/sqs_triggers'), icon: AwsIcon, disabled: $userStore?.operator }, { search_id: 'nav:gcp_pub_sub', - label: 'Go to GCP Pub/Sub' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Go to GCP Pub/Sub' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => gotoPage('/gcp_triggers'), icon: GoogleCloudIcon, disabled: $userStore?.operator @@ -264,12 +261,8 @@ return r } - let debounceTimeout: any = undefined - const debouncePeriod: number = 1000 - let loadingCompletedRuns: boolean = false let queryParseErrors: string[] = [] - let indexMetadata: any = {} async function handleSearch() { queryParseErrors = [] @@ -314,6 +307,7 @@ ) ) } + itemMap['default'] = itemMap['default'].filter((e) => !e.disabled) } if (tab === 'switch-mode') { itemMap['switch-mode'] = fuzzyFilter( @@ -323,26 +317,8 @@ ) } if (tab === 'runs') { - const s = removePrefix(searchTerm, RUNS_PREFIX) - clearTimeout(debounceTimeout) - loadingCompletedRuns = true - debounceTimeout = setTimeout(async () => { - clearTimeout(debounceTimeout) - let searchResults - try { - searchResults = await IndexSearchService.searchJobsIndex({ - searchQuery: s, - workspace: $workspaceStore! - }) - itemMap['runs'] = searchResults.hits - queryParseErrors = searchResults.query_parse_errors - indexMetadata = searchResults.index_metadata - } catch (e) { - sendUserToast(e.body, true) - } - loadingCompletedRuns = false - selectedItem = selectItem(0) - }, debouncePeriod) + await tick() + runsSearch?.handleRunSearch(removePrefix(searchTerm, RUNS_PREFIX)) } selectedItem = selectItem(0) } @@ -594,6 +570,8 @@ return 'max-h-[60vh]' } } + + let runsSearch: RunsSearch {#if open} @@ -652,18 +630,16 @@ {#if items.length > 0}
{#each items as el} - {#if !el.disabled} - (selectedItem = el)} - id={el?.search_id} - hovered={el?.search_id === selectedItem?.search_id} - label={el?.label} - icon={el?.icon} - shortcutKey={el?.shortcutKey} - bind:mouseMoved - /> - {/if} + (selectedItem = el)} + id={el?.search_id} + hovered={el?.search_id === selectedItem?.search_id} + label={el?.label} + icon={el?.icon} + shortcutKey={el?.shortcutKey} + bind:mouseMoved + /> {/each}
{/if} @@ -729,138 +705,17 @@ {/if}
{:else if tab === 'runs'} -
- {#if loadingCompletedRuns} -
-
- -
-
- {:else if itemMap['runs'] && itemMap['runs'].length > 0} -
- {#each itemMap['runs'] ?? [] as r} - { - selectedItem = r - selectedWorkspace = r?.document.workspace_id[0] - }} - on:keyboardOnlySelect={() => { - open = false - goto(`/run/${r?.document.id[0]}`) - }} - id={r?.document.id[0]} - hovered={selectedItem && r?.document.id[0] === selectedItem?.document.id[0]} - icon={r?.icon} - containerClass="rounded-md px-2 py-1 my-2" - bind:mouseMoved - > - -
-
-
-
{r?.document.script_path}
-
-
- {displayDateOnly(new Date(r?.document.created_at[0]))} -
-
- -
-
-
-
-
-
- {/each} -
-
- {#if selectedItem === undefined} - Select a result to preview - {:else} -
- -
- {/if} -
- {#if indexMetadata.indexed_until} - - Most recently indexed job was created at - - {/if} - {#if indexMetadata.lost_lock_ownership} - - - - The current indexer is no longer indexing new jobs. This is most likely - because of an ongoing deployment and indexing will resume once it's - complete. - - - {/if} -
-
- {:else} -
-
- {#if searchTerm === RUNS_PREFIX} -
Enter your search terms
-
Start typing to do full-text search across completed runs
- {:else} -
No runs found
-
There were no completed runs that match your query
- {/if} -
- Note that new runs might take a while to become searchable (by default ~5min) -
- {#if !$enterpriseLicense} -
- - - Full-text search on jobs is only available on EE. - - {/if} -
-
- {#if indexMetadata.indexed_until} - - Most recently indexed job was created at - - {/if} - {#if indexMetadata.lost_lock_ownership} - - - - The current indexer is no longer indexing new jobs. This is most likely - because of an ongoing deployment and indexing will resume once it's - complete. - - - {/if} -
-
- {/if} -
+ {/if}
diff --git a/frontend/src/lib/components/search/RunsSearch.svelte b/frontend/src/lib/components/search/RunsSearch.svelte new file mode 100644 index 0000000000..e955304786 --- /dev/null +++ b/frontend/src/lib/components/search/RunsSearch.svelte @@ -0,0 +1,266 @@ + + +
+ {#if loadingCompletedRuns} +
+
+ +
+
+ {:else if loadedRuns && loadedRuns.length > 0} +
+
+ {runSearchTotalCount} jobs matched the query +
+
+ {#each loadedRuns ?? [] as r} + {#if r.search_id === 'opt:load_more_jobs'} +
+ {#if loadingMoreJobs} +
+ +
+ {:else} + { + selectedItem = r + selectedWorkspace = undefined + const paginationOffset = runSearchTotalCount! - runSearchRemainingCount! + loadMoreJobs(searchTerm, paginationOffset) + }} + id={'opt:load_more_jobs'} + hovered={selectedItem && r?.search_id === selectedItem?.search_id} + containerClass="rounded-md px-2 py-1 my-2" + bind:mouseMoved + > + +
+ Some other {runSearchRemainingCount} jobs matched the query. Click to load more. + + +
+
+
+ {/if} + {:else} + { + selectedItem = r + selectedWorkspace = r?.document.workspace_id[0] + }} + on:keyboardOnlySelect={() => { + open = false + goto(`/run/${r?.document.id[0]}`) + }} + id={r?.document.id[0]} + hovered={selectedItem && r?.search_id === selectedItem?.search_id} + icon={r?.icon} + containerClass="rounded-md px-2 py-1 my-2" + bind:mouseMoved + > + +
+
+
+
{r?.document.script_path}
+
+
+ {displayDateOnly(new Date(r?.document.created_at[0]))} +
+
+ +
+
+
+
+
+
+ {/if} + {/each} +
+
+
+ {#if selectedItem === undefined} + Select a result to preview + {:else} +
+ +
+ {/if} +
+ {#if indexMetadata.indexed_until} + + Most recently indexed job was created at + + {/if} + {#if indexMetadata.lost_lock_ownership} + + + + The current indexer is no longer indexing new jobs. This is most likely because of an + ongoing deployment and indexing will resume once it's complete. + + + {/if} +
+
+ {:else} +
+
+ {#if searchTerm === ''} +
Enter your search terms
+
Start typing to do full-text search across completed runs
+ {:else} +
No runs found
+
There were no completed runs that match your query
+ {/if} +
+ Note that new runs might take a while to become searchable (by default ~5min) +
+ {#if !$enterpriseLicense} +
+ + + Full-text search on jobs is only available on EE. + + {/if} +
+
+ {#if indexMetadata.indexed_until} + + Most recently indexed job was created at + + {/if} + {#if indexMetadata.lost_lock_ownership} + + + + The current indexer is no longer indexing new jobs. This is most likely because of an + ongoing deployment and indexing will resume once it's complete. + + + {/if} +
+
+ {/if} +
From 6381cdf7d3823dfd246e3b6971e160d7e3ab8fe7 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 22 May 2025 18:26:41 +0200 Subject: [PATCH 09/30] improve service log select --- .../lib/components/ServiceLogsInner.svelte | 58 ++++++++++++++++--- .../apps/svelte-select/lib/Select.svelte | 13 +++-- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/frontend/src/lib/components/ServiceLogsInner.svelte b/frontend/src/lib/components/ServiceLogsInner.svelte index 9769e82fca..9b358adf80 100644 --- a/frontend/src/lib/components/ServiceLogsInner.svelte +++ b/frontend/src/lib/components/ServiceLogsInner.svelte @@ -15,6 +15,9 @@ import AnsiUp from 'ansi_up' import { scroll_into_view_if_needed_polyfill } from './multiselect/utils' import SplitPanesOrColumnOnMobile from './splitPanes/SplitPanesOrColumnOnMobile.svelte' + import Select from './apps/svelte-select/lib/Select.svelte' + import { SELECT_INPUT_DEFAULT_STYLE } from '$lib/defaults' + import DarkModeObserver from './DarkModeObserver.svelte' export let searchTerm: string export let queryParseErrors: string[] = [] @@ -319,10 +322,13 @@ const buckets = res['buckets'] sumOtherDocCount = res['sum_other_doc_count'] countsPerHost = new Map(buckets.map(({ key, doc_count }) => [key, doc_count])) - countsPerHost = buckets.reduce((acc: any, { key, doc_count }) => { - acc[key] = { doc_count } - return acc - }, {} as Record) + countsPerHost = buckets.reduce( + (acc: any, { key, doc_count }) => { + acc[key] = { doc_count } + return acc + }, + {} as Record + ) queryParseErrors = countLogsResponse.query_parse_errors ?? [] loadingLogCounts = false } @@ -376,7 +382,7 @@ let ret = {} for (const hk of Object.keys(countsPerHost)) { - let u = hk.split(",") + let u = hk.split(',') let [mode, wg, hn] = [u[0], u[1], u[2]] if (!ret[mode]) { @@ -392,8 +398,23 @@ return ret } + + function getSelectItems(allLogs: ByMode, countsPerHost: any): { label: string; value: any }[] { + return Object.entries(allLogsOrQueryResults(allLogs, countsPerHost)).flatMap(([mode, o1]) => + Object.entries(o1).flatMap(([wg, o2]) => + Object.keys(o2).map((hn) => ({ + label: hn, + value: [mode, wg, hn] + })) + ) + ) + } + + let darkMode = false + + @@ -436,7 +457,7 @@ month: '2-digit', hour: '2-digit', minute: '2-digit' - }) + }) : 'min datetime'} disabled /> @@ -476,7 +497,7 @@ month: '2-digit', hour: '2-digit', minute: '2-digit' - }) + }) : 'max datetime'} disabled /> @@ -548,6 +569,24 @@ > {/if} +
+ + {:else if bucket_config.type === 'AwsOidc'} + + + {:else}
Unknown bucket type {bucket_config['type']}
{/if} From d940b395091954cc0f1c7e2b47cf9a9de09e5870 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Mon, 26 May 2025 09:21:46 +0200 Subject: [PATCH 26/30] fix triggers reset upon deploy (#5812) --- frontend/src/lib/components/FlowBuilder.svelte | 2 +- frontend/src/lib/components/ScriptBuilder.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/lib/components/FlowBuilder.svelte b/frontend/src/lib/components/FlowBuilder.svelte index b28eb4bcec..ab8fc1ea9f 100644 --- a/frontend/src/lib/components/FlowBuilder.svelte +++ b/frontend/src/lib/components/FlowBuilder.svelte @@ -461,7 +461,7 @@ ...structuredClone(newSavedFlow), path: $pathStore } as Flow - triggersState.setTriggers([]) + setDraftTriggers([]) loadingSave = false dispatch('deploy', $pathStore) } catch (err) { diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte index 5fa096f06e..5f1da5267c 100644 --- a/frontend/src/lib/components/ScriptBuilder.svelte +++ b/frontend/src/lib/components/ScriptBuilder.svelte @@ -556,7 +556,7 @@ const { draft_triggers: _, ...newScript } = structuredClone(script) savedScript = structuredClone(newScript) as NewScriptWithDraft - triggersState.setTriggers([]) + setDraftTriggers([]) if (!disableHistoryChange) { history.replaceState(history.state, '', `/scripts/edit/${script.path}`) From 306f3eabd1c03fa904b0e59438de124a0e680597 Mon Sep 17 00:00:00 2001 From: HugoCasa Date: Mon, 26 May 2025 19:38:01 +0200 Subject: [PATCH 27/30] fix: add missing http_trigger_version_seq grants (#5816) --- .../migrations/20250526173025_http_trigger_seq_grants.down.sql | 1 + .../migrations/20250526173025_http_trigger_seq_grants.up.sql | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 backend/migrations/20250526173025_http_trigger_seq_grants.down.sql create mode 100644 backend/migrations/20250526173025_http_trigger_seq_grants.up.sql diff --git a/backend/migrations/20250526173025_http_trigger_seq_grants.down.sql b/backend/migrations/20250526173025_http_trigger_seq_grants.down.sql new file mode 100644 index 0000000000..d2f607c5b8 --- /dev/null +++ b/backend/migrations/20250526173025_http_trigger_seq_grants.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250526173025_http_trigger_seq_grants.up.sql b/backend/migrations/20250526173025_http_trigger_seq_grants.up.sql new file mode 100644 index 0000000000..bf09f0a555 --- /dev/null +++ b/backend/migrations/20250526173025_http_trigger_seq_grants.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +GRANT ALL ON SEQUENCE http_trigger_version_seq TO windmill_user; +GRANT ALL ON SEQUENCE http_trigger_version_seq TO windmill_admin; \ No newline at end of file From e49cf749676b10f8462105dbcb6755c4f6df0739 Mon Sep 17 00:00:00 2001 From: centdix <40307056+centdix@users.noreply.github.com> Date: Mon, 26 May 2025 19:45:09 +0200 Subject: [PATCH 28/30] use ai instead of aider (#5814) --- .github/workflows/claude.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 66eff9dc57..9bc9f8d7ea 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -13,10 +13,10 @@ on: jobs: check-membership: if: | - (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/aider') && !contains(github.event.comment.user.login, '[bot]')) || - (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/aider') && !contains(github.event.comment.user.login, '[bot]')) || - (github.event_name == 'pull_request_review' && contains(github.event.review.body, '/aider') && !contains(github.event.review.user.login, '[bot]')) || - (github.event_name == 'issues' && contains(github.event.issue.body, '/aider') && !contains(github.event.issue.user.login, '[bot]')) + (github.event_name == 'issue_comment' && contains(github.event.comment.body, '/ai') && !contains(github.event.comment.user.login, '[bot]')) || + (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/ai') && !contains(github.event.comment.user.login, '[bot]')) || + (github.event_name == 'pull_request_review' && contains(github.event.review.body, '/ai') && !contains(github.event.review.user.login, '[bot]')) || + (github.event_name == 'issues' && contains(github.event.issue.body, '/ai') && !contains(github.event.issue.user.login, '[bot]')) runs-on: ubicloud-standard-2 outputs: is_member: ${{ steps.check-membership.outputs.is_member }} @@ -82,4 +82,4 @@ jobs: - Bash(npm run generate-backend-client): Generate the backend client. You need this to run npm run check. - Bash(cargo check): Run the cargo check script. You should run this tool after making changes to the backend code. - Bash(curl https://sh.rustup.rs -sSf | sh): Install Rust. You need this to run cargo check." - trigger_phrase: "/aider" + trigger_phrase: "/ai" From 5897e7e01b8839425c30c2a97481ef7bb9090661 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Tue, 27 May 2025 01:09:55 +0200 Subject: [PATCH 29/30] Fix(frontend): auto completion and render of tailwind classes in app editor (#5817) * fix auto completion and render * Remove tailwind_full.css links and add tailwindUtils to package.json exports - Removed `` from AppEditor.svelte and AppPreview.svelte - Added `"./tailwindUtils"` export to package.json exports section for external consumption - Added tailwindUtils to typesVersions section for TypeScript support Co-authored-by: rubenfiszel --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: rubenfiszel --- frontend/package.json | 7 +++ .../src/lib/components/SimpleEditor.svelte | 49 ++++++++++++------- .../components/apps/editor/AppEditor.svelte | 1 - .../components/apps/editor/AppPreview.svelte | 1 - frontend/tailwind.config.cjs | 4 +- 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 51c7820491..f302f5c873 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -371,6 +371,10 @@ "types": "./package/components/SimpleEditor.svelte.d.ts", "svelte": "./package/components/SimpleEditor.svelte", "default": "./package/components/SimpleEditor.svelte" + }, + "./tailwindUtils": { + "types": "./package/components/apps/editor/componentsPanel/tailwindUtils.d.ts", + "default": "./package/components/apps/editor/componentsPanel/tailwindUtils.js" } }, "files": [ @@ -506,6 +510,9 @@ ], "components/icons/store": [ "./package/components/icons/store.d.ts" + ], + "tailwindUtils": [ + "./package/components/apps/editor/componentsPanel/tailwindUtils.d.ts" ] } }, diff --git a/frontend/src/lib/components/SimpleEditor.svelte b/frontend/src/lib/components/SimpleEditor.svelte index 3cc814b855..984b05564a 100644 --- a/frontend/src/lib/components/SimpleEditor.svelte +++ b/frontend/src/lib/components/SimpleEditor.svelte @@ -467,33 +467,46 @@ } function addTailwindClassCompletions() { + // Define a custom word definition for Tailwind classes + languages.setMonarchTokensProvider('tailwindcss', { + tokenizer: { + root: [[/[a-zA-Z0-9-]+/, 'tailwind-class']] + } + }) + languages.registerCompletionItemProvider('tailwindcss', { + triggerCharacters: ['-'], provideCompletionItems: function (model, position, context, token) { - const word = model.getWordUntilPosition(position) + const wordUntilPosition = model.getWordUntilPosition(position) + const lineContent = model.getLineContent(position.lineNumber) + + // Get the text from the start of the line to the cursor + const textUntilPosition = lineContent.substring(0, position.column - 1) + // Find the last space before the cursor + const lastSpaceIndex = textUntilPosition.lastIndexOf(' ') + const startColumn = lastSpaceIndex === -1 ? 1 : lastSpaceIndex + 2 + const range = { startLineNumber: position.lineNumber, - startColumn: word.startColumn, + startColumn: startColumn, endLineNumber: position.lineNumber, - endColumn: word.endColumn + endColumn: position.column } - if (word && word.word) { - const currentWord = word.word + const currentWord = wordUntilPosition.word - const suggestions = tailwindClasses - .filter((className) => className.includes(currentWord)) - .map((className) => ({ - label: className, - kind: languages.CompletionItemKind.Class, - insertText: className, - documentation: 'Custom CSS class', - range: range - })) + const suggestions = tailwindClasses + .filter((className) => className.includes(currentWord)) + .map((className) => ({ + label: className, + kind: languages.CompletionItemKind.Class, + insertText: className, + documentation: 'Tailwind CSS class', + range: range, + preselect: true + })) - return { suggestions } - } - - return { suggestions: [] } + return { suggestions } } }) } diff --git a/frontend/src/lib/components/apps/editor/AppEditor.svelte b/frontend/src/lib/components/apps/editor/AppEditor.svelte index 3276befa58..fd328beb28 100644 --- a/frontend/src/lib/components/apps/editor/AppEditor.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditor.svelte @@ -786,7 +786,6 @@ - diff --git a/frontend/src/lib/components/apps/editor/AppPreview.svelte b/frontend/src/lib/components/apps/editor/AppPreview.svelte index 2cc07c05bc..1438f0712c 100644 --- a/frontend/src/lib/components/apps/editor/AppPreview.svelte +++ b/frontend/src/lib/components/apps/editor/AppPreview.svelte @@ -243,7 +243,6 @@ - diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs index f65a852949..908f2516df 100644 --- a/frontend/tailwind.config.cjs +++ b/frontend/tailwind.config.cjs @@ -1,4 +1,5 @@ const plugin = require('tailwindcss/plugin') +const { tailwindClasses } = require('./src/lib/components/apps/editor/componentsPanel/tailwindUtils') const lightTheme = { surface: '#ffffff', @@ -80,7 +81,8 @@ const config = { 'autocomplete-list-item', 'autocomplete-list-item-create', 'selected', - 'wm-tab-selected' + 'wm-tab-selected', + ...tailwindClasses ], theme: { colors: { From 5dcefeff849e4514f107855e25ed20abc4962964 Mon Sep 17 00:00:00 2001 From: Guilhem Date: Tue, 27 May 2025 01:17:32 +0200 Subject: [PATCH 30/30] Allways render content in the app menu to load runnables (#5815) --- .../src/lib/components/apps/components/display/AppMenu.svelte | 1 + frontend/src/lib/components/meltComponents/Menu.svelte | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/components/apps/components/display/AppMenu.svelte b/frontend/src/lib/components/apps/components/display/AppMenu.svelte index 98c8dd5265..7fd1cb16ae 100644 --- a/frontend/src/lib/components/apps/components/display/AppMenu.svelte +++ b/frontend/src/lib/components/apps/components/display/AppMenu.svelte @@ -103,6 +103,7 @@ justifyEnd={false} class={resolvedConfig.fillContainer ? 'w-full h-full' : ''} usePointerDownOutside={true} + renderContent > diff --git a/frontend/src/lib/components/meltComponents/Menu.svelte b/frontend/src/lib/components/meltComponents/Menu.svelte index a53a2399ff..75ea762d26 100644 --- a/frontend/src/lib/components/meltComponents/Menu.svelte +++ b/frontend/src/lib/components/meltComponents/Menu.svelte @@ -17,6 +17,7 @@ export let usePointerDownOutside: boolean = false export let menuClass: string = '' export let open = false + export let renderContent: boolean = false // Use the passed createMenu function const menu = createMenu({ @@ -69,7 +70,7 @@ - {#if open} + {#if open || renderContent}