diff --git a/CHANGELOG.md b/CHANGELOG.md index e20b7f4631..acc2bd6c5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## [1.574.1](https://github.com/windmill-labs/windmill/compare/v1.574.0...v1.574.1) (2025-11-08) + + +### Bug Fixes + +* make get_logs work even for partial flow jobs ([d6421c2](https://github.com/windmill-labs/windmill/commit/d6421c2ea79993ef7815c50cf035d3b3425e271e)) + +## [1.574.0](https://github.com/windmill-labs/windmill/compare/v1.573.5...v1.574.0) (2025-11-07) + + +### Features + +* env var in flow ([#6852](https://github.com/windmill-labs/windmill/issues/6852)) ([c59183f](https://github.com/windmill-labs/windmill/commit/c59183f5c39f853d9679c00dd5aa755ef171d735)) + + +### Bug Fixes + +* **cli:** add automatic handler of .node files for codebase bundler ([62ffe9f](https://github.com/windmill-labs/windmill/commit/62ffe9ffce6d070c81794e8483ab83b431aee9ea)) +* teams selector svelte5 ([#7087](https://github.com/windmill-labs/windmill/issues/7087)) ([6045f0c](https://github.com/windmill-labs/windmill/commit/6045f0c40654a88e93be688bcdfab874cfc0b267)) + ## [1.573.5](https://github.com/windmill-labs/windmill/compare/v1.573.4...v1.573.5) (2025-11-07) diff --git a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json index 36ddb8ab9f..713ccb9dd3 100644 --- a/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json +++ b/backend/.sqlx/query-5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55.json @@ -15,7 +15,7 @@ ] }, "nullable": [ - true + null ] }, "hash": "5a219a2532517869578c4504ff3153c43903f929ae5d62fbba12610f89c36d55" diff --git a/backend/.sqlx/query-35061719d01929a7146c80de4b637abdad3198d3340ec7c04ed671baff0a4d0b.json b/backend/.sqlx/query-5e7cadffbee74b11e224b60322b102b9899b4a97b8e557692c0085a9b472b8a7.json similarity index 57% rename from backend/.sqlx/query-35061719d01929a7146c80de4b637abdad3198d3340ec7c04ed671baff0a4d0b.json rename to backend/.sqlx/query-5e7cadffbee74b11e224b60322b102b9899b4a97b8e557692c0085a9b472b8a7.json index e3d94ad1cf..414ba5924d 100644 --- a/backend/.sqlx/query-35061719d01929a7146c80de4b637abdad3198d3340ec7c04ed671baff0a4d0b.json +++ b/backend/.sqlx/query-5e7cadffbee74b11e224b60322b102b9899b4a97b8e557692c0085a9b472b8a7.json @@ -1,11 +1,11 @@ { "db_name": "PostgreSQL", - "query": "SELECT j.created_by AS \"created_by!\", CONCAT(coalesce(job_logs.logs, '')) as logs, job_logs.log_offset, job_logs.log_file_index\n FROM v2_job j\n LEFT JOIN job_logs ON job_logs.job_id = j.id\n WHERE j.id = $1 AND j.workspace_id = $2 AND ($3::text[] IS NULL OR j.tag = ANY($3))", + "query": "SELECT j.created_by AS \"created_by\", coalesce(job_logs.logs, '') as logs, COALESCE(job_logs.log_offset, 0) as log_offset, job_logs.log_file_index\n FROM v2_job j\n LEFT JOIN job_logs ON job_logs.job_id = j.id\n WHERE j.id = $1 AND j.workspace_id = $2 AND ($3::text[] IS NULL OR j.tag = ANY($3))", "describe": { "columns": [ { "ordinal": 0, - "name": "created_by!", + "name": "created_by", "type_info": "Varchar" }, { @@ -34,9 +34,9 @@ "nullable": [ false, null, - false, + null, true ] }, - "hash": "35061719d01929a7146c80de4b637abdad3198d3340ec7c04ed671baff0a4d0b" + "hash": "5e7cadffbee74b11e224b60322b102b9899b4a97b8e557692c0085a9b472b8a7" } diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 0485c7aa07..cb19092a20 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -9071,9 +9071,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.74" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ "bitflags 2.9.4", "cfg-if", @@ -9112,9 +9112,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.110" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", @@ -15137,7 +15137,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "aws-sdk-config", @@ -15197,7 +15197,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "argon2", @@ -15317,7 +15317,7 @@ dependencies = [ [[package]] name = "windmill-api-client" -version = "1.573.5" +version = "1.574.1" dependencies = [ "base64 0.22.1", "chrono", @@ -15332,7 +15332,7 @@ dependencies = [ [[package]] name = "windmill-audit" -version = "1.573.5" +version = "1.574.1" dependencies = [ "chrono", "lazy_static", @@ -15346,7 +15346,7 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "axum", @@ -15365,7 +15365,7 @@ dependencies = [ [[package]] name = "windmill-common" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "async-recursion", @@ -15450,7 +15450,7 @@ dependencies = [ [[package]] name = "windmill-git-sync" -version = "1.573.5" +version = "1.574.1" dependencies = [ "regex", "serde", @@ -15465,7 +15465,7 @@ dependencies = [ [[package]] name = "windmill-indexer" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "bytes", @@ -15489,7 +15489,7 @@ dependencies = [ [[package]] name = "windmill-macros" -version = "1.573.5" +version = "1.574.1" dependencies = [ "itertools 0.14.0", "lazy_static", @@ -15501,7 +15501,7 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.573.5" +version = "1.574.1" dependencies = [ "convert_case 0.6.0", "serde", @@ -15510,7 +15510,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "lazy_static", @@ -15522,7 +15522,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "serde_json", @@ -15534,7 +15534,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "gosyn", @@ -15546,7 +15546,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "lazy_static", @@ -15558,7 +15558,7 @@ dependencies = [ [[package]] name = "windmill-parser-java" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "serde_json", @@ -15570,7 +15570,7 @@ dependencies = [ [[package]] name = "windmill-parser-nu" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "nu-parser", @@ -15581,7 +15581,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15592,7 +15592,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "itertools 0.14.0", @@ -15604,7 +15604,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "async-recursion", @@ -15627,7 +15627,7 @@ dependencies = [ [[package]] name = "windmill-parser-ruby" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "lazy_static", @@ -15641,7 +15641,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -15658,7 +15658,7 @@ dependencies = [ [[package]] name = "windmill-parser-sql" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "lazy_static", @@ -15672,7 +15672,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "lazy_static", @@ -15690,7 +15690,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "serde", @@ -15701,7 +15701,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "async-recursion", @@ -15735,7 +15735,7 @@ dependencies = [ [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.573.5" +version = "1.574.1" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -15745,7 +15745,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.573.5" +version = "1.574.1" dependencies = [ "anyhow", "async-once-cell", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 26cacfdb8a..41e33efd9a 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.573.5" +version = "1.574.1" authors.workspace = true edition.workspace = true @@ -33,7 +33,7 @@ members = [ exclude = ["./windmill-duckdb-ffi-internal"] [workspace.package] -version = "1.573.5" +version = "1.574.1" authors = ["Ruben Fiszel "] edition = "2021" diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index b8a72ff3ab..7deb9bbeef 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.573.5 + version: 1.574.1 title: Windmill API contact: diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index d2de1a8f49..d006c2ec15 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -1468,7 +1468,7 @@ async fn get_job_logs( .flatten(); let record = sqlx::query!( - "SELECT j.created_by AS \"created_by!\", CONCAT(coalesce(job_logs.logs, '')) as logs, job_logs.log_offset, job_logs.log_file_index + "SELECT j.created_by AS \"created_by\", coalesce(job_logs.logs, '') as logs, COALESCE(job_logs.log_offset, 0) as log_offset, job_logs.log_file_index FROM v2_job j LEFT JOIN job_logs ON job_logs.job_id = j.id WHERE j.id = $1 AND j.workspace_id = $2 AND ($3::text[] IS NULL OR j.tag = ANY($3))", @@ -1497,11 +1497,21 @@ async fn get_job_logs( .await?; #[cfg(all(feature = "enterprise", feature = "parquet"))] - if let Some(r) = get_logs_from_store(record.log_offset, &logs, &record.log_file_index).await + if let Some(r) = get_logs_from_store( + record.log_offset.unwrap_or(0), + &logs, + &record.log_file_index, + ) + .await { return r.map(content_plain); } - if let Some(r) = get_logs_from_disk(record.log_offset, &logs, &record.log_file_index).await + if let Some(r) = get_logs_from_disk( + record.log_offset.unwrap_or(0), + &logs, + &record.log_file_index, + ) + .await { return r.map(content_plain); } @@ -4285,7 +4295,11 @@ pub async fn run_script_by_path_inner( timeout, None, // If the job has a parent job, set priority to 2 as it may be ran synchronously and block a current worker until being executed. Flow steps have a priority of 1 so this is higher. - if run_query.parent_job.is_some() || run_query.root_job.is_some() { Some(2) } else { None }, + if run_query.parent_job.is_some() || run_query.root_job.is_some() { + Some(2) + } else { + None + }, push_authed.as_ref(), false, None, diff --git a/backend/windmill-worker/src/js_eval.rs b/backend/windmill-worker/src/js_eval.rs index ec28b6f509..5827c8ba54 100644 --- a/backend/windmill-worker/src/js_eval.rs +++ b/backend/windmill-worker/src/js_eval.rs @@ -192,7 +192,7 @@ fn try_exact_property_access( let suffix = &expr[access_pattern_pos..]; let maybe_key_name = if suffix.starts_with(DOT_PATTERN) { let key_name_pos = DOT_PATTERN.len(); - Some(&expr[key_name_pos..]) + Some(&suffix[key_name_pos..]) } else if suffix.starts_with(START_BRACKET_PATTERN) { let key_name_pos = START_BRACKET_PATTERN.len(); let suffix = &suffix[key_name_pos..]; @@ -220,36 +220,40 @@ fn try_exact_property_access( } async fn handle_full_regex( - captures: regex::Captures<'_>, + expr: &str, authed_client: &AuthedClient, by_id: &IdContext, -) -> anyhow::Result> { - let obj_name = captures.get(1).unwrap().as_str(); - let obj_key = captures.get(2).unwrap().as_str(); - let idx_o = captures.get(3).map(|y| y.as_str()); - let rest = captures.get(4).map(|y| y.as_str()); - let query = if let Some(idx) = idx_o { - match rest { - Some(rest) => Some(format!("{}{}", idx, rest)), - None => Some(idx.to_string()), - } - } else { - rest.map(|x| x.trim_start_matches('.').to_string()) - }; +) -> Option>> { + if let Some(captures) = RE_FULL.captures(&expr) { + let obj_name = captures.get(1).unwrap().as_str(); + let obj_key = captures.get(2).unwrap().as_str(); + let idx_o = captures.get(3).map(|y| y.as_str()); + let rest = captures.get(4).map(|y| y.as_str()); + let query = if let Some(idx) = idx_o { + match rest { + Some(rest) => Some(format!("{}{}", idx, rest)), + None => Some(idx.to_string()), + } + } else { + rest.map(|x| x.trim_start_matches('.').to_string()) + }; - let result = if obj_name == "results" { - authed_client - .get_result_by_id(&by_id.flow_job.to_string(), obj_key, query) - .await - } else if obj_name == "flow_env" { - authed_client - .get_flow_env_by_flow_job_id(&by_id.flow_job.to_string(), obj_key, query) - .await - } else { - unreachable!(); - }; + let result = if obj_name == "results" { + authed_client + .get_result_by_id(&by_id.flow_job.to_string(), obj_key, query) + .await + } else if obj_name == "flow_env" { + authed_client + .get_flow_env_by_flow_job_id(&by_id.flow_job.to_string(), obj_key, query) + .await + } else { + unreachable!(); + }; - return result; + return Some(result); + } + + return None; } pub async fn eval_timeout( @@ -299,8 +303,8 @@ pub async fn eval_timeout( } if let (Some(by_id), Some(authed_client)) = (by_id, authed_client) { - if let Some(captures) = RE_FULL.captures(&expr) { - return handle_full_regex(captures, authed_client, by_id).await; + if let Some(result) = handle_full_regex(&expr, authed_client, by_id).await { + return result; } } @@ -444,9 +448,10 @@ fn replace_with_await(expr: String, fn_name: &str) -> String { s } lazy_static! { - static ref RE: Regex = - Regex::new(r#"(?m)(?P(?:results|flow_env)(?:\?)?(?:(?:\.[a-zA-Z_0-9]+)|(?:\[\".*?\"\])))"#) - .unwrap(); + static ref RE: Regex = Regex::new( + r#"(?m)(?P(?:results|flow_env)(?:\?)?(?:(?:\.[a-zA-Z_0-9]+)|(?:\[\".*?\"\])))"# + ) + .unwrap(); static ref RE_FULL: Regex = Regex::new( r"(?m)^(results|flow_env)(?:\?)?\.([a-zA-Z_0-9]+)(?:\[(\d+)\])?((?:\.[a-zA-Z_0-9]+)+)?$" ) diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index 5dfc44b9ae..14179cdde7 100644 --- a/benchmarks/lib.ts +++ b/benchmarks/lib.ts @@ -2,7 +2,7 @@ import { sleep } from "https://deno.land/x/sleep@v1.2.1/mod.ts"; import * as windmill from "https://deno.land/x/windmill@v1.174.0/mod.ts"; import * as api from "https://deno.land/x/windmill@v1.174.0/windmill-api/index.ts"; -export const VERSION = "v1.573.5"; +export const VERSION = "v1.574.1"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ diff --git a/cli/src/commands/script/script.ts b/cli/src/commands/script/script.ts index 3903be6f71..1c95cb297d 100644 --- a/cli/src/commands/script/script.ts +++ b/cli/src/commands/script/script.ts @@ -180,6 +180,14 @@ export async function handleScriptMetadata( } } +export interface OutputFile { + path: string + contents: Uint8Array + hash: string + /** "contents" as text (changes automatically with "contents") */ + readonly text: string +} + export async function handleFile( path: string, workspace: Workspace, @@ -210,7 +218,9 @@ export async function handleFile( let bundleContent: string | Tarball | undefined = undefined; + let forceTar = false; if (codebase) { + let outputFiles: OutputFile[] = []; if (codebase.customBundler) { log.info(`Using custom bundler ${codebase.customBundler} for ${path}`); bundleContent = execSync( @@ -232,35 +242,42 @@ export async function handleFile( external: codebase.external, inject: codebase.inject, define: codebase.define, + loader: codebase.loader ?? { ".node": "file" }, + outdir: '/', platform: "node", packages: "bundle", target: format == "cjs" ? "node20.15.1" : "esnext", }); const endTime = performance.now(); bundleContent = out.outputFiles[0].text; + outputFiles = out.outputFiles; log.info( `Finished bundling ${path}: ${(bundleContent.length / 1024).toFixed( 0 )}kB (${(endTime - startTime).toFixed(0)}ms)` ); } - if (Array.isArray(codebase.assets) && codebase.assets.length > 0) { + if (outputFiles.length > 1) { const archiveNpm = await import("npm:@ayonli/jsext/archive"); log.info( - `Using the following asset configuration for ${path}: ${JSON.stringify( - codebase.assets - )}` + `Found multiple output files for ${path}, creating a tarball... ${outputFiles.map((file) => file.path).join(", ")}` ); + forceTar = true; const startTime = performance.now(); const tarball = new archiveNpm.Tarball(); + const mainPath = path.split(SEP).pop()?.split(".")[0] + ".js"; + const content = outputFiles.find((file) => file.path == "/" + mainPath)?.text ?? ''; + log.info(`Main content: ${content.length}chars`); tarball.append( - new File([bundleContent], "main.js", { type: "text/plain" }) + new File([content], "main.js", { type: "text/plain" }) ); - for (const asset of codebase.assets) { - const data = fs.readFileSync(asset.from); - const blob = new Blob([data], { type: "text/plain" }); - const file = new File([blob], asset.to); - tarball.append(file); + for (const file of outputFiles) { + if (file.path == "/" + mainPath) { + continue; + } + log.info(`Adding file: ${file.path.substring(1)}`); + const fil = new File([file.contents], file.path.substring(1)); + tarball.append(fil); } const endTime = performance.now(); log.info( @@ -269,6 +286,33 @@ export async function handleFile( ).toFixed(0)}kB (${(endTime - startTime).toFixed(0)}ms)` ); bundleContent = tarball; + } else { + if (Array.isArray(codebase.assets) && codebase.assets.length > 0) { + const archiveNpm = await import("npm:@ayonli/jsext/archive"); + log.info( + `Using the following asset configuration for ${path}: ${JSON.stringify( + codebase.assets + )}` + ); + const startTime = performance.now(); + const tarball = new archiveNpm.Tarball(); + tarball.append( + new File([bundleContent], "main.js", { type: "text/plain" }) + ); + for (const asset of codebase.assets) { + const data = fs.readFileSync(asset.from); + const blob = new Blob([data], { type: "text/plain" }); + const file = new File([blob], asset.to); + tarball.append(file); + } + const endTime = performance.now(); + log.info( + `Finished creating tarball for ${path}: ${( + tarball.size / 1024 + ).toFixed(0)}kB (${(endTime - startTime).toFixed(0)}ms)` + ); + bundleContent = tarball; + } } } let typed = opts?.skipScriptsMetadata @@ -325,7 +369,7 @@ export async function handleFile( } if (typed && codebase) { - typed.codebase = await codebase.getDigest(); + typed.codebase = await codebase.getDigest(forceTar); } const requestBodyCommon: NewScript = { @@ -352,7 +396,7 @@ export async function handleFile( concurrency_key: typed?.concurrency_key, debounce_key: typed?.debounce_key, debounce_delay_s: typed?.debounce_delay_s, - codebase: await codebase?.getDigest(), + codebase: await codebase?.getDigest(forceTar), timeout: typed?.timeout, on_behalf_of_email: typed?.on_behalf_of_email, }; diff --git a/cli/src/core/conf.ts b/cli/src/core/conf.ts index 5a56f97435..0a6dbe8167 100644 --- a/cli/src/core/conf.ts +++ b/cli/src/core/conf.ts @@ -99,6 +99,7 @@ export interface Codebase { external?: string[]; define?: { [key: string]: string }; inject?: string[]; + loader?: any, format?: "cjs" | "esm"; } diff --git a/cli/src/main.ts b/cli/src/main.ts index 413cd2a59a..88ef77d73b 100644 --- a/cli/src/main.ts +++ b/cli/src/main.ts @@ -68,7 +68,7 @@ export { // } // }); -export const VERSION = "1.573.5"; +export const VERSION = "1.574.1"; export const WM_FORK_PREFIX = "wm-fork"; diff --git a/cli/src/utils/codebase.ts b/cli/src/utils/codebase.ts index 36dfbb16ed..3391f6f795 100644 --- a/cli/src/utils/codebase.ts +++ b/cli/src/utils/codebase.ts @@ -2,7 +2,7 @@ import { Codebase, SyncOptions } from "../core/conf.ts"; import { log } from "../../deps.ts"; import { digestDir } from "./utils.ts"; -export type SyncCodebase = Codebase & { getDigest: () => Promise }; +export type SyncCodebase = Codebase & { getDigest: (forceTar?: boolean) => Promise }; export function listSyncCodebases( options: SyncOptions ): SyncCodebase[] { @@ -13,16 +13,21 @@ export function listSyncCodebases( } for (const codebase of options?.codebases ?? []) { let _digest: string | undefined = undefined; - const getDigest: () => Promise = async () => { - if (_digest == undefined) { + let alreadyPrinted = false; + const getDigest: (forceTar?: boolean) => Promise = async (forceTar?: boolean) => { + if (_digest == undefined || forceTar) { _digest = await digestDir( codebase.relative_path, JSON.stringify(codebase) ); - if (Array.isArray(codebase.assets) && codebase.assets.length > 0) { + if (forceTar || (Array.isArray(codebase.assets) && codebase.assets.length > 0)) { _digest += ".tar"; } - log.info(`Codebase ${codebase.relative_path}, digest: ${_digest}`); + if (!alreadyPrinted) { + alreadyPrinted = true; + log.info(`Codebase ${codebase.relative_path}, digest: ${_digest}`); + } + return _digest; } return _digest; }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 48eea0020c..2055f79b82 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.573.5", + "version": "1.574.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.573.5", + "version": "1.574.1", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/frontend/package.json b/frontend/package.json index 47b0b78bc8..3f5a13c88e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "windmill-components", - "version": "1.573.5", + "version": "1.574.1", "scripts": { "dev": "vite dev", "build": "vite build", diff --git a/frontend/src/lib/components/ChannelSelector.svelte b/frontend/src/lib/components/ChannelSelector.svelte index b6e77e06d9..7bca9d26d0 100644 --- a/frontend/src/lib/components/ChannelSelector.svelte +++ b/frontend/src/lib/components/ChannelSelector.svelte @@ -18,7 +18,7 @@ channels?: ChannelItem[] teamId?: string onError?: (error: Error) => void - onselectedchannelchange?: (channel: ChannelItem | undefined) => void + onSelectedChannelChange?: (channel: ChannelItem | undefined) => void } let { @@ -30,7 +30,7 @@ channels = undefined, teamId, onError, - onselectedchannelchange + onSelectedChannelChange }: Props = $props() let isFetching = $state(false) @@ -69,7 +69,7 @@ $effect(() => { if (selectedChannel?.channel_id !== previousChannelId) { previousChannelId = selectedChannel?.channel_id - onselectedchannelchange?.(selectedChannel) + onSelectedChannelChange?.(selectedChannel) } }) diff --git a/frontend/src/lib/components/ErrorOrRecoveryHandler.svelte b/frontend/src/lib/components/ErrorOrRecoveryHandler.svelte index 25bc2f9adf..a21307977b 100644 --- a/frontend/src/lib/components/ErrorOrRecoveryHandler.svelte +++ b/frontend/src/lib/components/ErrorOrRecoveryHandler.svelte @@ -502,7 +502,7 @@ channel_name: handlerExtraArgs['channel_name'] } : undefined} - onselectedchannelchange={(channel) => { + onSelectedChannelChange={(channel) => { handlerExtraArgs['channel'] = channel?.channel_id handlerExtraArgs['channel_name'] = channel?.channel_name }} diff --git a/frontend/src/lib/components/FlowPreviewContent.svelte b/frontend/src/lib/components/FlowPreviewContent.svelte index 3c5267917d..cab32403f3 100644 --- a/frontend/src/lib/components/FlowPreviewContent.svelte +++ b/frontend/src/lib/components/FlowPreviewContent.svelte @@ -39,6 +39,7 @@ import { aiChatManager } from './copilot/chat/AIChatManager.svelte' import { stateSnapshot } from '$lib/svelte5Utils.svelte' import FlowChatInterface from './flows/conversations/FlowChatInterface.svelte' + import { randomUUID } from './flows/conversations/FlowChatManager.svelte' interface Props { previewMode: 'upTo' | 'whole' @@ -469,7 +470,7 @@ return jobId ?? '' }} createConversation={async () => { - const newConversationId = crypto.randomUUID() + const newConversationId = randomUUID() return newConversationId }} /> diff --git a/frontend/src/lib/components/InstanceSetting.svelte b/frontend/src/lib/components/InstanceSetting.svelte index 92685107a9..9e5906fdd9 100644 --- a/frontend/src/lib/components/InstanceSetting.svelte +++ b/frontend/src/lib/components/InstanceSetting.svelte @@ -586,7 +586,7 @@ minWidth="140px" showRefreshButton={false} selectedTeam={currentTeam} - onselectedteamchange={(team) => handleTeamChange(team, i)} + onSelectedTeamChange={(team) => handleTeamChange(team, i)} /> {#if $values['critical_error_channels'][i]?.teams_channel?.team_id} @@ -595,7 +595,7 @@ placeholder="Search channels" teamId={$values['critical_error_channels'][i]?.teams_channel?.team_id} selectedChannel={currentChannel} - onselectedchannelchange={(channel) => handleChannelChange(channel, i)} + onSelectedChannelChange={(channel) => handleChannelChange(channel, i)} onError={(e) => sendUserToast('Failed to load channels: ' + e.message, true)} /> diff --git a/frontend/src/lib/components/TeamSelector.svelte b/frontend/src/lib/components/TeamSelector.svelte index e55f0bec8f..6ba222f12d 100644 --- a/frontend/src/lib/components/TeamSelector.svelte +++ b/frontend/src/lib/components/TeamSelector.svelte @@ -18,7 +18,7 @@ teams?: TeamItem[] | undefined minWidth?: string onError?: (error: Error) => void - onselectedteamchange?: (team: TeamItem | undefined) => void + onSelectedTeamChange?: (team: TeamItem | undefined) => void } let { @@ -29,7 +29,7 @@ teams = undefined, minWidth = '160px', onError, - onselectedteamchange + onSelectedTeamChange }: Props = $props() let isFetching = $state(false) @@ -68,7 +68,7 @@ $effect(() => { if (selectedTeam?.team_id !== previousTeamId) { previousTeamId = selectedTeam?.team_id - onselectedteamchange?.(selectedTeam) + onSelectedTeamChange?.(selectedTeam) } }) diff --git a/frontend/src/lib/components/apps/components/inputs/AppMultiSelectV2.svelte b/frontend/src/lib/components/apps/components/inputs/AppMultiSelectV2.svelte index 929e4cb147..21171e3e11 100644 --- a/frontend/src/lib/components/apps/components/inputs/AppMultiSelectV2.svelte +++ b/frontend/src/lib/components/apps/components/inputs/AppMultiSelectV2.svelte @@ -55,7 +55,11 @@ }) let selectedItems: string[] = $state([...new Set(outputs?.result.peak())].map(convertToValue)) - $effect(() => setResultsFromSelectedItems(selectedItems)) + $effect(() => { + selectedItems + // console.log('selectedItems', selectedItems) + untrack(() => setResultsFromSelectedItems(selectedItems)) + }) let customItems: string[] = $state([]) diff --git a/frontend/src/lib/components/flows/content/FlowInput.svelte b/frontend/src/lib/components/flows/content/FlowInput.svelte index 7eae608898..bffdd2dcf9 100644 --- a/frontend/src/lib/components/flows/content/FlowInput.svelte +++ b/frontend/src/lib/components/flows/content/FlowInput.svelte @@ -49,6 +49,7 @@ import { AI_AGENT_SCHEMA } from '../flowInfers' import { nextId } from '../flowModuleNextId' import ConfirmationModal from '$lib/components/common/confirmationModal/ConfirmationModal.svelte' + import { randomUUID } from '../conversations/FlowChatManager.svelte' interface Props { noEditor: boolean @@ -491,7 +492,7 @@ { - const newConversationId = crypto.randomUUID() + const newConversationId = randomUUID() return newConversationId }} /> diff --git a/frontend/src/lib/components/flows/conversations/FlowChatManager.svelte.ts b/frontend/src/lib/components/flows/conversations/FlowChatManager.svelte.ts index 8afd1708e5..8f0948f4ed 100644 --- a/frontend/src/lib/components/flows/conversations/FlowChatManager.svelte.ts +++ b/frontend/src/lib/components/flows/conversations/FlowChatManager.svelte.ts @@ -18,6 +18,15 @@ export interface FlowChatManagerOptions { path?: string } +export function randomUUID() { + // Pure JS (RFC4122 v4) UUID implementation (no external dependencies) + return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { + const r = (Math.random() * 16) | 0 + const v = c === 'x' ? r : (r & 0x3) | 0x8 + return v.toString(16) + }) +} + class FlowChatManager { // State messages = $state([]) @@ -320,7 +329,7 @@ class FlowChatManager { delete this.#conversationsCache[currentConversationId] const userMessage: ChatMessage = { - id: crypto.randomUUID(), + id: randomUUID(), content: this.inputMessage.trim(), created_at: new Date().toISOString(), message_type: 'user', @@ -371,17 +380,20 @@ class FlowChatManager { let isCompleted = false try { + const jobId = await JobService.runFlowByPath({ + workspace: this.#workspace!, + path: this.#path!, + requestBody: { user_message: messageContent }, + memoryId: currentConversationId + }) // Encode the payload as base64 - const payload = { user_message: messageContent } - const payloadBase64 = btoa(JSON.stringify(payload)) // Build the EventSource URL - const streamUrl = `/api/w/${this.#workspace}/jobs/run_and_stream/f/${this.#path}` + const streamUrl = `/api/w/${this.#workspace}/jobs_u/getupdate_sse/${jobId}` const url = new URL(streamUrl, window.location.origin) - url.searchParams.set('payload', payloadBase64) - url.searchParams.set('memory_id', currentConversationId) url.searchParams.set('poll_delay_ms', '50') - + url.searchParams.set('fast', 'true') + url.searchParams.set('only_result', 'true') // Create EventSource connection const eventSource = new EventSource(url.toString()) this.currentEventSource = eventSource @@ -392,7 +404,6 @@ class FlowChatManager { eventSource.onmessage = async (event) => { try { const data = JSON.parse(event.data) - if (data.type === 'update') { if (data.flow_stream_job_id) { this.currentJobId = data.flow_stream_job_id @@ -420,7 +431,7 @@ class FlowChatManager { this.messages = [ ...this.messages, { - id: 'temp-' + crypto.randomUUID(), + id: 'temp-' + randomUUID(), content: newContent, created_at: new Date().toISOString(), message_type: 'tool', @@ -442,7 +453,7 @@ class FlowChatManager { assistantMessageId.length === 0 && accumulatedContent.length > 0 ) { - assistantMessageId = 'temp-' + crypto.randomUUID() + assistantMessageId = 'temp-' + randomUUID() this.messages = [ ...this.messages, { diff --git a/frontend/src/lib/components/propertyPicker/PropPicker.svelte b/frontend/src/lib/components/propertyPicker/PropPicker.svelte index af42ecb864..c90a437b8a 100644 --- a/frontend/src/lib/components/propertyPicker/PropPicker.svelte +++ b/frontend/src/lib/components/propertyPicker/PropPicker.svelte @@ -18,7 +18,7 @@ export let error: boolean = false export let allowCopy = false export let previousId: string | undefined = undefined - export let flow_env: Record | undefined = undefined + export let flow_env: Record | undefined = undefined let variables: Record = {} let resources: Record = {} diff --git a/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte index 84ceabe2b6..444bed9496 100644 --- a/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/flows/get/[...path]/+page.svelte @@ -65,6 +65,7 @@ initFlowGraphAssetsCtx } from '$lib/components/flows/FlowAssetsHandler.svelte' import { page } from '$app/state' + import { randomUUID } from '$lib/components/flows/conversations/FlowChatManager.svelte' let flow: Flow | undefined = $state() let can_write = false @@ -401,7 +402,7 @@ let path = $derived(page.params.path ?? '') async function handleNewConversation({ clearMessages = true }: { clearMessages?: boolean }) { - const newConversationId = crypto.randomUUID() + const newConversationId = randomUUID() // Add the new conversation to the sidebar (returns id of draft or new conversation) if (flowConversationsSidebar) { diff --git a/lsp/Pipfile b/lsp/Pipfile index 0a2289344c..5207532db2 100644 --- a/lsp/Pipfile +++ b/lsp/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -wmill = ">=1.573.5" -wmill_pg = ">=1.573.5" +wmill = ">=1.574.1" +wmill_pg = ">=1.574.1" sendgrid = "*" mysql-connector-python = "*" pymongo = "*" diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index a9a4009211..156eac8a54 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.573.5 + version: 1.574.1 title: OpenFlow Spec contact: name: Ruben Fiszel diff --git a/powershell-client/WindmillClient/WindmillClient.psd1 b/powershell-client/WindmillClient/WindmillClient.psd1 index cb51f183c0..ce25df0d21 100644 --- a/powershell-client/WindmillClient/WindmillClient.psd1 +++ b/powershell-client/WindmillClient/WindmillClient.psd1 @@ -12,7 +12,7 @@ RootModule = 'WindmillClient.psm1' # Version number of this module. - ModuleVersion = '1.573.5' + ModuleVersion = '1.574.1' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/python-client/wmill/pyproject.toml b/python-client/wmill/pyproject.toml index 8de01a20a3..7453c8d7de 100644 --- a/python-client/wmill/pyproject.toml +++ b/python-client/wmill/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill" -version = "1.573.5" +version = "1.574.1" description = "A client library for accessing Windmill server wrapping the Windmill client API" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/python-client/wmill_pg/pyproject.toml b/python-client/wmill_pg/pyproject.toml index 6410052700..cd9d5aecc8 100644 --- a/python-client/wmill_pg/pyproject.toml +++ b/python-client/wmill_pg/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill-pg" -version = "1.573.5" +version = "1.574.1" description = "An extension client for the wmill client library focused on pg" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/typescript-client/jsr.json b/typescript-client/jsr.json index 4f6cf29147..1ded4087d4 100644 --- a/typescript-client/jsr.json +++ b/typescript-client/jsr.json @@ -1,6 +1,6 @@ { "name": "@windmill/windmill", - "version": "1.573.5", + "version": "1.574.1", "exports": "./src/index.ts", "publish": { "exclude": ["!src", "./s3Types.ts", "./client.ts"] diff --git a/typescript-client/package.json b/typescript-client/package.json index 44676689ad..1bc35510dc 100644 --- a/typescript-client/package.json +++ b/typescript-client/package.json @@ -1,7 +1,7 @@ { "name": "windmill-client", "description": "Windmill SDK client for browsers and Node.js", - "version": "1.573.5", + "version": "1.574.1", "author": "Ruben Fiszel", "license": "Apache 2.0", "devDependencies": { diff --git a/version.txt b/version.txt index 0ace6d04cf..50a7825cc3 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.573.5 +1.574.1